main.js
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __reExport = (target, module2, desc) => {
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
}
return target;
};
var __toModule = (module2) => {
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// main.ts
__export(exports, {
default: () => SummaryPlugin
});
var import_obsidian3 = __toModule(require("obsidian"));
// settings.ts
var import_obsidian = __toModule(require("obsidian"));
var SummarySettingTab = class extends import_obsidian.PluginSettingTab {
constructor(app2, plugin) {
super(app2, plugin);
this.plugin = plugin;
}
display() {
let { containerEl } = this;
containerEl.empty();
new import_obsidian.Setting(containerEl).setName("Show Callouts").setDesc("Show the text inside callout blocks").addToggle((toggle) => toggle.setValue(this.plugin.settings.includecallout).onChange((value) => __async(this, null, function* () {
this.plugin.settings.includecallout = value;
yield this.plugin.saveSettings();
})));
new import_obsidian.Setting(containerEl).setName("Show Link").setDesc("Show link to original note").addToggle((toggle) => toggle.setValue(this.plugin.settings.includelink).onChange((value) => __async(this, null, function* () {
this.plugin.settings.includelink = value;
yield this.plugin.saveSettings();
})));
new import_obsidian.Setting(containerEl).setName("Remove Tags").setDesc("Remove tags from text").addToggle((toggle) => toggle.setValue(this.plugin.settings.removetags).onChange((value) => __async(this, null, function* () {
this.plugin.settings.removetags = value;
yield this.plugin.saveSettings();
})));
new import_obsidian.Setting(containerEl).setName("List Items").setDesc("Include only the items of a list that contain the tag, not the entire list.").addToggle((toggle) => toggle.setValue(this.plugin.settings.listparagraph).onChange((value) => __async(this, null, function* () {
this.plugin.settings.listparagraph = value;
yield this.plugin.saveSettings();
})));
new import_obsidian.Setting(containerEl).setName("Include Child Items").setDesc("Include the child items of a list.").addToggle((toggle) => toggle.setValue(this.plugin.settings.includechildren).onChange((value) => __async(this, null, function* () {
this.plugin.settings.includechildren = value;
yield this.plugin.saveSettings();
})));
new import_obsidian.Setting(containerEl).setName("Clear All Marks").setDesc("Clear all marked items in tag summaries.").addButton((button) => button.setButtonText("Clear All").setWarning().onClick(() => __async(this, null, function* () {
this.plugin.settings.markedItems = [];
this.plugin.markedItems = new Set();
yield this.plugin.saveSettings();
// 清除当前页面上所有已标记的元素
this.plugin.clearAllMarksFromDOM();
new import_obsidian.Notice("All marks cleared!");
})));
}
};
// summarytags.ts
var import_obsidian2 = __toModule(require("obsidian"));
var SummaryModal = class extends import_obsidian2.Modal {
constructor(app2, onSubmit) {
super(app2);
this.onSubmit = onSubmit;
}
onOpen() {
let listTags = [];
let listFiles = this.app.vault.getMarkdownFiles();
listFiles.forEach((file) => {
const cache = app.metadataCache.getFileCache(file);
listTags = listTags.concat((0, import_obsidian2.getAllTags)(cache));
});
const tagsSet = new Set(listTags);
listTags = Array.from(tagsSet).sort();
const tagsToExclude = ["None"].concat(listTags);
let { contentEl } = this;
contentEl.createEl("h1", { text: "Add Summary" });
if (listTags.length <= 0) {
contentEl.setText("There are no tags in your notes");
} else {
this.include = listTags[0];
new import_obsidian2.Setting(contentEl).setName("Select tag to include in the summary").addDropdown((menu) => {
for (let i = 0; i < listTags.length; i++) {
menu.addOption(listTags[i], listTags[i]);
}
menu.setValue(listTags[0]);
menu.onChange((value) => {
this.include = value;
});
});
this.exclude = tagsToExclude[0];
new import_obsidian2.Setting(contentEl).setName("Select tag to exclude from the summary").addDropdown((menu) => {
for (let i = 0; i < tagsToExclude.length; i++) {
menu.addOption(tagsToExclude[i], tagsToExclude[i]);
}
menu.setValue(tagsToExclude[0]);
menu.onChange((value) => {
this.exclude = value;
});
});
new import_obsidian2.Setting(contentEl).addButton((button) => {
button.setButtonText("Add Summary").setCta().onClick(() => {
this.close();
this.onSubmit(this.include, this.exclude);
});
});
}
}
onClose() {
let { contentEl } = this;
contentEl.empty();
}
};
// main.ts
var DEFAULT_SETTINGS = {
includecallout: true,
includelink: true,
removetags: false,
listparagraph: true,
includechildren: true,
markedItems: []
};
var SummaryPlugin = class extends import_obsidian3.Plugin {
onload() {
return __async(this, null, function* () {
yield this.loadSettings();
this.addSettingTab(new SummarySettingTab(this.app, this));
// 初始化标记状态
this.markedItems = new Set(this.settings.markedItems || []);
// 添加样式
this.addStyles();
this.addCommand({
id: "summary-modal",
name: "Add Summary",
editorCallback: (editor) => {
new SummaryModal(this.app, (include, exclude) => {
let summary = "```add-summary\n";
summary += "tags: " + include + "\n";
if (exclude != "None") {
summary += "exclude: " + exclude + "\n";
}
summary += "```\n";
editor.replaceRange(summary, editor.getCursor());
}).open();
}
});
this.registerMarkdownCodeBlockProcessor("add-summary", (source, el, ctx) => __async(this, null, function* () {
let tags = Array();
let include = Array();
let exclude = Array();
const rows = source.split("\n").filter((row) => row.length > 0);
rows.forEach((line) => {
if (line.match(/^\s*tags:[\p{L}0-9_\-/# ]+$/gu)) {
const content = line.replace(/^\s*tags:/, "").trim();
let list = content.split(/\s+/).map((tag) => tag.trim());
list = list.filter((tag) => {
if (tag.match(/^#[\p{L}]+[^#]*$/u)) {
return true;
} else {
return false;
}
});
tags = list;
}
if (line.match(/^\s*include:[\p{L}0-9_\-/# ]+$/gu)) {
const content = line.replace(/^\s*include:/, "").trim();
let list = content.split(/\s+/).map((tag) => tag.trim());
list = list.filter((tag) => {
if (tag.match(/^#[\p{L}]+[^#]*$/u)) {
return true;
} else {
return false;
}
});
include = list;
}
if (line.match(/^\s*exclude:[\p{L}0-9_\-/# ]+$/gu)) {
const content = line.replace(/^\s*exclude:/, "").trim();
let list = content.split(/\s+/).map((tag) => tag.trim());
list = list.filter((tag) => {
if (tag.match(/^#[\p{L}]+[^#]*$/u)) {
return true;
} else {
return false;
}
});
exclude = list;
}
});
if (tags.length > 0 || include.length > 0) {
yield this.createSummary(el, tags, include, exclude, ctx.sourcePath);
} else {
this.createEmptySummary(el);
}
}));
});
}
createEmptySummary(element) {
const container = createEl("div");
container.createEl("span", {
attr: { style: "color: var(--text-error) !important;" },
text: "There are no blocks that match the specified tags."
});
element.replaceWith(container);
}
createSummary(element, tags, include, exclude, filePath) {
return __async(this, null, function* () {
var _a;
const validTags = tags.concat(include);
let listFiles = this.app.vault.getMarkdownFiles();
listFiles = listFiles.filter((file) => {
const cache = app.metadataCache.getFileCache(file);
const tagsInFile = (0, import_obsidian3.getAllTags)(cache);
if (validTags.some((value) => tagsInFile.includes(value))) {
return true;
}
return false;
});
listFiles = listFiles.sort((file1, file2) => {
if (file1.path < file2.path) {
return -1;
} else if (file1.path > file2.path) {
return 1;
} else {
return 0;
}
});
let listContents = yield this.readFiles(listFiles);
let summary = "";
listContents.forEach((item) => {
const fileName = item[0].name.replace(/.md$/g, "");
const filePath2 = item[0].path;
let listParagraphs = Array();
const blocks = item[1].split(/\n\s*\n/).filter((row) => row.trim().length > 0);
blocks.forEach((paragraph) => {
let valid = false;
let listTags = paragraph.match(/#[\p{L}0-9_\-/#]+/gu);
if (listTags != null && listTags.length > 0) {
if (!paragraph.contains("```")) {
valid = this.isValidText(listTags, tags, include, exclude);
}
}
if (valid) {
// 简化处理:如果段落包含标签,直接添加整个段落
listParagraphs.push(paragraph);
}
});
listParagraphs.forEach((paragraph) => {
paragraph += "\n";
if (this.settings.includelink) {
paragraph = paragraph.replace(/(#[^\s#]+)/g, function(tag) {
return tag + " [[" + filePath2 + "|🖋️]]";
});
}
// 再移除标签本身,保留link
if (this.settings.removetags) {
paragraph = paragraph.replace(/#[^\s#]+ ?/g, "");
}
if (this.settings.includecallout) {
let callout = "> [!" + fileName + "]\n";
const rows = paragraph.split("\n");
rows.forEach((row) => {
callout += "> " + row + "\n";
});
paragraph = callout + "\n\n";
} else {
paragraph += "\n\n";
}
summary += paragraph;
});
});
if (summary != "") {
let summaryContainer = createEl("div");
yield import_obsidian3.MarkdownRenderer.renderMarkdown(summary, summaryContainer, (_a = this.app.workspace.getActiveFile()) == null ? void 0 : _a.path, null);
// 为容器添加点击标记功能
this.addClickMarking(summaryContainer);
element.replaceWith(summaryContainer);
} else {
this.createEmptySummary(element);
}
});
}
readFiles(listFiles) {
return __async(this, null, function* () {
let list = [];
for (let t = 0; t < listFiles.length; t += 1) {
const file = listFiles[t];
let content = yield this.app.vault.cachedRead(file);
list.push([file, content]);
}
return list;
});
}
isValidText(listTags, tags, include, exclude) {
let valid = true;
if (tags.length > 0) {
valid = valid && tags.some((value) => listTags.includes(value));
}
if (include.length > 0) {
valid = valid && include.every((value) => listTags.includes(value));
}
if (valid && exclude.length > 0) {
valid = !exclude.some((value) => listTags.includes(value));
}
return valid;
}
loadSettings() {
return __async(this, null, function* () {
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
});
}
saveSettings() {
return __async(this, null, function* () {
yield this.saveData(this.settings);
});
}
// 为容器添加点击标记功能
addClickMarking(container) {
// 为段落、列表项、任务项等添加点击事件和样式
const elements = container.querySelectorAll('p, li, .task-list-item');
elements.forEach((element) => {
if (element.textContent.trim()) {
element.classList.add('tag-summary-item');
element.title = '点击标记为已使用';
// 添加点击事件
element.addEventListener('click', (event) => {
// 如果点击的是链接,不处理标记
if (event.target.tagName === 'A' || event.target.closest('a')) {
return;
}
event.stopPropagation();
this.toggleMark(element);
});
}
});
// 恢复之前的标记状态
this.restoreMarkingState(container);
}
// 切换标记状态
toggleMark(element) {
if (element.classList.contains('tag-summary-used')) {
// 取消标记
element.classList.remove('tag-summary-used');
element.title = '点击标记为已使用';
} else {
// 标记为已使用
element.classList.add('tag-summary-used');
element.title = '点击取消标记';
}
// 保存标记状态
this.saveMarkingState(element);
}
// 保存标记状态到本地存储
saveMarkingState(element) {
const text = element.textContent.trim();
const isMarked = element.classList.contains('tag-summary-used');
if (!this.markedItems) {
this.markedItems = new Set();
}
if (isMarked) {
this.markedItems.add(text);
} else {
this.markedItems.delete(text);
}
// 将Set转换为数组保存到settings
this.settings.markedItems = Array.from(this.markedItems);
this.saveSettings();
}
// 从本地存储恢复标记状态
restoreMarkingState(container) {
if (!this.settings.markedItems) {
return;
}
this.markedItems = new Set(this.settings.markedItems);
const elements = container.querySelectorAll('.tag-summary-item');
elements.forEach((element) => {
const text = element.textContent.trim();
if (this.markedItems.has(text)) {
element.classList.add('tag-summary-used');
element.title = '点击取消标记';
}
});
}
// 清除DOM中所有已标记的元素
clearAllMarksFromDOM() {
const markedElements = document.querySelectorAll('.tag-summary-used');
markedElements.forEach((element) => {
element.classList.remove('tag-summary-used');
element.title = '点击标记为已使用';
});
}
// 添加CSS样式
addStyles() {
const style = document.createElement('style');
style.textContent = `
.tag-summary-item {
cursor: pointer;
transition: all 0.3s ease;
border-radius: 4px;
padding: 2px 4px;
margin: 1px 0;
}
.tag-summary-item:hover {
background-color: var(--background-modifier-hover);
}
.tag-summary-used {
opacity: 0.4 !important;
}
.tag-summary-used:hover {
opacity: 0.6 !important;
}
/* 确保列表项也能正确显示 */
li.tag-summary-item {
list-style-position: outside;
margin-left: 20px;
}
.task-list-item.tag-summary-item {
display: list-item;
}
`;
document.head.appendChild(style);
}
};