Compare commits

..

3 Commits

Author SHA1 Message Date
Zsolt Viczian
ebcf807501 1.2.0-alpha-2 2021-07-04 12:15:42 +02:00
Zsolt Viczian
bd155eced3 language file cleanup 2021-07-04 06:59:32 +02:00
Zsolt Viczian
2b7d0d5dc2 [[ encoding (incl. migration), template link. 2021-07-03 17:02:40 +02:00
8 changed files with 180 additions and 141 deletions

View File

@@ -1,6 +1,5 @@
import ExcalidrawPlugin from "./main";
import {
ExcalidrawElement,
FillStyle,
StrokeStyle,
StrokeSharpness,
@@ -12,7 +11,12 @@ import {
} from "obsidian"
import ExcalidrawView from "./ExcalidrawView";
import { getJSON } from "./ExcalidrawData";
import { CASCADIA_FONT, FRONTMATTER, nanoid, VIRGIL_FONT } from "./constants";
import {
FRONTMATTER,
nanoid,
JSON_stringify,
JSON_parse
} from "./constants";
declare type ConnectionPoint = "top"|"bottom"|"left"|"right";
@@ -159,7 +163,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
elements.push(this.elementsDict[this.elementIds[i]]);
}
navigator.clipboard.writeText(
JSON.stringify({
JSON_stringify({
"type":"excalidraw/clipboard",
"elements": elements,
}));
@@ -175,7 +179,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
params?.onNewPane ? params.onNewPane : false,
params?.foldername ? params.foldername : this.plugin.settings.folder,
FRONTMATTER + exportSceneToMD(
JSON.stringify({
JSON_stringify({
type: "excalidraw",
version: 2,
source: "https://excalidraw.com",
@@ -208,7 +212,7 @@ export async function initExcalidrawAutomate(plugin: ExcalidrawPlugin) {
elements.push(this.elementsDict[this.elementIds[i]]);
}
return ExcalidrawView.getSVG(
JSON.stringify({
JSON_stringify({
"type": "excalidraw",
"version": 2,
"source": "https://excalidraw.com",
@@ -231,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",
@@ -440,7 +444,6 @@ async function initFonts () {
for (let i=1;i<=3;i++) {
await (document as any).fonts.load('20px ' + getFontFamily(i));
}
console.log("Fonts Ready");
}
export function measureText (newText:string, fontSize:number, fontFamily:number) {
@@ -477,7 +480,7 @@ async function getTemplate(fileWithPath: string):Promise<{elements: any,appState
const file = vault.getAbstractFileByPath(normalizePath(fileWithPath));
if(file && file instanceof TFile) {
const data = await vault.read(file);
const excalidrawData = JSON.parse(getJSON(data));
const excalidrawData = JSON_parse(getJSON(data));
return {
elements: excalidrawData.elements,
appState: excalidrawData.appState,
@@ -496,7 +499,7 @@ async function getTemplate(fileWithPath: string):Promise<{elements: any,appState
*/
export function exportSceneToMD(data:string): string {
if(!data) return "";
const excalidrawData = JSON.parse(data);
const excalidrawData = JSON_parse(data);
const textElements = excalidrawData.elements?.filter((el:any)=> el.type=="text")
let outString = '# Text Elements\n';
let id:string;
@@ -511,5 +514,5 @@ async function getTemplate(fileWithPath: string):Promise<{elements: any,appState
}
outString += te.text+' ^'+id+'\n\n';
}
return outString + '# Drawing\n'+ data;
return outString + '# Drawing\n'+ data.replaceAll("[","&#91;");
}

View File

@@ -1,8 +1,16 @@
import { App, TFile } from "obsidian";
import { nanoid} from "./constants";
import {
nanoid,
FRONTMATTER_KEY_CUSTOM_PREFIX,
FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS,
} from "./constants";
import { measureText } from "./ExcalidrawAutomate";
import ExcalidrawPlugin from "./main";
import { ExcalidrawSettings } from "./settings";
import {
JSON_stringify,
JSON_parse
} from "./constants";
//![[link|alias]]![alias](link)
//1 2 3 4 5 6
@@ -25,7 +33,7 @@ export class ExcalidrawData {
private settings:ExcalidrawSettings;
private app:App;
private showLinkBrackets: boolean;
private linkIndicator: string;
private linkPrefix: string;
private allowParse: boolean = false;
constructor(plugin: ExcalidrawPlugin) {
@@ -40,19 +48,22 @@ export class ExcalidrawData {
*/
public async loadData(data: string,file: TFile, allowParse:boolean):Promise<boolean> {
//console.log("Excalidraw.Data.loadData()",{data:data,allowParse:allowParse,file:file});
//I am storing these because if the settings change while a drawing is open parsing will run into errors during save
//The drawing will use these values until next drawing is loaded or this drawing is re-loaded
this.showLinkBrackets = this.settings.showLinkBrackets;
this.linkIndicator = this.settings.linkIndicator;
this.file = file;
this.textElements = new Map<string,{raw:string, parsed:string}>();
//I am storing these because if the settings change while a drawing is open parsing will run into errors during save
//The drawing will use these values until next drawing is loaded or this drawing is re-loaded
this.setShowLinkBrackets();
this.setLinkPrefix();
//Load scene: Read the JSON string after "# Drawing"
this.scene = null;
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]);
this.scene = JSON_parse(parts.value[1]);
//Trim data to remove the JSON string
data = data.substring(0,parts.value.index);
@@ -127,7 +138,7 @@ export class ExcalidrawData {
//get scene text elements
const texts = this.scene.elements?.filter((el:any)=> el.type=="text")
let jsonString = JSON.stringify(this.scene);
let jsonString = JSON_stringify(this.scene);
let dirty:boolean = false; //to keep track if the json has changed
let id:string; //will be used to hold the new 8 char long ID for textelements that don't yet appear under # Text Elements
@@ -148,7 +159,7 @@ export class ExcalidrawData {
}
}
if(dirty) { //reload scene json in case it has changed
this.scene = JSON.parse(jsonString);
this.scene = JSON_parse(jsonString);
}
return dirty;
@@ -223,7 +234,7 @@ export class ExcalidrawData {
const file = this.app.metadataCache.getFirstLinkpathDest(parts.value[1],this.file.path);
const contents = await this.app.vault.cachedRead(file);
//get transcluded line and take the part before ^blockref
const REG_TRANSCLUDE = new RegExp("(.*)\\s\\^" + parts.value[2] + "\\n");
const REG_TRANSCLUDE = new RegExp("(.*)\\s\\^" + parts.value[2]);
const res = contents.match(REG_TRANSCLUDE);
if(res) return res[1];
return text;//if blockref not found in file, return the input string
@@ -255,7 +266,7 @@ export class ExcalidrawData {
}
outString += text.substring(position,text.length);
if (linkIcon) {
outString = this.linkIndicator + outString;
outString = this.linkPrefix + outString;
}
return outString;
@@ -271,21 +282,21 @@ export class ExcalidrawData {
for(const key of this.textElements.keys()){
outString += this.textElements.get(key).raw+' ^'+key+'\n\n';
}
return outString + '# Drawing\n' + JSON.stringify(this.scene);
return outString + '# Drawing\n' + JSON_stringify(this.scene);
}
public syncElements(newScene:any):boolean {
//console.log("Excalidraw.Data.syncElements()");
this.scene = JSON.parse(newScene);
const result = this.findNewTextElementsInScene();
this.scene = JSON_parse(newScene);
const result = this.setLinkPrefix() || this.setShowLinkBrackets() || this.findNewTextElementsInScene();
this.updateTextElementsFromSceneRawOnly();
return result;
}
public async updateScene(newScene:any){
//console.log("Excalidraw.Data.updateScene()");
this.scene = JSON.parse(newScene);
const result = this.findNewTextElementsInScene();
this.scene = JSON_parse(newScene);
const result = this.setLinkPrefix() || this.setShowLinkBrackets() || this.findNewTextElementsInScene();
await this.updateTextElementsFromScene();
if(result) {
await this.updateSceneTextElements();
@@ -298,4 +309,26 @@ export class ExcalidrawData {
return this.textElements.get(id)?.raw;
}
private setLinkPrefix():boolean {
const linkPrefix = this.linkPrefix;
const fileCache = this.app.metadataCache.getFileCache(this.file);
if (fileCache?.frontmatter && fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_PREFIX]!=null) {
this.linkPrefix=fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_PREFIX];
} else {
this.linkPrefix = this.settings.linkPrefix;
}
return linkPrefix != this.linkPrefix;
}
private setShowLinkBrackets():boolean {
const showLinkBrackets = this.showLinkBrackets;
const fileCache = this.app.metadataCache.getFileCache(this.file);
if (fileCache?.frontmatter && fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS]!=null) {
this.showLinkBrackets=fileCache.frontmatter[FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS]!=false;
} else {
this.showLinkBrackets = this.settings.showLinkBrackets;
}
return showLinkBrackets != this.showLinkBrackets;
}
}

View File

@@ -27,7 +27,8 @@ import {
FRONTMATTER_KEY,
UNLOCK_ICON_NAME,
LOCK_ICON_NAME,
JSON_stringify,
JSON_parse
} from './constants';
import ExcalidrawPlugin from './main';
import {ExcalidrawAutomate} from './ExcalidrawAutomate';
@@ -126,7 +127,7 @@ export default class ExcalidrawView extends TextFileView {
// get the new file content
// if drawing is in Text Element Edit Lock, then everything should be parsed and in sync
// if drawing is in Text Element Edit Unlock, then everything is raw and parse a.k.a async is not required.
// if drawing is in Text Element Edit Unlock, then everything is raw and parse and so an async function is not required here
getViewData () {
//console.log("ExcalidrawView.getViewData()");
if(this.getScene) {
@@ -344,7 +345,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()), this.file.basename+'.excalidraw');
this.download('data:text/plain;charset=utf-8',encodeURIComponent(this.getScene().replaceAll("&#91;","[")), this.file.basename+'.excalidraw');
});
})
.addItem((item) => {
@@ -397,7 +398,7 @@ export default class ExcalidrawView extends TextFileView {
}
async getLibrary() {
const data = JSON.parse(this.plugin.settings.library);
const data = JSON_parse(this.plugin.settings.library);
return data?.library ? data.library : [];
}
@@ -495,7 +496,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",
@@ -597,7 +598,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();
})();
}
@@ -610,7 +611,7 @@ export default class ExcalidrawView extends TextFileView {
public static getSVG(data:string, exportSettings:ExportSettings):SVGSVGElement {
try {
const excalidrawData = JSON.parse(data);
const excalidrawData = JSON_parse(data);
return exportToSvg({
elements: excalidrawData.elements,
appState: {
@@ -627,7 +628,7 @@ export default class ExcalidrawView extends TextFileView {
public static async getPNG(data:string, exportSettings:ExportSettings) {
try {
const excalidrawData = JSON.parse(data);
const excalidrawData = JSON_parse(data);
return await Excalidraw.exportToBlob({
elements: excalidrawData.elements,
appState: {

View File

@@ -1,7 +1,12 @@
//This is to avoid brackets littering graph view with links
export function JSON_stringify(x:any):string {return JSON.stringify(x).replaceAll("[","&#91;");}
export function JSON_parse(x:string):any {return JSON.parse(x.replaceAll("&#91;","["));}
import {customAlphabet} from "nanoid";
export const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',8);
export const FRONTMATTER_KEY = "excalidraw-plugin";
export const FRONTMATTER_KEY_CUSTOM_PREFIX = "excalidraw-link-prefix";
export const FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS = "excalidraw-link-brackets";
export const VIEW_TYPE_EXCALIDRAW = "excalidraw";
export const ICON_NAME = "excalidraw-icon";
export const MAX_COLORS = 5;

View File

@@ -1,77 +1,82 @@
// English
import { FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS, FRONTMATTER_KEY_CUSTOM_PREFIX } from "src/constants";
// English
export default {
// main.ts
OPEN_AS_EXCALIDRAW: "Open as Excalidraw Drawing",
TOGGLE_MODE: "Toggle between Excalidraw and markdown mode",
TOGGLE_MODE: "Toggle between Excalidraw and Markdown mode",
CONVERT_NOTE_TO_EXCALIDRAW: "Convert empty note to Excalidraw Drawing",
MIGRATE_TO_2: "MIGRATE to version 2: convert .excalidraw files to .md files",
CREATE_NEW : "New Excalidraw",
MIGRATE_TO_2: "MIGRATE to version 1.2: convert *.excalidraw to *.md files",
CREATE_NEW : "New Excalidraw drawing",
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) an Excalidraw drawing",
TRANSCLUDE_MOST_RECENT: "Transclude (embed) the most recently edited Excalidraw drawing",
TRANSCLUDE: "Transclude (embed) a drawing",
TRANSCLUDE_MOST_RECENT: "Transclude (embed) the most recently edited drawing",
NEW_IN_NEW_PANE: "Create a new drawing - IN A NEW PANE",
NEW_IN_ACTIVE_PANE: "Create a new drawing - IN THE CURRENT ACTIVE PANE",
NEW_IN_NEW_PANE_EMBED: "Create a new drawing - IN A NEW PANE - and embed in current document",
NEW_IN_ACTIVE_PANE_EMBED: "Create a new drawing - IN THE CURRENT ACTIVE PANE - and embed in current document",
EXPORT_SVG: "Export SVG. Save it next to the current file",
EXPORT_PNG: "Export PNG. Save it next to the current file",
TOGGLE_LOCK: "Toggle text element edit lock/unlock",
NEW_IN_NEW_PANE_EMBED: "Create a new drawing - IN A NEW PANE - and embed into active document",
NEW_IN_ACTIVE_PANE_EMBED: "Create a new drawing - IN THE CURRENT ACTIVE PANE - and embed into active document",
EXPORT_SVG: "Save as SVG next to the current file",
EXPORT_PNG: "Save as PNG next to the current file",
TOGGLE_LOCK: "Toggle Text Element edit LOCK/UNLOCK",
INSERT_LINK: "Insert link to file",
INSERT_LATEX: "Insert LaTeX-symbol (e.g. $\\theta$)",
ENTER_LATEX: "Enter a valid LaTeX expression",
//ExcalidrawView.ts
OPEN_AS_MD: "Open as markdown",
SAVE_AS_PNG: "Save as PNG into Vault (CTRL/META+click to export)",
SAVE_AS_SVG: "Save as SVG into Vault (CTRL/META+click to export)",
OPEN_LINK: "Open selected text as link\n(SHIFT+click to open in a new pane)",
EXPORT_EXCALIDRAW: "Export to .Excalidraw file",
UNLOCK_TO_EDIT: "Unlock text elements to edit",
LINK_BUTTON_CLICK_NO_TEXT: 'Select a text element containing an internal or external link.\n'+
'SHIFT CLICK this button to open link in a new pane.\n'+
'CTRL/META CLICK on the Text Element on the canvas also works!',
TEXT_ELEMENT_EMPTY: "Text element is empty, or [[valid-link|alias]] or [alias](valid-link) is not found",
OPEN_AS_MD: "Open as Markdown",
SAVE_AS_PNG: "Save as PNG into Vault (CTRL/META+CLICK to export)",
SAVE_AS_SVG: "Save as SVG into Vault (CTRL/META+CLICK to export)",
OPEN_LINK: "Open selected text as link\n(SHIFT+CLICK to open in a new pane)",
EXPORT_EXCALIDRAW: "Export to an .Excalidraw file",
UNLOCK_TO_EDIT: "UNLOCK Text Elements to edit",
LINK_BUTTON_CLICK_NO_TEXT: 'Select a Text Element containing an internal or external link.\n'+
'SHIFT CLICK this button to open the link in a new pane.\n'+
'CTRL/META CLICK the Text Element on the canvas has the same effect!',
TEXT_ELEMENT_EMPTY: "Text Element is empty, or [[valid-link|alias]] or [alias](valid-link) is not found",
FILENAME_INVALID_CHARS: 'File name cannot contain any of the following characters: * " \\  < > : | ?',
FILE_DOES_NOT_EXIST: "File does not exist. Hold down ALT (or ALT+SHIFT) and click link button to create a new file.",
FORCE_SAVE: "Force-save to update transclusions in adjacent panes\n(Please note, that autosave is always on)",
LOCK: "Text Elements are unlocked. Click to lock.",
UNLOCK: "Text Elements are locked. Click to unlock.",
FILE_DOES_NOT_EXIST: "File does not exist. Hold down ALT (or ALT+SHIFT) and CLICK link button to create a new file.",
FORCE_SAVE: "Force-save to update transclusions in adjacent panes.\n(Please note, that autosave is always on)",
LOCK: "Text Elements are unlocked. Click to LOCK.",
UNLOCK: "Text Elements are locked. Click to UNLOCK.",
NOFILE: "Excalidraw (no file)",
//settings.ts
FOLDER_NAME: "Excalidraw folder",
FOLDER_DESC: "Default location for your drawings. If empty, drawings will be created in the Vault root.",
FOLDER_DESC: "Default location for new drawings. If empty, drawings will be created in the Vault root.",
TEMPLATE_NAME: "Excalidraw template file",
TEMPLATE_DESC: "Full filepath to the Excalidraw template. " +
"E.g.: If your template is in the default Excalidraw folder, the setting would be: Excalidraw/Template",
FILENAME_HEAD: "New drawing filename",
FILENAME_DESC: '<p>The auto-generated filename consists of a prefix and a date. ' +
'e.g."Drawing 2021-05-24 12.58.07".</p>'+
'<p>Click this link for the <a href="https://momentjs.com/docs/#/displaying/format/">'+
'date and time format reference</a>.</p>',
"E.g.: If your template is in the default Excalidraw folder and it's name is " +
"Template.excalidraw, the setting would be: Excalidraw/Template.excalidraw",
FILENAME_HEAD: "Filenam for drawings",
FILENAME_DESC: "<p>The auto-generated filename consists of a prefix and a date. " +
"e.g.'Drawing 2021-05-24 12.58.07'.</p>"+
"<p>Click this link for the <a href='https://momentjs.com/docs/#/displaying/format/'>"+
"date and time format reference</a>.</p>",
FILENAME_SAMPLE: "The current file format is: <b>",
FILENAME_PREFIX_NAME: "Filename prefix",
FILENAME_PREFIX_DESC: "The first part of the filename",
FILENAME_DATE_NAME: "Filename date",
FILENAME_DATE_DESC: "The second part of the filename",
LINKS_HEAD: "Links in drawings",
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. ' +
'If the text starts as a valid web link (i.e. https:// or http://), then ' +
'the plugin will try to open it in a browser. ' +
'When Obsidian files change, the matching [[link]] in your drawings will also change. ' +
'If you don\'t want text accidentally changing in your drawings use [[links|with aliases]].',
LINK_BRACKETS_NAME: "Show [[bracket]] around links",
LINK_BRACKETS_DESC: "When parsing text elements, place brackets around links",
LINK_INDICATOR_NAME:"Link indicator",
LINK_INDICATOR_DESC:"If text element contains a link, precede the text with these characters in preview.",
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. " +
"If the text starts as a valid web link (i.e. https:// or http://), then " +
"the plugin will open it in a browser. " +
"When Obsidian files change, the matching [[link]] in your drawings will also change. " +
"If you don't want text accidentally changing in your drawings use [[links|with aliases]].",
LINK_BRACKETS_NAME: "Show [[brackets]] around links",
LINK_BRACKETS_DESC: "In preview (locked) mode, when parsing Text Elements, place brackets around links. " +
"You can override this setting for a specific drawing by adding '" + FRONTMATTER_KEY_CUSTOM_LINK_BRACKETS +
": true/false' to the file\'s frontmatter.",
LINK_PREFIX_NAME:"Link prefix",
LINK_PREFIX_DESC:"In preview (locked) mode, if the Text Element contains a link, precede the text with these characters. " +
"You can override this setting for a specific drawing by adding \'" + FRONTMATTER_KEY_CUSTOM_PREFIX +
': "👉 "\' to the file\'s frontmatter.',
LINK_CTRL_CLICK_NAME: "CTRL + CLICK on text to open them as links",
LINK_CTRL_CLICK_DESC: 'You can turn this feature off if it interferes with default Excalidraw features you want to use. If ' +
'this is turned off, only the link button in the title bar of the drawing pane will open links.',
EMBED_HEAD: "Embedded image settings",
LINK_CTRL_CLICK_DESC: "You can turn this feature off if it interferes with default Excalidraw features you want to use. If " +
"this is turned off, only the link button in the title bar of the drawing pane will open links.",
EMBED_HEAD: "Embedded/Export image settings",
EMBED_WIDTH_NAME: "Default width of embedded (transcluded) image",
EMBED_WIDTH_DESC: "The default width of an embedded drawing. You can specify a custom " +
"width when embedding an image using the ![[drawing.excalidraw|100]] or " +
@@ -79,24 +84,24 @@ export default {
EXPORT_BACKGROUND_NAME: "Export image with background",
EXPORT_BACKGROUND_DESC: "If turned off, the exported image will be transparent.",
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_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_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. '+
'Embed the .svg file into your documents instead of excalidraw to 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_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. "+
"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_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. ",
//openDrawings.ts
SELECT_FILE: "Select a file then hit enter.",
SELECT_FILE: "Select a file then press enter.",
NO_MATCH: "No file matches your query.",
SELECT_FILE_TO_LINK: "Select file to inster link for.",
SELECT_FILE_TO_LINK: "Select the file you want to insert the link for.",
TYPE_FILENAME: "Type name of drawing to select.",
SELECT_FILE_OR_TYPE_NEW: "Select existing drawing or type name of a new then hit enter.",
SELECT_TO_EMBED: "Select drawing to insert into document.",
SELECT_FILE_OR_TYPE_NEW: "Select existing drawing or type name of a new drawing then press Enter.",
SELECT_TO_EMBED: "Select the drawing to insert into active document.",
};

View File

@@ -63,8 +63,6 @@ export default class ExcalidrawPlugin extends Plugin {
private openDialog: OpenFileDialog;
private activeExcalidrawView: ExcalidrawView = null;
public lastActiveExcalidrawFilePath: string = null;
private workspaceEventHandlers:Map<string,any> = new Map();
private vaultEventHandlers:Map<string,any> = new Map();
private hover: {linkText: string, sourcePath: string} = {linkText: null, sourcePath: null};
private observer: MutationObserver;
@@ -82,7 +80,6 @@ export default class ExcalidrawPlugin extends Plugin {
await this.loadSettings();
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
await initExcalidrawAutomate(this);
this.registerView(
@@ -92,10 +89,10 @@ export default class ExcalidrawPlugin extends Plugin {
this.addMarkdownPostProcessor();
this.registerCommands();
this.registerEventListeners();
//inspiration taken from kanban: https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
//inspiration taken from kanban:
//https://github.com/mgmeyers/obsidian-kanban/blob/44118e25661bff9ebfe54f71ae33805dc88ffa53/src/main.ts#L267
this.registerMonkeyPatches();
}
@@ -207,7 +204,6 @@ export default class ExcalidrawPlugin extends Plugin {
* @returns
*/
const hoverEvent = (e:any) => {
//@ts-ignore
if(!(e.event.ctrlKey||e.event.metaKey)) return;
if(!e.linktext) return;
this.hover.linkText = e.linktext;
@@ -219,10 +215,11 @@ export default class ExcalidrawPlugin extends Plugin {
return;
}
};
//@ts-ignore
this.app.workspace.on('hover-link',hoverEvent);
this.workspaceEventHandlers.set('hover-link',hoverEvent);
};
this.registerEvent(
//@ts-ignore
this.app.workspace.on('hover-link',hoverEvent)
);
//monitoring for div.popover.hover-popover.file-embed.is-loaded to be added to the DOM tree
this.observer = new MutationObserver((m)=>{
@@ -283,8 +280,6 @@ export default class ExcalidrawPlugin extends Plugin {
this.app.workspace.on("file-menu", fileMenuHandler)
);
this.workspaceEventHandlers.set("file-menu",fileMenuHandler);
this.addCommand({
id: "excalidraw-open",
name: t("OPEN_EXISTING_NEW_PANE"),
@@ -409,7 +404,7 @@ export default class ExcalidrawPlugin extends Plugin {
this.addCommand({
id: "toggle-lock",
hotkeys: [{modifiers:["Ctrl" || "Meta"], key:"e"}],
hotkeys: [{modifiers:["Ctrl" || "Meta","Shift"], key:"e"}],
name: t("TOGGLE_LOCK"),
checkCallback: (checking: boolean) => {
if (checking) {
@@ -427,7 +422,7 @@ export default class ExcalidrawPlugin extends Plugin {
this.addCommand({
id: "insert-link",
hotkeys: [{modifiers:["Ctrl" || "Meta"], key:"k"}],
hotkeys: [{modifiers:["Ctrl" || "Meta","Shift"], key:"k"}],
name: t("INSERT_LINK"),
checkCallback: (checking: boolean) => {
if (checking) {
@@ -641,8 +636,9 @@ export default class ExcalidrawPlugin extends Plugin {
}
});
};
self.app.vault.on("rename",renameEventHandler);
this.vaultEventHandlers.set("rename",renameEventHandler);
self.registerEvent(
self.app.vault.on("rename",renameEventHandler)
);
const modifyEventHandler = async (file:TFile) => {
const leaves = self.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
@@ -653,13 +649,15 @@ export default class ExcalidrawPlugin extends Plugin {
}
});
}
self.app.vault.on("modify",modifyEventHandler);
this.vaultEventHandlers.set("modify",modifyEventHandler);
self.registerEvent(
self.app.vault.on("modify",modifyEventHandler)
)
//watch file delete and delete corresponding .svg
//watch file delete and delete corresponding .svg and .png
const deleteEventHandler = async (file:TFile) => {
if (!(file instanceof TFile)) return;
if (!self.isExcalidrawFile(file)) return;
if (!(file instanceof TFile)) return;
//@ts-ignore
if (file.unsaveCachedData && !file.unsafeCachedData.search(/---\n[\s\S]*excalidraw-plugin:\s*(locked|unlocked)\n[\s\S]*---/gm)==-1) return;
//close excalidraw view where this file is open
const leaves = self.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
@@ -680,8 +678,9 @@ export default class ExcalidrawPlugin extends Plugin {
});
}
}
self.app.vault.on("delete",deleteEventHandler);
this.vaultEventHandlers.set("delete",deleteEventHandler);
self.registerEvent(
self.app.vault.on("delete",deleteEventHandler)
);
//save open drawings when user quits the application
const quitEventHandler = (tasks: Tasks) => {
@@ -690,14 +689,14 @@ export default class ExcalidrawPlugin extends Plugin {
(leaves[i].view as ExcalidrawView).save();
}
}
self.app.workspace.on("quit",quitEventHandler);
this.workspaceEventHandlers.set("quit",quitEventHandler);
self.registerEvent(
self.app.workspace.on("quit",quitEventHandler)
);
//save Excalidraw leaf and update embeds when switching to another leaf
const activeLeafChangeEventHandler = async (leaf:WorkspaceLeaf) => {
const activeview:ExcalidrawView = (leaf.view instanceof ExcalidrawView) ? leaf.view as ExcalidrawView : null;
if(self.activeExcalidrawView && self.activeExcalidrawView != activeview) {
//console.log("ExcalidrawPlugin.activeLeafChangeEventHandler()");
await self.activeExcalidrawView.save();
self.triggerEmbedUpdates(self.activeExcalidrawView.file?.path);
}
@@ -706,19 +705,15 @@ export default class ExcalidrawPlugin extends Plugin {
self.lastActiveExcalidrawFilePath = self.activeExcalidrawView.file?.path;
}
};
self.app.workspace.on("active-leaf-change",activeLeafChangeEventHandler);
this.workspaceEventHandlers.set("active-leaf-change",activeLeafChangeEventHandler);
self.registerEvent(
self.app.workspace.on("active-leaf-change",activeLeafChangeEventHandler)
);
});
}
onunload() {
destroyExcalidrawAutomate();
for(const key of this.vaultEventHandlers.keys())
this.app.vault.off(key,this.vaultEventHandlers.get(key))
for(const key of this.workspaceEventHandlers.keys())
this.app.workspace.off(key,this.workspaceEventHandlers.get(key));
this.observer.disconnect();
const excalidrawLeaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
excalidrawLeaves.forEach((leaf) => {
this.setMarkdownView(leaf);
@@ -778,12 +773,12 @@ export default class ExcalidrawPlugin extends Plugin {
}
private getNextDefaultFilename():string {
return this.settings.drawingFilenamePrefix + window.moment().format(this.settings.drawingFilenameDateTime)+'.md';
return this.settings.drawingFilenamePrefix + window.moment().format(this.settings.drawingFilenameDateTime)+'.excalidraw.md';
}
private async getBlankDrawing():Promise<string> {
const template = this.app.vault.getAbstractFileByPath(normalizePath(this.settings.templateFilePath));
const template = this.app.metadataCache.getFirstLinkpathDest(normalizePath(this.settings.templateFilePath),"");
if(template && template instanceof TFile) {
const data = await this.app.vault.read(template);
if (data) return data;

View File

@@ -33,7 +33,7 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
this.inputEl.onkeyup = (e) => {
if(e.key=="Enter" && this.action == openDialogAction.openFile) {
if (this.containerEl.innerText.includes(EMPTY_MESSAGE)) {
this.plugin.createDrawing(this.plugin.settings.folder+'/'+this.inputEl.value+'.md', this.onNewPane);
this.plugin.createDrawing(this.plugin.settings.folder+'/'+this.inputEl.value+'.excalidraw.md', this.onNewPane);
this.close();
}
}
@@ -62,11 +62,8 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
break;
case(openDialogAction.insertLink):
//TO-DO
//change to this.app.metadataCache.fileToLinktext(file: TFile, sourcePath: string, omitMdExtension?: boolean): string;
//@ts-ignore
const filepath = this.app.metadataCache.getLinkpathDest(item.path,this.drawingPath)[0].path;
this.addText("[["+(filepath.endsWith(".md")?filepath.substr(0,filepath.length-3):filepath)+"]]"); //.md files don't need the extension
const filepath = this.app.metadataCache.fileToLinktext(item,this.drawingPath,true);
this.addText("[["+filepath+"]]");
break;
}
}

View File

@@ -15,7 +15,7 @@ export interface ExcalidrawSettings {
drawingFilenameDateTime: string,
width: string,
showLinkBrackets: boolean,
linkIndicator: string,
linkPrefix: string,
// validLinksOnly: boolean, //valid link as in [[valid Obsidian link]] - how to treat text elements in drawings
allowCtrlClick: boolean, //if disabled only the link button in the view header will open links
exportWithTheme: boolean,
@@ -28,11 +28,11 @@ export interface ExcalidrawSettings {
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
folder: 'Excalidraw',
templateFilePath: 'Excalidraw/Template',
templateFilePath: 'Excalidraw/Template.excalidraw',
drawingFilenamePrefix: 'Drawing ',
drawingFilenameDateTime: 'YYYY-MM-DD HH.mm.ss',
width: '400',
linkIndicator: ">> ",
linkPrefix: ">> ",
showLinkBrackets: true,
// validLinksOnly: false,
allowCtrlClick: true,
@@ -146,13 +146,13 @@ export class ExcalidrawSettingTab extends PluginSettingTab {
}));
new Setting(containerEl)
.setName(t("LINK_INDICATOR_NAME"))
.setDesc(t("LINK_INDICATOR_DESC"))
.setName(t("LINK_PREFIX_NAME"))
.setDesc(t("LINK_PREFIX_DESC"))
.addText(text => text
.setPlaceholder('>> ')
.setValue(this.plugin.settings.linkIndicator)
.setValue(this.plugin.settings.linkPrefix)
.onChange(async (value) => {
this.plugin.settings.linkIndicator = value;
this.plugin.settings.linkPrefix = value;
await this.plugin.saveSettings();
reloadDrawings();
}));