dataview实现获取最近修改文件列表,支持搜索,右键菜单

更新为第2版

更新内容:

  1. UI美化
  2. 增加右键菜单
  3. 增加HoverPopover
  4. 增加tooltip
  5. 增加多语言
代码
```dataviewjs
// 显示条数
const maxNum = 100;
// 本脚本的文件的名字
const currFileName = dv.current()?.file?.name || "Recently Modified";
// 打开时设置为预览模式
const activeLeaf = this.app.workspace.activeLeaf;
if(activeLeaf?.view?.file?.basename === currFileName){
	const state = activeLeaf?.view.getState();
	state.mode = "preview"
	activeLeaf?.setViewState({type: "markdown", state: state});
	activeLeaf?.containerEl.classList.add('recently-modified-view');
}
// 检查recently-modified-view是否设置成功
if(!document.querySelector('recently-modified-view')){
	app.workspace.getLeavesOfType('markdown').forEach(leaf => {
		if(leaf.view.file?.basename === currFileName){
			leaf?.containerEl.classList.add('recently-modified-view');
			if (leaf?.view?.getState()?.mode !== 'preview') {
				leaf?.setViewState({type: "markdown", state: state});
			}
		}
	})
}

// 多语言,默认为中文
const langMap = {
	en: {
		"标题:": "Title: ",
		"创建于:": "Created on: ",
		"更新于:": "Updated on: ",
		"所在文件夹:": "Folder: ",
		"根目录": "Root directory",
		"搜索...": "Search...",
	}
}
function t(str) {
    const lang = moment.locale();
    if(langMap[lang] && langMap[lang][str]) {
        return langMap[lang][str];
    }
    return str;
}

//添加样式
const style = `
.recently-modified-view .search-input {
    background-color: transparent;
    border: 1px solid #888;
    border-radius: 5px;
    height: 27px;
    width: 80%;
    padding: 0 5px;
    color: var(--text-normal);
    margin-top: 2px;
    margin-left: 2px;
}
.recently-modified-view .search-input:focus {
    box-shadow: 0 0 0 2px var(--background-modifier-border-focus);
	border-color: var(--background-modifier-border-focus);
    transition: box-shadow 0.15s ease-in-out, border 0.15s ease-in-out;
}
.recently-modified-view .markdown-preview-view ul{
    padding-left: 0;
    user-select: none;
}
.recently-modified-view .markdown-preview-view ul > li{
    list-style: none;
    padding: 4px 8px;
    border-radius: var(--radius-s);
}
.recently-modified-view .markdown-preview-view ul > li:hover{
    background-color: var(--nav-item-background-hover);
}
.recently-modified-view .markdown-preview-view ul > li.menu-hover {
    background-color: var(--nav-item-background-hover);
}
.recently-modified-view .markdown-preview-view ul > li a {
    text-decoration: none;
    color: var(--nav-item-color);
    width: 100%;
    display: list-item;
}
.recently-modified-view li:has(a[data-starred='true'])::after {
    content: "✩";
    position: absolute;
    top: 4px;
    right: 4px;
}
.recently-modified-view .inline-title {
    font-size: 23px;
}
/* 修改tooltip对齐方式 */
body:has(.recently-modified-view) .tooltip{
	text-align: left;
}
`;
const dvStyle = document.head.querySelector("#recently-modified-style");
if(dvStyle) dvStyle.remove();
document.head.appendChild(
	createEl("style", {
		attr: { id: "recently-modified-style" },
		text: style,
		type: "text/css",
	})
);

// 关键词搜索
const search = dv.el('input', '', { attr: { "class": "search-input", "placeholder": t("搜索...") } });
search.addEventListener('input', function(e) {
    const keyword = e.target.value.trim().toLowerCase();
    const listItems = this.parentElement.querySelectorAll('.list-view-ul li');
    listItems.forEach(item => {
        const text = item.textContent.toLowerCase();
        if (keyword === '' || text.includes(keyword)) {
            item.style.display = 'list-item';
        } else {
            item.style.display = 'none';
        }
        // 关键词高亮
        const itemWords = item.querySelector('a span');
        if (keyword) {
            const regex = new RegExp(`(${keyword})`, 'gi');
            const highlightedText = itemWords.textContent.replace(regex, `<mark>$1</mark>`);
            itemWords.innerHTML = highlightedText;
        } else {
            // 如果搜索框为空,移除高亮样式,恢复原始文本
            itemWords.innerHTML = itemWords.textContent;
        }
    });
});

// 最近修改文件列表
let lastActiveLeaf;
dv.list(
    dv.pages()
    //.filter(p => moment(p.file.mday.toString()).format('MD') === moment().format('MD'))
    .sort(p => p.file.mtime, 'desc')
    .limit(maxNum||100)
    .map(p => {
        let title = `${t('标题:')}${p.file.name}\n`;
		title += `${t('创建于:')}${moment(Number(p.file.ctime)).format('YYYY-MM-DD HH:mm:ss')}\n`;
		title += `${t('更新于:')}${moment(Number(p.file.mtime)).format('YYYY-MM-DD HH:mm:ss')}\n`;
		title += `${t('所在文件夹:')}${p.file.folder||t('根目录')}`;
        const a=dv.el('a', p.file.name, { attr: { "data-href": p.file.path, "data-starred": p.file.starred, "aria-label": title, "data-tooltip-position": "right" } });
        //click
        a.addEventListener('click', function(e) {
			let newLeaf = window.lastActiveLeaf || lastActiveLeaf || app.workspace.getLeaf('tab');
			// 当前激活文档不在root split则新标签打开
			if(!newLeaf.containerEl.closest(".mod-root")){
				newLeaf = app.workspace.getLeaf('tab');
			}
			// Ctrl或Meta键时则新标签打开
			if (isCtrlDown) {
			    newLeaf = app.workspace.getLeaf('tab');
			}
			// 如果叶子已关闭则新标签打开
			if(!newLeaf.containerEl.querySelector('.workspace-leaf-content')) {
			    newLeaf = app.workspace.getLeaf('tab');
			}
			newLeaf.openFile(app.vault.getAbstractFileByPath(this.getAttribute("data-href")));
	        setTimeout(() => {
		        lastActiveLeaf = app.workspace.activeLeaf;
	        }, 100);
        });
        // hover popover
        a.addEventListener('mouseover', function(event) {
            if(!isCtrlDown) return;
            if (!this?.getAttribute("data-href")) return;
            app.workspace.trigger('hover-link', {
                event,
                source: 'preview',
                hoverParent: this.closest('.dataview.list-view-ul'),
                targetEl: this,
                linktext: this.getAttribute("data-href"),
            });
        });
        // context menu
        a.addEventListener('contextmenu', function(event) {
            if (!this?.getAttribute("data-href")) return false;
            this.closest("li").classList.add('menu-hover');
            const file = app.vault.getAbstractFileByPath(this.getAttribute("data-href"));
            const menu = new obsidian.Menu();
            menu.addItem((item) =>
            item.setSection('action')
                .setTitle('Open in new tab')
                .setIcon('file-plus')
                .onClick(() => {
                    const leaf = app.workspace.getLeaf('tab');
                    leaf.openFile(file);
                })
            );
            app.workspace.trigger(
                'file-menu',
                menu,
                file,
                'link-context-menu',
            );
            menu.showAtPosition({ x: event.clientX, y: event.clientY });
            menu.onHide(() => {
                document.querySelectorAll('.recently-modified-view li.menu-hover')?.forEach(item=>item?.classList.remove('menu-hover'));
            });
            // 阻止浏默认的右键菜单
		    return false;
        });
        return a;
    })
)

// 用于记录Ctrl键是否被按下
let isCtrlDown = false;
const handleKeyDown = function(event) {
    if (event.key === 'Control'|| event.key === 'Meta') {
        isCtrlDown = true;
    }
};
document.removeEventListener('keydown', handleKeyDown);
document.addEventListener('keydown', handleKeyDown);
const handleKeyUp = function(event) {
    if (event.key === 'Control'|| event.key === 'Meta') {
        isCtrlDown = false;
    }
};
document.removeEventListener('keyup', handleKeyUp);
document.addEventListener('keyup', handleKeyUp);
```

使用方法参考 1楼

效果

3 个赞