diff --git a/manifest.json b/manifest.json index 19ff070..5617a24 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "1.5.6", + "version": "1.5.7", "minAppVersion": "0.12.16", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/package.json b/package.json index 34a7e3c..7a3a9d0 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "cross-env": "^7.0.3", "html2canvas": "^1.3.2", "nanoid": "^3.1.23", - "obsidian": "^0.12.16", + "obsidian": "^0.13.11", "rollup": "^2.52.3", "rollup-plugin-visualizer": "^5.5.2", "tslib": "^2.3.1", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 039c3b4..869857b 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -1058,8 +1058,8 @@ export async function initExcalidrawAutomate( errorMessage("targetView not set", "getViewSelectedElements()"); return []; } - const current = this.targetView?.excalidrawRef?.current; - const selectedElements = current?.getAppState()?.selectedElementIds; + const excalidrawAPI = this.targetView?.excalidrawAPI; + const selectedElements = excalidrawAPI.getAppState()?.selectedElementIds; if (!selectedElements) { return []; } @@ -1067,9 +1067,31 @@ export async function initExcalidrawAutomate( if (!selectedElementsKeys) { return []; } - return current + let elements:ExcalidrawElement[] = excalidrawAPI .getSceneElements() .filter((e: any) => selectedElementsKeys.includes(e.id)); + + const containerBoundTextElmenetsReferencedInElements = elements + .filter( + (el) => + el.boundElements && + el.boundElements.filter((be) => be.type === "text").length > 0, + ) + .map( + (el) => + el.boundElements + .filter((be) => be.type === "text") + .map((be) => be.id)[0], + ); + + const elementIDs = elements + .map((el) => el.id) + .concat(containerBoundTextElmenetsReferencedInElements); + + return this.getViewElements().filter((el: ExcalidrawElement) => + elementIDs.contains(el.id), + ); + }, getViewFileForImageElement(el: ExcalidrawElement): TFile | null { if (!this.targetView || !this.targetView?._loaded) { diff --git a/src/ExcalidrawData.ts b/src/ExcalidrawData.ts index 6150d1f..0f596f4 100644 --- a/src/ExcalidrawData.ts +++ b/src/ExcalidrawData.ts @@ -127,6 +127,9 @@ const estimateMaxLineLen = (text: string, originalText: string): number => { } //text will contain extra new line characters if wrapped let maxLineLen = 0; //will be non-null if text is container bound and multi line const splitText = text.split("\n"); + if (splitText.length === 1) { + return null; + } for (const line of splitText) { if (line.length > maxLineLen) { maxLineLen = line.length; @@ -859,15 +862,18 @@ export class ExcalidrawData { elementID: string, rawText: string, rawOriginalText: string, - ): Promise { - const maxLineLen = estimateMaxLineLen(rawText, rawOriginalText); - const parseResult = await this.parse(rawText); + ): Promise<[string, string]> { + let wrapAt: number = estimateMaxLineLen(rawText, rawOriginalText); + if (this.textElements.has(elementID)) { + wrapAt = this.textElements.get(elementID).wrapAt; + } + const parseResult = await this.parse(rawOriginalText); this.textElements.set(elementID, { - raw: rawText, + raw: rawOriginalText, parsed: parseResult, - wrapAt: maxLineLen, + wrapAt, }); - return parseResult; + return [wrap(parseResult, wrapAt), parseResult]; } public deleteTextElement(id: string) { diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 9512906..083fc6c 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -33,6 +33,7 @@ import { IMAGE_TYPES, CTRL_OR_CMD, REG_LINKINDEX_INVALIDCHARS, + KEYCODE, } from "./constants"; import ExcalidrawPlugin from "./main"; import { repositionElementsToCursor } from "./ExcalidrawAutomate"; @@ -331,6 +332,71 @@ export default class ExcalidrawView extends TextFileView { return this.data; } + addFullscreenchangeEvent() { + //excalidrawWrapperRef.current + this.contentEl.onfullscreenchange = () => { + if (this.plugin.settings.zoomToFitOnResize) { + this.zoomToFit(); + } + if (!this.isFullscreen()) { + this.clearFullscreenObserver(); + this.contentEl.removeAttribute("style"); + } + }; + } + + fullscreenModalObserver: MutationObserver = null; + gotoFullscreen() { + if (!this.excalidrawWrapperRef) { + return; + } + this.contentEl.requestFullscreen(); //{navigationUI: "hide"}); + this.excalidrawWrapperRef.current.focus(); + this.contentEl.setAttribute("style", "padding:0px;margin:0px;"); + + this.fullscreenModalObserver = new MutationObserver((m) => { + if (m.length !== 1) { + return; + } + if (!m[0].addedNodes || m[0].addedNodes.length !== 1) { + return; + } + const node: Node = m[0].addedNodes[0]; + if (node.nodeType !== Node.ELEMENT_NODE) { + return; + } + const element = node as HTMLElement; + if (!element.classList.contains("modal-container")) { + return; + } + this.contentEl.appendChild(element); + element.querySelector("input").focus(); + }); + + this.fullscreenModalObserver.observe(document.body, { + childList: true, + subtree: false, + }); + } + + clearFullscreenObserver() { + if (this.fullscreenModalObserver) { + this.fullscreenModalObserver.disconnect(); + this.fullscreenModalObserver = null; + } + } + + isFullscreen(): boolean { + return ( + document.fullscreenEnabled && + document.fullscreenElement === this.contentEl // excalidrawWrapperRef?.current + ); //this.contentEl; + } + + exitFullscreen() { + document.exitFullscreen(); + } + async handleLinkClick(view: ExcalidrawView, ev: MouseEvent) { const selectedText = this.getSelectedTextElement(); let file = null; @@ -369,9 +435,8 @@ export default class ExcalidrawView extends TextFileView { search[0].view.setQuery(`tag:${tags.value[1]}`); this.app.workspace.revealLeaf(search[0]); - if (document.fullscreenElement === this.contentEl) { - document.exitFullscreen(); - this.zoomToFit(); + if (this.isFullscreen()) { + this.exitFullscreen(); } return; } @@ -464,9 +529,8 @@ export default class ExcalidrawView extends TextFileView { } try { - if (ev.shiftKey && document.fullscreenElement === this.contentEl) { - document.exitFullscreen(); - this.zoomToFit(); + if (ev.shiftKey && this.isFullscreen()) { + this.exitFullscreen(); } const leaf = ev.shiftKey ? getNewOrAdjacentLeaf(this.plugin, view.leaf) @@ -527,16 +591,8 @@ export default class ExcalidrawView extends TextFileView { this.addAction( FULLSCREEN_ICON_NAME, "Press ESC to exit fullscreen mode", - () => { - this.contentEl.requestFullscreen(); //{navigationUI: "hide"}); - if (this.excalidrawWrapperRef) { - this.excalidrawWrapperRef.current.focus(); - } - }, + () => this.gotoFullscreen(), ); - this.contentEl.onfullscreenchange = () => { - this.zoomToFit(); - }; } //this is to solve sliding panes bug @@ -617,6 +673,10 @@ export default class ExcalidrawView extends TextFileView { clearInterval(this.autosaveTimer); this.autosaveTimer = null; } + if (this.fullscreenModalObserver) { + this.fullscreenModalObserver.disconnect(); + this.fullscreenModalObserver = null; + } } public async reload(fullreload: boolean = false, file?: TFile) { @@ -1175,17 +1235,18 @@ export default class ExcalidrawView extends TextFileView { const textElements = newElements.filter((el) => el.type == "text"); for (let i = 0; i < textElements.length; i++) { - const parseResult = await this.excalidrawData.addTextElement( - textElements[i].id, - //@ts-ignore - textElements[i].text, - //@ts-ignore - textElements[i].originalText, //TODO: implement originalText support in ExcalidrawAutomate - ); + const [parseResultWrapped, parseResult] = + await this.excalidrawData.addTextElement( + textElements[i].id, + //@ts-ignore + textElements[i].text, + //@ts-ignore + textElements[i].rawText, //TODO: implement originalText support in ExcalidrawAutomate + ); if (this.textMode == TextMode.parsed) { this.excalidrawData.updateTextElement( textElements[i], - parseResult, + parseResultWrapped, parseResult, ); } @@ -1480,13 +1541,8 @@ export default class ExcalidrawView extends TextFileView { if (e.target === excalidrawDiv.ref.current) { return; } //event should originate from the canvas - if ( - document.fullscreenEnabled && - document.fullscreenElement == this.contentEl && - e.keyCode === 27 - ) { - document.exitFullscreen(); - this.zoomToFit(); + if (this.isFullscreen() && e.keyCode === KEYCODE.ESC) { + this.exitFullscreen(); } this.ctrlKeyDown = e[CTRL_OR_CMD]; //.ctrlKey||e.metaKey; @@ -1550,7 +1606,7 @@ export default class ExcalidrawView extends TextFileView { sourcePath: this.plugin.hover.sourcePath, }); hoverPoint = currentPosition; - if (document.fullscreenElement === this.contentEl) { + if (this.isFullscreen()) { const self = this; setTimeout(() => { const popover = document.body.querySelector("div.popover"); @@ -1875,7 +1931,7 @@ export default class ExcalidrawView extends TextFileView { //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/318 //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/299 - if(!this.app.isMobile) { + if (!this.app.isMobile) { setTimeout(() => { this?.excalidrawWrapperRef?.current?.firstElementChild?.focus(); }, 50); @@ -1941,6 +1997,7 @@ export default class ExcalidrawView extends TextFileView { }); ReactDOM.render(reactElement, this.contentEl, () => { this.excalidrawWrapperRef.current.focus(); + this.addFullscreenchangeEvent(); }); } @@ -1971,16 +2028,16 @@ export default class ExcalidrawView extends TextFileView { } const maxZoom = this.plugin.settings.zoomToFitMaxLevel; const current = this.excalidrawAPI; - const fullscreen = document.fullscreenElement == this.contentEl; const elements = current.getSceneElements(); if (delay) { //time for the DOM to render, I am sure there is a more elegant solution setTimeout( - () => current.zoomToFit(elements, maxZoom, fullscreen ? 0 : 0.05), + () => + current.zoomToFit(elements, maxZoom, this.isFullscreen() ? 0 : 0.05), 100, ); } else { - current.zoomToFit(elements, maxZoom, fullscreen ? 0 : 0.05); + current.zoomToFit(elements, maxZoom, this.isFullscreen() ? 0 : 0.05); } } } diff --git a/src/InsertLinkDialog.ts b/src/InsertLinkDialog.ts index fbd3b87..fb4c9d4 100644 --- a/src/InsertLinkDialog.ts +++ b/src/InsertLinkDialog.ts @@ -1,3 +1,4 @@ +import { time } from "console"; import { App, FuzzySuggestModal, TFile } from "obsidian"; import { t } from "./lang/helpers"; @@ -20,21 +21,25 @@ export class InsertLinkDialog extends FuzzySuggestModal { this.emptyStateText = t("NO_MATCH"); } - getItems(): TFile[] { - return this.app.vault.getFiles(); + getItems(): any[] { + //@ts-ignore + return this.app.metadataCache.getLinkSuggestions(); } - getItemText(item: TFile): string { - return item.path; + getItemText(item: any): string { + return item.path + (item.alias ? `|${item.alias}` : ""); } - onChooseItem(item: TFile): void { - const filepath = this.app.metadataCache.fileToLinktext( - item, - this.drawingPath, - true, - ); - this.addText(`[[${filepath}]]`); + onChooseItem(item: any): void { + let filepath = item.path; + if (item.file) { + filepath = this.app.metadataCache.fileToLinktext( + item.file, + this.drawingPath, + true, + ); + } + this.addText(`[[${filepath + (item.alias ? `|${item.alias}` : "")}]]`); } public start(drawingPath: string, addText: Function) { diff --git a/src/constants.ts b/src/constants.ts index cec8891..3f3aafe 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -10,6 +10,9 @@ export const nanoid = customAlphabet( "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 8, ); +export const KEYCODE = { + ESC: 27, +}; export const fileid = customAlphabet("1234567890abcdef", 40); export const REG_LINKINDEX_INVALIDCHARS = /[<>:"\\|?*]/g; export const REG_BLOCK_REF_CLEAN = diff --git a/versions.json b/versions.json index 0e56c89..877b480 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,4 @@ { - "1.5.6": "0.12.16", + "1.5.7": "0.12.16", "1.4.2": "0.11.13" } diff --git a/yarn.lock b/yarn.lock index f8170de..e3b224c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -920,6 +920,36 @@ "@babel/helper-validator-identifier" "^7.14.9" "to-fast-properties" "^2.0.0" +"@codemirror/rangeset@^0.19.5": + "integrity" "sha512-L3b+RIwIRKOJ3pJLOtpkxCUjGnxZKFyPb0CjYWKnVLuzEIaEExWWK7sp6rsejxOy8RjYzfCHlFhYB4UdQN7brw==" + "resolved" "https://registry.npmjs.org/@codemirror/rangeset/-/rangeset-0.19.5.tgz" + "version" "0.19.5" + dependencies: + "@codemirror/state" "^0.19.0" + +"@codemirror/state@^0.19.0", "@codemirror/state@^0.19.3", "@codemirror/state@^0.19.6": + "integrity" "sha512-sqIQZE9VqwQj7D4c2oz9mfLhlT1ElAzGB5lO1lE33BPyrdNy1cJyCIOecT4cn4VeJOFrnjOeu+IftZ3zqdFETw==" + "resolved" "https://registry.npmjs.org/@codemirror/state/-/state-0.19.6.tgz" + "version" "0.19.6" + dependencies: + "@codemirror/text" "^0.19.0" + +"@codemirror/text@^0.19.0": + "integrity" "sha512-Syu5Xc7tZzeUAM/y4fETkT0zgGr48rDG+w4U38bPwSIUr+L9S/7w2wDE1WGNzjaZPz12F6gb1gxWiSTg9ocLow==" + "resolved" "https://registry.npmjs.org/@codemirror/text/-/text-0.19.5.tgz" + "version" "0.19.5" + +"@codemirror/view@^0.19.31": + "integrity" "sha512-SLuLx9p0O1ZHXLehvl5MwSvUrQRcsNGemzTgJ0zRajmc3BBsNigI1PXxdo7tvBhO5DcAzRRBXoke9DZFUR6Qqg==" + "resolved" "https://registry.npmjs.org/@codemirror/view/-/view-0.19.37.tgz" + "version" "0.19.37" + dependencies: + "@codemirror/rangeset" "^0.19.5" + "@codemirror/state" "^0.19.3" + "@codemirror/text" "^0.19.0" + "style-mod" "^4.0.0" + "w3c-keyname" "^2.2.4" + "@eslint/eslintrc@^1.0.5": "integrity" "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==" "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz" @@ -7441,11 +7471,13 @@ dependencies: "isobject" "^3.0.1" -"obsidian@^0.12.16": - "integrity" "sha512-YwwhYrmlv71A/ntTiGOyGaqr9ONhKPE1OKN1tcHovLJC0N/BRZ7XlGpzaN1T3BnAE5H8DmYLsAI3h67u6eJPGQ==" - "resolved" "https://registry.npmjs.org/obsidian/-/obsidian-0.12.16.tgz" - "version" "0.12.16" +"obsidian@^0.13.11": + "integrity" "sha512-KxOvAh4CG5vzcukmHvyuK9hUIr6ZFlM9FQfGZEwrrEV8VG2/W2Tk5cWrg0VM7EkGE3QBmjX6owjIDIO8QDXVUQ==" + "resolved" "https://registry.npmjs.org/obsidian/-/obsidian-0.13.11.tgz" + "version" "0.13.11" dependencies: + "@codemirror/state" "^0.19.6" + "@codemirror/view" "^0.19.31" "@types/codemirror" "0.0.108" "moment" "2.29.1" @@ -9736,6 +9768,11 @@ "loader-utils" "^1.0.2" "schema-utils" "^0.3.0" +"style-mod@^4.0.0": + "integrity" "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + "resolved" "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz" + "version" "4.0.0" + "supports-color@^2.0.0": "integrity" "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" @@ -10362,6 +10399,11 @@ "resolved" "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz" "version" "1.1.2" +"w3c-keyname@^2.2.4": + "integrity" "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" + "resolved" "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz" + "version" "2.2.4" + "walker@~1.0.5": "integrity" "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=" "resolved" "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz"