Greasy Fork is available in English.
从知网文献中直接复制引文,支持多种引文格式:BibTeX、GB/T 7714-2015、知网研学、CAJ-CD、MLA、APA、Refworks、EndNote、NoteExpress、NodeFirst
// ==UserScript== // @name 知网-文献-bibtex提取 // @namespace https://github.com/BNDou/getCnkiLiteratureBibTex // @description 从知网文献中直接复制引文,支持多种引文格式:BibTeX、GB/T 7714-2015、知网研学、CAJ-CD、MLA、APA、Refworks、EndNote、NoteExpress、NodeFirst // @license AGPL License // @version 4.2.1 // @author BN_Dou // @match *://kns.cnki.net/kcms2/article/abstract* // @match *://kns.cnki.net/kcms/detail* // @match *://kns.cnki.net/kns8s/defaultresult/index* // @match *://kns.cnki.net/kns8s/search* // @match *://kns.cnki.net/kns8s/AdvSearch* // @grant GM_registerMenuCommand // @grant GM_setClipboard // @grant GM_getValue // @grant GM_setValue // @icon https://www.cnki.net/favicon.ico // ==/UserScript== (function () { 'use strict'; // 引文类型定义 const CITATION_TYPES = { 'BibTeX': 'BibTex', 'GB/T 7714-2015': 'GBTREFER', '知网研学': 'elearning', 'CAJ-CD': 'REFER', 'MLA': 'MLA', 'APA': 'APA', 'Refworks': 'Refworks', 'EndNote': 'EndNote', 'NoteExpress': 'NoteExpress', 'NodeFirst': 'NodeFirst' }; // 获取当前引文类型 let currentCitationType = GM_getValue('citationType', 'BibTeX'); // 更新按钮文本 function updateButtonText() { // 更新普通按钮 const buttons = document.querySelectorAll('[id^="bibbtn"]'); buttons.forEach(button => { if (button.querySelector('span')) { button.querySelector('span').textContent = currentCitationType; } }); // 更新批量复制按钮 const batchLink = document.querySelector('#batch_bibbtn_li a'); if (batchLink) { batchLink.textContent = `批量复制${currentCitationType}`; } } // 更新菜单项 function updateMenuItems() { // 添加菜单项 for (const [typeName, _] of Object.entries(CITATION_TYPES)) { GM_registerMenuCommand(`🔄 切换到 ${typeName}`, () => switchCitationType(typeName)); } } // 切换引文类型 function switchCitationType(type) { currentCitationType = type; GM_setValue('citationType', type); updateButtonText(); } // 样式定义 const STYLES = { button: ` width: 65px; height: 25px; border-radius: 12px; background-color: #0f5de5; border: none; color: white; font-size: 12px; font-weight: 600; text-align: center; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(15, 93, 229, 0.3); display: flex; align-items: center; justify-content: center; gap: 4px; position: relative; z-index: 1; `, advSearchButton: ` width: 100%; height: 24px; padding: 0 8px; border-radius: 8px; background-color: #f0f0f0; border: 1px solid #ddd; color: #0f5de5; font-size: 12px; font-weight: normal; text-align: center; cursor: pointer; transition: all 0.2s ease; margin: 4px 0; display: inline-flex; align-items: center; justify-content: center; gap: 2px; `, successAnimation: ` @keyframes successPulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } ` }; let citationText = ''; // 创建并注入样式 function injectStyles() { const styleSheet = document.createElement('style'); styleSheet.textContent = STYLES.successAnimation; document.head.appendChild(styleSheet); } // 创建按钮 function createButton(isAdvSearch = false) { const button = document.createElement('button'); button.id = "bibbtn"; button.title = "点击复制引文"; button.innerHTML = `<span>${currentCitationType}</span>`; button.style.cssText = isAdvSearch ? STYLES.advSearchButton : STYLES.button; if (isAdvSearch) { // 高级检索页面的悬停效果 button.addEventListener('mouseover', () => { button.style.backgroundColor = '#e8e8e8'; button.style.borderColor = '#ccc'; }); button.addEventListener('mouseout', () => { button.style.backgroundColor = '#f0f0f0'; button.style.borderColor = '#ddd'; }); } else { // 原有页面的悬停效果 button.addEventListener('mouseover', () => { button.style.backgroundColor = '#0d4fc3'; button.style.transform = 'translateY(-1px)'; button.style.boxShadow = '0 4px 12px rgba(15, 93, 229, 0.4)'; }); button.addEventListener('mouseout', () => { button.style.backgroundColor = '#0f5de5'; button.style.transform = 'translateY(0)'; button.style.boxShadow = '0 2px 8px rgba(15, 93, 229, 0.3)'; }); } return button; } // 显示复制成功提示 function showCopySuccess(button) { const element = document.getElementById(button); if (!element) return; if (button === 'batch_bibbtn_li') { // 批量复制按钮的处理 const batchLink = element.querySelector('a'); if (!batchLink) return; const originalText = batchLink.textContent; batchLink.textContent = '✅ 已复制'; batchLink.style.animation = 'successPulse 0.5s ease'; setTimeout(() => { batchLink.textContent = originalText; batchLink.style.animation = ''; }, 1500); } else { // 普通按钮的处理 const originalText = element.innerHTML; // 检查是否为检索页面的按钮 const isSearchPageButton = button.startsWith('bibbtn_'); element.innerHTML = `<span style="color: ${isSearchPageButton ? '#0f5de5' : 'white'};">✅ 已复制</span>`; element.style.animation = 'successPulse 0.5s ease'; setTimeout(() => { element.innerHTML = originalText; element.style.animation = ''; }, 1500); } } // 获取引文数据 async function getCitationText(filename = null) { try { let params; if (filename) { // 高级检索页面的情况 params = { FileName: filename, DisplayMode: CITATION_TYPES[currentCitationType], OrderParam: 0, OrderType: 'desc', }; } else { // 默认情况 params = { FileName: document.getElementById("paramdbname").getAttribute("value") + '!' + document.getElementById("paramfilename").getAttribute("value") + '!1!0', DisplayMode: CITATION_TYPES[currentCitationType], OrderParam: 0, OrderType: 'desc', }; } // const response = await fetch('https://kns.cnki.net/dm/api/ShowExport', { const response = await fetch('https://kns.cnki.net/dm8/api/ShowExport', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Referer': 'https://kns.cnki.net/dm/manage/export.html', }, body: new URLSearchParams(params), }); const data = await response.text(); // 创建一个临时的div来解析HTML const tempDiv = document.createElement('div'); tempDiv.innerHTML = data; let sText = ''; const displayMode = CITATION_TYPES[currentCitationType].toUpperCase(); // 使用类似官方的提取逻辑 if (displayMode === 'MLA' || displayMode === 'APA') { // 对于MLA和APA格式,直接获取文本内容 const items = tempDiv.querySelectorAll('ul.literature-list li'); sText = Array.from(items) .map(item => item.textContent .replace(/\r/g, '') .replace(/\n/g, '') .replace(/ /g, '') .replace(/ /g, '')) .join('\n'); } else if (displayMode === "NODEFIRST") { // 对于NODEFIRST格式,直接获取文本内容 const items = tempDiv.querySelectorAll('ul.literature-list li'); sText = Array.from(items) .map(item => item.innerHTML .replace(/</g, "<") .replace(/>/g, ">") .replace(/\r/g, "") .replace(/\n/g, "") .replace(/<BR>/g, "\r\n") .replace(/<br>/g, "\r\n")) .join('\n'); } else { // 对于其他格式 const items = tempDiv.querySelectorAll('ul.literature-list>li'); sText = Array.from(items) .map(item => { let text = item.innerHTML .replace(/\r/g, '') .replace(/\n/g, '') .replace(/<BR>/g, '\n') .replace(/<br>/g, '\n') .replace(/</g, '<') .replace(/>/g, '>') .replace(/ /g, ' ') .replace(/ {/g, '{') .replace(/ /g, ''); // 根据不同格式处理空格 if (displayMode === 'GBTREFER') { text = text.replace(/ /g, ''); } else if (displayMode === 'REFER' || displayMode === 'NEW' || displayMode === 'NEWDEFINE') { text = text.replace(/ /g, ''); } else if (displayMode === 'SELFDEFINE') { text = text.replace(/ /g, ''); } else if (displayMode === 'BIBTEX') { text = text.replace(/author = \{(\s+)/g, 'author = {').replace(/(\s+)and(\s+)/g, ' and '); } // 移除所有HTML标签 text = text.replace(/<\/?.+?\/?>/g, ''); return text; }) .join('\n'); } if (!sText) { throw new Error('未找到引文数据'); } return sText; } catch (error) { console.error('获取引文失败:', error); return null; } } // 复制引文到剪贴板 async function copyText(buttonId = 'bibbtn', filename = null) { const citationContent = await getCitationText(filename); if (citationContent) { GM_setClipboard(citationContent); showCopySuccess(buttonId); } } // 初始化 function initialize() { injectStyles(); // 初始化菜单 updateMenuItems(); // 根据页面URL决定按钮添加位置 const currentURL = window.location.href; if (currentURL.includes('https://kns.cnki.net/kns8s/defaultresult/index') || currentURL.includes('https://kns.cnki.net/kns8s/AdvSearch') || currentURL.includes('https://kns.cnki.net/kns8s/search')) { // 高级检索页面 - 添加定时检测 // 添加批量操作按钮 function addBatchButton() { const batchOpsBox = document.getElementById('batchOpsBox'); if (batchOpsBox && !batchOpsBox.querySelector('li[id="batch_bibbtn_li"]')) { // 创建新的li元素 const batchLi = document.createElement('li'); batchLi.id = 'batch_bibbtn_li'; batchLi.className = 'export'; // 创建链接 const batchLink = document.createElement('a'); batchLink.href = 'javascript:void(0)'; batchLink.textContent = `批量复制${currentCitationType}`; batchLink.style.color = '#0f5de5'; // 为链接绑定点击事件 batchLink.addEventListener('click', () => { const checkedBoxes = document.querySelectorAll('.cbItem:checked'); if (checkedBoxes.length === 0) { alert('请先选择要复制的文献'); return; } const values = Array.from(checkedBoxes).map(cb => cb.value).join(','); copyText('batch_bibbtn_li', values); }); // 组装元素 batchLi.appendChild(batchLink); batchOpsBox.appendChild(batchLi); } } // 定义检测和添加按钮的函数 function checkAndAddButtons() { // 添加批量操作按钮 addBatchButton(); // 添加单个操作按钮 const operatElements = document.querySelectorAll('.operat, .opts ul.opts-btn'); Array.from(operatElements).forEach((element, index) => { // 检查该行是否已有按钮 if (element.querySelector('button[id^="bibbtn_"]')) return; const button = createButton(true); // 传入true表示是高级检索页面 button.id = `bibbtn_${index}`; // 为opts创建li元素 if (element.classList.contains('opts-btn')) { const li = document.createElement('li'); li.appendChild(button); element.insertBefore(li, element.firstChild); } else { element.insertBefore(button, element.firstChild); } let filename_param = ''; if (element.classList.contains('opts-btn')) { // 对于opts情况,从父级dd中查找cbItem const dd = element.closest('dd'); if (dd) { const cbItem = dd.querySelector('.cbItem'); if (cbItem) { filename_param = cbItem.value; } } } else { // 对于operat情况,从tr中查找cbItem const resultItem = element.closest('tr'); if (resultItem) { const cbItem = resultItem.querySelector('.cbItem'); if (cbItem) { filename_param = cbItem.value; } } } if (filename_param) { // 为按钮绑定点击事件 $(`#bibbtn_${index}`).click(() => { copyText(`bibbtn_${index}`, filename_param); }); } }); } // 启动定时检测 setInterval(checkAndAddButtons, 1000); } else { // 默认处理 const otherButtons = document.getElementsByClassName('other-btns')[0]; if (otherButtons) { // 创建按钮元素 const li = document.createElement('li'); li.className = 'btn-bibtex'; li.style.cssText = ` width: 65px; height: 25px; `; const button = createButton(); li.appendChild(button); // 插入到第一个位置 otherButtons.insertBefore(li, otherButtons.firstChild); // 绑定点击事件 $("#bibbtn").click(() => copyText()); } } } // 启动脚本 initialize(); })();