This commit is contained in:
Zsolt Viczian
2022-02-20 23:14:23 +01:00
parent 463eb1d228
commit 1ca87741a5
8 changed files with 197 additions and 54 deletions

View File

@@ -5,12 +5,36 @@ The script allows you to change the shape of selected Rectangles, Diamonds and E
```javascript
*/
const shapesDispaly=["○ ellipse","□ rectangle","◇ diamond"];
const shapes=["ellipse","rectangle","diamond"];
elements = ea.getViewSelectedElements().filter(el=>shapes.contains(el.type));
newShape = await utils.suggester(shapesDispaly, shapes);
if(!newShape) return;
const boxShapesDispaly=["○ ellipse","□ rectangle","◇ diamond"];
const boxShapes=["ellipse","rectangle","diamond"];
const lineShapesDispaly=["- line","⭢ arrow"];
const lineShapes=["line","arrow"];
let editedElements = [];
let elements = ea.getViewSelectedElements().filter(el=>boxShapes.contains(el.type));
if (elements.length>0) {
newShape = await utils.suggester(boxShapesDispaly, boxShapes, "Change shape of 'box' type elements in selection");
if(newShape) {
editedElements = elements;
elements.forEach(el=>el.type = newShape);
}
}
elements = ea.getViewSelectedElements().filter(el=>lineShapes.contains(el.type));
if (elements.length>0) {
newShape = await utils.suggester(lineShapesDispaly, lineShapes, "Change shape of 'line' type elements in selection");
if(newShape) {
editedElements = editedElements.concat(elements);
elements.forEach((el)=>{
el.type = newShape;
if(newShape === "arrow") {
el.endArrowhead = "triangle";
}
});
}
}
ea.copyViewElementsToEAforEditing(editedElements);
elements.forEach(el=>el.type = newShape);
ea.copyViewElementsToEAforEditing(elements);
ea.addElementsToView(false,false);

View File

@@ -1,7 +1,7 @@
{
"id": "obsidian-excalidraw-plugin",
"name": "Excalidraw",
"version": "1.6.13",
"version": "1.6.14",
"minAppVersion": "0.12.16",
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
"author": "Zsolt Viczian",

View File

@@ -83,28 +83,58 @@ export const REGEX_LINK = {
},
};
export const REG_LINKINDEX_HYPERLINK = /^\w+:\/\//;
//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;
const DRAWING_COMPRESSED_REG = /\n# Drawing\n[^`]*(```compressed\-json\n)([\s\S]*?)```\n/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182
const DRAWING_COMPRESSED_REG_FALLBACK = /\n# Drawing\n(```compressed\-json\n)?(.*)(```)?(%%)?/gm;
const DRAWING_COMPRESSED_REG = /(\n# Drawing\n[^`]*(?:```compressed\-json\n))([\s\S]*?)(```\n)/gm; //https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/182
const DRAWING_COMPRESSED_REG_FALLBACK = /(\n# Drawing\n(?:```compressed\-json\n)?)(.*)((```)?(%%)?)/gm;
export const REG_LINKINDEX_HYPERLINK = /^\w+:\/\//;
const isCompressedMD = (data:string):boolean => {
return data.match(/```compressed\-json\n/gm) !== null;
}
const getDecompressedScene = (data:string):[string,IteratorResult<RegExpMatchArray, any>] => {
let res = data.matchAll(DRAWING_COMPRESSED_REG);
//In case the user adds a text element with the contents "# Drawing\n"
let parts;
parts = res.next();
if (parts.done) {
//did not find a match
res = data.matchAll(DRAWING_COMPRESSED_REG_FALLBACK);
parts = res.next();
}
if (parts.value && parts.value.length > 1) {
return [decompress(parts.value[2]),parts];
}
return [null,parts];
}
export const changeThemeOfExcalidrawMD = (data:string):string => {
const compressed = isCompressedMD(data);
let scene = compressed ? getDecompressedScene(data)[0] : data;
if(!scene) return data;
if(isObsidianThemeDark) {
if((scene.match(/"theme"\s*:\s*"light"\s*,/g)||[]).length === 1) {
scene = scene.replace(/"theme"\s*:\s*"light"\s*,/,`"theme": "dark",`);
}
} else {
if((scene.match(/"theme"\s*:\s*"dark"\s*,/g)||[]).length === 1) {
scene = scene.replace(/"theme"\s*:\s*"dark"\s*,/,`"theme": "light",`);
}
}
if(compressed) {
return data.replace(DRAWING_COMPRESSED_REG,`$1${compress(scene)}$3`);
}
return scene;
}
export function getJSON(data: string): { scene: string; pos: number } {
let res;
if(data.match(/```compressed\-json\n/gm)) {
res = data.matchAll(DRAWING_COMPRESSED_REG);
//In case the user adds a text element with the contents "# Drawing\n"
let parts;
parts = res.next();
if (parts.done) {
//did not find a match
res = data.matchAll(DRAWING_COMPRESSED_REG_FALLBACK);
parts = res.next();
}
if (parts.value && parts.value.length > 1) {
const result = decompress(parts.value[2]);
if(isCompressedMD(data)) {
const [result,parts] = getDecompressedScene(data);
if(result) {
return {
scene: result.substring(0, result.lastIndexOf("}") + 1),
pos: parts.value.index,

View File

@@ -146,6 +146,7 @@ export default class ExcalidrawView extends TextFileView {
public excalidrawAPI: any = null;
public excalidrawWrapperRef: React.MutableRefObject<any> = null;
private justLoaded: boolean = false;
private preventAutozoomOnLoad: boolean = false;
private plugin: ExcalidrawPlugin;
private dirty: string = null;
public autosaveTimer: any = null;
@@ -693,7 +694,7 @@ export default class ExcalidrawView extends TextFileView {
this.textIsParsed_Element.hide();
}
if (reload) {
await this.save(false);
await this.save(false,true);
this.updateContainerSize();
this.excalidrawAPI.history.clear(); //to avoid undo replacing links with parsed text
}
@@ -758,6 +759,7 @@ export default class ExcalidrawView extends TextFileView {
const loadOnModifyTrigger = (file && file === this.file);
if (loadOnModifyTrigger) {
this.data = await this.app.vault.cachedRead(file);
this.preventAutozoomOnLoad = true;
}
if (fullreload) {
await this.excalidrawData.loadData(this.data, this.file, this.textMode);
@@ -1837,7 +1839,8 @@ export default class ExcalidrawView extends TextFileView {
viewModeEnabled = st.viewModeEnabled;
if (this.justLoaded) {
this.justLoaded = false;
this.zoomToFit(false);
if(!this.preventAutozoomOnLoad) this.zoomToFit(false);
this.preventAutozoomOnLoad = false;
this.previousSceneVersion = getSceneVersion(et);
return;
}

View File

@@ -45,6 +45,7 @@ export default {
"Insert LaTeX formula (e.g. \\binom{n}{k} = \\frac{n!}{k!(n-k)!})",
ENTER_LATEX: "Enter a valid LaTeX expression",
TRAY_MODE: "Toggle property-panel tray-mode",
SEARCH: "Search for text in drawing",
//ExcalidrawView.ts
INSTALL_SCRIPT_BUTTON: "Install or update Excalidraw Scripts",
@@ -256,6 +257,8 @@ export default {
"or a PNG or an SVG copy. You need to enable auto-export PNG / SVG (see below under Export Settings) for those image types to be available in the dropdown. For drawings that do not have a " +
"a corresponding PNG or SVG readily available the command palette action will insert a broken link. You need to open the original drawing and initiate export manually. " +
"This option will not autogenerate PNG/SVG files, but will simply reference the already existing files.",
EMBED_WIKILINK_NAME: "Embed SVG or PNG as Wiki link",
EMBED_WIKILINK_DESC: "Toggle ON: Excalidraw will embed a [[wiki link]]. Toggle OFF: Excalidraw will embed a [markdown](link).",
EXPORT_PNG_SCALE_NAME: "PNG export image scale",
EXPORT_PNG_SCALE_DESC: "The size-scale of the exported PNG image",
EXPORT_BACKGROUND_NAME: "Export image with background",

View File

@@ -15,6 +15,8 @@ import {
loadMathJax,
Scope,
request,
MetadataCache,
FrontMatterCache,
} from "obsidian";
import {
BLANK_DRAWING,
@@ -42,7 +44,7 @@ import {
VIRGIL_DATAURL,
} from "./constants";
import ExcalidrawView, { TextMode } from "./ExcalidrawView";
import { getMarkdownDrawingSection } from "./ExcalidrawData";
import { changeThemeOfExcalidrawMD, getMarkdownDrawingSection } from "./ExcalidrawData";
import {
ExcalidrawSettings,
DEFAULT_SETTINGS,
@@ -97,6 +99,7 @@ declare module "obsidian" {
}
export default class ExcalidrawPlugin extends Plugin {
private excalidrawFiles: Set<TFile> = new Set<TFile>();
public excalidrawFileModes: { [file: string]: string } = {};
private _loaded: boolean = false;
public settings: ExcalidrawSettings;
@@ -757,6 +760,55 @@ export default class ExcalidrawPlugin extends Plugin {
},
});
this.addCommand({
id: "search-text",
name: t("SEARCH"),
checkCallback: (checking: boolean) => {
if (checking) {
return (
this.app.workspace.activeLeaf.view.getViewType() ===
VIEW_TYPE_EXCALIDRAW
);
}
const view = this.app.workspace.activeLeaf.view;
if (view instanceof ExcalidrawView) {
(async ()=>{
const ea = this.ea;
ea.reset();
ea.setView(view);
const elements = ea.getViewElements().filter(el=>el.type==="text");
if(elements.length === 0) return;
let text = await ScriptEngine.inputPrompt(this.app,"Search for","use quotation marks for exact match","");
if(!text) return;
const res = text.matchAll(/"(.*?)"/g)
let query:string[] = [];
let parts;
while (!(parts = res.next()).done) {
query.push(parts.value[1]);
}
text = text.replaceAll(/"(.*?)"/g, "");
query = query.concat(text.split(" ").filter(s=>s.length!==0));
const match = elements
.filter((el:any)=>query
.some(q=>el
.rawText
.toLowerCase()
.replaceAll("\n"," ")
.match(q.toLowerCase())
));
if(match.length === 0) {
new Notice("I could not find a matching text element");
return;
}
ea.selectElementsInView(match);
ea.getExcalidrawAPI().zoomToFit(match,this.settings.zoomToFitMaxLevel,0.05);
})();
return true;
}
return false;
},
});
this.addCommand({
id: "export-png",
name: t("EXPORT_PNG"),
@@ -1253,14 +1305,9 @@ export default class ExcalidrawPlugin extends Plugin {
if (!(file instanceof TFile)) {
return;
}
const isExcalidarwFile =
//@ts-ignore
(file.unsafeCachedData &&
//@ts-ignore
file.unsafeCachedData.search(
/---[\r\n]+[\s\S]*excalidraw-plugin:\s*\w+[\r\n]+[\s\S]*---/gm,
) > -1) ||
file.extension == "excalidraw";
const isExcalidarwFile = this.excalidrawFiles.has(file);
this.updateFileCache(file,undefined,true);
if (!isExcalidarwFile) {
return;
}
@@ -1373,9 +1420,36 @@ export default class ExcalidrawPlugin extends Plugin {
activeLeafChangeEventHandler,
),
);
const metaCache:MetadataCache = self.app.metadataCache;
//@ts-ignore
metaCache.getCachedFiles().forEach((filename:string) => {
const fm = metaCache.getCache(filename)?.frontmatter;
if ((fm && Object.keys(fm).contains(FRONTMATTER_KEY)) ||
filename.match(/\.excalidraw$/)
) {
self.updateFileCache(
self.app.vault.getAbstractFileByPath(filename) as TFile, fm
);
}
});
this.registerEvent(metaCache.on("changed", (file, data, cache) => this.updateFileCache(file, cache?.frontmatter)));
});
}
updateFileCache(file: TFile, frontmatter?: FrontMatterCache, deleted: boolean = false) {
if(frontmatter) {
const isExcalidrawFile = Object.keys(frontmatter).contains(FRONTMATTER_KEY);
this.excalidrawFiles.add(file);
return;
}
if(!deleted && file.extension==="excalidraw") {
this.excalidrawFiles.add(file);
return;
}
this.excalidrawFiles.delete(file);
}
onunload() {
window.removeEventListener("keydown", this.onKeyDown, false);
window.removeEventListener("keyup", this.onKeyUp, false);
@@ -1413,7 +1487,8 @@ export default class ExcalidrawPlugin extends Plugin {
)
const editor = activeView.editor;
if (this.settings.embedType === "excalidraw") {
editor.replaceSelection(`![[${data}]]`);
editor.replaceSelection(this.settings.embedWikiLink
? `![[${data}]]` : `![](${encodeURI(data)})`);
editor.focus();
return;
}
@@ -1425,11 +1500,15 @@ export default class ExcalidrawPlugin extends Plugin {
file.path,"."+this.settings.embedType.toLowerCase()
);
await this.app.vault.create(filepath, "");
//await sleep(200);
const imgFile = this.app.vault.getAbstractFileByPath(filepath);
if(!imgFile) {
await this.app.vault.create(filepath, "");
await sleep(200);
}
editor.replaceSelection(
`![[${filename}]]\n%%[[${data}|🖋 Edit in Excalidraw]]%%`,
this.settings.embedWikiLink
? `![[${filename}]]\n%%[[${data}|🖋 Edit in Excalidraw]]%%`
: `![](${encodeURI(filename)})\n%%[🖋 Edit in Excalidraw](${encodeURI(data)})%%`,
);
editor.focus();
}
@@ -1515,18 +1594,7 @@ export default class ExcalidrawPlugin extends Plugin {
) {
let data = await this.app.vault.read(template);
if (data) {
if(this.settings.matchTheme) {
if(isObsidianThemeDark) {
if((data.match(/"theme"\s*:\s*"light"\s*,/g)||[]).length === 1) {
data = data.replace(/"theme"\s*:\s*"light"\s*,/,`"theme": "dark",`);
}
} else {
if((data.match(/"theme"\s*:\s*"dark"\s*,/g)||[]).length === 1) {
data = data.replace(/"theme"\s*:\s*"dark"\s*,/,`"theme": "light",`);
}
}
}
return data;
return this.settings.matchTheme ? changeThemeOfExcalidrawMD(data) : data;
}
}
}
@@ -1634,4 +1702,5 @@ export default class ExcalidrawPlugin extends Plugin {
const fileCache = f ? this.app.metadataCache.getFileCache(f) : null;
return !!fileCache?.frontmatter && !!fileCache.frontmatter[FRONTMATTER_KEY];
}
}

View File

@@ -50,6 +50,7 @@ export interface ExcalidrawSettings {
autoexportPNG: boolean;
autoexportExcalidraw: boolean;
embedType: "excalidraw" | "PNG" | "SVG";
embedWikiLink: boolean,
syncExcalidraw: boolean;
compatibilityMode: boolean;
experimentalFileType: boolean;
@@ -114,6 +115,7 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
autoexportPNG: false,
autoexportExcalidraw: false,
embedType: "excalidraw",
embedWikiLink: true,
syncExcalidraw: false,
experimentalFileType: false,
experimentalFileTag: "✏️",
@@ -789,6 +791,18 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName(t("EMBED_WIKILINK_NAME"))
.setDesc(fragWithHTML(t("EMBED_WIKILINK_DESC")))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.embedWikiLink)
.onChange(async (value) => {
this.plugin.settings.embedWikiLink = value;
this.applySettingsUpdate();
}),
);
let scaleText: HTMLDivElement;
new Setting(containerEl)

View File

@@ -1,4 +1,4 @@
{
"1.6.13": "0.12.16",
"1.6.14": "0.12.16",
"1.4.2": "0.11.13"
}