Greasy Fork is available in English.
This userscript tries to fit text to screen width after pinch gesture. It tries to replicate text reflow feature from Opera Mobile.
当前为
// ==UserScript==
// @name Text reflow on zoom by pinch gesture (mobile)
// @description This userscript tries to fit text to screen width after pinch gesture. It tries to replicate text reflow feature from Opera Mobile.
// @description:ru Этот скрипт пытается подогнать текст под ширину экрана после жеста увеличения на телефоне. Он воспроизводит функцию переноса текста из Opera Mobile.
// @version 1.0.0
// @author emvaized
// @license MIT
// @namespace text_reflow_on_pinch_zoom
// @match *://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
let isCssInjected = false, isPinching = false;
let zoomTarget, targetDyOffsetRatio;
// Function to adjust only outermost text-containing elements to the viewport width
function processElement(element){
element.classList.add('text-reflowed-userscript')
}
function reflowText() {
if (!isCssInjected) {
const styleContent = `.text-reflowed-userscript { word-wrap: break-word !important; overflow-wrap:break-word !important; max-width:var(--reflow-max-width) !important; }`;
const styleElement = document.createElement("style");
styleElement.textContent = styleContent;
document.head.appendChild(styleElement);
}
const viewportWidth = window.visualViewport.width;
document.documentElement.style.setProperty('--reflow-max-width', `${viewportWidth}px`);
// Select elements likely to contain text
const textElements = Array.from(document.querySelectorAll(
"p, a, h1, h2, h3, h4, h5, h6, li, strong, em, span"
));
textElements.forEach(element => {
processElement(element);
return;
});
/// Scroll initial target element into view
if (zoomTarget && targetDyOffsetRatio) {
setTimeout(t => {
// Scroll element into view horizontally
zoomTarget.scrollIntoView({ behavior: "instant", block: "nearest", inline: "center" });
// Scroll to element vertically, according to new page layout
const targetOffset = targetDyOffsetRatio * window.innerHeight;
const rect = zoomTarget.getBoundingClientRect();
const targetTop = rect.top + window.pageYOffset;
const scrollToPosition = targetTop - targetOffset;
window.scrollTo({
top: scrollToPosition,
behavior: "instant"
});
// Reset the target and offset after scrolling
zoomTarget = null;
targetDyOffsetRatio = null;
}, 5);
}
}
// Detect start of multi-touch (pinch) gesture
function handleTouchStart(event) {
if (!event.touches || event.touches.length >= 2) {
isPinching = true;
// Store info about target element
if (event.target) zoomTarget = event.target;
// Calculate the midpoint between the two touch points
const touch1 = event.touches[0];
const touch2 = event.touches[1];
const midpointX = (touch1.clientX + touch2.clientX) / 2;
const midpointY = (touch1.clientY + touch2.clientY) / 2;
// Use document.elementFromPoint to get the element at the midpoint
zoomTarget = document.elementFromPoint(midpointX, midpointY);
if (!zoomTarget) return;
const targetRect= zoomTarget.getBoundingClientRect();
targetDyOffsetRatio = targetRect.top / window.innerHeight;
}
}
// Detect end of multi-touch (pinch) gesture
function handleTouchEnd(event) {
if (isPinching && (!event.touches || event.touches.length === 0)) {
isPinching = false;
reflowText();
}
}
// Add event listeners
window.addEventListener('touchstart', handleTouchStart);
window.addEventListener('touchend', handleTouchEnd);
/// Uncomment for experimental trackpad support in Safari
// window.addEventListener('gesturestart', handleTouchStart);
// window.addEventListener('gestureend', handleTouchEnd);
})();