This commit is contained in:
Devon22 2025-06-24 00:11:29 +08:00
parent 7b0f8c19b9
commit 9409cafcc5
9 changed files with 158 additions and 44 deletions

79
main.ts
View file

@ -99,9 +99,9 @@ export default class GridExplorerPlugin extends Plugin {
// 註冊狀態列項目
this.statusBarItem = this.addStatusBarItem();
this.statusBarItem.onClickEvent(() => {
this.activateView();
});
// this.statusBarItem.onClickEvent(() => {
// this.activateView();
// });
// 註冊資料夾的右鍵選單
this.registerEvent(
@ -197,13 +197,10 @@ export default class GridExplorerPlugin extends Plugin {
.onClick(async () => {
const selectedText = editor.getSelection();
// 取得或啟用 GridView
const view = await this.activateView('folder','/');
const view = await this.activateView('','');
if (view instanceof GridView) {
// 設定搜尋模式和關鍵字
view.searchQuery = selectedText;
// 設定搜尋範圍 (預設搜尋所有檔案,不含媒體)
view.searchAllFiles = true;
view.searchMediaFiles = false;
// 重新渲染視圖
view.render(true); // resetScroll = true
}
@ -227,13 +224,10 @@ export default class GridExplorerPlugin extends Plugin {
.setSection?.("view")
.onClick(async () => {
// 取得或啟用 GridView
const view = await this.activateView('folder','/');
const view = await this.activateView('','');
if (view instanceof GridView) {
// 設定搜尋模式和關鍵字
view.searchQuery = `#${tagName}`;
// 設定搜尋範圍 (預設搜尋所有檔案,不含媒體)
view.searchAllFiles = true;
view.searchMediaFiles = false;
// 重新渲染視圖
view.render(true); // resetScroll = true
}
@ -241,6 +235,67 @@ export default class GridExplorerPlugin extends Plugin {
});
})
);
// 攔截所有tag點擊事件
this.registerDomEvent(document, 'click', async (evt: MouseEvent) => {
// 如果未啟用攔截所有tag點擊事件則跳過
if (!this.settings.interceptAllTagClicks) return;
// 只處理左鍵
if (evt.button !== 0) return;
// 從觸發點往上找,看是否碰到 tag 連結
const el = (evt.target as HTMLElement).closest(
'a.tag, /* 預覽模式中的 #tag */\n' +
'.tag-pane-tag, /* 標籤面板中的 tag */\n' +
'span.cm-hashtag, /* 編輯器中的 tag */\n' +
'.metadata-property[data-property-key="tags"] .multi-select-pill /* 屬性面板中的 tag */'
) as HTMLElement | null;
if (!el) return; // 不是 tag 點擊就跳過
// 取出 tag 名稱(去掉前導 #
let tagName = '';
if (el.matches('span.cm-hashtag')) {
// 編輯器模式:可能被拆成多個 span需組合
const collect = [] as string[];
let curr: HTMLElement | null = el;
// 向左收集
while (curr && curr.matches('span.cm-hashtag') && !curr.classList.contains('cm-formatting')) {
collect.unshift(curr.textContent ?? '');
curr = curr.previousElementSibling as HTMLElement | null;
if (curr && (!curr.matches('span.cm-hashtag') || curr.classList.contains('cm-formatting'))) break;
}
// 向右收集
curr = el.nextElementSibling as HTMLElement | null;
while (curr && curr.matches('span.cm-hashtag') && !curr.classList.contains('cm-formatting')) {
collect.push(curr.textContent ?? '');
curr = curr.nextElementSibling as HTMLElement | null;
}
tagName = collect.join('').trim();
} else if (el.classList.contains('tag-pane-tag')) {
// Tag Pane 中的元素,需避開計數器
const inner = el.querySelector('.tag-pane-tag-text, .tree-item-inner-text') as HTMLElement | null;
tagName = inner?.textContent?.trim() ?? '';
} else if (el.matches('.metadata-property[data-property-key="tags"] .multi-select-pill')) {
// Frontmatter/Properties view
tagName = el.textContent?.trim() ?? '';
} else {
// 預覽模式中的連結 a.tag
tagName = (el.getAttribute('data-tag') ?? el.textContent ?? '').trim();
}
tagName = tagName.replace(/^#/, '');
if (!tagName) return;
// 阻止 Obsidian 自己的處理(開搜尋窗)
evt.preventDefault();
evt.stopPropagation();
// 叫出 GridView並把搜尋字串設成這個 tag
const view = await this.activateView('', '');
if (view instanceof GridView) {
view.searchQuery = `#${tagName}`;
view.render(true); // resetScroll
}
}, true); // 用 capture可在其他 listener 前先吃到
}
async openNoteInRecentFiles(file: TFile) {
@ -300,7 +355,7 @@ export default class GridExplorerPlugin extends Plugin {
}
}
async activateView(mode = 'bookmarks', path = '') {
async activateView(mode = 'folder', path = '') {
const { workspace } = this.app;
let leaf = null;

View file

@ -1,7 +1,7 @@
{
"id": "gridexplorer",
"name": "GridExplorer",
"version": "2.4.5",
"version": "2.4.6",
"minAppVersion": "1.1.0",
"description": "Browse note files in a grid view.",
"author": "Devon22",

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "gridexplorer",
"version": "2.4.5",
"version": "2.4.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gridexplorer",
"version": "2.4.5",
"version": "2.4.6",
"license": "MIT",
"devDependencies": {
"@types/node": "^16.11.6",

View file

@ -1,6 +1,6 @@
{
"name": "gridexplorer",
"version": "2.4.5",
"version": "2.4.6",
"description": "Browse note files in a grid view.",
"main": "main.js",
"scripts": {

View file

@ -149,6 +149,7 @@ export class FileWatcher {
}, 200);
}
// 清理日期分隔線
private cleanupDateDividers(container: HTMLElement | null): void {
if (!container) return;

View file

@ -150,8 +150,11 @@ export class GridView extends ItemView {
}
}
this.sourceMode = mode;
this.sourcePath = path;
if(mode !== '') this.sourceMode = mode;
if(path !== '') this.sourcePath = path;
if(this.sourceMode === '') this.sourceMode = 'folder';
if(this.sourcePath === '') this.sourcePath = '/';
this.render(resetScroll);
// 通知 Obsidian 保存視圖狀態
this.app.workspace.requestSaveLayout();
@ -880,6 +883,13 @@ export class GridView extends ItemView {
default:
break;
}
} else if (this.searchQuery !== '' && this.searchAllFiles) {
// 顯示全域搜尋名稱
const folderNameContainer = this.containerEl.createDiv('ge-foldername-content');
folderNameContainer.createEl('span', {
text: `🔍 ${t('global_search')}`,
cls: 'ge-mode-title'
});
}
// 創建內容區域
@ -1657,21 +1667,32 @@ export class GridView extends ItemView {
tagEl.addEventListener('contextmenu', (e) => {
e.preventDefault();
e.stopPropagation();
const tagText = tag.startsWith('#') ? tag : `#${tag}`;
const menu = new Menu();
menu.addItem(item => item
.setTitle(t('add_to_search'))
.onClick(() => {
const tagText = tag.startsWith('#') ? tag : `#${tag}`;
if (this.searchQuery.includes(tagText)) {
return;
}
this.searchQuery += ` ${tagText}`;
this.searchAllFiles = true;
this.searchMediaFiles = false;
this.render(true);
return false;
})
);
//添加加入搜尋選項
if (!this.searchQuery.includes(tagText)) {
menu.addItem(item => item
.setTitle(t('add_tag_to_search'))
.setIcon('circle-plus')
.onClick(() => {
this.searchQuery += ` ${tagText}`;
this.render(true);
return false;
})
);
}
// 添加刪除標籤選項
if (this.searchQuery.includes(tagText)) {
menu.addItem(item => item
.setTitle(t('remove_tag_from_search'))
.setIcon('circle-minus')
.onClick(() => {
this.searchQuery = this.searchQuery.replace(tagText, '');
this.render(true);
return false;
})
);
}
menu.showAtPosition({
x: e.clientX,
y: e.clientY
@ -1687,8 +1708,6 @@ export class GridView extends ItemView {
return;
}
this.searchQuery = tagText;
this.searchAllFiles = true;
this.searchMediaFiles = false;
this.render(true);
return false;
});
@ -2104,12 +2123,12 @@ export class GridView extends ItemView {
for (const f of selectedFiles) {
await this.app.fileManager.trashFile(f);
}
// 清除選中狀態
this.clearSelection();
} else {
// 刪除單個檔案
await this.app.fileManager.trashFile(file);
}
// 清除選中狀態
this.clearSelection();
});
});
menu.showAtMouseEvent(event);

View file

@ -38,6 +38,7 @@ export interface GallerySettings {
dateDividerMode: string; // 日期分隔器模式none, year, month, day
showCodeBlocksInSummary: boolean; // 是否在摘要中顯示程式碼區塊
folderNoteDisplaySettings: string; // 資料夾筆記設定
interceptAllTagClicks: boolean; // 攔截所有tag點擊事件
}
// 預設設定
@ -61,7 +62,7 @@ export const DEFAULT_SETTINGS: GallerySettings = {
showBacklinksMode: true, // 預設顯示反向連結模式
showOutgoinglinksMode: false, // 預設不顯示外部連結模式
showAllFilesMode: false, // 預設不顯示所有檔案模式
showRandomNoteMode: false, // 預設不顯示隨機筆記模式
showRandomNoteMode: true, // 預設顯示隨機筆記模式
showRecentFilesMode: true, // 預設顯示最近筆記模式
showTasksMode: false, // 預設不顯示任務模式
recentFilesCount: 30, // 預設最近筆記模式顯示的筆數
@ -77,6 +78,7 @@ export const DEFAULT_SETTINGS: GallerySettings = {
dateDividerMode: 'none', // 預設不使用日期分隔器
showCodeBlocksInSummary: false, // 預設不在摘要中顯示程式碼區塊
folderNoteDisplaySettings: 'default', // 預設不處理資料夾筆記
interceptAllTagClicks: false, // 預設不攔截所有tag點擊事件
};
// 設定頁面類別
@ -410,6 +412,19 @@ export class GridExplorerSettingTab extends PluginSettingTab {
});
});
// 攔截所有tag點擊事件
new Setting(containerEl)
.setName(t('intercept_all_tag_clicks'))
.setDesc(t('intercept_all_tag_clicks_desc'))
.addToggle(toggle => {
toggle
.setValue(this.plugin.settings.interceptAllTagClicks)
.onChange(async (value) => {
this.plugin.settings.interceptAllTagClicks = value;
await this.plugin.saveSettings();
});
});
// 自訂文件副檔名設定
new Setting(containerEl)
.setName(t('custom_document_extensions'))

View file

@ -44,7 +44,9 @@ export const TRANSLATIONS: Translations = {
'add': '新增',
'root': '根目錄',
'more_options': '更多選項',
'add_to_search': '加入搜尋',
'add_tag_to_search': '加入搜尋',
'remove_tag_from_search': '從搜尋中移除',
'global_search': '全域搜尋',
// 視圖標題
'grid_view_title': '網格視圖',
@ -112,6 +114,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': '設定是否在摘要中顯示CodeBlock的內容',
'enable_file_watcher': '啟用檔案監控',
'enable_file_watcher_desc': '啟用後會自動偵測檔案變更並更新視圖,關閉後需手動點擊重新整理按鈕',
'intercept_all_tag_clicks': '攔截所有標籤點擊事件',
'intercept_all_tag_clicks_desc': '啟用後會攔截所有標籤點擊事件,並在網格視圖中打開標籤',
'reset_to_default' : '重置為預設值',
'reset_to_default_desc': '將所有設定重置為預設值',
'settings_reset_notice': '設定值已重置為預設值',
@ -252,7 +256,9 @@ export const TRANSLATIONS: Translations = {
'add': 'Add',
'root': 'Root',
'more_options': 'More options',
'add_to_search': 'Add to search',
'add_tag_to_search': 'Add to search',
'remove_tag_from_search': 'Remove from search',
'global_search': 'Global search',
// View Titles
'grid_view_title': 'Grid view',
@ -320,6 +326,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': 'Set whether to show code block in the summary',
'enable_file_watcher': 'Enable file watcher',
'enable_file_watcher_desc': 'When enabled, the view will automatically update when files change. If disabled, you need to click the refresh button manually',
'intercept_all_tag_clicks': 'Intercept all tag clicks',
'intercept_all_tag_clicks_desc': 'When enabled, all tag clicks will be intercepted and opened in the grid view',
'reset_to_default': 'Reset to default',
'reset_to_default_desc': 'Reset all settings to default values',
'settings_reset_notice': 'Settings have been reset to default values',
@ -460,7 +468,9 @@ export const TRANSLATIONS: Translations = {
'add': '添加',
'root': '根目录',
'more_options': '更多选项',
'add_to_search': '加入搜索',
'add_tag_to_search': '加入搜索',
'remove_tag_from_search': '从搜索中移除',
'global_search': '全域搜索',
// 视图标题
'grid_view_title': '网格视图',
@ -528,6 +538,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': '设置是否在摘要中显示CodeBlock的內容',
'enable_file_watcher': '启用文件监控',
'enable_file_watcher_desc': '启用后会自动检测文件变更并更新视图,关闭后需手动点击刷新按钮',
'intercept_all_tag_clicks': '攔截所有標籤點擊事件',
'intercept_all_tag_clicks_desc': '啟用後會攔截所有標籤點擊事件,並在網格視圖中打開標籤',
'reset_to_default': '重置为默认值',
'reset_to_default_desc': '将所有设置重置为默认值',
'settings_reset_notice': '设置值已重置为默认值',
@ -668,7 +680,9 @@ export const TRANSLATIONS: Translations = {
'add': '追加',
'root': 'ルート',
'more_options': 'もっと選択肢',
'add_to_search': '検索に追加',
'add_tag_to_search': '検索に追加',
'remove_tag_from_search': '検索から削除',
'global_search': 'グローバル検索',
// ビュータイトル
'grid_view_title': 'グリッドビュー',
@ -736,6 +750,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': '要約にCodeBlockを表示するかどうかを設定',
'enable_file_watcher': 'ファイル監視を有効にする',
'enable_file_watcher_desc': '有効にすると、ファイルの変更を自動的に検出してビューを更新します。無効の場合は、更新ボタンを手動でクリックする必要があります',
'intercept_all_tag_clicks': 'すべてのタグクリックを攔截する',
'intercept_all_tag_clicks_desc': '有効にすると、すべてのタグクリックを攔截し、グリッドビューでタグを開きます',
'reset_to_default': 'デフォルトに戻す',
'reset_to_default_desc': 'すべての設定をデフォルト値に戻',
'settings_reset_notice': '設定値がデフォルト値にリセットされました',
@ -876,7 +892,9 @@ export const TRANSLATIONS: Translations = {
'add': 'Добавить',
'root': 'Корень',
'more_options': 'Больше опций',
'add_to_search': 'Добавить в поиск',
'add_tag_to_search': 'Добавить в поиск',
'remove_tag_from_search': 'Удалить из поиска',
'global_search': 'Глобальный поиск',
// View Titles
'grid_view_title': 'Сеточный вид',
@ -944,6 +962,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': 'Установите, чтобы показывать CodeBlock в кратком описании',
'enable_file_watcher': 'Включить наблюдение за файлами',
'enable_file_watcher_desc': 'При включении вид будет автоматически обновляться при изменении файлов. Если отключено, нужно вручную нажимать кнопку обновления',
'intercept_all_tag_clicks': 'Поймать все клики по тегу',
'intercept_all_tag_clicks_desc': 'При включении все клики по тегу будут пойматься и открыться в сетке',
'reset_to_default': 'Сбросить на значения по умолчанию',
'reset_to_default_desc': 'Сбросить все настройки на значения по умолчанию',
'settings_reset_notice': 'Настройки сброшены на значения по умолчанию',
@ -1084,7 +1104,9 @@ export const TRANSLATIONS: Translations = {
'add': 'Додати',
'root': 'Корень',
'more_options': 'Більше опцій',
'add_to_search': 'Додати до пошуку',
'add_tag_to_search': 'Додати до пошуку',
'remove_tag_from_search': 'Видалити з пошуку',
'global_search': 'Глобальний пошук',
// View Titles
'grid_view_title': 'Сітковий вигляд',
@ -1152,6 +1174,8 @@ export const TRANSLATIONS: Translations = {
'show_code_block_in_summary_desc': 'Встановіть, щоб показувати CodeBlock в короткому описі',
'enable_file_watcher': 'Увімкнути спостереження за файлами',
'enable_file_watcher_desc': 'При увімкненні вигляд автоматично оновлюватиметься при зміні файлів. Якщо вимкнено, потрібно вручну натискати кнопку оновлення',
'intercept_all_tag_clicks': 'Поймати всі кліки по тегу',
'intercept_all_tag_clicks_desc': 'При увімкненні всі кліки по тегу будуть поймані та відображатися в сетці',
'reset_to_default': 'Скинути до стандартних значень',
'reset_to_default_desc': 'Скинути всі налаштування до стандартних значень',
'settings_reset_notice': 'Налаштування скинуто до стандартних значень',

View file

@ -1,3 +1,3 @@
{
"2.4.5": "1.1.0"
"2.4.6": "1.1.0"
}