您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a "open in popup" button to channels.
// ==UserScript== // @name Discord - Open chat in popup // @namespace lleaff // @supportURL https://gist.github.com/lleaff/8514033dc8e54ce02d6adf3c2e46d8ff#comments // @match https://discordapp.com/channels/* // @version 1 // @run-at document-end // @grant none // @noframes // @description Adds a "open in popup" button to channels. // ==/UserScript== /* =Configuration *------------------------------------------------------------*/ const POPUP_WIDTH /*: pixels */ = 400; const WAIT_FOR_LOAD_TRY_INTERVAL /*: milliseconds */ = 0.5e3; /* =DOM Utilities *------------------------------------------------------------*/ const $ = (selector, el) => Array.from((el || document).querySelectorAll(selector)); function hideAllSiblings(el) { const siblings = getSiblings(el); siblings.forEach(el => el.style.display = 'none'); } function getSiblings(el) { const all = Array.from(el.parentNode.childNodes); return all.filter(child => child !== el); } /** * Open and return a popup window. Ususally blocked by browser by default. * @param options - https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Position_and_size_features */ function openPopup(url, name, options) { const opts = Object.assign({ menubar: false, location: false, resizable: true, scrollbars: false, status: false }, options); const convertOptVal = val => { switch(val) { case false: return 'no'; case true: return 'yes'; default: return val; } } const optionsStr = Object.keys(opts) .map(key =>`${key}=${convertOptVal(opts[key])}`, '') .join(','); return window.open(url, name || `popup:${encodeURI(url)}`, optionsStr); } /* =Main window *------------------------------------------------------------*/ /** * Main function to be executed on main page */ function mainBootstrap() { const contacts = $('.channel:not(.btn-friends)'); if (!contacts.length) { return false; } contacts.forEach(contact => { addOpenPopupBtn(contact); }); } /* =Popup button *------------------------------------------------------------*/ function addOpenPopupBtn(el) { const btn = createOpenPopupBtnDOM(); btn.addEventListener('click', (e) => { openChatPopup(el); e.preventDefault(); }); const closeButton = $('.close', el)[0]; closeButton.parentNode.insertBefore(btn, closeButton); } function createOpenPopupBtnDOM() { let btn = document.createElement('button'); btn.className = 'close'; btn.style.backgroundImage = "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAAAEgAAABIAEbJaz4AAAEGSURBVCjPZZChS0NxFIW/9zZQ1Dnf3IYwu2AUu3+BYLOJgsWkWdAyMAiCYclgFy3+EYIGq6xoGiLIwoTN4dw+w5Pxe3puu+e73MNBglmxZaiRz2SA2G3bGWSIGFm0YsWqJWN37YVEnhJ7bFAA+pxxTY08oWw48N2mTesmHvuZeSF2bLlm2bIz/21FfXBWxH37gfOVZokBEZhknYnx5wHnHNAG1HsLItYdjq9PnTJ2x9cQmPPC71973k0Tc66GACaeeOehRY98tCqSBTDntJFln2xaEckDUVDLkC4QEWO6yNNjgSWaATZimTIvfKXAFVvc8Japd5GEWzpp1TUv7f6p78OGpTTVD4gGJTUFNt2qAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTEwLTIxVDA5OjQ0OjIzLTA1OjAwu1bogAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0xMC0yMVQwOTo0NDoyMy0wNTowMMoLUDwAAAAASUVORK5CYII=')"; return btn; } function openChatPopup(contactDiv) { const linkEl = $('a', contactDiv)[0]; if (!linkEl) { return false; } const url = linkEl.href; const popup = openPopup(url, 'popup', { width: POPUP_WIDTH }); if (!popup) { return; } const script = document.createElement('script'); script.innerHTML = `var IS_GM_POPUP = true;`; popup.document.head.appendChild(script); return popup; } /* =Popup *------------------------------------------------------------*/ /** * Main function to be executed on popup page */ function mainPopup() { if (!hideAllButChat()) { return false; } } function hideAllButChat() { const chat = $('.chat')[0]; if (!chat) { return false; } hideAllSiblings(chat); return true; } /* =Script running *------------------------------------------------------------*/ /** * Try running a function until it returns something other than `null` or `false`. */ function tryRunFunc(fn, interval) { if ([null, false].includes(fn())) { setTimeout(() => tryRunFunc(fn, interval), interval) } } function main() { const in_popup = typeof IS_GM_POPUP !== 'undefined'; const mainFunc = in_popup ? mainPopup : mainBootstrap; tryRunFunc(mainFunc, WAIT_FOR_LOAD_TRY_INTERVAL); } /* =Execution *------------------------------------------------------------*/ main();