I normally use mobile phone to navigate around the forum but anytime I come to make post or make a reply I find it difficult to figure out some things when making my post or reply.
The challenge i normally faced when typing in the reply box, I realized that anytime I'm typing the cursor normally get out of my view especially if the post is long, and as for me I normally zoom the reply box because if I decided to leave it like that i can't be able to see clearly, so I decided to make a tools for myself so that the cursor will be visible even though I zoom the reply box.
What it's does?It eliminate stress of scrolling side(left /right) with your hand just to see what you're typing and also it makes you focus directly to what you are typing.
How it works? Get a tempermonkey extension and insert the userscript below.
// ==UserScript==
// @name Bitcointalk Keep Caret Visible v2
// @namespace https://bitcointalk.org/
// @version 2.0
// @description Keeps the caret visible inside Bitcointalk textareas and scrolls the page to keep the active editor in view.
// @match https://bitcointalk.org/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const CONFIG = {
textareaMarginLines: 2,
pageMarginPx: 120,
smoothPageScroll: true,
smoothBehavior: 'smooth',
debug: false
};
function log(...args) {
if (CONFIG.debug) console.log('[BTT Caret]', ...args);
}
function isVisible(el) {
if (!el || !el.isConnected) return false;
const style = getComputedStyle(el);
return style.display !== 'none' &&
style.visibility !== 'hidden' &&
el.offsetParent !== null;
}
function toPxNumber(value, fallback = 0) {
const n = parseFloat(value);
return Number.isFinite(n) ? n : fallback;
}
function getLineHeight(style) {
let lh = toPxNumber(style.lineHeight, NaN);
if (!Number.isFinite(lh)) {
const fs = toPxNumber(style.fontSize, 16);
lh = fs * 1.2;
}
return lh;
}
function copyTextareaStyles(src, dst) {
const style = getComputedStyle(src);
const props = [
'boxSizing',
'width',
'height',
'overflowX',
'overflowY',
'borderTopWidth',
'borderRightWidth',
'borderBottomWidth',
'borderLeftWidth',
'borderStyle',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontStyle',
'fontVariant',
'fontWeight',
'fontStretch',
'fontSize',
'lineHeight',
'fontFamily',
'textAlign',
'textTransform',
'textIndent',
'textDecoration',
'letterSpacing',
'wordSpacing',
'tabSize',
'MozTabSize',
'whiteSpace',
'wordBreak',
'overflowWrap'
];
props.forEach((prop) => {
dst.style[prop] = style[prop];
});
return style;
}
function getCaretCoordinates(textarea, position) {
const mirror = document.createElement('div');
const span = document.createElement('span');
const style = copyTextareaStyles(textarea, mirror);
mirror.style.position = 'absolute';
mirror.style.visibility = 'hidden';
mirror.style.left = '-999999px';
mirror.style.top = '0';
mirror.style.whiteSpace = 'pre-wrap';
mirror.style.wordWrap = 'break-word';
mirror.style.overflow = 'hidden';
const value = textarea.value;
const before = value.slice(0, position);
const after = value.slice(position);
mirror.textContent = before;
span.textContent = after.length ? after[0] : '\u200b';
mirror.appendChild(span);
document.body.appendChild(mirror);
const paddingTop = toPxNumber(style.paddingTop);
const paddingLeft = toPxNumber(style.paddingLeft);
const coords = {
top: span.offsetTop + paddingTop,
left: span.offsetLeft + paddingLeft
};
document.body.removeChild(mirror);
return coords;
}
function keepCaretVisibleInTextarea(textarea) {
if (!textarea || textarea.selectionStart == null || !isVisible(textarea)) return;
const style = getComputedStyle(textarea);
const lineHeight = getLineHeight(style);
const margin = lineHeight * CONFIG.textareaMarginLines;
const caret = getCaretCoordinates(textarea, textarea.selectionStart);
const visibleTop = textarea.scrollTop;
const visibleBottom = visibleTop + textarea.clientHeight;
const caretTop = caret.top;
const caretBottom = caretTop + lineHeight;
let nextScrollTop = textarea.scrollTop;
if (caretBottom + margin > visibleBottom) {
nextScrollTop = Math.max(0, caretBottom - textarea.clientHeight + margin);
} else if (caretTop - margin < visibleTop) {
nextScrollTop = Math.max(0, caretTop - margin);
}
if (Math.abs(nextScrollTop - textarea.scrollTop) > 1) {
textarea.scrollTop = nextScrollTop;
}
}
function getViewportTop() {
return window.pageYOffset || document.documentElement.scrollTop || 0;
}
function getViewportBottom() {
return getViewportTop() + window.innerHeight;
}
function scrollPageToKeepTextareaVisible(textarea) {
if (!textarea || !isVisible(textarea)) return;
const rect = textarea.getBoundingClientRect();
const
I stand to be corrected, and I'm open for any new knowledge.