// ==UserScript== // @name Zoom In Twitter Image // @version 1.1.4 // @description Support 2019 new UI Twitter only. // @author Hayao-Gai // @namespace https://github.com/HayaoGai // @icon https://i.imgur.com/M9oO8K9.png // @include https://twitter.com/* // @require http://code.jquery.com/jquery-3.4.1.slim.min.js // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; const $ = window.jQuery; const urlLoad = "https://media.giphy.com/media/kDSfTo0HP8v6POpYO3/giphy.gif"; let canvas, zoom, loading, push, showing = false, waiting = false; $(document).ready(() => { createCanvas(); createZoom(); createLoading(); observeSystem(); detectAddress(); detectSwitch(); }); // 定義 Canvas function createCanvas() { canvas = $("
").css({ "position": "fixed", "width": "0px", "height": "0px", "pointerEvents": "none", "background-color": "white", "display": "inline", "opacity": "0", "transition": "opacity 0.4s" }).appendTo("body"); } // 定義 Zoom function createZoom() { zoom = $("").css({ "position": "fixed", "width": document.documentElement.clientWidth + "px", "height": document.documentElement.clientHeight + "px", "pointerEvents": "none", "display": "inline", "opacity": "0", "transition": "opacity 0.4s" }).appendTo("body"); } // 定義 Loading function createLoading() { loading = $("", { src: urlLoad }).css({ "position": "fixed", "width": "44px", "height": "44px", "left": (document.documentElement.clientWidth / 2 - 22) + "px", "top": (document.documentElement.clientHeight / 2 - 22) + "px", "display": "inline", }).appendTo("body"); loading.hide(); } // 觀察文件是否產生變化 function observeSystem() { setTimeout(() => { const h1 = $("section").find("H1"); const title = $("title"); if (h1.length === 0 || title.length === 0) observeSystem(); else { // 獲取目標 const target1 = [...h1[0].parentElement.childNodes].filter(child => child.tagName !== "H1")[0].childNodes[0].childNodes[0]; // 目標錯誤 if (target1.className == "css-1dbjc4n r-1adg3ll") observeSystem(); else { const target2 = title[0]; // 先執行一次 setTimeout(addListener, 1000); // 建立觀察者,文件有變化就執行下列函式 const mutation = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; //前綴 const observer = new mutation(addListener); // 設定觀察選項 const config = { attributes: true, childList: true, characterData: true }; // 開始觀察 observer.observe(target1, config); //時間軸 observer.observe(target2, config); //標籤頁 } } }, 500); } // 偵測是否僅切換地址 function detectAddress() { let pushState = history.pushState; history.pushState = function () { pushState.apply(history, arguments); observeSystem(); }; } // 偵測上一頁、下一頁 function detectSwitch() { window.addEventListener("popstate", observeSystem); } // 增加監聽的物件 function addListener() { if (location.href.match("photo/1")) return; //點進圖片後,不做放大效果 // 縮圖 $(".css-9pa8cd").each((index, image) => { $(image).on("mousemove", showImage); $(image).on("mouseleave", hideImage); }); // 展開按鈕 $('[role="button"]').each((index, button) => { $(button).on("click", observeSystem); }); // 上方標籤 $('[role="tab"]').each((index, tab) => { $(tab).on("click", () => { setTimeout(() => observeSystem, 3000); }); }); } // 顯示圖片 function showImage() { // 避免多次呼叫 if (showing) return; showing = true; // 取得圖片原始尺寸的網址 const url = getImage(this.src); if (url === null) return; // 設定圖片網址 zoom.attr("src", url); setImage(); } // 設定圖片 function setImage() { // 等待至取得圖片寬高為止 if (zoom[0].naturalWidth === 0) { // 避免 loading 不消失 if (!waiting) loading.show(); waiting = true; setTimeout(setImage, 20); return; } // 關掉 Loading loading.hide(); // 調整圖片大小 const w = zoom[0].naturalWidth; const h = zoom[0].naturalHeight; const clientW = document.documentElement.clientWidth; const clientH = document.documentElement.clientHeight; const condition1 = w > clientW; const condition2 = h > clientH; if (condition1 && condition2) { const rate = clientH / h; const new_w = w * rate; const new_h = clientH; if (new_w > clientW) { const rate2 = clientW / new_w; const new_w2 = clientW; const new_h2 = new_h * rate2; canvas.css({ "width": new_w2 + "px", "height": new_h2 + "px" }); zoom.css({ "width": (new_w2 - 10) + "px", "height": (new_h2 - 10) + "px" }); } else { canvas.css({ "width": new_w + "px", "height": new_h + "px" }); zoom.css({ "width": (new_w - 10) + "px", "height": (new_h - 10) + "px" }); } } else if (condition1) { const rate3 = clientW / w; const new_h3 = h * rate3; canvas.css({ "width": clientW + "px", "height": new_h3 + "px" }); zoom.css({ "width": (clientW - 10) + "px", "height": (new_h3 - 10) + "px" }); } else if (condition2) { const rate4 = clientH / h; const new_w4 = w * rate4; canvas.css({ "width": new_w4 + "px", "height": clientH + "px" }); zoom.css({ "width": (new_w4 - 10) + "px", "height": (clientH - 10) + "px" }); } else { canvas.css({ "width": (w + 10) + "px", "height": (h + 10) + "px" }); zoom.css({ "width": w + "px", "height": h + "px" }); } // 圖片位置 let cLeft = clientW / 2 - canvas.width() / 2; let cTop = clientH / 2 - canvas.height() / 2; if (cLeft < 0) cLeft = 0; if (cTop < 0) cTop = 0; let zLeft = clientW / 2 - zoom.width() / 2; let zTop = clientH / 2 - zoom.height() / 2; if (zLeft < 0) zLeft = 0; if (zTop < 0) zTop = 0; // 調整圖片屬性 canvas.css({ "left": cLeft + "px", "top": cTop + "px", "display": "inline", "opacity": "1" }); zoom.css({ "left": zLeft + "px", "top": zTop + "px", "display": "inline", "opacity": "1" }); } // 取得圖片網址 function getImage(url) { // 如果沒網址就直接跳開 if (url === null) return null; // 網域 const m1 = url.split("/"); let newUrl = "https://pbs.twimg.com/"; // 狀況 1:一般圖 if (m1[3].match("media") !== null) { for (let i = 3; i < m1.length; i++) { if (i !== m1.length - 1) newUrl += m1[i] + "/"; else newUrl += m1[i].split("&")[0] + "&name=orig"; } } // 狀況 2:使用者頭像 else if (m1[3].match("profile") !== null) { for (let i = 3; i < m1.length; i++) { if (i !== m1.length - 1) newUrl += m1[i] + "/"; else { const m2 = m1[i].split("_"); for (let i = 0; i < m2.length; i++) { if (i === 0) newUrl += m2[i]; else if (i !== m2.length - 1) newUrl += "_" + m2[i]; else newUrl += "." + m2[i].split(".")[1]; } } } } // 狀況 3:影片 => 不放大縮圖 else { newUrl = null; } return newUrl; } // 隱藏圖片 function hideImage() { showing = false; waiting = false; // 重置 畫布 canvas.css({ "width": "0px", "height": "0px", "display": "none", "opacity": "0" }); zoom.attr("src", null); zoom.css({ "width": "0px", "height": "0px", "display": "none", "opacity": "0" }); // 重置 Loading setTimeout(() => { loading.hide(); }, 50); } })();