🏠 返回首頁 

Greasy Fork is available in English.

Notes de coupe de cloud de Markdown

Un outil qui convertit le contenu Web au format Markdown, prend en charge des fonctionnalités telles que la copie, le téléchargement et l’envoi à GitHub et Obsidian.

// ==UserScript==
// @name              MarkDown Cloud Cut Notes
// @name:ar           ملاحظات قطع السحابة المتولد
// @name:bg           Бележки за изрязване на облак от Маркдаун
// @name:cs           Poznámky k cloudovému řezu Markdown
// @name:da           Markdown Cloud Cut Notes
// @name:de           Markdown Cloud Cut -Notizen
// @name:el           Σημειώσεις κοπής σύννεφων Markdown
// @name:en           MarkDown Cloud Cut Notes
// @name:eo           Markdown Cloud Cut Notes
// @name:es           Notas de corte de nube de markdown
// @name:fi           Markdown Cloud Cut Notes
// @name:fr           Notes de coupe de cloud de Markdown
// @name:fr-CA        Notes de coupe de cloud de Markdown
// @name:he           הערות Culd Cloud Markdown
// @name:hr           Markdown Cloud Cut Notes
// @name:hu           Markdown Cloud Cut jegyzetek
// @name:id           Markdown Cloud Cut Notes
// @name:it           Markdown Cloud Cut Notes
// @name:ja           マークダウンクラウドカットノート
// @name:ka           Markdown Cloud Cut Notes
// @name:ko           마크 다운 클라우드 컷 메모
// @name:nb           Markdown Cloud Cut Notes
// @name:nl           Markdown Cloud Cut Notes
// @name:pl           Notatki z Cloud Cloud Cloud
// @name:pt-BR        Notas de corte na nuvem de marcação
// @name:ro           Note de tăiere a norului markdown
// @name:ru           Примечания к облаку отметки
// @name:sk           Poznámky k mraku cloudu
// @name:sr           Напомена Цлоуд Цлоуд Сцрет Нотес
// @name:sv           Markdown Cloud Cut -anteckningar
// @name:th           MARKDOWN Cloud Cut Notes
// @name:tr           Markdown bulut kesim notları
// @name:ug           ماركېل بۇلۇت ئۈزۈلۈپ قالدى
// @name:uk           Нотатки з вирізанням Cloud Cloud
// @name:vi           Markdown Cloud Cut Ghi chú
// @name:zh           MarkDown 云剪笔记
// @name:zh-CN        MarkDown 云剪笔记
// @name:zh-HK        MarkDown 雲剪筆記
// @name:zh-SG        MarkDown 云剪笔记
// @name:zh-TW        MarkDown 雲剪筆記
// @description       A tool that converts web content to Markdown format, supports features such as copying, downloading, and sending to GitHub and Obsidian.
// @description:ar    تقوم أداة بتحويل محتوى الويب إلى تنسيق Markdown ، ويدعم ميزات مثل نسخ وتنزيل وإرسال Github و Obsidian.
// @description:bg    Инструмент, който преобразува уеб съдържание във формат за маркиране, поддържа функции като копиране, изтегляне и изпращане на GitHub и Obsidian.
// @description:cs    Nástroj, který převádí webový obsah do formátu označení, podporuje funkce, jako je kopírování, stahování a odesílání do GitHubu a obsidiánu.
// @description:da    Et værktøj, der konverterer webindhold til Markdown -format, understøtter funktioner såsom kopiering, download og sender til GitHub og Obsidian.
// @description:de    Ein Tool, das Webinhalte in Markdown -Format umwandelt, unterstützt Funktionen wie das Kopieren, Herunterladen und Senden an GitHub und Obsidian.
// @description:el    Ένα εργαλείο που μετατρέπει το περιεχόμενο ιστού σε μορφή Markdown, υποστηρίζει χαρακτηριστικά όπως η αντιγραφή, η λήψη και η αποστολή στο GitHub και ο Obsidian.
// @description:en    A tool that converts web content to Markdown format, supports features such as copying, downloading, and sending to GitHub and Obsidian.
// @description:eo    Ilo, kiu konvertas retan enhavon al Markdown -formato, subtenas funkciojn kiel kopii, elŝuti kaj sendi al Github kaj Obsidian.
// @description:es    Una herramienta que convierte el contenido web en formato de Markdown, admite características como copiar, descargar y enviar a Github y Obsidian.
// @description:fi    Työkalu, joka muuntaa verkkosisällön merkinnän muotoon, tukee ominaisuuksia, kuten kopiointia, lataamista ja lähettämistä GitHubille ja Obsidianille.
// @description:fr    Un outil qui convertit le contenu Web au format Markdown, prend en charge des fonctionnalités telles que la copie, le téléchargement et l’envoi à GitHub et Obsidian.
// @description:fr-CA Un outil qui convertit le contenu Web au format Markdown, prend en charge des fonctionnalités telles que la copie, le téléchargement et l’envoi à GitHub et Obsidian.
// @description:he    כלי שממיר תוכן אינטרנט לפורמט Markdown, תומך בתכונות כמו העתקה, הורדה ושליחה ל- Github ו- Obsidian.
// @description:hr    Alat koji pretvara web sadržaj u Markdown format, podržava značajke poput kopiranja, preuzimanja i slanja GitHub i Obsidian.
// @description:hu    Egy olyan eszköz, amely a webtartalmat Markdown formátumra konvertálja, támogatja azokat a funkciókat, mint például a másolást, a letöltést és a Github -nak és az Obsidian -nak küldését.
// @description:id    Alat yang mengonversi konten web ke format penurunan harga, mendukung fitur seperti menyalin, mengunduh, dan mengirim ke GitHub dan Obsidian.
// @description:it    Uno strumento che converte i contenuti Web in formato markdown, supporta funzionalità come la copia, il download e l’invio a Github e Obsidian.
// @description:ja    WebコンテンツをMarkdown形式に変換するツールは、GithubやObsidianへのコピー、ダウンロード、送信などの機能をサポートします。
// @description:ka    ინსტრუმენტი, რომელიც გარდაქმნის ვებ შინაარსს MarkDown ფორმატში, მხარს უჭერს ისეთ ფუნქციებს, როგორიცაა კოპირება, ჩამოტვირთვა და გაგზავნა Github და Obsidian.
// @description:ko    웹 컨텐츠를 Markdown 형식으로 변환하는 도구는 복사, 다운로드 및 Github 및 Obsidian으로 전송과 같은 기능을 지원합니다.
// @description:nb    Et verktøy som konverterer nettinnhold til Markdown -format, støtter funksjoner som kopiering, nedlasting og sending til Github og Obsidian.
// @description:nl    Een tool die webinhoud converteert naar Markdown -indeling, ondersteunt functies zoals kopiëren, downloaden en verzenden naar GitHub en Obsidian.
// @description:pl    Narzędzie, które konwertuje treść sieci w formacie Markdown, obsługuje takie funkcje, jak kopiowanie, pobieranie i wysyłanie do Github i Obsidian.
// @description:pt-BR Uma ferramenta que converte o conteúdo da Web em formato de marcação, suporta recursos como cópia, download e envio para o Github e Obsidian.
// @description:ro    Un instrument care convertește conținutul web în format markdown, acceptă funcții precum copierea, descărcarea și trimiterea către Github și Obsidian.
// @description:ru    Инструмент, который преобразует веб -контент в формат разметки, поддерживает такие функции, как копирование, загрузка и отправка в Github и Obsidian.
// @description:sk    Nástroj, ktorý prevádza webový obsah na formát Markdown, podporuje funkcie, ako je kopírovanie, sťahovanie a odosielanie spoločnosti GitHub a Obsidian.
// @description:sr    Алат који претвара Веб садржај у ознаку формата, подржава функције као што су копирање, преузимање и слање Гитхуб-а и Обсидијан.
// @description:sv    Ett verktyg som konverterar webbinnehåll till Markdown -format, stöder funktioner som kopiering, nedladdning och skickning till GitHub och Obsidian.
// @description:th    เครื่องมือที่แปลงเนื้อหาเว็บเป็นรูปแบบ Markdown รองรับคุณสมบัติต่าง ๆ เช่นการคัดลอกการดาวน์โหลดและการส่งไปยัง GitHub และ Obsidian
// @description:tr    Web içeriğini işaretleme biçimine dönüştüren bir araç, GitHub ve Obsidian’a kopyalama, indirme ve gönderme gibi özellikleri destekler.
// @description:ug    تور مەزمۇنىنى بەلگە قىلىپ بەلگە قىلالايدىغان بىر قورال گاتسىيە ۋە Obstidiation غا توپلاش ۋە ئەۋەتىش قاتارلىق ئىقتىدارلارنى قوللايدىغان ئىقتىدارلارنى قوللايدۇ.
// @description:uk    Інструмент, який перетворює веб -вміст у формат Markdown, підтримує такі функції, як копіювання, завантаження та надсилання в Github та Обсидіан.
// @description:vi    Một công cụ chuyển đổi nội dung web thành định dạng đánh dấu, hỗ trợ các tính năng như sao chép, tải xuống và gửi đến GitHub và Obsidian.
// @description:zh    将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
// @description:zh-CN 将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
// @description:zh-HK 將網頁內容轉換為 Markdown 格式的工具,支持複製、下載、發送到 GitHub 和 Obsidian 等功能。
// @description:zh-SG 将网页内容转换为 Markdown 格式的工具,支持复制、下载、发送到 GitHub 和 Obsidian 等功能。
// @description:zh-TW 將網頁內容轉換為 Markdown 格式的工具,支持複製、下載、發送到 GitHub 和 Obsidian 等功能。
// @author            shiquda,人民的勤务员 <[email protected]>
// @namespace         https://github.com/#####GodMan/UserScripts
// @supportURL        https://github.com/#####GodMan/UserScripts/issues
// @homepageURL       https://github.com/#####GodMan/UserScripts
// @license           MIT
// @grant             GM_addStyle
// @grant             GM_registerMenuCommand
// @grant             GM_setClipboard
// @grant             GM_setValue
// @grant             GM_getValue
// @require           https://code.jquery.com/jquery-3.6.0.min.js
// @require           https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
// @require           https://unpkg.com/turndown/dist/turndown.js
// @require           https://unpkg.com/@guyplusplus/turndown-plugin-gfm/dist/turndown-plugin-gfm.js
// @require           https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.0/marked.min.js
// @match             *://*/*
// @icon              data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAABHNCSVQICAgIfAhkiAAABBdJREFUaIHtmluIVlUUx39pMup4Q1FrRi1CrMAaREUS75KlBhKKSGAKzkPRQ0lBPngjkIZeBMWHAccH8VIKJQTSIAgWVBQKglco7YYiitrYjONtjg/7G2bPPmt/nvOdtc8ndn5wQM/+77X+i73PnrPP/qCgoKCg4P/Bi8CGAHFfAj4JEDcTc4GodM1Ujt1aintcOW4mTtFT8GnFuAusuBGwSjF2xdQCdwlj7LwTt1kpbiYGAh30NtauEHe1EzMCtivEVeEEcXObM8bsFGIuyxhTjY3EzUXA4ArjNQmxHmSIp86zwH3iJvdWEGuoECcC9qs4VWQ3stGXU8b52hNnoppTJcYjG/05RYxJnhiHVZ0qcgjZ8OKE/X/x9J+t7lQJ3wj9lqDvUk/fNDOkKhxDNv5+mT5PAb97+r0d0qwG9nu1fV3DvKRIrPX0+SOwVzVOIxfQJGgHA20e/eocvKrwFnIBETDa0W716P7Ny6wWl5AL+cLS1Hs0EfBpnmY1eId4EfeBkZbmsKCJgHu5OlXkBr0Lsb+ITME/uo352tTjA3qKuATUWG1nkYv9M2ePqvSjZwV+17q/HP/ozsvZozpbgAvOvevIxR7N11oYRgLTrP+vxz+6r+TuLjBDkffNEdBSRV/B2IVcbCe9/1w9ETTgn8obq+grGEeQi70MPF1FX0FYiH90V5Y09Zht4hPBGeRi7VOKc8CM/K3pswb/6L7maB6r86NK6APcIl7oAWB6SdMPuGK1rcjfpg79MdNUGlmbz4X2N0OZ0lgkhmCOSF8FxgF1mDPdCR79JuCz0r/7Yz791Aq6m5gp/jdm43EO+J4qbi4WAD/ifz6lqwMY4MRpThnjH2Ad5lHIhT7Alx4zt/FvDHwvGGMw50aSvgv5UK278IYA9cU4KCQ/CyzBTOfhwPOY00Nb04aZ/hLuKF8HFgEvAGMxq/leIe8N4t/IVJkjJD3k0W5zdJvLxB2H+axj6/sKusVC/j3pSkjHN06yyx5dnaO7hdkplWMnyQr50NHdIdAo12CeGzvZex7tt44uyRfIsZhn1u5X79G6W8zXE1WQkjriC4hkaKqjuYZZ6JLgjnKrR/edo/soYfxUPEd8BKRpetzRrE2R4xmnb0TP66fNV47m4xQ5EjMC8zJgJ5ruaJY47TcryNPixDgmaH51NOUO6ipmIPHThIOOxv2ZUZrR7WY48VF+w2qvFdqDvYoeFZLNKrU1Ovc7MuRxPwWdsNpanbYuzIIXhFXEC76D2d795dzPspAME/I0In8T+yFDnkdS7uDavm4r5NqRII873YMwHv/7bfc1VynX1UfkCfHrXZFBwD7BQAfmtxpajAJOCnkuAPMrCZh1P1wDTMZsCv4DfsLsfLSZiNlItGOKvRggR0FBQcHjx0Ng/VhKUt8K3AAAAABJRU5ErkJggg==
// @compatible        chrome
// @compatible        firefox
// @compatible        edge
// @compatible        opera
// @compatible        safari
// @compatible        kiwi
// @compatible        qq
// @compatible        via
// @compatible        brave
// @version           2025.03.19.0450
// @created           2025-03-18 07:13:13
// @modified          2025-03-18 07:13:13
// ==/UserScript==
/**
* File: web-clipper.user.js
* Project: UserScripts
* File Created: 2025/03/18,Tuesday 07:13:13
* Author: 人民的勤务员@#####GodMan ([email protected])
* -----
* Last Modified: 2025/03/19,Wednesday 04:50:15
* Modified By: 人民的勤务员@#####GodMan ([email protected])
* -----
* License: MIT License
* Copyright © 2024 - 2025 #####GodMan,Inc
*/
//! https://greasyfork.org/zh-CN/scripts/486888
(function () {
'use strict'
// User Config
// Short cut
const shortCutUserConfig = {
/* Example:
"Shift": false,
"Ctrl": true,
"Alt": false,
"Key": "m"
*/
}
// Obsidian
const obsidianUserConfig = {
/* Example:
"my note": [
"Inbox/Web/",
"Collection/Web/Reading/"
]
*/
}
const userLang =
(navigator.languages && navigator.languages[0]) ||
navigator.language ||
'en'
const translations = {
en: {
copy: 'Copy to clipboard',
copied: 'Copied successfully!',
download_md: 'Download as MD',
send_to_github: 'Send to Github',
send_to_obsidian: 'Send to Obsidian',
github_failed: 'Creation failed:',
github_success: 'Creation succeeded:',
configure: 'Please configure your GitHub information first',
menu: 'Convert to Markdown',
gui_title: 'Set Up GitHub',
gui_tokeninput: 'Please enter your GitHub Personal Access Token',
gui_github_repo: 'Please enter your GitHub repository name',
gui_github_generate: 'Generate',
gui_github_owner: 'Please enter your GitHub username',
gui_save: 'Save',
gui_cancel: 'Cancel',
guide: `
- Use **arrow keys** to select elements:
- Up: Select parent element
- Down: Select the first child element
- Left: Select the previous sibling element
- Right: Select the next sibling element
- Use **scroll wheel** to zoom in and out:
* Up: Select parent element
- Down: Select the first child element
- Click to select an element
- Press \`Esc\` key to cancel selection
`
},
'zh-CN,zh,zh-SG': {
copy: '复制到剪辑版',
copied: '复制成功!',
download_md: '下载为MD',
send_to_github: '保存到GitHub',
send_to_obsidian: '发送到Obsidian',
github_failed: '创建失败:',
github_success: '创建成功:',
configure: '请先配置你的GitHub信息',
menu: '转换为Markdown',
gui_title: '设置 GitHub',
gui_tokeninput: '请输入您的GitHub个人访问令牌',
gui_github_repo: '请输入您的GitHub仓库名称',
gui_github_generate: '生成',
gui_github_owner: '请输入您的GitHub用户名',
gui_save: '保存',
gui_cancel: '取消',
guide: `
- 使用**方向键**选择元素
- 上:选择父元素
- 下:选择第一个子元素
- 左:选择上一个兄弟元素
- 右:选择下一个兄弟元素
- 使用**滚轮**放大缩小
- 上:选择父元素
- 下:选择第一个子元素
- 点击元素选择
- 按下 \`Esc\` 键取消选择
`
},
'zh-TW,zh-HK,zh-MO': {
copy: '複製到剪貼簿',
copied: '複製成功!',
download_md: '下載為MD',
send_to_github: '保存到GitHub',
send_to_obsidian: '發送到Obsidian',
github_failed: '創建失敗:',
github_success: '創建成功:',
configure: '請先配置你的GitHub 信息',
menu: '轉換為Markdown',
guide: `
- 使用**方向鍵**選擇元素
- 上:選擇父元素
- 下:選擇第一個子元素
- 左:選擇上一個兄弟元素
- 右:選擇下一個兄弟元素
- 使用**滾輪**放大縮小
- 上:選擇父元素
- 下:選擇第一個子元素
- 點擊元素選擇
- 按下 \`Esc\` 鍵取消選擇
`
},
vi: {
copy: 'Sao chép vào clipboard',
copied: 'Sao chép thành công!',
download_md: 'Tải xuống dưới dạng MD',
send_to_github: 'Gửi đến Github',
send_to_obsidian: 'Gửi đến Obsidian',
github_failed: 'Tạo thất bại:',
github_success: 'Tạo thành công:',
configure: 'Vui lòng cấu hình thông tin GitHub của bạn trước',
menu: 'Chuyển đổi sang Markdown',
guide: `
- Sử dụng **phím mũi tên** để chọn các phần tử:
- Lên: Chọn phần tử cha
- Xuống: Chọn phần tử con đầu tiên
- Trái: Chọn phần tử anh em trước
- Phải: Chọn phần tử anh em sau
- Sử dụng **bánh xe cuộn** để phóng to và thu nhỏ:
- Lên: Chọn phần tử cha
- Xuống: Chọn phần tử con đầu tiên
- Nhấp để chọn một phần tử
- Nhấn phím \`Esc\` để hủy chọn
`
},
ja: {
copy: 'クリップボードにコピー',
copied: 'コピー成功!',
download_md: 'MDとしてダウンロード',
send_to_github: 'Githubに送信',
send_to_obsidian: 'Obsidianに送信',
github_failed: '作成失敗:',
github_success: '作成成功:',
configure: 'まずGitHub情報を設定してください',
menu: 'Markdownに変換',
guide: `
- **矢印キー**を使用して要素を選択します:
- 上: 親要素を選択
- 下: 最初の子要素を選択
- 左: 前の兄弟要素を選択
- 右: 次の兄弟要素を選択
- **スクロールホイール**を使用してズームインおよびズームアウトします:
- 上: 親要素を選択
- 下: 最初の子要素を選択
- 要素をクリックして選択
- \`Esc\`キーを押して選択をキャンセル
`
},
ko: {
copy: '클립보드에 복사',
copied: '복사 성공!',
download_md: 'MD로 다운로드',
send_to_github: 'Github에 보내기',
send_to_obsidian: 'Obsidian에 보내기',
github_failed: '생성 실패:',
github_success: '생성 성공:',
configure: '먼저 GitHub 정보를 구성하십시오',
menu: 'Markdown으로 변환',
guide: `
- **화살표 키**를 사용하여 요소를 선택합니다:
- 위: 부모 요소 선택
- 아래: 첫 번째 자식 요소 선택
- 왼쪽: 이전 형제 요소 선택
- 오른쪽: 다음 형제 요소 선택
- **스크롤 휠**을 사용하여 확대 및 축소합니다:
- 위: 부모 요소 선택
- 아래: 첫 번째 자식 요소 선택
- 요소를 선택하려면 클릭
- 선택을 취소하려면 \`Esc\` 키를 누르십시오
`
},
fr: {
copy: 'Copier dans le presse-papiers',
copied: 'Copié avec succès!',
download_md: 'Télécharger en tant que MD',
send_to_github: 'Envoyer à Github',
send_to_obsidian: 'Envoyer à Obsidian',
github_failed: 'Échec de la création:',
github_success: 'Création réussie:',
configure: 'Veuillez d\'abord configurer vos informations GitHub',
menu: 'Convertir en Markdown',
guide: `
- Utilisez les **touches fléchées** pour sélectionner les éléments:
- Haut: Sélectionner l'élément parent
- Bas: Sélectionner le premier élément enfant
- Gauche: Sélectionner l'élément frère précédent
- Droite: Sélectionner l'élément frère suivant
- Utilisez la **molette de défilement** pour zoomer et dézoomer:
- Haut: Sélectionner l'élément parent
- Bas: Sélectionner le premier élément enfant
- Cliquez pour sélectionner un élément
- Appuyez sur la touche \`Esc\` pour annuler la sélection
`
},
it: {
copy: 'Copia negli appunti',
copied: 'Copiato con successo!',
download_md: 'Scarica come MD',
send_to_github: 'Invia a Github',
send_to_obsidian: 'Invia a Obsidian',
github_failed: 'Creazione fallita:',
github_success: 'Creazione riuscita:',
configure: 'Si prega di configurare prima le informazioni di GitHub',
menu: 'Converti in Markdown',
guide: `
- Usa i **tasti freccia** per selezionare gli elementi:
- Su: Seleziona l'elemento padre
- Giù: Seleziona il primo elemento figlio
- Sinistra: Seleziona l'elemento fratello precedente
- Destra: Seleziona l'elemento fratello successivo
- Usa la **rotella di scorrimento** per ingrandire e ridurre:
- Su: Seleziona l'elemento padre
- Giù: Seleziona il primo elemento figlio
- Clicca per selezionare un elemento
- Premi il tasto \`Esc\` per annullare la selezione
`
},
de: {
copy: 'In die Zwischenablage kopieren',
copied: 'Erfolgreich kopiert!',
download_md: 'Als MD herunterladen',
send_to_github: 'An Github senden',
send_to_obsidian: 'An Obsidian senden',
github_failed: 'Erstellung fehlgeschlagen:',
github_success: 'Erstellung erfolgreich:',
configure: 'Bitte konfigurieren Sie zuerst Ihre GitHub-Informationen',
menu: 'In Markdown konvertieren',
guide: `
- Verwenden Sie die **Pfeiltasten**, um Elemente auszuwählen:
- Oben: Elternelement auswählen
- Unten: Erstes Kindelement auswählen
- Links: Vorheriges Geschwisterelement auswählen
- Rechts: Nächstes Geschwisterelement auswählen
- Verwenden Sie das **Scrollrad**, um hinein- und herauszuzoomen:
- Oben: Elternelement auswählen
- Unten: Erstes Kindelement auswählen
- Klicken Sie, um ein Element auszuwählen
- Drücken Sie die \`Esc\`-Taste, um die Auswahl abzubrechen
`
}
}
const getTranslations = (lang) => {
for (const key in translations) {
if (key === lang || key.split(',').includes(lang)) {
return translations[key]
}
}
return translations['en']
}
const translate = new Proxy(
function (key) {
const lang = userLang
const strings = getTranslations(lang)
return strings[key] || translations['en'][key]
},
{
get(target, prop) {
const lang = userLang
const strings = getTranslations(lang)
return strings[prop] || translations['en'][prop]
}
}
)
// 全局变量
var isSelecting = false
var selectedElement = null
let shortCutConfig, obsidianConfig
// 读取配置
// 初始化快捷键配置
let storedShortCutConfig = GM_getValue('shortCutConfig')
if (Object.keys(shortCutUserConfig).length !== 0) {
GM_setValue('shortCutConfig', JSON.stringify(shortCutUserConfig))
shortCutConfig = shortCutUserConfig
} else if (storedShortCutConfig) {
shortCutConfig = JSON.parse(storedShortCutConfig)
}
// 初始化Obsidian配置
let storedObsidianConfig = GM_getValue('obsidianConfig')
if (Object.keys(obsidianUserConfig).length !== 0) {
GM_setValue('obsidianConfig', JSON.stringify(obsidianUserConfig))
obsidianConfig = obsidianUserConfig
} else if (storedObsidianConfig) {
obsidianConfig = JSON.parse(storedObsidianConfig)
}
GM_addStyle(`
.modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);display:flex;justify-content:center;align-items:center;z-index:10000;}
.modal-content{background:white;padding:20px;border-radius:8px;width:400px;box-shadow:0 4px 15px rgba(0,0,0,0.2);position:relative;}
.modal-title{margin:0 0 10px 0;font-size:20px;}
.modal-description{margin-bottom:20px;font-size:14px;color:#666;}
.modal-description a{color:#007bff;text-decoration:underline;}
.modal-close-btn {position: absolute;top: 10px;right: 10px;background-color: red;color: white;border: none;border-radius: 50%;width: 24px;height: 24px;font-size: 16px;cursor: pointer;display: flex;justify-content: center;align-items: center;line-height: 1;}
.modal-close-btn:hover {background-color: darkred;}
.gui-input{width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;margin-bottom:20px;font-size:14px;}
#save-token{background-color:#28a745;color:white;border:none;padding:10px 20px;cursor:pointer;border-radius:4px;margin-right:10px;}
#cancel-token{background-color:#dc3545;color:white;border:none;padding:10px 20px;cursor:pointer;border-radius:4px;}
`)
function showConfig() {
const modalHTML = `
<div class="modal-overlay">
<div class="modal-content">
<h3 class="modal-title">${translate.gui_title}</h3>
<p class="modal-description">${translate.gui_tokeninput}
<a href="https://github.com/settings/tokens/new?description=Web%20Clipper%20Token%20UserScript&scopes=repo" target="_blank" rel="noopener noreferrer">${translate.gui_github_generate}</a>
</p>
<input type="text" id="github-token-input" class="gui-input" placeholder="${translate.gui_tokeninput}">
<p class="modal-description">${translate.gui_github_owner}</p>
<input type="text" id="github-owner-input" class="gui-input" placeholder="${translate.gui_github_owner}">
<p class="modal-description">${translate.gui_github_repo}</p>
<input type="text" id="github-repo-input" class="gui-input" placeholder="${translate.gui_github_repo}">
<button id="save-token">${translate.gui_save}</button>
<button id="cancel-token" class="cancel">${translate.gui_cancel}</button>
</div>
</div>
`
const modalContainer = document.createElement('div')
modalContainer.innerHTML = modalHTML
document.body.appendChild(modalContainer)
const elements = {
token: modalContainer.querySelector('#github-token-input'),
owner: modalContainer.querySelector('#github-owner-input'),
repo: modalContainer.querySelector('#github-repo-input'),
saveButton: modalContainer.querySelector('#save-token'),
cancelButton: modalContainer.querySelector('#cancel-token')
}
elements.token.value = GM_getValue('github_token', '')
elements.owner.value = GM_getValue('OWNER', '')
elements.repo.value = GM_getValue('REPO', '')
elements.saveButton.addEventListener('click', () => {
if (elements.token.value && elements.owner.value && elements.repo.value) {
GM_setValue('github_token', elements.token.value)
GM_setValue('OWNER', elements.owner.value)
GM_setValue('REPO', elements.repo.value)
modalContainer.remove()
} else {
alert(`${translate.configure}`)
}
})
elements.cancelButton.addEventListener('click', () => modalContainer.remove())
}
function showDialog(info, link) {
const modalHTML = `
<div class="modal-overlay">
<div class="modal-content">
<button class="modal-close-btn" id="cancel-token" >×</button>
<h3 class="modal-title">${info}</h3>
<p class="modal-description">
${info}
<a href="${link}" target="_blank" rel="noopener noreferrer">${link}</a>
</p>
</div>
</div>
`
const modalContainer = document.createElement('div')
modalContainer.innerHTML = modalHTML
document.body.appendChild(modalContainer)
modalContainer.querySelector('#cancel-token').addEventListener('click', () => modalContainer.remove())
}
// HTML2Markdown
function convertToMarkdown(element) {
var html = element.outerHTML
let turndownMd = turndownService.turndown(html)
turndownMd = turndownMd.replaceAll('[\n\n]', '[]') // 防止 <a> 元素嵌套的暂时方法,并不完善
return turndownMd
}
// 预览
function showMarkdownModal(markdown) {
var $modal = $(`
<div class="h2m-modal-overlay">
<div class="h2m-modal">
<textarea>${markdown}</textarea>
<div class="h2m-preview">${marked.parse(markdown)}</div>
<div class="h2m-buttons">
<button class="h2m-copy">${translate.copy}</button>
<button class="h2m-download">${translate.download_md}</button>
<button class="h2m-github">${translate.send_to_github}</button>
<select class="h2m-obsidian-select">${translate.send_to_obsidian}</select>
</div>
<button class="h2m-close">X</button>
</div>
</div>
`)
$modal.find('.h2m-obsidian-select').append($('<option>').val('').text(`${translate.send_to_obsidian}`))
for (const vault in obsidianConfig) {
for (const path of obsidianConfig[vault]) {
// 插入元素
const $option = $('<option>')
.val(`obsidian://advanced-uri?vault=${vault}&filepath=${path}`)
.text(`${vault}: ${path}`)
$modal.find('.h2m-obsidian-select').append($option)
}
}
$modal.find('textarea').on('input', function () {
// console.log("Input event triggered");
var markdown = $(this).val()
var html = marked.parse(markdown)
// console.log("Markdown:", markdown);
// console.log("HTML:", html);
$modal.find('.h2m-preview').html(html)
})
$modal.on('keydown', function (e) {
if (e.key === 'Escape') {
$modal.remove()
}
})
$modal.find('.h2m-copy').on('click', function () { // 复制到剪贴板
GM_setClipboard($modal.find('textarea').val())
$modal.find('.h2m-copy').text(`${translate.copied}`)
setTimeout(() => {
$modal.find('.h2m-copy').text(`${translate.copy}`)
}, 1000)
})
$modal.find('.h2m-github').on('click', function () {
const github_token = GM_getValue('github_token', '')
const github_owner = GM_getValue('OWNER', '')
const github_repo = GM_getValue('REPO', '')
if (!github_token || !github_owner || !github_repo) {
showConfig()
return
}
const labels = ['web-clipper']//标签,可多项
const markdown = $modal.find('textarea').val()
const title = markdown.split('\n')[0]
const body = markdown
createIssue(github_token, github_owner, github_repo, title, body, labels)
})
$modal.find('.h2m-download').on('click', function () { // 下载
var markdown = $modal.find('textarea').val()
var blob = new Blob([markdown], { type: 'text/markdown' })
var url = URL.createObjectURL(blob)
var a = document.createElement('a')
a.href = url
// 当前页面标题 + 时间
a.download = `${document.title}-${new Date().toISOString().replace(/:/g, '-')}.md`
a.click()
})
$modal.find('.h2m-obsidian-select').on('change', function () { // 发送到 Obsidian
const val = $(this).val()
if (!val) return
const markdown = $modal.find('textarea').val()
GM_setClipboard(markdown)
const title = document.title.replaceAll(/[\\/:*?"<>|]/g, '_') // File name cannot contain any of the following characters: * " \ / < > : | ?
const url = `${val}${title}.md&clipboard=true`
window.open(url)
})
$modal.find('.h2m-close').on('click', function () { // 关闭按钮 X
$modal.remove()
})
// 同步滚动
// 获取两个元素
var $textarea = $modal.find('textarea')
var $preview = $modal.find('.h2m-preview')
var isScrolling = false
// 当 textarea 滚动时,设置 preview 的滚动位置
$textarea.on('scroll', function () {
if (isScrolling) {
isScrolling = false
return
}
var scrollPercentage = this.scrollTop / (this.scrollHeight - this.offsetHeight)
$preview[0].scrollTop = scrollPercentage * ($preview[0].scrollHeight - $preview[0].offsetHeight)
isScrolling = true
})
// 当 preview 滚动时,设置 textarea 的滚动位置
$preview.on('scroll', function () {
if (isScrolling) {
isScrolling = false
return
}
var scrollPercentage = this.scrollTop / (this.scrollHeight - this.offsetHeight)
$textarea[0].scrollTop = scrollPercentage * ($textarea[0].scrollHeight - $textarea[0].offsetHeight)
isScrolling = true
})
$(document).on('keydown', function (e) {
if (e.key === 'Escape' && $('.h2m-modal-overlay').length > 0) {
$('.h2m-modal-overlay').remove()
}
})
$('body').append($modal)
}
// 开始选择
function startSelecting() {
$('body').addClass('h2m-no-scroll') // 防止页面滚动
isSelecting = true
// 操作指南
tip(marked.parse(translate.guide))
}
// 结束选择
function endSelecting() {
isSelecting = false
$('.h2m-selection-box').removeClass('h2m-selection-box')
$('body').removeClass('h2m-no-scroll')
$('.h2m-tip').remove()
}
function tip(message, timeout = null) {
var $tipElement = $('<div>')
.addClass('h2m-tip')
.html(message)
.appendTo('body')
.hide()
.fadeIn(200)
if (timeout === null) {
return
}
setTimeout(function () {
$tipElement.fadeOut(200, function () {
$tipElement.remove()
})
}, timeout)
}
// Turndown 配置
var turndownPluginGfm = TurndownPluginGfmService
var turndownService = new TurndownService({ codeBlockStyle: 'fenced' })
turndownPluginGfm.gfm(turndownService) // 引入全部插件
// turndownService.addRule('strikethrough', {
//     filter: ['del', 's', 'strike'],
//     replacement: function (content) {
//         return '~' + content + '~'
//     }
// });
// turndownService.addRule('latex', {
//     filter: ['mjx-container'],
//     replacement: function (content, node) {
//         const text = node.querySelector('img')?.title;
//         const isInline = !node.getAttribute('display');
//         if (text) {
//             if (isInline) {
//                 return '$' + text + '$'
//             }
//             else {
//                 return '$$' + text + '$$'
//             }
//         }
//         return '';
//     }
// });
// 添加CSS样式
GM_addStyle(`
.h2m-selection-box {
border: 2px dashed #f00;
background-color: rgba(255, 0, 0, 0.2);
}
.h2m-no-scroll {
overflow: hidden;
z-index: 9997;
}
.h2m-modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
height: 80%;
background: white;
border-radius: 10px;
display: flex;
flex-direction: row;
z-index: 9999;
}
.h2m-modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 9998;
}
.h2m-modal textarea,
.h2m-modal .h2m-preview {
width: 50%;
height: 100%;
padding: 20px;
box-sizing: border-box;
overflow-y: auto;
}
.h2m-modal .h2m-buttons {
position: absolute;
bottom: 10px;
right: 10px;
}
.h2m-modal .h2m-buttons button,
.h2m-modal .h2m-obsidian-select {
margin-left: 10px;
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 13px 16px;
border-radius: 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
transition-duration: 0.4s;
cursor: pointer;
}
.h2m-modal .h2m-buttons button:hover,
.h2m-modal .h2m-obsidian-select:hover {
background-color: #45a049;
}
.h2m-modal .h2m-close {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
width: 25px;
height: 25px;
background-color: #f44336;
color: white;
font-size: 16px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.h2m-tip {
position: fixed;
top: 22%;
left: 82%;
transform: translate(-50%, -50%);
background-color: white;
border: 1px solid black;
padding: 8px;
z-index: 9999;
border-radius: 10px;
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
background-color: rgba(255, 255, 255, 0.7);
}
`)
// 注册触发器
shortCutConfig = shortCutConfig ? shortCutConfig : {
'Shift': false,
'Ctrl': true,
'Alt': false,
'Key': 'm'
}
$(document).on('keydown', function (e) {
if (e.ctrlKey === shortCutConfig['Ctrl'] &&
e.altKey === shortCutConfig['Alt'] &&
e.shiftKey === shortCutConfig['Shift'] &&
e.key.toUpperCase() === shortCutConfig['Key'].toUpperCase()) {
e.preventDefault()
startSelecting()
}
// else {
//     console.log(e.ctrlKey, e.altKey, e.shiftKey, e.key.toUpperCase());
// }
})
// $(document).on('keydown', function (e) {
//     if (e.ctrlKey && e.key === 'm') {
//         e.preventDefault();
//         startSelecting()
//     }
// });
GM_registerMenuCommand(`${translate.menu}`, function () {
startSelecting()
})
GM_registerMenuCommand(`${translate.gui_title}`, function () {
showConfig()
})
$(document).on('mouseover', function (e) { // 开始选择
if (isSelecting) {
$(selectedElement).removeClass('h2m-selection-box')
selectedElement = e.target
$(selectedElement).addClass('h2m-selection-box')
}
}).on('wheel', function (e) { // 滚轮事件
if (isSelecting) {
e.preventDefault()
if (e.originalEvent.deltaY < 0) {
selectedElement = selectedElement.parentElement ? selectedElement.parentElement : selectedElement // 扩大
if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
selectedElement = selectedElement.firstElementChild
}
} else {
selectedElement = selectedElement.firstElementChild ? selectedElement.firstElementChild : selectedElement // 缩小
}
$('.h2m-selection-box').removeClass('h2m-selection-box')
$(selectedElement).addClass('h2m-selection-box')
}
}).on('keydown', function (e) { // 键盘事件
if (isSelecting) {
e.preventDefault()
if (e.key === 'Escape') {
endSelecting()
return
}
switch (e.key) { // 方向键:上下左右
case 'ArrowUp':
selectedElement = selectedElement.parentElement ? selectedElement.parentElement : selectedElement // 扩大
if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') { // 排除HTML 和 BODY
selectedElement = selectedElement.firstElementChild
}
break
case 'ArrowDown':
selectedElement = selectedElement.firstElementChild ? selectedElement.firstElementChild : selectedElement // 缩小
break
case 'ArrowLeft': // 寻找上一个元素,若是最后一个子元素则选择父元素的下一个兄弟元素,直到找到一个元素
var prev = selectedElement.previousElementSibling
while (prev === null && selectedElement.parentElement !== null) {
selectedElement = selectedElement.parentElement
prev = selectedElement.previousElementSibling ? selectedElement.previousElementSibling.lastChild : null
}
if (prev !== null) {
if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
selectedElement = selectedElement.firstElementChild
}
selectedElement = prev
}
break
case 'ArrowRight':
var next = selectedElement.nextElementSibling
while (next === null && selectedElement.parentElement !== null) {
selectedElement = selectedElement.parentElement
next = selectedElement.nextElementSibling ? selectedElement.nextElementSibling.firstElementChild : null
}
if (next !== null) {
if (selectedElement.tagName === 'HTML' || selectedElement.tagName === 'BODY') {
selectedElement = selectedElement.firstElementChild
}
selectedElement = next
}
break
}
$('.h2m-selection-box').removeClass('h2m-selection-box')
$(selectedElement).addClass('h2m-selection-box') // 更新选中元素的样式
}
}
).on('mousedown', function (e) { // 鼠标事件,选择 mousedown 是因为防止点击元素后触发其他事件
if (isSelecting) {
e.preventDefault()
var markdown = convertToMarkdown(selectedElement)
showMarkdownModal(markdown)
endSelecting()
}
})
function createIssue(token, owner, repo, title, body, labels = []) {
const url = `https://api.github.com/repos/${owner}/${repo}/issues`
const issueData = {
title: title,
body: body,
labels: labels
}
const xhr = new XMLHttpRequest()
xhr.open('POST', url, true)
xhr.setRequestHeader('Authorization', `token ${token}`)
xhr.setRequestHeader('Accept', 'application/vnd.github+json')
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
const response = JSON.parse(xhr.responseText)
showDialog(translate.github_success, response.html_url)
} else {
alert(`${translate.github_failed}\n ${xhr.status}\n ${xhr.statusText}\n ${xhr.responseText}`)
console.error(`${translate.github_failed}`, xhr.status, xhr.statusText, xhr.responseText)
}
}
}
xhr.send(JSON.stringify(issueData))
}
})()