From e714c50e5bc888a4fb122e9ce5f46eaee1ed51f5 Mon Sep 17 00:00:00 2001 From: iiz00 Date: Sat, 7 Oct 2023 16:34:30 +0900 Subject: [PATCH] Support for links in properties --- README.md | 17 +++ manifest.json | 2 +- package.json | 2 +- src/constructDOM.ts | 243 ++++++++++++++++++++++++++++++++++++++---- src/drawUI.ts | 30 +++++- src/fileView.ts | 48 ++++++--- src/folderView.ts | 48 ++++++--- src/getOutline.ts | 5 +- src/getTargetFiles.ts | 11 +- src/main.ts | 54 ++++++---- src/setting.ts | 31 +++--- src/util.ts | 27 ++++- 12 files changed, 416 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index c10ba88..8eacc57 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ If this is the case, change "Note title background color" in the settings, and i ## Acknowledgement In developing Daily Note Outline and Multiple Notes Outline, I have use many great plugins in Obsidian community as references. In particular,
[Spaced Repetition by @st3v3nmw](https://github.com/st3v3nmw/obsidian-spaced-repetition) and [Recent Files by @tgrosinger](https://github.com/tgrosinger/recent-files-obsidian) for creating custom views.
+As for getting backlink files, I am using the function of [Dataview by @blacksmithgu](https://github.com/blacksmithgu/obsidian-dataview).
I also searched and referred to a bunch of posts in plugin-dev channel on Discord.

## Buy Me A Coffee @@ -80,6 +81,21 @@ If you like my plugin, I would appreciate it if you could buy me a cup of coffee [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/iiz00)

## Changelog +- 0.2.0 + - Improvement + - Support for links in properties + - Now links in properties are also reflected as outgoing and backlinks. + - NOTE: Installation of Dataview plugin is recommended to improve backlink files acquisition speed. + - Now you can change the level of headings to be displayed quickly from the context menu of the heading toggle icon('H' icon). + - Now colors of MNO views immediately reflects the light/dark mode change. + - The option "other files to main file only" has been added to "Hide link elements between displayed files" in the settings. + - If this option is selected, links from the main target file to other files will be displayed as outline elements, but links from backlinked files to the main target file will not be displayed. + - Fixed + - Fixed a problem in which MNO views being active every time Obsidian is started. + - Fixed a problem in which the folded state of a file was not stored correctly in Folder view. + - Fixed Tooltip preview was not working properly due to recent Obsidian changes. + - Changed + - The default value of "Open File/Folder View at startup" in the settings has been changed to OFF. - 0.1.3 - Fixed file view not working properly when backlinks are hidden. - 0.1.1 @@ -163,6 +179,7 @@ MNOにはインラインプレビューとツールチッププレビューの2 ## Acknowledgement 謝辞 本プラグインの作成にあたり、多くの素晴らしいObsidianのプラグインを参考にさせて頂きました。特に、
カスタムビューの作成にSpaced Repetition by st3v3nmwとRecent files by tgrosingerを大いに参考にさせて頂きました。
+バックリンクファイルの取得については、Dataview by blacksmithguの機能を利用させていただいています。
また、discordの plugin-devの書き込みを多数参考にさせて頂きました。

## Buy Me A Coffee diff --git a/manifest.json b/manifest.json index 63121ba..c72b7aa 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "multiple-notes-outline", "name": "Multiple Notes Outline", - "version": "0.1.4", + "version": "0.2.0", "minAppVersion": "1.3.0", "description": "Add custom views which show outlines of multiple notes with headings, links, tags and list items.", "author": "iiz", diff --git a/package.json b/package.json index d8bce9b..2175a59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multiple-notes-outline", - "version": "0.1.4", + "version": "0.2.0", "description": "Add custom views which shows outline of multiple notes at once", "main": "main.js", "scripts": { diff --git a/src/constructDOM.ts b/src/constructDOM.ts index 56628cf..aa3d73e 100644 --- a/src/constructDOM.ts +++ b/src/constructDOM.ts @@ -1,9 +1,9 @@ -import { TFile, setIcon, Menu, MarkdownView, App, TAbstractFile, TFolder } from 'obsidian'; +import { TFile, setIcon, Menu, MarkdownView, App, TAbstractFile, TFolder, setTooltip } from 'obsidian'; import { OutlineData, FileInfo, FileStatus } from 'src/main'; import { MultipleNotesOutlineViewType, Category } from './fileView'; import { getFileInfo, getOutline } from 'src/getOutline'; -import { addFlag, changeNoteTitleBackgroundColor, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag } from 'src/util'; +import { addFlag, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag } from 'src/util'; export function constructNoteDOM (files:TAbstractFile[], status: FileStatus[], info: FileInfo[], data:OutlineData[][], @@ -155,7 +155,20 @@ export function constructNoteDOM (files:TAbstractFile[], status: FileStatus[], i }, false ); + + //hover preview + noteTitleEl.addEventListener('mouseover', (event: MouseEvent) => { + this.app.workspace.trigger('hover-link', { + event, + source: MultipleNotesOutlineViewType, + hoverParent: parentEl, // rootEl→parentElにした + targetEl: noteTitleEl, + linktext: files[si].path, + }); + }); + } + // コンテキストメニュー noteTitleEl.addEventListener( @@ -244,17 +257,22 @@ export function constructNoteDOM (files:TAbstractFile[], status: FileStatus[], i constructOutlineDOM.call(this, files[si], info[si], data[si], noteChildrenEl, category); } - // 折りたたまれていれば子要素を非表示にする + // 折りたたまれているのは以下のケース + // collpaseAllが有効な場合、 + // ファイルビューで各カテゴリ(メイン/アウトゴーイング/自カテゴリ)に重複がある場合、 + // relatedFilesで折りたたみフラグが立っている場合 if ((this.collapseAll) || (status[si].duplicated.main && this.settings.showFiles.main) || (status[si].duplicated.outgoing && this.settings.showFiles.outgoing) || (status[si].duplicated.self) || - (this.settings.relatedFiles?.[srcFile.path]?.[files[si].path]?.fold) && !parentEl.classList.contains("mod-root")) { + (this.settings.relatedFiles?.[srcFile.path]?.[files[si].path]?.fold)) { noteEl.classList.add('is-collapsed'); noteCollapseIcon.classList.add('is-collapsed'); status[si].isFolded = true; noteChildrenEl.style.display = 'none'; + } else { + status[si].isFolded = false; } } } @@ -277,6 +295,159 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // extract マッチする項目があったかどうか filter関連コメントアウト // let isExtracted = false; + // propertiesの処理 + if (this.settings.showPropertyLinks && info.frontmatterLinks){ + frontmatterlinksloop: for (let j = 0; j < info.frontmatterLinks.length; j++){ + + const linkTarget = this.app.metadataCache.getFirstLinkpathDest(info.frontmatterLinks[j].link, file.path); + if (!(linkTarget instanceof TFile)) { + continue; + } + // 抽出 extract filter関連コメントアウト + // if (this.extractMode == true) { + // if (this.extractTask == true || !info[i].frontmatterLinks[j].displayText.toLowerCase().includes(this.settings.wordsToExtract.toLowerCase())){ + // continue; + // } else { + // isExtracted = true; + // } + // } + + // hideLinksBetweenRelatedFilesの設定に従って重複除外 + if (this.settings.hideLinksBetweenRelatedFiles == 'mainOnly'){ + if (category == 'main'){ + continue; + } + if (linkTarget.path == this.targetFiles.main?.[0].path){ + continue; + } + } + if (this.settings.hideLinksBetweenRelatedFiles == 'toMainOnly'){ + if (linkTarget.path == this.targetFiles.main?.[0].path){ + continue; + } + } + if (this.settings.hideLinksBetweenRelatedFiles == 'all'){ + for (let category in this.targetFiles){ + // info.frontmatterLinks[j].linkに一致するファイル名があるかどうかの処理。 + if (this.targetFiles[category].some( (targetfile) => targetfile.path == linkTarget.path)){ + continue frontmatterlinksloop; + } + } + } + + + + const outlineEl: HTMLElement = parentEl.createDiv("tree-item nav-file"); + const outlineTitle: HTMLElement = outlineEl.createDiv("tree-item-self is-clickable nav-file-title"); + setIcon(outlineTitle,'link'); + + outlineTitle.style.paddingLeft ='0.5em'; + outlineTitle.createDiv("tree-item-inner nav-file-title-content").setText(info.frontmatterLinks[j].displayText); + + + //クリック時 + outlineTitle.addEventListener( + "click", + // async(event: MouseEvent) => { + // event.preventDefault(); + // // if (file != this.activeFile){ + // // this.holdUpdateOnce = true; + // // } + // await this.app.workspace.getLeaf().openFile(info[i].backlinks[j]); + // const view = this.app.workspace.getActiveViewOfType(MarkdownView); + // }, + (event: MouseEvent) => { + event.preventDefault(); + this.app.workspace.getLeaf().openFile(file); + }, + false + ); + //hover preview + outlineTitle.addEventListener('mouseover', (event: MouseEvent) => { + this.app.workspace.trigger('hover-link', { + event, + source: MultipleNotesOutlineViewType, + hoverParent: parentEl, // rootEl→parentElにした + targetEl: outlineTitle, + linktext: file.path, + }); + }); + + // contextmenu + outlineTitle.addEventListener( + "contextmenu", + (event: MouseEvent) => { + const menu = new Menu(); + + //抽出 filter関連コメントアウト + // menu.addItem((item) => + // item + // .setTitle("Extract") + // .setIcon("search") + // .onClick(async ()=>{ + // this.plugin.settings.wordsToExtract = data[j].displayText; + // await this.plugin.saveSettings(); + // this.extractMode = true; + // this.extractTask = false; + // this.refreshView(false,false); + // }) + // ); + // menu.addSeparator(); + + + menu.addItem((item)=> + item + .setTitle("Open linked file") + .setIcon("links-going-out") + .onClick(async()=>{ + this.app.workspace.getLeaf().openFile(linkTarget); + }) + ); + menu.addSeparator(); + + + //新規タブに開く + menu.addItem((item)=> + item + .setTitle("Open in new tab") + .setIcon("file-plus") + .onClick(async()=> { + if (file != this.activeFile){ + this.holdUpdateOnce = true; + } + await this.app.workspace.getLeaf('tab').openFile(file); + }) + ); + //右に開く + menu.addItem((item)=> + item + .setTitle("Open to the right") + .setIcon("separator-vertical") + .onClick(async()=> { + if (file != this.activeFile){ + this.holdUpdateOnce = true; + } + await this.app.workspace.getLeaf('split').openFile(file); + }) + ); + //新規ウィンドウに開く + menu.addItem((item)=> + item + .setTitle("Open in new window") + .setIcon("box-select") + .onClick(async()=> { + if (file != this.activeFile){ + this.holdUpdateOnce = true; + } + await this.app.workspace.getLeaf('window').openFile(file); + }) + ); + + menu.showAtMouseEvent(event); + } + ); + } + } // 最新の見出しレベル let latestHeadingLevel = 0; @@ -378,27 +549,51 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // links if (element == 'link'){ // mainは設定次第でリンクは非表示(アウトゴーイングファイル群で代替できるので) - if (this.settings.hideLinksBetweenRelatedFiles != 'none'){ + // if (this.settings.hideLinksBetweenRelatedFiles != 'none'){ + // if (category == 'main'){ + // continue; + // } + // if (this.settings.hideLinksBetweenRelatedFiles == 'mainOnly'){ + + // if (category == 'backlink' && app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path == this.targetFiles.main[0].path){ + // continue; + // } + // } else { + // // hideLinksBetweenrelatedFiles == 'all' + // const linktargetpath = app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path; + // if (linktargetpath){ + // for (let category in this.targetFiles){ + // // data[j].linkに一致するファイル名があるかどうかの処理。 + // if (this.targetFiles[category].some( (targetfile) => targetfile.path == linktargetpath)){ + // continue elementloop; + // } + // } + // } + + // } + // } + if (this.settings.hideLinksBetweenRelatedFiles == 'mainOnly'){ if (category == 'main'){ continue; } - if (this.settings.hideLinksBetweenRelatedFiles == 'mainOnly'){ - - if (category == 'backlink' && app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path == this.targetFiles.main[0].path){ - continue; - } - } else { - // hideLinksBetweenrelatedFiles == 'all' - const linktargetpath = app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path; - if (linktargetpath){ - for (let category in this.targetFiles){ - // data[j].linkに一致するファイル名があるかどうかの処理。 - if (this.targetFiles[category].some( (targetfile) => targetfile.path == linktargetpath)){ - continue elementloop; - } + if (this.app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path == this.targetFiles.main?.[0].path){ + continue; + } + } + if (this.settings.hideLinksBetweenRelatedFiles == 'toMainOnly'){ + if (this.app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path == this.targetFiles.main?.[0].path){ + continue; + } + } + if (this.settings.hideLinksBetweenRelatedFiles == 'all'){ + const linkTargetPath = this.app.metadataCache.getFirstLinkpathDest(data[j].link, file.path)?.path; + if (linkTargetPath){ + for (let category in this.targetFiles){ + // data[j].linkに一致するファイル名があるかどうかの処理。 + if (this.targetFiles[category].some( (targetfile) => targetfile.path == linkTargetPath)){ + continue elementloop; } } - } } } @@ -557,10 +752,12 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat } // 空行を除去 previewText2 = previewText2.replace(/\n$|\n(?=\n)/g,''); - outlineTitle.ariaLabel = previewText2; + setTooltip(outlineTitle, previewText2, {classes:['daily-note-preview']}); + + // outlineTitle.ariaLabel = previewText2; outlineTitle.dataset.tooltipPosition = this.settings.tooltipPreviewDirection; - outlineTitle.setAttribute('aria-label-delay','10'); - outlineTitle.setAttribute('aria-label-classes','daily-note-preview'); + outlineTitle.setAttribute('data-tooltip-delay','10'); + // outlineTitle.setAttribute('aria-label-classes','daily-note-preview'); } //クリック時 diff --git a/src/drawUI.ts b/src/drawUI.ts index 016ce0f..bdad7e0 100644 --- a/src/drawUI.ts +++ b/src/drawUI.ts @@ -4,8 +4,6 @@ import MultipleNotesOutlinePlugin from "./main"; import { setIcon, TFile, Menu } from 'obsidian'; -import { ModalExtract } from 'src/modalExtract' - // 操作アイコン部分を描画 export function drawUI(): void { @@ -288,6 +286,34 @@ function uiToggleHeading (parentEl:HTMLElement):void{ this.refreshView(false,false); } ); + navActionButton.addEventListener( + "contextmenu", + (event: MouseEvent) => { + const menu = new Menu(); + menu.addItem( (item)=> + item.setTitle('heading level to display')); + + for (let i = 0; i<6; i++){ + const dispText = (i == 0)? "H1": "H1 - H"+(i+1).toString(); + menu.addItem((item)=> + item + .setTitle(dispText) + .onClick(async()=>{ + for(let j =0; j<6; j++){ + if (j <= i){ + this.settings.headingLevel[j] = true; + } else { + this.settings.headingLevel[j] = false; + } + } + await this.plugin.saveSettings(); + this.refreshView(false,false); + }) + ) + } + menu.showAtMouseEvent(event); + } + ) } function uiToggleLink (parentEl:HTMLElement):void{ diff --git a/src/fileView.ts b/src/fileView.ts index e6795ff..a2dbe65 100644 --- a/src/fileView.ts +++ b/src/fileView.ts @@ -7,7 +7,7 @@ import MultipleNotesOutlinePlugin, { MultipleNotesOutlineSettings, OutlineData, import { getBacklinkFiles, getOutgoingLinkFiles } from 'src/getTargetFiles'; import { initFileStatus, getFileInfo, getOutline } from 'src/getOutline' -import { addFlag, changeNoteTitleBackgroundColor, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag, sortFileOrder } from 'src/util'; +import { addFlag, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag, sortFileOrder, getTheme, setNoteTitleBackgroundColor } from 'src/util'; import { drawUI } from 'src/drawUI'; import { constructNoteDOM, constructOutlineDOM } from 'src/constructDOM'; @@ -109,6 +109,9 @@ export class MultipleNotesOutlineView extends ItemView { // viewタイプ DOMのidに付加 viewType: string = 'MNOfileview'; + // 現在のライトモード/ダークモードの状態 + theme: 'light' | 'dark'; + constructor( leaf: WorkspaceLeaf, plugin: MultipleNotesOutlinePlugin, @@ -201,6 +204,16 @@ export class MultipleNotesOutlineView extends ItemView { debouncerRequestRefresh.call(this); } })); + + this.registerEvent(this.app.workspace.on('css-change', (e)=>{ + + const newTheme = getTheme(); + if (newTheme !== this.theme){ + this.theme = newTheme; + setNoteTitleBackgroundColor(this.theme, this.settings); + } + + })); } async onClose(){ @@ -211,17 +224,21 @@ export class MultipleNotesOutlineView extends ItemView { await this.bootDelay(); //起動直後に少しウエイト(DNOの時はこれがないとデータ取得に失敗していた) this.collapseAll = this.settings.collapseAllAtStartup; + // ノートタイトル背景色の設定 + this.theme = getTheme(); + setNoteTitleBackgroundColor(this.theme, this.settings); + this.activeFile = this.app.workspace.getActiveFile(); if (this.activeFile){ this.targetFiles.main[0]= this.activeFile; this.refreshView(true, true); } else { - console.log("failed to get active file"); + console.log("Multiple Notes Outline: failed to get active file"); } } private async bootDelay(): Promise { - return new Promise(resolve => { setTimeout(resolve, 2000);}); + return new Promise(resolve => { setTimeout(resolve, 500);}); } // ファイル修正、削除、リネームなどの際の自動更新 @@ -313,10 +330,7 @@ export class MultipleNotesOutlineView extends ItemView { async refreshView(flagGetTarget:boolean, flagGetOutline:boolean){ // 描画所要時間を測定 - // const startTime = performance.now(); - - // ファイル名背景色を再設定 - changeNoteTitleBackgroundColor(this.plugin.settings); + const startTime = performance.now(); // スクロール位置の取得 const containerEl = document.getElementById('MNOfileview-listcontainer'); @@ -332,7 +346,7 @@ export class MultipleNotesOutlineView extends ItemView { [this.fileStatus.main, this.fileInfo.main,this.outlineData.main] = await this.getOutlines(this.targetFiles.main, this.fileStatus.main); // 現ファイル情報をもとにアウトゴーイングリンク/バックリンク先のファイルを取得 - this.targetFiles.outgoing = getOutgoingLinkFiles(this.app, this.targetFiles.main[0], this.outlineData.main[0]); + this.targetFiles.outgoing = getOutgoingLinkFiles(this.app, this.targetFiles.main[0], this.fileInfo.main[0], this.outlineData.main[0]); this.fileStatus.outgoing = initFileStatus(this.targetFiles.outgoing); this.fileOrder.outgoing = [...Array(this.targetFiles.outgoing.length)].map((_, i) => i); @@ -357,21 +371,21 @@ export class MultipleNotesOutlineView extends ItemView { sortFileOrder(this.fileOrder.backlink, this.targetFiles.backlink, this.fileStatus.backlink, this.fileInfo.backlink, this.settings); } - // const midTime = performance.now(); - // if (this.settings.showDebugInfo){ - // console.log ('time required to get outlines, file view: ',this.targetFiles.main[0], midTime - startTime); - // } + const midTime = performance.now(); + if (this.settings.showDebugInfo){ + console.log('Multiple Notes Outline: time required to get outlines, file view: ',this.targetFiles.main[0], midTime - startTime); + } drawUI.call(this); this.drawOutline(previousY); // 描画所要時間を測定 - // const endTime = performance.now(); - // if (this.settings.showDebugInfo){ - // console.log ('time required to draw outlines, file view: ',this.targetFiles.main[0], endTime - midTime, previousY); + const endTime = performance.now(); + if (this.settings.showDebugInfo){ + console.log('Multiple Notes Outline: time required to draw outlines, file view: ',this.targetFiles.main[0], endTime - midTime, previousY); - // console.log ('time required to refresh view, file view',this.targetFiles.main[0].path, endTime - startTime); - // } + console.log('Multiple Notes Outline: time required to refresh view, file view',this.targetFiles.main[0].path, endTime - startTime); + } } //ファイル情報、アウトライン情報を作成・取得 diff --git a/src/folderView.ts b/src/folderView.ts index d5d90ce..3b79ff2 100644 --- a/src/folderView.ts +++ b/src/folderView.ts @@ -5,10 +5,9 @@ import { ItemView, WorkspaceLeaf, TFile, TAbstractFile} from 'obsidian' import MultipleNotesOutlinePlugin, { MultipleNotesOutlineSettings, OutlineData, FileInfo, FileStatus } from 'src/main'; -import { ModalExtract } from 'src/modalExtract' import { getBacklinkFiles, getOutgoingLinkFiles } from 'src/getTargetFiles'; import { initFileStatus, getFileInfo, getOutline } from 'src/getOutline' -import { addFlag, changeNoteTitleBackgroundColor, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag, sortFileOrder } from 'src/util'; +import { addFlag, checkFlag, cleanRelatedFiles, removeFlag, toggleFlag, sortFileOrder, getTheme, setNoteTitleBackgroundColor } from 'src/util'; import { drawUI, drawUIFolderView } from 'src/drawUI'; import { constructNoteDOM, constructOutlineDOM } from 'src/constructDOM'; @@ -75,6 +74,9 @@ export class MultipleNotesOutlineFolderView extends ItemView { // viewタイプ DOMのidに付加 viewType: string = 'MNOfolderview'; + // 現在のライトモード/ダークモードの状態 + theme: 'light' | 'dark'; + constructor( leaf: WorkspaceLeaf, plugin: MultipleNotesOutlinePlugin, @@ -141,6 +143,16 @@ export class MultipleNotesOutlineFolderView extends ItemView { this.flagRenamed = true; debouncerRequestRefresh.call(this); })); + + this.registerEvent(this.app.workspace.on('css-change', (e)=>{ + + const newTheme = getTheme(); + if (newTheme !== this.theme){ + this.theme = newTheme; + setNoteTitleBackgroundColor(this.theme, this.settings); + } + + })); } async onClose(){ @@ -150,6 +162,10 @@ export class MultipleNotesOutlineFolderView extends ItemView { private async initView() { await this.bootDelay(); //起動直後に少しウエイト(DNOの時はこれがないとデータ取得に失敗していた) this.collapseAll = this.settings.collapseAllAtStartup; + + // ノートタイトル背景色の設定 + this.theme = getTheme(); + setNoteTitleBackgroundColor(this.theme, this.settings); if (this.targetFolder){ this.refreshView(true, true); @@ -159,13 +175,13 @@ export class MultipleNotesOutlineFolderView extends ItemView { this.targetFolder = this.activeFile.parent; this.refreshView(true,true); } else { - console.log("failed to get active file"); + console.log("Multiple Notes Outline: failed to get active file"); } } } private async bootDelay(): Promise { - return new Promise(resolve => { setTimeout(resolve, 2100);}); + return new Promise(resolve => { setTimeout(resolve, 600);}); } // ファイル修正、削除、リネームなどの際の自動更新 @@ -235,10 +251,8 @@ export class MultipleNotesOutlineFolderView extends ItemView { async refreshView(flagGetTarget:boolean, flagGetOutline:boolean){ // 描画所要時間を測定 - // const startTime = performance.now(); - - // ファイル名背景色を再設定 - changeNoteTitleBackgroundColor(this.plugin.settings); + const startTime = performance.now(); + // スクロール位置の取得 const containerEl = document.getElementById('MNOfolderview-listcontainer'); @@ -254,20 +268,20 @@ export class MultipleNotesOutlineFolderView extends ItemView { } } - // const midTime = performance.now(); - // if (this.settings.showDebugInfo){ - // console.log ('time required to get outlines, folder view: ',this.targetFolder.path, midTime - startTime); - // } + const midTime = performance.now(); + if (this.settings.showDebugInfo){ + console.log ('Multiple Notes Outline: time required to get outlines, folder view: ',this.targetFolder.path, midTime - startTime); + } drawUIFolderView.call(this); this.drawOutline(previousY); // 描画所要時間を測定 - // const endTime = performance.now(); - // if (this.settings.showDebugInfo){ - // console.log ('time required to draw outlines, folder view: ',this.targetFolder.path, endTime - midTime); - // console.log ('time required to refresh view, folder view: ',this.targetFolder.path, endTime - startTime); - // } + const endTime = performance.now(); + if (this.settings.showDebugInfo){ + console.log ('Multiple Notes Outline: time required to draw outlines, folder view: ',this.targetFolder.path, endTime - midTime); + console.log ('Multiple Notes Outline: time required to refresh view, folder view: ',this.targetFolder.path, endTime - startTime); + } } // フォルダ内ファイルを処理(ファイル取得、ステータス初期化、情報、アウトライン取得) diff --git a/src/getOutline.ts b/src/getOutline.ts index a8fc3d3..f67b0d3 100644 --- a/src/getOutline.ts +++ b/src/getOutline.ts @@ -37,7 +37,8 @@ export async function getFileInfo(app: App, file: TFile, settings:MultipleNotesO const info:FileInfo = { lines: lines, numOfLines: lines.length, - backlinks: backlinkFiles + backlinks: backlinkFiles, + frontmatterLinks: undefined } @@ -54,6 +55,8 @@ export async function getOutline (app: App, file: TFile, status:FileStatus, info if (!cache){ return null; } + // properties(frontmatter)からリンクを取得 + info.frontmatterLinks = cache?.frontmatterLinks; // headings,links,tags を抽出 diff --git a/src/getTargetFiles.ts b/src/getTargetFiles.ts index 5ce51e4..7aea42f 100644 --- a/src/getTargetFiles.ts +++ b/src/getTargetFiles.ts @@ -1,9 +1,16 @@ import { App, TFile, TFolder } from 'obsidian'; -import { OutlineData } from 'src/main'; +import { FileInfo, OutlineData } from 'src/main'; -export function getOutgoingLinkFiles(app: App, file:TFile, cache:OutlineData[]):TFile[] | null { +export function getOutgoingLinkFiles(app: App, file:TFile, info:FileInfo, cache:OutlineData[]):TFile[] | null { let files:TFile[] =[]; + for (let i=0; i< info.frontmatterLinks?.length; i++){ + const fileobj = app.metadataCache.getFirstLinkpathDest(info.frontmatterLinks[i].link, file.path); + if (fileobj instanceof TFile){ + files.push(fileobj); + } + } + for (let i = 0; i< cache.length; i++ ){ if (cache[i].typeOfElement != 'link'){ continue; diff --git a/src/main.ts b/src/main.ts index 45f76e9..5d8a25c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -26,7 +26,7 @@ export interface MultipleNotesOutlineSettings { headingLevel: boolean[]; - hideLinksBetweenRelatedFiles: 'none' | 'mainOnly'|'all'; + hideLinksBetweenRelatedFiles: 'none' | 'mainOnly'|'toMainOnly'|'all'; allRootItems: boolean; allTasks: boolean; @@ -126,7 +126,7 @@ export interface MultipleNotesOutlineSettings { 'fold'?: boolean; 'top'?: boolean }; - } + }; }; openAtStartup:{ @@ -141,6 +141,8 @@ export interface MultipleNotesOutlineSettings { showDebugInfo: boolean; collapseAllAtStartup: boolean; + + showPropertyLinks: boolean; } // 設定項目デフォルト @@ -257,8 +259,8 @@ export const DEFAULT_SETTINGS: MultipleNotesOutlineSettings = { relatedFiles: {}, openAtStartup:{ - file: true, - folder: true + file: false, + folder: false }, collapseFolder: true, @@ -266,6 +268,8 @@ export const DEFAULT_SETTINGS: MultipleNotesOutlineSettings = { showDebugInfo: false, collapseAllAtStartup: false, + + showPropertyLinks: true, } @@ -286,6 +290,12 @@ export interface FileInfo { lines: string[]; numOfLines: number; backlinks?: TFile[]; + frontmatterLinks?: { + displayText?: string; + key: string; + link: string; + original: string; + }[]; } export interface OutlineData { @@ -349,7 +359,7 @@ export default class MultipleNotesOutlinePlugin extends Plugin { name: 'Open File View', callback: async ()=> { - this.checkFileView(); + this.checkFileView(true); } }); this.addCommand({ @@ -357,7 +367,7 @@ export default class MultipleNotesOutlinePlugin extends Plugin { name: 'Open Folder View', callback: async ()=> { - this.checkFolderView(); + this.checkFolderView(true); } }); @@ -367,7 +377,14 @@ export default class MultipleNotesOutlinePlugin extends Plugin { // } else { // this.registerEvent(this.app.workspace.on('layout-ready', this.checkAllView)); // } - this.app.workspace.onLayoutReady(this.checkAllView); + this.app.workspace.onLayoutReady(async()=>{ + if (this.settings.openAtStartup.file){ + this.checkFileView(false); + } + if (this.settings.openAtStartup.folder){ + this.checkFolderView(false); + } + }); // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new MultipleNotesOutlineSettingTab(this.app, this)); @@ -386,7 +403,7 @@ export default class MultipleNotesOutlinePlugin extends Plugin { await this.saveData(this.settings); } - checkFileView = async():Promise => { + checkFileView = async(activateView: boolean):Promise => { let [leaf] = this.app.workspace.getLeavesOfType(MultipleNotesOutlineViewType); if (!leaf) { @@ -409,11 +426,14 @@ export default class MultipleNotesOutlinePlugin extends Plugin { } await leaf.setViewState({ type: MultipleNotesOutlineViewType}); } - this.app.workspace.revealLeaf(leaf); + + if (activateView){ + this.app.workspace.revealLeaf(leaf); + } } - checkFolderView = async():Promise => { + checkFolderView = async(activateView: boolean):Promise => { let [leaf] = this.app.workspace.getLeavesOfType(MultipleNotesOutlineFolderViewType); if (!leaf) { @@ -436,16 +456,10 @@ export default class MultipleNotesOutlinePlugin extends Plugin { } await leaf.setViewState({ type: MultipleNotesOutlineFolderViewType}); } - this.app.workspace.revealLeaf(leaf); + if (activateView){ + this.app.workspace.revealLeaf(leaf); + } } - checkAllView = async():Promise =>{ - if (this.settings.openAtStartup.file){ - this.checkFileView(); - } - if (this.settings.openAtStartup.folder){ - this.checkFolderView(); - } - } - + } \ No newline at end of file diff --git a/src/setting.ts b/src/setting.ts index f354f8e..507d98c 100644 --- a/src/setting.ts +++ b/src/setting.ts @@ -317,12 +317,13 @@ export class MultipleNotesOutlineSettingTab extends PluginSettingTab { }); new Setting(containerEl) - .setName("Hide links between related files") - .setDesc("main only: hide links from the main file to outgoing files and links from backlink files to the main file. all: hide links between main/outgoing/backlink files.") + .setName("Hide link elements between displayed files") + .setDesc("main file only: hide links between the main file and other displayed. other files to main file only: hide links from other displayed files to the main file. all: hide links between all displayed files.") .addDropdown((dropdown) => { dropdown .addOption("none", "none") - .addOption("mainOnly","main only") + .addOption("mainOnly","main file only") + .addOption("toMainOnly","other files to main file only") .addOption("all","all") .setValue(this.plugin.settings.hideLinksBetweenRelatedFiles) .onChange(async (value: 'none'|'mainOnly'|'all') => { @@ -1263,18 +1264,18 @@ export class MultipleNotesOutlineSettingTab extends PluginSettingTab { }); - // new Setting(containerEl) - // .setName("show debug information") - // .setDesc("display debug information in the console") - // .addToggle((toggle) => { - // toggle - // .setValue(this.plugin.settings.showDebugInfo) - // .onChange(async (value) => { - // this.plugin.settings.showDebugInfo = value; - // this.display(); - // await this.plugin.saveSettings(); - // }) - // }); + new Setting(containerEl) + .setName("show debug information") + .setDesc("display debug information in the console") + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.showDebugInfo) + .onChange(async (value) => { + this.plugin.settings.showDebugInfo = value; + this.display(); + await this.plugin.saveSettings(); + }) + }); } diff --git a/src/util.ts b/src/util.ts index bea5811..662478d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -42,10 +42,14 @@ export function toggleFlag(srcFile:TAbstractFile, dstFile:TAbstractFile, flag: ' } } +// テーマ(ライト/ダーク)を取得 +export function getTheme():'light'|'dark' { + const theme = (app.vault.config?.theme === 'moonstone')? 'light':'dark'; + return theme; +} -// ファイルタイトルの背景色を指定(css変数を設定値に基づいて変更) ※ファイルエクスプローラのフォルダの背景色に相当 -export function changeNoteTitleBackgroundColor(settings: MultipleNotesOutlineSettings){ - const theme = document.getElementsByTagName('body')[0].classList.contains('theme-light') ? 'light' : 'dark'; +// ファイルタイトルの背景色を指定ver2(css変数を設定値に基づいて変更) ※ファイルエクスプローラのフォルダの背景色に相当 +export function setNoteTitleBackgroundColor(theme: 'light'|'dark', settings: MultipleNotesOutlineSettings){ switch(settings.noteTitleBackgroundColor){ case 'none': break; @@ -60,6 +64,23 @@ export function changeNoteTitleBackgroundColor(settings: MultipleNotesOutlineSet } } +// ファイルタイトルの背景色を指定(css変数を設定値に基づいて変更) ※ファイルエクスプローラのフォルダの背景色に相当 +// export function changeNoteTitleBackgroundColor(settings: MultipleNotesOutlineSettings){ +// const theme = document.getElementsByTagName('body')[0].classList.contains('theme-light') ? 'light' : 'dark'; +// switch(settings.noteTitleBackgroundColor){ +// case 'none': +// break; +// case 'custom': +// document.getElementsByTagName('body')[0].style.setProperty("--MNO-filetitle-background", settings.customNoteTitleBackgroundColor[theme]); +// document.getElementsByTagName('body')[0].style.setProperty("--MNO-filetitle-background-hover", settings.customNoteTitleBackgroundColorHover[theme]); +// break; +// default: +// document.getElementsByTagName('body')[0].style.setProperty("--MNO-filetitle-background", FILE_TITLE_BACKGROUND_COLOR[settings.noteTitleBackgroundColor][theme]); +// document.getElementsByTagName('body')[0].style.setProperty("--MNO-filetitle-background-hover", FILE_TITLE_BACKGROUND_COLOR_HOVER[settings.noteTitleBackgroundColor][theme]); +// break; +// } +// } + // ファイル順ソート export function sortFileOrder( order: number[], files: TAbstractFile[], status: FileStatus[], info: FileInfo[], settings: MultipleNotesOutlineSettings):void {