@@ -38,6 +38,7 @@ ActiveCode.prototype.init = function(opts) {
3838 this . chatcodes = $ ( orig ) . data ( 'chatcodes' ) ;
3939 this . hidehistory = $ ( orig ) . data ( 'hidehistory' ) ;
4040 this . tie = $ ( orig ) . data ( 'tie' )
41+ this . dburl = $ ( orig ) . data ( 'dburl' ) ;
4142 this . runButton = null ;
4243 this . enabledownload = $ ( orig ) . data ( 'enabledownload' ) ;
4344 this . downloadButton = null ;
@@ -475,7 +476,7 @@ ActiveCode.prototype.createOutput = function () {
475476 // to hold turtle graphics output. We use a div in case the turtle changes from
476477 // using a canvas to using some other element like svg in the future.
477478 var outDiv = document . createElement ( "div" ) ;
478- $ ( outDiv ) . addClass ( "ac_output col-md-5 " ) ;
479+ $ ( outDiv ) . addClass ( "ac_output col-md-12 " ) ;
479480 this . outDiv = outDiv ;
480481 this . output = document . createElement ( 'pre' ) ;
481482 this . output . id = this . divid + '_stdout' ;
@@ -2358,6 +2359,153 @@ LiveCode.prototype.pushDataFile = function (file, resolve, reject) {
23582359 return classes ;
23592360 }
23602361
2362+ //
2363+ // SQL
2364+ //
2365+
2366+ SQLActiveCode . prototype = new ActiveCode ( ) ;
2367+
2368+ function SQLActiveCode ( opts ) {
2369+ if ( opts ) {
2370+ this . init ( opts )
2371+ }
2372+ }
2373+
2374+ SQLActiveCode . prototype . init = function ( opts ) {
2375+
2376+ ActiveCode . prototype . init . apply ( this , arguments ) ;
2377+
2378+ if ( eBookConfig . useRunestoneServices ) {
2379+ var fnprefix = '/runestone/books/published/' + eBookConfig . basecourse + '/_static' ;
2380+ } else {
2381+ var fnprefix = '/_static' ;
2382+ }
2383+ this . config = {
2384+ locateFile : filename => `${ fnprefix } /${ filename } `
2385+ }
2386+
2387+ var self = this ;
2388+
2389+ initSqlJs ( this . config ) . then ( function ( SQL ) {
2390+ // set up call to load database asynchronously if given
2391+ if ( self . dburl ) {
2392+ var xhr = new XMLHttpRequest ( ) ;
2393+ $ ( self . runButton ) . attr ( 'disabled' , 'disabled' )
2394+ // For example: https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite.sqlite
2395+ xhr . open ( 'GET' , self . dburl , true ) ;
2396+ xhr . responseType = 'arraybuffer' ;
2397+
2398+ xhr . onload = e => {
2399+ var uInt8Array = new Uint8Array ( xhr . response ) ;
2400+ self . db = new SQL . Database ( uInt8Array ) ;
2401+ $ ( self . runButton ) . removeAttr ( 'disabled' )
2402+ // contents is now [{columns:['col1','col2',...], values:[[first row], [second row], ...]}]
2403+ } ;
2404+ xhr . send ( ) ;
2405+ } else {
2406+ self . db = new SQL . Database ( ) ;
2407+ }
2408+ } ) ;
2409+ } ;
2410+
2411+
2412+ SQLActiveCode . prototype . runProg = function ( ) {
2413+ var result_mess = "success"
2414+ var scrubber_dfd , history_dfd , saveCode
2415+ // Clear any old results
2416+ saveCode = "True"
2417+ let divid = this . divid + '_sql_out' ;
2418+ let respDiv = document . getElementById ( divid ) ;
2419+ if ( respDiv ) {
2420+ respDiv . parentElement . removeChild ( respDiv )
2421+ }
2422+ $ ( this . output ) . text ( "" )
2423+ // Run this query
2424+ let query = this . buildProg ( ) ;
2425+ try {
2426+ var res = this . db . exec ( query ) ;
2427+ } catch ( error ) {
2428+ result_mess = error . toString ( ) ;
2429+ $ ( this . output ) . text ( error ) ;
2430+ $ ( this . outDiv ) . show ( ) ;
2431+
2432+ }
2433+ this . logRunEvent ( {
2434+ 'div_id' : this . divid ,
2435+ 'code' : this . editor . getValue ( ) ,
2436+ 'lang' : this . language ,
2437+ 'errinfo' : result_mess ,
2438+ 'to_save' : saveCode ,
2439+ 'prefix' : this . pretext ,
2440+ 'suffix' : this . suffix ,
2441+ 'partner' : this . partner
2442+ } ) ; // Log the run event
2443+
2444+ var __ret = this . manage_scrubber ( scrubber_dfd , history_dfd , saveCode ) ;
2445+ history_dfd = __ret . history_dfd ;
2446+ saveCode = __ret . saveCode ;
2447+
2448+ history_dfd . then ( function ( ) {
2449+ if ( this . slideit ) {
2450+ $ ( this . historyScrubber ) . on ( "slidechange" , this . slideit . bind ( this ) ) ;
2451+ }
2452+ $ ( this . historyScrubber ) . slider ( "enable" ) ;
2453+ } ) ;
2454+
2455+ if ( result_mess != "success" ) {
2456+ return ;
2457+ }
2458+ // Create a nice table to show the result of the query
2459+ if ( res [ 0 ] . values . length > 100 ) {
2460+ $ ( this . output ) . text ( "Result set is longer than 100 rows limiting output to first 100" )
2461+ }
2462+ let table = createTable ( res [ 0 ] ) ;
2463+ respDiv = document . createElement ( 'div' )
2464+ respDiv . id = divid ;
2465+ $ ( respDiv ) . addClass ( 'table-responsive-md' )
2466+ $ ( respDiv ) . css ( 'max-height' , '500px' )
2467+ $ ( respDiv ) . css ( 'overflow' , 'scroll' )
2468+ this . outDiv . appendChild ( respDiv )
2469+ respDiv . appendChild ( table )
2470+ $ ( this . outDiv ) . show ( )
2471+
2472+ }
2473+
2474+ function createTable ( tableData ) {
2475+ var table = document . createElement ( 'table' ) ;
2476+ var head = document . createElement ( 'thead' ) ;
2477+ var tableBody = document . createElement ( 'tbody' ) ;
2478+ var theads = document . createElement ( 'tr' )
2479+
2480+ tableData . columns . forEach ( function ( colData ) {
2481+ let th = document . createElement ( 'th' ) ;
2482+ th . appendChild ( document . createTextNode ( colData ) ) ;
2483+ theads . appendChild ( th ) ;
2484+ } ) ;
2485+ table . appendChild ( head ) ;
2486+ head . appendChild ( theads ) ;
2487+ tableData . values . slice ( 0 , 100 ) . forEach ( function ( rowData ) {
2488+ var row = document . createElement ( 'tr' ) ;
2489+
2490+ rowData . forEach ( function ( cellData ) {
2491+ var cell = document . createElement ( 'td' ) ;
2492+ cell . appendChild ( document . createTextNode ( cellData ) ) ;
2493+ row . appendChild ( cell ) ;
2494+ } ) ;
2495+
2496+ tableBody . appendChild ( row ) ;
2497+ } ) ;
2498+
2499+ table . appendChild ( tableBody ) ;
2500+ $ ( table ) . css ( 'background' , 'white' ) ;
2501+ $ ( table ) . addClass ( 'table-striped table-light thead-dark' )
2502+ return table ;
2503+ }
2504+
2505+
2506+ //
2507+ // ActiveCode Factory Class
2508+ //
23612509
23622510ACFactory = { } ;
23632511
@@ -2372,6 +2520,8 @@ ACFactory.createActiveCode = function (orig, lang, addopts) {
23722520 return new JSActiveCode ( opts ) ;
23732521 } else if ( lang === 'htmlmixed' ) {
23742522 return new HTMLActiveCode ( opts ) ;
2523+ } else if ( lang === 'sql' ) {
2524+ return new SQLActiveCode ( opts ) ;
23752525 } else if ( [ 'java' , 'cpp' , 'c' , 'python3' , 'python2' ] . indexOf ( lang ) > - 1 ) {
23762526 return new LiveCode ( opts ) ;
23772527 } else { // default is python
@@ -2380,6 +2530,7 @@ ACFactory.createActiveCode = function (orig, lang, addopts) {
23802530
23812531} ;
23822532
2533+
23832534// used by web2py controller(s)
23842535ACFactory . addActiveCodeToDiv = function ( outerdivid , acdivid , sid , initialcode , language ) {
23852536 var thepre , newac ;
@@ -2462,6 +2613,11 @@ ACFactory.toggleScratchActivecode = function () {
24622613
24632614} ;
24642615
2616+
2617+ //
2618+ // Page Initialization
2619+ //
2620+
24652621$ ( document ) . ready ( function ( ) {
24662622 ACFactory . createScratchActivecode ( ) ;
24672623 $ ( '[data-component=activecode]' ) . each ( function ( index ) {
0 commit comments