Pick a DB file and store its name in session

This commit is contained in:
b committed 2024-07-29 14:44:06 -06:00
1 parent 52ca219659
commit b80242b74b
10 files changed
+121 -6

No files matched your search

+42 -6
View File
@@ -8,9 +8,45 @@ db:exec("PRAGMA foreign_keys")
-- migrate.migrate(db)
fm = require "fullmoon"
fm.setTemplate({"/tmpl/", tmpl = "fmt"})
fm.setRoute("/hello/:name", function(r)
return fm.serveContent("hello", {name = r.params.name})
end)
fm.setRoute("/", fm.serveContent("opendb"))
fm.run()
fm.sessionOptions.secret = false
fm.setTemplate({ "/tmpl/", tmpl = "fmt" })
fm.setRoute("/static/*", fm.servePath)
fm.setRoute(fm.POST "/open", function(r)
local filename = r.params.filename
if filename == "" then filename = nil end
r.session.filename = filename
return false
end)
fm.setRoute("/open", function(r)
local files = {}
local filename = r.session.filename or ""
return fm.serveContent("opendb", { filename = filename, dir = files })
end)
fm.setRoute("/dirlist", function(r)
local function isSpecial(name)
return name == "." or name == ".." or string.sub(name, 1, 1) == "$"
end
local dirpath = r.params.dirpath
local files, directories = {}, {}
for name, kind in assert(unix.opendir(dirpath)) do
if not isSpecial(name) then
local file = { name = name, path = path.join(dirpath, name) }
if kind == unix.DT_REG then
table.insert(files, file)
elseif kind == unix.DT_DIR then
table.insert(directories, file)
end
end
end
local function compareName(f1, f2)
return f1.name < f2.name
end
table.sort(directories, compareName)
table.sort(files, compareName)
return fm.serveContent("fragment/dirlist", { files = files, directories = directories })
end)
fm.setRoute("/", fm.serveContent "home")
fm.run()
+26
View File
@@ -0,0 +1,26 @@
.filepicker {
details:has(input[type=radio]:checked)>summary,
label:has(input[type=radio]:checked) {
background-color: lightblue;
}
.directories {
margin-left: 0.7em;
}
.files>li {
list-style-type: none;
}
.directories+.files {
margin-top: 0;
}
.directories:has(+ .files) {
margin-bottom: 0;
}
max-height: 30em;
overflow-y: scroll;
}
+5
View File
@@ -0,0 +1,5 @@
body {
width: 60em;
margin-left: auto;
margin-right: auto;
}
+1
View File
@@ -0,0 +1 @@
(function(e,t){const r=t(e);if(typeof exports==="object"&&typeof exports["nodeName"]!=="string"){module.exports=r}else{e["_hyperscript"]=r;if("document"in e)e["_hyperscript"].browserInit()}})(typeof self!=="undefined"?self:this,(e=>{"use strict";const t={dynamicResolvers:[function(e,t){if(e==="Fixed"){return Number(t).toFixed()}else if(e.indexOf("Fixed:")===0){let r=e.split(":")[1];return Number(t).toFixed(parseInt(r))}}],String:function(e){if(e.toString){return e.toString()}else{return""+e}},Int:function(e){return parseInt(e)},Float:function(e){return parseFloat(e)},Number:function(e){return Number(e)},Date:function(e){return new Date(e)},Array:function(e){return Array.from(e)},JSON:function(e){return JSON.stringify(e)},Object:function(e){if(e instanceof String){e=e.toString()}if(typeof e==="string"){return JSON.parse(e)}else{return Object.assign({},e)}}};const r={attributes:"_, script, data-script",defaultTransition:"all 500ms ease-in",disableSelector:"[disable-scripting], [data-disable-scripting]",hideShowStrategies:{},conversions:t};class n{static OP_TABLE={"+":"PLUS","-":"MINUS","*":"MULTIPLY","/":"DIVIDE",".":"PERIOD","..":"ELLIPSIS","\\":"BACKSLASH",":":"COLON","%":"PERCENT","|":"PIPE","!":"EXCLAMATION","?":"QUESTION","#":"POUND","&":"AMPERSAND",$:"DOLLAR",";":"SEMI",",":"COMMA","(":"L_PAREN",")":"R_PAREN","<":"L_ANG",">":"R_ANG","<=":"LTE_ANG",">=":"GTE_ANG","==":"EQ","===":"EQQ","!=":"NEQ","!==":"NEQQ","{":"L_BRACE","}":"R_BRACE","[":"L_BRACKET","]":"R_BRACKET","=":"EQUALS"};static isValidCSSClassChar(e){return n.isAlpha(e)||n.isNumeric(e)||e==="-"||e==="_"||e===":"}static isValidCSSIDChar(e){return n.isAlpha(e)||n.isNumeric(e)||e==="-"||e==="_"||e===":"}static isWhitespace(e){return e===" "||e==="\t"||n.isNewline(e)}static positionString(e){return"[Line: "+e.line+", Column: "+e.column+"]"}static isNewline(e){return e==="\r"||e==="\n"}static isNumeric(e){return e>="0"&&e<="9"}static isAlpha(e){return e>="a"&&e<="z"||e>="A"&&e<="Z"}static isIdentifierChar(e,t){return e==="_"||e==="$"}static isReservedChar(e){return e==="`"||e==="^"}static isValidSingleQuoteStringStart(e){if(e.length>0){var t=e[e.length-1];if(t.type==="IDENTIFIER"||t.type==="CLASS_REF"||t.type==="ID_REF"){return false}if(t.op&&(t.value===">"||t.value===")")){return false}}return true}static tokenize(e,t){var r=[];var a=e;var o=0;var s=0;var u=1;var l="<START>";var c=0;function f(){return t&&c===0}while(o<a.length){if(q()==="-"&&N()==="-"&&(n.isWhitespace(I(2))||I(2)===""||I(2)==="-")||q()==="/"&&N()==="/"&&(n.isWhitespace(I(2))||I(2)===""||I(2)==="/")){h()}else if(q()==="/"&&N()==="*"&&(n.isWhitespace(I(2))||I(2)===""||I(2)==="*")){v()}else{if(n.isWhitespace(q())){r.push(A())}else if(!R()&&q()==="."&&(n.isAlpha(N())||N()==="{"||N()==="-")){r.push(d())}else if(!R()&&q()==="#"&&(n.isAlpha(N())||N()==="{")){r.push(k())}else if(q()==="["&&N()==="@"){r.push(E())}else if(q()==="@"){r.push(T())}else if(q()==="*"&&n.isAlpha(N())){r.push(y())}else if(n.isAlpha(q())||!f()&&n.isIdentifierChar(q())){r.push(x())}else if(n.isNumeric(q())){r.push(g())}else if(!f()&&(q()==='"'||q()==="`")){r.push(w())}else if(!f()&&q()==="'"){if(n.isValidSingleQuoteStringStart(r)){r.push(w())}else{r.push(b())}}else if(n.OP_TABLE[q()]){if(l==="$"&&q()==="{"){c++}if(q()==="}"){c--}r.push(b())}else if(f()||n.isReservedChar(q())){r.push(p("RESERVED",C()))}else{if(o<a.length){throw Error("Unknown token: "+q()+" ")}}}}return new i(r,[],a);function m(e,t){var r=p(e,t);r.op=true;return r}function p(e,t){return{type:e,value:t||"",start:o,end:o+1,column:s,line:u}}function h(){while(q()&&!n.isNewline(q())){C()}C()}function v(){while(q()&&!(q()==="*"&&N()==="/")){C()}C();C()}function d(){var e=p("CLASS_REF");var t=C();if(q()==="{"){e.template=true;t+=C();while(q()&&q()!=="}"){t+=C()}if(q()!=="}"){throw Error("Unterminated class reference")}else{t+=C()}}else{while(n.isValidCSSClassChar(q())){t+=C()}}e.value=t;e.end=o;return e}function E(){var e=p("ATTRIBUTE_REF");var t=C();while(o<a.length&&q()!=="]"){t+=C()}if(q()==="]"){t+=C()}e.value=t;e.end=o;return e}function T(){var e=p("ATTRIBUTE_REF");var t=C();while(n.isValidCSSIDChar(q())){t+=C()}if(q()==="="){t+=C();if(q()==='"'||q()==="'"){let e=w();t+=e.value}else if(n.isAlpha(q())||n.isNumeric(q())||n.isIdentifierChar(q())){let e=x();t+=e.value}}e.value=t;e.end=o;return e}function y(){var e=p("STYLE_REF");var t=C();while(n.isAlpha(q())||q()==="-"){t+=C()}e.value=t;e.end=o;return e}function k(){var e=p("ID_REF");var t=C();if(q()==="{"){e.template=true;t+=C();while(q()&&q()!=="}"){t+=C()}if(q()!=="}"){throw Error("Unterminated id reference")}else{C()}}else{while(n.isValidCSSIDChar(q())){t+=C()}}e.value=t;e.end=o;return e}function x(){var e=p("IDENTIFIER");var t=C();while(n.isAlpha(q())||n.isNumeric(q())||n.isIdentifierChar(q())){t+=C()}if(q()==="!"&&t==="beep"){t+=C()}e.value=t;e.end=o;return e}function g(){var e=p("NUMBER");var t=C();while(n.isNumeric(q())){t+=C()}if(q()==="."&&n.isNumeric(N())){t+=C()}while(n.isNumeric(q())){t+=C(Line truncated
+1
View File
@@ -0,0 +1 @@
var htmx=function(){"use strict";const Q={onLoad:null,process:null,on:null,off:null,trigger:null,ajax:null,find:null,findAll:null,closest:null,values:function(e,t){const n=cn(e,t||"post");return n.values},remove:null,addClass:null,removeClass:null,toggleClass:null,takeClass:null,swap:null,defineExtension:null,removeExtension:null,logAll:null,logNone:null,logger:null,config:{historyEnabled:true,historyCacheSize:10,refreshOnHistoryMiss:false,defaultSwapStyle:"innerHTML",defaultSwapDelay:0,defaultSettleDelay:20,includeIndicatorStyles:true,indicatorClass:"htmx-indicator",requestClass:"htmx-request",addedClass:"htmx-added",settlingClass:"htmx-settling",swappingClass:"htmx-swapping",allowEval:true,allowScriptTags:true,inlineScriptNonce:"",inlineStyleNonce:"",attributesToSettle:["class","style","width","height"],withCredentials:false,timeout:0,wsReconnectDelay:"full-jitter",wsBinaryType:"blob",disableSelector:"[hx-disable], [data-hx-disable]",scrollBehavior:"instant",defaultFocusScroll:false,getCacheBusterParam:false,globalViewTransitions:false,methodsThatUseUrlParams:["get","delete"],selfRequestsOnly:true,ignoreTitle:false,scrollIntoViewOnBoost:true,triggerSpecsCache:null,disableInheritance:false,responseHandling:[{code:"204",swap:false},{code:"[23]..",swap:true},{code:"[45]..",swap:false,error:true}],allowNestedOobSwaps:true},parseInterval:null,_:null,version:"2.0.1"};Q.onLoad=$;Q.process=kt;Q.on=be;Q.off=we;Q.trigger=he;Q.ajax=Hn;Q.find=r;Q.findAll=p;Q.closest=g;Q.remove=K;Q.addClass=Y;Q.removeClass=o;Q.toggleClass=W;Q.takeClass=ge;Q.swap=ze;Q.defineExtension=Un;Q.removeExtension=Bn;Q.logAll=z;Q.logNone=J;Q.parseInterval=d;Q._=_;const n={addTriggerHandler:Et,bodyContains:le,canAccessLocalStorage:j,findThisElement:Ee,filterValues:dn,swap:ze,hasAttribute:s,getAttributeValue:te,getClosestAttributeValue:re,getClosestMatch:T,getExpressionVars:Cn,getHeaders:hn,getInputValues:cn,getInternalData:ie,getSwapSpecification:pn,getTriggerSpecs:lt,getTarget:Ce,makeFragment:k,mergeObjects:ue,makeSettleInfo:xn,oobSwap:Te,querySelectorExt:fe,settleImmediately:Gt,shouldCancel:dt,triggerEvent:he,triggerErrorEvent:ae,withExtensions:Ut};const v=["get","post","put","delete","patch"];const R=v.map(function(e){return"[hx-"+e+"], [data-hx-"+e+"]"}).join(", ");const O=e("head");function e(e,t=false){return new RegExp(`<${e}(\\s[^>]*>|>)([\\s\\S]*?)<\\/${e}>`,t?"gim":"im")}function d(e){if(e==undefined){return undefined}let t=NaN;if(e.slice(-2)=="ms"){t=parseFloat(e.slice(0,-2))}else if(e.slice(-1)=="s"){t=parseFloat(e.slice(0,-1))*1e3}else if(e.slice(-1)=="m"){t=parseFloat(e.slice(0,-1))*1e3*60}else{t=parseFloat(e)}return isNaN(t)?undefined:t}function ee(e,t){return e instanceof Element&&e.getAttribute(t)}function s(e,t){return!!e.hasAttribute&&(e.hasAttribute(t)||e.hasAttribute("data-"+t))}function te(e,t){return ee(e,t)||ee(e,"data-"+t)}function u(e){const t=e.parentElement;if(!t&&e.parentNode instanceof ShadowRoot)return e.parentNode;return t}function ne(){return document}function H(e,t){return e.getRootNode?e.getRootNode({composed:t}):ne()}function T(e,t){while(e&&!t(e)){e=u(e)}return e||null}function q(e,t,n){const r=te(t,n);const o=te(t,"hx-disinherit");var i=te(t,"hx-inherit");if(e!==t){if(Q.config.disableInheritance){if(i&&(i==="*"||i.split(" ").indexOf(n)>=0)){return r}else{return null}}if(o&&(o==="*"||o.split(" ").indexOf(n)>=0)){return"unset"}}return r}function re(t,n){let r=null;T(t,function(e){return!!(r=q(t,ce(e),n))});if(r!=="unset"){return r}}function a(e,t){const n=e instanceof Element&&(e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.oMatchesSelector);return!!n&&n.call(e,t)}function L(e){const t=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i;const n=t.exec(e);if(n){return n[1].toLowerCase()}else{return""}}function N(e){const t=new DOMParser;return t.parseFromString(e,"text/html")}function A(e,t){while(t.childNodes.length>0){e.append(t.childNodes[0])}}function I(e){const t=ne().createElement("script");se(e.attributes,function(e){t.setAttribute(e.name,e.value)});t.textContent=e.textContent;t.async=false;if(Q.config.inlineScriptNonce){t.nonce=Q.config.inlineScriptNonce}return t}function P(e){return e.matches("script")&&(e.type==="text/javascript"||e.type==="module"||e.type==="")}function D(e){Array.from(e.querySelectorAll("script")).forEach(e=>{if(P(e)){const t=I(e);const n=e.parentNode;try{n.insertBefore(t,e)}catch(e){w(e)}finally{e.remove()}}})}function k(e){const t=e.replace(O,"");const n=L(t);let r;if(n==="html"){r=new DocumentFragment;const i=N(e);A(r,i.body);r.title=i.title}else if(n==="body"){r=new DocumentFragment;const i=N(t);A(r,i.body);r.title=i.title}else{const i=N('<body><template class="internal-htmx-wrapper">'+t+"</template></body>");r=i.querySelector("template").content;r.title=i.title;var o=r.querySelector("title");if(o&&o.parentNode===r){o.remove();r.title=o.innerText}}if(r){if(Q.config.allowScriptTags){D(r)}else{r.querySelectorAll("script").forEach(e=>e.remove())}}rLine truncated
+23
View File
@@ -0,0 +1,23 @@
{% if #directories ~= 0 then %}
<ul class="directories">
{% for _, dir in ipairs(directories) do %}
<details
hx-trigger="toggle once"
hx-get="/dirlist?dirpath={%& dir.path %}"
hx-target="find .details-children">
<summary>{%& dir.name %}</summary>
<div class="details-children"></div>
</details>
{% end %}
</ul>
{% end %}
{% if #files ~= 0 then %}
<ul class="files">
{% for _, file in ipairs(files) do %}
<li><label>
<input type="radio" name="filename-option" value="{%& file.path %}">
{%& file.name %}
</label></li>
{% end %}
</ul>
{% end %}
+4
View File
@@ -0,0 +1,4 @@
{% function block.pagebody() %}
<a href="/open">Open…</a>
{% end %}
{% render('layout') %}
+7
View File
@@ -1,9 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<script src="/static/js/htmx.min.js"></script>
<script src="/static/js/_hyperscript.min.js"></script>
<title>Everything is Peachy</title>
<link rel="stylesheet" href="/static/css/site.css">
{% if block.styles then for _, style in ipairs(block.styles) do %}
<link rel="stylesheet" href="{%& style %}">
{% end end %}
</head>
<body>
<h1>Peachy</h1>
{% function block.pagebody() %}
<h1>It works!</h1>
<p>But something seems to be missing…</p>
+11
View File
@@ -1,4 +1,15 @@
{% block.styles = { "/static/css/filepicker.css" } %}
{% function block.pagebody() %}
<p>Please select a database file to load.</p>
<form action="/open" method=POST>
<input id="filename-input" name="filename" value="{%& filename %}">
<input type="submit">
</form>
<div
class="filepicker"
hx-get="/dirlist?dirpath=/"
hx-trigger="load"
_="on change(target)[target.type=='radio'] set #filename-input.value to target.value">
</div>
{% end %}
{% render('layout') %}