Discord - Open chat in popup

Adds a "open in popup" button to channels.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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