| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | (function(){ |
| | 'use strict'; |
| | |
| | |
| |
|
| | const storage = (function(NS){ |
| | |
| | |
| | |
| | 'use strict'; |
| | NS = NS||{}; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const tryStorage = function f(obj){ |
| | if(!f.key) f.key = 'storage.access.check'; |
| | try{ |
| | obj.setItem(f.key, 'f'); |
| | const x = obj.getItem(f.key); |
| | obj.removeItem(f.key); |
| | if(x!=='f') throw new Error(f.key+" failed") |
| | return obj; |
| | }catch(e){ |
| | return undefined; |
| | } |
| | }; |
| |
|
| | |
| | const $storage = |
| | tryStorage(window.localStorage) |
| | || tryStorage(window.sessionStorage) |
| | || tryStorage({ |
| | |
| | $$$:{}, |
| | setItem: function(k,v){this.$$$[k]=v}, |
| | getItem: function(k){ |
| | return this.$$$.hasOwnProperty(k) ? this.$$$[k] : undefined; |
| | }, |
| | removeItem: function(k){delete this.$$$[k]}, |
| | clear: function(){this.$$$={}} |
| | }); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const $storageHolder = $storage.hasOwnProperty('$$$') ? $storage.$$$ : $storage; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const storageKeyPrefix = ( |
| | $storageHolder===$storage |
| | ? ( |
| | (NS.config ? |
| | (NS.config.projectCode || NS.config.projectName |
| | || NS.config.shortProjectName) |
| | : false) |
| | || window.location.pathname |
| | )+'::' : ( |
| | '' |
| | ) |
| | ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | NS.storage = { |
| | storageKeyPrefix: storageKeyPrefix, |
| | |
| | |
| | set: (k,v)=>$storage.setItem(storageKeyPrefix+k,v), |
| | |
| | setJSON: (k,v)=>$storage.setItem(storageKeyPrefix+k,JSON.stringify(v)), |
| | |
| | |
| | get: (k,dflt)=>$storageHolder.hasOwnProperty( |
| | storageKeyPrefix+k |
| | ) ? $storage.getItem(storageKeyPrefix+k) : dflt, |
| | |
| | |
| | |
| | |
| | getBool: function(k,dflt){ |
| | return 'true'===this.get(k,''+(!!dflt)); |
| | }, |
| | |
| | |
| | |
| | getJSON: function f(k,dflt){ |
| | try { |
| | const x = this.get(k,f); |
| | return x===f ? dflt : JSON.parse(x); |
| | } |
| | catch(e){return dflt} |
| | }, |
| | |
| | |
| | contains: (k)=>$storageHolder.hasOwnProperty(storageKeyPrefix+k), |
| | |
| | remove: function(k){ |
| | $storage.removeItem(storageKeyPrefix+k); |
| | return this; |
| | }, |
| | |
| | clear: function(){ |
| | this.keys().forEach((k)=>$storage.removeItem(k)); |
| | return this; |
| | }, |
| | |
| | keys: ()=>Object.keys($storageHolder).filter((v)=>(v||'').startsWith(storageKeyPrefix)), |
| | |
| | |
| | |
| | isTransient: ()=>$storageHolder!==$storage, |
| | |
| | storageImplName: function(){ |
| | if($storage===window.localStorage) return 'localStorage'; |
| | else if($storage===window.sessionStorage) return 'sessionStorage'; |
| | else return 'transient'; |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | storageHelpDescription: function(){ |
| | return { |
| | localStorage: "Browser-local persistent storage with an "+ |
| | "unspecified long-term lifetime (survives closing the browser, "+ |
| | "but maybe not a browser upgrade).", |
| | sessionStorage: "Storage local to this browser tab, "+ |
| | "lost if this tab is closed.", |
| | "transient": "Transient storage local to this invocation of this page." |
| | }[this.storageImplName()]; |
| | } |
| | }; |
| | return NS.storage; |
| | })({}); |
| |
|
| |
|
| | |
| | const configStorageKey = 'sqlite3-fiddle-config'; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | const SF |
| | = window.SqliteFiddle = { |
| | |
| | config: { |
| | |
| | |
| | |
| | autoScrollOutput: true, |
| | |
| | |
| | autoClearOutput: false, |
| | |
| | |
| | |
| | echoToConsole: false, |
| | |
| | sideBySide: true, |
| | |
| | swapInOut: false |
| | }, |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | echo: function f(text) { |
| | |
| | |
| | |
| | |
| | |
| | if(!f._){ |
| | f._ = document.getElementById('output'); |
| | f._.value = ''; |
| | } |
| | if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); |
| | else if(1===arguments.length && Array.isArray(text)) text = text.join(' '); |
| | |
| | |
| | |
| | |
| | |
| | if(null===text){ |
| | f._.value = ''; |
| | return; |
| | }else if(this.echo._clearPending){ |
| | delete this.echo._clearPending; |
| | f._.value = ''; |
| | } |
| | if(this.config.echoToConsole) console.log(text); |
| | if(this.jqTerm) this.jqTerm.echo(text); |
| | f._.value += text + "\n"; |
| | if(this.config.autoScrollOutput){ |
| | f._.scrollTop = f._.scrollHeight; |
| | } |
| | }, |
| | _msgMap: {}, |
| | |
| | |
| | addMsgHandler: function f(type,callback){ |
| | if(Array.isArray(type)){ |
| | type.forEach((t)=>this.addMsgHandler(t, callback)); |
| | return this; |
| | } |
| | (this._msgMap.hasOwnProperty(type) |
| | ? this._msgMap[type] |
| | : (this._msgMap[type] = [])).push(callback); |
| | return this; |
| | }, |
| | |
| | runMsgHandlers: function(msg){ |
| | const list = (this._msgMap.hasOwnProperty(msg.type) |
| | ? this._msgMap[msg.type] : false); |
| | if(!list){ |
| | console.warn("No handlers found for message type:",msg); |
| | return false; |
| | } |
| | |
| | list.forEach((f)=>f(msg)); |
| | return true; |
| | }, |
| | |
| | clearMsgHandlers: function(type){ |
| | delete this._msgMap[type]; |
| | return this; |
| | }, |
| | |
| | wMsg: function(type,data,transferables){ |
| | this.worker.postMessage({type, data}, transferables || []); |
| | return this; |
| | }, |
| | |
| | |
| | |
| | |
| | resetDb: function(){ |
| | if(window.confirm("Really destroy all content and tables " |
| | +"in the (transient) db?")){ |
| | this.wMsg('db-reset'); |
| | } |
| | return this; |
| | }, |
| | |
| | storeConfig: function(){ |
| | storage.setJSON(configStorageKey,this.config); |
| | } |
| | }; |
| |
|
| | if(1){ |
| | const storedConfig = storage.getJSON(configStorageKey); |
| | if(storedConfig){ |
| | |
| | |
| | |
| | |
| | Object.keys(SF.config).forEach(function(k){ |
| | if(storedConfig.hasOwnProperty(k)){ |
| | SF.config[k] = storedConfig[k]; |
| | } |
| | }); |
| | } |
| | } |
| |
|
| | SF.worker = new Worker('fiddle-worker.js'+self.location.search); |
| | SF.worker.onmessage = (ev)=>SF.runMsgHandlers(ev.data); |
| | SF.addMsgHandler(['stdout', 'stderr'], (ev)=>SF.echo(ev.data)); |
| | SF.addMsgHandler('sqlite-version', (ev)=>{ |
| | const v = ev.data; |
| | const a = E('#sqlite-version-link'); |
| | const li = v.srcId.split(' '); |
| | a.setAttribute('href', |
| | |
| | 'https://sqlite.org/src/info/'+li[2].substr(0,20) |
| | ); |
| | a.setAttribute('target', '_blank'); |
| | a.innerText = [ |
| | v.lib, |
| | v.srcId.substr(0,34) |
| | ].join(' '); |
| | SF.echo("SQLite version",a.innerText); |
| | }); |
| | SF.addMsgHandler('wasm-info', (ev)=>{ |
| | const v = ev.data; |
| | SF.e.wasmInfo.innerText = 'WASM: '+( |
| | 4===v.pointerSize ? 32 : 64 |
| | )+'-bit' |
| | |
| | |
| | ; |
| | }); |
| |
|
| | |
| | const EAll = function(){ |
| | return (arguments.length>1 ? arguments[0] : document) |
| | .querySelectorAll(arguments[arguments.length-1]); |
| | }; |
| | |
| | const E = function(){ |
| | return (arguments.length>1 ? arguments[0] : document) |
| | .querySelector(arguments[arguments.length-1]); |
| | }; |
| |
|
| | |
| | SF.addMsgHandler('module', function f(ev){ |
| | ev = ev.data; |
| | if('status'!==ev.type){ |
| | console.warn("Unexpected module-type message:",ev); |
| | return; |
| | } |
| | if(!f.ui){ |
| | f.ui = { |
| | status: E('#module-status'), |
| | progress: E('#module-progress'), |
| | spinner: E('#module-spinner') |
| | }; |
| | } |
| | const msg = ev.data; |
| | if(f.ui.progres){ |
| | progress.value = msg.step; |
| | progress.max = msg.step + 1; |
| | } |
| | if(1==msg.step){ |
| | f.ui.progress.classList.remove('hidden'); |
| | f.ui.spinner.classList.remove('hidden'); |
| | } |
| | if(msg.text){ |
| | f.ui.status.classList.remove('hidden'); |
| | f.ui.status.innerText = msg.text; |
| | }else{ |
| | if(f.ui.progress){ |
| | f.ui.progress.remove(); |
| | f.ui.spinner.remove(); |
| | delete f.ui.progress; |
| | delete f.ui.spinner; |
| | } |
| | f.ui.status.classList.add('hidden'); |
| | |
| | |
| | |
| | |
| | } |
| | }); |
| |
|
| | |
| | |
| | |
| | |
| | SF.addMsgHandler('fiddle-ready', function(){ |
| | SF.clearMsgHandlers('fiddle-ready'); |
| | self.onSFLoaded(); |
| | }); |
| |
|
| | SF.e ={ |
| | about: E('#view-about'), |
| | split: E('#view-split'), |
| | wasmInfo: E('#opt-wasm-info'), |
| | terminal: E('#view-terminal'), |
| | hideInTerminal: EAll('.hide-in-terminal' |
| | ) |
| | }; |
| | SF.eViews = EAll('.app-view'); |
| | SF.setMainView = function(eMain){ |
| | if( SF.e.main === eMain ) return; |
| | SF.eViews.forEach((e)=>{ |
| | if( e===eMain ) e.classList.remove('hidden'); |
| | else e.classList.add('hidden'); |
| | }); |
| | SF.e.hideInTerminal.forEach(e=>{ |
| | if( eMain === SF.e.terminal ) e.classList.add('hidden'); |
| | else e.classList.remove('hidden'); |
| | }); |
| | SF.e.main = eMain; |
| | SF.ForceResizeKludge(); |
| | }; |
| |
|
| | |
| | SF.toggleAbout = function(){ |
| | if( SF.e.about.classList.contains('hidden') ){ |
| | SF.e.about.$returnTo = SF.e.main; |
| | SF.setMainView( SF.e.about ); |
| | }else{ |
| | const e = SF.e.about.$returnTo; |
| | delete SF.e.about.$returnTo; |
| | SF.setMainView( e ); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const effectiveHeight = function f(e){ |
| | if(!e) return 0; |
| | if(!f.measure){ |
| | f.measure = function callee(e, depth){ |
| | if(!e) return; |
| | const m = e.getBoundingClientRect(); |
| | if(0===depth){ |
| | callee.top = m.top; |
| | callee.bottom = m.bottom; |
| | }else{ |
| | callee.top = m.top ? Math.min(callee.top, m.top) : callee.top; |
| | callee.bottom = Math.max(callee.bottom, m.bottom); |
| | } |
| | Array.prototype.forEach.call(e.children,(e)=>callee(e,depth+1)); |
| | if(0===depth){ |
| | |
| | f.extra += callee.bottom - callee.top; |
| | } |
| | return f.extra; |
| | }; |
| | } |
| | f.extra = 0; |
| | f.measure(e,0); |
| | return f.extra; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const debounce = function f(func, wait, immediate) { |
| | var timeout; |
| | if(!wait) wait = f.$defaultDelay; |
| | return function() { |
| | const context = this, args = Array.prototype.slice.call(arguments); |
| | const later = function() { |
| | timeout = undefined; |
| | if(!immediate) func.apply(context, args); |
| | }; |
| | const callNow = immediate && !timeout; |
| | clearTimeout(timeout); |
| | timeout = setTimeout(later, wait); |
| | if(callNow) func.apply(context, args); |
| | }; |
| | }; |
| | debounce.$defaultDelay = 500 ; |
| |
|
| | SF.ForceResizeKludge = (function(){ |
| | |
| | |
| | |
| | |
| | |
| | |
| | const eVisibles = EAll('.app-view'); |
| | const elemsToCount = [ |
| | |
| | |
| | E('body > header'), |
| | E('body > footer'), |
| | E('body > fieldset.options') |
| | ]; |
| | const resized = function f(){ |
| | if(f.$disabled) return; |
| | const wh = window.innerHeight; |
| | var ht; |
| | var extra = 0; |
| | elemsToCount.forEach((e)=>e ? extra += effectiveHeight(e) : false); |
| | ht = wh - extra; |
| | eVisibles.forEach(function(e){ |
| | e.style.height = |
| | e.style.maxHeight = [ |
| | "calc(", (ht>=100 ? ht : 100), "px", |
| | " - 2em",")" |
| | |
| | |
| | |
| | ].join(''); |
| | }); |
| | }; |
| | resized.$disabled = true; |
| | window.addEventListener('resize', debounce(resized, 250), false); |
| | return resized; |
| | })(); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | self.onSFLoaded = function(){ |
| | delete this.onSFLoaded; |
| |
|
| | |
| | EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden')); |
| | SF.e.main = EAll('.app-view:not(.hidden)')[0] |
| | |
| | ; |
| | if( (new URL(self.location.href).searchParams).has('about') ){ |
| | SF.toggleAbout() ; |
| | } |
| | E('#btn-reset').addEventListener('click',()=>SF.resetDb()); |
| | EAll('#btn-about, #btn-about-close').forEach((e)=>{ |
| | e.addEventListener('click',()=>SF.toggleAbout()) |
| | }); |
| | const taInput = E('#input'); |
| | const btnClearIn = E('#btn-clear'); |
| | const selectExamples = E('#select-examples'); |
| | btnClearIn.addEventListener('click',function(){ |
| | taInput.value = ''; |
| | selectExamples.selectedIndex = 0; |
| | },false); |
| | |
| | taInput.addEventListener('keydown',function(ev){ |
| | if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){ |
| | ev.preventDefault(); |
| | ev.stopPropagation(); |
| | btnShellExec.click(); |
| | } |
| | }, false); |
| | const taOutput = E('#output'); |
| | const btnClearOut = E('#btn-clear-output'); |
| | btnClearOut.addEventListener('click',function(){ |
| | taOutput.value = ''; |
| | if(SF.jqTerm) SF.jqTerm.clear(); |
| | },false); |
| | const btnShellExec = E('#btn-shell-exec'); |
| | btnShellExec.addEventListener('click',function(ev){ |
| | let sql; |
| | ev.preventDefault(); |
| | if(taInput.selectionStart<taInput.selectionEnd){ |
| | sql = taInput.value.substring(taInput.selectionStart,taInput.selectionEnd).trim(); |
| | }else{ |
| | sql = taInput.value.trim(); |
| | } |
| | if(sql) SF.dbExec(sql); |
| | },false); |
| |
|
| | const btnInterrupt = E("#btn-interrupt"); |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const preStartWork = function f(){ |
| | if(!f._){ |
| | const title = E('title'); |
| | f._ = { |
| | btnLabel: btnShellExec.innerText, |
| | pageTitle: title, |
| | pageTitleOrig: title.innerText |
| | }; |
| | } |
| | f._.pageTitle.innerText = "[working...] "+f._.pageTitleOrig; |
| | btnShellExec.setAttribute('disabled','disabled'); |
| | btnInterrupt.removeAttribute('disabled','disabled'); |
| | }; |
| |
|
| | |
| | |
| | |
| | SF.dbExec = function f(sql){ |
| | if(null!==sql && this.config.autoClearOutput){ |
| | this.echo._clearPending = true; |
| | } |
| | preStartWork(); |
| | this.wMsg('shellExec',sql); |
| | }; |
| |
|
| | SF.addMsgHandler('working',function f(ev){ |
| | switch(ev.data){ |
| | case 'start': ; return; |
| | case 'end': |
| | preStartWork._.pageTitle.innerText = preStartWork._.pageTitleOrig; |
| | btnShellExec.innerText = preStartWork._.btnLabel; |
| | btnShellExec.removeAttribute('disabled'); |
| | btnInterrupt.setAttribute('disabled','disabled'); |
| | return; |
| | } |
| | console.warn("Unhandled 'working' event:",ev.data); |
| | }); |
| |
|
| | |
| | |
| | |
| | EAll('input[type=checkbox][data-csstgt]') |
| | .forEach(function(e){ |
| | const tgt = E(e.dataset.csstgt); |
| | const cssClass = e.dataset.cssclass || 'error'; |
| | e.checked = tgt.classList.contains(cssClass); |
| | e.addEventListener('change', function(){ |
| | tgt.classList[ |
| | this.checked ? 'add' : 'remove' |
| | ](cssClass) |
| | }, false); |
| | }); |
| | |
| | |
| | |
| | EAll('input[type=checkbox][data-config]') |
| | .forEach(function(e){ |
| | const confVal = !!SF.config[e.dataset.config]; |
| | if(e.checked !== confVal){ |
| | |
| | |
| | e.checked = confVal; |
| | e.dispatchEvent(new Event('change')); |
| | } |
| | e.addEventListener('change', function(){ |
| | SF.config[this.dataset.config] = this.checked; |
| | SF.storeConfig(); |
| | }, false); |
| | }); |
| | |
| | |
| | const cmdClick = function(){SF.dbExec(this.dataset.cmd);}; |
| | EAll('button[data-cmd]').forEach( |
| | e => e.addEventListener('click', cmdClick, false) |
| | ); |
| |
|
| | btnInterrupt.addEventListener('click',function(){ |
| | SF.wMsg('interrupt'); |
| | }); |
| |
|
| | |
| | const btnExport = E('#btn-export'); |
| | const eLoadDb = E('#load-db'); |
| | const btnLoadDb = E('#btn-load-db'); |
| | btnLoadDb.addEventListener('click', ()=>eLoadDb.click()); |
| | |
| | |
| | |
| | |
| | |
| | const enableMutatingElements = function f(enable){ |
| | if(!f._elems){ |
| | f._elems = [ |
| | |
| | |
| | |
| | |
| | |
| | btnShellExec, btnExport, eLoadDb |
| | ]; |
| | } |
| | f._elems.forEach( enable |
| | ? (e)=>e.removeAttribute('disabled') |
| | : (e)=>e.setAttribute('disabled','disabled') ); |
| | }; |
| | btnExport.addEventListener('click',function(){ |
| | enableMutatingElements(false); |
| | SF.wMsg('db-export'); |
| | }); |
| | SF.addMsgHandler('db-export', function(ev){ |
| | enableMutatingElements(true); |
| | ev = ev.data; |
| | if(ev.error){ |
| | SF.echo("Export failed:",ev.error); |
| | return; |
| | } |
| | const blob = new Blob([ev.buffer], |
| | {type:"application/x-sqlite3"}); |
| | const a = document.createElement('a'); |
| | document.body.appendChild(a); |
| | a.href = window.URL.createObjectURL(blob); |
| | a.download = ev.filename; |
| | a.addEventListener('click',function(){ |
| | setTimeout(function(){ |
| | SF.echo("Exported (possibly auto-downloaded):",ev.filename); |
| | window.URL.revokeObjectURL(a.href); |
| | a.remove(); |
| | },500); |
| | }); |
| | a.click(); |
| | }); |
| | |
| | |
| | |
| | eLoadDb.addEventListener('change',function(){ |
| | const f = this.files[0]; |
| | const r = new FileReader(); |
| | const status = {loaded: 0, total: 0}; |
| | enableMutatingElements(false); |
| | r.addEventListener('loadstart', function(){ |
| | SF.echo("Loading",f.name,"..."); |
| | }); |
| | r.addEventListener('progress', function(ev){ |
| | SF.echo("Loading progress:",ev.loaded,"of",ev.total,"bytes."); |
| | }); |
| | const that = this; |
| | r.addEventListener('load', function(){ |
| | enableMutatingElements(true); |
| | SF.echo("Loaded",f.name+". Opening db..."); |
| | SF.wMsg('open',{ |
| | filename: f.name, |
| | buffer: this.result |
| | }, [this.result]); |
| | }); |
| | r.addEventListener('error',function(){ |
| | enableMutatingElements(true); |
| | SF.echo("Loading",f.name,"failed for unknown reasons."); |
| | }); |
| | r.addEventListener('abort',function(){ |
| | enableMutatingElements(true); |
| | SF.echo("Cancelled loading of",f.name+"."); |
| | }); |
| | r.readAsArrayBuffer(f); |
| | }); |
| |
|
| | EAll('fieldset.collapsible').forEach(function(fs){ |
| | const btnToggle = E(fs,'legend > .fieldset-toggle'), |
| | content = EAll(fs,':scope > div'); |
| | btnToggle.addEventListener('click', function(){ |
| | fs.classList.toggle('collapsed'); |
| | content.forEach((d)=>d.classList.toggle('hidden')); |
| | }, false); |
| | }); |
| |
|
| | |
| | (function(){ |
| | const xElem = E('#select-examples'); |
| | const examples = [ |
| | {name: "Help", sql: [ |
| | "-- ================================================\n", |
| | "-- Use ctrl-enter or shift-enter to execute sqlite3\n", |
| | "-- shell commands and SQL.\n", |
| | "-- If a subset of the text is currently selected,\n", |
| | "-- only that part is executed.\n", |
| | "-- ================================================\n", |
| | ".help\n" |
| | ]}, |
| | |
| | |
| | {name: "Box Mode", sql: ".mode box"}, |
| | {name: "Setup table T", sql:[ |
| | ".nullvalue NULL\n", |
| | "CREATE TABLE t(a,b);\n", |
| | "INSERT INTO t(a,b) VALUES('abc',123),('def',456),(NULL,789),('ghi',012);\n", |
| | "SELECT * FROM t;\n" |
| | ]}, |
| | {name: "sqlite_schema", sql: "select * from sqlite_schema"}, |
| | {name: "Mandelbrot", sql:[ |
| | "WITH RECURSIVE", |
| | " xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),\n", |
| | " yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),\n", |
| | " m(iter, cx, cy, x, y) AS (\n", |
| | " SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n", |
| | " UNION ALL\n", |
| | " SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n", |
| | " WHERE (x*x + y*y) < 4.0 AND iter<28\n", |
| | " ),\n", |
| | " m2(iter, cx, cy) AS (\n", |
| | " SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n", |
| | " ),\n", |
| | " a(t) AS (\n", |
| | " SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n", |
| | " FROM m2 GROUP BY cy\n", |
| | " )\n", |
| | "SELECT group_concat(rtrim(t),x'0a') as Mandelbrot FROM a;\n", |
| | ]}, |
| | {name: "JSON pretty-print", |
| | sql: "select json_pretty(json_object('ex',json('[52,3.14159]')))" |
| | }, |
| | {name: "JSON pretty-print (with tabs)", |
| | sql: "select json_pretty(json_object('ex',json('[52,3.14159]')),char(0x09))" |
| | } |
| | ]; |
| | const newOpt = function(lbl,val){ |
| | const o = document.createElement('option'); |
| | if(Array.isArray(val)) val = val.join(''); |
| | o.value = val; |
| | if(!val) o.setAttribute('disabled',true); |
| | o.appendChild(document.createTextNode(lbl)); |
| | xElem.appendChild(o); |
| | }; |
| | newOpt("Examples (replaces input!)"); |
| | examples.forEach((o)=>newOpt(o.name, o.sql)); |
| | |
| | xElem.selectedIndex = 0; |
| | xElem.addEventListener('change', function(){ |
| | taInput.value = '-- ' + |
| | this.selectedOptions[0].innerText + |
| | '\n' + this.value; |
| | SF.dbExec(this.value); |
| | }); |
| | })(); |
| |
|
| | |
| | if(window.jQuery && window.jQuery.terminal && SF.e.terminal){ |
| | |
| | const jqeTerm = window.jQuery(SF.e.terminal).empty(); |
| | SF.jqTerm = jqeTerm.terminal(SF.dbExec.bind(SF),{ |
| | prompt: 'sqlite> ', |
| | greetings: false |
| | }); |
| | EAll('.unhide-if-terminal-available').forEach(e=>{ |
| | e.classList.remove('hidden'); |
| | }); |
| | EAll('.remove-if-terminal-available').forEach(e=>{ |
| | e.parentElement.removeChild(e); |
| | }); |
| | |
| | const ePlaceholder = E('#terminal-button-placeholder'); |
| | ePlaceholder.classList.add('labeled-input'); |
| | ePlaceholder.classList.remove('hidden'); |
| | const btnToggleView = document.createElement('button'); |
| | btnToggleView.innerText = "Toggle view"; |
| | ePlaceholder.appendChild( btnToggleView ); |
| | btnToggleView.addEventListener('click',function f(){ |
| | const terminalOn = document.body.classList.toggle('terminal-mode'); |
| | SF.setMainView( terminalOn ? SF.e.terminal : SF.e.split ); |
| | }, false); |
| | btnToggleView.click(); |
| | } |
| | const urlParams = new URL(self.location.href).searchParams; |
| | SF.dbExec(urlParams.get('sql') || null); |
| | delete SF.ForceResizeKludge.$disabled; |
| | SF.ForceResizeKludge(); |
| | }; |
| | })(); |
| |
|