[mod] wsl

This commit is contained in:
Andy Bunce 2025-11-11 15:36:33 +00:00
parent b741dc5952
commit ddd772f563
69 changed files with 26660 additions and 25940 deletions

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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));
}

View file

@ -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>

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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>

View file

@ -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`
}});

View file

@ -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>

View file

@ -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;

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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