您需要先安装一个扩展,例如 篡改猴、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.2.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 // @grant GM_addStyle // @license MIT // ==/UserScript== // @ts-check (async function () { const arriveEventConfigArticle = { fireOnAttributesModification: false, existing: true }; const style = ` .tm_dynamic_height { height: auto !important; } .tm_remove_position_setting { position: unset !important; } `; // @ts-ignore GM_addStyle(style); // @ts-ignore const arrive = await import("https://cdnjs.cloudflare.com/ajax/libs/arrive/2.5.2/arrive.min.js"); // @ts-ignore document.querySelector("#reader_pane")?.arrive(".ar", arriveEventConfigArticle, (article) => start(article)); const querySelectorPathArticleRoot = ".article_full_contents .article_content"; const querySelectorArticleContentWrapper = ".article_tile_content_wraper"; const querySelectorArticleFooter = ".article_tile_footer"; function start(element) { if (notHaveDynamicHeight(element)) { // @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 content 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} */ 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"); } }); } } /** * Checks if article already has dynamic height set. */ function notHaveDynamicHeight(element) { return element?.hasChildNodes() && element?.id?.includes("article_") && element?.classList.contains("ar") && !element?.classList.contains("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]); }; })();