您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Makes cards' heights to be dynamic depending on image height
当前为
- // ==UserScript==
- // @name InoReader dynamic height of tiles in the card view
- // @namespace http://tampermonkey.net/
- // @version 0.0.4
- // @description Makes cards' heights to be dynamic depending on image height
- // @author Kenya-West
- // @match https://*.inoreader.com/feed*
- // @match https://*.inoreader.com/article*
- // @match https://*.inoreader.com/folder*
- // @match https://*.inoreader.com/starred*
- // @match https://*.inoreader.com/library*
- // @match https://*.inoreader.com/dashboard*
- // @match https://*.inoreader.com/web_pages*
- // @match https://*.inoreader.com/trending*
- // @match https://*.inoreader.com/commented*
- // @match https://*.inoreader.com/recent*
- // @match https://*.inoreader.com/search*
- // @match https://*.inoreader.com/channel*
- // @match https://*.inoreader.com/teams*
- // @match https://*.inoreader.com/dashboard*
- // @match https://*.inoreader.com/pocket*
- // @match https://*.inoreader.com/liked*
- // @match https://*.inoreader.com/tags*
- // @icon https://inoreader.com/favicon.ico?v=8
- // @license MIT
- // ==/UserScript==
- // @ts-check
- (function () {
- "use strict";
- document.head.insertAdjacentHTML("beforeend", `
- <style>
- .tm_dynamic_height {
- height: auto !important;
- }
- .tm_remove_position_setting {
- position: unset !important;
- }
- </style>`);
- const appConfig = {
- corsProxy: "https://corsproxy.io/?",
- };
- const appState = {
- tmObserverArticleListLinked: false,
- };
- // Select the node that will be observed for mutations
- const targetNode = document.body;
- // Options for the observer (which mutations to observe)
- const mutationObserverGlobalConfig = {
- attributes: false,
- childList: true,
- subtree: true,
- };
- const querySelectorPathArticleRoot =
- ".article_full_contents .article_content";
- const querySelectorArticleContentWrapper = ".article_tile_content_wraper";
- const querySelectorArticleFooter = ".article_tile_footer";
- /**
- * Callback function to execute when mutations are observed
- * @param {MutationRecord[]} mutationsList - List of mutations observed
- * @param {MutationObserver} observer - The MutationObserver instance
- */
- const callback = function (mutationsList, observer) {
- for (let mutation of mutationsList) {
- if (mutation.type === "childList") {
- mutation.addedNodes.forEach(function (node) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- stylizeCardsInList(node);
- }
- });
- }
- }
- };
- /**
- *
- * @param {Node} node
- * @returns {void}
- */
- function stylizeCardsInList(node) {
- /**
- * @type {MutationObserver | undefined}
- */
- let tmObserverArticleList;
- const readerPane = document.body.querySelector("#reader_pane");
- if (readerPane) {
- if (!appState.tmObserverArticleListLinked) {
- appState.tmObserverArticleListLinked = true;
- /**
- * Callback function to execute when mutations are observed
- * @param {MutationRecord[]} mutationsList - List of mutations observed
- * @param {MutationObserver} observer - The MutationObserver instance
- */
- const callback = function (mutationsList, observer) {
- for (let mutation of mutationsList) {
- if (mutation.type === "childList") {
- mutation.addedNodes.forEach(function (node) {
- if (node.nodeType === Node.ELEMENT_NODE) {
- if (appState.tmObserverArticleListLinked) {
- setTimeout(() => {
- start(node);
- }, 3500);
- // the second attempt is needed because some images or videos are loaded after the first attempt
- setTimeout(() => {
- start(node);
- }, 10000);
- }
- }
- });
- }
- }
- };
- // Options for the observer (which mutations to observe)
- const mutationObserverLocalConfig = {
- attributes: false,
- childList: true,
- subtree: false,
- };
- // Create an observer instance linked to the callback function
- tmObserverArticleList = new MutationObserver(callback);
- // Start observing the target node for configured mutations
- tmObserverArticleList.observe(
- readerPane,
- mutationObserverLocalConfig
- );
- }
- } else {
- appState.tmObserverArticleListLinked = false;
- tmObserverArticleList?.disconnect();
- }
- /**
- *
- * @param {Node} node
- */
- function start(node) {
- /**
- * @type {Node & HTMLDivElement}
- */
- // @ts-ignore
- const element = node;
- if (
- element.hasChildNodes() &&
- element.id.includes("article_") &&
- element.classList.contains("ar") &&
- !element.classList.contains("tm_dynamic_height")
- ) {
- // @ts-ignore
- const cardWidth = element.clientWidth ?? element.offsetWidth ?? element.scrollWidth;
- // @ts-ignore
- const cardHeight = element.clientHeight ?? element.offsetHeight ?? element.scrollHeight;
- // 1. Set card height dynamic
- setDynamicHeight(element);
- // 2. Set cotnent wrapper height dynamic
- const articleContentWrapperElement = element.querySelector(
- querySelectorArticleContentWrapper
- );
- if (articleContentWrapperElement) {
- setDynamicHeight(articleContentWrapperElement);
- }
- // 3. Remove position setting from article footer
- const articleFooter = element.querySelector(
- querySelectorArticleFooter
- );
- if (articleFooter) {
- removePositionSetting(articleFooter);
- }
- // 4. Find image height
- /**
- * @type {HTMLDivElement | null}
- */
- const divImageElement = element.querySelector(
- "a[href] > .article_tile_picture[style*='background-image']"
- );
- if (!divImageElement) {
- return;
- }
- const imageUrl = getImageLink(divImageElement);
- if (!imageUrl) {
- return;
- }
- const dimensions = getImageDimensions(imageUrl);
- // 5. Set image height (and - automatically - the card height)
- dimensions.then(([width, height]) => {
- if (height > 0) {
- const calculatedHeight = Math.round(
- (cardWidth / width) * height
- );
- const pictureOldHeight =
- (divImageElement.clientHeight ??
- divImageElement.offsetHeight ??
- divImageElement.scrollHeight) ||
- cardHeight;
- /**
- * @type {HTMLDivElement}
- */
- // @ts-ignore
- const div = divImageElement;
- if (calculatedHeight > pictureOldHeight) {
- div.style.height = `${calculatedHeight}px`;
- }
- // 5.1. Set card class to `.tm_dynamic_height` to not process it again next time
- element.classList?.add("tm_dynamic_height");
- }
- });
- }
- }
- /**
- *
- * @param {Element} element
- * @returns {void}
- */
- function setDynamicHeight(element) {
- element.classList?.add("tm_dynamic_height");
- }
- /**
- *
- * @param {Element} element
- * @returns {void}
- */
- function removeDynamicHeight(element) {
- const div = element.querySelector("img");
- if (!div) {
- return;
- }
- div.classList?.remove("tm_dynamic_height");
- }
- /**
- *
- * @param {Element} element
- * @returns {void}
- */
- function removePositionSetting(element) {
- element.classList?.add("tm_remove_position_setting");
- }
- /**
- *
- * @param {Element} element
- * @returns {void}
- */
- function restorePositionSetting(element) {
- element.classList?.remove("tm_remove_position_setting");
- }
- /**
- *
- * @param {HTMLDivElement} div
- * @returns {string | null}
- */
- function getImageLink(div) {
- const backgroundImageUrl = div?.style.backgroundImage;
- /**
- * @type {string | undefined}
- */
- let imageUrl;
- try {
- imageUrl = backgroundImageUrl?.match(/url\("(.*)"\)/)?.[1];
- } catch (error) {
- imageUrl = backgroundImageUrl?.slice(5, -2);
- }
- if (!imageUrl || imageUrl == "undefined") {
- return null;
- }
- if (!imageUrl?.startsWith("http")) {
- console.error(
- `The image could not be parsed. Image URL: ${imageUrl}`
- );
- return null;
- }
- return imageUrl;
- }
- /**
- *
- * @param {string} url
- * @returns {Promise<[number, number]>}
- */
- async function getImageDimensions(url) {
- const img = new Image();
- img.src = url;
- try {
- await img.decode();
- } catch (error) {
- return Promise.reject(error);
- }
- return Promise.resolve([img.width, img.height]);
- };
- }
- // Create an observer instance linked to the callback function
- const tmObserverDynamicHeight = new MutationObserver(callback);
- // Start observing the target node for configured mutations
- tmObserverDynamicHeight.observe(targetNode, mutationObserverGlobalConfig);
- /**
- *
- * @param {Function | void} mainFunction
- * @param {number} delay
- * @returns
- */
- function debounce(mainFunction, delay) {
- // Declare a variable called 'timer' to store the timer ID
- /**
- * @type {number}
- */
- let timer;
- // Return an anonymous function that takes in any number of arguments
- /**
- * @param {...any} args
- * @returns {void}
- */
- return function (...args) {
- // Clear the previous timer to prevent the execution of 'mainFunction'
- clearTimeout(timer);
- // Set a new timer that will execute 'mainFunction' after the specified delay
- timer = setTimeout(() => {
- // @ts-ignore
- mainFunction(...args);
- }, delay);
- };
- }
- })();