diff --git a/docs/Juggl.md b/docs/Juggl.md index 223a9db..2a1f698 100644 --- a/docs/Juggl.md +++ b/docs/Juggl.md @@ -9,7 +9,6 @@ Juggl is the next generation of PKM-focused graph views! - **Code** is on Github: https://github.com/HEmile/juggl - **Support the development** of Juggl: - Buy me a kofi: https://ko-fi.com/Emile - - Sponsor me on Github: https://github.com/sponsors/HEmile - Paypal.me: https://paypal.me/EvanKrieken # Features @@ -51,6 +50,8 @@ Note that Juggl is GPL3 **dual-**licensed. Contact me for details. # Neo4j Graph View If you came here looking for the documentation of the deprecated [[Neo4j Graph View Plugin]], please go [[Neo4j Graph View Plugin|here]]. + + --- #plugin - author [[Emile van Krieken]] diff --git a/juggl/main.ts b/juggl/main.ts index aa4a077..4682728 100644 --- a/juggl/main.ts +++ b/juggl/main.ts @@ -9,20 +9,17 @@ import { DefaultJugglSettings, LAYOUTS, genStyleGroups, emptyStyleGroup, } from './settings'; -import {Juggl, MD_VIEW_TYPE} from './viz/visualization'; +import {Juggl} from './viz/visualization'; import {ImageServer} from './image-server'; import type { ICoreDataStore, IDataStore, IJugglStores, - ITypedLink, - ITypedLinkProperties, IJugglPlugin, IJuggl, } from 'juggl-api'; import {OBSIDIAN_STORE_NAME, ObsidianStore} from './obsidian-store'; import cytoscape, {NodeSingular} from 'cytoscape'; -// import coseBilkent from 'cytoscape-cose-bilkent'; import navigator from 'cytoscape-navigator'; import popper from 'cytoscape-popper'; import cola from 'cytoscape-cola'; @@ -50,9 +47,7 @@ import {GlobalWarningModal} from './ui/settings/global-graph-modal'; export default class JugglPlugin extends Plugin implements IJugglPlugin { // Match around [[ and ]], and ensure content isn't a wikilnk closure // This doesn't explicitly parse aliases. - static wikilinkRegex = '\\[\\[([^\\]\\r\\n]+?)\\]\\]';// static CAT_DANGLING = 'dangling'; - static nameRegex = '[^\\W\\d]\\w*'; settings: IJugglPluginSettings; path: string; @@ -294,6 +289,7 @@ export default class JugglPlugin extends Plugin implements IJugglPlugin { this.setGlobalIcon(); this.addChild(new ImageServer(this)); } + public setGlobalIcon() { if (this.ribbonIcon) { this.ribbonIcon.detach(); @@ -304,6 +300,7 @@ export default class JugglPlugin extends Plugin implements IJugglPlugin { }); } } + public async openFileFromNode(node: NodeSingular, newLeaf= false): Promise { const id = VizId.fromNode(node); if (!(id.storeId === 'core')) { @@ -361,114 +358,6 @@ export default class JugglPlugin extends Plugin implements IJugglPlugin { // '"}) OPTIONAL MATCH (n)-[r]-(m) RETURN n,r,m'; // } - _parseTags(tags: string[]): string[] { - return [].concat(...tags - .map((tag) => { - tag = tag.slice(1); - const hSplit = tag.split('/'); - const tags = []; - for (const i in hSplit) { - const hTag = hSplit.slice(0, parseInt(i) + 1).join('-'); - tags.push(`tag-${hTag}`); - } - return tags; - })); - } - - public getClasses(file: TFile): string[] { - if (file) { - const classes = []; - if (['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg', 'tiff'].contains(file.extension)) { - classes.push('image'); - } else if (['mp3', 'webm', 'wav', 'm4a', 'ogg', '3gp', 'flac'].contains(file.extension)) { - classes.push('audio'); - } else if (['mp4', 'webm', 'ogv'].contains(file.extension)) { - classes.push('video'); - } else if (file.extension === 'pdf') { - classes.push('pdf'); - } - // This is replaced by the 'path' data attribute. - // if (!(file.parent.name === '/' || file.parent.name === '')) { - // classes.push(`folder-${file.parent.name - // .replace(' ', '_')}`); - // } else { - // classes.push('root'); - // } - if (file.extension === 'md') { - classes.push('note'); - const cache = this.app.metadataCache.getFileCache(file); - if (cache?.frontmatter) { - if ('image' in cache.frontmatter) { - classes.push('image'); - } - if ('tags' in cache.frontmatter) { - const tags = parseFrontMatterTags(cache.frontmatter); - if (tags) { - classes.push(...this._parseTags(tags)); - } - } - if ('cssclass' in cache.frontmatter) { - const clazzes = parseFrontMatterStringArray(cache.frontmatter, 'cssclass'); - if (clazzes) { - classes.push(...clazzes); - } - } - } - if (cache?.tags) { - classes.push(...this._parseTags(cache.tags.map((t) => t.tag))); - } - } else { - classes.push('file'); - } - return classes; - } - return [JugglPlugin.CAT_DANGLING]; - } - - regexEscape(str: string) { - return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - public parseTypedLink(link: ReferenceCache, line: string): ITypedLink { - // TODO: This is something specific I use, but shouldn't keep being in this repo. - const regexPublishedIn = new RegExp( - `^${this.regexEscape(this.settings.typedLinkPrefix)} (publishedIn) (\\d\\d\\d\\d) (${JugglPlugin.wikilinkRegex},? *)+$`); - const matchPI = regexPublishedIn.exec(line); - if (!(matchPI === null)) { - return { - class: 'type-publishedIn', - isInline: false, - properties: { - year: matchPI[2], - context: '', - type: 'publishedIn', - } as ITypedLinkProperties, - } as ITypedLink; - } - - // Intuition: Start with the typed link prefix. Then a neo4j name (nameRegex). - // Then one or more of the wikilink group: wikilink regex separated by optional comma and multiple spaces - const regex = new RegExp( - `^${this.regexEscape(this.settings.typedLinkPrefix)} (${JugglPlugin.nameRegex}) (${JugglPlugin.wikilinkRegex},? *)+$`); - const match = regex.exec(line); - const splitLink = link.original.split('|'); - let alias = null; - if (splitLink.length > 1) { - alias = splitLink.slice(1).join().slice(0, -2); - } - if (!(match === null)) { - return { - class: `type-${match[1]}`, - isInline: false, - properties: { - alias: alias, - context: '', - type: match[1], - } as ITypedLinkProperties, - } as ITypedLink; - } - return null; - } // executeQuery() { // // Code taken from https://github.com/mrjackphil/obsidian-text-expand/blob/0.6.4/main.ts diff --git a/juggl/obsidian-store.ts b/juggl/obsidian-store.ts index 0490ee9..1f3dbce 100644 --- a/juggl/obsidian-store.ts +++ b/juggl/obsidian-store.ts @@ -12,12 +12,10 @@ import type JugglPlugin from './main'; import type { NodeDefinition, EdgeDefinition, - NodeDataDefinition, NodeCollection, - EdgeDataDefinition, Collection, } from 'cytoscape'; import {CLASS_EXPANDED} from './constants'; -import {VizId} from 'juggl-api'; +import {nodeDangling, nodeFromFile, parseRefCache, VizId} from 'juggl-api'; export const OBSIDIAN_STORE_NAME = 'Obsidian'; @@ -54,31 +52,7 @@ export class ObsidianStore extends Component implements ICoreDataStore { if (toNodes.$id(otherId).length > 0) { const edgeId = `${srcId}->${otherId}`; const count = edgeId in edges ? edges[edgeId].length + 1 : 1; - const line = content[ref.position.start.line]; - let data = { - id: `${edgeId}${count}`, - source: srcId, - target: otherId, - context: line, - edgeCount: 1, - } as EdgeDataDefinition; - const splitLink = ref.original.split('|'); - if (splitLink.length > 1) { - data['alias'] = splitLink.slice(1).join().slice(0, -2); - } - let classes = ''; - const typedLink = this.plugin.parseTypedLink(ref, line); - if (typedLink === null) { - classes = `${classes} inline`; - } else { - data = {...typedLink.properties, ...data}; - classes = `${classes} ${typedLink.class}`; - } - const edge = { - group: 'edges', - data: data, - classes: classes, - } as EdgeDefinition; + const edge = parseRefCache(ref, content, `${edgeId}${count}`, srcId, otherId, this.plugin.settings.typedLinkPrefix); if (edgeId in edges) { edges[edgeId].push(edge); } else { @@ -166,9 +140,9 @@ ${edge.data.context}`; const path = getLinkpath(link.link); const file = this.metadata.getFirstLinkpathDest(path, sourcePath); if (file) { - return await this.nodeFromFile(file); + return await nodeFromFile(file, this.plugin); } else { - return this.nodeDangling(path); + return nodeDangling(path); } } @@ -187,61 +161,13 @@ ${edge.data.context}`; const file = this.vault.getAbstractFileByPath(otherPath) as TFile; const id = VizId.fromFile(file).toId(); if (!(id in nodes)) { - nodes[id] = await this.nodeFromFile(file); + nodes[id] = await nodeFromFile(file, this.plugin); } } } } } - async nodeFromFile(file: TFile) : Promise { - const cache = this.metadata.getFileCache(file); - const name = file.extension === 'md' ? file.basename : file.name; - const classes = this.plugin.getClasses(file).join(' '); - const data = { - id: VizId.toId(file.name, this.storeId()), - name: name, - path: file.path, - resource_url: `http://localhost:${this.plugin.settings.imgServerPort}/${encodeURI(file.path)}`, - } as NodeDataDefinition; - data['content'] = await this.vault.cachedRead(file); - const frontmatter = cache?.frontmatter; - if (frontmatter) { - Object.keys(frontmatter).forEach((k) => { - if (!(k === 'position')) { - if (k === 'image') { - const imageField = frontmatter[k]; - try { - // Check if url. throws error otherwise - new URL(imageField); - data[k] = imageField; - } catch { - data[k] = `http://localhost:${this.plugin.settings.imgServerPort}/${encodeURI(imageField)}`; - } - } else { - data[k] = frontmatter[k]; - } - } - }); - } - - return { - group: 'nodes', - data: data, - classes: classes, - }; - } - - nodeDangling(path: string): NodeDefinition { - return { - group: 'nodes', - data: { - id: VizId.toId(path, this.storeId()), - name: path, - }, - classes: 'dangling', - }; - } async getNeighbourhood(nodeIds: VizId[]): Promise { const nodes: Record = {}; @@ -256,7 +182,7 @@ ${edge.data.context}`; continue; } if (!(nodeId.toId() in nodes)) { - nodes[nodeId.toId()] = await this.nodeFromFile(file); + nodes[nodeId.toId()] = await nodeFromFile(file, this.plugin); } const promiseNodes: Record> = {}; iterateCacheRefs(cache, (ref) => { @@ -290,7 +216,7 @@ ${edge.data.context}`; console.log('returning empty cache', nodeId); return null; } - return Promise.resolve(this.nodeFromFile(file)); + return Promise.resolve(nodeFromFile(file, this.plugin)); } async refreshNode(view: IJuggl, id: VizId) { diff --git a/juggl/package-lock.json b/juggl/package-lock.json index f1770eb..1790b86 100644 --- a/juggl/package-lock.json +++ b/juggl/package-lock.json @@ -18,7 +18,7 @@ "cytoscape-dblclick": "^0.3.1", "cytoscape-navigator": "^2.0.1", "cytoscape-popper": "^2.0.0", - "juggl-api": "github:hemile/juggl-api", + "juggl-api": "github:HEmile/juggl-api", "obsidian": "github:obsidianmd/obsidian-api", "search-query-parser": "^1.5.5" }, @@ -2276,7 +2276,7 @@ }, "node_modules/juggl-api": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/hemile/juggl-api.git#7c9e0b0937d9e3119b36a800c8e34c9e3f4e81ce", + "resolved": "git+ssh://git@github.com/HEmile/juggl-api.git#f7d07e8a93788a0478dc4ef36c6d1394ce2f49a0", "dependencies": { "@types/cytoscape": "^3.14.11" } @@ -2519,7 +2519,7 @@ }, "node_modules/obsidian": { "version": "0.12.0", - "resolved": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#ffc713b80981abb444b0e1ed21f2a870a3e15610", + "resolved": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#068ff3052f0641baff90856dcb420dc2721680c9", "license": "MIT", "dependencies": { "@types/codemirror": "0.0.108", @@ -5242,8 +5242,8 @@ } }, "juggl-api": { - "version": "git+ssh://git@github.com/hemile/juggl-api.git#7c9e0b0937d9e3119b36a800c8e34c9e3f4e81ce", - "from": "juggl-api@github:hemile/juggl-api", + "version": "git+ssh://git@github.com/HEmile/juggl-api.git#f7d07e8a93788a0478dc4ef36c6d1394ce2f49a0", + "from": "juggl-api@github:HEmile/juggl-api", "requires": { "@types/cytoscape": "^3.14.11" } @@ -5436,7 +5436,7 @@ } }, "obsidian": { - "version": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#ffc713b80981abb444b0e1ed21f2a870a3e15610", + "version": "git+ssh://git@github.com/obsidianmd/obsidian-api.git#068ff3052f0641baff90856dcb420dc2721680c9", "from": "obsidian@github:obsidianmd/obsidian-api", "requires": { "@types/codemirror": "0.0.108", diff --git a/juggl/package.json b/juggl/package.json index 73f674a..4b2d952 100644 --- a/juggl/package.json +++ b/juggl/package.json @@ -58,7 +58,7 @@ "cytoscape-dblclick": "^0.3.1", "cytoscape-navigator": "^2.0.1", "cytoscape-popper": "^2.0.0", - "juggl-api": "github:hemile/juggl-api", + "juggl-api": "github:HEmile/juggl-api", "obsidian": "github:obsidianmd/obsidian-api", "search-query-parser": "^1.5.5" } diff --git a/manifest.json b/manifest.json index 5f8c13a..cbd33bc 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "juggl", "name": "Juggl", - "version": "1.1.0", + "version": "1.1.1", "minAppVersion": "0.11.5", "description": "Adds a completely interactive, stylable and expandable graph view to Obsidian.", "author": "Emile",