您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Non-brittle shim for expanding titles in the media card for posts that restores the full string. Also adds hover-to-expand CSS. You will be able to see titles without any truncation. (Version agnostic)
当前为
// ==UserScript== // @name Kemono Longer Expanded Title Cards on Hover // @namespace http://tampermonkey.net/ // @version 2.1 // @description Non-brittle shim for expanding titles in the media card for posts that restores the full string. Also adds hover-to-expand CSS. You will be able to see titles without any truncation. (Version agnostic) // @match https://kemono.cr/* // @run-at document-start // @grant none // @license MIT // ==/UserScript== (function () { "use strict"; // 1) Inject CSS immediately (works even if the shim fails for any reason) try { const style = document.createElement("style"); style.textContent = ` .post-card__header { padding: 5px !important; z-index: 1 !important; color: #fff !important; white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; max-width: 100% !important; display: block !important; position: relative !important; } .post-card__header:hover { white-space: normal !important; overflow: visible !important; background: #2e1905 !important; color: #fff !important; padding: 4px 6px !important; z-index: 9999 !important; position: absolute !important; width: auto !important; max-width: 300px !important; border-radius: 6px !important; }`; (document.head || document.documentElement).appendChild(style); } catch (e) { // ignore } // 2) Inject a minimal page-context shim that targets only: // "".concat(X.slice(0, 50), "...") // It returns the original full X, not the 50-char slice. // This avoids brittle function replacement and bundler assumptions. const shim = function () { try { const S = String.prototype; const origSlice = S.slice; const origConcat = S.concat; // Side channel to connect slice -> concat for the exact pattern let lastSliceValue = null; let lastSliceSource = null; Object.defineProperty(S, "slice", { configurable: true, writable: true, value: function (start, end) { // Call the real slice first const src = String(this); const out = origSlice.call(src, start, end); // Only record when pattern matches exactly slice(0, 50) and src was // actually longer (so truncation was intended). if ( start === 0 && end === 50 && typeof out === "string" && src.length > 50 ) { lastSliceValue = out; lastSliceSource = src; } else { // Any other slice clears the channel lastSliceValue = null; lastSliceSource = null; } return out; }, }); Object.defineProperty(S, "concat", { configurable: true, writable: true, value: function (...args) { // Only target: "".concat(<recent-slice-0-50>, "...") // i.e. receiver is "", 2 args, last is "...", first equals the last // recorded slice result. try { if ( (this === "" || String(this) === "") && args.length === 2 && args[1] === "..." && typeof args[0] === "string" && lastSliceValue !== null && args[0] === lastSliceValue ) { // Return the original full string (undo truncation entirely) return lastSliceSource; } } catch (e) { // fall through to original } return origConcat.apply(this, args); }, }); } catch (e) { // If anything goes wrong, fail silently rather than breaking the page } }; // Ensure the shim runs in the page context (not the userscript sandbox) try { const s = document.createElement("script"); s.textContent = `(${shim})();`; (document.head || document.documentElement).appendChild(s); s.remove(); } catch (e) { // ignore } })();