1
0

Handle inline images and attachments via data urls

This commit is contained in:
Zef Hemel 2023-01-08 15:29:34 +01:00
parent 0365673c41
commit 8dac58f38a
7 changed files with 53 additions and 16 deletions

View File

@ -185,6 +185,12 @@ export class Space extends EventEmitter<SpaceEvents> {
); );
} }
/**
* Reads an attachment
* @param name path of the attachment
* @param encoding how the return value is expected to be encoded
* @returns
*/
readAttachment( readAttachment(
name: string, name: string,
encoding: FileEncoding, encoding: FileEncoding,

View File

@ -78,10 +78,10 @@ export class CapacitorSpacePrimitives implements SpacePrimitives {
} }
} }
return { return {
data, data: data!,
meta: await this.getFileMeta(name), meta: await this.getFileMeta(name),
}; };
} catch (e: any) { } catch {
throw new Error(`Page not found`); throw new Error(`Page not found`);
} }
} }

View File

@ -46,6 +46,11 @@ export function openUrl(url: string): Promise<void> {
return syscall("editor.openUrl", url); return syscall("editor.openUrl", url);
} }
// Force the client to download the file in dataUrl with filename as file name
export function downloadFile(filename: string, dataUrl: string): Promise<void> {
return syscall("editor.downloadFile", filename, dataUrl);
}
export function flashNotification( export function flashNotification(
message: string, message: string,
type: "info" | "error" = "info", type: "info" | "error" = "info",

View File

@ -35,12 +35,24 @@ export function getAttachmentMeta(name: string): Promise<AttachmentMeta> {
return syscall("space.getAttachmentMeta", name); return syscall("space.getAttachmentMeta", name);
} }
/**
* Read an attachment from the space
* @param name path of the attachment to read
* @returns the attachment data encoded as a data URL
*/
export function readAttachment( export function readAttachment(
name: string, name: string,
): Promise<string> { ): Promise<string> {
return syscall("space.readAttachment", name); return syscall("space.readAttachment", name);
} }
/**
* Writes an attachment to the space
* @param name path of the attachment to write
* @param encoding encoding of the data ("string" or "dataurl)
* @param data data itself
* @returns
*/
export function writeAttachment( export function writeAttachment(
name: string, name: string,
encoding: "string" | "dataurl", encoding: "string" | "dataurl",
@ -49,6 +61,10 @@ export function writeAttachment(
return syscall("space.writeAttachment", name, encoding, data); return syscall("space.writeAttachment", name, encoding, data);
} }
/**
* Deletes an attachment from the space
* @param name path of the attachment to delete
*/
export function deleteAttachment(name: string): Promise<void> { export function deleteAttachment(name: string): Promise<void> {
return syscall("space.deleteAttachment", name); return syscall("space.deleteAttachment", name);
} }

View File

@ -1,5 +1,10 @@
import type { ClickEvent } from "$sb/app_event.ts"; import type { ClickEvent } from "$sb/app_event.ts";
import { editor, markdown, system } from "$sb/silverbullet-syscall/mod.ts"; import {
editor,
markdown,
space,
system,
} from "$sb/silverbullet-syscall/mod.ts";
import { import {
addParentPointers, addParentPointers,
findNodeOfType, findNodeOfType,
@ -8,14 +13,6 @@ import {
ParseTree, ParseTree,
} from "$sb/lib/tree.ts"; } from "$sb/lib/tree.ts";
// Checks if the URL contains a protocol, if so keeps it, otherwise assumes an attachment
function patchUrl(url: string): string {
if (url.indexOf("://") === -1) {
return `fs/${url}`;
}
return url;
}
async function actionClickOrActionEnter( async function actionClickOrActionEnter(
mdTree: ParseTree | null, mdTree: ParseTree | null,
inNewWindow = false, inNewWindow = false,
@ -71,7 +68,7 @@ async function actionClickOrActionEnter(
break; break;
} }
case "NakedURL": case "NakedURL":
await editor.openUrl(patchUrl(mdTree.children![0].text!)); await editor.openUrl(mdTree.children![0].text!);
break; break;
case "Image": case "Image":
case "Link": { case "Link": {
@ -79,11 +76,18 @@ async function actionClickOrActionEnter(
if (!urlNode) { if (!urlNode) {
return; return;
} }
const url = patchUrl(urlNode.children![0].text!); let url = urlNode.children![0].text!;
if (url.length <= 1) { if (url.length <= 1) {
return editor.flashNotification("Empty link, ignoring", "error"); return editor.flashNotification("Empty link, ignoring", "error");
} }
await editor.openUrl(url); if (url.indexOf("://") === -1) {
url = decodeURIComponent(url);
// attachment URL, let's fetch as a data url
const dataUrl = await space.readAttachment(url);
return editor.downloadFile(url, dataUrl);
} else {
await editor.openUrl(url);
}
break; break;
} }
case "CommandLink": { case "CommandLink": {

View File

@ -27,8 +27,8 @@ class InlineImageWidget extends WidgetType {
if (this.url.startsWith("http")) { if (this.url.startsWith("http")) {
img.src = this.url; img.src = this.url;
} else { } else {
// Specific to mobile // Load the image as a dataURL and inject it into the img's src attribute
this.space.readAttachment(decodeURI(this.url), "dataurl").then( this.space.readAttachment(decodeURIComponent(this.url), "dataurl").then(
({ data }) => { ({ data }) => {
img.src = data as string; img.src = data as string;
}, },

View File

@ -38,6 +38,12 @@ export function editorSyscalls(editor: Editor): SysCallMapping {
win.focus(); win.focus();
} }
}, },
"editor.downloadFile": (_ctx, filename: string, dataUrl: string) => {
const link = document.createElement("a");
link.href = dataUrl;
link.download = filename;
link.click();
},
"editor.flashNotification": ( "editor.flashNotification": (
_ctx, _ctx,
message: string, message: string,