LeetCode Assistant

【使用前先看介绍/有问题可反馈】力扣助手 (LeetCode Assistant):为力扣页面增加辅助功能。

Od 11.09.2021.. Pogledajte najnovija verzija.

// ==UserScript==
// @name         LeetCode Assistant
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  【使用前先看介绍/有问题可反馈】力扣助手 (LeetCode Assistant):为力扣页面增加辅助功能。
// @author       cc
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.js
// @require      https://greatest.deepsurf.us/scripts/422854-bubble-message.js
// @match        https://leetcode-cn.com/problems/*
// @match        https://leetcode-cn.com/problemset/all/
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
  var executing = false;
  const bm = new BubbleMessage();
  const config = {
    recommendVisible: false,
  };

  // 通用
  function updateData(obj) {
    var data = GM_getValue('data');
    if (!obj) {
      // 初始化调用
      if (!data) {
        // 未初始化
        data = {};
        Object.assign(data, config);
        GM_setValue('data', data);
      } else {
        // 已初始化
        Object.assign(config, data);
      }
    } else {
      // 更新调用
      Object.assign(config, obj);
      Object.assign(data, config);
      GM_setValue('data', data);
    }
  }

  function insertTextarea() {
    let textarea = document.createElement('textarea');
    textarea.setAttribute('id', 'leetcode-assistant-textarea');
    document.body.appendChild(textarea);
  }

  function executeCopy(value) {
    let textarea = document.getElementById('leetcode-assistant-textarea');
    textarea.value = value;
    textarea.setAttribute('value', value);
    textarea.select();
    document.execCommand('copy');
    bm.message({
      type: 'success',
      message: '复制成功',
      duration: 1500,
    });
  }

  function switchVisible(nodes, visible) {
    if (visible) {
      nodes.forEach(node => node.style.display = '');
    } else {
      nodes.forEach(node => node.style.display = 'none');
    }
  }

  function observeChildList(node, callback) {
    let observer = new MutationObserver(function(mutations) {
      mutations.forEach((mutation) => {
        if (mutation.type == 'childList' && mutation.addedNodes.length > 0) {
          callback([...mutation.addedNodes]);
        }
      });
    });
    observer.observe(node, { childList: true });
  }

  function listenHistoryState() {
    const _historyWrap = function(type) {
      const orig = history[type];
      const e = new Event(type);
      return function() {
          const rv = orig.apply(this, arguments);
          e.arguments = arguments;
          window.dispatchEvent(e);
          return rv;
        };
      };
    history.pushState = _historyWrap('pushState');
    window.addEventListener('pushState', () => {
      if (!executing) {
        executing = true;
        main();
      }
    });
  }

  // 提交记录页
  function requestCode(qid) {
    let query = `
      query mySubmissionDetail($id: ID!) {
        submissionDetail(submissionId: $id) {
          id
          code
          runtime
          memory
          rawMemory
          statusDisplay
          timestamp
          lang
          passedTestCaseCnt
          totalTestCaseCnt
          sourceUrl
          question {
            titleSlug
            title
            translatedTitle
            questionId
            __typename
          }
          ... on GeneralSubmissionNode {
            outputDetail {
              codeOutput
              expectedOutput
              input
              compileError
              runtimeError
              lastTestcase
              __typename
            }
            __typename
          }
          submissionComment {
            comment
            flagType
            __typename
          }
          __typename
        }
      }`;
    $.ajax({
      url: 'https://leetcode-cn.com/graphql/',
      method: 'POST',
      contentType: 'application/json',
      data: JSON.stringify({
        operationName: 'mySubmissionDetail',
        query: query,
        variables: {
          id: qid
        },
      }),
    }).then(res => {
      executeCopy(res.data.submissionDetail.code);
    });
  }

  function insertCopyFunction() {
    let tbody = document.querySelector('.ant-table-tbody');
    let trs = [...tbody.querySelectorAll('tr')];
    let processTr = (tr) => {
      let qid = tr.dataset.rowKey;
      let cell = tr.querySelector(':nth-child(4)');
      cell.title = '点击复制代码'
      cell.style = 'cursor: pointer; color: #007aff';
      cell.addEventListener('click', function() {
        requestCode(qid);
      });
    }
    trs.forEach(processTr);
    observeChildList(tbody, (nodes) => {
      let node = nodes[0];
      if (node.tagName == 'TR')
        processTr(node);
    });
    executing = false;
  }

  // 首页
  function switchRecommendVisible() {
    var nodes = [];
    var target = document.querySelector('.border-divider-border-2');
    while (target) {
      nodes.push(target);
      target = target.previousElementSibling;
    }
    var sidebar = document.querySelector('.col-span-4:nth-child(2)');
    target = sidebar.querySelector('.space-y-4:nth-child(2)');
    while (target) {
      nodes.push(target);
      target = target.nextElementSibling;
    }
    switchVisible(nodes, config.recommendVisible);
    observeChildList(sidebar, (nodes) => {
      switchVisible(nodes, config.recommendVisible);
    });
  }
  
  function insertVisibleSwitch() {
    var insertDiv = document.querySelector('.relative.space-x-5').nextElementSibling;
    insertDiv.style = 'display: inline-flex; align-items: center;';
    var switchCheckbox = document.createElement('input');
    switchCheckbox.type = 'checkbox';
    switchCheckbox.checked = true;
    switchCheckbox.setAttribute('id', 'leetcode-assistant-recommend-switch');
    switchCheckbox.addEventListener('change', function() {
      updateData({ recommendVisible: !this.checked });
      switchRecommendVisible();
    });
    var switchLabel = document.createElement('label');
    switchLabel.setAttribute('for', 'leetcode-assistant-recommend-switch');
    switchLabel.innerText = '简洁模式';
    switchLabel.style.marginLeft = '5px';
    insertDiv.appendChild(switchCheckbox);
    insertDiv.appendChild(switchLabel);
  }

  // 主函数
  function main() {
    if (location.href.match(/\/submissions\/$/)) {
      (function r() {
        if (document.querySelector('.ant-table-thead')) {
          insertCopyFunction();
        } else {
          setTimeout(r, 500);
        }
      })();
    } else if (location.href == 'https://leetcode-cn.com/problemset/all/') {
      insertVisibleSwitch();
      switchRecommendVisible();
    } else {
      executing = false;
    }
  }

  window.addEventListener('load', () => {
    updateData();
    insertTextarea();
    listenHistoryState();
    main();
  });
})();