From 8095f0f6356dbc426d8df9374c765a6f53179682 Mon Sep 17 00:00:00 2001 From: iiz00 Date: Mon, 4 Mar 2024 09:19:46 +0900 Subject: [PATCH] Support for canvas and List Callouts, other improvements --- README.md | 15 +++ manifest.json | 4 +- package.json | 2 +- src/FavAndRecent.ts | 13 ++- src/constructDOM.ts | 265 ++++++++++++++++++++++++++------------------ src/drawUI.ts | 8 +- src/fileView.ts | 16 ++- src/folderView.ts | 4 + src/getOutline.ts | 62 ++++++++++- src/main.ts | 49 +++++++- src/setting.ts | 44 ++++++++ src/util.ts | 36 ++++++ styles.css | 3 +- versions.json | 3 +- 14 files changed, 396 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 0245a5c..ca05e96 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,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.5.0 + - New function + - Canvas support + - When a canvas file is selected, notes in the canvas file are displayed as link elements and cards are displayed as list itmes in the outline. So when a canvas file is selected as the main target file in File view, the outlines of notes in the canvas file can also be displayed at once. + - Support for List Callouts plugin + - List items marked by List Callouts plugin by @mgmeyers are displayed with coloring. + - Improvements + - Increased the maximum width of tooltip preview + - Embedded links are now treated as link outline elements + - Added setting to hide outgoing links in outgoing link files section and backlinks in backlink files section (Settings -> File View -> Hide minor 2 hop links) + - You can now specify whether to save the history sequentially (Settings -> Recent/favorites -> Save recent view). + - Turning this off may cause some history to be lost when Obsidian exits, but will reduce the frequency of data.json rewrites. + - View history is now synchronized across devices. This requires Obsidian v1.5.8 or later. + - Changed + - Setting changes made by clicking UI icons (headings, links, list items, and backlinks) are now not saved sequentially. This reduces the frequency of data.json rewriting, although some of the history of these changes may be lost when Obsidian exits. If you switch settings from the settings screen, the settings are saved each time. - 0.4.0 - Improvements - You can now choose whether to open the location of the element or the linked file when you click on a link element. diff --git a/manifest.json b/manifest.json index d234075..eda98d2 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "id": "multiple-notes-outline", "name": "Multiple Notes Outline", - "version": "0.4.0", - "minAppVersion": "1.3.0", + "version": "0.5.0", + "minAppVersion": "1.5.8", "description": "Add custom views which show outlines of multiple notes with headings, links, tags and list items.", "author": "iiz", "authorUrl": "https://github.com/iiz00", diff --git a/package.json b/package.json index 7508e20..d27878a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multiple-notes-outline", - "version": "0.4.0", + "version": "0.5.0", "description": "Add custom views which shows outline of multiple notes at once", "main": "main.js", "scripts": { diff --git a/src/FavAndRecent.ts b/src/FavAndRecent.ts index 26bf0ca..ae8c0a2 100644 --- a/src/FavAndRecent.ts +++ b/src/FavAndRecent.ts @@ -16,15 +16,18 @@ export async function updateFavAndRecent(targetPath: string, category: 'file'|'f this.settings.recent[category].pop(); } } - await this.plugin.saveSettings(); + if (this.settings.saveRecentView || this.suggestType =='favorite'){ + await this.plugin.saveSettings(); + } } export async function deleteFavAndRecent(targetPath: string, category: 'file'|'folder', suggestType: 'recent'|'favorite'):Promise { this.settings[suggestType][category] = this.settings[suggestType][category].filter( (value: string) => targetPath !== value ); - - await this.plugin.saveSettings(); + if (this.settings.saveRecentView || this.suggestType =='favorite'){ + await this.plugin.saveSettings(); + } } export class ModalJump extends SuggestModal{ @@ -89,7 +92,9 @@ export class ModalJump extends SuggestModal{ async onChooseSuggestion(item: string, evt: MouseEvent | KeyboardEvent) { updateFavAndRecent.call(this.view, item, this.category, this.suggestType); - await this.view.plugin.saveSettings(); + if (this.view.settings.saveRecentView || this.suggestType == 'favorite'){ + await this.view.plugin.saveSettings(); + } this.onSubmit(item); } diff --git a/src/constructDOM.ts b/src/constructDOM.ts index 748f24c..aeb186a 100644 --- a/src/constructDOM.ts +++ b/src/constructDOM.ts @@ -3,7 +3,7 @@ import { TFile, setIcon, Menu, MarkdownView, App, TAbstractFile, TFolder, setToo import { OutlineData, FileInfo, FileStatus } from 'src/main'; import { MultipleNotesOutlineViewType, Category } from './fileView'; import { getFileInfo, getOutline } from 'src/getOutline'; -import { addFlag, checkFlag, cleanRelatedFiles, getSubpathPosition, removeFlag, toggleFlag } from 'src/util'; +import { addFlag, checkFlag, checkListCallouts, cleanRelatedFiles, getSubpathPosition, removeFlag, shouldDisplayListItem, toggleFlag } from 'src/util'; import { deleteFavAndRecent, updateFavAndRecent } from './FavAndRecent'; @@ -338,8 +338,10 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // extract マッチする項目があったかどうか filter関連コメントアウト // let isExtracted = false; + const isCanvas = Boolean(file.extension == 'canvas'); + // propertiesの処理 - if (this.settings.showPropertyLinks && info.frontmatterLinks){ + if (this.settings.showPropertyLinks && info.frontmatterLinks && !(category =='outgoing' && this.settings.hideMinor2hopLink)){ frontmatterlinksloop: for (let j = 0; j < info.frontmatterLinks.length; j++){ const linkTarget = this.app.metadataCache.getFirstLinkpathDest(parseLinktext(info.frontmatterLinks[j].link).path, file.path); @@ -577,6 +579,7 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // 現アウトライン要素の種別を取得 const element = data[j].typeOfElement; + let displayText = data[j].displayText; const linkTarget = (element !== 'link')? null : this.app.metadataCache.getFirstLinkpathDest(parseLinktext(data[j]?.link).path, file.path); const linkSubpath = (!linkTarget)? undefined : parseLinktext(data[j]?.link).subpath; @@ -690,6 +693,9 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat } } } + if (this.settings.hideMinor2hopLink && category == 'outgoing'){ + continue; + } } // tags @@ -698,19 +704,26 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // listItems + let calloutsIndex = undefined; if (element == 'listItems'){ - // 完了タスク非表示設定であれば完了タスクはスキップ - if (this.settings.hideCompletedTasks == true && data[j].task =='x'){ - continue; - // 非タスク非表示設定であれば非タスクはスキップ - } else if (this.settings.taskOnly == true && data[j].task === void 0){ + if (this.settings.dispListCallouts){ + calloutsIndex = checkListCallouts(displayText, this.app.plugins.plugins?.['obsidian-list-callouts']?.settings); + } + if (shouldDisplayListItem(data[j], this.settings, calloutsIndex) == false){ continue; - // 非タスクの通常リストアイテム、または タスクは全表示の設定で無ければレベルに応じてスキップ - } else if (this.settings.allTasks == false || data[j].task === void 0){ - if ( (data[j].level == 2) || (data[j].level ==1 && this.settings.allRootItems == false)){ - continue; - } } + // // 完了タスク非表示設定であれば完了タスクはスキップ + // if (this.settings.hideCompletedTasks == true && data[j].task =='x'){ + // continue; + // // 非タスク非表示設定であれば非タスクはスキップ + // } else if (this.settings.taskOnly == true && data[j].task === void 0){ + // continue; + // // 非タスクの通常リストアイテム、または タスクは全表示の設定で無ければレベルに応じてスキップ + // } else if (this.settings.allTasks == false || data[j].task === void 0){ + // if ( (data[j].level == 2) || (data[j].level ==1 && this.settings.allRootItems == false)){ + // continue; + // } + // } } @@ -745,7 +758,30 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat this.settings.customIcon.task : this.settings.icon.task); } } - + + // リストに対する処理タスクだった場合アイコン上書き + if (element =='listItems'){ + //タスクだった場合アイコン上書き + if (data[j].task !== void 0){ + if (data[j].task == 'x'){ + setIcon(outlineTitle, this.settings.icon.taskDone == 'custom' ? + this.settings.customIcon.taskDone : this.settings.icon.taskDone); + } else { + setIcon(outlineTitle, this.settings.icon.task =='custom' ? + this.settings.customIcon.task : this.settings.icon.task); + } + } + + //リストコールアウトへの対応 + if (typeof calloutsIndex =='number') { + outlineTitle.style.backgroundColor =`RGBA(${this.app.plugins.plugins['obsidian-list-callouts'].settings[calloutsIndex].color},0.15)`; + if (this.app.plugins.plugins['obsidian-list-callouts'].settings[calloutsIndex].hasOwnProperty('icon') && data[j].task === void 0){ + setIcon(outlineTitle, this.app.plugins.plugins['obsidian-list-callouts'].settings[calloutsIndex].icon); + displayText = displayText.replace(/^.\s/,''); + } + } + } + //prefix let prefix = this.settings.prefix[element]; if ( element == 'heading'){ @@ -771,7 +807,7 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat indent = indent + (additionalIndent > 0 ? additionalIndent : 0); } // リンクが前のエレメントと同じ行だった場合インデント付加 - if (element =='link' && data[j].position.start.line == data[j-1]?.position.start.line){ + if (!isCanvas && element =='link' && data[j].position.start.line == data[j-1]?.position.start.line){ indent = indent + 1.5; } @@ -785,12 +821,12 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat } } - outlineTitle.createDiv("tree-item-inner nav-file-title-content").setText(prefix + data[j].displayText); + outlineTitle.createDiv("tree-item-inner nav-file-title-content").setText(prefix + displayText); // インラインプレビュー // リンクとタグは、アウトライン要素のあとに文字列が続く場合その行をプレビュー、そうでなければ次の行をプレビュー - if (this.settings.inlinePreview) { + if (!isCanvas && this.settings.inlinePreview ) { let previewText: string =''; if ((element == 'link' || element == 'tag') && data[j].position.end.col < info.lines[ data[j].position.start.line ].length){ @@ -806,50 +842,60 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat // ツールチッププレビュー // その要素の行から次の要素の前までをプレビュー if (this.settings.tooltipPreview){ - let previewText2:string =''; - // まず次の表示要素の引数を特定 - let endLine:number = info.numOfLines - 1; //初期値は文章末 - let k = j +1; // 現在のアウトライン引数+1からループ開始 - endpreviewloop: while (k< data.length) { - //表示するエレメントタイプであれば行を取得してループを打ち切る - if (this.settings.showElements[data[k].typeOfElement]){ - //ただし各種の実際には非表示となる条件を満たしていたら打ち切らない - // リストの設定による非表示 - if (data[k].typeOfElement == 'listItems' && - ( data[k].level >=2 || - ((this.settings.allRootItems == false && data[k].level == 1) && (this.settings.allTasks == false || data[k].task === void 0)) || - (this.settings.taskOnly && data[k].task === void 0) || - (this.settings.hideCompletedTasks && data[k].task == 'x'))){ - k++; - continue; - // 見出しのレベルによる非表示 - } else if (data[k].typeOfElement == 'heading' && - this.settings.headingLevel[data[k].level - 1] == false){ - k++; - continue; - // simple filterによる非表示 - } else { - for (const value of this.settings.wordsToIgnore[data[k].typeOfElement]){ - if( (value) && data[k].displayText.includes(value)){ - k++; - continue endpreviewloop; - } + if (!isCanvas){ + let previewText2:string =''; + + // まず次の表示要素の引数を特定 + let endLine:number = info.numOfLines - 1; //初期値は文章末 + let k = j +1; // 現在のアウトライン引数+1からループ開始 + endpreviewloop: while (k< data.length) { + //表示するエレメントタイプであれば行を取得してループを打ち切る + if (this.settings.showElements[data[k].typeOfElement]){ + //ただし各種の実際には非表示となる条件を満たしていたら打ち切らない + // リストの設定による非表示 + if (data[k].typeOfElement == 'listItems' && + ( data[k].level >=2 || + ((this.settings.allRootItems == false && data[k].level == 1) && (this.settings.allTasks == false || data[k].task === void 0)) || + (this.settings.taskOnly && data[k].task === void 0) || + (this.settings.hideCompletedTasks && data[k].task == 'x'))){ + k++; + continue; + // 見出しのレベルによる非表示 + } else if (data[k].typeOfElement == 'heading' && + this.settings.headingLevel[data[k].level - 1] == false){ + k++; + continue; + // simple filterによる非表示 + } else { + for (const value of this.settings.wordsToIgnore[data[k].typeOfElement]){ + if( (value) && data[k].displayText.includes(value)){ + k++; + continue endpreviewloop; + } + } + endLine = data[k].position.start.line -1; + break; } - endLine = data[k].position.start.line -1; - break; } + k++; + } + for (let l = data[j].position.start.line; l <= endLine; l++){ + previewText2 = previewText2 + info.lines[l] +'\n'; + } + // 空行を除去 + previewText2 = previewText2.replace(/\n$|\n(?=\n)/g,''); + setTooltip(outlineTitle, previewText2, {classes:['MNO-preview']}); + + outlineTitle.dataset.tooltipPosition = this.settings.tooltipPreviewDirection; + outlineTitle.setAttribute('data-tooltip-delay','10'); + } else { + //canvas だった場合カードにプレビューを付加 + if (data[j].typeOfElement =='listItems'){ + setTooltip(outlineTitle, data[j].displayText, {classes:['MNO-preview']}); + outlineTitle.dataset.tooltipPosition = this.settings.tooltipPreviewDirection; + outlineTitle.setAttribute('data-tooltip-delay','10'); } - k++; - } - for (let l = data[j].position.start.line; l <= endLine; l++){ - previewText2 = previewText2 + info.lines[l] +'\n'; } - // 空行を除去 - previewText2 = previewText2.replace(/\n$|\n(?=\n)/g,''); - setTooltip(outlineTitle, previewText2, {classes:['daily-note-preview']}); - - outlineTitle.dataset.tooltipPosition = this.settings.tooltipPreviewDirection; - outlineTitle.setAttribute('data-tooltip-delay','10'); } //クリック時 @@ -866,7 +912,7 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat const subpathPosition = getSubpathPosition(this.app, linkTarget, linkSubpath); scrollToElement(subpathPosition.start?.line, 0, this.app); } - } else { + } else if (!isCanvas) { if (file != this.activeFile){ this.holdUpdateOnce = true; } @@ -900,14 +946,16 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat state: posInfo }); } else { - this.app.workspace.trigger('hover-link', { - event, - source: MultipleNotesOutlineViewType, - hoverParent: parentEl, // rootEl→parentElにした - targetEl: outlineTitle, - linktext: file.path, - state:{scroll: data[j].position.start.line} - }); + if (!isCanvas){ + this.app.workspace.trigger('hover-link', { + event, + source: MultipleNotesOutlineViewType, + hoverParent: parentEl, // rootEl→parentElにした + targetEl: outlineTitle, + linktext: file.path, + state:{scroll: data[j].position.start.line} + }); + } } }); @@ -1013,53 +1061,56 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat .setTitle("Search this tag") .setIcon("search") .onClick(async()=>{ - const searchString = "tag: #"+ data[j].displayText; + const searchString = "tag: #"+ displayText; this.app.internalPlugins.plugins["global-search"]?.instance.openGlobalSearch(searchString); }) ); menu.addSeparator(); } + // 以下はcanvasでは非表示 + if (!isCanvas){ - //新規タブに開く - 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); - scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); - - }) - ); - //右に開く - 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); - scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); - }) - ); - //新規ウィンドウに開く - menu.addItem((item)=> - item - .setTitle("Open in new window") - .setIcon("scan") - .onClick(async()=> { - if (file != this.activeFile){ - this.holdUpdateOnce = true; - } - await this.app.workspace.openPopoutLeaf({size:{width:this.settings.popoutSize.width,height:this.settings.popoutSize.height}}).openFile(file); - scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); - }) - ); + //新規タブに開く + 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); + scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); + + }) + ); + //右に開く + 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); + scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); + }) + ); + //新規ウィンドウに開く + menu.addItem((item)=> + item + .setTitle("Open in new window") + .setIcon("scan") + .onClick(async()=> { + if (file != this.activeFile){ + this.holdUpdateOnce = true; + } + await this.app.workspace.openPopoutLeaf({size:{width:this.settings.popoutSize.width,height:this.settings.popoutSize.height}}).openFile(file); + scrollToElement(data[j].position.start.line, data[j].position.start.col, this.app); + }) + ); + } menu.showAtMouseEvent(event); } @@ -1099,7 +1150,7 @@ export function constructOutlineDOM (file:TFile, info:FileInfo, data: OutlineDat } // main以外の場合、backlink filesの処理 - if (category =='main' || this.settings.showBacklinks == false || !info.backlinks){ + if (category =='main' || this.settings.showBacklinks == false || !info.backlinks || (category =='backlink' && this.settings.hideMinor2hopLink)){ return; } backlinkfileloop: for (let i = 0; i < info.backlinks?.length; i++){ diff --git a/src/drawUI.ts b/src/drawUI.ts index bba603c..5c5cddd 100644 --- a/src/drawUI.ts +++ b/src/drawUI.ts @@ -409,7 +409,7 @@ function uiToggleHeading (parentEl:HTMLElement):void{ "click", async (event:MouseEvent) =>{ this.settings.showElements.heading = !this.settings.showElements.heading; - await this.plugin.saveSettings(); + // await this.plugin.saveSettings(); this.refreshView(false,false); } ); @@ -454,7 +454,7 @@ function uiToggleLink (parentEl:HTMLElement):void{ "click", async (event:MouseEvent) =>{ this.settings.showElements.link = !this.settings.showElements.link; - await this.plugin.saveSettings(); + // await this.plugin.saveSettings(); this.refreshView(false,false); } ); @@ -471,7 +471,7 @@ function uiToggleListItems (parentEl:HTMLElement):void{ "click", async (event:MouseEvent) =>{ this.settings.showElements.listItems = !this.settings.showElements.listItems; - await this.plugin.saveSettings(); + // await this.plugin.saveSettings(); this.refreshView(false,false); } ); @@ -489,7 +489,7 @@ function uiToggleBacklinks (parentEl:HTMLElement):void{ "click", async (event:MouseEvent) =>{ this.settings.showBacklinks = !this.settings.showBacklinks; - await this.plugin.saveSettings(); + // await this.plugin.saveSettings(); this.refreshView(false,false); } ); diff --git a/src/fileView.ts b/src/fileView.ts index b23b709..cda83ca 100644 --- a/src/fileView.ts +++ b/src/fileView.ts @@ -20,7 +20,7 @@ export type Category = 'main'|'outgoing'|'backlink'; export class MultipleNotesOutlineView extends ItemView { - plugin: MultipleNotesOutlinePlugin; + plugin: MultipleNotesOutlinePlugin; settings:MultipleNotesOutlineSettings; activeFile: TFile; @@ -128,15 +128,15 @@ export class MultipleNotesOutlineView extends ItemView { this.plugin = plugin; this.settings = settings; } - + getViewType(): string { return MultipleNotesOutlineViewType; } - + getDisplayText(): string { return 'MNO - file view'; } - + getIcon(): string { return 'files'; } @@ -161,6 +161,10 @@ export class MultipleNotesOutlineView extends ItemView { // } } + updateSettings(){ + this.settings = this.plugin.settings; + } + async onClose(){ // Nothin to clean up } @@ -212,6 +216,8 @@ export class MultipleNotesOutlineView extends ItemView { if (!this.settings.autoupdateFileView || (this.settings.suspendUpdateByClickingView && this.holdUpdateOnce) || this.pinnedMode == true){ // autoupdateがfalseか、 viewからの直接の遷移の場合更新しない設定であれば更新をスキップ + } else if (this.targetFiles.main[0].extension == 'canvas' && this.targetFiles.outgoing.includes(this.activeFile)){ + // canvasがメインの際、canvasに含まれるファイルを開いてもviewを更新しない } else { this.targetFiles.main[0] = this.activeFile; this.hasMainChanged = true; @@ -281,7 +287,7 @@ export class MultipleNotesOutlineView extends ItemView { } this.flagRegetTarget = true; - + debouncerRequestRefresh.call(this); } })); diff --git a/src/folderView.ts b/src/folderView.ts index 663f854..1c620ea 100644 --- a/src/folderView.ts +++ b/src/folderView.ts @@ -123,6 +123,10 @@ export class MultipleNotesOutlineFolderView extends ItemView { } + updateSettings(){ + this.settings = this.plugin.settings; + } + async onClose(){ // Nothin to clean up } diff --git a/src/getOutline.ts b/src/getOutline.ts index cb6ddce..eb811be 100644 --- a/src/getOutline.ts +++ b/src/getOutline.ts @@ -1,4 +1,4 @@ -import { App, TAbstractFile, TFile, TFolder} from 'obsidian'; +import { App, CachedMetadata, TAbstractFile, TFile, TFolder} from 'obsidian'; import MultipleNotesOutlinePlugin, { FileInfo, FileStatus, MultipleNotesOutlineSettings, OutlineData} from 'src/main'; import { getBacklinkFiles, getBacklinkFilesDataview } from 'src/getTargetFiles'; @@ -49,7 +49,6 @@ export async function getFileInfo(app: App, file: TFile, settings:MultipleNotesO } return info; } - } // 単一ファイルのアウトライン取得 @@ -58,6 +57,10 @@ export async function getOutline (app: App, file: TFile, status:FileStatus, info let data: OutlineData[] = []; const cache = app.metadataCache.getFileCache(file); + // canvasは独自のアウトラインを返す + if(file.extension == 'canvas'){ + return await getCanvasOutline(app, file); + } // .md以外は空アウトラインを返す if(file.extension != 'md'){ return data; @@ -100,6 +103,22 @@ export async function getOutline (app: App, file: TFile, status:FileStatus, info data.push(element); } } + //embedsに対応 + if (cache.hasOwnProperty("embeds")){ + for (let j=0; j< cache.embeds.length ; j++){ + const element:OutlineData = { + typeOfElement : "link", + position : cache.embeds[j].position, + //マークダウンリンク に対応 + displayText : + (cache.embeds[j].displayText =="") + ? cache.embeds[j].original.substring(1,cache.embeds[j].original.indexOf("]")) + : cache.embeds[j].displayText, + link: cache.embeds[j].link + }; + data.push(element); + } + } // console.log('check lists'); if (cache.hasOwnProperty("listItems")){ @@ -155,3 +174,42 @@ export async function getOutline (app: App, file: TFile, status:FileStatus, info }); return data; } + +// canvasについて、ノートをリンクとして、カードをリスト項目としてアウトラインを構成 +async function getCanvasOutline(app: App, file: TFile): Promise{ + let data: OutlineData[] = []; + const canvas = await app.vault.read(file); + const canvasData = JSON.parse(canvas); + if (!canvasData?.nodes){ + return data; + } + for (const node of canvasData.nodes){ + if (node.type == "file"){ + const element:OutlineData = { + typeOfElement : "link", + position : undefined, + displayText : app.vault.getAbstractFileByPath(node.file).name, + link : app.vault.getAbstractFileByPath(node.file).name + } + data.push(element); + } + if (node.type == "text"){ + const element:OutlineData = { + typeOfElement: "listItems", + position: undefined, + displayText : node.text, + level: 0, + task : undefined + } + data.push(element); + } + + } + data.sort((a,b)=>{ + if (a.typeOfElement != b.typeOfElement){ + return a.typeOfElement == 'link' ? -1: 1; + } + return (a.displayText < b.displayText ? -1: 1); + }); + return data; +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index fca90d2..20a1634 100644 --- a/src/main.ts +++ b/src/main.ts @@ -171,6 +171,9 @@ export interface MultipleNotesOutlineSettings { openLinkByClick: boolean; + hideMinor2hopLink: boolean; + dispListCallouts: boolean; + saveRecentView: boolean; } // 設定項目デフォルト @@ -324,6 +327,10 @@ export const DEFAULT_SETTINGS: MultipleNotesOutlineSettings = { openLinkByClick: false, + hideMinor2hopLink: false, + dispListCallouts: true, + + saveRecentView: true, } @@ -385,6 +392,40 @@ export const FILE_TITLE_BACKGROUND_COLOR_HOVER = { } } +export const LIST_CALLOUT_DEFAULT = +[ + { + color: "255, 214, 0", + "char": "&" + }, + { + "color": "255, 145, 0", + "char": "?" + }, + { + "color": "255, 23, 68", + "char": "!", + "icon": "lucide-alert-circle" + }, + { + "color": "124, 77, 255", + "char": "~", + "icon": "lucide-crosshair" + }, + { + "color": "0, 184, 212", + "char": "@" + }, + { + "color": "0, 200, 83", + "char": "$" + }, + { + "color": "158, 158, 158", + "char": "%" + } +] + export default class MultipleNotesOutlinePlugin extends Plugin { settings: MultipleNotesOutlineSettings; @@ -398,7 +439,7 @@ export default class MultipleNotesOutlinePlugin extends Plugin { //register custome view according to Devloper Docs this.registerView( MultipleNotesOutlineViewType, - (leaf) => (this.view =new MultipleNotesOutlineView(leaf, this, this.settings)) + (leaf) => (this.view = new MultipleNotesOutlineView(leaf, this, this.settings)) ); this.registerView( @@ -480,6 +521,12 @@ export default class MultipleNotesOutlinePlugin extends Plugin { await this.saveData(this.settings); } + async onExternalSettingsChange() { + await this.loadSettings(); + this.view.updateSettings(); + this.folderview.updateSettings(); + } + checkFileView = async(activateView: boolean):Promise => { let [leaf] = this.app.workspace.getLeavesOfType(MultipleNotesOutlineViewType); diff --git a/src/setting.ts b/src/setting.ts index f10ea19..3c6d283 100644 --- a/src/setting.ts +++ b/src/setting.ts @@ -125,6 +125,21 @@ export class MultipleNotesOutlineSettingTab extends PluginSettingTab { this.callRefreshView(false); }) }); + + new Setting(containerEl) + .setName("Show list callouts") + .setDesc("shows list items marked with List Callouts plugin") + .setClass('setting-indent') + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.dispListCallouts) + .onChange(async (value) => { + this.plugin.settings.dispListCallouts = value; + this.display(); + await this.plugin.saveSettings(); + this.callRefreshView(false); + }) + }); } new Setting(containerEl) @@ -347,6 +362,20 @@ export class MultipleNotesOutlineSettingTab extends PluginSettingTab { this.callRefreshView(false); }) }); + + new Setting(containerEl) + .setName("Hide minor 2 hop links") + .setDesc("hides outgoing links in outgoing files section and backlinks in backlink files section.(default = off)") + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.hideMinor2hopLink) + .onChange(async (value) => { + this.plugin.settings.hideMinor2hopLink = value; + this.display(); + await this.plugin.saveSettings(); + this.callRefreshView(false); + }) + }); this.containerEl.createEl("h4", { @@ -614,6 +643,21 @@ export class MultipleNotesOutlineSettingTab extends PluginSettingTab { }) }); + new Setting(containerEl) + .setName("Save recent view") + .setDesc("If disabled, the history of views displayed will not be saved sequentially. History is sometimes lost, but the frequency of data.json rewriting and subsequent synchronization is reduced.") + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.saveRecentView) + .onChange(async (value) => { + this.plugin.settings.saveRecentView = value; + this.display(); + await this.plugin.saveSettings(); + }) + }); + + + // フィルター /* filter関連コメントアウト this.containerEl.createEl("h4", { diff --git a/src/util.ts b/src/util.ts index a8f58a2..635f220 100644 --- a/src/util.ts +++ b/src/util.ts @@ -287,4 +287,40 @@ export function checkDataview (app: App):boolean { } else { return false; } +} + + +// list calloutのチェック +export function checkListCallouts (checkString: string, callouts){ + if (!callouts) return null; + for (let i=0; i