From 963c1aa4ad313b62e3b23121e21d9429eae14c79 Mon Sep 17 00:00:00 2001 From: Ozuba Date: Mon, 3 Feb 2025 20:50:35 +0100 Subject: [PATCH 1/2] Working deep-link reference for kicad-embed --- src/kicanvas/elements/kicanvas-embed.ts | 62 ++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/kicanvas/elements/kicanvas-embed.ts b/src/kicanvas/elements/kicanvas-embed.ts index f5f30549..2ce2264f 100644 --- a/src/kicanvas/elements/kicanvas-embed.ts +++ b/src/kicanvas/elements/kicanvas-embed.ts @@ -14,6 +14,8 @@ import { } from "../../base/web-components"; import { KCUIElement } from "../../kc-ui"; import kc_ui_styles from "../../kc-ui/kc-ui.css"; +import type { BoardViewer } from "../../viewers/board/viewer"; +import type { SchematicViewer } from "../../viewers/schematic/viewer"; import { Project } from "../project"; import { FetchFileSystem, VirtualFileSystem } from "../services/vfs"; import type { KCBoardAppElement } from "./kc-board/app"; @@ -95,7 +97,10 @@ class KiCanvasEmbedElement extends KCUIElement { }); } - async #setup_events() {} + async #setup_events() { + //Setup the deep link handler + window.addEventListener('hashchange', handleDeepLink); + } async #load_src() { const sources = []; @@ -160,7 +165,7 @@ class KiCanvasEmbedElement extends KCUIElement { const focus_overlay = (this.controls ?? "none") == "none" || - this.controlslist?.includes("nooverlay") + this.controlslist?.includes("nooverlay") ? null : html``; @@ -168,6 +173,35 @@ class KiCanvasEmbedElement extends KCUIElement { ${this.#schematic_app} ${this.#board_app} ${focus_overlay} `; } + + + async deepLinkSelect(ref: string) { + //We assure the filetype + console.log("Active Page:", this.#project.active_page); + + + switch (this.#project.active_page?.type) { + case "pcb": + const boardView = this.#board_app.viewer as BoardViewer; + boardView.select(ref); + boardView.zoom_to_selection() + break; + + case "schematic": + const schView = this.#schematic_app.viewer as SchematicViewer; + schView.select(ref); + schView.zoom_to_selection() + break; + + default: + console.log("Unknown file type"); + break; + } + + + + + } } window.customElements.define("kicanvas-embed", KiCanvasEmbedElement); @@ -195,3 +229,27 @@ document.body.appendChild( href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0&family=Nunito:wght@300;400;500;600;700&display=swap" crossorigin="anonymous" />`, ); + +function handleDeepLink() { + const hash = window.location.hash.substring(1); + if (hash) { + const parts = hash.split(":"); + if (!parts) { + console.log("Incorrect reference format"); + return null; + } + let id: string = parts[0] as string; + let ref: string = parts[1] as string; + + console.log('ID:', id, 'Reference:', ref); + const element = document.getElementById(id) as KiCanvasEmbedElement; //this should get us the kicanvas element + if (element instanceof KiCanvasEmbedElement) { //If embed element exists trigger its select + console.log(element); + element.scrollIntoView({ behavior: 'smooth' }); + element.deepLinkSelect(ref); //Sends selection of file:component + } else { + console.log("Element is not a kicanvasEmbedElement"); + } + } + return null; +} From acd2d7bff019eb92c4db2a20e1ea4efa34dd37e9 Mon Sep 17 00:00:00 2001 From: Ozuba Date: Wed, 5 Feb 2025 16:58:16 +0100 Subject: [PATCH 2/2] Implemented file changing selection --- src/kicanvas/elements/kicanvas-embed.ts | 51 ++++++++++++++----------- src/kicanvas/project.ts | 11 +++++- src/viewers/base/document-viewer.ts | 10 ++--- src/viewers/base/viewer.ts | 4 +- 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/kicanvas/elements/kicanvas-embed.ts b/src/kicanvas/elements/kicanvas-embed.ts index 2ce2264f..1c63bdc2 100644 --- a/src/kicanvas/elements/kicanvas-embed.ts +++ b/src/kicanvas/elements/kicanvas-embed.ts @@ -175,22 +175,27 @@ class KiCanvasEmbedElement extends KCUIElement { } - async deepLinkSelect(ref: string) { + async deepLinkSelect(filename: string, reference: string) { //We assure the filetype console.log("Active Page:", this.#project.active_page); - - - switch (this.#project.active_page?.type) { + let page = this.#project.page_by_name(filename); + switch (page?.type) { case "pcb": + this.#project.set_active_page(page); const boardView = this.#board_app.viewer as BoardViewer; - boardView.select(ref); - boardView.zoom_to_selection() + boardView.resolve_loaded(false); //This fixes the viewer reload bug where you cant select element if coming from the same viewer as the loaded Barrier isnt renewed + await boardView.loaded; + boardView.select(reference); + boardView.zoom_to_selection(); break; case "schematic": + this.#project.set_active_page(page); const schView = this.#schematic_app.viewer as SchematicViewer; - schView.select(ref); - schView.zoom_to_selection() + schView.resolve_loaded(false);//This fixes the viewer reload bug where you cant select element if coming from the same viewer as the loaded Barrier isnt renewed + await schView.loaded; + schView.select(reference); + schView.zoom_to_selection(); break; default: @@ -233,23 +238,23 @@ document.body.appendChild( function handleDeepLink() { const hash = window.location.hash.substring(1); if (hash) { - const parts = hash.split(":"); - if (!parts) { - console.log("Incorrect reference format"); - return null; - } - let id: string = parts[0] as string; - let ref: string = parts[1] as string; - - console.log('ID:', id, 'Reference:', ref); - const element = document.getElementById(id) as KiCanvasEmbedElement; //this should get us the kicanvas element - if (element instanceof KiCanvasEmbedElement) { //If embed element exists trigger its select - console.log(element); - element.scrollIntoView({ behavior: 'smooth' }); - element.deepLinkSelect(ref); //Sends selection of file:component + const regex = /^(?[^:]+):(?[^:]+):(?[^:]+)$/; + const match = hash.match(regex); + if (match && match.groups) { + const { id, file, reference } = match.groups; + console.log("ID:", id, " File:", file, " Reference:", reference); + const element = document.getElementById(id as string) as KiCanvasEmbedElement; //this should get us the kicanvas element + if (element instanceof KiCanvasEmbedElement) { //If embed element exists trigger its select + console.log(element); + element.scrollIntoView({ behavior: 'smooth' }); + element.deepLinkSelect(file as string, reference as string); //Sends + } else { + console.log("Element is not a kicanvasEmbedElement"); + } } else { - console.log("Element is not a kicanvasEmbedElement"); + console.log("Invalid format"); } + } return null; } diff --git a/src/kicanvas/project.ts b/src/kicanvas/project.ts index 32c78822..439bdb3f 100644 --- a/src/kicanvas/project.ts +++ b/src/kicanvas/project.ts @@ -301,6 +301,15 @@ export class Project extends EventTarget implements IDisposable { return this.#pages_by_path.get(project_path); } + public page_by_name(filename: string) { + for (const page of this.#pages_by_path.values()) { + if (page.filename === filename) { + return page; + } + } + return null; + } + public async download(name: string) { if (this.#pages_by_path.has(name)) { name = this.#pages_by_path.get(name)!.filename; @@ -351,7 +360,7 @@ export class ProjectPage { public sheet_path: string, public name?: string, public page?: string, - ) {} + ) { } /** * A unique identifier for this page within the project, diff --git a/src/viewers/base/document-viewer.ts b/src/viewers/base/document-viewer.ts index d8b148f4..43d0b3ae 100644 --- a/src/viewers/base/document-viewer.ts +++ b/src/viewers/base/document-viewer.ts @@ -74,16 +74,14 @@ export abstract class DocumentViewer< log.info("Positioning camera"); this.zoom_to_page(); - // Mark the viewer as loaded and notify event listeners - this.resolve_loaded(true); - - // Deselect any selected items. + // Deselect any selected items before marking as loaded to not cause a bug when changing page and selecting item if (this.selected) { this.selected = null; } - // Draw this.draw(); + // Mark the viewer as loaded and notify event listeners + this.resolve_loaded(true); }); } @@ -152,7 +150,7 @@ export abstract class DocumentViewer< `Unable to select item ${item}, could not find an object that matched.`, ); } - + console.log("Reference found and loadded") this.selected = item ?? null; } } diff --git a/src/viewers/base/viewer.ts b/src/viewers/base/viewer.ts index 3a497006..34add7c3 100644 --- a/src/viewers/base/viewer.ts +++ b/src/viewers/base/viewer.ts @@ -125,10 +125,12 @@ export abstract class Viewer extends EventTarget { public abstract load(src: any): Promise; - protected resolve_loaded(value: boolean) { + public resolve_loaded(value: boolean) { if (value) { this.loaded.open(); this.dispatchEvent(new KiCanvasLoadEvent()); + } else { //To enable reload awaiting + this.loaded = new Barrier(); } }