diff --git a/manifest.json b/manifest.json index 20159c6..868b6f3 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "excalibrain", "name": "ExcaliBrain", - "version": "0.2.5", + "version": "0.2.6", "minAppVersion": "1.1.6", "description": "A clean, intuitive and editable graph view for Obsidian", "author": "Zsolt Viczian", diff --git a/src/Components/AddToOntologyModal.ts b/src/Components/AddToOntologyModal.ts new file mode 100644 index 0000000..5093379 --- /dev/null +++ b/src/Components/AddToOntologyModal.ts @@ -0,0 +1,205 @@ +import { create } from "domain"; +import { App, Modal, Notice, Setting } from "obsidian"; +import { createBinaryOps } from "obsidian-dataview/lib/expression/binaryop"; +import ExcaliBrain from "src/excalibrain-main"; +import { t } from "src/lang/helpers"; + +export enum Ontology { + Parent = "parent", + Child = "child", + LeftFriend = "leftFriend", + RightFriend = "rightFriend", + Previous = "previous", + Next = "next", +} + +export class AddToOntologyModal extends Modal { + private ontology:Ontology|null = null; + private fieldName:string; + constructor( + app: App, + private plugin: ExcaliBrain, + ) { + super(app); + } + + private getCurrentOntology():Ontology|null { + const { settings } = this.plugin; + const field = this.fieldName; + + if(settings.hierarchy.parents.includes(field)) { + return Ontology.Parent; + } + if(settings.hierarchy.children.includes(field)) { + return Ontology.Child; + } + if(settings.hierarchy.leftFriends.includes(field)) { + return Ontology.LeftFriend; + } + if(settings.hierarchy.rightFriends.includes(field)) { + return Ontology.RightFriend; + } + if(settings.hierarchy.previous.includes(field)) { + return Ontology.Previous; + } + if(settings.hierarchy.next.includes(field)) { + return Ontology.Next; + } + + return null; + } + + private async setOntology(ontology:Ontology) { + if(this.ontology === ontology) return; + const { settings } = this.plugin; + const plugin = this.plugin; + + //remove from current ontology + switch(this.ontology) { + case Ontology.Parent: + settings.hierarchy.parents = settings.hierarchy.parents.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.parents = []; + settings.hierarchy.parents.forEach(f=>plugin.hierarchyLowerCase.parents.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Child: + settings.hierarchy.children = settings.hierarchy.children.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.children = []; + settings.hierarchy.children.forEach(f=>plugin.hierarchyLowerCase.children.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.LeftFriend: + settings.hierarchy.leftFriends = settings.hierarchy.leftFriends.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.leftFriends = []; + settings.hierarchy.leftFriends.forEach(f=>plugin.hierarchyLowerCase.leftFriends.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.RightFriend: + settings.hierarchy.rightFriends = settings.hierarchy.rightFriends.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.rightFriends = []; + settings.hierarchy.rightFriends.forEach(f=>plugin.hierarchyLowerCase.rightFriends.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Previous: + settings.hierarchy.previous = settings.hierarchy.previous.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.previous = []; + settings.hierarchy.previous.forEach(f=>plugin.hierarchyLowerCase.previous.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Next: + settings.hierarchy.next = settings.hierarchy.next.filter(f=>f!==this.fieldName); + plugin.hierarchyLowerCase.next = []; + settings.hierarchy.next.forEach(f=>plugin.hierarchyLowerCase.next.push(f.toLowerCase().replaceAll(" ","-"))); + break; + } + + //add to new ontology + switch(ontology) { + case Ontology.Parent: + settings.hierarchy.parents.push(this.fieldName); + settings.hierarchy.parents = settings.hierarchy.parents.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.parents.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Child: + settings.hierarchy.children.push(this.fieldName); + settings.hierarchy.children = settings.hierarchy.children.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.children.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.LeftFriend: + settings.hierarchy.leftFriends.push(this.fieldName); + settings.hierarchy.leftFriends = settings.hierarchy.leftFriends.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.leftFriends.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.RightFriend: + settings.hierarchy.rightFriends.push(this.fieldName); + settings.hierarchy.rightFriends = settings.hierarchy.rightFriends.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.rightFriends.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Previous: + settings.hierarchy.previous.push(this.fieldName); + settings.hierarchy.previous = settings.hierarchy.previous.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.previous.push(f.toLowerCase().replaceAll(" ","-"))); + break; + case Ontology.Next: + settings.hierarchy.next.push(this.fieldName); + settings.hierarchy.next = settings.hierarchy.next.sort((a,b)=>a.toLowerCase()plugin.hierarchyLowerCase.next.push(f.toLowerCase().replaceAll(" ","-"))); + break; + } + await this.plugin.saveSettings(); + if (plugin.scene && !plugin.scene.terminated) { + plugin.scene.vaultFileChanged = true; + } + new Notice(`Added ${this.fieldName} as ${ontology}`); + this.fieldName = null; + this.close(); + } + + async show( fieldName:string ) { + await this.plugin.loadSettings(); + this.fieldName = fieldName; + this.ontology = this.getCurrentOntology(); + this.open(); + } + + public async addFieldToOntology(ontology:Ontology, fieldName:string) { + await this.plugin.loadSettings(); + this.fieldName = fieldName; + this.ontology = this.getCurrentOntology(); + await this.setOntology(ontology); + this.fieldName = null; + } + + open () { + if(!this.fieldName) return; + const { contentEl, titleEl } = this; + titleEl.setText(this.fieldName); + contentEl.createEl("p", {text: t("ADD_TO_ONTOLOGY_MODAL_DESC")}); + const setting = new Setting(contentEl) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("PARENTS_NAME")) + if(this.ontology === Ontology.Parent) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.Parent)) + }) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("CHILDREN_NAME")) + if(this.ontology === Ontology.Child) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.Child)) + }) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("LEFT_FRIENDS_NAME")) + if(this.ontology === Ontology.LeftFriend) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.LeftFriend)) + }) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("RIGHT_FRIENDS_NAME")) + if(this.ontology === Ontology.RightFriend) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.RightFriend)) + }) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("PREVIOUS_NAME")) + if(this.ontology === Ontology.Previous) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.Previous)) + }) + .addButton((b) => { + b.buttonEl.style.flex = "1 0 calc(33.33% - var(--size-4-2))"; + b.setButtonText(t("NEXT_NAME")) + if(this.ontology === Ontology.Next) b.setCta(); + b.onClick(()=>this.setOntology(Ontology.Next)) + }); + setting.controlEl.style.flexWrap = "wrap"; + setting.controlEl.style.justifyContent = "space-between"; + super.open(); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} \ No newline at end of file diff --git a/src/Scene.ts b/src/Scene.ts index a8e2c1b..8c71bd2 100644 --- a/src/Scene.ts +++ b/src/Scene.ts @@ -542,11 +542,11 @@ export class Scene { this.layouts.push(lChildren); const friendOrigoX = isCompactView && isCenterEmbedded - ? centerEmbedWidth/2 + 1.5 * this.nodeWidth + ? centerEmbedWidth/2 + this.nodeWidth : Math.max( (((manyNextFriends?1:0)+Math.max(childrenCols,parentCols)+1.9)/2.4) * this.nodeWidth, // (manyChildren ? -3 : -2) * this.nodeWidth, isCenterEmbedded - ? centerEmbedWidth/2 + 1.5 * this.nodeWidth + ? centerEmbedWidth/2 + this.nodeWidth : 0 ); diff --git a/src/excalibrain-main.ts b/src/excalibrain-main.ts index b643b11..9977e48 100644 --- a/src/excalibrain-main.ts +++ b/src/excalibrain-main.ts @@ -1,4 +1,4 @@ -import { App, MarkdownView, Notice, Plugin, PluginManifest, TextFileView, TFile, TFolder, WorkspaceLeaf } from 'obsidian'; +import { App, Editor, MarkdownView, Menu, MenuItem, Notice, Plugin, PluginManifest, TextFileView, TFile, TFolder, WorkspaceLeaf } from 'obsidian'; import { Page } from './graph/Page'; import { DEFAULT_SETTINGS, ExcaliBrainSettings, ExcaliBrainSettingTab } from './Settings'; import { errorlog, keepOnTop } from './utils/utils'; @@ -16,6 +16,7 @@ import { FieldSuggester } from './Suggesters/OntologySuggester'; import { Literal } from 'obsidian-dataview/lib/data-model/value'; import { isEmbedFileType } from './utils/fileUtils'; import { URLParser } from './graph/URLParser'; +import { AddToOntologyModal, Ontology } from './Components/AddToOntologyModal'; declare module "obsidian" { interface App { @@ -58,6 +59,7 @@ export default class ExcaliBrain extends Plugin { public customNodeLabel: (dvPage: Literal, defaultName:string) => string public navigationHistory: string[] = []; public urlParser: URLParser; + private addToOntologyModal: AddToOntologyModal; constructor(app: App, manifest: PluginManifest) { super(app, manifest); @@ -69,6 +71,7 @@ export default class ExcaliBrain extends Plugin { "Initializing index, please wait" ) ] + this.addToOntologyModal = new AddToOntologyModal(app,this); } async onload() { @@ -76,6 +79,7 @@ export default class ExcaliBrain extends Plugin { this.navigationHistory = this.settings.navigationHistory; this.addSettingTab(new ExcaliBrainSettingTab(this.app, this)); this.registerEditorSuggest(new FieldSuggester(this)); + this.registerEvents(); this.urlParser = new URLParser(this); this.app.workspace.onLayoutReady(()=>{ this.urlParser.init(); @@ -138,6 +142,46 @@ export default class ExcaliBrain extends Plugin { }); } + private registerEvents() { + this.registerEvent( + this.app.workspace.on("editor-menu", this.handleEditorMenu, this) + ); + } + + private getFieldName(editor: Editor): string { + let line = editor.getLine(editor.getCursor().line).substring(0,editor.getCursor().ch); + const regex = /(?:^|[(\[])(?:==|\*\*|~~|\*|_|__)?([^\:\]\()]*?)(?:==|\*\*|~~|\*|_|__)?::/g; + let lastMatch = null; + let match; + + while ((match = regex.exec(line)) !== null) { + lastMatch = match; + } + + //default to the full line, maybe the user positioned the cursor in the middle of the field + if(!lastMatch) { + line = editor.getLine(editor.getCursor().line); + while ((match = regex.exec(line)) !== null) { + lastMatch = match; + } + } + return lastMatch !== null ? lastMatch[1] : null; + } + + private handleEditorMenu(menu: Menu, editor: Editor, view: MarkdownView) { + const field = this.getFieldName(editor); + if(field) { + menu.addItem((item: MenuItem) => { + item + .setTitle(`Add "${field}" to ExcaliBrain Ontology`) + .setIcon("plus") + .onClick(() => { + this.addToOntologyModal.show(field); + }); + }); + } + } + public lowercasePathMap: Map; public async createIndex() { @@ -304,132 +348,72 @@ export default class ExcaliBrain extends Plugin { searchElement?.focus(); } + private addFieldToOntology(field: string, direction: Ontology) { + this.addToOntologyModal.addFieldToOntology(direction, field); + } + private registerCommands() { - const addFieldToOntology = (checking: boolean, desc: string):boolean => { - const activeView = app.workspace.activeLeaf?.view; - if(checking) { - return (activeView instanceof MarkdownView) && activeView.getMode() === "source"; - } - if(!(activeView instanceof MarkdownView) || activeView.getMode() !== "source") { + const addFieldToOntology = (checking: boolean, direction: Ontology | "select"):boolean => { + const activeView = app.workspace.activeLeaf?.view; + if(!activeView || !(activeView instanceof MarkdownView) || activeView.getMode() !== "source") { return false; } - const cursor = activeView.editor.getCursor(); - const line = activeView.editor.getLine(cursor.line); - const field = line.match(/^([^\:]*)::/); + const field = this.getFieldName(activeView.editor); if(!field) { return false; } - - (async() => { - await this.loadSettings(); - - if(this.settings.hierarchy.parents.includes(field[1])) { - new Notice(`${field[1]} is already registered as a PARENT`); - return; - } - if(this.settings.hierarchy.children.includes(field[1])) { - new Notice(`${field[1]} is already registered as a CHILD`); - return; - } - if(this.settings.hierarchy.leftFriends.includes(field[1])) { - new Notice(`${field[1]} is already registered as a LEFT-SIDE FRIEND`); - return; - } - if(this.settings.hierarchy.rightFriends.includes(field[1])) { - new Notice(`${field[1]} is already registered as a RIGHT-SIDE FRIEND`); - return; - } - if(this.settings.hierarchy.previous.includes(field[1])) { - new Notice(`${field[1]} is already registered as a PREVIOUS (FRIEND)`); - return; - } - if(this.settings.hierarchy.next.includes(field[1])) { - new Notice(`${field[1]} is already registered as a NEXT (FRIEND)`); - return; - } - - switch (desc) { - case "parent": - this.settings.hierarchy.parents.push(field[1]); - this.settings.hierarchy.parents = this.settings.hierarchy.parents.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.parents.push(f.toLowerCase().replaceAll(" ","-"))) - break; - case "child": - this.settings.hierarchy.children.push(field[1]); - this.settings.hierarchy.children = this.settings.hierarchy.children.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.children.push(f.toLowerCase().replaceAll(" ","-"))) - break; - case "rightFriend": - this.settings.hierarchy.rightFriends.push(field[1]); - this.settings.hierarchy.rightFriends = this.settings.hierarchy.rightFriends.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.rightFriends.push(f.toLowerCase().replaceAll(" ","-"))) - break; - case "previous": - this.settings.hierarchy.previous.push(field[1]); - this.settings.hierarchy.previous = this.settings.hierarchy.previous.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.previous.push(f.toLowerCase().replaceAll(" ","-"))) - break; - case "next": - this.settings.hierarchy.next.push(field[1]); - this.settings.hierarchy.next = this.settings.hierarchy.next.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.next.push(f.toLowerCase().replaceAll(" ","-"))) - break; - default: - this.settings.hierarchy.leftFriends.push(field[1]); - this.settings.hierarchy.leftFriends = this.settings.hierarchy.leftFriends.sort((a,b)=>a.toLowerCase()this.hierarchyLowerCase.leftFriends.push(f.toLowerCase().replaceAll(" ","-"))) - } - await this.saveSettings(); - if (this.scene && !this.scene.terminated) { - this.scene.vaultFileChanged = true; - } - new Notice(`Added ${field[1]} as ${desc}`); - })(); - + if(checking) { + return true; + } + if(direction === "select") { + this.addToOntologyModal.show(field); + return true; + } + this.addFieldToOntology(field,direction); return true; - } + } this.addCommand({ id: "excalibrain-addParentField", name: t("COMMAND_ADD_PARENT_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "parent"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.Parent), }); this.addCommand({ id: "excalibrain-addChildField", name: t("COMMAND_ADD_CHILD_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "child"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.Child), }); this.addCommand({ id: "excalibrain-addLeftFriendField", name: t("COMMAND_ADD_LEFT_FRIEND_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "leftFriend"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.LeftFriend), }); this.addCommand({ id: "excalibrain-addRightFriendField", name: t("COMMAND_ADD_RIGHT_FRIEND_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "rightFriend"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.RightFriend), }); this.addCommand({ id: "excalibrain-addPreviousField", name: t("COMMAND_ADD_PREVIOUS_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "previous"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.Previous), }); this.addCommand({ id: "excalibrain-addNextField", name: t("COMMAND_ADD_NEXT_FIELD"), - checkCallback: (checking: boolean) => addFieldToOntology(checking, "next"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, Ontology.Next), + }); + + this.addCommand({ + id: "excalibrain-selectOntology", + name: t("COMMAND_ADD_ONTOLOGY_MODAL"), + checkCallback: (checking: boolean) => addFieldToOntology(checking, "select"), }); this.addCommand({ diff --git a/src/graph/URLParser.ts b/src/graph/URLParser.ts index 721e238..eb71b4a 100644 --- a/src/graph/URLParser.ts +++ b/src/graph/URLParser.ts @@ -7,8 +7,13 @@ export interface FileURL { origin: string; } -export const linkRegex = /\[([^[\]]+)\]\((https?:\d*?\/\/[a-z0-9&#=.\/\-?_]+)\)/gi; // Matches links in markdown format [label](url) -export const plainLinkRegex = /(https?:\d*?\/\/[a-z0-9&#=.\/\-?_]+)/gi; // Matches plain links +// Matches links in markdown format [label](url) +//export const linkRegex = /\[([^[\]]+)\]\(((?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))\)/gi; +// Matches plain links +//export const plainLinkRegex = /((?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/gi; +//export const plainLinkRegex = /((?:(?:ftp|https?|sftp|shttp|tftp):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/gi; + +export const linkRegex = /(?:\[([^[\]]+)\]\()((?:(?:ftp|https?|sftp|shttp|tftp):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>"']|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))\)|\b()((?:(?:ftp|https?|sftp|shttp|tftp):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>"']|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))\b/gi; export class URLParser { fileToUrlMap: Map = new Map(); @@ -52,7 +57,11 @@ export class URLParser { let match; while ((match = linkRegex.exec(content)) !== null) { - const [, alias, url] = match; + const alias = match[1] ?? match[3] ?? ""; + let url = match[2] ?? match[4] ?? ""; + if(!url.match(/^(?:ftp|https?|sftp|shttp|tftp):/)) { + url = "https://" + url; + } if (!links.has(url)) { const origin = this.getOrigin(url,file); links.set(url,{ url, alias, origin}); @@ -65,15 +74,6 @@ export class URLParser { } } - while ((match = plainLinkRegex.exec(content)) !== null) { - const url = match[0]; - if (!links.has(url)) { - const origin = this.getOrigin(url,file); - links.set(url, { url, alias: '', origin}); - this.updateInverseMap(url, file, origin); - } - } - const linkArray = Array.from(links.values()); if (linkArray.length > 0) { this.fileToUrlMap.set(file, linkArray); diff --git a/src/lang/locale/en.ts b/src/lang/locale/en.ts index d62841f..fa949de 100644 --- a/src/lang/locale/en.ts +++ b/src/lang/locale/en.ts @@ -172,6 +172,7 @@ export default { COMMAND_ADD_RIGHT_FRIEND_FIELD: "Add dataview field to ontology as RIGHT-SIDE FRIEND", COMMAND_ADD_PREVIOUS_FIELD: "Add dataview field to ontology as PREVIOUS", COMMAND_ADD_NEXT_FIELD: "Add dataview field to ontology as NEXT", + COMMAND_ADD_ONTOLOGY_MODAL: "Add dataview field to ontology: Open Ontology Modal", COMMAND_START: "ExcaliBrain Normal", COMMAND_START_HOVER: "ExcaliBrain Hover-Editor", COMMAND_START_POPOUT: "ExcaliBrain Popout Window", @@ -191,5 +192,8 @@ export default { SHOW_HIDE_FOLDER: "Show/Hide folder nodes", SHOW_HIDE_TAG: "Show/Hide tag nodes", SHOW_HIDE_PAGES: "Show/Hide page nodes (incl. defined, inferred, virtual and attachments)", - PIN_LEAF: "Link ExcaliBrain to most recent active leaf" + PIN_LEAF: "Link ExcaliBrain to most recent active leaf", + + //AddToOntologyModal + ADD_TO_ONTOLOGY_MODAL_DESC: "Select the direction of the ontology. If one of the buttons is highlighted, then the field is already part of the ontology in that direction.", } diff --git a/src/utils/dataview.ts b/src/utils/dataview.ts index cd0f8ad..330095a 100644 --- a/src/utils/dataview.ts +++ b/src/utils/dataview.ts @@ -1,7 +1,7 @@ import { App, TFile } from "obsidian"; import { Literal } from "obsidian-dataview/lib/data-model/value"; import ExcaliBrain from "src/excalibrain-main"; -import { plainLinkRegex } from "src/graph/URLParser"; +import { linkRegex } from "src/graph/URLParser"; import { ExcaliBrainSettings } from "src/Settings"; import { NodeStyle } from "src/types"; @@ -32,8 +32,8 @@ const readLinksFromString = (data: string, file:TFile):string[] => { } let match; - while ((match = plainLinkRegex.exec(data)) !== null) { - res.add(match[0]); + while ((match = linkRegex.exec(data)) !== null) { + res.add(match[2]??match[4]); } return Array.from(res);