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();