mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
3 Commits
1.3.15
...
ImageEleme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78fb37b173 | ||
|
|
a17638717f | ||
|
|
70de8ba2f8 |
@@ -119,6 +119,19 @@ export interface ExcalidrawAutomate extends Window {
|
||||
}
|
||||
):boolean;
|
||||
addElementsToView (repositionToCursor:boolean, save:boolean):Promise<boolean>;
|
||||
onDropHook (data: {
|
||||
ea: ExcalidrawAutomate,
|
||||
event: React.DragEvent<HTMLDivElement>,
|
||||
draggable: any, //Obsidian draggable object
|
||||
type: "file"|"text"|"unknown",
|
||||
payload: {
|
||||
files: TFile[], //TFile[] array of dropped files
|
||||
text: string, //string
|
||||
},
|
||||
excalidrawFile: TFile, //the file receiving the drop event
|
||||
view: ExcalidrawView, //the excalidraw view receiving the drop
|
||||
pointerPosition: {x:number, y:number} //the pointer position on canvas at the time of drop
|
||||
}):boolean;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,4 +184,38 @@ Adds elements created with ExcalidrawAutomate to the target ExcalidrawView.
|
||||
|
||||
`save` default is false
|
||||
- true: the drawing will be saved after the elements were added.
|
||||
- false: the drawing will be saved at the next autosave cycle. Use false when adding multiple elements one after the other. Else, best to use true, to minimize risk of data loss.
|
||||
- false: the drawing will be saved at the next autosave cycle. Use false when adding multiple elements one after the other. Else, best to use true, to minimize risk of data loss.
|
||||
|
||||
### onDropHook
|
||||
```typescript
|
||||
onDropHook (data: {
|
||||
ea: ExcalidrawAutomate,
|
||||
event: React.DragEvent<HTMLDivElement>,
|
||||
draggable: any, //Obsidian draggable object
|
||||
type: "file"|"text"|"unknown",
|
||||
payload: {
|
||||
files: TFile[], //TFile[] array of dropped files
|
||||
text: string, //string
|
||||
},
|
||||
excalidrawFile: TFile, //the file receiving the drop event
|
||||
view: ExcalidrawView, //the excalidraw view receiving the drop
|
||||
pointerPosition: {x:number, y:number} //the pointer position on canvas at the time of drop
|
||||
}):boolean;
|
||||
```
|
||||
|
||||
Callback function triggered when an draggable item is dropped on Excalidraw.
|
||||
The function should return a boolean value. True if the drop was handled by the hook and futher native processing should be stopped, and false if Excalidraw should continue with the processing of the drop.
|
||||
type of drop can be one of:
|
||||
- "file" if a file from Obsidian file explorer is dropped onto Excalidraw. In this case payload.files will contain the list of files dropped.
|
||||
- "text" if a link (e.g. url, or wiki link) or other text is dropped. In this case payload.text will contain the received string
|
||||
- "unknown" if Excalidraw plugin does not recognize the type of dropped object. In this case you can use React.DragEvent to analysed the dropped object.
|
||||
|
||||
Use Templater startup templates or similar to set the Hook function.
|
||||
|
||||
```typescript
|
||||
ea = ExcalidrawAutomate;
|
||||
ea.onDropHook = (data) => {
|
||||
console.log(data);
|
||||
return false;
|
||||
}
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "1.3.15",
|
||||
"version": "1.3.16",
|
||||
"minAppVersion": "0.12.0",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@zsviczian/excalidraw": "0.9.0-obsidian-11",
|
||||
"@zsviczian/excalidraw": "0.9.0-obsidian-image-support-3",
|
||||
"monkey-around": "^2.2.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
||||
@@ -15,9 +15,10 @@ import {
|
||||
FRONTMATTER,
|
||||
nanoid,
|
||||
JSON_parse,
|
||||
VIEW_TYPE_EXCALIDRAW
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
MAX_IMAGE_SIZE
|
||||
} from "./constants";
|
||||
import { wrapText } from "./Utils";
|
||||
import { getObsidianImage, wrapText } from "./Utils";
|
||||
import { AppState } from "@zsviczian/excalidraw/types/types";
|
||||
|
||||
declare type ConnectionPoint = "top"|"bottom"|"left"|"right";
|
||||
@@ -26,6 +27,7 @@ export interface ExcalidrawAutomate extends Window {
|
||||
ExcalidrawAutomate: {
|
||||
plugin: ExcalidrawPlugin;
|
||||
elementsDict: {};
|
||||
imagesDict: {};
|
||||
style: {
|
||||
strokeColor: string;
|
||||
backgroundColor: string;
|
||||
@@ -102,6 +104,7 @@ export interface ExcalidrawAutomate extends Window {
|
||||
endObjectId?:string
|
||||
}
|
||||
):string ;
|
||||
addImage(topX:number, topY:number, imageFile: TFile):Promise<string>;
|
||||
connectObjects (
|
||||
objectA: string,
|
||||
connectionA: ConnectionPoint,
|
||||
@@ -138,6 +141,19 @@ export interface ExcalidrawAutomate extends Window {
|
||||
}
|
||||
):boolean;
|
||||
addElementsToView (repositionToCursor:boolean, save:boolean):Promise<boolean>;
|
||||
onDropHook (data: {
|
||||
ea: ExcalidrawAutomate,
|
||||
event: React.DragEvent<HTMLDivElement>,
|
||||
draggable: any, //Obsidian draggable object
|
||||
type: "file"|"text"|"unknown",
|
||||
payload: {
|
||||
files: TFile[], //TFile[] array of dropped files
|
||||
text: string, //string
|
||||
},
|
||||
excalidrawFile: TFile, //the file receiving the drop event
|
||||
view: ExcalidrawView, //the excalidraw view receiving the drop
|
||||
pointerPosition: {x:number, y:number} //the pointer position on canvas at the time of drop
|
||||
}):boolean;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -147,6 +163,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
window.ExcalidrawAutomate = {
|
||||
plugin: plugin,
|
||||
elementsDict: {},
|
||||
imagesDict: {},
|
||||
style: {
|
||||
strokeColor: "#000000",
|
||||
backgroundColor: "transparent",
|
||||
@@ -500,6 +517,25 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
}
|
||||
return id;
|
||||
},
|
||||
async addImage(topX:number, topY:number, imageFile: TFile):Promise<string> {
|
||||
const id = nanoid();
|
||||
const image = await getObsidianImage(this.plugin.app,imageFile);
|
||||
if(!image) return null;
|
||||
this.imagesDict[image.imageId] = {
|
||||
type:"image",
|
||||
id: image.imageId,
|
||||
dataURL: image.dataURL
|
||||
}
|
||||
if (Math.max(image.size.width,image.size.height) > MAX_IMAGE_SIZE) {
|
||||
const scale = MAX_IMAGE_SIZE/Math.max(image.size.width,image.size.height);
|
||||
image.size.width = scale*image.size.width;
|
||||
image.size.height = scale*image.size.height;
|
||||
}
|
||||
this.elementsDict[id] = boxedElement(id,"image",topX,topY,image.size.width,image.size.height);
|
||||
this.elementsDict[id].imageId = image.imageId;
|
||||
this.elementsDict[id].scale = [1,1];
|
||||
return id;
|
||||
},
|
||||
connectObjects(objectA: string, connectionA: ConnectionPoint, objectB: string, connectionB: ConnectionPoint, formatting?:{numberOfPoints?: number,startArrowHead?:string,endArrowHead?:string, padding?: number}):void {
|
||||
if(!(this.elementsDict[objectA] && this.elementsDict[objectB])) {
|
||||
return;
|
||||
@@ -539,6 +575,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
},
|
||||
clear() {
|
||||
this.elementsDict = {};
|
||||
this.imagesDict = {};
|
||||
},
|
||||
reset() {
|
||||
this.clear();
|
||||
@@ -669,9 +706,9 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
return false;
|
||||
}
|
||||
const elements = this.getElements();
|
||||
return await this.targetView.addElements(elements,repositionToCursor,save);
|
||||
return await this.targetView.addElements(elements,repositionToCursor,save,this.imagesDict);
|
||||
},
|
||||
|
||||
onDropHook:null,
|
||||
};
|
||||
await initFonts();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ declare module "obsidian" {
|
||||
|
||||
export const REGEX_LINK = {
|
||||
//![[link|alias]] [alias](link){num}
|
||||
//12 3 4 5 6 7 8
|
||||
// 1 2 3 4 5 6 7 8 9
|
||||
EXPR: /(!)?(\[\[([^|\]]+)\|?(.+)?]]|\[(.*)\]\((.*)\))(\{(\d+)\})?/g,
|
||||
isTransclusion: (parts: IteratorResult<RegExpMatchArray, any>):boolean => {
|
||||
return parts.value[1] ? true:false;
|
||||
@@ -288,14 +288,24 @@ export class ExcalidrawData {
|
||||
(this.showLinkBrackets ? "]]" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param text
|
||||
* @returns [string,number] - the transcluded text, and the line number for the location of the text
|
||||
*/
|
||||
public async getTransclusion (text:string):Promise<[string,number]> {
|
||||
//file-name#^blockref
|
||||
//1 2 3
|
||||
const REG_FILE_BLOCKREF = /(.*)#(\^)?(.*)/g;
|
||||
const parts=text.matchAll(REG_FILE_BLOCKREF).next();
|
||||
if(parts.done || !parts.value[1] || !parts.value[3]) return [text,0]; //filename and/or blockref not found
|
||||
const file = this.app.metadataCache.getFirstLinkpathDest(parts.value[1],this.file.path);
|
||||
if(!parts.done && !parts.value[1]) return [text,0]; //filename not found
|
||||
const filename = parts.done ? text : parts.value[1];
|
||||
const file = this.app.metadataCache.getFirstLinkpathDest(filename,this.file.path);
|
||||
if(!file || !(file instanceof TFile)) return [text,0];
|
||||
const contents = await this.app.vault.cachedRead(file);
|
||||
if(parts.done) { //no blockreference
|
||||
return([contents.substr(0,this.plugin.settings.pageTransclusionCharLimit),0]);
|
||||
}
|
||||
const isParagraphRef = parts.value[2] ? true : false; //does the reference contain a ^ character?
|
||||
const id = parts.value[3]; //the block ID or heading text
|
||||
const blocks = (await this.app.metadataCache.blockCache.getForFile({isCancelled: ()=>false},file)).blocks.filter((block:any)=>block.node.type!="comment");
|
||||
|
||||
@@ -28,7 +28,8 @@ import {
|
||||
TEXT_DISPLAY_RAW_ICON_NAME,
|
||||
TEXT_DISPLAY_PARSED_ICON_NAME,
|
||||
FULLSCREEN_ICON_NAME,
|
||||
JSON_parse
|
||||
JSON_parse,
|
||||
IMAGE_TYPES
|
||||
} from './constants';
|
||||
import ExcalidrawPlugin from './main';
|
||||
import {estimateBounds, ExcalidrawAutomate, repositionElementsToCursor} from './ExcalidrawAutomate';
|
||||
@@ -275,6 +276,12 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
}
|
||||
|
||||
onResize() {
|
||||
if(!this.plugin.settings.zoomToFitOnResize) return;
|
||||
if(!this.excalidrawRef) return;
|
||||
this.zoomToFit(false);
|
||||
}
|
||||
|
||||
onload() {
|
||||
//console.log("ExcalidrawView.onload()");
|
||||
this.addAction(DISK_ICON_NAME,t("FORCE_SAVE"),async (ev)=> {
|
||||
@@ -453,6 +460,12 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
|
||||
setMarkdownView() {
|
||||
if(this.excalidrawRef) {
|
||||
const el = this.excalidrawRef.current.getSceneElements();
|
||||
if(el.filter((e:any)=>e.type==="image").length>0) {
|
||||
new Notice(t("DRAWING_CONTAINS_IMAGE"),6000);
|
||||
}
|
||||
}
|
||||
this.plugin.excalidrawFileModes[this.id || this.file.path] = "markdown";
|
||||
this.plugin.setMarkdownView(this.leaf);
|
||||
}
|
||||
@@ -634,7 +647,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.addElements(window.ExcalidrawAutomate.getElements(),false,true);
|
||||
}
|
||||
|
||||
this.addElements = async (newElements:ExcalidrawElement[],repositionToCursor:boolean = false, save:boolean=false):Promise<boolean> => {
|
||||
this.addElements = async (newElements:ExcalidrawElement[],repositionToCursor:boolean = false, save:boolean=false, images:any):Promise<boolean> => {
|
||||
if(!excalidrawRef?.current) return false;
|
||||
|
||||
const textElements = newElements.filter((el)=>el.type=="text");
|
||||
@@ -647,7 +660,20 @@ export default class ExcalidrawView extends TextFileView {
|
||||
};
|
||||
|
||||
const el: ExcalidrawElement[] = excalidrawRef.current.getSceneElements();
|
||||
const st: AppState = excalidrawRef.current.getAppState();
|
||||
let st: AppState = excalidrawRef.current.getAppState();
|
||||
if(!st.files) {
|
||||
st.files = {};
|
||||
}
|
||||
if(images) {
|
||||
Object.keys(images).forEach((k)=>{
|
||||
st.files[k]={
|
||||
type:images[k].type,
|
||||
id: images[k].id,
|
||||
dataURL: images[k].dataURL
|
||||
}
|
||||
});
|
||||
}
|
||||
//merge appstate.files with files
|
||||
if(repositionToCursor) newElements = repositionElementsToCursor(newElements,currentPosition,true);
|
||||
this.excalidrawRef.current.updateScene({
|
||||
elements: el.concat(newElements),
|
||||
@@ -664,6 +690,13 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
const el: ExcalidrawElement[] = excalidrawRef.current.getSceneElements();
|
||||
const st: AppState = excalidrawRef.current.getAppState();
|
||||
|
||||
if(st.files) {
|
||||
const imgIds = el.filter((e)=>e.type=="image").map((e:any)=>e.imageId);
|
||||
const toDelete = Object.keys(st.files).filter((k)=>!imgIds.contains(k));
|
||||
toDelete.forEach((k)=>delete st.files[k]);
|
||||
}
|
||||
|
||||
return {
|
||||
type: "excalidraw",
|
||||
version: 2,
|
||||
@@ -687,6 +720,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
currentItemEndArrowhead: st.currentItemEndArrowhead,
|
||||
currentItemLinearStrokeSharpness: st.currentItemLinearStrokeSharpness,
|
||||
gridSize: st.gridSize,
|
||||
files: st.files??{},
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -910,23 +944,71 @@ export default class ExcalidrawView extends TextFileView {
|
||||
currentPosition = viewportCoordsToSceneCoords({ clientX: event.clientX, clientY: event.clientY },st);
|
||||
|
||||
const draggable = (this.app as any).dragManager.draggable;
|
||||
const onDropHook = (type:"file"|"text"|"unknown", files:TFile[], text:string):boolean => {
|
||||
if (window.ExcalidrawAutomate.onDropHook) {
|
||||
try {
|
||||
return window.ExcalidrawAutomate.onDropHook({
|
||||
//@ts-ignore
|
||||
ea: window.ExcalidrawAutomate, //the Excalidraw Automate object
|
||||
event: event, //React.DragEvent<HTMLDivElement>
|
||||
draggable: draggable, //Obsidian draggable object
|
||||
type: type, //"file"|"text"
|
||||
payload: {
|
||||
files: files, //TFile[] array of dropped files
|
||||
text: text, //string
|
||||
},
|
||||
excalidrawFile: this.file, //the file receiving the drop event
|
||||
view: this, //the excalidraw view receiving the drop
|
||||
pointerPosition: currentPosition //the pointer position on canvas at the time of drop
|
||||
});
|
||||
} catch (e) {
|
||||
new Notice("on drop hook error. See console log for details");
|
||||
console.log(e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch(draggable?.type) {
|
||||
case "file":
|
||||
this.addText(`[[${this.app.metadataCache.fileToLinktext(draggable.file,this.file.path,true)}]]`);
|
||||
if (!onDropHook("file",[draggable.file],null)) {
|
||||
if((event.ctrlKey || event.metaKey) && IMAGE_TYPES.contains(draggable.file.extension)) {
|
||||
const f = draggable.file;
|
||||
const topX = currentPosition.x;
|
||||
const topY = currentPosition.y;
|
||||
const ea = window.ExcalidrawAutomate;
|
||||
ea.reset();
|
||||
ea.setView(this);
|
||||
(async () => {
|
||||
await ea.addImage(currentPosition.x,currentPosition.y,draggable.file);
|
||||
ea.addElementsToView(false,false);
|
||||
})();
|
||||
return false;
|
||||
}
|
||||
this.addText(`[[${this.app.metadataCache.fileToLinktext(draggable.file,this.file.path,true)}]]`);
|
||||
}
|
||||
return false;
|
||||
case "files":
|
||||
for(const f of draggable.files) {
|
||||
this.addText(`[[${this.app.metadataCache.fileToLinktext(f,this.file.path,true)}]]`);
|
||||
currentPosition.y+=st.currentItemFontSize*2;
|
||||
if (!onDropHook("file",draggable.files,null)) {
|
||||
for(const f of draggable.files) {
|
||||
this.addText(`[[${this.app.metadataCache.fileToLinktext(f,this.file.path,true)}]]`);
|
||||
currentPosition.y+=st.currentItemFontSize*2;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (event.dataTransfer.types.includes("text/plain")) {
|
||||
const text:string = event.dataTransfer.getData("text");
|
||||
if(!text) return true;
|
||||
this.addText(text.replace(/(!\[\[.*#[^\]]*\]\])/g,"$1{40}"));
|
||||
if (!onDropHook("text",null,text)) {
|
||||
this.addText(text.replace(/(!\[\[.*#[^\]]*\]\])/g,"$1{40}"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(onDropHook("unknown",null,null)) return false;
|
||||
return true;
|
||||
},
|
||||
onBeforeTextEdit: (textElement: ExcalidrawTextElement) => {
|
||||
|
||||
69
src/Utils.ts
69
src/Utils.ts
@@ -1,6 +1,9 @@
|
||||
import { normalizePath, TAbstractFile, TFolder, Vault } from "obsidian";
|
||||
import { App, normalizePath, TAbstractFile, TFile, TFolder, Vault } from "obsidian";
|
||||
import { Random } from "roughjs/bin/math";
|
||||
import { Zoom } from "@zsviczian/excalidraw/types/types";
|
||||
import { nanoid } from "nanoid";
|
||||
import { IMAGE_TYPES } from "./constants";
|
||||
|
||||
|
||||
/**
|
||||
* Splits a full path including a folderpath and a filename into separate folderpath and filename components
|
||||
@@ -122,4 +125,66 @@ export const viewportCoordsToSceneCoords = (
|
||||
const x = (clientX - zoom.translation.x - offsetLeft) * invScale - scrollX;
|
||||
const y = (clientY - zoom.translation.y - offsetTop) * invScale - scrollY;
|
||||
return { x, y };
|
||||
};
|
||||
};
|
||||
|
||||
export const getObsidianImage = async (app: App, file: TFile)
|
||||
:Promise<{
|
||||
imageId: string,
|
||||
dataURL: string,
|
||||
size: {height: number, width: number},
|
||||
}> => {
|
||||
if(!app || !file) return null;
|
||||
if (!IMAGE_TYPES.contains(file.extension)) return null;
|
||||
const ab = await app.vault.readBinary(file);
|
||||
return {
|
||||
imageId: await generateIdFromFile(ab),
|
||||
dataURL: file.extension==="svg" ? await getSVGData(app,file) : await getDataURL(ab),
|
||||
size: await getImageSize(app,file)
|
||||
}
|
||||
}
|
||||
|
||||
const getSVGData = async (app: App, file: TFile): Promise<string> => {
|
||||
const svg = await app.vault.read(file);
|
||||
return "data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(svg.replaceAll(" "," "))))
|
||||
}
|
||||
|
||||
const getDataURL = async (file: ArrayBuffer): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const dataURL = reader.result as string;
|
||||
resolve(dataURL);
|
||||
};
|
||||
reader.onerror = (error) => reject(error);
|
||||
reader.readAsDataURL(new Blob([new Uint8Array(file)]));
|
||||
});
|
||||
};
|
||||
|
||||
const generateIdFromFile = async (file: ArrayBuffer):Promise<string> => {
|
||||
let id: string;
|
||||
try {
|
||||
const hashBuffer = await window.crypto.subtle.digest(
|
||||
"SHA-1",
|
||||
file,
|
||||
);
|
||||
id =
|
||||
// convert buffer to byte array
|
||||
Array.from(new Uint8Array(hashBuffer))
|
||||
// convert to hex string
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
id = nanoid(40);
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
const getImageSize = async (app: App, file:TFile):Promise<{height:number, width:number}> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let img = new Image()
|
||||
img.onload = () => resolve({height: img.height, width:img.width});
|
||||
img.onerror = reject;
|
||||
img.src = app.vault.getResourcePath(file);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ export function JSON_parse(x:string):any {return JSON.parse(x.replaceAll("["
|
||||
|
||||
import {customAlphabet} from "nanoid";
|
||||
export const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',8);
|
||||
export const IMAGE_TYPES = ['jpeg', 'jpg', 'png', 'gif', 'svg', 'bmp'];
|
||||
export const MAX_IMAGE_SIZE = 600;
|
||||
export const FRONTMATTER_KEY = "excalidraw-plugin";
|
||||
export const FRONTMATTER_KEY_CUSTOM_PREFIX = "excalidraw-link-prefix";
|
||||
export const FRONTMATTER_KEY_CUSTOM_URL_PREFIX = "excalidraw-url-prefix";
|
||||
|
||||
@@ -44,6 +44,8 @@ export default {
|
||||
NOFILE: "Excalidraw (no file)",
|
||||
COMPATIBILITY_MODE: "*.excalidraw file opened in compatibility mode. Convert to new format for full plugin functionality.",
|
||||
CONVERT_FILE: "Convert to new format",
|
||||
DRAWING_CONTAINS_IMAGE: "Warning! The drawing contains image elements. Depending on the number and size of the images, " +
|
||||
"loading Markdown View may take a while. Please be patient. ",
|
||||
|
||||
//settings.ts
|
||||
FOLDER_NAME: "Excalidraw folder",
|
||||
@@ -69,6 +71,9 @@ export default {
|
||||
FILENAME_PREFIX_DESC: "The first part of the filename",
|
||||
FILENAME_DATE_NAME: "Filename date",
|
||||
FILENAME_DATE_DESC: "The second part of the filename",
|
||||
DISPLAY_HEAD: "Display",
|
||||
ZOOM_TO_FIT_NAME: "Zoom to fit on view resize",
|
||||
ZOOM_TO_FIT_DESC: "Zoom to fit drawing when the pane is resized",
|
||||
LINKS_HEAD: "Links and transclusion",
|
||||
LINKS_DESC: "CTRL/META + CLICK on Text Elements to open them as links. " +
|
||||
"If the selected text has more than one [[valid Obsidian links]], only the first will be opened. " +
|
||||
@@ -95,6 +100,9 @@ export default {
|
||||
TRANSCLUSION_WRAP_DESC: "Number specifies the character count where the text should be wrapped. " +
|
||||
"Set the text wrapping behavior of transcluded text. Turn this ON to force-wrap " +
|
||||
"text (i.e. no overflow), or OFF to soft-warp text (at the nearest whitespace).",
|
||||
PAGE_TRANSCLUSION_CHARCOUNT_NAME: "Page transclusion max char count",
|
||||
PAGE_TRANSCLUSION_CHARCOUNT_DESC: "The maximum number of characters to display from the page when transcluding an entire page with the "+
|
||||
"![[markdown page]] format.",
|
||||
EMBED_HEAD: "Embed & Export",
|
||||
EMBED_PREVIEW_SVG_NAME: "Display SVG in markdown preview",
|
||||
EMBED_PREVIEW_SVG_DESC: "The default is to display drawings as SVG images in the markdown preview. Turning this feature off, the markdown preview will display the drawing as an embedded PNG image.",
|
||||
|
||||
@@ -1135,7 +1135,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
outString += te.text+' ^'+id+'\n\n';
|
||||
}
|
||||
return outString + this.getMarkdownDrawingSection(data);
|
||||
return outString + this.getMarkdownDrawingSection(JSON.stringify(JSON_parse(data)));
|
||||
}
|
||||
|
||||
public async createDrawing(filename: string, onNewPane: boolean, foldername?: string, initData?:string):Promise<string> {
|
||||
|
||||
@@ -17,11 +17,13 @@ export interface ExcalidrawSettings {
|
||||
drawingFilenameDateTime: string,
|
||||
displaySVGInPreview: boolean,
|
||||
width: string,
|
||||
zoomToFitOnResize: boolean,
|
||||
showLinkBrackets: boolean,
|
||||
linkPrefix: string,
|
||||
urlPrefix: string,
|
||||
allowCtrlClick: boolean, //if disabled only the link button in the view header will open links
|
||||
forceWrap: boolean,
|
||||
pageTransclusionCharLimit: number,
|
||||
pngExportScale: number,
|
||||
exportWithTheme: boolean,
|
||||
exportWithBackground: boolean,
|
||||
@@ -47,11 +49,13 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
drawingFilenameDateTime: 'YYYY-MM-DD HH.mm.ss',
|
||||
displaySVGInPreview: true,
|
||||
width: '400',
|
||||
zoomToFitOnResize: true,
|
||||
linkPrefix: "📍",
|
||||
urlPrefix: "🌐",
|
||||
showLinkBrackets: true,
|
||||
allowCtrlClick: true,
|
||||
forceWrap: false,
|
||||
pageTransclusionCharLimit: 200,
|
||||
pngExportScale: 1,
|
||||
exportWithTheme: true,
|
||||
exportWithBackground: true,
|
||||
@@ -184,6 +188,17 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
|
||||
this.containerEl.createEl('h1', {text: t("DISPLAY_HEAD")});
|
||||
new Setting(containerEl)
|
||||
.setName(t("ZOOM_TO_FIT_NAME"))
|
||||
.setDesc(t("ZOOM_TO_FIT_DESC"))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.zoomToFitOnResize)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.zoomToFitOnResize = value;
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
|
||||
this.containerEl.createEl('h1', {text: t("LINKS_HEAD")});
|
||||
this.containerEl.createEl('p',{
|
||||
text: t("LINKS_DESC")});
|
||||
@@ -242,6 +257,29 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
}));
|
||||
s.descEl.innerHTML="<code>![[doc#^ref]]{number}</code> "+t("TRANSCLUSION_WRAP_DESC");
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("PAGE_TRANSCLUSION_CHARCOUNT_NAME"))
|
||||
.setDesc(t("PAGE_TRANSCLUSION_CHARCOUNT_DESC"))
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.pageTransclusionCharLimit.toString())
|
||||
.onChange(async (value) => {
|
||||
const intVal = parseInt(value);
|
||||
if(isNaN(intVal) && value!=="") {
|
||||
text.setValue(this.plugin.settings.pageTransclusionCharLimit.toString());
|
||||
return;
|
||||
}
|
||||
this.requestEmbedUpdate = true;
|
||||
if(value === "") {
|
||||
this.plugin.settings.pageTransclusionCharLimit = 10;
|
||||
this.applySettingsUpdate(true);
|
||||
return;
|
||||
}
|
||||
this.plugin.settings.pageTransclusionCharLimit = intVal;
|
||||
text.setValue(this.plugin.settings.pageTransclusionCharLimit.toString());
|
||||
this.applySettingsUpdate(true);
|
||||
}));
|
||||
|
||||
this.containerEl.createEl('h1', {text: t("EMBED_HEAD")});
|
||||
|
||||
|
||||
@@ -267,6 +305,7 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
this.applySettingsUpdate();
|
||||
this.requestEmbedUpdate = true;
|
||||
}));
|
||||
|
||||
let dropdown: DropdownComponent;
|
||||
|
||||
new Setting(containerEl)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"1.3.15": "0.11.13"
|
||||
"1.3.16": "0.11.13"
|
||||
}
|
||||
|
||||
@@ -1024,10 +1024,10 @@
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
|
||||
"@zsviczian/excalidraw@0.9.0-obsidian-11":
|
||||
"integrity" "sha512-h4d8l0slwWB2yLaZnD1qSoYQ9eaZFWEe2Ls2rJYNIc6v9EAEAWMj/4NGRgOpcxdU4dKt5MSknHzezRsfeDz5bQ=="
|
||||
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.9.0-obsidian-11.tgz"
|
||||
"version" "0.9.0-obsidian-11"
|
||||
"@zsviczian/excalidraw@0.9.0-obsidian-image-support-3":
|
||||
"integrity" "sha512-Y+hIhIxoNsoyYS2AmhE9I8G0M6Q6KaQ3LxSn8p3JZbUGFqoAmDg+26fGHXhMsboaVXhKqonkw5UN1UlZYL5k1A=="
|
||||
"resolved" "https://registry.npmjs.org/@zsviczian/excalidraw/-/excalidraw-0.9.0-obsidian-image-support-3.tgz"
|
||||
"version" "0.9.0-obsidian-image-support-3"
|
||||
|
||||
"abab@^1.0.3":
|
||||
"integrity" "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4="
|
||||
|
||||
Reference in New Issue
Block a user