mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
3 Commits
1.2.0-alph
...
1.2.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc342189b | ||
|
|
454c68b4b9 | ||
|
|
09889d7ed3 |
@@ -212,7 +212,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
elements.push(this.elementsDict[this.elementIds[i]]);
|
||||
}
|
||||
return ExcalidrawView.getSVG(
|
||||
JSON_stringify({
|
||||
{//createDrawing
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
@@ -221,7 +221,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
"theme": template ? template.appState.theme : this.canvas.theme,
|
||||
"viewBackgroundColor": template? template.appState.viewBackgroundColor : this.canvas.viewBackgroundColor
|
||||
}
|
||||
}),
|
||||
},//),
|
||||
{
|
||||
withBackground: plugin.settings.exportWithBackground,
|
||||
withTheme: plugin.settings.exportWithTheme
|
||||
@@ -235,7 +235,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
elements.push(this.elementsDict[this.elementIds[i]]);
|
||||
}
|
||||
return ExcalidrawView.getPNG(
|
||||
JSON_stringify({
|
||||
{ //JSON_stringify(
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
@@ -244,7 +244,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
|
||||
"theme": template ? template.appState.theme : this.canvas.theme,
|
||||
"viewBackgroundColor": template? template.appState.viewBackgroundColor : this.canvas.viewBackgroundColor
|
||||
}
|
||||
}),
|
||||
},//),
|
||||
{
|
||||
withBackground: plugin.settings.exportWithBackground,
|
||||
withTheme: plugin.settings.exportWithTheme
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { App, TFile } from "obsidian";
|
||||
import { App, normalizePath, TFile } from "obsidian";
|
||||
import {
|
||||
nanoid,
|
||||
FRONTMATTER_KEY_CUSTOM_PREFIX,
|
||||
@@ -57,14 +57,22 @@ export class ExcalidrawData {
|
||||
this.setShowLinkBrackets();
|
||||
this.setLinkPrefix();
|
||||
|
||||
|
||||
|
||||
//Load scene: Read the JSON string after "# Drawing"
|
||||
this.scene = null;
|
||||
if (this.settings.syncExcalidraw) {
|
||||
const excalfile = file.path.substring(0,file.path.lastIndexOf('.md')) + '.excalidraw';
|
||||
const f = this.app.vault.getAbstractFileByPath(excalfile);
|
||||
if(f && f instanceof TFile && f.stat.mtime>file.stat.mtime) { //the .excalidraw file is newer then the .md file
|
||||
const d = await this.app.vault.read(f);
|
||||
this.scene = JSON.parse(d);
|
||||
}
|
||||
}
|
||||
|
||||
//Load scene: Read the JSON string after "# Drawing"
|
||||
let parts = data.matchAll(/\n# Drawing\n(.*)/gm).next();
|
||||
if(!(parts.value && parts.value.length>1)) return false; //JSON not found or invalid
|
||||
this.scene = JSON_parse(parts.value[1]);
|
||||
|
||||
if(!this.scene) { //scene was not loaded from .excalidraw
|
||||
this.scene = JSON_parse(parts.value[1]);
|
||||
}
|
||||
//Trim data to remove the JSON string
|
||||
data = data.substring(0,parts.value.index);
|
||||
|
||||
@@ -287,7 +295,7 @@ export class ExcalidrawData {
|
||||
|
||||
public syncElements(newScene:any):boolean {
|
||||
//console.log("Excalidraw.Data.syncElements()");
|
||||
this.scene = JSON_parse(newScene);
|
||||
this.scene = newScene;//JSON_parse(newScene);
|
||||
const result = this.setLinkPrefix() || this.setShowLinkBrackets() || this.findNewTextElementsInScene();
|
||||
this.updateTextElementsFromSceneRawOnly();
|
||||
return result;
|
||||
|
||||
@@ -74,10 +74,21 @@ export default class ExcalidrawView extends TextFileView {
|
||||
this.excalidrawData = new ExcalidrawData(plugin);
|
||||
}
|
||||
|
||||
public async saveSVG(data?: string) {
|
||||
if(!data) {
|
||||
public saveExcalidraw(scene?: any){
|
||||
if(!scene) {
|
||||
if (!this.getScene) return false;
|
||||
data = this.getScene();
|
||||
scene = this.getScene();
|
||||
}
|
||||
const filepath = this.file.path.substring(0,this.file.path.lastIndexOf('.md')) + '.excalidraw';
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(filepath));
|
||||
if(file && file instanceof TFile) this.app.vault.modify(file,JSON.stringify(scene));//data.replaceAll("[","["));
|
||||
else this.app.vault.create(filepath,JSON.stringify(scene));//.replaceAll("[","["));
|
||||
}
|
||||
|
||||
public async saveSVG(scene?: any) {
|
||||
if(!scene) {
|
||||
if (!this.getScene) return false;
|
||||
scene = this.getScene();
|
||||
}
|
||||
const filepath = this.file.path.substring(0,this.file.path.lastIndexOf('.md')) + '.svg';
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(filepath));
|
||||
@@ -85,7 +96,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
withBackground: this.plugin.settings.exportWithBackground,
|
||||
withTheme: this.plugin.settings.exportWithTheme
|
||||
}
|
||||
const svg = ExcalidrawView.getSVG(data,exportSettings);
|
||||
const svg = ExcalidrawView.getSVG(scene,exportSettings);
|
||||
if(!svg) return;
|
||||
const svgString = ExcalidrawView.embedFontsInSVG(svg).outerHTML;
|
||||
if(file && file instanceof TFile) await this.app.vault.modify(file,svgString);
|
||||
@@ -103,16 +114,16 @@ export default class ExcalidrawView extends TextFileView {
|
||||
return svg;
|
||||
}
|
||||
|
||||
public async savePNG(data?: string) {
|
||||
if(!data) {
|
||||
public async savePNG(scene?: any) {
|
||||
if(!scene) {
|
||||
if (!this.getScene) return false;
|
||||
data = this.getScene();
|
||||
scene = this.getScene();
|
||||
}
|
||||
const exportSettings: ExportSettings = {
|
||||
withBackground: this.plugin.settings.exportWithBackground,
|
||||
withTheme: this.plugin.settings.exportWithTheme
|
||||
}
|
||||
const png = await ExcalidrawView.getPNG(data,exportSettings);
|
||||
const png = await ExcalidrawView.getPNG(scene,exportSettings);
|
||||
if(!png) return;
|
||||
const filepath = this.file.path.substring(0,this.file.path.lastIndexOf('.md')) + '.png';
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(filepath));
|
||||
@@ -131,15 +142,19 @@ export default class ExcalidrawView extends TextFileView {
|
||||
getViewData () {
|
||||
//console.log("ExcalidrawView.getViewData()");
|
||||
if(this.getScene) {
|
||||
const scene = this.getScene();
|
||||
if(this.plugin.settings.autoexportSVG) this.saveSVG(scene);
|
||||
if(this.plugin.settings.autoexportPNG) this.savePNG(scene);
|
||||
if(this.excalidrawData.syncElements(scene)) {
|
||||
|
||||
if(this.excalidrawData.syncElements(this.getScene())) {
|
||||
this.loadDrawing(false);
|
||||
}
|
||||
let trimLocation = this.data.search("# Text Elements\n");
|
||||
if(trimLocation == -1) trimLocation = this.data.search("# Drawing\n");
|
||||
if(trimLocation == -1) return this.data;
|
||||
|
||||
const scene = this.excalidrawData.scene;
|
||||
if(this.plugin.settings.autoexportSVG) this.saveSVG(scene);
|
||||
if(this.plugin.settings.autoexportPNG) this.savePNG(scene);
|
||||
if(this.plugin.settings.autoexportExcalidraw) this.saveExcalidraw(scene);
|
||||
|
||||
const header = this.data.substring(0,trimLocation)
|
||||
.replace(/excalidraw-plugin:\s.*\n/,FRONTMATTER_KEY+": " + (this.isTextLocked ? "locked\n" : "unlocked\n"));
|
||||
return header + this.excalidrawData.generateMD();
|
||||
@@ -284,6 +299,8 @@ export default class ExcalidrawView extends TextFileView {
|
||||
async setViewData (data: string, clear: boolean) {
|
||||
this.app.workspace.onLayoutReady(async ()=>{
|
||||
//console.log("ExcalidrawView.setViewData()");
|
||||
this.plugin.settings.drawingOpenCount++;
|
||||
this.plugin.saveSettings();
|
||||
this.lock(data.search("excalidraw-plugin: locked\n")>-1,false);
|
||||
if(!(await this.excalidrawData.loadData(data, this.file,this.isTextLocked))) return;
|
||||
if(clear) this.clear();
|
||||
@@ -313,6 +330,10 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
}
|
||||
|
||||
//Compatibility mode with .excalidraw files
|
||||
/* canAcceptExtension(extension: string) {
|
||||
return extension == "excalidraw";
|
||||
}*/
|
||||
|
||||
// gets the title of the document
|
||||
getDisplayText() {
|
||||
@@ -348,7 +369,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
.setIcon(ICON_NAME)
|
||||
.onClick( async (ev) => {
|
||||
if(!this.getScene || !this.file) return;
|
||||
this.download('data:text/plain;charset=utf-8',encodeURIComponent(this.getScene().replaceAll("[","[")), this.file.basename+'.excalidraw');
|
||||
this.download('data:text/plain;charset=utf-8',encodeURIComponent(JSON.stringify(this.getScene())), this.file.basename+'.excalidraw');
|
||||
});
|
||||
})
|
||||
.addItem((item) => {
|
||||
@@ -499,7 +520,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
const el: ExcalidrawElement[] = excalidrawRef.current.getSceneElements();
|
||||
const st: AppState = excalidrawRef.current.getAppState();
|
||||
return JSON_stringify({
|
||||
return { //JSON_stringify(
|
||||
type: "excalidraw",
|
||||
version: 2,
|
||||
source: "https://excalidraw.com",
|
||||
@@ -523,7 +544,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
currentItemLinearStrokeSharpness: st.currentItemLinearStrokeSharpness,
|
||||
gridSize: st.gridSize,
|
||||
}
|
||||
});
|
||||
};//);
|
||||
};
|
||||
|
||||
this.refresh = () => {
|
||||
@@ -546,13 +567,13 @@ export default class ExcalidrawView extends TextFileView {
|
||||
if(this.isTextLocked && (e.target instanceof HTMLCanvasElement) && this.getSelectedText(true)) { //text element is selected
|
||||
const now = (new Date()).getTime();
|
||||
if(now-timestamp < 600) { //double click
|
||||
var event = new MouseEvent('dblclick', {
|
||||
let event = new MouseEvent('dblclick', {
|
||||
'view': window,
|
||||
'bubbles': true,
|
||||
'cancelable': true,
|
||||
});
|
||||
e.target.dispatchEvent(event);
|
||||
new Notice(t("UNLOCK_TO_EDIT"))
|
||||
new Notice(t("UNLOCK_TO_EDIT"));
|
||||
timestamp = now;
|
||||
return;
|
||||
}
|
||||
@@ -601,7 +622,7 @@ export default class ExcalidrawView extends TextFileView {
|
||||
},
|
||||
onLibraryChange: (items:LibraryItems) => {
|
||||
(async () => {
|
||||
this.plugin.settings.library = EXCALIDRAW_LIB_HEADER+JSON_stringify(items)+'}';
|
||||
this.plugin.settings.library = EXCALIDRAW_LIB_HEADER+JSON.stringify(items)+'}';
|
||||
await this.plugin.saveSettings();
|
||||
})();
|
||||
}
|
||||
@@ -612,15 +633,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
ReactDOM.render(reactElement,(this as any).contentEl);
|
||||
}
|
||||
|
||||
public static getSVG(data:string, exportSettings:ExportSettings):SVGSVGElement {
|
||||
public static getSVG(scene:any, exportSettings:ExportSettings):SVGSVGElement {
|
||||
try {
|
||||
const excalidrawData = JSON_parse(data);
|
||||
return exportToSvg({
|
||||
elements: excalidrawData.elements,
|
||||
elements: scene.elements,
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme ? (excalidrawData.appState?.theme=="light" ? false : true) : false,
|
||||
... excalidrawData.appState,},
|
||||
exportWithDarkMode: exportSettings.withTheme ? (scene.appState?.theme=="light" ? false : true) : false,
|
||||
... scene.appState,},
|
||||
exportPadding:10,
|
||||
metadata: "Generated by Excalidraw-Obsidian plugin",
|
||||
});
|
||||
@@ -629,15 +649,14 @@ export default class ExcalidrawView extends TextFileView {
|
||||
}
|
||||
}
|
||||
|
||||
public static async getPNG(data:string, exportSettings:ExportSettings) {
|
||||
public static async getPNG(scene:any, exportSettings:ExportSettings) {
|
||||
try {
|
||||
const excalidrawData = JSON_parse(data);
|
||||
return await Excalidraw.exportToBlob({
|
||||
elements: excalidrawData.elements,
|
||||
elements: scene.elements,
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme ? (excalidrawData.appState?.theme=="light" ? false : true) : false,
|
||||
... excalidrawData.appState,},
|
||||
exportWithDarkMode: exportSettings.withTheme ? (scene.appState?.theme=="light" ? false : true) : false,
|
||||
... scene.appState,},
|
||||
mimeType: "image/png",
|
||||
exportWithDarkMode: "true",
|
||||
metadata: "Generated by Excalidraw-Obsidian plugin",
|
||||
|
||||
@@ -24,11 +24,20 @@ export class MigrationPrompt extends Modal {
|
||||
div.addClass("excalidarw-prompt-div");
|
||||
div.style.maxWidth = "600px";
|
||||
div.createEl('p',{text: "This version comes with many new features and possibilities. Please read the description in Community Plugins to find out more."});
|
||||
div.createEl('p',{text: "⚠ WARNING: Drawings you have created with version 1.1.x need to be converted, they WILL NOT WORK out of the box. "+
|
||||
"During conversion your old *.excalidraw files will be replaced with new *.excalidraw.md files."});
|
||||
div.createEl('p',{text: "Click CONVERT to convert all of your *.excalidraw files now, or if you prefer to make a backup first, then select CANCEL."});
|
||||
div.createEl('p',{text: "To convert files manually, select 'Excalidraw: Convert *.excalidraw files to *.md files' from the Command Palette at any time in the future."});
|
||||
div.createEl('p',{text: "This message will only appear maximum 3 times."});
|
||||
div.createEl('p',{text: ""} , (el) => {
|
||||
el.innerHTML = "<b>⚠ ATTENTION</b>: Drawings you've created with version 1.1.x need to be converted, they WILL NOT WORK out of the box. "+
|
||||
"During conversion your old *.excalidraw files will be replaced with new *.excalidraw.md files.";
|
||||
});
|
||||
div.createEl('p',{text: ""}, (el) => {//files manually follow one of two options:
|
||||
el.innerHTML = "To convert your drawings you have the following options:<br><ul>" +
|
||||
"<li>Click <code>CONVERT</code> to convert all of your *.excalidraw files now, or if you prefer to make a backup first, then click <code>CANCEL</code>.</li>" +
|
||||
"<li>Using the Command Palette select <code>Excalidraw: Convert *.excalidraw files to *.excalidraw.md files</code></li>" +
|
||||
"<li>Right click an *.excalidraw file in File Explorer and select one of the following to convert files individually: <ul>"+
|
||||
"<li><code>*.excalidraw => *.excalidraw.md</code></li>"+
|
||||
"<li><code>*.excalidraw => *.md (Logseq compatibility)</code>. This option will retain the original *.excalidraw file next to the new Obsidian format. " +
|
||||
"Make sure you also enable <code>Compatibility features</code> in Settings for a full solution.</li></ul></li></ul>";
|
||||
});
|
||||
div.createEl('p',{text: "This message will only appear maximum 3 times in case you have *.excalidraw files in your Vault."});
|
||||
const bConvert = div.createEl('button', {text: "CONVERT FILES"});
|
||||
bConvert.onclick = (ev)=>{
|
||||
this.plugin.convertExcalidrawToMD();
|
||||
|
||||
@@ -8,6 +8,8 @@ export default {
|
||||
CONVERT_NOTE_TO_EXCALIDRAW: "Convert empty note to Excalidraw Drawing",
|
||||
CONVERT_EXCALIDRAW: "Convert *.excalidraw to *.md files",
|
||||
CREATE_NEW : "New Excalidraw drawing",
|
||||
CONVERT_FILE_KEEP_EXT: "*.excalidraw => *.excalidraw.md",
|
||||
CONVERT_FILE_REPLACE_EXT: "*.excalidraw => *.md (Logseq compatibility)",
|
||||
OPEN_EXISTING_NEW_PANE: "Open an existing drawing - IN A NEW PANE",
|
||||
OPEN_EXISTING_ACTIVE_PANE: "Open an existing drawing - IN THE CURRENT ACTIVE PANE",
|
||||
TRANSCLUDE: "Transclude (embed) a drawing",
|
||||
@@ -91,16 +93,23 @@ export default {
|
||||
EXPORT_THEME_NAME: "Export image with theme",
|
||||
EXPORT_THEME_DESC: "Export the image matching the dark/light theme of your drawing. If turned off, " +
|
||||
"drawings created in drak mode will appear as they would in light mode.",
|
||||
EXPORT_HEAD: "Export Settings",
|
||||
EXPORT_SYNC_NAME:"Keep the .SVG and/or .PNG filenames in sync with the drawing file",
|
||||
EXPORT_SYNC_DESC:"When turned on, the plugin will automaticaly update the filename of the .SVG and/or .PNG files when the drawing in the same folder (and same name) is renamed. " +
|
||||
"The plugin will also automatically delete the .SVG and/or .PNG files when the drawing in the same folder (and same name) is deleted. ",
|
||||
EXPORT_SVG_NAME: "Auto-export SVG",
|
||||
EXPORT_SVG_DESC: "Automatically create an SVG export of your drawing matching the title of your file. " +
|
||||
"The plugin will save the .SVG file in the same folder as the drawing. "+
|
||||
"The plugin will save the *.SVG file in the same folder as the drawing. "+
|
||||
"Embed the .svg file into your documents instead of excalidraw making you embeds platform independent. " +
|
||||
"While the auto-export switch is on, this file will get updated every time you edit the excalidraw drawing with the matching name.",
|
||||
EXPORT_PNG_NAME: "Auto-export PNG",
|
||||
EXPORT_PNG_DESC: "Same as the auto-export SVG, but for PNG.",
|
||||
EXPORT_SYNC_NAME:"Keep the .SVG and/or .PNG filenames in sync with the drawing file",
|
||||
EXPORT_SYNC_DESC:"When turned on, the plugin will automaticaly update the filename of the .SVG and/or .PNG files when the drawing in the same folder (and same name) is renamed. " +
|
||||
"The plugin will also automatically delete the .SVG and/or .PNG files when the drawing in the same folder (and same name) is deleted. ",
|
||||
EXPORT_PNG_DESC: "Same as the auto-export SVG, but for *.PNG",
|
||||
COMPATIBILITY_HEAD: "Compatibility features",
|
||||
EXPORT_EXCALIDRAW_NAME: "Auto-export Excalidraw",
|
||||
EXPORT_EXCALIDRAW_DESC: "Same as the auto-export SVG, but for *.Excalidraw",
|
||||
SYNC_EXCALIDRAW_NAME: "Sync *.excalidraw with *.md version of the same drawing",
|
||||
SYNC_EXCALIDRAW_DESC: "If the modified date of the *.excalidraw file is more recent than the modified date of the *.md file " +
|
||||
"then update the drawing in the .md file based on the .excalidraw file",
|
||||
|
||||
//openDrawings.ts
|
||||
SELECT_FILE: "Select a file then press enter.",
|
||||
|
||||
75
src/main.ts
75
src/main.ts
@@ -35,7 +35,8 @@ import {
|
||||
LOCK_ICON,
|
||||
LOCK_ICON_NAME,
|
||||
UNLOCK_ICON_NAME,
|
||||
UNLOCK_ICON
|
||||
UNLOCK_ICON,
|
||||
JSON_parse
|
||||
} from "./constants";
|
||||
import ExcalidrawView, {ExportSettings} from "./ExcalidrawView";
|
||||
import {getJSON} from "./ExcalidrawData";
|
||||
@@ -139,7 +140,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
withBackground: this.settings.exportWithBackground,
|
||||
withTheme: this.settings.exportWithTheme
|
||||
}
|
||||
let svg = ExcalidrawView.getSVG(getJSON(content),exportSettings);
|
||||
let svg = ExcalidrawView.getSVG(JSON_parse(getJSON(content)),exportSettings);
|
||||
if(!svg) return null;
|
||||
svg = ExcalidrawView.embedFontsInSVG(svg);
|
||||
const img = createEl("img");
|
||||
@@ -166,7 +167,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
attr.fname = drawing.getAttribute("src");
|
||||
file = this.app.metadataCache.getFirstLinkpathDest(attr.fname, ctx.sourcePath);
|
||||
if(file && file instanceof TFile && this.isExcalidrawFile(file)) {
|
||||
attr.fwidth = drawing.getAttribute("width");
|
||||
attr.fwidth = drawing.getAttribute("width") ? drawing.getAttribute("width") : this.settings.width;
|
||||
attr.fheight = drawing.getAttribute("height");
|
||||
alt = drawing.getAttribute("alt");
|
||||
if(alt == attr.fname) alt = ""; //when the filename starts with numbers followed by a space Obsidian recognizes the filename as alt-text
|
||||
@@ -187,8 +188,8 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
div = createDiv(attr.style, (el)=>{
|
||||
el.append(img);
|
||||
el.setAttribute("src",file.path);
|
||||
el.setAttribute("w",attr.fwidth);
|
||||
el.setAttribute("h",attr.fheight);
|
||||
if(attr.fwidth) el.setAttribute("w",attr.fwidth);
|
||||
if(attr.fheight) el.setAttribute("h",attr.fheight);
|
||||
el.onClickEvent((ev)=>{
|
||||
if(ev.target instanceof Element && ev.target.tagName.toLowerCase() != "img") return;
|
||||
let src = el.getAttribute("src");
|
||||
@@ -279,7 +280,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
this.createDrawing(this.getNextDefaultFilename(), e.ctrlKey||e.metaKey);
|
||||
});
|
||||
|
||||
const fileMenuHandler = (menu: Menu, file: TFile) => {
|
||||
const fileMenuHandlerCreateNew = (menu: Menu, file: TFile) => {
|
||||
menu.addItem((item: MenuItem) => {
|
||||
item.setTitle(t("CREATE_NEW"))
|
||||
.setIcon(ICON_NAME)
|
||||
@@ -294,7 +295,37 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
};
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-menu", fileMenuHandler)
|
||||
this.app.workspace.on("file-menu", fileMenuHandlerCreateNew)
|
||||
);
|
||||
|
||||
const fileMenuHandlerConvertKeepExtension = (menu: Menu, file: TFile) => {
|
||||
if(file instanceof TFile && file.extension == "excalidraw") {
|
||||
menu.addItem((item: MenuItem) => {
|
||||
item.setTitle(t("CONVERT_FILE_KEEP_EXT"))
|
||||
.onClick(evt => {
|
||||
this.convertSingleExcalidrawToMD(file,false,false);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-menu", fileMenuHandlerConvertKeepExtension)
|
||||
);
|
||||
|
||||
const fileMenuHandlerConvertReplaceExtension = (menu: Menu, file: TFile) => {
|
||||
if(file instanceof TFile && file.extension == "excalidraw") {
|
||||
menu.addItem((item: MenuItem) => {
|
||||
item.setTitle(t("CONVERT_FILE_REPLACE_EXT"))
|
||||
.onClick(evt => {
|
||||
this.convertSingleExcalidrawToMD(file,true,true);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on("file-menu", fileMenuHandlerConvertReplaceExtension)
|
||||
);
|
||||
|
||||
this.addCommand({
|
||||
@@ -541,14 +572,19 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
});
|
||||
}
|
||||
|
||||
public async convertExcalidrawToMD() {
|
||||
public async convertSingleExcalidrawToMD(file: TFile, replaceExtension:boolean = false, keepOriginal:boolean = false) {
|
||||
const data = await this.app.vault.read(file);
|
||||
const filename = file.name.substr(0,file.name.lastIndexOf(".excalidraw")) + (replaceExtension ? ".md" : ".excalidraw.md");
|
||||
const fname = this.getNewUniqueFilepath(filename,normalizePath(file.path.substr(0,file.path.lastIndexOf(file.name))));
|
||||
console.log(fname);
|
||||
await this.app.vault.create(fname,FRONTMATTER + exportSceneToMD(data));
|
||||
if (!keepOriginal) this.app.vault.delete(file);
|
||||
}
|
||||
|
||||
public async convertExcalidrawToMD(replaceExtension:boolean = false, keepOriginal:boolean = false) {
|
||||
const files = this.app.vault.getFiles().filter((f)=>f.extension=="excalidraw");
|
||||
for (const file of files) {
|
||||
const data = await this.app.vault.read(file);
|
||||
const fname = this.getNewUniqueFilepath(file.name+'.md',normalizePath(file.path.substr(0,file.path.lastIndexOf(file.name))));
|
||||
console.log(fname);
|
||||
await this.app.vault.create(fname,FRONTMATTER + exportSceneToMD(data));
|
||||
this.app.vault.delete(file);
|
||||
this.convertSingleExcalidrawToMD(file,replaceExtension,keepOriginal);
|
||||
}
|
||||
new Notice("Converted " + files.length + " files.")
|
||||
}
|
||||
@@ -653,7 +689,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
if(!(file instanceof TFile)) return;
|
||||
if (!self.isExcalidrawFile(file)) return;
|
||||
if (!self.settings.keepInSync) return;
|
||||
['.svg','.png'].forEach(async (ext:string)=>{
|
||||
['.svg','.png','.excalidraw'].forEach(async (ext:string)=>{
|
||||
const oldIMGpath = oldPath.substring(0,oldPath.lastIndexOf('.md')) + ext;
|
||||
const imgFile = self.app.vault.getAbstractFileByPath(normalizePath(oldIMGpath));
|
||||
if(imgFile && imgFile instanceof TFile) {
|
||||
@@ -670,8 +706,11 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
const leaves = self.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
leaves.forEach((leaf:WorkspaceLeaf)=> {
|
||||
const excalidrawView = (leaf.view as ExcalidrawView);
|
||||
if(excalidrawView.file && excalidrawView.file.path == file.path) {
|
||||
excalidrawView.reload(true,file);
|
||||
if(excalidrawView.file
|
||||
&& (excalidrawView.file.path == file.path
|
||||
|| (file.extension=="excalidraw"
|
||||
&& file.path.substring(0,file.path.lastIndexOf('.excalidraw'))+'.md' == excalidrawView.file.path))) {
|
||||
excalidrawView.reload(true,excalidrawView.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -695,7 +734,7 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
|
||||
//delete PNG and SVG files as well
|
||||
if (self.settings.keepInSync) {
|
||||
['.svg','.png'].forEach(async (ext:string) => {
|
||||
['.svg','.png','.excalidraw'].forEach(async (ext:string) => {
|
||||
const imgPath = file.path.substring(0,file.path.lastIndexOf('.md')) + ext;
|
||||
const imgFile = self.app.vault.getAbstractFileByPath(normalizePath(imgPath));
|
||||
if(imgFile && imgFile instanceof TFile) {
|
||||
@@ -777,8 +816,6 @@ export default class ExcalidrawPlugin extends Plugin {
|
||||
}
|
||||
|
||||
public openDrawing(drawingFile: TFile, onNewPane: boolean) {
|
||||
this.settings.drawingOpenCount++;
|
||||
this.saveSettings();
|
||||
const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
let leaf:WorkspaceLeaf = null;
|
||||
|
||||
|
||||
@@ -20,9 +20,11 @@ export interface ExcalidrawSettings {
|
||||
allowCtrlClick: boolean, //if disabled only the link button in the view header will open links
|
||||
exportWithTheme: boolean,
|
||||
exportWithBackground: boolean,
|
||||
keepInSync: boolean,
|
||||
autoexportSVG: boolean,
|
||||
autoexportPNG: boolean,
|
||||
keepInSync: boolean,
|
||||
autoexportExcalidraw: boolean,
|
||||
syncExcalidraw: boolean,
|
||||
library: string,
|
||||
loadCount: number, //version 1.2 migration counter
|
||||
drawingOpenCount: number,
|
||||
@@ -40,9 +42,11 @@ export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
allowCtrlClick: true,
|
||||
exportWithTheme: true,
|
||||
exportWithBackground: true,
|
||||
keepInSync: false,
|
||||
autoexportSVG: false,
|
||||
autoexportPNG: false,
|
||||
keepInSync: false,
|
||||
autoexportExcalidraw: false,
|
||||
syncExcalidraw: false,
|
||||
library: `{"type":"excalidrawlib","version":1,"library":[]}`,
|
||||
loadCount: 0,
|
||||
drawingOpenCount: 0,
|
||||
@@ -228,7 +232,19 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.triggerEmbedUpdates();
|
||||
}));
|
||||
|
||||
|
||||
this.containerEl.createEl('h1', {text: t("EXPORT_HEAD")});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("EXPORT_SYNC_NAME"))
|
||||
.setDesc(t("EXPORT_SYNC_DESC"))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.keepInSync)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.keepInSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("EXPORT_SVG_NAME"))
|
||||
.setDesc(t("EXPORT_SVG_DESC"))
|
||||
@@ -239,26 +255,38 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("EXPORT_PNG_NAME"))
|
||||
.setDesc(t("EXPORT_PNG_DESC"))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.autoexportPNG)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoexportPNG = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.autoexportPNG)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoexportPNG = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
this.containerEl.createEl('h1', {text: t("COMPATIBILITY_HEAD")});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("EXPORT_SYNC_NAME"))
|
||||
.setDesc(t("EXPORT_SYNC_DESC"))
|
||||
.setName(t("EXPORT_EXCALIDRAW_NAME"))
|
||||
.setDesc(t("EXPORT_EXCALIDRAW_DESC"))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.keepInSync)
|
||||
.setValue(this.plugin.settings.autoexportExcalidraw)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.keepInSync = value;
|
||||
this.plugin.settings.autoexportExcalidraw = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t("SYNC_EXCALIDRAW_NAME"))
|
||||
.setDesc(t("SYNC_EXCALIDRAW_DESC"))
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.syncExcalidraw)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.syncExcalidraw = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
12
styles.css
12
styles.css
@@ -61,4 +61,14 @@ button.ToolIcon_type_button[title="Export"] {
|
||||
|
||||
.excalidraw-prompt-input {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "Virgil";
|
||||
src: url("https://excalidraw.com/Virgil.woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Cascadia";
|
||||
src: url("https://excalidraw.com/Cascadia.woff2");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user