Skip to content

Commit

Permalink
feat: extract URLs from frontmatter values
Browse files Browse the repository at this point in the history
  • Loading branch information
giselle197 committed Feb 23, 2023
1 parent a668671 commit 8371b9c
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 16 deletions.
19 changes: 18 additions & 1 deletion README-ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,29 @@
- 選擇是否顯示H1~H6標題,並設定最小顯示標題
- 依照網址字典排序 (此功能只在**沒有**顯示標題時有效)
- 自行設定 內部鏈接、重複的外部鏈接 的高亮顏色
- [v1.1.0] 擷取metadata中的URLs

### 注意
雖然內部鏈接在面板中也有高亮顯示,但無法點擊。
- 雖然內部鏈接在面板中也有高亮顯示,但無法點擊。
- [v1.1.0] 如果 metadata的欄位是一個段落,裡面有 URL(s),則需要在 URL 的結尾處加上空格

## 使用
輸入指令 "External Links: Open external links view for the current file" 或點選位在 ribbon 的 "album" 圖標,即可啟動此插件。

## 安裝
`main.js`, `styles.css`, `manifest.json` 複製到vault的插件資料夾 `VaultFolder/.obsidian/plugins/obsidian-external-links-in-document/`.

## 更新記錄

### v1.0.0
基本功能 -- 顯示URL或網頁標題、顯示或不顯示標題、對URL進行排序

### v1.1.0
功能來自 https://github.com/giselle197/obsidian-external-links-in-document/issues/1 ,感謝[@mnaoumov](https://github.com/mnaoumov)的建議!

增加功能:從metadata中提取URLs

1. YAML中的URL不能被賦予標題。
2. YAML中的URLs不參與排序。
3. YAML中的URLs不包括在計數中。因為它們與正文區域分開,計數會造成混亂。
4. 我假設使用者在寫metadata時很謹慎,並且順序是有意義的。
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,32 @@ There is status bar item showing the total number of external links. When the mo

## Feature
- show URL or webpage title (if it is in the content)
- show headings or not, and you can set the minimal level of headings.
- show headings or not, and you can set the minimal level of headings
- sort by URLs alphebatically (only work when the headings are not showed)
- set highlight color for internal links and duplicate exteral links
- [v1.1.0] extract URLs from frontmatter values

### Notice
Although internal links are also highlighted, they can't be click.
- Although internal links are also highlighted, they can't be clicked.
- [v1.1.0] URL(s) in frontmatter value **must** have a space at the end if they are inside the paragraph.

## Usage
The panel is activated by command "External Links: Open external links view for the current file" or click the "album" ribbon icon.

## Manually installing the plugin
Copy over `main.js`, `styles.css`, `manifest.json` to your vault `VaultFolder/.obsidian/plugins/obsidian-external-links-in-document/`.

## Update log

### v1.0.0
basic features -- show URL or title, show headings or not, and sort URLs

### v1.1.0
inspired from https://github.com/giselle197/obsidian-external-links-in-document/issues/1, thanks for [@mnaoumov](https://github.com/mnaoumov)'s adivice!

Add feature: extract URLs from frontmatter values

1. URLs in YAML can't be assigned title.
2. URLs in YAML don't participate in sorting.
3. URLs from frontmatter values are not included in the count. Since they are separated from content region, counting will cause chaos.
4. I assume users write metadata with care, and the order is meaningful.
4 changes: 3 additions & 1 deletion main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface ExternalLinksPluginSettings {
duplicateUrlColor: string;
internalLinkColor: string;
defDuplicate: string;
showMetadata: boolean;
}

const DEFAULT_SETTINGS: Partial<ExternalLinksPluginSettings> = {
Expand All @@ -22,6 +23,7 @@ const DEFAULT_SETTINGS: Partial<ExternalLinksPluginSettings> = {
duplicateUrlColor: "#ff0000",
internalLinkColor: "#0000ff",
defDuplicate: "all",
showMetadata: true,
}


Expand Down Expand Up @@ -104,4 +106,4 @@ export default class ExternalLinksPlugin extends Plugin {
this.app.workspace.getLeavesOfType(VIEW_TYPE_EXTERNAL_LINKS)[0]
);
}
}
}
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "external-links-in-document",
"name": "External Links",
"version": "1.0.1",
"version": "1.1.0",
"minAppVersion": "0.15.0",
"description": "Show all external links (URLs) in the current file",
"author": "Giselle",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "external-links-in-document",
"version": "1.0.1",
"version": "1.1.0",
"description": "Show all external links (URLs) in the current file",
"main": "main.js",
"scripts": {
Expand Down
15 changes: 14 additions & 1 deletion settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ export class ExternalLinksPluginSettingTab extends PluginSettingTab {
containerEl.empty();
containerEl.createEl("h1", { text: "My Plugin Settings" });

new Setting(containerEl)
.setName("Show URLs from frontmatter values")
.setDesc("⚠️ URLs from frontmatter values are not included in the count")
.addToggle((toggle) => {
toggle.setTooltip(("default: true"))
.setValue(this.plugin.settings.showMetadata)
.onChange(async (value) => {
this.plugin.settings.showMetadata = value;
this.plugin.saveSettings();
view.onOpen();
})
});

new Setting(containerEl)
.setName("Show number of duplicate URLs")
.addToggle((toggle) => {
Expand All @@ -50,7 +63,7 @@ export class ExternalLinksPluginSettingTab extends PluginSettingTab {

new Setting(containerEl)
.setName("Color for internal links")
.setDesc("internal links can't be clicked")
.setDesc("⚠️ internal links can't be clicked")
.addColorPicker(color => color
.setValue(this.plugin.settings.internalLinkColor)
.onChange(async (value) => {
Expand Down
128 changes: 119 additions & 9 deletions view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,122 @@ export class ExternalLinksView extends ItemView {
})
}

// Code provided by OpenAI ChatGPT
detectUrlsInParagraph(paragraph: any) { // type: string
const urlRegex = /((http(s)?:\/\/)|(www\.))[^\s]+/gi;
const urls = paragraph.match(urlRegex);

return urls;
}

async render() {
const { contentEl } = this;
for (let i = 0; i < contentEl.childNodes.length; i++) {
let child = <HTMLDivElement>contentEl.childNodes[i];
if (child.className == "cont") {
contentEl.removeChild(child);
}
}
var contEl = contentEl.createEl("div");
contEl.className = "cont";
// console.log("contentEl.childNodes", contentEl.childNodes);

// clear old output
const temp = document.getElementsByClassName("cont");
Array.from(temp).forEach((x) => {
x.empty();
contentEl.removeChild(x);
})

const noteFile = this.app.workspace.getActiveFile()!;
const fileContent: string = await this.app.vault.read(noteFile);

if (this.plugin.settings.showMetadata) {
// metadata
let met = contentEl.createEl("h2", { text: "Metadata" });
let metEl = contentEl.createEl("div");
met.className = "cont";
metEl.className = "cont";

const ul_metadata = document.createElement("ul"); // metadata ul, outermost layer
// ul_metadata.className = "cont"; // error
metEl.appendChild(ul_metadata);

// ref: https://obsidian-snippets.pages.dev/tags/development/
const metadata = this.app.metadataCache.getFileCache(noteFile)
if (metadata) {

for (const k in metadata.frontmatter) {
if (k == "position") continue;

const values = metadata.frontmatter[k]

if (typeof (values) == 'string') { // there is single URL in this field OR there is a paragraph including several URLs
const urls = this.detectUrlsInParagraph(values);
if (urls == null) continue;

if (urls.length == 1) {
const li_fieldname = document.createElement("li");

// make fieldname and link in the same line
const title = document.createElement('span');
title.innerText = k + ":\t";
title.classList.add('metadata-title');
li_fieldname.appendChild(title);

const a = document.createElement("a");
a.href = urls[0];
a.textContent = urls[0];

li_fieldname.appendChild(a);
ul_metadata.appendChild(li_fieldname);

}
else {

const li_fieldname = document.createElement("li");
li_fieldname.textContent = k;
const ul_inner = document.createElement("ol"); // inner layer
li_fieldname.appendChild(ul_inner); // li > ol

for (const x in urls) {

const lli = document.createElement("li");
const a = document.createElement("a");
a.href = urls[x];
a.textContent = urls[x];

ul_inner.appendChild(lli); // ol > li
lli.appendChild(a);
ul_metadata.appendChild(li_fieldname);
}

}
}
else { // typeof (values) is 'object' // there are several URLs in this field

const li_fieldname = document.createElement("li");
li_fieldname.textContent = k;
const ul_inner = document.createElement("ol"); // inner layer

for (const i in values) {
const urls = this.detectUrlsInParagraph(values[i]);

li_fieldname.appendChild(ul_inner); // li > ol

for (const x in urls) {
const lli = document.createElement("li");
const a = document.createElement("a");
a.href = urls[x];
a.textContent = urls[x];

ul_inner.appendChild(lli); // ol > li
lli.appendChild(a);
ul_metadata.appendChild(li_fieldname);
}
}
}

}
}


}



//ref: https://www.programcreek.com/typescript/?code=OliverBalfour%2Fobsidian-pandoc%2Fobsidian-pandoc-master%2Frenderer.ts
// Use Obsidian's markdown renderer to render to a hidden <div>
const wrapper = document.createElement('div');
Expand Down Expand Up @@ -142,6 +243,15 @@ export class ExternalLinksView extends ItemView {
else
elements = wrapper.querySelectorAll(".external-link");

if (elements.length > 0 && this.plugin.settings.showMetadata) {
// content, context
let cont = contentEl.createEl("h2", { text: "Content" });
cont.className = "cont";
}
// content, context
let contEl = contentEl.createEl("div");
contEl.className = "cont";

const block = Array.from(elements);

// make a dictionary of URLs (although in the headings) and the number of occurances to check if there are duplicate URLs
Expand Down Expand Up @@ -259,4 +369,4 @@ export class ExternalLinksView extends ItemView {
async onClose() {
// Nothing to clean up.
}
}
}

0 comments on commit 8371b9c

Please sign in to comment.