+20
@@ -7,6 +7,12 @@ import { PageNamespaceHook } from "../server/hooks/page_namespace.ts";
|
||||
import { SilverBulletHooks } from "../common/manifest.ts";
|
||||
import { System } from "../plugos/system.ts";
|
||||
import { BuiltinSettings } from "./types.ts";
|
||||
import { fulltextSyscalls } from "./syscalls/fulltext.ts";
|
||||
import { indexerSyscalls } from "./syscalls/index.ts";
|
||||
import { storeSyscalls } from "./syscalls/store.ts";
|
||||
import { EventHook } from "../plugos/hooks/event.ts";
|
||||
import { clientStoreSyscalls } from "./syscalls/clientStore.ts";
|
||||
import { sandboxFetchSyscalls } from "./syscalls/fetch.ts";
|
||||
|
||||
safeRun(async () => {
|
||||
const httpPrimitives = new HttpSpacePrimitives("");
|
||||
@@ -35,6 +41,16 @@ safeRun(async () => {
|
||||
const serverSpace = new Space(spacePrimitives);
|
||||
serverSpace.watch();
|
||||
|
||||
// Register some web-specific syscall implementations
|
||||
system.registerSyscalls(
|
||||
[],
|
||||
storeSyscalls(serverSpace),
|
||||
indexerSyscalls(serverSpace),
|
||||
clientStoreSyscalls(),
|
||||
fulltextSyscalls(serverSpace),
|
||||
sandboxFetchSyscalls(serverSpace),
|
||||
);
|
||||
|
||||
console.log("Booting...");
|
||||
|
||||
const settings = parseYamlSettings(settingsPageText) as BuiltinSettings;
|
||||
@@ -42,10 +58,14 @@ safeRun(async () => {
|
||||
if (!settings.indexPage) {
|
||||
settings.indexPage = "index";
|
||||
}
|
||||
// Event hook
|
||||
const eventHook = new EventHook();
|
||||
system.addHook(eventHook);
|
||||
|
||||
const editor = new Editor(
|
||||
serverSpace,
|
||||
system,
|
||||
eventHook,
|
||||
document.getElementById("sb-root")!,
|
||||
"",
|
||||
settings,
|
||||
|
||||
@@ -7,8 +7,14 @@ import {
|
||||
} from "../deps.ts";
|
||||
import { decoratorStateField } from "./util.ts";
|
||||
|
||||
import type { Space } from "../../common/spaces/space.ts";
|
||||
|
||||
class InlineImageWidget extends WidgetType {
|
||||
constructor(readonly url: string, readonly title: string) {
|
||||
constructor(
|
||||
readonly url: string,
|
||||
readonly title: string,
|
||||
readonly space: Space,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -21,8 +27,14 @@ class InlineImageWidget extends WidgetType {
|
||||
if (this.url.startsWith("http")) {
|
||||
img.src = this.url;
|
||||
} else {
|
||||
img.src = `fs/${this.url}`;
|
||||
// Specific to mobile
|
||||
this.space.readAttachment(decodeURI(this.url), "dataurl").then(
|
||||
({ data }) => {
|
||||
img.src = data as string;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
img.alt = this.title;
|
||||
img.title = this.title;
|
||||
img.style.display = "block";
|
||||
@@ -32,7 +44,7 @@ class InlineImageWidget extends WidgetType {
|
||||
}
|
||||
}
|
||||
|
||||
export function inlineImagesPlugin() {
|
||||
export function inlineImagesPlugin(space: Space) {
|
||||
return decoratorStateField((state: EditorState) => {
|
||||
const widgets: Range<Decoration>[] = [];
|
||||
const imageRegex = /!\[(?<title>[^\]]*)\]\((?<url>.+)\)/;
|
||||
@@ -54,7 +66,7 @@ export function inlineImagesPlugin() {
|
||||
const title = imageRexexResult.groups.title;
|
||||
widgets.push(
|
||||
Decoration.widget({
|
||||
widget: new InlineImageWidget(url, title),
|
||||
widget: new InlineImageWidget(url, title, space),
|
||||
}).range(node.to),
|
||||
);
|
||||
},
|
||||
|
||||
+30
-9
@@ -24,6 +24,7 @@ import {
|
||||
markdown,
|
||||
runScopeHandlers,
|
||||
searchKeymap,
|
||||
sqlLanguage,
|
||||
standardKeymap,
|
||||
StreamLanguage,
|
||||
syntaxHighlighting,
|
||||
@@ -32,7 +33,6 @@ import {
|
||||
ViewPlugin,
|
||||
ViewUpdate,
|
||||
yamlLanguage,
|
||||
sqlLanguage,
|
||||
} from "../common/deps.ts";
|
||||
import { SilverBulletHooks } from "../common/manifest.ts";
|
||||
import {
|
||||
@@ -96,6 +96,7 @@ import type {
|
||||
CompleteEvent,
|
||||
} from "../plug-api/app_event.ts";
|
||||
import { CodeWidgetHook } from "./hooks/code_widget.ts";
|
||||
import { sandboxFetchSyscalls } from "../plugos/syscalls/fetch.ts";
|
||||
|
||||
const frontMatterRegex = /^---\n(.*?)---\n/ms;
|
||||
|
||||
@@ -139,6 +140,7 @@ export class Editor {
|
||||
constructor(
|
||||
space: Space,
|
||||
system: System<SilverBulletHooks>,
|
||||
eventHook: EventHook,
|
||||
parent: Element,
|
||||
urlPrefix: string,
|
||||
readonly builtinSettings: BuiltinSettings,
|
||||
@@ -150,9 +152,7 @@ export class Editor {
|
||||
this.viewDispatch = () => {};
|
||||
this.indexPage = builtinSettings.indexPage;
|
||||
|
||||
// Event hook
|
||||
this.eventHook = new EventHook();
|
||||
this.system.addHook(this.eventHook);
|
||||
this.eventHook = eventHook;
|
||||
|
||||
// Code widget hook
|
||||
this.codeWidgetHook = new CodeWidgetHook();
|
||||
@@ -191,12 +191,8 @@ export class Editor {
|
||||
eventSyscalls(this.eventHook),
|
||||
editorSyscalls(this),
|
||||
spaceSyscalls(this),
|
||||
indexerSyscalls(this.space),
|
||||
fulltextSyscalls(this.space),
|
||||
systemSyscalls(this, this.system),
|
||||
markdownSyscalls(buildMarkdown(this.mdExtensions)),
|
||||
clientStoreSyscalls(),
|
||||
storeSyscalls(this.space),
|
||||
sandboxSyscalls(this.system),
|
||||
assetSyscalls(this.system),
|
||||
collabSyscalls(this),
|
||||
@@ -484,6 +480,7 @@ export class Editor {
|
||||
}
|
||||
// deno-lint-ignore no-this-alias
|
||||
const editor = this;
|
||||
let touchCount = 0;
|
||||
|
||||
return EditorState.create({
|
||||
doc: this.collabState ? this.collabState.ytext.toString() : text,
|
||||
@@ -528,7 +525,7 @@ export class Editor {
|
||||
),
|
||||
],
|
||||
}),
|
||||
inlineImagesPlugin(),
|
||||
inlineImagesPlugin(this.space),
|
||||
highlightSpecialChars(),
|
||||
history(),
|
||||
drawSelection(),
|
||||
@@ -601,6 +598,29 @@ export class Editor {
|
||||
},
|
||||
]),
|
||||
EditorView.domEventHandlers({
|
||||
// This may result in duplicated touch events on mobile devices
|
||||
touchmove: (event: TouchEvent, view: EditorView) => {
|
||||
touchCount++;
|
||||
},
|
||||
touchend: (event: TouchEvent, view: EditorView) => {
|
||||
if (touchCount === 0) {
|
||||
safeRun(async () => {
|
||||
const touch = event.changedTouches.item(0)!;
|
||||
const clickEvent: ClickEvent = {
|
||||
page: pageName,
|
||||
ctrlKey: event.ctrlKey,
|
||||
metaKey: event.metaKey,
|
||||
altKey: event.altKey,
|
||||
pos: view.posAtCoords({
|
||||
x: touch.clientX,
|
||||
y: touch.clientY,
|
||||
})!,
|
||||
};
|
||||
await this.dispatchAppEvent("page:click", clickEvent);
|
||||
});
|
||||
}
|
||||
touchCount = 0;
|
||||
},
|
||||
click: (event: MouseEvent, view: EditorView) => {
|
||||
safeRun(async () => {
|
||||
const clickEvent: ClickEvent = {
|
||||
@@ -1011,6 +1031,7 @@ export class Editor {
|
||||
description: `Open page (${isMacLike() ? "Cmd-k" : "Ctrl-k"})`,
|
||||
callback: () => {
|
||||
dispatch({ type: "start-navigate" });
|
||||
this.space.updatePageList();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
+42
-38
@@ -1,43 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<base href="/" />
|
||||
|
||||
<title>Silver Bullet</title>
|
||||
<script>
|
||||
Deno = {
|
||||
args: [],
|
||||
build: {
|
||||
arch: "x86_64",
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<base href="/" />
|
||||
|
||||
<title>Silver Bullet</title>
|
||||
<script>
|
||||
Deno = {
|
||||
args: [],
|
||||
build: {
|
||||
arch: "x86_64",
|
||||
},
|
||||
env: {
|
||||
get(key) {
|
||||
// return undefined;
|
||||
},
|
||||
env: {
|
||||
get(key) {
|
||||
// return undefined;
|
||||
},
|
||||
},
|
||||
errors: {
|
||||
AlreadyExists: class extends Error {},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
},
|
||||
errors: {
|
||||
AlreadyExists: class extends Error { },
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/main.css" />
|
||||
<script type="module" src="/client.js"></script>
|
||||
<link rel="manifest" href="/manifest.json" -->
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="sb-root"></div>
|
||||
</body>
|
||||
</html>
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/main.css" />
|
||||
<script type="module" src="/client.js"></script>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.png" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="sb-root"></div>
|
||||
<h1>SUPPP</h1>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { SysCallMapping } from "../../plugos/system.ts";
|
||||
import { proxySyscalls } from "../../plugos/syscalls/transport.ts";
|
||||
import type { Space } from "../../common/spaces/space.ts";
|
||||
|
||||
export function sandboxFetchSyscalls(space: Space): SysCallMapping {
|
||||
return proxySyscalls(
|
||||
[
|
||||
"sandboxFetch.fetch",
|
||||
],
|
||||
(ctx, name, ...args) => space.proxySyscall(ctx.plug, name, args),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user