]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Numerous layout tweaks, the most significant being that the layout now adapts to...
authorstephan <stephan@noemail.net>
Thu, 19 May 2022 15:58:13 +0000 (15:58 +0000)
committerstephan <stephan@noemail.net>
Thu, 19 May 2022 15:58:13 +0000 (15:58 +0000)
FossilOrigin-Name: 1aad3642c9fc14c25223628a309d84decc8d73a123e42d6efdc36d855b5b0666

ext/fiddle/fiddle.in.html
ext/fiddle/module-post.js
ext/fiddle/module-pre.js
manifest
manifest.uuid

index b78019565a4b58f042eab9ad9cb1bb4809e48003..a14bf5b4b4d57b5fbcedadc373064a1107e05468 100644 (file)
@@ -4,6 +4,8 @@
     <meta charset="utf-8">
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <title>sqlite3 fiddle</title>
+    <!-- script src="jqterm/jqterm-bundle.min.js"></script>
+    <link rel="stylesheet" href="jqterm/jquery.terminal.min.css"/ -->
     <style>
       /* emcscript-related styling, used during the intialization phase... */
       .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
       }
       #main-wrapper {
           display: flex;
-          flex-direction: column;
+          flex-direction: column-reverse;
+          flex: 20 1 auto;
       }
       #main-wrapper.side-by-side {
-          flex-direction: row;
+          flex-direction: row-reverse;
       }
       .ta-wrapper{
           display: flex;
           flex-direction: column;
           align-items: stretch;
+          margin: 0 0.25em;
           flex: 1 1 auto;
-          margin: 0.25em;
       }
+      .ta-wrapper.input { flex: 10 1 auto; }
+      .ta-wrapper.output { flex: 20 1 auto; }
       .ta-wrapper textarea {
           font-size: 110%;
           filter: invert(100%);
+          flex: 10 1 auto;
       }
+      /*#main-wrapper:not(.side-by-side) .ta-wrapper.input {
+          flex: 5 1 auto;
+      }*/
       .button-bar {
           display: flex;
           justify-content: center;
+          flex: 0 1 auto;
       }
       .button-bar button {
           margin: 0.25em 1em;
           margin-top: 0.5em;
       }
       .center { text-align: center; }
+
+      body.terminal-mode {
+          max-height: calc(100% - 2em);
+          display: flex;
+          flex-direction: column;
+          align-items: stretch;
+      }
+      #jqterminal {
+      }
+      .app-view {
+          flex: 20 1 auto;
+      }
+      #titlebar {
+          display: flex;
+          justify-content: space-between;
+          margin-bottom: 0.5em;
+      }
+      #view-split {
+          display: flex;
+          flex-direction: column;
+      }
     </style>
   </head>
   <body>
-    <header>sqlite3 fiddle</header>
+    <header id='titlebar'><span>sqlite3 fiddle</span></header>
     <figure id="spinner">
       <div class="spinner"></div>
       <div class='center'><strong>Initializing app...</strong></div>
     <div class="emscripten">
       <progress value="0" max="100" id="progress" hidden='1'></progress>  
     </div>
-    <fieldset class='options initially-hidden'>
-      <legend>Options</legend>
-      <div class=''>
-        <span class='labeled-input'>
-          <input type='checkbox' id='opt-cb-sbs'>
-          <label for='opt-cb-sbs'>Side-by-side</label>
-        </span>
-        <span class='labeled-input'>
-          <input type='checkbox' id='opt-cb-autoscroll'
-                 data-config='autoScrollOutput'>
-          <label for='opt-cb-autoscroll'>Auto-scroll output</label>
-        </span>
-        <span class='labeled-input'>
-          <input type='checkbox' id='opt-cb-autoclear'
-                 data-config='autoClearOutput'>
-          <label for='opt-cb-autoclear'>Auto-clear output</label>
-        </span>
-      </div>
-    </fieldset>
-    <div id='main-wrapper' class='initially-hidden'>
-      <div class='ta-wrapper'>
-        <textarea id="input" rows="8"
-                  placeholder="Shell input. Ctrl-enter/shift-enter runs it.">
+
+    <div id='jqterminal' class='app-view hidden initially-hidden'>
+      This is a placeholder for a terminal-like view.
+    </div>
+
+    <div id='view-split' class='app-view initially-hidden'>
+      <fieldset class='options'>
+        <legend>Options</legend>
+        <div class=''>
+          <span class='labeled-input'>
+            <input type='checkbox' id='opt-cb-sbs' checked>
+            <label for='opt-cb-sbs'>Side-by-side</label>
+          </span>
+          <span class='labeled-input'>
+            <input type='checkbox' id='opt-cb-autoscroll'
+                   data-config='autoScrollOutput'>
+            <label for='opt-cb-autoscroll'>Auto-scroll output</label>
+          </span>
+          <span class='labeled-input'>
+            <input type='checkbox' id='opt-cb-autoclear'
+                   data-config='autoClearOutput'>
+            <label for='opt-cb-autoclear'>Auto-clear output</label>
+          </span>
+        </div>
+      </fieldset>
+      <div id='main-wrapper' class='side-by-side'>
+        <div class='ta-wrapper input'>
+          <textarea id="input"
+                    placeholder="Shell input. Ctrl-enter/shift-enter runs it.">
 -- Use ctrl-enter or shift-enter to execute SQL
 .nullvalue NULL
 .mode box
 CREATE TABLE t(a,b);
 INSERT INTO t(a,b) VALUES('abc',123),('def',456),(NULL,789),('ghi',012);
 SELECT * FROM t;</textarea>        
-        <div class='button-bar'>
-          <button id='btn-run'>Run</button>
-          <button id='btn-clear'>Clear</button>
-          <button data-cmd='.help'>Help</button>
+          <div class='button-bar'>
+            <button id='btn-run'>Run</button>
+            <button id='btn-clear'>Clear</button>
+            <button data-cmd='.help'>Help</button>
+          </div>
         </div>
-      </div>
-      <div class='ta-wrapper'>
-        <textarea id="output" rows="18" readonly
-                  placeholder="Shell output."></textarea>
-        <div class='button-bar'>
-          <button id='btn-clear-output'>Clear</button>
+        <div class='ta-wrapper output'>
+          <textarea id="output" readonly
+                    placeholder="Shell output."></textarea>
+          <div class='button-bar'>
+            <button id='btn-clear-output'>Clear</button>
+          </div>
         </div>
       </div>
-    </div>
-    <div id='notes-caveats' class='initially-hidden'>
-      <header>
-        Notes and Caveats
-        <button id='btn-notes-caveats'>Remove</button>
-      </header>
-      <p>
-        This JavaScript application runs a C application which has been
-        compiled into WASM (Web Assembly). As such, it has certain
-        limitations. Those include, but are not limited to:
-      </p>
-      <ul>
-        <li>It <strong>cannot recover after a call to
-            <code>exit()</code></strong>. If the native code triggers
-          an exit, reloading the page is the only way to restart
-          the application. (Making the app restartable without reloading
-          the page would require significant surgery in the C code.)
-        </li>
-        <li>It <strong>cannot perform any file I/O</strong>, and running
-          any command which attempts to do so might trigger an
-          <code>exit()</code>.
-        </li>
-        <li>A number of dot-commands available in the CLI shell are
-            explicitly removed from this version of the shell.
-        </li>
-      </ul>
-    </div><!-- #notes-caveats -->
+    </div> <!-- .app-view -->
     <!-- Maintenance notes:
 
         - emscripten module init goes is in fiddle-pre.js and gets
index 5f91d0ca2535799af8716fd444fe350ea81d4eed..1ee266b0089fc931dfc9e2e73bda7ddd0d7f3799 100644 (file)
@@ -46,6 +46,7 @@ window.Module.onRuntimeInitialized = function(){
     const btnClearOut = E('#btn-clear-output');
     btnClearOut.addEventListener('click',function(){
         taOutput.value = '';
+        if(Module.jqTerm) Module.jqTerm.clear();
     },false);
     /* Sends the given text to the shell. If it's null or empty, this
        is a no-op except that the very first call will initialize the
@@ -73,10 +74,6 @@ window.Module.onRuntimeInitialized = function(){
                 this.checked ? 'add' : 'remove'
             ]('side-by-side');
         }, false);
-    E('#btn-notes-caveats')
-        .addEventListener('click', function(){
-            E('#notes-caveats').remove();
-        }, false);
 
     /* For each checkbox with data-config=X, set up a binding to
        Module.config[X]. */
@@ -95,6 +92,128 @@ window.Module.onRuntimeInitialized = function(){
         e => e.addEventListener('click', cmdClick, false)
     );
 
+
+    /**
+       Given a DOM element, this routine measures its "effective
+       height", which is the bounding top/bottom range of this element
+       and all of its children, recursively. For some DOM structure
+       cases, a parent may have a reported height of 0 even though
+       children have non-0 sizes.
+
+       Returns 0 if !e or if the element really has no height.
+    */
+    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){
+                    //console.debug("measure() height:",e.className, callee.top, callee.bottom, (callee.bottom - callee.top));
+                    f.extra += callee.bottom - callee.top;
+                }
+                return f.extra;
+            };
+        }
+        f.extra = 0;
+        f.measure(e,0);
+        return f.extra;
+    };
+
+    /**
+       Returns a function, that, as long as it continues to be invoked,
+       will not be triggered. The function will be called after it stops
+       being called for N milliseconds. If `immediate` is passed, call
+       the callback immediately and hinder future invocations until at
+       least the given time has passed.
+
+       If passed only 1 argument, or passed a falsy 2nd argument,
+       the default wait time set in this function's $defaultDelay
+       property is used.
+
+       Source: underscore.js, by way of https://davidwalsh.name/javascript-debounce-function
+    */
+    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 /*arbitrary*/;
+
+    const ForceResizeKludge = (function(){
+        /* Workaround for Safari mayhem regarding use of vh CSS units....
+           We cannot use vh units to set the terminal area size because
+           Safari chokes on that, so we calculate that height here. Larger
+           than ~95% is too big for Firefox on Android, causing the input
+           area to move off-screen. */
+        const bcl = document.body.classList;
+        const appViews = EAll('.app-view');
+        const resized = function f(){
+            if(f.$disabled) return;
+            const wh = window.innerHeight;
+            var ht;
+            var extra = 0;
+            const elemsToCount = [
+                E('body > header')
+            ];
+            elemsToCount.forEach((e)=>e ? extra += effectiveHeight(e) : false);
+            ht = wh - extra;
+            appViews.forEach(function(e){
+                e.style.height =
+                e.style.maxHeight = [
+                    "calc(", (ht>=100 ? ht : 100), "px",
+                    " - 3em"/*fudge value*/,")"
+                    /* ^^^^ hypothetically not needed, but both Chrome/FF on
+                       Linux will force scrollbars on the body if this value is
+                       too small (<0.75em in my tests). */
+                ].join('');
+            });
+        };
+        resized.$disabled = true/*gets deleted when setup is finished*/;
+        window.addEventListener('resize', debounce(resized, 250), false);
+        return resized;
+    })();
+
     Module.print(null/*clear any output generated by the init process*/);
-    doExec(null)/*sets up the db and outputs the header*/;
+    if(window.jQuery && window.jQuery.terminal){
+        /* Set up the terminal-style view... */
+        const eTerm = window.jQuery('#jqterminal').empty();
+        Module.jqTerm = eTerm.terminal(doExec,{
+            prompt: 'sqlite> ',
+            greetings: false /* note that the docs incorrectly call this 'greeting' */
+        });
+        //Module.jqTerm.clear(/*remove the "greeting"*/);
+        /* Set up a button to toggle the views... */
+        const head = E('header#titlebar');
+        const btnToggleView = jQuery("<button>Toggle View</button>")[0];
+        head.appendChild(btnToggleView);
+        btnToggleView.addEventListener('click',function f(){
+            EAll('.app-view').forEach(e=>e.classList.toggle('hidden'));
+            if(document.body.classList.toggle('terminal-mode')){
+                ForceResizeKludge();
+            }
+        }, false);
+        btnToggleView.click();
+    }
+    doExec(null/*init the db and output the header*/);
+    delete ForceResizeKludge.$disabled;
+    ForceResizeKludge();
 };
index 9e9c88f22e6c6a636c214038a77c7675180fde96..8021b243df44c76c561605899dd43cefeb22a27e 100644 (file)
@@ -24,7 +24,7 @@
             autoClearOutput: false,
             /* If true, Module.print() will echo its output to
                the console, in addition to its normal output widget. */
-            printToConsole: false,
+            printToConsole: true
         },
         preRun: [],
         postRun: [],
@@ -49,6 +49,7 @@
                     return;
                 }
                 if(window.Module.config.printToConsole) console.log(text);
+                if(window.Module.jqTerm) window.Module.jqTerm.echo(text);
                 outputElem.value += text + "\n";
                 if(window.Module.config.autoScrollOutput){
                     outputElem.scrollTop = outputElem.scrollHeight;
index 0a5f20a3c717957c25152ade5b1bbfd030ff4e43..5583e925312d1a66a17942227a4faeae9366f1f2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C fiddle\smake\starget\snow\saccepts\sfiddle_cflags=...\sfrom\sthe\sCLI\sto\soverrid\s-Ox\sand\ssuch\sfor\sone-off\sbuilds.
-D 2022-05-19T10:58:59.923
+C Numerous\slayout\stweaks,\sthe\smost\ssignificant\sbeing\sthat\sthe\slayout\snow\sadapts\sto\sthe\swindow\ssize.\sSwapped\spositions\sof\sthe\sinput/output\sareas.\sThis\sversion\ssupports,\sby\suncommenting\sa\sfew\sbits,\sa\sjquery.terminal-based\sview\sbut\salternatives\sto\sthat\s300kb\sdependency\sare\sstill\sunder\sinvestigation.
+D 2022-05-19T15:58:13.139
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -56,10 +56,10 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0
 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
 F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
 F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc
-F ext/fiddle/fiddle.in.html fc5bb8e6c13cac9880dfb41eceed3ff031d51d2a73bf66da51e5cc171e1ee28c
+F ext/fiddle/fiddle.in.html 0a176030dd3643a811007c39b8dde2271652b5a7a8597f0d7db8259a2f043111
 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf
-F ext/fiddle/module-post.js 5295dfb2bd744cb0ad03d219e8e14123b1bb8ad39054f8b65c3358df4d746cd2
-F ext/fiddle/module-pre.js baff3e5f693db09f693af0bf398c0c89cdef04bdc3ffb6ad4ed02775077fdea4
+F ext/fiddle/module-post.js 0ff724148ea206d69e39241b771006606ec11131536fe677bfaf4d8faf546299
+F ext/fiddle/module-pre.js 318fe73db5b9bf829d6f7a509ed557205ca7e64de59fcbb108d1dc4fa7aa3ac6
 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
 F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
 F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
@@ -1959,8 +1959,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 1d8d0593573f9fc8e0990a292a4b3317d8a4c323d60514d0768543dd65c24d1e
-R 95e0243279f406591d2490a8625a64de
+P 4609a4f8626ae3d8179cae27e391bd06ffda18e9ef9e1b78745b36c7e8dd25db
+R e1efe6508b92a0a525711479235be1f2
 U stephan
-Z 342f02945f9525abd872463c70c813a2
+Z 187d58546525d991c64f645554e38d64
 # Remove this line to create a well-formed Fossil manifest.
index 1b25cdb1c6a61bb6f098e2ada509e18a96c8c413..45f4f50a9619c536b1375797bb959ef7bbb86c13 100644 (file)
@@ -1 +1 @@
-4609a4f8626ae3d8179cae27e391bd06ffda18e9ef9e1b78745b36c7e8dd25db
\ No newline at end of file
+1aad3642c9fc14c25223628a309d84decc8d73a123e42d6efdc36d855b5b0666
\ No newline at end of file