[mod] wsl
This commit is contained in:
parent
b741dc5952
commit
ddd772f563
69 changed files with 26660 additions and 25940 deletions
|
|
@ -1,19 +1,19 @@
|
|||
module namespace wsa = 'app/sockets';
|
||||
import module namespace ws="http://basex.org/modules/ws";
|
||||
|
||||
|
||||
declare function wsa:wsids()
|
||||
as xs:string*
|
||||
{
|
||||
ws:ids()
|
||||
};
|
||||
|
||||
declare %rest:path('/app/api/sockets')
|
||||
function wsa:list()
|
||||
as element(ul)
|
||||
{
|
||||
<ul>{
|
||||
wsa:wsids()!<li><a href="/app/sockets/{.}">{.}</a></li>
|
||||
}</ul>
|
||||
|
||||
module namespace wsa = 'app/sockets';
|
||||
import module namespace ws="http://basex.org/modules/ws";
|
||||
|
||||
|
||||
declare function wsa:wsids()
|
||||
as xs:string*
|
||||
{
|
||||
ws:ids()
|
||||
};
|
||||
|
||||
declare %rest:path('/app/api/sockets')
|
||||
function wsa:list()
|
||||
as element(ul)
|
||||
{
|
||||
<ul>{
|
||||
wsa:wsids()!<li><a href="/app/sockets/{.}">{.}</a></li>
|
||||
}</ul>
|
||||
|
||||
};
|
||||
|
|
@ -1,26 +1,26 @@
|
|||
module namespace _ = 'app/error-reporting';
|
||||
import module namespace cm = "app/cm" at "common.xqm";
|
||||
|
||||
|
||||
declare
|
||||
%rest:error("*")
|
||||
%rest:error-param("code", "{$code}")
|
||||
%rest:error-param("description", "{$description}")
|
||||
%rest:error-param("value", "{$value}")
|
||||
%rest:error-param("module", "{$module}")
|
||||
%rest:error-param("line-number", "{$line-number}")
|
||||
%rest:error-param("column-number","{$column-number}")
|
||||
%rest:error-param("additional", "{$additional}")
|
||||
function _:error($code,$description,$value,
|
||||
$module,$line-number,$column-number,$additional) {
|
||||
let $err:=map{"code":$code, "description":$description,
|
||||
"value": _:format($value), "module": $module,
|
||||
"line-number": $line-number, "column-number": $column-number,
|
||||
"additional": _:format($additional)}
|
||||
return cm:htmx2("error.htm", $err)
|
||||
};
|
||||
|
||||
declare function _:format($item)
|
||||
as xs:string{
|
||||
serialize($item,map{"method":"basex"})
|
||||
module namespace _ = 'app/error-reporting';
|
||||
import module namespace cm = "app/cm" at "common.xqm";
|
||||
|
||||
|
||||
declare
|
||||
%rest:error("*")
|
||||
%rest:error-param("code", "{$code}")
|
||||
%rest:error-param("description", "{$description}")
|
||||
%rest:error-param("value", "{$value}")
|
||||
%rest:error-param("module", "{$module}")
|
||||
%rest:error-param("line-number", "{$line-number}")
|
||||
%rest:error-param("column-number","{$column-number}")
|
||||
%rest:error-param("additional", "{$additional}")
|
||||
function _:error($code,$description,$value,
|
||||
$module,$line-number,$column-number,$additional) {
|
||||
let $err:=map{"code":$code, "description":$description,
|
||||
"value": _:format($value), "module": $module,
|
||||
"line-number": $line-number, "column-number": $column-number,
|
||||
"additional": _:format($additional)}
|
||||
return cm:htmx2("error.htm", $err)
|
||||
};
|
||||
|
||||
declare function _:format($item)
|
||||
as xs:string{
|
||||
serialize($item,map{"method":"basex"})
|
||||
};
|
||||
|
|
@ -1,102 +1,102 @@
|
|||
xquery version '3.1';
|
||||
(:~ save conversion outputs to file
|
||||
ensures target folders created
|
||||
save multiple docs when root <wrapper> found
|
||||
optionally serialize XML with default namespace
|
||||
@author quodatum Andy Bunce
|
||||
:)
|
||||
module namespace outlet = 'urn:conversion:outlet';
|
||||
|
||||
(: serialization options
|
||||
key is arbitary name, value is BaseX serialization option map
|
||||
for xml serializations the non-standard 'ns' option supplies a namespace to use as default ' :)
|
||||
declare variable $outlet:serial:=map{
|
||||
"xvrl": map{"method":"xml","ns":"http://www.xproc.org/ns/xvrl"},
|
||||
"docbook":map{"method":"xml","ns":"http://docbook.org/ns/docbook"},
|
||||
"csv": map{"method":"text"},
|
||||
"xml": map{"method":"xml"}
|
||||
};
|
||||
|
||||
(:~save $doc to $dest unless empty,will create directories as required
|
||||
@param $opts serialization options and ns to set a default namespace :)
|
||||
declare function outlet:save($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string?{
|
||||
if (exists($dest))
|
||||
then
|
||||
let $doc:=if($opts?ns)
|
||||
then outlet:change-element-ns-deep($doc,$opts?ns,"")
|
||||
else $doc
|
||||
return (
|
||||
file:create-dir(file:parent($dest)),
|
||||
file:write($dest,$doc,map:remove($opts,"ns")),
|
||||
$dest
|
||||
)
|
||||
};
|
||||
|
||||
(:~ save file or files if node is wrapper
|
||||
@return paths to saved files
|
||||
:)
|
||||
declare function outlet:save-wrapper($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string*{
|
||||
if ($doc/wrapper)
|
||||
then $doc/wrapper/result! outlet:save(*,file:resolve-path(@href,$dest),$opts)
|
||||
else outlet:save($doc,$dest,$opts)
|
||||
};
|
||||
|
||||
(:~ from functx http://www.xqueryfunctions.com/xq/functx_change-element-ns-deep.html :)
|
||||
declare function outlet:change-element-ns-deep
|
||||
( $nodes as node()* ,
|
||||
$newns as xs:string ,
|
||||
$prefix as xs:string ) as node()* {
|
||||
|
||||
for $node in $nodes
|
||||
return if ($node instance of element())
|
||||
then (element
|
||||
{QName ($newns,
|
||||
concat($prefix,
|
||||
if ($prefix = '')
|
||||
then ''
|
||||
else ':',
|
||||
local-name($node)))}
|
||||
{$node/@*,
|
||||
outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)})
|
||||
else if ($node instance of document-node())
|
||||
then outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)
|
||||
else $node
|
||||
} ;
|
||||
|
||||
(:~ @see https://stackoverflow.com/a/8600987/3210344 :)
|
||||
declare function outlet:remove-prefixes($node as node(), $prefixes as xs:string*)
|
||||
as node(){
|
||||
typeswitch ($node)
|
||||
case element()
|
||||
return
|
||||
if ($prefixes = ('#all', prefix-from-QName(node-name($node)))) then
|
||||
element {QName(namespace-uri($node), local-name($node))} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
else
|
||||
element {node-name($node)} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
case document-node()
|
||||
return
|
||||
document {
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
default
|
||||
return $node
|
||||
};
|
||||
|
||||
(:~ relative file paths below folder $path, matching $selector :)
|
||||
declare function outlet:select($path as xs:string,$selector as map(xs:string,item()*))
|
||||
as xs:string*
|
||||
{
|
||||
file:list($path,true(),$selector?pattern)
|
||||
[some $i in $selector?include satisfies contains(.,$i)]
|
||||
[every $x in $selector?exclude satisfies not(contains(.,$x))]
|
||||
xquery version '3.1';
|
||||
(:~ save conversion outputs to file
|
||||
ensures target folders created
|
||||
save multiple docs when root <wrapper> found
|
||||
optionally serialize XML with default namespace
|
||||
@author quodatum Andy Bunce
|
||||
:)
|
||||
module namespace outlet = 'urn:conversion:outlet';
|
||||
|
||||
(: serialization options
|
||||
key is arbitary name, value is BaseX serialization option map
|
||||
for xml serializations the non-standard 'ns' option supplies a namespace to use as default ' :)
|
||||
declare variable $outlet:serial:=map{
|
||||
"xvrl": map{"method":"xml","ns":"http://www.xproc.org/ns/xvrl"},
|
||||
"docbook":map{"method":"xml","ns":"http://docbook.org/ns/docbook"},
|
||||
"csv": map{"method":"text"},
|
||||
"xml": map{"method":"xml"}
|
||||
};
|
||||
|
||||
(:~save $doc to $dest unless empty,will create directories as required
|
||||
@param $opts serialization options and ns to set a default namespace :)
|
||||
declare function outlet:save($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string?{
|
||||
if (exists($dest))
|
||||
then
|
||||
let $doc:=if($opts?ns)
|
||||
then outlet:change-element-ns-deep($doc,$opts?ns,"")
|
||||
else $doc
|
||||
return (
|
||||
file:create-dir(file:parent($dest)),
|
||||
file:write($dest,$doc,map:remove($opts,"ns")),
|
||||
$dest
|
||||
)
|
||||
};
|
||||
|
||||
(:~ save file or files if node is wrapper
|
||||
@return paths to saved files
|
||||
:)
|
||||
declare function outlet:save-wrapper($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string*{
|
||||
if ($doc/wrapper)
|
||||
then $doc/wrapper/result! outlet:save(*,file:resolve-path(@href,$dest),$opts)
|
||||
else outlet:save($doc,$dest,$opts)
|
||||
};
|
||||
|
||||
(:~ from functx http://www.xqueryfunctions.com/xq/functx_change-element-ns-deep.html :)
|
||||
declare function outlet:change-element-ns-deep
|
||||
( $nodes as node()* ,
|
||||
$newns as xs:string ,
|
||||
$prefix as xs:string ) as node()* {
|
||||
|
||||
for $node in $nodes
|
||||
return if ($node instance of element())
|
||||
then (element
|
||||
{QName ($newns,
|
||||
concat($prefix,
|
||||
if ($prefix = '')
|
||||
then ''
|
||||
else ':',
|
||||
local-name($node)))}
|
||||
{$node/@*,
|
||||
outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)})
|
||||
else if ($node instance of document-node())
|
||||
then outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)
|
||||
else $node
|
||||
} ;
|
||||
|
||||
(:~ @see https://stackoverflow.com/a/8600987/3210344 :)
|
||||
declare function outlet:remove-prefixes($node as node(), $prefixes as xs:string*)
|
||||
as node(){
|
||||
typeswitch ($node)
|
||||
case element()
|
||||
return
|
||||
if ($prefixes = ('#all', prefix-from-QName(node-name($node)))) then
|
||||
element {QName(namespace-uri($node), local-name($node))} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
else
|
||||
element {node-name($node)} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
case document-node()
|
||||
return
|
||||
document {
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
default
|
||||
return $node
|
||||
};
|
||||
|
||||
(:~ relative file paths below folder $path, matching $selector :)
|
||||
declare function outlet:select($path as xs:string,$selector as map(xs:string,item()*))
|
||||
as xs:string*
|
||||
{
|
||||
file:list($path,true(),$selector?pattern)
|
||||
[some $i in $selector?include satisfies contains(.,$i)]
|
||||
[every $x in $selector?exclude satisfies not(contains(.,$x))]
|
||||
};
|
||||
|
|
@ -1,199 +1,199 @@
|
|||
xquery version '3.1';
|
||||
(:~
|
||||
Library to manage running multiple jobs using BaseX job:eval,
|
||||
where the jobs are the execution of one function for a set of arguments
|
||||
|
||||
The function will have signature `fn($key as xs:string) as element()`
|
||||
The function will typically create outputs and have side effects.
|
||||
|
||||
State information is persisted with the storage module, using the key '_wrangle'
|
||||
It is a map{$wid: {"jobs":}}
|
||||
requires basex 10+
|
||||
@licence BSD
|
||||
@author: quodatum
|
||||
@date: 2023/02/12
|
||||
:)
|
||||
module namespace wrangle = 'urn:quodatum:wrangler';
|
||||
(:~ semantic version :)
|
||||
declare variable $wrangle:version:="1.0.0";
|
||||
(:~ used in bindings to indicate a wrangle job and as store key :)
|
||||
declare variable $wrangle:id:="_wrangle";
|
||||
|
||||
(:~
|
||||
submit wrangle jobs for each $item
|
||||
@param wrangle data{xq:...,bindings:..}
|
||||
@return unique id for the job set
|
||||
:)
|
||||
declare function wrangle:queue($items as item()*,$wrangle as map(*))
|
||||
as xs:string{
|
||||
let $wid := random:uuid()
|
||||
let $jobs := $items!job:eval($wrangle?xq,
|
||||
map:merge(($wrangle?bindings(.),map:entry($wrangle:id,$wid))),
|
||||
map{"cache":true()}
|
||||
)
|
||||
|
||||
let $this := map:entry($wid,map:entry("jobs",$jobs!map:entry(.,
|
||||
map{
|
||||
"complete":false(),
|
||||
"details":job:list-details(.)
|
||||
})))
|
||||
|
||||
let $_:=store:put($wrangle:id,map:merge((($this,wrangle:store()))))
|
||||
return $wid
|
||||
};
|
||||
|
||||
(:~ active wrangle ids :)
|
||||
declare function wrangle:active()
|
||||
as xs:string*{
|
||||
job:list()!job:bindings(.)?($wrangle:id)=>distinct-values()
|
||||
};
|
||||
|
||||
(:~ known wrangles :)
|
||||
declare function wrangle:list()
|
||||
as xs:string*{
|
||||
wrangle:store()=>map:keys()
|
||||
};
|
||||
|
||||
(:~ details for $wid wrangle :)
|
||||
declare function wrangle:list-details($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:store()=>map:get($wid)
|
||||
};
|
||||
|
||||
(:~ all wrangled jobs :)
|
||||
declare function wrangle:job-list()
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)=>map:contains($wrangle:id)]
|
||||
};
|
||||
|
||||
(:~ jobs for wrangle id :)
|
||||
declare function wrangle:job-list($wid as xs:string)
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
};
|
||||
|
||||
(:~ is wrangle id finished (or unknown) :)
|
||||
declare function wrangle:finished($wid as xs:string)
|
||||
as xs:string*{
|
||||
every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid] satisfies job:finished($job)
|
||||
};
|
||||
|
||||
(:~ wait wrangle id finished (or unknown) :)
|
||||
declare function wrangle:wait($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
let $done:=every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
satisfies empty(job:wait($job))
|
||||
return if($done) then ()
|
||||
};
|
||||
|
||||
(:~ cancel wrangle id :)
|
||||
declare function wrangle:remove($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]!job:remove(.),
|
||||
store:put($wrangle:id,wrangle:store()=>map:remove($wid))
|
||||
};
|
||||
|
||||
(:~ tally of non-zero job status for $wid "scheduled", "queued", "running", "cached" :)
|
||||
declare function wrangle:status($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!job:list-details(.)/@state/string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ job-results with no error as sequence:)
|
||||
declare function wrangle:results($wid as xs:string)
|
||||
as item()*{
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[not(?error)]?result
|
||||
};
|
||||
|
||||
(:~ error counts keyed on $err:code :)
|
||||
declare function wrangle:errors($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[?error]?result?code!string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ key is $err:code values are joblists :)
|
||||
declare function wrangle:jobs-by-error($wid as xs:string)
|
||||
as map(*){
|
||||
(for $jobId in wrangle:job-list($wid)
|
||||
let $result:=wrangle:job-result($jobId)[?error]
|
||||
where exists($result)
|
||||
return map:entry($result?result?code!string(),$jobId)
|
||||
)
|
||||
=> map:merge( map{"duplicates":"combine"})
|
||||
};
|
||||
|
||||
(:~ return key for job:)
|
||||
declare function wrangle:job-key($jobId as xs:string)
|
||||
as xs:string{
|
||||
let $b:=job:bindings($jobId)
|
||||
return $b?(map:keys($b)[. ne $wrangle:id])
|
||||
};
|
||||
|
||||
(:~ return map from peek at result:)
|
||||
declare function wrangle:job-result($jobId as xs:string)
|
||||
as map(*){
|
||||
try{
|
||||
map{
|
||||
"error":false(),
|
||||
"result": job:result($jobId,map{"keep":true()})
|
||||
}
|
||||
}catch *{
|
||||
map{
|
||||
"error":true(),
|
||||
"result": map{"description": $err:description,
|
||||
"code": $err:code,
|
||||
"line": $err:column-number,
|
||||
"additional": $err:additional,
|
||||
"value":$err:value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(:~ XQuery for background service :)
|
||||
declare function wrangle:service()
|
||||
as xs:string{
|
||||
``[
|
||||
import module namespace wrangle = 'urn:quodatum:wrangler:v1'; at "`{ static-base-uri() }`";
|
||||
let $done:=wrangle:job-list()[job:finished(.)]
|
||||
if(exists($done))
|
||||
then let $w:=store:get($wrangle:id)
|
||||
for $job in $done
|
||||
group by $wid= job:bindings($job)?($wrangle:id)
|
||||
for $job in $job
|
||||
let $_:=store:put($wrangle:id)
|
||||
]``
|
||||
|
||||
};
|
||||
(:~ schedule as service :)
|
||||
declare function wrangle:schedule-service()
|
||||
as xs:string{
|
||||
wrangle:service()
|
||||
=>job:eval((), map { 'id':$wrangle:id, 'service':true(),
|
||||
'interval': 'PT1S','log': $wrangle:id})
|
||||
};
|
||||
|
||||
(:~ cached data as map :)
|
||||
declare function wrangle:store()
|
||||
as map(*){
|
||||
store:get-or-put($wrangle:id,function(){map{}})
|
||||
};
|
||||
|
||||
(:~ @return map string->count for fold-left :)
|
||||
declare %private function wrangle:tally-count($r as map(*),$this as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($this,if(map:contains($r,$this)) then $r($this)+1 else 1),$r),
|
||||
map{"duplicates":"use-first"}
|
||||
)
|
||||
};
|
||||
(:~ @return map string->(string*) for fold-left :)
|
||||
declare %private function wrangle:tally-list($r as map(*),$key as xs:string,$value as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($key,$value),$r),
|
||||
map{"duplicates":"combine"}
|
||||
)
|
||||
xquery version '3.1';
|
||||
(:~
|
||||
Library to manage running multiple jobs using BaseX job:eval,
|
||||
where the jobs are the execution of one function for a set of arguments
|
||||
|
||||
The function will have signature `fn($key as xs:string) as element()`
|
||||
The function will typically create outputs and have side effects.
|
||||
|
||||
State information is persisted with the storage module, using the key '_wrangle'
|
||||
It is a map{$wid: {"jobs":}}
|
||||
requires basex 10+
|
||||
@licence BSD
|
||||
@author: quodatum
|
||||
@date: 2023/02/12
|
||||
:)
|
||||
module namespace wrangle = 'urn:quodatum:wrangler';
|
||||
(:~ semantic version :)
|
||||
declare variable $wrangle:version:="1.0.0";
|
||||
(:~ used in bindings to indicate a wrangle job and as store key :)
|
||||
declare variable $wrangle:id:="_wrangle";
|
||||
|
||||
(:~
|
||||
submit wrangle jobs for each $item
|
||||
@param wrangle data{xq:...,bindings:..}
|
||||
@return unique id for the job set
|
||||
:)
|
||||
declare function wrangle:queue($items as item()*,$wrangle as map(*))
|
||||
as xs:string{
|
||||
let $wid := random:uuid()
|
||||
let $jobs := $items!job:eval($wrangle?xq,
|
||||
map:merge(($wrangle?bindings(.),map:entry($wrangle:id,$wid))),
|
||||
map{"cache":true()}
|
||||
)
|
||||
|
||||
let $this := map:entry($wid,map:entry("jobs",$jobs!map:entry(.,
|
||||
map{
|
||||
"complete":false(),
|
||||
"details":job:list-details(.)
|
||||
})))
|
||||
|
||||
let $_:=store:put($wrangle:id,map:merge((($this,wrangle:store()))))
|
||||
return $wid
|
||||
};
|
||||
|
||||
(:~ active wrangle ids :)
|
||||
declare function wrangle:active()
|
||||
as xs:string*{
|
||||
job:list()!job:bindings(.)?($wrangle:id)=>distinct-values()
|
||||
};
|
||||
|
||||
(:~ known wrangles :)
|
||||
declare function wrangle:list()
|
||||
as xs:string*{
|
||||
wrangle:store()=>map:keys()
|
||||
};
|
||||
|
||||
(:~ details for $wid wrangle :)
|
||||
declare function wrangle:list-details($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:store()=>map:get($wid)
|
||||
};
|
||||
|
||||
(:~ all wrangled jobs :)
|
||||
declare function wrangle:job-list()
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)=>map:contains($wrangle:id)]
|
||||
};
|
||||
|
||||
(:~ jobs for wrangle id :)
|
||||
declare function wrangle:job-list($wid as xs:string)
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
};
|
||||
|
||||
(:~ is wrangle id finished (or unknown) :)
|
||||
declare function wrangle:finished($wid as xs:string)
|
||||
as xs:string*{
|
||||
every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid] satisfies job:finished($job)
|
||||
};
|
||||
|
||||
(:~ wait wrangle id finished (or unknown) :)
|
||||
declare function wrangle:wait($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
let $done:=every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
satisfies empty(job:wait($job))
|
||||
return if($done) then ()
|
||||
};
|
||||
|
||||
(:~ cancel wrangle id :)
|
||||
declare function wrangle:remove($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]!job:remove(.),
|
||||
store:put($wrangle:id,wrangle:store()=>map:remove($wid))
|
||||
};
|
||||
|
||||
(:~ tally of non-zero job status for $wid "scheduled", "queued", "running", "cached" :)
|
||||
declare function wrangle:status($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!job:list-details(.)/@state/string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ job-results with no error as sequence:)
|
||||
declare function wrangle:results($wid as xs:string)
|
||||
as item()*{
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[not(?error)]?result
|
||||
};
|
||||
|
||||
(:~ error counts keyed on $err:code :)
|
||||
declare function wrangle:errors($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[?error]?result?code!string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ key is $err:code values are joblists :)
|
||||
declare function wrangle:jobs-by-error($wid as xs:string)
|
||||
as map(*){
|
||||
(for $jobId in wrangle:job-list($wid)
|
||||
let $result:=wrangle:job-result($jobId)[?error]
|
||||
where exists($result)
|
||||
return map:entry($result?result?code!string(),$jobId)
|
||||
)
|
||||
=> map:merge( map{"duplicates":"combine"})
|
||||
};
|
||||
|
||||
(:~ return key for job:)
|
||||
declare function wrangle:job-key($jobId as xs:string)
|
||||
as xs:string{
|
||||
let $b:=job:bindings($jobId)
|
||||
return $b?(map:keys($b)[. ne $wrangle:id])
|
||||
};
|
||||
|
||||
(:~ return map from peek at result:)
|
||||
declare function wrangle:job-result($jobId as xs:string)
|
||||
as map(*){
|
||||
try{
|
||||
map{
|
||||
"error":false(),
|
||||
"result": job:result($jobId,map{"keep":true()})
|
||||
}
|
||||
}catch *{
|
||||
map{
|
||||
"error":true(),
|
||||
"result": map{"description": $err:description,
|
||||
"code": $err:code,
|
||||
"line": $err:column-number,
|
||||
"additional": $err:additional,
|
||||
"value":$err:value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(:~ XQuery for background service :)
|
||||
declare function wrangle:service()
|
||||
as xs:string{
|
||||
``[
|
||||
import module namespace wrangle = 'urn:quodatum:wrangler:v1'; at "`{ static-base-uri() }`";
|
||||
let $done:=wrangle:job-list()[job:finished(.)]
|
||||
if(exists($done))
|
||||
then let $w:=store:get($wrangle:id)
|
||||
for $job in $done
|
||||
group by $wid= job:bindings($job)?($wrangle:id)
|
||||
for $job in $job
|
||||
let $_:=store:put($wrangle:id)
|
||||
]``
|
||||
|
||||
};
|
||||
(:~ schedule as service :)
|
||||
declare function wrangle:schedule-service()
|
||||
as xs:string{
|
||||
wrangle:service()
|
||||
=>job:eval((), map { 'id':$wrangle:id, 'service':true(),
|
||||
'interval': 'PT1S','log': $wrangle:id})
|
||||
};
|
||||
|
||||
(:~ cached data as map :)
|
||||
declare function wrangle:store()
|
||||
as map(*){
|
||||
store:get-or-put($wrangle:id,function(){map{}})
|
||||
};
|
||||
|
||||
(:~ @return map string->count for fold-left :)
|
||||
declare %private function wrangle:tally-count($r as map(*),$this as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($this,if(map:contains($r,$this)) then $r($this)+1 else 1),$r),
|
||||
map{"duplicates":"use-first"}
|
||||
)
|
||||
};
|
||||
(:~ @return map string->(string*) for fold-left :)
|
||||
declare %private function wrangle:tally-list($r as map(*),$key as xs:string,$value as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($key,$value),$r),
|
||||
map{"duplicates":"combine"}
|
||||
)
|
||||
};
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>dev</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item href="/app/dev">DEV</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>dba</sl-breadcrumb-item>
|
||||
|
||||
</sl-breadcrumb>
|
||||
<iframe src="/dba/logs?input=%2Fapp%2F|£" allowScripts="true"
|
||||
style="width:100%;height:80vh;overflow:clip;"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>dev</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item href="/app/dev">DEV</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>dba</sl-breadcrumb-item>
|
||||
|
||||
</sl-breadcrumb>
|
||||
<iframe src="/dba/logs?input=%2Fapp%2F|£" allowScripts="true"
|
||||
style="width:100%;height:80vh;overflow:clip;"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,40 +1,40 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Dev home</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Dev</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/dba" class="nav-link" >dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/jobs" class="nav-link" >jobs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/dba/logs?input=%2Fapp%2F|£" target="_blank" class="nav-link" >DBA <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/api" target="_blank" class="nav-link" >wadl <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
list tasks etc
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Dev home</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Dev</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/dba" class="nav-link" >dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/jobs" class="nav-link" >jobs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/dba/logs?input=%2Fapp%2F|£" target="_blank" class="nav-link" >DBA <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/api" target="_blank" class="nav-link" >wadl <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
list tasks etc
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Jobs</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container-fluid">
|
||||
<div class="d-flex ">
|
||||
<sl-breadcrumb class="flex-grow-1" >
|
||||
<sl-breadcrumb-item href="/app/jobs">Jobs home</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>jobs <span class="badge bg-secondary">4</span></sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
<sl-switch id="job-refresh" checked="checked" >Refresh</sl-switch>
|
||||
</div>
|
||||
|
||||
<h2>Jobs</h2>
|
||||
<hr />
|
||||
<div hx-get="/app/jobs/table" hx-trigger="every 1s [htmx.find('#job-refresh').checked]" >
|
||||
Nothing Yet!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Jobs</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container-fluid">
|
||||
<div class="d-flex ">
|
||||
<sl-breadcrumb class="flex-grow-1" >
|
||||
<sl-breadcrumb-item href="/app/jobs">Jobs home</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>jobs <span class="badge bg-secondary">4</span></sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
<sl-switch id="job-refresh" checked="checked" >Refresh</sl-switch>
|
||||
</div>
|
||||
|
||||
<h2>Jobs</h2>
|
||||
<hr />
|
||||
<div hx-get="/app/jobs/table" hx-trigger="every 1s [htmx.find('#job-refresh').checked]" >
|
||||
Nothing Yet!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<h2 >Error: <span th:text="${code}" class="btn btn-danger"></span></h2>
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd th:text="${description}"></dd>
|
||||
<dt>Value</dt>
|
||||
<dd th:text="${value}"></dd>
|
||||
<dt>Module</dt>
|
||||
<dd ><span th:text="${module}"/>[<span th:text="${line-number}"/>,<span th:text="${column-number}"/>]</dd>
|
||||
<dt>Additional</dt>
|
||||
<dd>
|
||||
<pre th:text="${additional}"></pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<h2 >Error: <span th:text="${code}" class="btn btn-danger"></span></h2>
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd th:text="${description}"></dd>
|
||||
<dt>Value</dt>
|
||||
<dd th:text="${value}"></dd>
|
||||
<dt>Module</dt>
|
||||
<dd ><span th:text="${module}"/>[<span th:text="${line-number}"/>,<span th:text="${column-number}"/>]</dd>
|
||||
<dt>Additional</dt>
|
||||
<dd>
|
||||
<pre th:text="${additional}"></pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,64 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<html layout:decorate="~{layout.htm}"
|
||||
xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<!-- have a button POST a click via AJAX -->
|
||||
<div style="display:inline-flex">
|
||||
<p th:text="${version}">ver</p>
|
||||
<sl-button hx-get="http://v2.jokeapi.dev/joke/Any?format=txt&safe-mode&type=single" hx-target="#joke-container" variant="default" hx-confirm="Do you want a Joke?">
|
||||
<sl-icon slot="prefix" name="emoji-laughing"></sl-icon>Joke
|
||||
</sl-button>
|
||||
<p id="joke-container" style="flex-grow:4"> </p>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<form hx-put="/pdf3/api/contact/1" hx-target="this" hx-swap="outerHTML">
|
||||
<div>
|
||||
<label>First Name</label>
|
||||
<input type="text" name="firstName" value="Joe"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Last Name</label>
|
||||
<input type="text" name="lastName" value="Blow"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" value="joe@blow.com"/>
|
||||
</div>
|
||||
<button class="btn">Submit</button>
|
||||
<button class="btn" hx-get="/contact/1">Cancel</button>
|
||||
</form>
|
||||
<hr />
|
||||
<h2>Contacts</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="contacts-table" hx-get="/pdf3/api/contacts/table" hx-trigger="newContact from:body">
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Add A Contact</h2>
|
||||
<form hx-post="/pdf3/api/contacts">
|
||||
<label>
|
||||
Name
|
||||
<input name="name" type="text"/>
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input name="email" type="email"/>
|
||||
</label>
|
||||
</form>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html layout:decorate="~{layout.htm}"
|
||||
xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<!-- have a button POST a click via AJAX -->
|
||||
<div style="display:inline-flex">
|
||||
<p th:text="${version}">ver</p>
|
||||
<sl-button hx-get="http://v2.jokeapi.dev/joke/Any?format=txt&safe-mode&type=single" hx-target="#joke-container" variant="default" hx-confirm="Do you want a Joke?">
|
||||
<sl-icon slot="prefix" name="emoji-laughing"></sl-icon>Joke
|
||||
</sl-button>
|
||||
<p id="joke-container" style="flex-grow:4"> </p>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<form hx-put="/pdf3/api/contact/1" hx-target="this" hx-swap="outerHTML">
|
||||
<div>
|
||||
<label>First Name</label>
|
||||
<input type="text" name="firstName" value="Joe"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Last Name</label>
|
||||
<input type="text" name="lastName" value="Blow"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" value="joe@blow.com"/>
|
||||
</div>
|
||||
<button class="btn">Submit</button>
|
||||
<button class="btn" hx-get="/contact/1">Cancel</button>
|
||||
</form>
|
||||
<hr />
|
||||
<h2>Contacts</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="contacts-table" hx-get="/pdf3/api/contacts/table" hx-trigger="newContact from:body">
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Add A Contact</h2>
|
||||
<form hx-post="/pdf3/api/contacts">
|
||||
<label>
|
||||
Name
|
||||
<input name="name" type="text"/>
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input name="email" type="email"/>
|
||||
</label>
|
||||
</form>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,68 +1,68 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="htmx-config"
|
||||
content='{
|
||||
"responseHandling":[
|
||||
{"code":"204", "swap": false},
|
||||
{"code":"[23]..", "swap": true},
|
||||
{"code":"404", "swap": true},
|
||||
{"code":"[45]..", "swap": false, "error":true},
|
||||
{"code":"...", "swap": true}
|
||||
],
|
||||
"selfRequestsOnly": false
|
||||
}'
|
||||
/>
|
||||
<title>LSP manager</title>
|
||||
<link rel="icon" href="/app/static/favicon.png" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/missing.css@1.2.0" />
|
||||
<link rel="stylesheet" href="/app/static/styles.css" />
|
||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.js" integrity="sha384-yWakaGAFicqusuwOYEmoRjLNOC+6OFsdmwC2lbGQaRELtuVEqNzt11c2J711DeCZ" crossorigin="anonymous"></script>
|
||||
<script defer="defer" src="/app/static/script.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body hx-boost="true" hx-indicator="#indicator" data-bs-theme="light" >
|
||||
<div class='App'>
|
||||
<header id="header" class="navbar">
|
||||
|
||||
<nav >
|
||||
|
||||
<ul role="list">
|
||||
<li >
|
||||
<a class="active" aria-current="page" href="/app/home">Home</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/app/socket">connections </a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
<main id="main" class="App-main">
|
||||
<p layout:fragment="content">MAIN</p>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<button onclick="toast('Hi. '+new Date())">toast</button>
|
||||
|
||||
LoggedIn: ??
|
||||
<button type="button" class="btn btn-primary" id="liveToastBtn">Show live toast</button>
|
||||
|
||||
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="htmx-config"
|
||||
content='{
|
||||
"responseHandling":[
|
||||
{"code":"204", "swap": false},
|
||||
{"code":"[23]..", "swap": true},
|
||||
{"code":"404", "swap": true},
|
||||
{"code":"[45]..", "swap": false, "error":true},
|
||||
{"code":"...", "swap": true}
|
||||
],
|
||||
"selfRequestsOnly": false
|
||||
}'
|
||||
/>
|
||||
<title>LSP manager</title>
|
||||
<link rel="icon" href="/app/static/favicon.png" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/missing.css@1.2.0" />
|
||||
<link rel="stylesheet" href="/app/static/styles.css" />
|
||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.js" integrity="sha384-yWakaGAFicqusuwOYEmoRjLNOC+6OFsdmwC2lbGQaRELtuVEqNzt11c2J711DeCZ" crossorigin="anonymous"></script>
|
||||
<script defer="defer" src="/app/static/script.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body hx-boost="true" hx-indicator="#indicator" data-bs-theme="light" >
|
||||
<div class='App'>
|
||||
<header id="header" class="navbar">
|
||||
|
||||
<nav >
|
||||
|
||||
<ul role="list">
|
||||
<li >
|
||||
<a class="active" aria-current="page" href="/app/home">Home</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/app/socket">connections </a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
<main id="main" class="App-main">
|
||||
<p layout:fragment="content">MAIN</p>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<button onclick="toast('Hi. '+new Date())">toast</button>
|
||||
|
||||
LoggedIn: ??
|
||||
<button type="button" class="btn btn-primary" id="liveToastBtn">Show live toast</button>
|
||||
|
||||
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<form onsubmit="${login}" action="${router.guardUrl()}">
|
||||
<fieldset style="width:50%;">
|
||||
<sl-input label="User name" value="${session.login}" oninput="${html.set(session, 'login')}"
|
||||
clearable="clearable"></sl-input>
|
||||
|
||||
<sl-input value="${session.password}" oninput="${html.set(session, 'password')}" type="password"
|
||||
label="Password" password-toggle="password-toggle" clearable="clearable"></sl-input>
|
||||
<input type="checkbox" checked="${session.loggedIn}" />
|
||||
</fieldset>
|
||||
<button type="submit">Login</button>
|
||||
<button onclick="${fastlogin}">Fast</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<form onsubmit="${login}" action="${router.guardUrl()}">
|
||||
<fieldset style="width:50%;">
|
||||
<sl-input label="User name" value="${session.login}" oninput="${html.set(session, 'login')}"
|
||||
clearable="clearable"></sl-input>
|
||||
|
||||
<sl-input value="${session.password}" oninput="${html.set(session, 'password')}" type="password"
|
||||
label="Password" password-toggle="password-toggle" clearable="clearable"></sl-input>
|
||||
<input type="checkbox" checked="${session.loggedIn}" />
|
||||
</fieldset>
|
||||
<button type="submit">Login</button>
|
||||
<button onclick="${fastlogin}">Fast</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,42 +1,42 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-card class="card-overview">
|
||||
|
||||
<div slot="header">
|
||||
<sl-tooltip>
|
||||
<div th:text="${pdf.slug}" slot="content">path</div>
|
||||
<sl-badge th:text="${pdf.index}">{pdf.index}</sl-badge>
|
||||
</sl-tooltip>
|
||||
|
||||
<a th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/details"><small>{pdf}</small></a>
|
||||
<sl-button-group label="History">
|
||||
<sl-icon-button name="file-earmark-pdf" label="Settings"
|
||||
th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/view"></sl-icon-button>
|
||||
|
||||
</sl-button-group>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;">
|
||||
<div>
|
||||
<a href="/app/pdfs/{pdf.id}/details" class="holder center">
|
||||
<img src="/app/pdfs/{pdf.id}/cover" loading="{index >10?'lazy':'eager'}"
|
||||
alt="A kitten sits patiently." />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
slug:<br /><small th:text="${pdf.id}">{pdf.id}</small><br />
|
||||
</div>
|
||||
</div>
|
||||
</sl-card>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-card class="card-overview">
|
||||
|
||||
<div slot="header">
|
||||
<sl-tooltip>
|
||||
<div th:text="${pdf.slug}" slot="content">path</div>
|
||||
<sl-badge th:text="${pdf.index}">{pdf.index}</sl-badge>
|
||||
</sl-tooltip>
|
||||
|
||||
<a th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/details"><small>{pdf}</small></a>
|
||||
<sl-button-group label="History">
|
||||
<sl-icon-button name="file-earmark-pdf" label="Settings"
|
||||
th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/view"></sl-icon-button>
|
||||
|
||||
</sl-button-group>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;">
|
||||
<div>
|
||||
<a href="/app/pdfs/{pdf.id}/details" class="holder center">
|
||||
<img src="/app/pdfs/{pdf.id}/cover" loading="{index >10?'lazy':'eager'}"
|
||||
alt="A kitten sits patiently." />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
slug:<br /><small th:text="${pdf.id}">{pdf.id}</small><br />
|
||||
</div>
|
||||
</div>
|
||||
</sl-card>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>404</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<h2>Page not found:</h2>
|
||||
<ul>
|
||||
<li th:text="${path}">Page: pdf2/${ path }</li>
|
||||
<li>Method: ${ method }</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>404</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<h2>Page not found:</h2>
|
||||
<ul>
|
||||
<li th:text="${path}">Page: pdf2/${ path }</li>
|
||||
<li>Method: ${ method }</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
{
|
||||
"capabilities": {
|
||||
"textDocumentSync": 2,
|
||||
"completionProvider": {
|
||||
"resolveProvider": false,
|
||||
"triggerCharacters": [
|
||||
"\"",
|
||||
":"
|
||||
],
|
||||
"documentSelector": [
|
||||
{
|
||||
"language": "xquery"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hoverProvider": true,
|
||||
"documentSymbolProvider": true,
|
||||
"documentRangeFormattingProvider": false,
|
||||
"colorProvider": false,
|
||||
"foldingRangeProvider": false,
|
||||
"selectionRangeProvider": false,
|
||||
"documentLinkProvider": {},
|
||||
"serverInfo": {
|
||||
"name": "XQuery 4.0b Language Server",
|
||||
"version": "0.0.2"
|
||||
}
|
||||
}
|
||||
{
|
||||
"capabilities": {
|
||||
"textDocumentSync": 2,
|
||||
"completionProvider": {
|
||||
"resolveProvider": false,
|
||||
"triggerCharacters": [
|
||||
"\"",
|
||||
":"
|
||||
],
|
||||
"documentSelector": [
|
||||
{
|
||||
"language": "xquery"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hoverProvider": true,
|
||||
"documentSymbolProvider": true,
|
||||
"documentRangeFormattingProvider": false,
|
||||
"colorProvider": false,
|
||||
"foldingRangeProvider": false,
|
||||
"selectionRangeProvider": false,
|
||||
"documentLinkProvider": {},
|
||||
"serverInfo": {
|
||||
"name": "XQuery 4.0b Language Server",
|
||||
"version": "0.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"tabSize": 2,
|
||||
"insertSpaces": true,
|
||||
"trimTrailingWhitespace": true,
|
||||
"insertFinalNewline": true,
|
||||
"trimFinalNewlines": true
|
||||
{
|
||||
"tabSize": 2,
|
||||
"insertSpaces": true,
|
||||
"trimTrailingWhitespace": true,
|
||||
"insertFinalNewline": true,
|
||||
"trimFinalNewlines": true
|
||||
}
|
||||
|
|
@ -1,266 +1,266 @@
|
|||
{
|
||||
"new library module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "library module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
"@author: ",
|
||||
"@date: $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE",
|
||||
":)",
|
||||
"module namespace ${1:prefix} = '${2:http://www.example.com/}';",
|
||||
""
|
||||
],
|
||||
"description": "New library module template"
|
||||
},
|
||||
"new main module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "main module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
":)",
|
||||
"${1:expr}",
|
||||
""
|
||||
],
|
||||
"description": "New main module template"
|
||||
},
|
||||
"flowr": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"flowr"
|
||||
],
|
||||
"body": [
|
||||
"for \\$${1:var} at \\$${2:pos} in ${3:expr}",
|
||||
"let \\$${4:var2} := ${5:expr}",
|
||||
"where ${6:boolean}",
|
||||
"order by ${7:expr}",
|
||||
"return ${8:expr2}"
|
||||
],
|
||||
"description": "Full FLOWR expression"
|
||||
},
|
||||
"return": {
|
||||
"prefix": "return",
|
||||
"body": "return ${1:expr}"
|
||||
},
|
||||
"import": {
|
||||
"prefix": "import",
|
||||
"body": "import module namespace ${1:ns} = '${2:http://www.example.com/}';",
|
||||
"description": "Import module"
|
||||
},
|
||||
"if": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if (${1:boolean})",
|
||||
"then ${2:expr1}",
|
||||
"else ${3:expr2}"
|
||||
],
|
||||
"description": "If then else expression"
|
||||
},
|
||||
"module": {
|
||||
"prefix": "module",
|
||||
"body": "module namespace ${1:ns} = '${2:http://www.example.com}';"
|
||||
},
|
||||
"every": {
|
||||
"prefix": "every",
|
||||
"body": "every \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"some": {
|
||||
"prefix": "some",
|
||||
"body": "some \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"declare namespace": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"namespace"
|
||||
],
|
||||
"body": [
|
||||
"declare ${1:prefix}='${2:namespace}';",
|
||||
""
|
||||
],
|
||||
"description": "declare namespace"
|
||||
},
|
||||
"declare base-uri": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"baseuri"
|
||||
],
|
||||
"body": [
|
||||
"declare base-uri '${1:uriliteral}';",
|
||||
""
|
||||
],
|
||||
"description": "declare base-uri"
|
||||
},
|
||||
"declare option": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"option"
|
||||
],
|
||||
"body": [
|
||||
"declare option ${1:eqname} '${2:string}';",
|
||||
""
|
||||
],
|
||||
"description": "declare option"
|
||||
},
|
||||
"declare function": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"function"
|
||||
],
|
||||
"body": [
|
||||
"(:~ ${1:name} :)",
|
||||
"declare function ${2:ns}:${1:name}()",
|
||||
"as ${3:type}{",
|
||||
"${3:expr}",
|
||||
"};",
|
||||
""
|
||||
],
|
||||
"description": "declare function"
|
||||
},
|
||||
"declare variable": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"variable"
|
||||
],
|
||||
"body": [
|
||||
"(:~ \\$${1:varname} :)",
|
||||
"declare variable \\$${1:varname} := ${2:expr};",
|
||||
""
|
||||
],
|
||||
"description": "declare variable"
|
||||
},
|
||||
"switch": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "switch statement"
|
||||
},
|
||||
"typeswitch": {
|
||||
"prefix": "type",
|
||||
"body": [
|
||||
"typeswitch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "typeswitch statement"
|
||||
},
|
||||
"try": {
|
||||
"prefix": "try",
|
||||
"body": [
|
||||
"try {",
|
||||
" ${1:expr}",
|
||||
"} catch ${2:*}",
|
||||
" { ${3:expr}",
|
||||
"}"
|
||||
],
|
||||
"description": "try catch"
|
||||
},
|
||||
"tumbling": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"tumbling",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for tumbling window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "tumbling window"
|
||||
},
|
||||
"sliding": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"sliding",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for sliding window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "sliding window"
|
||||
},
|
||||
"let": {
|
||||
"prefix": "let",
|
||||
"body": "let \\$${1:varname} := ${2:expr}"
|
||||
},
|
||||
"castable": {
|
||||
"body": "castable as ${1:atomicType}"
|
||||
},
|
||||
"cast": {
|
||||
"body": "cast as ${1:atomicType}"
|
||||
},
|
||||
|
||||
"update insert": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"insert"
|
||||
],
|
||||
"body": "insert node ${1:expr} into ${2:xpath}"
|
||||
},
|
||||
"update delete": {
|
||||
"prefix": ["delete","update"],
|
||||
"body": "delete node ${1:xpath}"
|
||||
},
|
||||
"update replace node": {
|
||||
"prefix":["update","replace"],
|
||||
"body": "replace node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update replace value": {
|
||||
"prefix": [ "update",
|
||||
"replace",
|
||||
"value"
|
||||
],
|
||||
"body": "replace value of node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update rename": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"rename"
|
||||
],
|
||||
"body": "rename node ${1:xpath} as ${2:eqname}"
|
||||
},
|
||||
"copy modify return": {
|
||||
"prefix": [
|
||||
"copy",
|
||||
"modify",
|
||||
"return"
|
||||
],
|
||||
"body": [
|
||||
"copy \\$${1:varname} := ${2:node}",
|
||||
"modify ${3:updates}",
|
||||
"return \\$${1:varname}"
|
||||
]
|
||||
},
|
||||
"transform with": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"with",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} transform with {",
|
||||
" ${2:update}",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"transform update": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} update {",
|
||||
"${2:update}",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
"new library module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "library module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
"@author: ",
|
||||
"@date: $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE",
|
||||
":)",
|
||||
"module namespace ${1:prefix} = '${2:http://www.example.com/}';",
|
||||
""
|
||||
],
|
||||
"description": "New library module template"
|
||||
},
|
||||
"new main module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "main module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
":)",
|
||||
"${1:expr}",
|
||||
""
|
||||
],
|
||||
"description": "New main module template"
|
||||
},
|
||||
"flowr": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"flowr"
|
||||
],
|
||||
"body": [
|
||||
"for \\$${1:var} at \\$${2:pos} in ${3:expr}",
|
||||
"let \\$${4:var2} := ${5:expr}",
|
||||
"where ${6:boolean}",
|
||||
"order by ${7:expr}",
|
||||
"return ${8:expr2}"
|
||||
],
|
||||
"description": "Full FLOWR expression"
|
||||
},
|
||||
"return": {
|
||||
"prefix": "return",
|
||||
"body": "return ${1:expr}"
|
||||
},
|
||||
"import": {
|
||||
"prefix": "import",
|
||||
"body": "import module namespace ${1:ns} = '${2:http://www.example.com/}';",
|
||||
"description": "Import module"
|
||||
},
|
||||
"if": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if (${1:boolean})",
|
||||
"then ${2:expr1}",
|
||||
"else ${3:expr2}"
|
||||
],
|
||||
"description": "If then else expression"
|
||||
},
|
||||
"module": {
|
||||
"prefix": "module",
|
||||
"body": "module namespace ${1:ns} = '${2:http://www.example.com}';"
|
||||
},
|
||||
"every": {
|
||||
"prefix": "every",
|
||||
"body": "every \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"some": {
|
||||
"prefix": "some",
|
||||
"body": "some \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"declare namespace": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"namespace"
|
||||
],
|
||||
"body": [
|
||||
"declare ${1:prefix}='${2:namespace}';",
|
||||
""
|
||||
],
|
||||
"description": "declare namespace"
|
||||
},
|
||||
"declare base-uri": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"baseuri"
|
||||
],
|
||||
"body": [
|
||||
"declare base-uri '${1:uriliteral}';",
|
||||
""
|
||||
],
|
||||
"description": "declare base-uri"
|
||||
},
|
||||
"declare option": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"option"
|
||||
],
|
||||
"body": [
|
||||
"declare option ${1:eqname} '${2:string}';",
|
||||
""
|
||||
],
|
||||
"description": "declare option"
|
||||
},
|
||||
"declare function": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"function"
|
||||
],
|
||||
"body": [
|
||||
"(:~ ${1:name} :)",
|
||||
"declare function ${2:ns}:${1:name}()",
|
||||
"as ${3:type}{",
|
||||
"${3:expr}",
|
||||
"};",
|
||||
""
|
||||
],
|
||||
"description": "declare function"
|
||||
},
|
||||
"declare variable": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"variable"
|
||||
],
|
||||
"body": [
|
||||
"(:~ \\$${1:varname} :)",
|
||||
"declare variable \\$${1:varname} := ${2:expr};",
|
||||
""
|
||||
],
|
||||
"description": "declare variable"
|
||||
},
|
||||
"switch": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "switch statement"
|
||||
},
|
||||
"typeswitch": {
|
||||
"prefix": "type",
|
||||
"body": [
|
||||
"typeswitch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "typeswitch statement"
|
||||
},
|
||||
"try": {
|
||||
"prefix": "try",
|
||||
"body": [
|
||||
"try {",
|
||||
" ${1:expr}",
|
||||
"} catch ${2:*}",
|
||||
" { ${3:expr}",
|
||||
"}"
|
||||
],
|
||||
"description": "try catch"
|
||||
},
|
||||
"tumbling": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"tumbling",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for tumbling window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "tumbling window"
|
||||
},
|
||||
"sliding": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"sliding",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for sliding window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "sliding window"
|
||||
},
|
||||
"let": {
|
||||
"prefix": "let",
|
||||
"body": "let \\$${1:varname} := ${2:expr}"
|
||||
},
|
||||
"castable": {
|
||||
"body": "castable as ${1:atomicType}"
|
||||
},
|
||||
"cast": {
|
||||
"body": "cast as ${1:atomicType}"
|
||||
},
|
||||
|
||||
"update insert": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"insert"
|
||||
],
|
||||
"body": "insert node ${1:expr} into ${2:xpath}"
|
||||
},
|
||||
"update delete": {
|
||||
"prefix": ["delete","update"],
|
||||
"body": "delete node ${1:xpath}"
|
||||
},
|
||||
"update replace node": {
|
||||
"prefix":["update","replace"],
|
||||
"body": "replace node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update replace value": {
|
||||
"prefix": [ "update",
|
||||
"replace",
|
||||
"value"
|
||||
],
|
||||
"body": "replace value of node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update rename": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"rename"
|
||||
],
|
||||
"body": "rename node ${1:xpath} as ${2:eqname}"
|
||||
},
|
||||
"copy modify return": {
|
||||
"prefix": [
|
||||
"copy",
|
||||
"modify",
|
||||
"return"
|
||||
],
|
||||
"body": [
|
||||
"copy \\$${1:varname} := ${2:node}",
|
||||
"modify ${3:updates}",
|
||||
"return \\$${1:varname}"
|
||||
]
|
||||
},
|
||||
"transform with": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"with",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} transform with {",
|
||||
" ${2:update}",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"transform update": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} update {",
|
||||
"${2:update}",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,279 +1,279 @@
|
|||
{
|
||||
"new library module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "library module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
"@author: ",
|
||||
"@date: $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE",
|
||||
":)",
|
||||
"module namespace ${1:prefix} = '${2:http://www.example.com/}';",
|
||||
""
|
||||
],
|
||||
"description": "New library module template"
|
||||
},
|
||||
"new main module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "main module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
":)",
|
||||
"${1:expr}",
|
||||
""
|
||||
],
|
||||
"description": "New main module template"
|
||||
},
|
||||
"flowr": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"flowr"
|
||||
],
|
||||
"body": [
|
||||
"for \\$${1:var} at \\$${2:pos} in ${3:expr}",
|
||||
"let \\$${4:var2} := ${5:expr}",
|
||||
"where ${6:boolean}",
|
||||
"order by ${7:expr}",
|
||||
"return ${8:expr2}"
|
||||
],
|
||||
"description": "Full FLOWR expression"
|
||||
},
|
||||
"return": {
|
||||
"prefix": "return",
|
||||
"body": "return ${1:expr}"
|
||||
},
|
||||
"import": {
|
||||
"prefix": "import",
|
||||
"body": "import module namespace ${1:ns} = '${2:http://www.example.com/}';",
|
||||
"description": "Import module"
|
||||
},
|
||||
"if": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if (${1:boolean})",
|
||||
"then ${2:expr1}",
|
||||
"else ${3:expr2}"
|
||||
],
|
||||
"description": "If then else expression"
|
||||
},
|
||||
"module": {
|
||||
"prefix": "module",
|
||||
"body": "module namespace ${1:ns} = '${2:http://www.example.com}';"
|
||||
},
|
||||
"every": {
|
||||
"prefix": "every",
|
||||
"body": "every \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"some": {
|
||||
"prefix": "some",
|
||||
"body": "some \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"declare namespace": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"namespace"
|
||||
],
|
||||
"body": [
|
||||
"declare ${1:prefix}='${2:namespace}';",
|
||||
""
|
||||
],
|
||||
"description": "declare namespace"
|
||||
},
|
||||
"declare base-uri": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"baseuri"
|
||||
],
|
||||
"body": [
|
||||
"declare base-uri '${1:uriliteral}';",
|
||||
""
|
||||
],
|
||||
"description": "declare base-uri"
|
||||
},
|
||||
"declare option": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"option"
|
||||
],
|
||||
"body": [
|
||||
"declare option ${1:eqname} '${2:string}';",
|
||||
""
|
||||
],
|
||||
"description": "declare option"
|
||||
},
|
||||
"declare function": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"function"
|
||||
],
|
||||
"body": [
|
||||
"(:~ ${1:name} :)",
|
||||
"declare function ${2:ns}:${1:name}()",
|
||||
"as ${3:type}{",
|
||||
"${3:expr}",
|
||||
"};",
|
||||
""
|
||||
],
|
||||
"description": "declare function"
|
||||
},
|
||||
"declare variable": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"variable"
|
||||
],
|
||||
"body": [
|
||||
"(:~ \\$${1:varname} :)",
|
||||
"declare variable \\$${1:varname} := ${2:expr};",
|
||||
""
|
||||
],
|
||||
"description": "declare variable"
|
||||
},
|
||||
"switch": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "switch statement"
|
||||
},
|
||||
"typeswitch": {
|
||||
"prefix": "type",
|
||||
"body": [
|
||||
"typeswitch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "typeswitch statement"
|
||||
},
|
||||
"try": {
|
||||
"prefix": "try",
|
||||
"body": [
|
||||
"try {",
|
||||
" ${1:expr}",
|
||||
"} catch ${2:*}",
|
||||
" { ${3:expr}",
|
||||
"}"
|
||||
],
|
||||
"description": "try catch"
|
||||
},
|
||||
"tumbling": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"tumbling",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for tumbling window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "tumbling window"
|
||||
},
|
||||
"sliding": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"sliding",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for sliding window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "sliding window"
|
||||
},
|
||||
"let": {
|
||||
"prefix": "let",
|
||||
"body": "let \\$${1:varname} := ${2:expr}"
|
||||
},
|
||||
"castable": {
|
||||
"body": "castable as ${1:atomicType}"
|
||||
},
|
||||
"cast": {
|
||||
"body": "cast as ${1:atomicType}"
|
||||
},
|
||||
// Updates ***************
|
||||
"update insert": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"insert"
|
||||
],
|
||||
"body": "insert node ${1:expr} into ${2:xpath}"
|
||||
},
|
||||
"update delete": {
|
||||
"prefix": ["delete","update"],
|
||||
"body": "delete node ${1:xpath}"
|
||||
},
|
||||
"update replace node": {
|
||||
"prefix":["update","replace"],
|
||||
"body": "replace node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update replace value": {
|
||||
"prefix": [ "update",
|
||||
"replace",
|
||||
"value"
|
||||
],
|
||||
"body": "replace value of node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update rename": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"rename"
|
||||
],
|
||||
"body": "rename node ${1:xpath} as ${2:eqname}"
|
||||
},
|
||||
"copy modify return": {
|
||||
"prefix": [
|
||||
"copy",
|
||||
"modify",
|
||||
"return"
|
||||
],
|
||||
"body": [
|
||||
"copy \\$${1:varname} := ${2:node}",
|
||||
"modify ${3:updates}",
|
||||
"return \\$${1:varname}"
|
||||
]
|
||||
},
|
||||
"transform with": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"with",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} transform with {",
|
||||
" ${2:update}",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"transform update": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} update {",
|
||||
"${2:update}",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//snippet group
|
||||
// group by $${1:varname} := ${2:expr}
|
||||
//snippet order
|
||||
// order by ${1:expr} ${2:descending}
|
||||
//snippet stable
|
||||
// stable order by ${1:expr}
|
||||
//snippet count
|
||||
// count $${1:varname}
|
||||
//snippet ordered
|
||||
// ordered { ${1:expr} }
|
||||
//snippet unordered
|
||||
// unordered { ${1:expr} }
|
||||
//snippet treat
|
||||
// treat as ${1:expr}
|
||||
{
|
||||
"new library module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "library module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
"@author: ",
|
||||
"@date: $CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE",
|
||||
":)",
|
||||
"module namespace ${1:prefix} = '${2:http://www.example.com/}';",
|
||||
""
|
||||
],
|
||||
"description": "New library module template"
|
||||
},
|
||||
"new main module": {
|
||||
"isFileTemplate": true,
|
||||
"prefix": "main module",
|
||||
"body": [
|
||||
"xquery version '3.1';",
|
||||
"(:~",
|
||||
":)",
|
||||
"${1:expr}",
|
||||
""
|
||||
],
|
||||
"description": "New main module template"
|
||||
},
|
||||
"flowr": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"flowr"
|
||||
],
|
||||
"body": [
|
||||
"for \\$${1:var} at \\$${2:pos} in ${3:expr}",
|
||||
"let \\$${4:var2} := ${5:expr}",
|
||||
"where ${6:boolean}",
|
||||
"order by ${7:expr}",
|
||||
"return ${8:expr2}"
|
||||
],
|
||||
"description": "Full FLOWR expression"
|
||||
},
|
||||
"return": {
|
||||
"prefix": "return",
|
||||
"body": "return ${1:expr}"
|
||||
},
|
||||
"import": {
|
||||
"prefix": "import",
|
||||
"body": "import module namespace ${1:ns} = '${2:http://www.example.com/}';",
|
||||
"description": "Import module"
|
||||
},
|
||||
"if": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if (${1:boolean})",
|
||||
"then ${2:expr1}",
|
||||
"else ${3:expr2}"
|
||||
],
|
||||
"description": "If then else expression"
|
||||
},
|
||||
"module": {
|
||||
"prefix": "module",
|
||||
"body": "module namespace ${1:ns} = '${2:http://www.example.com}';"
|
||||
},
|
||||
"every": {
|
||||
"prefix": "every",
|
||||
"body": "every \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"some": {
|
||||
"prefix": "some",
|
||||
"body": "some \\$${1:varname} in ${2:expr} satisfies ${3:expr}"
|
||||
},
|
||||
"declare namespace": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"namespace"
|
||||
],
|
||||
"body": [
|
||||
"declare ${1:prefix}='${2:namespace}';",
|
||||
""
|
||||
],
|
||||
"description": "declare namespace"
|
||||
},
|
||||
"declare base-uri": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"baseuri"
|
||||
],
|
||||
"body": [
|
||||
"declare base-uri '${1:uriliteral}';",
|
||||
""
|
||||
],
|
||||
"description": "declare base-uri"
|
||||
},
|
||||
"declare option": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"option"
|
||||
],
|
||||
"body": [
|
||||
"declare option ${1:eqname} '${2:string}';",
|
||||
""
|
||||
],
|
||||
"description": "declare option"
|
||||
},
|
||||
"declare function": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"function"
|
||||
],
|
||||
"body": [
|
||||
"(:~ ${1:name} :)",
|
||||
"declare function ${2:ns}:${1:name}()",
|
||||
"as ${3:type}{",
|
||||
"${3:expr}",
|
||||
"};",
|
||||
""
|
||||
],
|
||||
"description": "declare function"
|
||||
},
|
||||
"declare variable": {
|
||||
"prefix": [
|
||||
"declare",
|
||||
"variable"
|
||||
],
|
||||
"body": [
|
||||
"(:~ \\$${1:varname} :)",
|
||||
"declare variable \\$${1:varname} := ${2:expr};",
|
||||
""
|
||||
],
|
||||
"description": "declare variable"
|
||||
},
|
||||
"switch": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "switch statement"
|
||||
},
|
||||
"typeswitch": {
|
||||
"prefix": "type",
|
||||
"body": [
|
||||
"typeswitch(${1:foo})",
|
||||
"case ${2:foo} return ${3:true}",
|
||||
"default return ${4:false}"
|
||||
],
|
||||
"description": "typeswitch statement"
|
||||
},
|
||||
"try": {
|
||||
"prefix": "try",
|
||||
"body": [
|
||||
"try {",
|
||||
" ${1:expr}",
|
||||
"} catch ${2:*}",
|
||||
" { ${3:expr}",
|
||||
"}"
|
||||
],
|
||||
"description": "try catch"
|
||||
},
|
||||
"tumbling": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"tumbling",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for tumbling window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "tumbling window"
|
||||
},
|
||||
"sliding": {
|
||||
"prefix": [
|
||||
"for",
|
||||
"sliding",
|
||||
"window"
|
||||
],
|
||||
"body": [
|
||||
"for sliding window \\$${1:varname} in ${2:expr}",
|
||||
"start at \\$${3:start} when ${4:expr}",
|
||||
"end at \\$${5:end} when ${6:expr}",
|
||||
"return ${7:expr}"
|
||||
],
|
||||
"description": "sliding window"
|
||||
},
|
||||
"let": {
|
||||
"prefix": "let",
|
||||
"body": "let \\$${1:varname} := ${2:expr}"
|
||||
},
|
||||
"castable": {
|
||||
"body": "castable as ${1:atomicType}"
|
||||
},
|
||||
"cast": {
|
||||
"body": "cast as ${1:atomicType}"
|
||||
},
|
||||
// Updates ***************
|
||||
"update insert": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"insert"
|
||||
],
|
||||
"body": "insert node ${1:expr} into ${2:xpath}"
|
||||
},
|
||||
"update delete": {
|
||||
"prefix": ["delete","update"],
|
||||
"body": "delete node ${1:xpath}"
|
||||
},
|
||||
"update replace node": {
|
||||
"prefix":["update","replace"],
|
||||
"body": "replace node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update replace value": {
|
||||
"prefix": [ "update",
|
||||
"replace",
|
||||
"value"
|
||||
],
|
||||
"body": "replace value of node ${1:xpath} with ${2:expr}"
|
||||
},
|
||||
"update rename": {
|
||||
"prefix": [
|
||||
"update",
|
||||
"rename"
|
||||
],
|
||||
"body": "rename node ${1:xpath} as ${2:eqname}"
|
||||
},
|
||||
"copy modify return": {
|
||||
"prefix": [
|
||||
"copy",
|
||||
"modify",
|
||||
"return"
|
||||
],
|
||||
"body": [
|
||||
"copy \\$${1:varname} := ${2:node}",
|
||||
"modify ${3:updates}",
|
||||
"return \\$${1:varname}"
|
||||
]
|
||||
},
|
||||
"transform with": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"with",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} transform with {",
|
||||
" ${2:update}",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
"transform update": {
|
||||
"prefix": [
|
||||
"transform",
|
||||
"update"
|
||||
],
|
||||
"body": [
|
||||
"${1:node} update {",
|
||||
"${2:update}",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//snippet group
|
||||
// group by $${1:varname} := ${2:expr}
|
||||
//snippet order
|
||||
// order by ${1:expr} ${2:descending}
|
||||
//snippet stable
|
||||
// stable order by ${1:expr}
|
||||
//snippet count
|
||||
// count $${1:varname}
|
||||
//snippet ordered
|
||||
// ordered { ${1:expr} }
|
||||
//snippet unordered
|
||||
// unordered { ${1:expr} }
|
||||
//snippet treat
|
||||
// treat as ${1:expr}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
module namespace lint="lsp/lint";
|
||||
(:
|
||||
Describes a problem or hint for a piece of code.
|
||||
|
||||
from: number The start position of the relevant text.
|
||||
to: number The end position. May be equal to from, though actually covering text is preferable.
|
||||
severity: "error" | "hint" | "info" | "warning". The severity of the problem. This will influence how it is displayed.
|
||||
|
||||
markClass?: string When given, add an extra CSS class to parts of the code that this diagnostic applies to.
|
||||
|
||||
source?: string An optional source string indicating where the diagnostic is coming from. You can put the name of your linter here, if applicable.
|
||||
|
||||
message: string The message associated with this diagnostic.
|
||||
|
||||
renderMessage?: fn(view: EditorView) → Node An optional custom rendering function that displays the message as a DOM node.
|
||||
|
||||
actions?: readonly Action[] An optional array of actions that can be taken on this diagnostic.
|
||||
module namespace lint="lsp/lint";
|
||||
(:
|
||||
Describes a problem or hint for a piece of code.
|
||||
|
||||
from: number The start position of the relevant text.
|
||||
to: number The end position. May be equal to from, though actually covering text is preferable.
|
||||
severity: "error" | "hint" | "info" | "warning". The severity of the problem. This will influence how it is displayed.
|
||||
|
||||
markClass?: string When given, add an extra CSS class to parts of the code that this diagnostic applies to.
|
||||
|
||||
source?: string An optional source string indicating where the diagnostic is coming from. You can put the name of your linter here, if applicable.
|
||||
|
||||
message: string The message associated with this diagnostic.
|
||||
|
||||
renderMessage?: fn(view: EditorView) → Node An optional custom rendering function that displays the message as a DOM node.
|
||||
|
||||
actions?: readonly Action[] An optional array of actions that can be taken on this diagnostic.
|
||||
:)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
job:eval(xs:anyURI("parse.xq"),
|
||||
{"textDocument":"2+3","webSocket":ws:id()},
|
||||
{ 'cache': true() }
|
||||
job:eval(xs:anyURI("parse.xq"),
|
||||
{"textDocument":"2+3","webSocket":ws:id()},
|
||||
{ 'cache': true() }
|
||||
)
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
import * as aceBuilds from 'https://esm.run/ace-builds';
|
||||
|
||||
import ace from 'https://cdn.jsdelivr.net/npm/ace/+esm'
|
||||
|
||||
/* import 'ace-builds/src-noconflict/mode-javascript';
|
||||
import 'ace-builds/src-noconflict/theme-chrome'; */
|
||||
|
||||
/* import {AceLanguageClient} from "ace-linters/build/ace-language-client";
|
||||
|
||||
const serverData = {
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: "json|json5",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
|
||||
}
|
||||
*/
|
||||
// Initialize the editor
|
||||
const editor = ace.edit("editor", {
|
||||
theme: "ace/theme/chrome",
|
||||
mode: "ace/mode/javascript",
|
||||
fontSize: "14px",
|
||||
showPrintMargin: false,
|
||||
useWorker: false // Disable web worker for this simple demo
|
||||
});
|
||||
|
||||
// Create a language provider for WebSocket
|
||||
//let languageProvider = AceLanguageClient.for(serverData);
|
||||
import * as aceBuilds from 'https://esm.run/ace-builds';
|
||||
|
||||
import ace from 'https://cdn.jsdelivr.net/npm/ace/+esm'
|
||||
|
||||
/* import 'ace-builds/src-noconflict/mode-javascript';
|
||||
import 'ace-builds/src-noconflict/theme-chrome'; */
|
||||
|
||||
/* import {AceLanguageClient} from "ace-linters/build/ace-language-client";
|
||||
|
||||
const serverData = {
|
||||
module: () => import("ace-linters/build/language-client"),
|
||||
modes: "json|json5",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
|
||||
}
|
||||
*/
|
||||
// Initialize the editor
|
||||
const editor = ace.edit("editor", {
|
||||
theme: "ace/theme/chrome",
|
||||
mode: "ace/mode/javascript",
|
||||
fontSize: "14px",
|
||||
showPrintMargin: false,
|
||||
useWorker: false // Disable web worker for this simple demo
|
||||
});
|
||||
|
||||
// Create a language provider for WebSocket
|
||||
//let languageProvider = AceLanguageClient.for(serverData);
|
||||
//languageProvider.registerEditor(editor);
|
||||
|
|
@ -1,52 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>BaseX LSP</title>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-modelist.js"></script>
|
||||
<!-- -->
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-language-client.js"></script>
|
||||
<script type="module" src="acego.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>something<button onclick="foo()">send</button><a href="/dba/logs" target="_blank">dba</a></div>
|
||||
<div id="editor" style="height: 100px">some text</div>
|
||||
|
||||
<script>
|
||||
var modelist = ace.require('ace/ext/modelist');
|
||||
if(modelist.modesByName['json'] == undefined) {
|
||||
console.log("mode doesn't exist");
|
||||
}
|
||||
var servers = [
|
||||
{
|
||||
module: () => import("XXXXXace-linters/build/language-client"),
|
||||
modes: "json",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"),
|
||||
}
|
||||
];
|
||||
let languageProvider = AceLanguageClient.for(servers);
|
||||
|
||||
ace.require("ace/ext/language_tools"); //To allow autocompletion
|
||||
var editor = ace.edit("editor", {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
mode: "json"
|
||||
});
|
||||
|
||||
languageProvider.registerEditor(editor);
|
||||
// editor.session.setMode("astro"); // mode now contains "ace/mode/javascript".
|
||||
function foo(){
|
||||
servers[0].socket.send("TTTTT")
|
||||
alert("hi")
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>BaseX LSP</title>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-modelist.js"></script>
|
||||
<!-- -->
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-language-client.js"></script>
|
||||
<script type="module" src="acego.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>something<button onclick="foo()">send</button><a href="/dba/logs" target="_blank">dba</a></div>
|
||||
<div id="editor" style="height: 100px">some text</div>
|
||||
|
||||
<script>
|
||||
var modelist = ace.require('ace/ext/modelist');
|
||||
if(modelist.modesByName['json'] == undefined) {
|
||||
console.log("mode doesn't exist");
|
||||
}
|
||||
var servers = [
|
||||
{
|
||||
module: () => import("XXXXXace-linters/build/language-client"),
|
||||
modes: "json",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"),
|
||||
}
|
||||
];
|
||||
let languageProvider = AceLanguageClient.for(servers);
|
||||
|
||||
ace.require("ace/ext/language_tools"); //To allow autocompletion
|
||||
var editor = ace.edit("editor", {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
mode: "json"
|
||||
});
|
||||
|
||||
languageProvider.registerEditor(editor);
|
||||
// editor.session.setMode("astro"); // mode now contains "ace/mode/javascript".
|
||||
function foo(){
|
||||
servers[0].socket.send("TTTTT")
|
||||
alert("hi")
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,29 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width,height=device-height" />
|
||||
<title>BaseX LSP Demo WIP</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/service-manager.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>something
|
||||
<button onclick="opts(editor)">console</button>
|
||||
<button onclick="editor.showSettingsMenu();">Settings</button>
|
||||
<a href="/dba/logs" target="_blank">dba</a>
|
||||
</header>
|
||||
<div>
|
||||
<div id="settings" style="height: 100px">sett</div>
|
||||
<div id="editor" style="height: 100px">some text</div>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width,height=device-height" />
|
||||
<title>BaseX LSP Demo WIP</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ext-language_tools.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/ace-linters.js"></script>
|
||||
<script src="https://www.unpkg.com/ace-linters@latest/build/service-manager.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>something
|
||||
<button onclick="opts(editor)">console</button>
|
||||
<button onclick="editor.showSettingsMenu();">Settings</button>
|
||||
<a href="/dba/logs" target="_blank">dba</a>
|
||||
</header>
|
||||
<div>
|
||||
<div id="settings" style="height: 100px">sett</div>
|
||||
<div id="editor" style="height: 100px">some text</div>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,42 +1,42 @@
|
|||
ace.require("ace/ext/language_tools"); //To allow autocompletion
|
||||
var editor = ace.edit("editor", {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
theme: "ace/theme/chrome",
|
||||
mode: "ace/mode/html",
|
||||
fontSize: "14px",
|
||||
showPrintMargin: false,
|
||||
useWorker: false // Disable web worker for this simple demo
|
||||
});
|
||||
|
||||
ace.require('ace/ext/settings_menu');
|
||||
editor.setTheme("ace/theme/github");
|
||||
//editor.session.setMode("ace/mode/html");
|
||||
editor.commands.addCommands([
|
||||
{
|
||||
name: "showSettingsMenu",
|
||||
bindKey: {
|
||||
win: "Ctrl-q",
|
||||
mac: "Ctrl-q"
|
||||
},
|
||||
exec: function (editor) {
|
||||
editor.showSettingsMenu();
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
]);
|
||||
var provider = LanguageProvider.fromCdn("https://www.unpkg.com/ace-linters@latest/build/");
|
||||
provider.registerEditor(editor);
|
||||
|
||||
const serverData = {
|
||||
module: () => import("https://www.unpkg.com/ace-linters@latest/build/language-client"),
|
||||
modes: "json|json5",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
|
||||
}
|
||||
|
||||
function opts(editor) {
|
||||
const modes=editor.session.$modes;
|
||||
console.log(editor.session.$modeId);
|
||||
console.log(Object.keys(modes));
|
||||
ace.require("ace/ext/language_tools"); //To allow autocompletion
|
||||
var editor = ace.edit("editor", {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
theme: "ace/theme/chrome",
|
||||
mode: "ace/mode/html",
|
||||
fontSize: "14px",
|
||||
showPrintMargin: false,
|
||||
useWorker: false // Disable web worker for this simple demo
|
||||
});
|
||||
|
||||
ace.require('ace/ext/settings_menu');
|
||||
editor.setTheme("ace/theme/github");
|
||||
//editor.session.setMode("ace/mode/html");
|
||||
editor.commands.addCommands([
|
||||
{
|
||||
name: "showSettingsMenu",
|
||||
bindKey: {
|
||||
win: "Ctrl-q",
|
||||
mac: "Ctrl-q"
|
||||
},
|
||||
exec: function (editor) {
|
||||
editor.showSettingsMenu();
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
]);
|
||||
var provider = LanguageProvider.fromCdn("https://www.unpkg.com/ace-linters@latest/build/");
|
||||
provider.registerEditor(editor);
|
||||
|
||||
const serverData = {
|
||||
module: () => import("https://www.unpkg.com/ace-linters@latest/build/language-client"),
|
||||
modes: "json|json5",
|
||||
type: "socket",
|
||||
socket: new WebSocket("ws://127.0.0.1:3000/ws/lsp"), // your websocket server address
|
||||
}
|
||||
|
||||
function opts(editor) {
|
||||
const modes=editor.session.$modes;
|
||||
console.log(editor.session.$modeId);
|
||||
console.log(Object.keys(modes));
|
||||
}
|
||||
|
|
@ -1,33 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width,height=device-height" />
|
||||
<title>BaseX LSP</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Socket <button onclick="foo()">send</button><a href="/dba/logs" target="_blank">dba</a></div>
|
||||
<script>
|
||||
|
||||
var socket = new WebSocket("ws://127.0.0.1:3000/ws/lsp") // address of your websocket server
|
||||
// Listen for possible errors
|
||||
socket.addEventListener("error", (event) => {
|
||||
console.log("WebSocket error: ", event);
|
||||
});
|
||||
socket.addEventListener("close", (event) => {
|
||||
console.log("closed", event.code, event.reason, event.wasClean);
|
||||
});
|
||||
socket.addEventListener("open", (event) => {
|
||||
setInterval(function ping() { socket.send('{"type":"ping","msg":"staying alive"}'); }, 100000);
|
||||
socket.send('{"type":"ping","msg":"Hello Server!"}');
|
||||
});
|
||||
function foo() {
|
||||
socket.send('{"type":"ping","msg":"foo!"}');
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width,height=device-height" />
|
||||
<title>BaseX LSP</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>Socket <button onclick="foo()">send</button><a href="/dba/logs" target="_blank">dba</a></div>
|
||||
<script>
|
||||
|
||||
var socket = new WebSocket("ws://127.0.0.1:3000/ws/lsp") // address of your websocket server
|
||||
// Listen for possible errors
|
||||
socket.addEventListener("error", (event) => {
|
||||
console.log("WebSocket error: ", event);
|
||||
});
|
||||
socket.addEventListener("close", (event) => {
|
||||
console.log("closed", event.code, event.reason, event.wasClean);
|
||||
});
|
||||
socket.addEventListener("open", (event) => {
|
||||
setInterval(function ping() { socket.send('{"type":"ping","msg":"staying alive"}'); }, 100000);
|
||||
socket.send('{"type":"ping","msg":"Hello Server!"}');
|
||||
});
|
||||
function foo() {
|
||||
socket.send('{"type":"ping","msg":"foo!"}');
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
header {
|
||||
background-color: aqua;
|
||||
}
|
||||
.box {
|
||||
border: 2px dotted rgb(96 139 168);
|
||||
display: flex;
|
||||
header {
|
||||
background-color: aqua;
|
||||
}
|
||||
.box {
|
||||
border: 2px dotted rgb(96 139 168);
|
||||
display: flex;
|
||||
}
|
||||
|
|
@ -1,122 +1,122 @@
|
|||
@import url("../codicon@0.0.40/codicon.css");
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--quiet-primary-seed: #e98d61;
|
||||
--quiet-content-spacing: 0.75rem;
|
||||
--quiet-form-control-height-md:0.9rem;
|
||||
--quiet-focus-width: 2px;
|
||||
--quiet-focus-offset: 0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
form header {
|
||||
background-color: burlywood;
|
||||
}
|
||||
|
||||
.page-wrap {
|
||||
background: white;
|
||||
height: 100vh ;
|
||||
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: minmax(10px, 1fr) minmax(10px, 4fr);
|
||||
grid-template-rows: min-content min-content 1fr min-content;
|
||||
|
||||
|
||||
|
||||
|
||||
details {
|
||||
|
||||
}
|
||||
|
||||
details[open] {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
summary {
|
||||
background-color: var(--quiet-neutral-fill-softer);
|
||||
}
|
||||
|
||||
/* Set editor dimensions */
|
||||
#editor {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
height: 75cqh;
|
||||
}
|
||||
|
||||
/* Stretch editor to fit inside its containing div */
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
details[open]::details-content {
|
||||
padding: 0.1em;
|
||||
border: thin solid grey;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: auto;
|
||||
|
||||
>* {
|
||||
grid-column: 1 / -1 !important;
|
||||
grid-row: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tConnect:state(unchecked) {
|
||||
outline: dashed 4px deeppink;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background: #ffecb3;
|
||||
}
|
||||
|
||||
.page-sidebar {
|
||||
grid-column: 1 / 2;
|
||||
grid-row: 2 / 4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.page-nav {
|
||||
grid-column: 2 / 3;
|
||||
background: red;
|
||||
|
||||
}
|
||||
|
||||
.page-main {
|
||||
grid-column: 2 / 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
grid-column: 1 / -1;
|
||||
background: #ffecb3;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding:2px;
|
||||
@import url("../codicon@0.0.40/codicon.css");
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--quiet-primary-seed: #e98d61;
|
||||
--quiet-content-spacing: 0.75rem;
|
||||
--quiet-form-control-height-md:0.9rem;
|
||||
--quiet-focus-width: 2px;
|
||||
--quiet-focus-offset: 0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
form header {
|
||||
background-color: burlywood;
|
||||
}
|
||||
|
||||
.page-wrap {
|
||||
background: white;
|
||||
height: 100vh ;
|
||||
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: minmax(10px, 1fr) minmax(10px, 4fr);
|
||||
grid-template-rows: min-content min-content 1fr min-content;
|
||||
|
||||
|
||||
|
||||
|
||||
details {
|
||||
|
||||
}
|
||||
|
||||
details[open] {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
summary {
|
||||
background-color: var(--quiet-neutral-fill-softer);
|
||||
}
|
||||
|
||||
/* Set editor dimensions */
|
||||
#editor {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
height: 75cqh;
|
||||
}
|
||||
|
||||
/* Stretch editor to fit inside its containing div */
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
details[open]::details-content {
|
||||
padding: 0.1em;
|
||||
border: thin solid grey;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: auto;
|
||||
|
||||
>* {
|
||||
grid-column: 1 / -1 !important;
|
||||
grid-row: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tConnect:state(unchecked) {
|
||||
outline: dashed 4px deeppink;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background: #ffecb3;
|
||||
}
|
||||
|
||||
.page-sidebar {
|
||||
grid-column: 1 / 2;
|
||||
grid-row: 2 / 4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.page-nav {
|
||||
grid-column: 2 / 3;
|
||||
background: red;
|
||||
|
||||
}
|
||||
|
||||
.page-main {
|
||||
grid-column: 2 / 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
grid-column: 1 / -1;
|
||||
background: #ffecb3;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding:2px;
|
||||
}
|
||||
|
|
@ -1,307 +1,307 @@
|
|||
<!doctype html>
|
||||
<html lang="en" class="quiet-cloak quiet-blue"
|
||||
data-quiet="/static/clients/quietui@1.6.2/dist"> <!-- also quiet-dark -->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Codemirror6 example using BaseX LSP</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
|
||||
<!-- Quiet theme + autoloader -->
|
||||
<!-- Default theme (if not already installed) -->
|
||||
<link rel="stylesheet" href="/static/clients/quietui@1.6.2/dist/themes/quiet.css">
|
||||
<!-- Quiet Restyle -->
|
||||
<link rel="stylesheet" href="/static/clients/quietui@1.6.2/dist/themes/restyle.css">
|
||||
<script type="module" src="/static/clients/quietui@1.6.2/dist/quiet.loader.js"></script>
|
||||
<script type="module" src="icons.js"></script>
|
||||
<link rel="stylesheet" href="grail.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-wrap">
|
||||
<header class="page-header">
|
||||
<quiet-dropdown placement="right">
|
||||
<quiet-button slot="trigger">File
|
||||
<quiet-icon slot="end" name="chevron-right"></quiet-icon>
|
||||
</quiet-button>
|
||||
<quiet-dropdown-item id="bnNew">
|
||||
<quiet-icon slot="start" name="file"></quiet-icon>New...
|
||||
<div slot="details">create a new doc</div>
|
||||
</quiet-dropdown-item>
|
||||
|
||||
<quiet-dropdown-item id="bnRead">
|
||||
<quiet-icon slot="start" name="folder-open"></quiet-icon>Open...
|
||||
<div slot="details">select a local file</div>
|
||||
</quiet-dropdown-item>
|
||||
<input type="file" id="fileElem" multiple accept="*/*" style="display: none;" />
|
||||
|
||||
<quiet-dropdown-item id="popover__url">
|
||||
<quiet-icon slot="start" name="link"></quiet-icon>Url...
|
||||
<div slot="details">Fetch from a url</div>
|
||||
</quiet-dropdown-item>
|
||||
</quiet-dropdown>
|
||||
|
||||
<div>
|
||||
<span class="quiet-h4">XQuery 4.0 LSP client</span>
|
||||
<quiet-toggle-icon id="tConnect" label="Connection status" size="lg"
|
||||
style="--checked-color: green;--unchecked-color: red;">
|
||||
<quiet-icon slot="unchecked" name="network-off" family="outline"></quiet-icon>
|
||||
<quiet-icon slot="checked" name="network" family="outline"></quiet-icon>
|
||||
</quiet-toggle-icon>
|
||||
<quiet-tooltip id="tipConnect" for="tConnect">I'm a tooltip</quiet-tooltip>
|
||||
</div>
|
||||
|
||||
|
||||
<quiet-button-group>
|
||||
<quiet-dropdown>
|
||||
<quiet-button slot="trigger" with-caret>Dev tools</quiet-button>
|
||||
<quiet-dropdown-item href="/app/home" target="lsp" rel="noreferrer noopener">
|
||||
LSP Manager <quiet-icon name="external-link" slot="icon"></quiet-icon></quiet-dropdown-item>
|
||||
<quiet-dropdown-item href="/dba/logs" target="dba" rel="noreferrer noopener">
|
||||
Dba <quiet-icon name="external-link" slot="icon"></quiet-icon></quiet-dropdown-item>
|
||||
<quiet-divider></quiet-divider>
|
||||
</quiet-dropdown>
|
||||
<button popovertarget="popAbout" type="button">
|
||||
<quiet-icon name="help"></quiet-icon>
|
||||
</button>
|
||||
</quiet-button-group>
|
||||
</header>
|
||||
|
||||
|
||||
<main id="main" class="page-main" style="overflow: auto;">
|
||||
<quiet-toolbar style="padding:2px;background-color: var(--quiet-neutral-fill-softer);">
|
||||
|
||||
<quiet-button-group>
|
||||
<quiet-button id="search" title="Search" icon-label="search" size="xs">
|
||||
<quiet-icon name="search"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="lint" title="Display diagnostics" icon-label="diagnostics" size="xs">
|
||||
<quiet-icon name="message-report"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="symbols2" title="symbols" icon-label="Symbols" size="xs">
|
||||
<quiet-icon name="icons"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="format" type="button" title="Format (Shift-Alt-f)" icon-label="Format" size="xs">
|
||||
<quiet-icon name="align-justified"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
</quiet-button-group>
|
||||
|
||||
<quiet-button-group>
|
||||
<button id="sync" title="Sync changes to server">
|
||||
<i class="codicon codicon-sync"></i>
|
||||
</button>
|
||||
|
||||
<button id="cmdList" title="Command and key mapping help">
|
||||
<i class="codicon codicon-record-keys"></i>
|
||||
</button>
|
||||
|
||||
<button type="button" popovertarget="popSettings" title="Settings">
|
||||
<i class="codicon codicon-settings"></i>
|
||||
</button>
|
||||
<button id="fullscreen" title="Full screen editor" type="button">
|
||||
<i class="codicon codicon-screen-full"></i>
|
||||
</button>
|
||||
|
||||
<button id="bnSave" type="button" title="save view">
|
||||
<i class="codicon codicon-git-stash"></i></button>
|
||||
|
||||
<button id="bnLoad" type="button" title="load view">
|
||||
<i class="codicon codicon-git-stash-pop"></i></button>
|
||||
|
||||
<button id="bnWordAt" type="button" title="word at">
|
||||
<i class="codicon codicon-whole-word"></i></button>
|
||||
|
||||
|
||||
<quiet-button id="bnDebug" title="Debug " icon-label="debug" size="xs">
|
||||
<quiet-icon library="codicon" name="debug"></quiet-icon>
|
||||
</quiet-button>
|
||||
</quiet-button-group>
|
||||
</quiet-toolbar>
|
||||
|
||||
<!-- Editor goes in here -->
|
||||
<div id="editor"></div>
|
||||
</main>
|
||||
|
||||
<aside class="page-sidebar">
|
||||
|
||||
<details id="workspacePanel" open="open">
|
||||
<summary class='bg-info'>WORKSPACE <i class='codicon codicon-kebab-vertical' style="float:right"></i>
|
||||
</summary>
|
||||
<quiet-listbox size="sm">
|
||||
<quiet-listbox-item value="file:///some/file.xqm">file:///some/file.xqm</quiet-listbox-item>
|
||||
<quiet-listbox-item value="2">Luna</quiet-listbox-item>
|
||||
<quiet-listbox-item value="3">Meowy McGee</quiet-listbox-item>
|
||||
<quiet-listbox-item value="4">Milo</quiet-listbox-item>
|
||||
<quiet-listbox-item value="5">Mittens</quiet-listbox-item>
|
||||
<quiet-listbox-item value="6">Oliver</quiet-listbox-item>
|
||||
|
||||
</quiet-listbox>
|
||||
|
||||
</details>
|
||||
|
||||
<details id="symPanel">
|
||||
<summary>OUTLINE
|
||||
<quiet-dropdown id="symOptions" style="display:inline-block;float:right;">
|
||||
<quiet-icon id="symTrigger" name="dots-vertical" slot="trigger"></quiet-icon>
|
||||
<quiet-dropdown-item type="checkbox" value="canvas" checked>Follow cursor</quiet-dropdown-item>
|
||||
|
||||
<quiet-divider></quiet-divider>
|
||||
<quiet-dropdown-item type="checkbox" value="position" checked>sort by:
|
||||
Position</quiet-dropdown-item>
|
||||
<quiet-dropdown-item type="checkbox" value="name">sort by: Name</quiet-dropdown-item>
|
||||
<quiet-dropdown-item type="checkbox" value="category">sort by: Category</quiet-dropdown-item>
|
||||
</quiet-dropdown>
|
||||
</summary>
|
||||
<qd-list id="symList" style="flex-grow:1;"></qd-list>
|
||||
</details>
|
||||
|
||||
<details id="msgPanel">
|
||||
<summary>MESSAGES
|
||||
<i id="msgIcon" class='codicon codicon-kebab-vertical' style="float:right"></i>
|
||||
</summary>
|
||||
<qd-list id="msgList" style="flex-grow:1;"></qd-list>
|
||||
</details>
|
||||
</aside>
|
||||
|
||||
<footer class="page-footer">
|
||||
<div style="display:flex;">
|
||||
|
||||
<div>
|
||||
<label for="iFile">File:</label>
|
||||
<input id="iFile" type="url" value="file:///some/file.xqm"
|
||||
style="width:20em;display:inline-block;" />
|
||||
|
||||
<label for="symbols">Symbols:</label>
|
||||
<select id="symbols" disabled="disabled" style="width:10em;display:inline-block;"></select>
|
||||
</div>
|
||||
</div>
|
||||
<quiet-relative-time live id="relative-time__live" numeric='always' format='short' style="width:10em;"></quiet-relative-time>
|
||||
<select id="language" style="width:10em;display:inline-block;">
|
||||
<option selected>Language</option>
|
||||
<option value="plaintext">plaintext</option>
|
||||
<option value="xquery">xquery</option>
|
||||
<option value="xml">xml</option>
|
||||
</select>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- dialogs -->
|
||||
<quiet-popover id="popWeb" for="popover__url">
|
||||
<div style="display:flex;background: #ffecb3;">
|
||||
<div style="flex: 1 1 auto;">Load a document from the web</div>
|
||||
<quiet-button icon-label="Close" appearance="text" data-popover="close">
|
||||
<quiet-icon name="x"></quiet-icon>
|
||||
</quiet-button>
|
||||
</div>
|
||||
|
||||
<form id="popUrl">
|
||||
<quiet-text-field type="url" name="url" label="URL to fetch" placeholder="http://..." with-clear required
|
||||
style="width: 20em;">
|
||||
<datalist>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/expkg-zone58/pdfbox/refs/heads/main/src/Pdfbox3.xqm">
|
||||
Pdfbox3.xqm (expkg-zone58/pdfbox) </option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/Quodatum/xqdoca/refs/heads/master/src/main/lib/model.xqm">
|
||||
model.xqm (Quodatum/xqdoca)</option>
|
||||
<option
|
||||
value="https://git.quodatum.duckdns.org/api/v1/repos/quodatum/basex-lsp/raw/webapp/lsp/lsp-text.xqm">
|
||||
lsp-text.xqm (quodatum/basex-lsp FORGEIO)</option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq">
|
||||
generator.xquery</option>
|
||||
</datalist>
|
||||
</quiet-text-field>
|
||||
<quiet-button type="submit" variant="primary">Fetch</quiet-button>
|
||||
</form>
|
||||
|
||||
</quiet-popover>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Popovers -->
|
||||
|
||||
<dialog id="popConnect" popover>
|
||||
<form>
|
||||
<header>Connect to LSP
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popConnect').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
<div id="state">🔴</div>
|
||||
<input id="iServer" type="text" style="width:25em" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="connect">connect</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<dialog id="popCmds" popover>
|
||||
<form>
|
||||
<header>Commands and keys
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popCmds').hidePopover(); "></button>
|
||||
</header>
|
||||
<div id="popHelpInfo" class="modal-body" style="height: 50vh;overflow:scroll;">
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<dialog id="popAbout" popover>
|
||||
<form>
|
||||
<header>Help</header>
|
||||
<div class="modal-body" style="height: 50vh;overflow:scroll;">
|
||||
<p>TODO help info</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- <popup-info id="popHelp">hhhh</popup-info> -->
|
||||
|
||||
<dialog id="popSettings" popover>
|
||||
<form id="fSettings">
|
||||
<header>Editor configuration
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popSettings').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input name="wrapLines" type="checkbox" class="form-check-input" id="lineWrap">
|
||||
<label class="form-check-label" for="lineWrap">Wrap lines</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input name="highlightWhitespace" type="checkbox" class="form-check-input" id="highlightWhitespace">
|
||||
<label class="form-check-label" for="highlightWhitespace">highlight Whitespace</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input name="minimap" type="checkbox" class="form-check-input" id="minimap">
|
||||
<label class="form-check-label" for="minimap">Show minimap</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- CodeMirror 6 -->
|
||||
<script src="./lsp.bundle.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
<script src="./wc-qd-list.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" class="quiet-cloak quiet-blue"
|
||||
data-quiet="/static/clients/quietui@1.6.2/dist"> <!-- also quiet-dark -->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Codemirror6 example using BaseX LSP</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
|
||||
<!-- Quiet theme + autoloader -->
|
||||
<!-- Default theme (if not already installed) -->
|
||||
<link rel="stylesheet" href="/static/clients/quietui@1.6.2/dist/themes/quiet.css">
|
||||
<!-- Quiet Restyle -->
|
||||
<link rel="stylesheet" href="/static/clients/quietui@1.6.2/dist/themes/restyle.css">
|
||||
<script type="module" src="/static/clients/quietui@1.6.2/dist/quiet.loader.js"></script>
|
||||
<script type="module" src="icons.js"></script>
|
||||
<link rel="stylesheet" href="grail.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-wrap">
|
||||
<header class="page-header">
|
||||
<quiet-dropdown placement="right">
|
||||
<quiet-button slot="trigger">File
|
||||
<quiet-icon slot="end" name="chevron-right"></quiet-icon>
|
||||
</quiet-button>
|
||||
<quiet-dropdown-item id="bnNew">
|
||||
<quiet-icon slot="start" name="file"></quiet-icon>New...
|
||||
<div slot="details">create a new doc</div>
|
||||
</quiet-dropdown-item>
|
||||
|
||||
<quiet-dropdown-item id="bnRead">
|
||||
<quiet-icon slot="start" name="folder-open"></quiet-icon>Open...
|
||||
<div slot="details">select a local file</div>
|
||||
</quiet-dropdown-item>
|
||||
<input type="file" id="fileElem" multiple accept="*/*" style="display: none;" />
|
||||
|
||||
<quiet-dropdown-item id="popover__url">
|
||||
<quiet-icon slot="start" name="link"></quiet-icon>Url...
|
||||
<div slot="details">Fetch from a url</div>
|
||||
</quiet-dropdown-item>
|
||||
</quiet-dropdown>
|
||||
|
||||
<div>
|
||||
<span class="quiet-h4">XQuery 4.0 LSP client</span>
|
||||
<quiet-toggle-icon id="tConnect" label="Connection status" size="lg"
|
||||
style="--checked-color: green;--unchecked-color: red;">
|
||||
<quiet-icon slot="unchecked" name="network-off" family="outline"></quiet-icon>
|
||||
<quiet-icon slot="checked" name="network" family="outline"></quiet-icon>
|
||||
</quiet-toggle-icon>
|
||||
<quiet-tooltip id="tipConnect" for="tConnect">I'm a tooltip</quiet-tooltip>
|
||||
</div>
|
||||
|
||||
|
||||
<quiet-button-group>
|
||||
<quiet-dropdown>
|
||||
<quiet-button slot="trigger" with-caret>Dev tools</quiet-button>
|
||||
<quiet-dropdown-item href="/app/home" target="lsp" rel="noreferrer noopener">
|
||||
LSP Manager <quiet-icon name="external-link" slot="icon"></quiet-icon></quiet-dropdown-item>
|
||||
<quiet-dropdown-item href="/dba/logs" target="dba" rel="noreferrer noopener">
|
||||
Dba <quiet-icon name="external-link" slot="icon"></quiet-icon></quiet-dropdown-item>
|
||||
<quiet-divider></quiet-divider>
|
||||
</quiet-dropdown>
|
||||
<button popovertarget="popAbout" type="button">
|
||||
<quiet-icon name="help"></quiet-icon>
|
||||
</button>
|
||||
</quiet-button-group>
|
||||
</header>
|
||||
|
||||
|
||||
<main id="main" class="page-main" style="overflow: auto;">
|
||||
<quiet-toolbar style="padding:2px;background-color: var(--quiet-neutral-fill-softer);">
|
||||
|
||||
<quiet-button-group>
|
||||
<quiet-button id="search" title="Search" icon-label="search" size="xs">
|
||||
<quiet-icon name="search"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="lint" title="Display diagnostics" icon-label="diagnostics" size="xs">
|
||||
<quiet-icon name="message-report"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="symbols2" title="symbols" icon-label="Symbols" size="xs">
|
||||
<quiet-icon name="icons"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
<quiet-button id="format" type="button" title="Format (Shift-Alt-f)" icon-label="Format" size="xs">
|
||||
<quiet-icon name="align-justified"></quiet-icon>
|
||||
</quiet-button>
|
||||
|
||||
</quiet-button-group>
|
||||
|
||||
<quiet-button-group>
|
||||
<button id="sync" title="Sync changes to server">
|
||||
<i class="codicon codicon-sync"></i>
|
||||
</button>
|
||||
|
||||
<button id="cmdList" title="Command and key mapping help">
|
||||
<i class="codicon codicon-record-keys"></i>
|
||||
</button>
|
||||
|
||||
<button type="button" popovertarget="popSettings" title="Settings">
|
||||
<i class="codicon codicon-settings"></i>
|
||||
</button>
|
||||
<button id="fullscreen" title="Full screen editor" type="button">
|
||||
<i class="codicon codicon-screen-full"></i>
|
||||
</button>
|
||||
|
||||
<button id="bnSave" type="button" title="save view">
|
||||
<i class="codicon codicon-git-stash"></i></button>
|
||||
|
||||
<button id="bnLoad" type="button" title="load view">
|
||||
<i class="codicon codicon-git-stash-pop"></i></button>
|
||||
|
||||
<button id="bnWordAt" type="button" title="word at">
|
||||
<i class="codicon codicon-whole-word"></i></button>
|
||||
|
||||
|
||||
<quiet-button id="bnDebug" title="Debug " icon-label="debug" size="xs">
|
||||
<quiet-icon library="codicon" name="debug"></quiet-icon>
|
||||
</quiet-button>
|
||||
</quiet-button-group>
|
||||
</quiet-toolbar>
|
||||
|
||||
<!-- Editor goes in here -->
|
||||
<div id="editor"></div>
|
||||
</main>
|
||||
|
||||
<aside class="page-sidebar">
|
||||
|
||||
<details id="workspacePanel" open="open">
|
||||
<summary class='bg-info'>WORKSPACE <i class='codicon codicon-kebab-vertical' style="float:right"></i>
|
||||
</summary>
|
||||
<quiet-listbox size="sm">
|
||||
<quiet-listbox-item value="file:///some/file.xqm">file:///some/file.xqm</quiet-listbox-item>
|
||||
<quiet-listbox-item value="2">Luna</quiet-listbox-item>
|
||||
<quiet-listbox-item value="3">Meowy McGee</quiet-listbox-item>
|
||||
<quiet-listbox-item value="4">Milo</quiet-listbox-item>
|
||||
<quiet-listbox-item value="5">Mittens</quiet-listbox-item>
|
||||
<quiet-listbox-item value="6">Oliver</quiet-listbox-item>
|
||||
|
||||
</quiet-listbox>
|
||||
|
||||
</details>
|
||||
|
||||
<details id="symPanel">
|
||||
<summary>OUTLINE
|
||||
<quiet-dropdown id="symOptions" style="display:inline-block;float:right;">
|
||||
<quiet-icon id="symTrigger" name="dots-vertical" slot="trigger"></quiet-icon>
|
||||
<quiet-dropdown-item type="checkbox" value="canvas" checked>Follow cursor</quiet-dropdown-item>
|
||||
|
||||
<quiet-divider></quiet-divider>
|
||||
<quiet-dropdown-item type="checkbox" value="position" checked>sort by:
|
||||
Position</quiet-dropdown-item>
|
||||
<quiet-dropdown-item type="checkbox" value="name">sort by: Name</quiet-dropdown-item>
|
||||
<quiet-dropdown-item type="checkbox" value="category">sort by: Category</quiet-dropdown-item>
|
||||
</quiet-dropdown>
|
||||
</summary>
|
||||
<qd-list id="symList" style="flex-grow:1;"></qd-list>
|
||||
</details>
|
||||
|
||||
<details id="msgPanel">
|
||||
<summary>MESSAGES
|
||||
<i id="msgIcon" class='codicon codicon-kebab-vertical' style="float:right"></i>
|
||||
</summary>
|
||||
<qd-list id="msgList" style="flex-grow:1;"></qd-list>
|
||||
</details>
|
||||
</aside>
|
||||
|
||||
<footer class="page-footer">
|
||||
<div style="display:flex;">
|
||||
|
||||
<div>
|
||||
<label for="iFile">File:</label>
|
||||
<input id="iFile" type="url" value="file:///some/file.xqm"
|
||||
style="width:20em;display:inline-block;" />
|
||||
|
||||
<label for="symbols">Symbols:</label>
|
||||
<select id="symbols" disabled="disabled" style="width:10em;display:inline-block;"></select>
|
||||
</div>
|
||||
</div>
|
||||
<quiet-relative-time live id="relative-time__live" numeric='always' format='short' style="width:10em;"></quiet-relative-time>
|
||||
<select id="language" style="width:10em;display:inline-block;">
|
||||
<option selected>Language</option>
|
||||
<option value="plaintext">plaintext</option>
|
||||
<option value="xquery">xquery</option>
|
||||
<option value="xml">xml</option>
|
||||
</select>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- dialogs -->
|
||||
<quiet-popover id="popWeb" for="popover__url">
|
||||
<div style="display:flex;background: #ffecb3;">
|
||||
<div style="flex: 1 1 auto;">Load a document from the web</div>
|
||||
<quiet-button icon-label="Close" appearance="text" data-popover="close">
|
||||
<quiet-icon name="x"></quiet-icon>
|
||||
</quiet-button>
|
||||
</div>
|
||||
|
||||
<form id="popUrl">
|
||||
<quiet-text-field type="url" name="url" label="URL to fetch" placeholder="http://..." with-clear required
|
||||
style="width: 20em;">
|
||||
<datalist>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/expkg-zone58/pdfbox/refs/heads/main/src/Pdfbox3.xqm">
|
||||
Pdfbox3.xqm (expkg-zone58/pdfbox) </option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/Quodatum/xqdoca/refs/heads/master/src/main/lib/model.xqm">
|
||||
model.xqm (Quodatum/xqdoca)</option>
|
||||
<option
|
||||
value="https://git.quodatum.duckdns.org/api/v1/repos/quodatum/basex-lsp/raw/webapp/lsp/lsp-text.xqm">
|
||||
lsp-text.xqm (quodatum/basex-lsp FORGEIO)</option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq">
|
||||
generator.xquery</option>
|
||||
</datalist>
|
||||
</quiet-text-field>
|
||||
<quiet-button type="submit" variant="primary">Fetch</quiet-button>
|
||||
</form>
|
||||
|
||||
</quiet-popover>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Popovers -->
|
||||
|
||||
<dialog id="popConnect" popover>
|
||||
<form>
|
||||
<header>Connect to LSP
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popConnect').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
<div id="state">🔴</div>
|
||||
<input id="iServer" type="text" style="width:25em" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="connect">connect</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<dialog id="popCmds" popover>
|
||||
<form>
|
||||
<header>Commands and keys
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popCmds').hidePopover(); "></button>
|
||||
</header>
|
||||
<div id="popHelpInfo" class="modal-body" style="height: 50vh;overflow:scroll;">
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<dialog id="popAbout" popover>
|
||||
<form>
|
||||
<header>Help</header>
|
||||
<div class="modal-body" style="height: 50vh;overflow:scroll;">
|
||||
<p>TODO help info</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- <popup-info id="popHelp">hhhh</popup-info> -->
|
||||
|
||||
<dialog id="popSettings" popover>
|
||||
<form id="fSettings">
|
||||
<header>Editor configuration
|
||||
<button type="button" class="btn-close" aria-label="Close"
|
||||
onclick="$('popSettings').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input name="wrapLines" type="checkbox" class="form-check-input" id="lineWrap">
|
||||
<label class="form-check-label" for="lineWrap">Wrap lines</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input name="highlightWhitespace" type="checkbox" class="form-check-input" id="highlightWhitespace">
|
||||
<label class="form-check-label" for="highlightWhitespace">highlight Whitespace</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input name="minimap" type="checkbox" class="form-check-input" id="minimap">
|
||||
<label class="form-check-label" for="minimap">Show minimap</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- CodeMirror 6 -->
|
||||
<script src="./lsp.bundle.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
<script src="./wc-qd-list.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { registerIconLibrary } from '/static/clients/quietui@1.6.2/dist/quiet.loader.js';
|
||||
|
||||
registerIconLibrary('codicon', {
|
||||
resolve: (name, family) => {
|
||||
return `/static/clients/codicon@0.0.40/icons/${name}.svg`
|
||||
import { registerIconLibrary } from '/static/clients/quietui@1.6.2/dist/quiet.loader.js';
|
||||
|
||||
registerIconLibrary('codicon', {
|
||||
resolve: (name, family) => {
|
||||
return `/static/clients/codicon@0.0.40/icons/${name}.svg`
|
||||
}});
|
||||
|
|
@ -1,196 +1,196 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Codemirror6 example using BaseX LSP</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
<link href="../bootstrap@5.3.7.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="grail.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="page-wrap">
|
||||
<header class="page-header">
|
||||
<nav class="navbar bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a id="help" class="navbar-brand">XQuery 4.0 LSP client
|
||||
<button id="popcon" popovertarget="popConnect" class="btn btn-danger">
|
||||
<i class="codicon codicon-vm-outline"></i>
|
||||
</button>
|
||||
</a>
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Editor</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Msgs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/dba/logs" target="dba">Dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<nav class="page-nav">
|
||||
<div class="navbar py-0 bg-light">
|
||||
|
||||
<div class="btn-group mr-2" role="group" aria-label="First group">
|
||||
<label for="file">File:</label>
|
||||
<input id="iFile" type="url" value="file:///some/file.xqm" />
|
||||
|
||||
<label for="symbols">Symbols:</label><select id="symbols" disabled="disabled"></select>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm " role="group" aria-label="Second group">
|
||||
|
||||
<button id="search" title="Search" type="button" class="btn btn-light"><i
|
||||
class="codicon codicon-search"></i></button>
|
||||
|
||||
<button id="lint" title="Display diagnostics" type="button" class="btn btn-light"><i
|
||||
class="codicon codicon-report"></i></button>
|
||||
|
||||
<button id="symbols2" type="button" class="btn btn-light" title="symbols">
|
||||
<i class="codicon codicon-symbol-misc"></i></button>
|
||||
|
||||
<button id="format" type="button" class="btn btn-light" title="Format (Shift-Alt-f)"><i
|
||||
class="codicon codicon-list-flat"></i></button>
|
||||
|
||||
<button id="sync" title="Sync changes to server" type="button" class="btn btn-light">
|
||||
<i class="codicon codicon-sync"></i>
|
||||
</button>
|
||||
<button id="fullscreen" title="Full screen editor" type="button" class="btn btn-light">
|
||||
<i class="codicon codicon-screen-full"></i>
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-light" popovertarget="popSettings" title="Settings">
|
||||
<i class="codicon codicon-settings"></i></button>
|
||||
</div>
|
||||
<div class="btn-group" role="group" aria-label="Third group">
|
||||
|
||||
<button id="syntax" type="button" class="btn btn-light" title="Unused"><i
|
||||
class="codicon codicon-comment"></i></button>
|
||||
|
||||
<button id="cmd" type="button" class="btn btn-light" title="Cmd list to console">
|
||||
<i class="codicon codicon-debug-console"></i>
|
||||
</button>
|
||||
|
||||
<button id="wordAt" type="button" class="btn btn-light" title="word at">
|
||||
<i>1</i></button>
|
||||
|
||||
|
||||
<button id="unused3" type="button" class="btn btn-light" title="unused3">
|
||||
<i>3</i></button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="page-main" style="overflow: auto;">
|
||||
<!-- Editor goes in here -->
|
||||
<div id="editor"></div>
|
||||
</main>
|
||||
|
||||
<aside class="page-sidebar">
|
||||
|
||||
<details id="workspacePanel" open="open" >
|
||||
<summary class='bg-info'>Workspace <b>0</b></summary>
|
||||
<select id="load">
|
||||
<option selected value="">load..</option>
|
||||
<optgroup label="XQuery3">
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/expkg-zone58/pdfbox/refs/heads/main/src/Pdfbox3.xqm">
|
||||
Pdfbox3.xqm</option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/Quodatum/xqdoca/refs/heads/master/src/main/lib/model.xqm">
|
||||
model.xqm</option>
|
||||
</optgroup>
|
||||
<optgroup label="XQuery4">
|
||||
<option
|
||||
value="https://git.quodatum.duckdns.org/quodatum/basex-lsp/raw/branch/main/webapp/lsp/lsp-text.xqm">
|
||||
lsp-text.xqm</option>
|
||||
<option value="../../../lsp/lsp-text.xqm">
|
||||
lsp-text.xqm</option>
|
||||
</optgroup>
|
||||
|
||||
<optgroup label="xpath">
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq">
|
||||
generator.xquery</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
|
||||
<ul id="traffic" style="overflow: scroll;">
|
||||
<li>-</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<details id="symPanel">
|
||||
<summary >OutLine <b>0</b></summary>
|
||||
<json-list id="symList" ></json-list>
|
||||
</details>
|
||||
|
||||
<details id="msgPanel" >
|
||||
<summary >Messages <b>0</b></summary>
|
||||
<div id="msg">(msgs)<i class='codicon codicon-symbol-method'></i></div>
|
||||
</details>
|
||||
</aside>
|
||||
|
||||
<footer class="page-footer">
|
||||
Footer <select id="language">
|
||||
<option selected>Language</option>
|
||||
<option value="plaintext">plaintext</option>
|
||||
<option value="xquery">xquery</option>
|
||||
<option value="xml">xml</option>
|
||||
</select>
|
||||
<button popovertarget="popHelp"><i class="codicon codicon-info"></i></button>
|
||||
</footer>
|
||||
</div>
|
||||
<!-- Popovers -->
|
||||
<dialog id="popConnect" popover>
|
||||
<header>Connect to LSP
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
<div id="state">🔴</div>
|
||||
<input id="iServer" type="text" style="width:25em" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="connect">connect</button>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- <popup-info id="popHelp">hhhh</popup-info> -->
|
||||
|
||||
<dialog id="popSettings" popover>
|
||||
<form id="fSettings">
|
||||
<header>Editor configuration
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"
|
||||
onclick="$('popSettings').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input name="wrap-lines" type="checkbox" class="form-check-input" id="exampleCheck1">
|
||||
<label class="form-check-label" for="exampleCheck1">Wrap lines</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- CodeMirror 6 -->
|
||||
<script src="./lsp.bundle.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
<script src="./list.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Codemirror6 example using BaseX LSP</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
<link href="../bootstrap@5.3.7.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="grail.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="page-wrap">
|
||||
<header class="page-header">
|
||||
<nav class="navbar bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a id="help" class="navbar-brand">XQuery 4.0 LSP client
|
||||
<button id="popcon" popovertarget="popConnect" class="btn btn-danger">
|
||||
<i class="codicon codicon-vm-outline"></i>
|
||||
</button>
|
||||
</a>
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">Editor</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Msgs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/dba/logs" target="dba">Dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<nav class="page-nav">
|
||||
<div class="navbar py-0 bg-light">
|
||||
|
||||
<div class="btn-group mr-2" role="group" aria-label="First group">
|
||||
<label for="file">File:</label>
|
||||
<input id="iFile" type="url" value="file:///some/file.xqm" />
|
||||
|
||||
<label for="symbols">Symbols:</label><select id="symbols" disabled="disabled"></select>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm " role="group" aria-label="Second group">
|
||||
|
||||
<button id="search" title="Search" type="button" class="btn btn-light"><i
|
||||
class="codicon codicon-search"></i></button>
|
||||
|
||||
<button id="lint" title="Display diagnostics" type="button" class="btn btn-light"><i
|
||||
class="codicon codicon-report"></i></button>
|
||||
|
||||
<button id="symbols2" type="button" class="btn btn-light" title="symbols">
|
||||
<i class="codicon codicon-symbol-misc"></i></button>
|
||||
|
||||
<button id="format" type="button" class="btn btn-light" title="Format (Shift-Alt-f)"><i
|
||||
class="codicon codicon-list-flat"></i></button>
|
||||
|
||||
<button id="sync" title="Sync changes to server" type="button" class="btn btn-light">
|
||||
<i class="codicon codicon-sync"></i>
|
||||
</button>
|
||||
<button id="fullscreen" title="Full screen editor" type="button" class="btn btn-light">
|
||||
<i class="codicon codicon-screen-full"></i>
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-light" popovertarget="popSettings" title="Settings">
|
||||
<i class="codicon codicon-settings"></i></button>
|
||||
</div>
|
||||
<div class="btn-group" role="group" aria-label="Third group">
|
||||
|
||||
<button id="syntax" type="button" class="btn btn-light" title="Unused"><i
|
||||
class="codicon codicon-comment"></i></button>
|
||||
|
||||
<button id="cmd" type="button" class="btn btn-light" title="Cmd list to console">
|
||||
<i class="codicon codicon-debug-console"></i>
|
||||
</button>
|
||||
|
||||
<button id="wordAt" type="button" class="btn btn-light" title="word at">
|
||||
<i>1</i></button>
|
||||
|
||||
|
||||
<button id="unused3" type="button" class="btn btn-light" title="unused3">
|
||||
<i>3</i></button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="page-main" style="overflow: auto;">
|
||||
<!-- Editor goes in here -->
|
||||
<div id="editor"></div>
|
||||
</main>
|
||||
|
||||
<aside class="page-sidebar">
|
||||
|
||||
<details id="workspacePanel" open="open" >
|
||||
<summary class='bg-info'>Workspace <b>0</b></summary>
|
||||
<select id="load">
|
||||
<option selected value="">load..</option>
|
||||
<optgroup label="XQuery3">
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/expkg-zone58/pdfbox/refs/heads/main/src/Pdfbox3.xqm">
|
||||
Pdfbox3.xqm</option>
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/Quodatum/xqdoca/refs/heads/master/src/main/lib/model.xqm">
|
||||
model.xqm</option>
|
||||
</optgroup>
|
||||
<optgroup label="XQuery4">
|
||||
<option
|
||||
value="https://git.quodatum.duckdns.org/quodatum/basex-lsp/raw/branch/main/webapp/lsp/lsp-text.xqm">
|
||||
lsp-text.xqm</option>
|
||||
<option value="../../../lsp/lsp-text.xqm">
|
||||
lsp-text.xqm</option>
|
||||
</optgroup>
|
||||
|
||||
<optgroup label="xpath">
|
||||
<option
|
||||
value="https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq">
|
||||
generator.xquery</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
|
||||
<ul id="traffic" style="overflow: scroll;">
|
||||
<li>-</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<details id="symPanel">
|
||||
<summary >OutLine <b>0</b></summary>
|
||||
<json-list id="symList" ></json-list>
|
||||
</details>
|
||||
|
||||
<details id="msgPanel" >
|
||||
<summary >Messages <b>0</b></summary>
|
||||
<div id="msg">(msgs)<i class='codicon codicon-symbol-method'></i></div>
|
||||
</details>
|
||||
</aside>
|
||||
|
||||
<footer class="page-footer">
|
||||
Footer <select id="language">
|
||||
<option selected>Language</option>
|
||||
<option value="plaintext">plaintext</option>
|
||||
<option value="xquery">xquery</option>
|
||||
<option value="xml">xml</option>
|
||||
</select>
|
||||
<button popovertarget="popHelp"><i class="codicon codicon-info"></i></button>
|
||||
</footer>
|
||||
</div>
|
||||
<!-- Popovers -->
|
||||
<dialog id="popConnect" popover>
|
||||
<header>Connect to LSP
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
<div id="state">🔴</div>
|
||||
<input id="iServer" type="text" style="width:25em" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="connect">connect</button>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<!-- <popup-info id="popHelp">hhhh</popup-info> -->
|
||||
|
||||
<dialog id="popSettings" popover>
|
||||
<form id="fSettings">
|
||||
<header>Editor configuration
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"
|
||||
onclick="$('popSettings').hidePopover(); "></button>
|
||||
</header>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<input name="wrap-lines" type="checkbox" class="form-check-input" id="exampleCheck1">
|
||||
<label class="form-check-label" for="exampleCheck1">Wrap lines</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
<!-- CodeMirror 6 -->
|
||||
<script src="./lsp.bundle.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
<script src="./list.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -31344,103 +31344,103 @@ ${text}</tr>
|
|||
},
|
||||
});
|
||||
|
||||
let create = (v) => {
|
||||
const dom = document.createElement('div');
|
||||
return { dom }
|
||||
};
|
||||
const compartment = new Compartment();
|
||||
let curOpts = {
|
||||
lineWrap: true,
|
||||
minimap: true,
|
||||
highlightWhitespace: true
|
||||
};
|
||||
// array of extensions reflecting opts
|
||||
function optExts(opts) {
|
||||
let exts = [];
|
||||
if (opts.lineWrap) exts.push(EditorView.lineWrapping);
|
||||
if (opts.highlightWhitespace) exts.push(highlightWhitespace());
|
||||
if (opts.minimap) exts.push(
|
||||
showMinimap.compute(['doc'], (state) => {
|
||||
return {
|
||||
create,
|
||||
/* optional showOverlay: 'mouse-over' */
|
||||
displayText: 'characters'
|
||||
|
||||
}
|
||||
}));
|
||||
return exts
|
||||
}
|
||||
|
||||
function updateCompartment(opts) {
|
||||
view.dispatch({
|
||||
effects: [compartment.reconfigure(optExts(opts))]
|
||||
});
|
||||
}
|
||||
|
||||
// return promise with socket map or reject if no connect
|
||||
function simpleWebSocketTransport(uri) {
|
||||
let handlers = [];
|
||||
return new Promise(function (resolve, reject) {
|
||||
let sock = new WebSocket(uri);
|
||||
|
||||
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
|
||||
sock.onerror = e => reject(e);
|
||||
sock.onopen = () => resolve({
|
||||
socket: sock,
|
||||
send: (message) => sock.send(message),
|
||||
subscribe: (handler) => handlers.push(handler),
|
||||
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
const baseExts = [
|
||||
lineNumbers(),
|
||||
highlightActiveLineGutter(),
|
||||
history(),
|
||||
foldGutter(),
|
||||
lintGutter(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
tooltips({ }), // clipped
|
||||
keymap.of([indentWithTab]),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
highlightActiveLine(),
|
||||
highlightSelectionMatches(),
|
||||
keymap.of([
|
||||
...closeBracketsKeymap,
|
||||
...defaultKeymap,
|
||||
...searchKeymap,
|
||||
...historyKeymap,
|
||||
...foldKeymap,
|
||||
...completionKeymap,
|
||||
...lintKeymap
|
||||
]),
|
||||
StreamLanguage.define(xQuery),
|
||||
compartment.of(optExts(curOpts))
|
||||
];
|
||||
|
||||
|
||||
|
||||
// map cmd->{keybings,fn}
|
||||
function listCommands(view) {
|
||||
const commands = new Map();
|
||||
const keymaps = view.state.facet(keymap);
|
||||
for (let km of keymaps) {
|
||||
for (let binding of km) {
|
||||
if (binding.run && binding.run.name) {
|
||||
commands.set(binding.run.name, { key: binding.key, fn: binding.run });
|
||||
}
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
let create = (v) => {
|
||||
const dom = document.createElement('div');
|
||||
return { dom }
|
||||
};
|
||||
const compartment = new Compartment();
|
||||
let curOpts = {
|
||||
lineWrap: true,
|
||||
minimap: true,
|
||||
highlightWhitespace: true
|
||||
};
|
||||
// array of extensions reflecting opts
|
||||
function optExts(opts) {
|
||||
let exts = [];
|
||||
if (opts.lineWrap) exts.push(EditorView.lineWrapping);
|
||||
if (opts.highlightWhitespace) exts.push(highlightWhitespace());
|
||||
if (opts.minimap) exts.push(
|
||||
showMinimap.compute(['doc'], (state) => {
|
||||
return {
|
||||
create,
|
||||
/* optional showOverlay: 'mouse-over' */
|
||||
displayText: 'characters'
|
||||
|
||||
}
|
||||
}));
|
||||
return exts
|
||||
}
|
||||
|
||||
function updateCompartment(opts) {
|
||||
view.dispatch({
|
||||
effects: [compartment.reconfigure(optExts(opts))]
|
||||
});
|
||||
}
|
||||
|
||||
// return promise with socket map or reject if no connect
|
||||
function simpleWebSocketTransport(uri) {
|
||||
let handlers = [];
|
||||
return new Promise(function (resolve, reject) {
|
||||
let sock = new WebSocket(uri);
|
||||
|
||||
sock.onmessage = e => { for (let h of handlers) h(e.data.toString()); };
|
||||
sock.onerror = e => reject(e);
|
||||
sock.onopen = () => resolve({
|
||||
socket: sock,
|
||||
send: (message) => sock.send(message),
|
||||
subscribe: (handler) => handlers.push(handler),
|
||||
unsubscribe: (handler) => handlers = handlers.filter(h => h != handler)
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
const baseExts = [
|
||||
lineNumbers(),
|
||||
highlightActiveLineGutter(),
|
||||
history(),
|
||||
foldGutter(),
|
||||
lintGutter(),
|
||||
drawSelection(),
|
||||
dropCursor(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
tooltips({ }), // clipped
|
||||
keymap.of([indentWithTab]),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
bracketMatching(),
|
||||
closeBrackets(),
|
||||
autocompletion(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
highlightActiveLine(),
|
||||
highlightSelectionMatches(),
|
||||
keymap.of([
|
||||
...closeBracketsKeymap,
|
||||
...defaultKeymap,
|
||||
...searchKeymap,
|
||||
...historyKeymap,
|
||||
...foldKeymap,
|
||||
...completionKeymap,
|
||||
...lintKeymap
|
||||
]),
|
||||
StreamLanguage.define(xQuery),
|
||||
compartment.of(optExts(curOpts))
|
||||
];
|
||||
|
||||
|
||||
|
||||
// map cmd->{keybings,fn}
|
||||
function listCommands(view) {
|
||||
const commands = new Map();
|
||||
const keymaps = view.state.facet(keymap);
|
||||
for (let km of keymaps) {
|
||||
for (let binding of km) {
|
||||
if (binding.run && binding.run.name) {
|
||||
commands.set(binding.run.name, { key: binding.key, fn: binding.run });
|
||||
}
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
exports.EditorState = EditorState;
|
||||
|
|
|
|||
|
|
@ -1,246 +1,246 @@
|
|||
|
||||
const view = new lsp.EditorView({
|
||||
extensions: lsp.baseExts,
|
||||
parent: document.getElementById("editor")
|
||||
});
|
||||
let doc = "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n";
|
||||
var client; // https://codemirror.net/docs/ref/#lsp-client
|
||||
|
||||
var workspace = {
|
||||
"file:///some/file.xqm": null
|
||||
};
|
||||
|
||||
function $(id) { return document.getElementById(id) };
|
||||
|
||||
// Load saved content from localStorage when the page loads
|
||||
window.addEventListener('load', () => {
|
||||
|
||||
const savedText = localStorage.getItem('code');
|
||||
if (savedText) doc = savedText;
|
||||
let svr = localStorage.getItem('lsp');
|
||||
if (!svr) {
|
||||
let x = new URL(window.location.href);
|
||||
x.protocol = "ws";
|
||||
x.pathname = "ws/lsp"
|
||||
svr = x.href;
|
||||
}
|
||||
$("iServer").value = svr;
|
||||
formFromStore('fSettings');
|
||||
view.setState(lsp.EditorState.create({ doc: doc, extensions: lsp.baseExts }));
|
||||
lsp.updateCompartment(objectFromForm('fSettings'))
|
||||
connect();
|
||||
});
|
||||
|
||||
// Save content to localStorage when the page is about to unload
|
||||
window.addEventListener('beforeunload', () => {
|
||||
const doc = view.state.doc.toString();
|
||||
localStorage.setItem('code', doc);
|
||||
localStorage.setItem('lsp', $("iServer").value);
|
||||
});
|
||||
|
||||
$("connect").onclick = e => { e.preventDefault(); connect() };
|
||||
|
||||
$("symTrigger").onclick = e => { e.preventDefault(); };
|
||||
$("symOptions").onclick = e => { e.preventDefault(); };
|
||||
$("bnNew").onclick = e => {
|
||||
let name = prompt("New file name?", "untitled.xq");
|
||||
if (name === null) return;
|
||||
docSwitch("", name);
|
||||
};
|
||||
|
||||
$("search").onclick = e => lsp.openSearchPanel(view);
|
||||
|
||||
$("fullscreen").onclick = e => $("editor").requestFullscreen();
|
||||
|
||||
$("bnWordAt").onclick = e => {
|
||||
let pos = view.state.selection.main.head;
|
||||
let w = view.state.wordAt(pos);
|
||||
alert("wordAt " + JSON.stringify(w));
|
||||
};
|
||||
|
||||
$("symbols2").onclick = e => {
|
||||
client.sync();
|
||||
client.request("textDocument/documentSymbol", { "textDocument": { "uri": $("iFile").value } })
|
||||
.then(r => {
|
||||
console.log("symbols", r)
|
||||
$("symPanel").open = true;
|
||||
$("symList").setData(r);
|
||||
});
|
||||
};
|
||||
|
||||
$("cmdList").onclick = e => {
|
||||
let cmds = lsp.listCommands(view);
|
||||
let result = "";
|
||||
[...cmds.keys()].sort().forEach(key => {
|
||||
result += `<li>${key} ${cmds.get(key).key}</li>`
|
||||
});
|
||||
$("popHelpInfo").innerHTML = `<ul>${result}</ul>`
|
||||
$("popCmds").showPopover()
|
||||
};
|
||||
|
||||
$("symList").addEventListener("itemSelected", e => {
|
||||
const plugin = lsp.LSPPlugin.get(view)
|
||||
if (!plugin) return;
|
||||
const sel = e.detail.range // or selectionRange;
|
||||
console.log("SYM selection range", sel);
|
||||
const an = plugin.fromPosition(sel.start)
|
||||
const hd = plugin.fromPosition(sel.end)
|
||||
view.dispatch({ selection: { anchor: an, head: hd }, scrollIntoView: true });
|
||||
});
|
||||
|
||||
$("lint").onclick = async e => {
|
||||
console.log("word", view.state.wordAt(1));
|
||||
lsp.openLintPanel(view);
|
||||
};
|
||||
|
||||
$("sync").onclick = e => { client.sync(); console.log("XXXsync"); };
|
||||
// state a state
|
||||
$("bnSave").onclick = e => { workspace[iFile] = view.state; };
|
||||
$("bnLoad").onclick = e => { const v = workspace[iFile]; if (v) view.setState(v) };
|
||||
|
||||
|
||||
// select local file
|
||||
$("bnRead").onclick = e => { $("fileElem").click(); };
|
||||
$("fileElem").onchange = e => {
|
||||
let file = e.target.files[0]
|
||||
let fr = new FileReader();
|
||||
fr.onload = () => docSwitch(fr.result, file.name);
|
||||
fr.readAsText(file);
|
||||
};
|
||||
|
||||
$("format").onclick = e => { console.log("FMT", lsp.formatDocument(view)); };
|
||||
|
||||
$("popUrl").onsubmit = e => {
|
||||
e.preventDefault();
|
||||
const f = objectFromForm("popUrl");
|
||||
fetch(f.url)
|
||||
.then(response => response.text())
|
||||
.then(t => {
|
||||
docSwitch(t, f.url)
|
||||
$("popWeb").open = false;
|
||||
})
|
||||
.catch(error => {
|
||||
alert("CORS?: " + error)
|
||||
});
|
||||
};
|
||||
$("bnDebug").onclick = e => { debugger; };
|
||||
|
||||
|
||||
$("tConnect").addEventListener('quiet-change', e => {
|
||||
e.preventDefault();
|
||||
$("popConnect").showPopover()
|
||||
});
|
||||
$("msgIcon").onclick = e => {
|
||||
e.preventDefault();
|
||||
alert("NOT YET")
|
||||
};
|
||||
|
||||
|
||||
function updateSettings(event) {
|
||||
event.preventDefault();
|
||||
|
||||
console.log("COPTS", lsp.curOpts);
|
||||
const opts = {
|
||||
lineWrap: $("lineWrap").checked,
|
||||
highlightWhitespace: $("highlightWhitespace").checked,
|
||||
minimap: $("minimap").checked
|
||||
}
|
||||
console.log(opts)
|
||||
lsp.updateCompartment(opts);
|
||||
$('popSettings').hidePopover();
|
||||
formToStore("fSettings");
|
||||
};
|
||||
|
||||
$("fSettings").addEventListener("submit", updateSettings);
|
||||
|
||||
function connect() {
|
||||
const server = $("iServer").value;
|
||||
const file = $("iFile").value;
|
||||
lsp.simpleWebSocketTransport(server)
|
||||
.then(transport => {
|
||||
transport.socket.onclose = (event) => $("tConnect").checked = false;
|
||||
transport.socket.oneror = (event) => $("msg").innerText = "sock error!";
|
||||
transport.subscribe(incoming);
|
||||
client = new lsp.LSPClient({ extensions: lsp.languageServerExtensions() });
|
||||
client.connect(transport);
|
||||
$("popConnect").hidePopover();
|
||||
$("tConnect").checked = true;
|
||||
$("tipConnect").innerText=server;
|
||||
const extLsp = client.plugin(file, "xquery");
|
||||
|
||||
view.dispatch({
|
||||
effects: lsp.StateEffect.appendConfig.of(
|
||||
[lsp.linter(null, { autoPanel: true }), ...extLsp,
|
||||
lsp.keymap.of([...lsp.formatKeymap])])
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
$("tConnect").checked = false;
|
||||
alert("connection failed: " + server)
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// change active doc
|
||||
function docSwitch(text,urlNew) {
|
||||
const urlOld=$("iFile").value;
|
||||
client.workspace.closeFile(urlOld);
|
||||
view.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: view.state.doc.length,
|
||||
insert: text
|
||||
}
|
||||
})
|
||||
client.workspace.openFile(urlNew,"xquery",view)
|
||||
$("iFile").value = urlNew;
|
||||
};
|
||||
|
||||
|
||||
function incoming(msg) {
|
||||
const rpc = JSON.parse(msg);
|
||||
log(rpc);
|
||||
};
|
||||
|
||||
|
||||
function log(rpc) {
|
||||
console.log("<-", rpc)
|
||||
const when = (new Date()).toISOString();
|
||||
const msg = { name: rpc.method ?? rpc.id, detail: when.substring(1 + when.indexOf("T")), kind: 23 /* event */ };
|
||||
//name,details,kind
|
||||
$("msgList").setData([msg], true)
|
||||
$("relative-time__live").date=new Date();
|
||||
};
|
||||
|
||||
function formFromStore(name) {
|
||||
let v = localStorage.getItem(name)
|
||||
if (!!v) formDeserialize($(name), v);
|
||||
};
|
||||
|
||||
function formToStore(name) {
|
||||
localStorage.setItem(name, formSerialize($(name)));
|
||||
};
|
||||
|
||||
function objectFromForm(name) {
|
||||
const data = new FormData($(name));
|
||||
//https://stackabuse.com/convert-form-data-to-javascript-object/
|
||||
return Object.fromEntries(data.entries());
|
||||
}
|
||||
function formSerialize(form) {
|
||||
const data = new FormData(form);
|
||||
//https://stackoverflow.com/a/44033425/1869660
|
||||
return new URLSearchParams(data).toString();
|
||||
}
|
||||
|
||||
function formDeserialize(form, data) {
|
||||
const entries = (new URLSearchParams(data)).entries();
|
||||
for (const [key, val] of entries) {
|
||||
//http://javascript-coder.com/javascript-form/javascript-form-value.phtml
|
||||
const input = form.elements[key];
|
||||
switch (input.type) {
|
||||
case 'checkbox': input.checked = !!val; break;
|
||||
default: input.value = val; break;
|
||||
}
|
||||
}
|
||||
|
||||
const view = new lsp.EditorView({
|
||||
extensions: lsp.baseExts,
|
||||
parent: document.getElementById("editor")
|
||||
});
|
||||
let doc = "xquery version '3.1';\n(:~ comment:)\nmodule namespace pdfbox='ns';\n";
|
||||
var client; // https://codemirror.net/docs/ref/#lsp-client
|
||||
|
||||
var workspace = {
|
||||
"file:///some/file.xqm": null
|
||||
};
|
||||
|
||||
function $(id) { return document.getElementById(id) };
|
||||
|
||||
// Load saved content from localStorage when the page loads
|
||||
window.addEventListener('load', () => {
|
||||
|
||||
const savedText = localStorage.getItem('code');
|
||||
if (savedText) doc = savedText;
|
||||
let svr = localStorage.getItem('lsp');
|
||||
if (!svr) {
|
||||
let x = new URL(window.location.href);
|
||||
x.protocol = "ws";
|
||||
x.pathname = "ws/lsp"
|
||||
svr = x.href;
|
||||
}
|
||||
$("iServer").value = svr;
|
||||
formFromStore('fSettings');
|
||||
view.setState(lsp.EditorState.create({ doc: doc, extensions: lsp.baseExts }));
|
||||
lsp.updateCompartment(objectFromForm('fSettings'))
|
||||
connect();
|
||||
});
|
||||
|
||||
// Save content to localStorage when the page is about to unload
|
||||
window.addEventListener('beforeunload', () => {
|
||||
const doc = view.state.doc.toString();
|
||||
localStorage.setItem('code', doc);
|
||||
localStorage.setItem('lsp', $("iServer").value);
|
||||
});
|
||||
|
||||
$("connect").onclick = e => { e.preventDefault(); connect() };
|
||||
|
||||
$("symTrigger").onclick = e => { e.preventDefault(); };
|
||||
$("symOptions").onclick = e => { e.preventDefault(); };
|
||||
$("bnNew").onclick = e => {
|
||||
let name = prompt("New file name?", "untitled.xq");
|
||||
if (name === null) return;
|
||||
docSwitch("", name);
|
||||
};
|
||||
|
||||
$("search").onclick = e => lsp.openSearchPanel(view);
|
||||
|
||||
$("fullscreen").onclick = e => $("editor").requestFullscreen();
|
||||
|
||||
$("bnWordAt").onclick = e => {
|
||||
let pos = view.state.selection.main.head;
|
||||
let w = view.state.wordAt(pos);
|
||||
alert("wordAt " + JSON.stringify(w));
|
||||
};
|
||||
|
||||
$("symbols2").onclick = e => {
|
||||
client.sync();
|
||||
client.request("textDocument/documentSymbol", { "textDocument": { "uri": $("iFile").value } })
|
||||
.then(r => {
|
||||
console.log("symbols", r)
|
||||
$("symPanel").open = true;
|
||||
$("symList").setData(r);
|
||||
});
|
||||
};
|
||||
|
||||
$("cmdList").onclick = e => {
|
||||
let cmds = lsp.listCommands(view);
|
||||
let result = "";
|
||||
[...cmds.keys()].sort().forEach(key => {
|
||||
result += `<li>${key} ${cmds.get(key).key}</li>`
|
||||
});
|
||||
$("popHelpInfo").innerHTML = `<ul>${result}</ul>`
|
||||
$("popCmds").showPopover()
|
||||
};
|
||||
|
||||
$("symList").addEventListener("itemSelected", e => {
|
||||
const plugin = lsp.LSPPlugin.get(view)
|
||||
if (!plugin) return;
|
||||
const sel = e.detail.range // or selectionRange;
|
||||
console.log("SYM selection range", sel);
|
||||
const an = plugin.fromPosition(sel.start)
|
||||
const hd = plugin.fromPosition(sel.end)
|
||||
view.dispatch({ selection: { anchor: an, head: hd }, scrollIntoView: true });
|
||||
});
|
||||
|
||||
$("lint").onclick = async e => {
|
||||
console.log("word", view.state.wordAt(1));
|
||||
lsp.openLintPanel(view);
|
||||
};
|
||||
|
||||
$("sync").onclick = e => { client.sync(); console.log("XXXsync"); };
|
||||
// state a state
|
||||
$("bnSave").onclick = e => { workspace[iFile] = view.state; };
|
||||
$("bnLoad").onclick = e => { const v = workspace[iFile]; if (v) view.setState(v) };
|
||||
|
||||
|
||||
// select local file
|
||||
$("bnRead").onclick = e => { $("fileElem").click(); };
|
||||
$("fileElem").onchange = e => {
|
||||
let file = e.target.files[0]
|
||||
let fr = new FileReader();
|
||||
fr.onload = () => docSwitch(fr.result, file.name);
|
||||
fr.readAsText(file);
|
||||
};
|
||||
|
||||
$("format").onclick = e => { console.log("FMT", lsp.formatDocument(view)); };
|
||||
|
||||
$("popUrl").onsubmit = e => {
|
||||
e.preventDefault();
|
||||
const f = objectFromForm("popUrl");
|
||||
fetch(f.url)
|
||||
.then(response => response.text())
|
||||
.then(t => {
|
||||
docSwitch(t, f.url)
|
||||
$("popWeb").open = false;
|
||||
})
|
||||
.catch(error => {
|
||||
alert("CORS?: " + error)
|
||||
});
|
||||
};
|
||||
$("bnDebug").onclick = e => { debugger; };
|
||||
|
||||
|
||||
$("tConnect").addEventListener('quiet-change', e => {
|
||||
e.preventDefault();
|
||||
$("popConnect").showPopover()
|
||||
});
|
||||
$("msgIcon").onclick = e => {
|
||||
e.preventDefault();
|
||||
alert("NOT YET")
|
||||
};
|
||||
|
||||
|
||||
function updateSettings(event) {
|
||||
event.preventDefault();
|
||||
|
||||
console.log("COPTS", lsp.curOpts);
|
||||
const opts = {
|
||||
lineWrap: $("lineWrap").checked,
|
||||
highlightWhitespace: $("highlightWhitespace").checked,
|
||||
minimap: $("minimap").checked
|
||||
}
|
||||
console.log(opts)
|
||||
lsp.updateCompartment(opts);
|
||||
$('popSettings').hidePopover();
|
||||
formToStore("fSettings");
|
||||
};
|
||||
|
||||
$("fSettings").addEventListener("submit", updateSettings);
|
||||
|
||||
function connect() {
|
||||
const server = $("iServer").value;
|
||||
const file = $("iFile").value;
|
||||
lsp.simpleWebSocketTransport(server)
|
||||
.then(transport => {
|
||||
transport.socket.onclose = (event) => $("tConnect").checked = false;
|
||||
transport.socket.oneror = (event) => $("msg").innerText = "sock error!";
|
||||
transport.subscribe(incoming);
|
||||
client = new lsp.LSPClient({ extensions: lsp.languageServerExtensions() });
|
||||
client.connect(transport);
|
||||
$("popConnect").hidePopover();
|
||||
$("tConnect").checked = true;
|
||||
$("tipConnect").innerText=server;
|
||||
const extLsp = client.plugin(file, "xquery");
|
||||
|
||||
view.dispatch({
|
||||
effects: lsp.StateEffect.appendConfig.of(
|
||||
[lsp.linter(null, { autoPanel: true }), ...extLsp,
|
||||
lsp.keymap.of([...lsp.formatKeymap])])
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
$("tConnect").checked = false;
|
||||
alert("connection failed: " + server)
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// change active doc
|
||||
function docSwitch(text,urlNew) {
|
||||
const urlOld=$("iFile").value;
|
||||
client.workspace.closeFile(urlOld);
|
||||
view.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: view.state.doc.length,
|
||||
insert: text
|
||||
}
|
||||
})
|
||||
client.workspace.openFile(urlNew,"xquery",view)
|
||||
$("iFile").value = urlNew;
|
||||
};
|
||||
|
||||
|
||||
function incoming(msg) {
|
||||
const rpc = JSON.parse(msg);
|
||||
log(rpc);
|
||||
};
|
||||
|
||||
|
||||
function log(rpc) {
|
||||
console.log("<-", rpc)
|
||||
const when = (new Date()).toISOString();
|
||||
const msg = { name: rpc.method ?? rpc.id, detail: when.substring(1 + when.indexOf("T")), kind: 23 /* event */ };
|
||||
//name,details,kind
|
||||
$("msgList").setData([msg], true)
|
||||
$("relative-time__live").date=new Date();
|
||||
};
|
||||
|
||||
function formFromStore(name) {
|
||||
let v = localStorage.getItem(name)
|
||||
if (!!v) formDeserialize($(name), v);
|
||||
};
|
||||
|
||||
function formToStore(name) {
|
||||
localStorage.setItem(name, formSerialize($(name)));
|
||||
};
|
||||
|
||||
function objectFromForm(name) {
|
||||
const data = new FormData($(name));
|
||||
//https://stackabuse.com/convert-form-data-to-javascript-object/
|
||||
return Object.fromEntries(data.entries());
|
||||
}
|
||||
function formSerialize(form) {
|
||||
const data = new FormData(form);
|
||||
//https://stackoverflow.com/a/44033425/1869660
|
||||
return new URLSearchParams(data).toString();
|
||||
}
|
||||
|
||||
function formDeserialize(form, data) {
|
||||
const entries = (new URLSearchParams(data)).entries();
|
||||
for (const [key, val] of entries) {
|
||||
//http://javascript-coder.com/javascript-form/javascript-form-value.phtml
|
||||
const input = form.elements[key];
|
||||
switch (input.type) {
|
||||
case 'checkbox': input.checked = !!val; break;
|
||||
default: input.value = val; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,35 @@
|
|||
|
||||
@import url("../bootstrap-icons.min.css");
|
||||
html { height: 100%;}
|
||||
body { min-height: 100vh; }
|
||||
|
||||
/* Set editor dimensions */
|
||||
#editor {
|
||||
height: 400px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: burlywood;
|
||||
}
|
||||
|
||||
/* Stretch editor to fit inside its containing div */
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
|
||||
}
|
||||
/* header */
|
||||
nav {
|
||||
background-color: burlywood!;
|
||||
}
|
||||
.nav-pills > li > a
|
||||
{
|
||||
/* adjust padding for height*/
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
dialog > header
|
||||
{
|
||||
background-color: burlywood;
|
||||
|
||||
@import url("../bootstrap-icons.min.css");
|
||||
html { height: 100%;}
|
||||
body { min-height: 100vh; }
|
||||
|
||||
/* Set editor dimensions */
|
||||
#editor {
|
||||
height: 400px;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: burlywood;
|
||||
}
|
||||
|
||||
/* Stretch editor to fit inside its containing div */
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
|
||||
}
|
||||
/* header */
|
||||
nav {
|
||||
background-color: burlywood!;
|
||||
}
|
||||
.nav-pills > li > a
|
||||
{
|
||||
/* adjust padding for height*/
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
dialog > header
|
||||
{
|
||||
background-color: burlywood;
|
||||
}
|
||||
|
|
@ -1,204 +1,204 @@
|
|||
/* Define a web component providing a settable and selectable list
|
||||
$("symList").setData(r, append = false);
|
||||
where r is array of objects with properties name,detail,kind
|
||||
|
||||
https://stackoverflow.com/questions/50404970/web-components-pass-data-to-and-from
|
||||
https://www.w3schools.com/howto/howto_js_treeview.asp
|
||||
*/
|
||||
class ListComponent extends HTMLElement {
|
||||
#shadow;
|
||||
#data;
|
||||
#iconKinds; //array from kind integer to codicon name
|
||||
constructor() {
|
||||
super();
|
||||
this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
this.#data = [];
|
||||
// codicons kind
|
||||
this.#iconKinds = [
|
||||
'symbol-file',
|
||||
'symbol-class',
|
||||
'symbol-namespace',
|
||||
'symbol-structure',
|
||||
'symbol-class',
|
||||
'symbol-method',
|
||||
'symbol-property',
|
||||
'symbol-field',
|
||||
'symbol-method-arrow',
|
||||
'symbol-enum',
|
||||
'symbol-interface',
|
||||
'symbol-method',
|
||||
'symbol-variable',
|
||||
'symbol-constant',
|
||||
'symbol-string',
|
||||
'symbol-numeric',
|
||||
'symbol-boolean',
|
||||
'symbol-array',
|
||||
'symbol-structure',
|
||||
'symbol-key',
|
||||
'dash',
|
||||
'symbol-enum-member',
|
||||
'symbol-misc',
|
||||
'symbol-event',
|
||||
'symbol-operator',
|
||||
'symbol-parameter'
|
||||
];
|
||||
this.render();
|
||||
}
|
||||
|
||||
setData(newData, append = false) {
|
||||
if (!Array.isArray(newData)) {
|
||||
console.warn("Invalid format, expected an array.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.#data = append ? this.#data.concat(newData) : structuredClone(newData);
|
||||
this.render();
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this.setData(value, false);
|
||||
}
|
||||
get data() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
/* Render the list items #data */
|
||||
render() {
|
||||
// eventhandler for click and keyboard, updates usage of selected class and raises event
|
||||
const select = e => {
|
||||
if(e.type ==="keyup" && !(e.key==="Enter" )) return;
|
||||
this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; });
|
||||
e.currentTarget.className = 'selected';
|
||||
const i=e.currentTarget.getAttribute("data-index")
|
||||
console.log('Item index clicked:', i,this.#data[i]);
|
||||
// You can dispatch a custom event here if needed.
|
||||
this.dispatchEvent(new CustomEvent('itemSelected', {
|
||||
detail: this.#data[i],
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
};
|
||||
// create list and items
|
||||
const list = document.createElement('ul');
|
||||
list.style = "overflow: auto;";
|
||||
this.#data.forEach((item, index) => {
|
||||
const listItem = document.createElement('li');
|
||||
const icon=this.#iconKinds[item.kind];
|
||||
listItem.setAttribute("tabindex", "0")
|
||||
listItem.setAttribute("data-index", index)
|
||||
listItem.innerHTML = `<i class='codicon codicon-${icon}'
|
||||
title='${icon}'></i>
|
||||
<span >${item.name} - ${item.detail}</span>`;
|
||||
|
||||
listItem.addEventListener('click', select);
|
||||
listItem.addEventListener('keyup', select);
|
||||
list.appendChild(listItem);
|
||||
});
|
||||
|
||||
this.#shadow.innerHTML = '';
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@import url("../codicon@0.0.40/codicon.css");
|
||||
ul { list-style-type: none; padding:0;margin:0;overflow: auto;
|
||||
background-color: #f8f9fa;font-size: 80%;}
|
||||
li { padding: 0 0 0 2px; cursor: pointer; width:100%; }
|
||||
li:not(.selected) :hover { background-color: #ccc; }
|
||||
.selected { background-color: #0d6efd;color: #ffff;}
|
||||
i {vertical-align: middle;}
|
||||
`;
|
||||
this.#shadow.appendChild(style);
|
||||
this.#shadow.appendChild(list);
|
||||
}
|
||||
|
||||
/* Render an error message if JSON fetching fails */
|
||||
renderError(error) {
|
||||
this.#shadow.innerHTML = `<p>Error loading data: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the new custom element */
|
||||
customElements.define('qd-list', ListComponent);
|
||||
|
||||
class PanelComponent extends HTMLElement {
|
||||
#shadow;
|
||||
#data;
|
||||
#iconKinds; //array from kind integer to codicon name
|
||||
constructor() {
|
||||
super();
|
||||
this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
this.#data = [];
|
||||
this.#iconKinds = [];
|
||||
this.render();
|
||||
}
|
||||
|
||||
setData(newData, append = false) {
|
||||
if (!Array.isArray(newData)) {
|
||||
console.warn("Invalid format, expected an array.");
|
||||
return;
|
||||
}
|
||||
this.#data = append ? this.#data.concat(newData) : structuredClone(newData);
|
||||
this.render();
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this.setData(value, false);
|
||||
}
|
||||
get data() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
/* Render the list items #data */
|
||||
render() {
|
||||
const list = document.createElement('ul');
|
||||
list.style = "overflow: auto;";
|
||||
|
||||
const select = e => {
|
||||
if(e.type ==="keyup" && !(e.key==="Enter" )) return;
|
||||
this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; });
|
||||
e.currentTarget.className = 'selected';
|
||||
const i=e.currentTarget.getAttribute("data-index")
|
||||
console.log('Item index clicked:', i,this.#data[i]);
|
||||
// You can dispatch a custom event here if needed.
|
||||
this.dispatchEvent(new CustomEvent('itemSelected', {
|
||||
detail: this.#data[i],
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
};
|
||||
this.#data.forEach((item, index) => {
|
||||
const listItem = document.createElement('li');
|
||||
const icon=this.#iconKinds[item.kind];
|
||||
listItem.setAttribute("tabindex", "0")
|
||||
listItem.setAttribute("data-index", index)
|
||||
listItem.innerHTML = `<span title='A ${icon}'>XX<i class='codicon codicon-${icon}' >*</i></span>
|
||||
<span >${item.name} - ${item.detail}</span>`;
|
||||
|
||||
listItem.addEventListener('click', select);
|
||||
listItem.addEventListener('keyup', select);
|
||||
list.appendChild(listItem);
|
||||
});
|
||||
|
||||
this.#shadow.innerHTML = '';
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@import url("../codicon@0.0.40/codicon.css");
|
||||
ul { list-style-type: none; padding:0;margin:0;
|
||||
background-color: #e3e4e4ff;font-size: 80%; scrollbar-color: #000077 #bada55;}
|
||||
li { padding: 0 0 0 2px; border-bottom: 1px solid #ccc; cursor: pointer; width:100%; }
|
||||
li:not(.selected) :hover { background-color: #ccc; }
|
||||
.selected { background-color: #0d6efd;color: #ffff;}
|
||||
i {vertical-align: middle;}
|
||||
`;
|
||||
this.#shadow.appendChild(style);
|
||||
this.#shadow.appendChild(list);
|
||||
}
|
||||
|
||||
/* Render an error message if JSON fetching fails */
|
||||
renderError(error) {
|
||||
this.#shadow.innerHTML = `<p>Error loading data: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the new custom element */
|
||||
customElements.define('qd-panel', PanelComponent);
|
||||
|
||||
/* Define a web component providing a settable and selectable list
|
||||
$("symList").setData(r, append = false);
|
||||
where r is array of objects with properties name,detail,kind
|
||||
|
||||
https://stackoverflow.com/questions/50404970/web-components-pass-data-to-and-from
|
||||
https://www.w3schools.com/howto/howto_js_treeview.asp
|
||||
*/
|
||||
class ListComponent extends HTMLElement {
|
||||
#shadow;
|
||||
#data;
|
||||
#iconKinds; //array from kind integer to codicon name
|
||||
constructor() {
|
||||
super();
|
||||
this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
this.#data = [];
|
||||
// codicons kind
|
||||
this.#iconKinds = [
|
||||
'symbol-file',
|
||||
'symbol-class',
|
||||
'symbol-namespace',
|
||||
'symbol-structure',
|
||||
'symbol-class',
|
||||
'symbol-method',
|
||||
'symbol-property',
|
||||
'symbol-field',
|
||||
'symbol-method-arrow',
|
||||
'symbol-enum',
|
||||
'symbol-interface',
|
||||
'symbol-method',
|
||||
'symbol-variable',
|
||||
'symbol-constant',
|
||||
'symbol-string',
|
||||
'symbol-numeric',
|
||||
'symbol-boolean',
|
||||
'symbol-array',
|
||||
'symbol-structure',
|
||||
'symbol-key',
|
||||
'dash',
|
||||
'symbol-enum-member',
|
||||
'symbol-misc',
|
||||
'symbol-event',
|
||||
'symbol-operator',
|
||||
'symbol-parameter'
|
||||
];
|
||||
this.render();
|
||||
}
|
||||
|
||||
setData(newData, append = false) {
|
||||
if (!Array.isArray(newData)) {
|
||||
console.warn("Invalid format, expected an array.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.#data = append ? this.#data.concat(newData) : structuredClone(newData);
|
||||
this.render();
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this.setData(value, false);
|
||||
}
|
||||
get data() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
/* Render the list items #data */
|
||||
render() {
|
||||
// eventhandler for click and keyboard, updates usage of selected class and raises event
|
||||
const select = e => {
|
||||
if(e.type ==="keyup" && !(e.key==="Enter" )) return;
|
||||
this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; });
|
||||
e.currentTarget.className = 'selected';
|
||||
const i=e.currentTarget.getAttribute("data-index")
|
||||
console.log('Item index clicked:', i,this.#data[i]);
|
||||
// You can dispatch a custom event here if needed.
|
||||
this.dispatchEvent(new CustomEvent('itemSelected', {
|
||||
detail: this.#data[i],
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
};
|
||||
// create list and items
|
||||
const list = document.createElement('ul');
|
||||
list.style = "overflow: auto;";
|
||||
this.#data.forEach((item, index) => {
|
||||
const listItem = document.createElement('li');
|
||||
const icon=this.#iconKinds[item.kind];
|
||||
listItem.setAttribute("tabindex", "0")
|
||||
listItem.setAttribute("data-index", index)
|
||||
listItem.innerHTML = `<i class='codicon codicon-${icon}'
|
||||
title='${icon}'></i>
|
||||
<span >${item.name} - ${item.detail}</span>`;
|
||||
|
||||
listItem.addEventListener('click', select);
|
||||
listItem.addEventListener('keyup', select);
|
||||
list.appendChild(listItem);
|
||||
});
|
||||
|
||||
this.#shadow.innerHTML = '';
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@import url("../codicon@0.0.40/codicon.css");
|
||||
ul { list-style-type: none; padding:0;margin:0;overflow: auto;
|
||||
background-color: #f8f9fa;font-size: 80%;}
|
||||
li { padding: 0 0 0 2px; cursor: pointer; width:100%; }
|
||||
li:not(.selected) :hover { background-color: #ccc; }
|
||||
.selected { background-color: #0d6efd;color: #ffff;}
|
||||
i {vertical-align: middle;}
|
||||
`;
|
||||
this.#shadow.appendChild(style);
|
||||
this.#shadow.appendChild(list);
|
||||
}
|
||||
|
||||
/* Render an error message if JSON fetching fails */
|
||||
renderError(error) {
|
||||
this.#shadow.innerHTML = `<p>Error loading data: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the new custom element */
|
||||
customElements.define('qd-list', ListComponent);
|
||||
|
||||
class PanelComponent extends HTMLElement {
|
||||
#shadow;
|
||||
#data;
|
||||
#iconKinds; //array from kind integer to codicon name
|
||||
constructor() {
|
||||
super();
|
||||
this.#shadow = this.attachShadow({ mode: "open", delegatesFocus: true });
|
||||
this.#data = [];
|
||||
this.#iconKinds = [];
|
||||
this.render();
|
||||
}
|
||||
|
||||
setData(newData, append = false) {
|
||||
if (!Array.isArray(newData)) {
|
||||
console.warn("Invalid format, expected an array.");
|
||||
return;
|
||||
}
|
||||
this.#data = append ? this.#data.concat(newData) : structuredClone(newData);
|
||||
this.render();
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this.setData(value, false);
|
||||
}
|
||||
get data() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
/* Render the list items #data */
|
||||
render() {
|
||||
const list = document.createElement('ul');
|
||||
list.style = "overflow: auto;";
|
||||
|
||||
const select = e => {
|
||||
if(e.type ==="keyup" && !(e.key==="Enter" )) return;
|
||||
this.#shadow.querySelectorAll('li.selected').forEach(item => { item.className = ''; });
|
||||
e.currentTarget.className = 'selected';
|
||||
const i=e.currentTarget.getAttribute("data-index")
|
||||
console.log('Item index clicked:', i,this.#data[i]);
|
||||
// You can dispatch a custom event here if needed.
|
||||
this.dispatchEvent(new CustomEvent('itemSelected', {
|
||||
detail: this.#data[i],
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
};
|
||||
this.#data.forEach((item, index) => {
|
||||
const listItem = document.createElement('li');
|
||||
const icon=this.#iconKinds[item.kind];
|
||||
listItem.setAttribute("tabindex", "0")
|
||||
listItem.setAttribute("data-index", index)
|
||||
listItem.innerHTML = `<span title='A ${icon}'>XX<i class='codicon codicon-${icon}' >*</i></span>
|
||||
<span >${item.name} - ${item.detail}</span>`;
|
||||
|
||||
listItem.addEventListener('click', select);
|
||||
listItem.addEventListener('keyup', select);
|
||||
list.appendChild(listItem);
|
||||
});
|
||||
|
||||
this.#shadow.innerHTML = '';
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@import url("../codicon@0.0.40/codicon.css");
|
||||
ul { list-style-type: none; padding:0;margin:0;
|
||||
background-color: #e3e4e4ff;font-size: 80%; scrollbar-color: #000077 #bada55;}
|
||||
li { padding: 0 0 0 2px; border-bottom: 1px solid #ccc; cursor: pointer; width:100%; }
|
||||
li:not(.selected) :hover { background-color: #ccc; }
|
||||
.selected { background-color: #0d6efd;color: #ffff;}
|
||||
i {vertical-align: middle;}
|
||||
`;
|
||||
this.#shadow.appendChild(style);
|
||||
this.#shadow.appendChild(list);
|
||||
}
|
||||
|
||||
/* Render an error message if JSON fetching fails */
|
||||
renderError(error) {
|
||||
this.#shadow.innerHTML = `<p>Error loading data: ${error.message}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the new custom element */
|
||||
customElements.define('qd-panel', PanelComponent);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,33 @@
|
|||
// a popover dialog NOT WORKING
|
||||
class PopupInfo extends HTMLElement {
|
||||
constructor() {
|
||||
// Always call super first in constructor
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Create a shadow root
|
||||
const shadow = this.attachShadow({ mode: "open" });
|
||||
|
||||
// Create spans
|
||||
const dialog = document.createElement("dialog");
|
||||
dialog.setAttribute("id", this.getAttribute("id"));
|
||||
dialog.setAttribute("popover","popover");
|
||||
const header = document.createElement("header");
|
||||
header.innerText="HEADE"
|
||||
const main = document.createElement("main");
|
||||
main.innerText="MAIN"
|
||||
const footer = document.createElement("footer");
|
||||
footer.innerText="WWW"
|
||||
dialog.appendChild(header);
|
||||
dialog.appendChild(main);
|
||||
dialog.appendChild(footer)
|
||||
// Attach the created elements to the shadow dom
|
||||
shadow.appendChild(dialog);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Define the new element
|
||||
customElements.define("popup-info", PopupInfo);
|
||||
// a popover dialog NOT WORKING
|
||||
class PopupInfo extends HTMLElement {
|
||||
constructor() {
|
||||
// Always call super first in constructor
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Create a shadow root
|
||||
const shadow = this.attachShadow({ mode: "open" });
|
||||
|
||||
// Create spans
|
||||
const dialog = document.createElement("dialog");
|
||||
dialog.setAttribute("id", this.getAttribute("id"));
|
||||
dialog.setAttribute("popover","popover");
|
||||
const header = document.createElement("header");
|
||||
header.innerText="HEADE"
|
||||
const main = document.createElement("main");
|
||||
main.innerText="MAIN"
|
||||
const footer = document.createElement("footer");
|
||||
footer.innerText="WWW"
|
||||
dialog.appendChild(header);
|
||||
dialog.appendChild(main);
|
||||
dialog.appendChild(footer)
|
||||
// Attach the created elements to the shadow dom
|
||||
shadow.appendChild(dialog);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Define the new element
|
||||
customElements.define("popup-info", PopupInfo);
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
```html
|
||||
<i class='codicon codicon-symbol-method'></i>
|
||||
```
|
||||
|
||||
* [search codicon icons](https://microsoft.github.io/vscode-codicons/dist/codicon.html)
|
||||
* https://github.com/microsoft/vscode-codicons
|
||||
```html
|
||||
<i class='codicon codicon-symbol-method'></i>
|
||||
```
|
||||
|
||||
* [search codicon icons](https://microsoft.github.io/vscode-codicons/dist/codicon.html)
|
||||
* https://github.com/microsoft/vscode-codicons
|
||||
* https://github.com/microsoft/vscode-codicons/releases/tag/v0.0.40
|
||||
Loading…
Add table
Add a link
Reference in a new issue