您需要先安装一个扩展,例如 篡改猴、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.1.0 // @description Makes cards' heights to be dynamic depending on image height // @author Kenya-West // @match https://*.inoreader.com/* // @icon https://inoreader.com/favicon.ico?v=8 // @license MIT // ==/UserScript== // @ts-check (function () { "use strict"; document.addEventListener('tm_inoreader-viewing-api-for-userscripts_articleAdded', (e) => { const { element } = e.detail?.details; setTimeout(() => { start(element); }, 3500); // the second attempt is needed because some images or videos are loaded after the first attempt setTimeout(() => { start(element); }, 10000); }); const querySelectorPathArticleRoot = ".article_full_contents .article_content"; const querySelectorArticleContentWrapper = ".article_tile_content_wraper"; const querySelectorArticleFooter = ".article_tile_footer"; document.head.insertAdjacentHTML("beforeend", ` <style> .tm_dynamic_height { height: auto !important; } .tm_remove_position_setting { position: unset !important; } </style>`); /** * * @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]); }; })();