diff --git a/ea-scripts/Box Each Selected Groups.md b/ea-scripts/Box Each Selected Groups.md index 6875f96..ca33cec 100644 --- a/ea-scripts/Box Each Selected Groups.md +++ b/ea-scripts/Box Each Selected Groups.md @@ -1,181 +1,181 @@ -/* -![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg) - -Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian. - -![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-each-selected-groups.png) - -This script will add encapsulating boxes around each of the currently selected groups in Excalidraw. - -You can focus on content creation first, and then batch add consistent style boxes to each group of text. - -Tips 1: You can copy the desired style to the global state using script `Copy Selected Element Style to Global`, then add boxes with the same global style using script `Box Each Selected Groups`. - -Tips 2: Next you can use scripts `Expand rectangles horizontally keep text centered` and `Expand rectangles vertically keep text centered` to make the boxes the same size, if you wish. - -Tips 3: If you want the left and right margins to be different from the top and bottom margins, input something like `32,16`, this will create a box with left and right margins of `32` and top and bottom margins of `16`. - -See documentation for more details: -https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html - -```javascript -*/ -if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) { - new Notice("This script requires a newer version of Excalidraw. Please install the latest version."); - return; -} -settings = ea.getScriptSettings(); -//set default values on first run -if(!settings["Default padding"]) { - settings = { - "Prompt for padding?": true, - "Default padding" : { - value: 10, - description: "Padding between the bounding box of the selected elements, and the box the script creates" - }, - "Remember last padding?": false - }; - ea.setScriptSettings(settings); -} - -let paddingStr = settings["Default padding"].value.toString(); -const rememberLastPadding = settings["Remember last padding?"]; - -if(settings["Prompt for padding?"]) { - paddingStr = await utils.inputPrompt("padding?","string",paddingStr); -} -if(!paddingStr) { - return; -} -if(rememberLastPadding) { - settings["Default padding"].value = paddingStr; - ea.setScriptSettings(settings); -} -var paddingLR = 0; -var paddingTB = 0; -if(paddingStr.indexOf(',') > 0) { - const paddingParts = paddingStr.split(','); - paddingLR = parseInt(paddingParts[0]); - paddingTB = parseInt(paddingParts[1]); -} -else { - paddingLR = paddingTB = parseInt(paddingStr); -} - -if(isNaN(paddingLR) || isNaN(paddingTB)) { - return; -} - -const selectedElements = ea.getViewSelectedElements(); -const groups = ea.getMaximumGroups(selectedElements); -const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements()) - .reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ? - [...result, group[0]] : result, []); -for(const elements of groups) { - if(elements.length === 1 && elements[0].type ==="arrow" || elements[0].type==="line") { - // individual arrows or lines are not affected - continue; - } - const box = ea.getBoundingBox(elements); - color = ea - .getExcalidrawAPI() - .getAppState() - .currentItemStrokeColor; - // use current stroke with and style - const appState = ea.getExcalidrawAPI().getAppState(); - const strokeWidth = appState.currentItemStrokeWidth; - const strokeStyle = appState.currentItemStrokeStyle; - const strokeSharpness = appState.currentItemStrokeSharpness; - const roughness = appState.currentItemRoughness; - const fillStyle = appState.currentItemFillStyle; - const backgroundColor = appState.currentItemBackgroundColor; - ea.style.strokeWidth = strokeWidth; - ea.style.strokeStyle = strokeStyle; - ea.style.strokeSharpness = strokeSharpness; - ea.style.roughness = roughness; - ea.style.fillStyle = fillStyle; - ea.style.backgroundColor = backgroundColor; - ea.style.strokeColor = color; - - const id = ea.addRect( - box.topX - paddingLR, - box.topY - paddingTB, - box.width + 2*paddingLR, - box.height + 2*paddingTB - ); - - // Change the join point in the group to the new box - const elementsWithBounded = elements.filter(el => (el.boundElements || []).length > 0); - const boundedElementsCollection = elementsWithBounded.reduce((result, el) => [...result, ...el.boundElements], []); - for(const el of elementsWithBounded) { - el.boundElements = []; - } - - const newRect = ea.getElement(id); - newRect.boundElements = boundedElementsCollection; - - const elementIds = elements.map(el => el.id); - - const startBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.startBinding||{}).elementId)); - for(startBindingLine of startBindingLines) { - startBindingLine.startBinding.elementId = id; - recalculateStartPointOfLine(startBindingLine, newRect); - } - - const endBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.endBinding||{}).elementId)); - for(endBindingLine of endBindingLines) { - endBindingLine.endBinding.elementId = id; - recalculateEndPointOfLine(endBindingLine, newRect); - } - - ea.copyViewElementsToEAforEditing(elements); - ea.addToGroup([id].concat(elements.map((el)=>el.id))); - ea.addElementsToView(false); - ea.reset(); -} - -function recalculateStartPointOfLine(line, el) { - const aX = el.x + el.width/2; - const bX = line.x + line.points[1][0]; - const aY = el.y + el.height/2; - const bY = line.y + line.points[1][1]; - - line.startBinding.gap = 8; - line.startBinding.focus = 0; - const intersectA = ea.intersectElementWithLine( - el, - [bX, bY], - [aX, aY], - line.startBinding.gap - ); - - if(intersectA.length > 0) { - line.points[0] = [0, 0]; - for(var i = 1; i 0) { - line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y]; - } +/* +![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg) + +Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian. + +![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-each-selected-groups.png) + +This script will add encapsulating boxes around each of the currently selected groups in Excalidraw. + +You can focus on content creation first, and then batch add consistent style boxes to each group of text. + +Tips 1: You can copy the desired style to the global state using script `Copy Selected Element Style to Global`, then add boxes with the same global style using script `Box Each Selected Groups`. + +Tips 2: Next you can use scripts `Expand rectangles horizontally keep text centered` and `Expand rectangles vertically keep text centered` to make the boxes the same size, if you wish. + +Tips 3: If you want the left and right margins to be different from the top and bottom margins, input something like `32,16`, this will create a box with left and right margins of `32` and top and bottom margins of `16`. + +See documentation for more details: +https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html + +```javascript +*/ +if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) { + new Notice("This script requires a newer version of Excalidraw. Please install the latest version."); + return; +} +settings = ea.getScriptSettings(); +//set default values on first run +if(!settings["Default padding"]) { + settings = { + "Prompt for padding?": true, + "Default padding" : { + value: 10, + description: "Padding between the bounding box of the selected elements, and the box the script creates" + }, + "Remember last padding?": false + }; + ea.setScriptSettings(settings); +} + +let paddingStr = settings["Default padding"].value.toString(); +const rememberLastPadding = settings["Remember last padding?"]; + +if(settings["Prompt for padding?"]) { + paddingStr = await utils.inputPrompt("padding?","string",paddingStr); +} +if(!paddingStr) { + return; +} +if(rememberLastPadding) { + settings["Default padding"].value = paddingStr; + ea.setScriptSettings(settings); +} +var paddingLR = 0; +var paddingTB = 0; +if(paddingStr.indexOf(',') > 0) { + const paddingParts = paddingStr.split(','); + paddingLR = parseInt(paddingParts[0]); + paddingTB = parseInt(paddingParts[1]); +} +else { + paddingLR = paddingTB = parseInt(paddingStr); +} + +if(isNaN(paddingLR) || isNaN(paddingTB)) { + return; +} + +const selectedElements = ea.getViewSelectedElements(); +const groups = ea.getMaximumGroups(selectedElements); +const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements()) + .reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ? + [...result, group[0]] : result, []); +for(const elements of groups) { + if(elements.length === 1 && elements[0].type ==="arrow" || elements[0].type==="line") { + // individual arrows or lines are not affected + continue; + } + const box = ea.getBoundingBox(elements); + color = ea + .getExcalidrawAPI() + .getAppState() + .currentItemStrokeColor; + // use current stroke with and style + const appState = ea.getExcalidrawAPI().getAppState(); + const strokeWidth = appState.currentItemStrokeWidth; + const strokeStyle = appState.currentItemStrokeStyle; + const strokeSharpness = appState.currentItemStrokeSharpness; + const roughness = appState.currentItemRoughness; + const fillStyle = appState.currentItemFillStyle; + const backgroundColor = appState.currentItemBackgroundColor; + ea.style.strokeWidth = strokeWidth; + ea.style.strokeStyle = strokeStyle; + ea.style.strokeSharpness = strokeSharpness; + ea.style.roughness = roughness; + ea.style.fillStyle = fillStyle; + ea.style.backgroundColor = backgroundColor; + ea.style.strokeColor = color; + + const id = ea.addRect( + box.topX - paddingLR, + box.topY - paddingTB, + box.width + 2*paddingLR, + box.height + 2*paddingTB + ); + + // Change the join point in the group to the new box + const elementsWithBounded = elements.filter(el => (el.boundElements || []).length > 0); + const boundedElementsCollection = elementsWithBounded.reduce((result, el) => [...result, ...el.boundElements], []); + for(const el of elementsWithBounded) { + el.boundElements = []; + } + + const newRect = ea.getElement(id); + newRect.boundElements = boundedElementsCollection; + + const elementIds = elements.map(el => el.id); + + const startBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.startBinding||{}).elementId)); + for(startBindingLine of startBindingLines) { + startBindingLine.startBinding.elementId = id; + recalculateStartPointOfLine(startBindingLine, newRect); + } + + const endBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.endBinding||{}).elementId)); + for(endBindingLine of endBindingLines) { + endBindingLine.endBinding.elementId = id; + recalculateEndPointOfLine(endBindingLine, newRect); + } + + ea.copyViewElementsToEAforEditing(elements); + ea.addToGroup([id].concat(elements.map((el)=>el.id))); + ea.addElementsToView(false); + ea.reset(); +} + +function recalculateStartPointOfLine(line, el) { + const aX = el.x + el.width/2; + const bX = line.x + line.points[1][0]; + const aY = el.y + el.height/2; + const bY = line.y + line.points[1][1]; + + line.startBinding.gap = 8; + line.startBinding.focus = 0; + const intersectA = ea.intersectElementWithLine( + el, + [bX, bY], + [aX, aY], + line.startBinding.gap + ); + + if(intersectA.length > 0) { + line.points[0] = [0, 0]; + for(var i = 1; i 0) { + line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y]; + } } \ No newline at end of file diff --git a/manifest.json b/manifest.json index 3a7689f..a82f174 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-excalidraw-plugin", "name": "Excalidraw", - "version": "1.5.21", + "version": "1.5.22", "minAppVersion": "0.12.16", "description": "An Obsidian plugin to edit and view Excalidraw drawings", "author": "Zsolt Viczian", diff --git a/src/ExcalidrawAutomate.ts b/src/ExcalidrawAutomate.ts index 2ce349a..a0461f8 100644 --- a/src/ExcalidrawAutomate.ts +++ b/src/ExcalidrawAutomate.ts @@ -786,10 +786,11 @@ export async function initExcalidrawAutomate( : 0.1, gap: GAP, }, - startArrowhead: formatting?.startArrowHead + //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/388 + startArrowhead: typeof (formatting?.startArrowHead) !== "undefined" ? formatting.startArrowHead : this.style.startArrowHead, - endArrowhead: formatting?.endArrowHead + endArrowhead: typeof (formatting?.endArrowHead) !== "undefined" ? formatting.endArrowHead : this.style.endArrowHead, ...boxedElement(id, "arrow", points[0][0], points[0][1], box.w, box.h), diff --git a/src/ExcalidrawData.ts b/src/ExcalidrawData.ts index cfa6e5d..9e3e154 100644 --- a/src/ExcalidrawData.ts +++ b/src/ExcalidrawData.ts @@ -81,7 +81,8 @@ export const REGEX_LINK = { export const REG_LINKINDEX_HYPERLINK = /^\w+:\/\//; -const DRAWING_REG = /\n# Drawing\n[^`]*(```json\n)([\s\S]*?)```/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 +//added \n at and of DRAWING_REG: https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/357 +const DRAWING_REG = /\n# Drawing\n[^`]*(```json\n)([\s\S]*?)```\n/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182 const DRAWING_REG_FALLBACK = /\n# Drawing\n(```json\n)?(.*)(```)?(%%)?/gm; export function getJSON(data: string): { scene: string; pos: number } { let res = data.matchAll(DRAWING_REG); @@ -105,11 +106,7 @@ export function getJSON(data: string): { scene: string; pos: number } { } export function getMarkdownDrawingSection(jsonString: string) { - return `%%\n# Drawing\n${String.fromCharCode(96)}${String.fromCharCode( - 96, - )}${String.fromCharCode(96)}json\n${jsonString}\n${String.fromCharCode( - 96, - )}${String.fromCharCode(96)}${String.fromCharCode(96)}\n%%`; + return `%%\n# Drawing\n\x60\x60\x60json\n${jsonString}\n\x60\x60\x60\n%%`; } /** @@ -382,11 +379,7 @@ export class ExcalidrawData { newOriginalText: string, forceUpdate: boolean = false, ) { - //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/376 - if (sceneTextElement.containerId) { - return; //I leave the setting of text size to excalidraw, when text is in a container - //because text width is fixed to the container width - } + if (forceUpdate || newText != sceneTextElement.text) { const measure = measureText( newText, @@ -395,7 +388,13 @@ export class ExcalidrawData { ); sceneTextElement.text = newText; sceneTextElement.originalText = newOriginalText; - sceneTextElement.width = measure.w; + + if (!sceneTextElement.containerId) { + //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/376 + //I leave the setting of text width to excalidraw, when text is in a container + //because text width is fixed to the container width + sceneTextElement.width = measure.w; + } sceneTextElement.height = measure.h; sceneTextElement.baseline = measure.baseline; } diff --git a/src/ExcalidrawView.ts b/src/ExcalidrawView.ts index 67ee85a..937b59e 100644 --- a/src/ExcalidrawView.ts +++ b/src/ExcalidrawView.ts @@ -1942,7 +1942,7 @@ export default class ExcalidrawView extends TextFileView { this.isEditingTextResetTimer = setTimeout(() => { this.isEditingText = false; this.isEditingTextResetTimer = null; - }, 300); // to give time for the onscreen keyboard to disappear + }, 1500); // to give time for the onscreen keyboard to disappear if (isDeleted) { this.excalidrawData.deleteTextElement(textElement.id); diff --git a/src/MarkdownPostProcessor.ts b/src/MarkdownPostProcessor.ts index 7f20fe0..2c5e5c4 100644 --- a/src/MarkdownPostProcessor.ts +++ b/src/MarkdownPostProcessor.ts @@ -52,6 +52,9 @@ const getIMG = async ( file = f; } + // https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/387 + imgAttributes.style = imgAttributes.style.replaceAll(" ","-"); + const exportSettings: ExportSettings = { withBackground: plugin.settings.exportWithBackground, withTheme: plugin.settings.exportWithTheme, @@ -237,7 +240,6 @@ const processInternalEmbeds = async ( attr.style = `excalidraw-svg${parts[3] ? `-${parts[3]}` : ""}`; } } - attr.fname = file?.path; attr.file = file; const div = await createImageDiv(attr); diff --git a/src/Scripts.ts b/src/Scripts.ts index a8f219b..475713c 100644 --- a/src/Scripts.ts +++ b/src/Scripts.ts @@ -1,9 +1,10 @@ -import { App, Instruction, TAbstractFile, TFile } from "obsidian"; +import { App, Instruction, Notice, TAbstractFile, TFile } from "obsidian"; import { PLUGIN_ID, VIEW_TYPE_EXCALIDRAW } from "./constants"; import ExcalidrawView from "./ExcalidrawView"; +import { t } from "./lang/helpers"; import ExcalidrawPlugin from "./main"; import { GenericInputPrompt, GenericSuggester } from "./Prompt"; -import { splitFolderAndFilename } from "./Utils"; +import { errorlog, splitFolderAndFilename } from "./Utils"; export class ScriptEngine { private plugin: ExcalidrawPlugin; @@ -70,20 +71,23 @@ export class ScriptEngine { this.loadScripts(); } - loadScripts() { + public getListofScripts(): TFile[] { const app = this.plugin.app; this.scriptPath = this.plugin.settings.scriptFolderPath; if (!app.vault.getAbstractFileByPath(this.scriptPath)) { this.scriptPath = null; return; } - const scripts = app.vault + return app.vault .getFiles() .filter((f: TFile) => f.path.startsWith(this.scriptPath)); - scripts.forEach((f) => this.loadScript(f)); } - getScriptName(f: TFile | string): string { + loadScripts() { + this.getListofScripts()?.forEach((f) => this.loadScript(f)); + } + + public getScriptName(f: TFile | string): string { let basename = ""; let path = ""; if (f instanceof TFile) { @@ -161,9 +165,9 @@ export class ScriptEngine { //https://stackoverflow.com/questions/45381204/get-asyncfunction-constructor-in-typescript changed tsconfig to es2017 //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor; - const result = await new AsyncFunction("ea", "utils", script)( - this.plugin.ea, - { + let result = null; + try { + result = await new AsyncFunction("ea", "utils", script)(this.plugin.ea, { inputPrompt: (header: string, placeholder?: string, value?: string) => ScriptEngine.inputPrompt(this.plugin.app, header, placeholder, value), suggester: ( @@ -179,8 +183,11 @@ export class ScriptEngine { hint, instructions, ), - }, - ); + }); + } catch (e) { + new Notice(t("SCRIPT_EXECUTION_ERROR"), 4000); + errorlog({ script: this.plugin.ea.activeScript, error: e }); + } this.plugin.ea.activeScript = null; return result; } diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index 5dbaa05..e3f1218 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -316,4 +316,8 @@ export default { //EmbeddedFileLoader.ts INFINITE_LOOP_WARNING: "EXCALIDRAW WARNING\nAborted loading embedded images due to infinite loop in file:\n", + + //Scripts.ts + SCRIPT_EXECUTION_ERROR: + "Script execution error. Please find error message on the developer console.", }; diff --git a/src/settings.ts b/src/settings.ts index a1abaa6..5d66a20 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,3 +1,4 @@ +import { borderTopRightRadius } from "html2canvas/dist/types/css/property-descriptors/border-radius"; import { App, DropdownComponent, @@ -913,7 +914,13 @@ export class ExcalidrawSettingTab extends PluginSettingTab { ); }); - if (Object.keys(this.plugin.settings.scriptEngineSettings).length > 0) { + const scripts = this.plugin.scriptEngine + .getListofScripts() + ?.map((f) => this.plugin.scriptEngine.getScriptName(f)); + if ( + Object.keys(this.plugin.settings.scriptEngineSettings).length > 0 && + scripts + ) { const getValue = (scriptName: string, variableName: string): any => { const variable = //@ts-ignore @@ -1034,8 +1041,9 @@ export class ExcalidrawSettingTab extends PluginSettingTab { }; this.containerEl.createEl("h1", { text: t("SCRIPT_SETTINGS_HEAD") }); - Object.keys(this.plugin.settings.scriptEngineSettings).forEach( - (scriptName: string) => { + Object.keys(this.plugin.settings.scriptEngineSettings) + .filter((s) => scripts.contains(s)) + .forEach((scriptName: string) => { const settings = //@ts-ignore this.plugin.settings.scriptEngineSettings[scriptName]; @@ -1084,8 +1092,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab { break; } }); - }, - ); + }); } } } diff --git a/versions.json b/versions.json index f7625da..66564a9 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,4 @@ { - "1.5.21": "0.12.16", + "1.5.22": "0.12.16", "1.4.2": "0.11.13" }