/* 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()); }); }; // src/main.ts __export(exports, { default: () => CustomFramesPlugin }); var import_obsidian4 = __toModule(require("obsidian")); // src/frame.ts var import_obsidian = __toModule(require("obsidian")); // src/settings.ts var defaultSettings = { frames: [], padding: 5 }; var presets = { "obsidian": { url: "https://forum.obsidian.md/", displayName: "Obsidian Forum", icon: "edit", hideOnMobile: true, addRibbonIcon: true, openInCenter: true, zoomLevel: 1, forceIframe: false, customCss: "", customJs: "" }, "detexify": { url: "https://detexify.kirelabs.org/classify.html", displayName: "Detexify", icon: "type", hideOnMobile: true, addRibbonIcon: true, openInCenter: false, zoomLevel: 0.95, forceIframe: false, customCss: `/* hide info clutter and ad banner */ #classify--info-area, .adsbygoogle { display: none !important }`, customJs: "" }, "calendar": { url: "https://calendar.google.com/calendar", displayName: "Google Calendar", icon: "calendar", hideOnMobile: true, addRibbonIcon: true, openInCenter: true, zoomLevel: 1, forceIframe: false, customCss: `/* hide the menu bar "Calendar" text and remove minimum width */ div[style*="min-width: 238px"] { min-width: 0 !important; padding-right: 0 !important; } div[style*="min-width: 238px"] span[role*="heading"] { display: none !important; }`, customJs: "" }, "keep": { url: "https://keep.google.com", displayName: "Google Keep", icon: "files", hideOnMobile: true, addRibbonIcon: false, openInCenter: false, zoomLevel: 1, forceIframe: false, customCss: `/* hide the menu bar, the "Keep" text and the Google Apps button */ html > body > div:nth-child(2) > div:nth-child(2) > div:first-child, html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child > span, html > body > div:first-child > header:first-child > div:nth-child(2) > div:first-child > div:first-child, html > body > div:first-child > header:first-child > div:nth-child(2) > div:nth-child(3) > div:first-child > div:first-child > div:first-child { display: none !important; } html > body > div:first-child > header:first-child > div > div:first-child > div > div:first-child > a:first-child { cursor: default; }`, customJs: "" }, "todoist": { url: "https://todoist.com", displayName: "Todoist", icon: "list-checks", hideOnMobile: true, addRibbonIcon: false, openInCenter: false, zoomLevel: 1, forceIframe: false, customCss: `/* hide the help, home, search, and productivity overview buttons, create extra space, and prevent toast pop-up from acting weird */ [aria-label="Go to Home view"], #quick_find, [aria-label="Productivity"], [aria-label="Help & Feedback"] { display: none !important; } .view_content { padding-left: 15px; } .view_header { padding-left: 15px; padding-top: 10px; } .undo_toast { width: 95%; }`, customJs: "" }, "notion": { url: "https://www.notion.so/", displayName: "Notion", icon: "box", hideOnMobile: true, addRibbonIcon: true, openInCenter: true, zoomLevel: 1, forceIframe: false, customCss: "", customJs: "" }, "twitter": { url: "https://twitter.com", displayName: "Twitter", icon: "twitter", hideOnMobile: true, addRibbonIcon: false, openInCenter: false, zoomLevel: 1, forceIframe: false, customCss: "", customJs: "" }, "tasks": { url: "https://tasks.google.com/embed/?origin=https://calendar.google.com&fullWidth=1", displayName: "Google Tasks", icon: "list-checks", hideOnMobile: true, addRibbonIcon: false, openInCenter: false, zoomLevel: 1, forceIframe: false, customCss: "", customJs: "" }, "readwise-daily-review": { "url": "https://readwise.io/dailyreview", "displayName": "Readwise Daily Review", "icon": "highlighter", "hideOnMobile": true, "addRibbonIcon": false, "openInCenter": false, "zoomLevel": 1, "forceIframe": false, "customCss": ".fixed-nav {\n display: none !important;\n}", "customJs": "" } }; function getIcon(settings) { return settings.icon ? `lucide-${settings.icon}` : "documents"; } function getId(settings) { return settings.displayName.toLowerCase().replace(/\s/g, "-"); } // src/frame.ts var CustomFrame = class { constructor(settings, data) { this.settings = settings; this.data = data; } create(parent, additionalStyle = void 0, urlSuffix = void 0) { let style = `padding: ${this.settings.padding}px;`; if (additionalStyle) style += additionalStyle; if (import_obsidian.Platform.isDesktopApp && !this.data.forceIframe) { let frameDoc = parent.doc; this.frame = frameDoc.createElement("webview"); this.frame.partition = "persist:vault-" + app.appId; parent.appendChild(this.frame); this.frame.setAttribute("allowpopups", ""); this.frame.addEventListener("dom-ready", () => { this.frame.setZoomFactor(this.data.zoomLevel); this.frame.insertCSS(this.data.customCss); this.frame.executeJavaScript(this.data.customJs); }); this.frame.addEventListener("destroyed", () => { if (frameDoc != parent.doc) { this.frame.detach(); this.create(parent, additionalStyle, urlSuffix); } }); } else { this.frame = parent.doc.createElement("iframe"); parent.appendChild(this.frame); this.frame.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads"); this.frame.setAttribute("allow", "encrypted-media; fullscreen; oversized-images; picture-in-picture; sync-xhr; geolocation;"); style += `transform: scale(${this.data.zoomLevel}); transform-origin: 0 0;`; } this.frame.addClass("custom-frames-frame"); this.frame.addClass(`custom-frames-${getId(this.data)}`); this.frame.setAttribute("style", style); let src = new URL(this.data.url); if (urlSuffix) { let suffix = new URL(urlSuffix, src.origin); suffix.searchParams.forEach((value, key) => { src.searchParams.set(key, value); }); if (suffix.pathname !== "/") { src.pathname += suffix.pathname; } src.hash = suffix.hash || src.hash; } this.frame.setAttribute("src", src.toString()); } refresh() { if (this.frame instanceof HTMLIFrameElement) { this.frame.contentWindow.location.reload(); } else { this.frame.reload(); } } return() { if (this.frame instanceof HTMLIFrameElement) { this.frame.contentWindow.open(this.data.url); } else { this.frame.loadURL(this.data.url); } } goBack() { if (this.frame instanceof HTMLIFrameElement) { this.frame.contentWindow.history.back(); } else { this.frame.goBack(); } } goForward() { if (this.frame instanceof HTMLIFrameElement) { this.frame.contentWindow.history.forward(); } else { this.frame.goForward(); } } toggleDevTools() { if (!(this.frame instanceof HTMLIFrameElement)) { if (!this.frame.isDevToolsOpened()) { this.frame.openDevTools(); } else { this.frame.closeDevTools(); } } } getCurrentUrl() { return this.frame instanceof HTMLIFrameElement ? this.frame.contentWindow.location.href : this.frame.getURL(); } focus() { if (this.frame instanceof HTMLIFrameElement) { this.frame.contentWindow.focus(); } else { this.frame.focus(); } } }; // src/settings-tab.ts var import_obsidian2 = __toModule(require("obsidian")); var CustomFramesSettingTab = class extends import_obsidian2.PluginSettingTab { constructor(app2, plugin) { super(app2, plugin); this.plugin = plugin; } display() { this.containerEl.empty(); this.containerEl.createEl("h2", { text: "自定义标签页设置" }); this.containerEl.createEl("p", { text: "请注意,大多数设置需要重启或重新加载Obsidian才能生效。", cls: "mod-warning" }); new import_obsidian2.Setting(this.containerEl).setName("标签页内边距").setDesc("自定义标签页内部周围应留的内边距,单位为像素。").addText((t) => { t.inputEl.type = "number"; t.setValue(String(this.plugin.settings.padding)); t.onChange((v) => __async(this, null, function* () { this.plugin.settings.padding = v.length ? Number(v) : defaultSettings.padding; yield this.plugin.saveSettings(); })); }); for (let frame of this.plugin.settings.frames) { let heading = this.containerEl.createEl("h3", { text: frame.displayName || "Unnamed Frame" }); let toggle = new import_obsidian2.ButtonComponent(this.containerEl).setButtonText("显示设置").setClass("custom-frames-show").onClick(() => __async(this, null, function* () { content.hidden = !content.hidden; toggle.setButtonText(content.hidden ? "Show Settings" : "Hide Settings"); })); let content = this.containerEl.createDiv(); content.hidden = true; new import_obsidian2.Setting(content).setName("显示名称").setDesc("此标签页应具有的显示名称。").addText((t) => { t.setValue(frame.displayName); t.onChange((v) => __async(this, null, function* () { frame.displayName = v; heading.setText(frame.displayName || "Unnamed Frame"); yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("图标").setDesc(createFragment((f) => { f.createSpan({ text: "此标签页应具有的图标。可以使用任何 " }); f.createEl("a", { text: "Lucide 图标", href: "https://lucide.dev/" }); f.createSpan({ text: " 的名称。" }); })).addText((t) => { t.setValue(frame.icon); t.onChange((v) => __async(this, null, function* () { frame.icon = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("URL").setDesc("此标签页中应打开的URL。").addText((t) => { t.setValue(frame.url); t.onChange((v) => __async(this, null, function* () { frame.url = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("在移动设备上禁用").setDesc("自定义标签页在移动设备上受到更多限制,不支持显示相同类型的内容。如果某个标签页在移动设备上无法正常工作,可以将其禁用。").addToggle((t) => { t.setValue(frame.hideOnMobile); t.onChange((v) => __async(this, null, function* () { frame.hideOnMobile = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("添加侧边栏图标").setDesc("是否应在侧边栏添加一个按钮来打开此标签页。").addToggle((t) => { t.setValue(frame.addRibbonIcon); t.onChange((v) => __async(this, null, function* () { frame.addRibbonIcon = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("在中间打开").setDesc("此标签页是否应在未固定的中心编辑器中打开,而不是在侧边栏中打开。这对于在狭窄视图下效果不佳的网站,或在查看时不需要打开笔记的网站很有用。").addToggle((t) => { t.setValue(frame.openInCenter); t.onChange((v) => __async(this, null, function* () { frame.openInCenter = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("强制使用iframe").setDesc(createFragment((f) => { f.createSpan({ text: "此标签页在桌面端是使用iframe还是Electron webviews。" }); f.createEl("br"); f.createEl("em", { text: "仅当此标签页导致问题或频繁崩溃时才启用此设置。此设置会导致所有仅限桌面端的设置被忽略。" }); })).addToggle((t) => { t.setValue(frame.forceIframe); t.onChange((v) => __async(this, null, function* () { frame.forceIframe = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("页面缩放").setDesc("此标签页页面应显示的缩放比例,以百分比表示。").addText((t) => { t.inputEl.type = "number"; t.setValue(String(frame.zoomLevel * 100)); t.onChange((v) => __async(this, null, function* () { frame.zoomLevel = v.length ? Number(v) / 100 : 1; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("额外CSS").setDesc(createFragment((f) => { f.createSpan({ text: "应应用于此标签页的额外CSS代码片段。" }); f.createEl("br"); f.createEl("em", { text: "请注意,这仅适用于桌面端。" }); })).addTextArea((t) => { t.inputEl.rows = 5; t.inputEl.cols = 50; t.setValue(frame.customCss); t.onChange((v) => __async(this, null, function* () { frame.customCss = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.Setting(content).setName("额外JavaScript").setDesc(createFragment((f) => { f.createSpan({ text: "应应用于此标签页的额外JavaScript代码片段。" }); f.createEl("br"); f.createEl("em", { text: "请注意,这仅适用于桌面端。" }); })).addTextArea((t) => { t.inputEl.rows = 5; t.inputEl.cols = 50; t.setValue(frame.customJs); t.onChange((v) => __async(this, null, function* () { frame.customJs = v; yield this.plugin.saveSettings(); })); }); new import_obsidian2.ButtonComponent(content).setButtonText("移除标签页").onClick(() => __async(this, null, function* () { this.plugin.settings.frames.remove(frame); yield this.plugin.saveSettings(); this.display(); })); } this.containerEl.createEl("hr"); this.containerEl.createEl("p", { text: `创建一个新标签页,可以从插件自带的预设中选择,也可以自定义编辑。每个标签页的标签页都可以通过“自定义标签页:打开”命令打开。` }); let addDiv = this.containerEl.createDiv(); let dropdown = new import_obsidian2.DropdownComponent(addDiv); dropdown.addOption("new", "Custom"); for (let [key, value] of Object.entries(presets).sort((a, b) => a[1].displayName.localeCompare(b[1].displayName))) dropdown.addOption(key, value.displayName); new import_obsidian2.ButtonComponent(addDiv).setButtonText("添加标签页").setClass("custom-frames-add").onClick(() => __async(this, null, function* () { let option = dropdown.getValue(); if (option == "new") { this.plugin.settings.frames.push({ url: "", displayName: "New Frame", icon: "", hideOnMobile: true, addRibbonIcon: false, openInCenter: false, zoomLevel: 1, forceIframe: false, customCss: "", customJs: "" }); } else { this.plugin.settings.frames.push(presets[option]); } yield this.plugin.saveSettings(); this.display(); })); let disclaimer = this.containerEl.createEl("p", { cls: "mod-warning" }); disclaimer.createSpan({ text: "请注意,当您将网站添加为自定义标签页时,您输入的个人信息可能会暴露给您安装的其他插件。有关更多信息,请参阅 " }); disclaimer.createEl("a", { text: "此讨论", href: "https://github.com/Ellpeck/ObsidianCustomFrames/issues/54#issuecomment-1210879685", cls: "mod-warning" }); disclaimer.createSpan({ text: "。" }); this.containerEl.createEl("hr"); this.containerEl.createEl("p", { text: "需要插件使用帮助?欢迎加入Discord服务器!" }); this.containerEl.createEl("a", { href: "https://link.ellpeck.de/discordweb" }).createEl("img", { attr: { src: "https://ellpeck.de/res/discord-wide.png" }, cls: "custom-frames-support" }); this.containerEl.createEl("p", { text: "如果您喜欢此插件并希望支持其开发,可以通过点击此精美图片访问我的网站进行支持!" }); this.containerEl.createEl("a", { href: "https://ellpeck.de/support" }).createEl("img", { attr: { src: "https://ellpeck.de/res/generalsupport-wide.png" }, cls: "custom-frames-support" }); } }; // src/view.ts var import_obsidian3 = __toModule(require("obsidian")); var _CustomFrameView = class extends import_obsidian3.ItemView { constructor(leaf, settings, data, name) { super(leaf); this.data = data; this.name = name; this.frame = new CustomFrame(settings, data); this.navigation = data.openInCenter; for (let action of _CustomFrameView.actions) this.addAction(action.icon, action.name, () => action.action(this)); } onload() { this.contentEl.empty(); this.contentEl.addClass("custom-frames-view"); this.frame.create(this.contentEl); } onPaneMenu(menu, source) { super.onPaneMenu(menu, source); for (let action of _CustomFrameView.actions) { menu.addItem((i) => { i.setTitle(action.name); i.setIcon(action.icon); i.onClick(() => action.action(this)); }); } } getViewType() { return this.name; } getDisplayText() { return this.data.displayName; } getIcon() { return getIcon(this.data); } focus() { this.frame.focus(); } }; var CustomFrameView = _CustomFrameView; CustomFrameView.actions = [ { name: "返回原始页面", icon: "home", action: (v) => v.frame.return() }, { name: "打开开发者工具", icon: "binary", action: (v) => v.frame.toggleDevTools() }, { name: "复制链接", icon: "link", action: (v) => navigator.clipboard.writeText(v.frame.getCurrentUrl()) }, { name: "在浏览器中打开", icon: "globe", action: (v) => open(v.frame.getCurrentUrl()) }, { name: "刷新", icon: "refresh-cw", action: (v) => v.frame.refresh() }, { name: "前进", icon: "arrow-right", action: (v) => v.frame.goForward() }, { name: "后退", icon: "arrow-left", action: (v) => v.frame.goBack() } ]; // src/main.ts var CustomFramesPlugin = class extends import_obsidian4.Plugin { onload() { return __async(this, null, function* () { yield this.loadSettings(); for (let frame of this.settings.frames) { if (!frame.url || !frame.displayName) continue; let name = `custom-frames-${getId(frame)}`; if (import_obsidian4.Platform.isMobileApp && frame.hideOnMobile) { console.log(`跳过在移动设备上隐藏的标签页 ${name}`); continue; } try { console.log(`为URL ${frame.url} 注册标签页 ${name}`); this.registerView(name, (l) => new CustomFrameView(l, this.settings, frame, name)); this.addCommand({ id: `open-${name}`, name: `打开 ${frame.displayName}`, callback: () => this.openLeaf(name, frame.openInCenter, false) }); if (frame.addRibbonIcon) this.addRibbonIcon(getIcon(frame), `Open ${frame.displayName}`, (e) => this.openLeaf(name, frame.openInCenter, import_obsidian4.Platform.isMacOS ? e.metaKey : e.ctrlKey)); } catch (e) { console.error(`无法注册标签页 ${name},是否已存在同名标签页?`); } } this.addSettingTab(new CustomFramesSettingTab(this.app, this)); this.registerMarkdownCodeBlockProcessor("custom-frames", (s, e) => { e.empty(); e.addClass("custom-frames-view-file"); let frameMatch = /frame:([^\n]+)/gi.exec(s); let frameName = frameMatch && frameMatch[1].trim(); if (!frameName) { e.createSpan({ text: "无法解析标签页名称" }); return; } let data = this.settings.frames.find((f) => f.displayName == frameName); if (!data) { e.createSpan({ text: `找不到名为 ${frameName} 的标签页` }); return; } if (import_obsidian4.Platform.isMobileApp && data.hideOnMobile) { e.createSpan({ text: `${frameName} 在移动设备上隐藏` }); return; } let styleMatch = /style:([^\n]+)/gi.exec(s); let style = styleMatch && styleMatch[1].trim(); style || (style = "height: 600px;"); let urlSuffixMatch = /urlsuffix:([^\n]+)/gi.exec(s); let urlSuffix = urlSuffixMatch && urlSuffixMatch[1].trim(); urlSuffix || (urlSuffix = ""); let frame = new CustomFrame(this.settings, data); frame.create(e, style, urlSuffix); }); }); } loadSettings() { return __async(this, null, function* () { this.settings = Object.assign({}, defaultSettings, yield this.loadData()); }); } saveSettings() { return __async(this, null, function* () { yield this.saveData(this.settings); }); } openLeaf(name, center, split) { return __async(this, null, function* () { let leaf; if (center) { leaf = this.app.workspace.getLeaf(split); yield leaf.setViewState({ type: name, active: true }); } else { if (!this.app.workspace.getLeavesOfType(name).length) yield this.app.workspace.getRightLeaf(false).setViewState({ type: name, active: true }); leaf = this.app.workspace.getLeavesOfType(name)[0]; this.app.workspace.revealLeaf(leaf); } if (leaf.view instanceof CustomFrameView) leaf.view.focus(); }); } }; /* nosourcemap */