Greasy Fork is available in English.

去掉飞书虚拟滚动

去掉飞书虚拟滚动,连接整个网页

// ==UserScript==
// @name         去掉飞书虚拟滚动
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  去掉飞书虚拟滚动,连接整个网页
// @author       You
// @match        https://*.feishu.cn/docx/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=feishu.cn
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  "use strict";
  async function accumulate() {
    const scrollContainer = document.querySelector(".bear-web-x-container");
    const contentContainer = document.querySelector(".render-unit-wrapper");
    await setScrollTop();
    const frag = await scroll(scrollContainer, contentContainer);
    return frag;
  }

  function appendFragment(frag) {
    document.body.innerHTML = "";
    document.body.appendChild(frag);
    document.body.style.cssText = `
        width: 80%;
        padding: 0 100px;
        margin: auto;
        height: auto;
        overflow: auto;
    `;
  }

  function scroll(el, container, options) {
    let resolve;
    const promise = new Promise((r) => (resolve = r));
    const fragment = observe(container);
    const { scrollGap, scrollInterval } = Object.assign(
      {
        scrollGap: 300,
        scrollInterval: 200,
      },
      options
    );

    let lastScrollHeight = -1;

    const end = (window.stop = () => {
      clearInterval(interval);
      resolve(fragment);
    });
    const interval = setInterval(() => {
      if (el.scrollTop === lastScrollHeight) {
        end();
        return;
      }
      lastScrollHeight = el.scrollTop;
      el.scrollBy(0, scrollGap);
    }, scrollInterval);

    return promise;
  }

  function observe(target, callback) {
    const fragment = (window.f = document.createDocumentFragment());

    appendNodes(target.childNodes);

    function appendNodes(nodes) {
      for (let node of [...nodes]) {
        if (
          node.hasAttribute("data-block-id") &&
          !node.classList.contains("isEmpty")
        ) {
          fragment.appendChild(node.cloneNode(true));
        }
      }
    }

    const observer = new MutationObserver((mutationsList) => {
      for (let mutation of mutationsList) {
        if (mutation.type === "childList") {
          setTimeout(() => {
            appendNodes(mutation.addedNodes);
          }, 2000);
        }
      }

      if (callback) {
        callback(fragment);
      }
    });

    observer.observe(target, {
      childList: true,
    });

    return fragment;
  }

  async function setScrollTop() {
    const els = document.querySelectorAll(".catalogue__item-title");
    let anchor;
    for (let i = 0; i < els.length; i++) {
      let el = els[i];
      if (el.innerText.includes("上课")) {
        anchor = el;
      }
    }
    anchor.click();
    await wait(2000);
  }

  async function wait(ms) {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve();
      }, ms);
    });
  }

  async function waitPageLoad() {
    return new Promise((resolve) => {
      if (document.readyState === "complete") resolve();
      window.addEventListener("load", async (event) => {
        await wait(1000);
        resolve();
      });
    });
  }

  async function main() {
    await waitPageLoad();
    const frag = await accumulate();
    appendFragment(frag);
  }

  main();
})();