diff --git a/apps/fullstack/components/editor/worker/pageWorker/pageworker.ts b/apps/fullstack/components/editor/worker/pageWorker/pageworker.ts index 8d1d3cc0cdf75f2938a1ae8f3e628774b0127693..14cc908fc2694f870e925fc3a4620d1faf45e7bf 100644 --- a/apps/fullstack/components/editor/worker/pageWorker/pageworker.ts +++ b/apps/fullstack/components/editor/worker/pageWorker/pageworker.ts @@ -33,7 +33,7 @@ const debug = (...args: unknown[]) => { export class PageWorker { static #instance: PageWorker; - private constructor() { } + private constructor() {} public static get instance(): PageWorker { if (!PageWorker.#instance) { @@ -221,6 +221,7 @@ export class PageWorker { throw new Error("Page needs to be initialized to place snips!"); } debug("[placeOnPage]", "Placing snip", data.snip.id); + data.snip.book_id = this.page.data.book_id; const snip = await loadSnip(data.snip); debug("[placeOnPage]", "Got snip", snip.type); snip.socket = this.page.socket; diff --git a/apps/fullstack/lib/hooks/useDevicePixelRatio.ts b/apps/fullstack/lib/hooks/useDevicePixelRatio.ts index 24797e119ecea999d126a8888d35842dfd98e18e..7f4bba47164d8642fe0b225999d8ed00d35c27f5 100644 --- a/apps/fullstack/lib/hooks/useDevicePixelRatio.ts +++ b/apps/fullstack/lib/hooks/useDevicePixelRatio.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useState } from "react"; const useDevicePixelRatio = () => { - const [pixelRatio, setPixelRatio] = useState(window?.devicePixelRatio || 1); + const [pixelRatio, setPixelRatio] = useState(getDevicePixelRatio()); const handleChange = useCallback(() => { setPixelRatio(window.devicePixelRatio); @@ -31,4 +31,17 @@ const useDevicePixelRatio = () => { return pixelRatio; }; +/** + * Returns the current device pixel ratio (DPR) given the passed options + * + * @param options + * @returns current device pixel ratio + */ +export function getDevicePixelRatio(): number { + const hasDprProp = + typeof window !== "undefined" && + typeof window.devicePixelRatio === "number"; + return hasDprProp ? window.devicePixelRatio : 1; //defaults to 1 +} + export default useDevicePixelRatio; diff --git a/apps/images/src/render/overrides.ts b/apps/images/src/render/overrides.ts index ad57975fd5986e20548a6dca3aa09eb069d1ffa8..27e9b46c1e1d14874e1ec528fe9af29e36c4f8a9 100644 --- a/apps/images/src/render/overrides.ts +++ b/apps/images/src/render/overrides.ts @@ -1,9 +1,13 @@ -import { createCanvas, Image } from "canvas"; +import { Canvas, Image } from "canvas"; import sharp from "sharp"; +import { BaseSnip } from "@snip/snips/general/base"; import { ImageSnip } from "@snip/snips/general/image"; import { ImageSnipLegacy } from "@snip/snips/general/legacy/image"; -import { TextSnip } from "@snip/snips/general/text"; + +BaseSnip.prototype.createCanvas = function (width: number, height: number) { + return new Canvas(width, height); +}; // eslint-disable-next-line @typescript-eslint/no-explicit-any const get_bitmap = async function (this: any) { @@ -40,63 +44,3 @@ const get_bitmap = async function (this: any) { ImageSnipLegacy.prototype.get_bitmap = get_bitmap; ImageSnip.prototype.get_bitmap = get_bitmap; - -TextSnip.prototype.get_overlap_index_v3 = function (str, maxWidth, font) { - if (maxWidth == -1) { - return undefined; - } - const canvas = createCanvas(1, 1); - const ctx = canvas.getContext("2d"); - ctx.font = font; - - let width = 0; - for (let c = 0; c < str.length; c++) { - const char = str.charAt(c); - width += ctx.measureText(char).width; - if (width > maxWidth) { - return c; - } - } - return undefined; -}; - -TextSnip.prototype.splitStringAtWrap = function ( - str: string, - maxWidth: number, - font: string, -): string[] { - if (maxWidth == -1) { - return [str]; - } - - const canvas = createCanvas(1, 1); - const ctx = canvas.getContext("2d"); - ctx.font = font; - - let width = 0; - const splits = []; - for (let c = 0; c < str.length; c++) { - const char = str.charAt(c); - const cWidth = ctx.measureText(char).width; - width += cWidth; - if (width >= maxWidth) { - splits.push(c); - width = cWidth; - } - } - - // split into segments - const segments: string[] = []; - let start = 0; - - for (const split of splits) { - segments.push(str.slice(start, split)); - start = split; - } - - // Add the last segment if there's any remaining part of the string - if (start < str.length) { - segments.push(str.slice(start)); - } - return segments; -}; diff --git a/apps/socket/src/prefixes/snip/socket.ts b/apps/socket/src/prefixes/snip/socket.ts index 0d2b9f96b929f5d249ca002e9d5177ffb75ea0e2..405cbc458c7d52709ead055a87787bc7db3739ab 100644 --- a/apps/socket/src/prefixes/snip/socket.ts +++ b/apps/socket/src/prefixes/snip/socket.ts @@ -212,7 +212,13 @@ async function update( await triggerRender(socket.book_id, page_id, server); } -async function remove({ socket, server }: SocketData, id: ID, callback) { +async function remove( + { socket, server }: SocketData, + id: ID, + callback: ( + res: { success: true } | { success: false; details: string }, + ) => void, +) { // Snips can only be removed/erased if one has created them oneself // and if they are placed in the last 5 mins let page_id; @@ -221,8 +227,9 @@ async function remove({ socket, server }: SocketData, id: ID, callback) { page_id = snip.page_id; if ( snip.created_by != socket.data.id || - snip.last_updated.getTime() < - Date.now() - client_config.TOOLS.ERASER.TIMEOUT * 1000 + (snip.last_updated && + snip.last_updated.getTime() < + Date.now() - client_config.TOOLS.ERASER.TIMEOUT * 1000) ) { throw new Error("Cant delete snip!"); } @@ -236,7 +243,7 @@ async function remove({ socket, server }: SocketData, id: ID, callback) { } catch (e) { callback?.({ success: false, - details: e.message, + details: ((e as Error)?.message as string) || "", }); } diff --git a/packages/database/src/services/snip.ts b/packages/database/src/services/snip.ts index 2222bf7a6c5187413f59196eab4d87569b03e53d..d1e6fdec861e8b32fe2b7840df25ebf4cdea4fef 100644 --- a/packages/database/src/services/snip.ts +++ b/packages/database/src/services/snip.ts @@ -97,6 +97,10 @@ export class SnipService implements SnipStrategy { console.warn("SnipService.insert: id is set, inserting new snip"); } + if (!snipData.created_by) { + console.warn(`Inserting without owner (created_by)!`); + } + // Check if snip has blob and insert let blob_id: number | null = null; if (hasOwnProperty(snipData.data, "blob")) { @@ -118,6 +122,10 @@ export class SnipService implements SnipStrategy { // Insert nested snips snip_data.snips = await Promise.all( snip_data.snips.map(async (snipd) => { + // Sanity overwrite for book id and created by + snipd.created_by = snipData.created_by; + snipd.book_id = snipData.book_id; + return await this.insert(snipd); }), ); @@ -129,6 +137,11 @@ export class SnipService implements SnipStrategy { const snip_data = snipData.data as BaseData & { snip: SnipData<BaseData, BaseView>; }; + + // Sanity overwrite for book id and created by + snip_data.snip.created_by = snipData.created_by; + snip_data.snip.book_id = snipData.book_id; + snip_data.snip = await this.insert(snip_data.snip); snipData.data = snip_data; }