// ==UserScript== // @name Ovearleaf-BibTex // @namespace com.jw23.overleaf // @version 0.1.1 // @description the script will make you search bibtex easily in overleaf // @author jw23 // @match https://www.overleaf.com/project/* // @require https://cdn.jsdelivr.net/npm/@floating-ui/core@1.6.8 // @require https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.6.12 // @require https://cdn.jsdelivr.net/npm/simple-notify@1.0.6/dist/simple-notify.min.js // @resource notifycss https://cdn.jsdelivr.net/npm/simple-notify/dist/simple-notify.css // @grant GM_setClipboard // @grant GM_xmlhttpRequest // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @license MIT // @downloadURL none // ==/UserScript== /* ==UserConfig== configure: origin: title: Orgin description: choose google scholar or its mirror type: select bind: $origins ==/UserConfig== */ // configure the origin const origins = ["https://scholar.google.com.hk", "https://scholar.lanfanshu.cn", "https://xs.vygc.top"] let oldOrigins = GM_getValue("origins", []); const mergedArray = [...new Set([...origins, ...oldOrigins])]; GM_setValue("origins", mergedArray) // If you are not using scriptable cat, just change the https://scholar.google.com.hk let currentOrigin = () => { return GM_getValue("configure.origin", "https://scholar.google.com.hk") } let scholarIcon = ``; let showBox = false; let scholarURL = query => `${currentOrigin()}/scholar?hl=zh-CN&as_sdt=0%2C5&q=${query}&oq=a`; let scholarRefPageURL = id => `${currentOrigin()}/scholar?q=info:${id}:scholar.google.com/&output=cite&scirp=1&hl=zh-CN`; (function () { 'use strict'; GM_addStyle(GM_getResourceText('notifycss')) injectScript() setInterval(() => { if (!document.getElementById('toggleIcon')) { injectScript() } }, 2000) })(); function injectScript() { // query element by className waitUtil('div.ol-cm-toolbar-button-group.ol-cm-toolbar-end', el => { let iconBox = createToggleIcon(); el.appendChild(iconBox); let popupBox = createBox(); let oldPopup = document.querySelector("#popup"); // toggle the search box with the icon. if (oldPopup) { popupBox = oldPopup; } document.body.appendChild(popupBox) popupBox.addEventListener('keydown', env => { if (env.key === 'Enter') { queryArticle() } }) FloatingUIDOM.autoUpdate(iconBox, popupBox, () => { FloatingUIDOM.computePosition(iconBox, popupBox, { middleware: [FloatingUICore.shift(), FloatingUICore.flip(), FloatingUICore.offset(6)], }).then(({ x, y }) => { Object.assign(popupBox.style, { top: `${y}px`, left: `${x}px` }) }) }) iconBox.onclick = (ev) => { if (showBox) { showBox = false; popupBox.style.display = 'none'; } else { showBox = true; popupBox.style.display = 'block'; } } let searchIcon = document.getElementById('search-word'); let content = document.getElementById("search-content"); content.onclick = (env) => { if (env.target.className == 'scholar-data') { let id = env.target.getAttribute("data-cid"); getBibTex(id).then(bib => { new Notify({ status: 'success', title: 'Copy successfully', text: 'Bib has been copied to clipboard', effect: 'slide', type: 'filled' }) GM_setClipboard(bib); }).catch(_ => { new Notify({ status: 'error', title: "Copy failed", text: "Failed to get bib tex", effect: "slide", type: "filled" }) }) } } searchIcon.onclick = () => { queryArticle() } }) } function queryArticle() { let content = document.getElementById("search-content"); content.innerHTML = "Loading......" let word = document.querySelector('input.search-input').value; getArticleIDList(word).then(async lists => { let searchText = ""; lists.forEach((article) => { let articleId = article.id; searchText += scholarContent(`${article.title}@${article.author}`, articleId) }) return searchText }).then(text => { content.innerHTML = text; }); } function waitUtil(el, callback, timeout = 6000) { let query = setInterval(() => { let target = document.querySelector(el) if (target) { // 如果找到了目标元素,则清除查询任务 clearInterval(query) callback(target) } }) // 超时则清除查询任务 setTimeout(() => { clearInterval(query) }, timeout) } function createToggleIcon() { let iconBox = document.createElement('div'); iconBox.className = 'ol-cm-toolbar-button'; iconBox.style.display = 'flex'; iconBox.style.justifyContent = 'center'; iconBox.style.alignItems = 'center'; iconBox.id = "toggleIcon" iconBox.innerHTML = scholarIcon; return iconBox; } // create box to show search box and result box function createBox() { let box = document.createElement('div'); box.id = "popup" box.style = 'width:265px;background:#eef;padding:5px;border:1px solid #ccc;border-radius:5px;position: absolute;display:none;top:0px;left:0px'; box.innerHTML = `
` return box; } function scholarContent(ref, cid) { return `
${ref}
` } // query article list , the function returns article ids function getArticleIDList(query) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: scholarURL(query), method: "GET", onload: response => { let parser = new DOMParser(); let doc = parser.parseFromString(response.responseText, 'text/html'); let searchItems = doc.querySelectorAll('div[data-cid]'); let articlesIDs = []; searchItems.forEach((article, key) => { let cid = article.getAttribute('data-cid'); try { let title = article.querySelector("h3").textContent; let author = article.querySelector("div.gs_a").textContent; if (!cid.startsWith("gs") && key <= 8) { articlesIDs.push({ id: cid, title: title, author: author }); } } catch (err) { console.log(err) } }) resolve(articlesIDs) }, onerror: err => { reject(err) } }) }) } // get reference page by ID function getRefPage(id) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: scholarRefPageURL(id), method: "GET", onload: res => { resolve(res.response) }, onerror: err => { reject(err) } }) }) } function getGBRef(id) { return getRefPage(id).then(page => { let dom = document.createElement("div"); dom.innerHTML = page; let refs = dom.querySelectorAll("#gs_citt tr"); for (let ref of refs) { let v = ref.querySelector('.gs_citr').textContent.trim(); let styleName = ref.querySelector('.gs_cith').textContent.trim(); if ("GB/T 7714" == styleName) { return v; } } }) } function getBibTex(id) { return new Promise((resolve, reject) => { getRefPage(id).then(page => { let dom = document.createElement("div"); dom.innerHTML = page; let first = dom.querySelector("#gs_citi>a.gs_citi").href; return GM_xmlhttpRequest({ url: first, method: "GET", onload: (res) => { resolve(res.responseText); }, onerror: err => { console.log("获取bib发生了错误:", err); reject(err) } }); }) }) }