Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Holotower Thread Status Updater
- // @namespace http://holotower.org/
- // @version 1.4.1
- // @author Anonymous
- // @description Adds accurate post counts, favicon notifications, and other features to Holotower
- // @icon https://boards.holotower.org/favicon.gif
- // @match *://boards.holotower.org/*/res/*
- // @match *://holotower.org/*/res/*
- // @run-at document-end
- // ==/UserScript==
- (function() {
- 'use strict';
- // === Settings ===
- const settings = JSON.parse(localStorage.getItem("Thread Settings")) || {};
- const showDeletedCounter = settings.showDeletedCounter ?? true;
- const showDeletedIcon = settings.showDeletedIcon ?? true;
- const showDeletedText = settings.showDeletedText ?? false;
- const hideDeleted = settings.hideDeletedPosts ?? false;
- const showArchivedMessage = settings.showArchivedMessage ?? true;
- const enableFaviconChanges = settings.faviconUpdater ?? true;
- const notifyNewPost = settings.notifyNewPost ?? true;
- const notifyNewYou = settings.notifyNewYou ?? true;
- const changeFaviconOnArchive = settings.changeFaviconOnArchive ?? true;
- const showUnreadLine = settings.showUnreadLine ?? true;
- const appendQuotes = settings.appendQuotes ?? true;
- const appendCrossThread = settings.appendCrossThread ?? false;
- const FAVICON_URL = window.location.hostname === 'boards.holotower.org'
- ? 'https://boards.holotower.org/favicon.gif'
- : 'https://holotower.org/favicon.gif';
- let alertState = 'none';
- let lastPostCount = null;
- let lastSeenPostId = 0;
- let lastLine = 0;
- let hasUnreadLine = false;
- let previousStyle = '';
- let currentThreadId = null;
- let lowPostWarningCount = 0;
- let isLargeDrop = false;
- function setFavicon(url) {
- let link = document.querySelector("link[rel*='icon']") || document.createElement('link');
- link.type = 'image/x-icon';
- link.rel = 'shortcut icon';
- link.href = url;
- if (!link.parentNode) document.head.appendChild(link);
- }
- function updateFavicon(color) {
- if (alertState === 'red' && color === 'white') return;
- if (alertState === color) return;
- const img = new Image();
- img.onload = () => {
- const canvas = document.createElement('canvas');
- canvas.width = img.width;
- canvas.height = img.height;
- const ctx = canvas.getContext('2d');
- ctx.drawImage(img, 0, 0);
- ctx.beginPath();
- ctx.arc(canvas.width - 16, 16, 5, 0, 2 * Math.PI);
- ctx.fillStyle = color;
- ctx.fill();
- setFavicon(canvas.toDataURL('image/x-icon'));
- alertState = color;
- };
- img.src = FAVICON_URL;
- }
- function updateFaviconArchived() {
- if (!changeFaviconOnArchive) return;
- const img = new Image();
- img.onload = () => {
- const canvas = document.createElement('canvas');
- canvas.width = img.width;
- canvas.height = img.height;
- const ctx = canvas.getContext('2d');
- ctx.drawImage(img, 0, 0);
- ctx.globalCompositeOperation = 'source-atop';
- ctx.fillStyle = 'red';
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- setFavicon(canvas.toDataURL('image/x-icon'));
- };
- img.src = FAVICON_URL;
- }
- function revertFavicon() {
- if (alertState !== 'none') {
- setFavicon(FAVICON_URL);
- alertState = 'none';
- }
- }
- window.addEventListener('scroll', () => {
- if (window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 2) {
- revertFavicon();
- removeUnreadLine();
- }
- });
- const appendedPostIds = new Set();
- function appendPosts(post) {
- const body = post.querySelector('.body');
- if (!body) return;
- const postId = post.id.split('_')[1];
- appendedPostIds.add(postId);
- const smallTags = body.querySelectorAll('small');
- let visibleCount = 0;
- for (let j = 0; j < smallTags.length; j++) {
- if (getComputedStyle(smallTags[j]).display !== 'none') visibleCount++;
- }
- const skipAppendingYou = visibleCount < smallTags.length;
- for (let j = 0; j < smallTags.length; j++) {
- const small = smallTags[j];
- const label = small.textContent.trim();
- if (label !== '(You)' && label !== '(OP)') continue;
- const isVisible = getComputedStyle(small).display !== 'none';
- let target = small.previousSibling;
- while (target && (target.nodeType !== 1 || target.tagName !== 'A')) {
- target = target.previousSibling;
- }
- if (target?.tagName !== 'A') continue;
- if (isVisible) {
- small.setAttribute('style', 'display: none !important;');
- if (label === '(You)' && skipAppendingYou) continue;
- if (!target.textContent.includes(label)) {
- target.textContent += ` ${label}`;
- }
- } else if (label !== '(You)' && !target.textContent.includes(label)) {
- target.textContent += ` ${label}`;
- }
- }
- const links = body.querySelectorAll('a[href*="/res/"]');
- for (let j = 0; j < links.length; j++) {
- const link = links[j];
- const href = link.getAttribute('href');
- const match = href?.match(/\/res\/(\d+)\.html#(\d+)/);
- if (!match) continue;
- const linkThreadId = match[1];
- const quotedPostId = match[2];
- const hasFollowingSmall = link.nextSibling &&
- link.nextSibling.nodeType === 1 &&
- link.nextSibling.tagName === 'SMALL';
- if (quotedPostId === currentThreadId && !hasFollowingSmall && !link.textContent.includes('(OP)')) {
- link.textContent += ' (OP)';
- }
- if (linkThreadId !== currentThreadId && !hasFollowingSmall && !link.textContent.includes('→') && !link.textContent.includes('(Cross-thread)')) {
- link.textContent += appendCrossThread ? ' (Cross-thread)' : ' →';
- }
- }
- }
- function initializePosts() {
- const lastPostCountEl = document.getElementById("thread_stats_posts");
- if (lastPostCountEl) {
- lastPostCount = parseInt(lastPostCountEl.textContent, 10);
- }
- const posts = document.querySelectorAll('div.post.reply');
- if (posts.length) {
- const lastPost = posts[posts.length - 1];
- const lastPostId = lastPost.id.split('_')[1];
- lastSeenPostId = lastPostId;
- lastLine = lastPostId;
- }
- if (appendQuotes) {
- for (let i = 0; i < posts.length; i++) {
- const post = posts[i];
- const postId = post.id.split('_')[1];
- if (!appendedPostIds.has(postId)) {
- appendPosts(post);
- }
- }
- }
- }
- function addUnreadLine() {
- if (!showUnreadLine) return;
- const lastPost = document.querySelector(`#reply_${lastLine}`);
- if (lastPost && !hasUnreadLine) {
- previousStyle = lastPost.getAttribute('style') || '';
- lastPost.style.boxShadow = '0 3px red';
- hasUnreadLine = true;
- }
- }
- function removeUnreadLine() {
- if (!showUnreadLine) return;
- const lastPost = document.querySelector(`#reply_${lastLine}`);
- if (lastPost && hasUnreadLine) {
- if (previousStyle) {
- lastPost.setAttribute('style', previousStyle);
- } else {
- lastPost.removeAttribute('style');
- }
- lastLine = lastSeenPostId;
- hasUnreadLine = false;
- }
- }
- function updateThreadStatsActual() {
- if (lastPostCount !== null) {
- const oldElement = document.getElementById('thread_stats_posts');
- if (oldElement) {
- oldElement.style.display = 'none';
- let newElement = document.getElementById('thread_stats_posts_actual');
- if (!newElement) {
- newElement = document.createElement('span');
- newElement.id = 'thread_stats_posts_actual';
- oldElement.parentNode.insertBefore(newElement, oldElement.nextSibling);
- }
- newElement.textContent = lastPostCount;
- const postsDeleted = parseInt(oldElement.textContent) - lastPostCount;
- if (showDeletedCounter) {
- let deletedElement = document.getElementById('thread_stats_posts_deleted');
- if (postsDeleted >= 1) {
- if (!deletedElement) {
- deletedElement = document.createElement('span');
- deletedElement.id = 'thread_stats_posts_deleted';
- const imagesElement = document.getElementById('thread_stats_images');
- if (imagesElement) {
- imagesElement.parentNode.insertBefore(deletedElement, imagesElement);
- }
- }
- deletedElement.textContent = postsDeleted;
- deletedElement.insertAdjacentHTML('beforeend', ' deleted | ');
- } else if (deletedElement) {
- deletedElement.remove();
- }
- }
- if (lastPostCount >= 1500) {
- if (enableFaviconChanges && changeFaviconOnArchive) {
- updateFaviconArchived();
- }
- if (showArchivedMessage && !document.getElementById('archived-msg')) {
- addArchivedMessage();
- }
- }
- }
- }
- }
- function addArchivedMessage() {
- const postControlsForm = document.forms["postcontrols"];
- if (!postControlsForm) return;
- const archivedMsg = document.createElement('div');
- archivedMsg.id = 'archived-msg';
- archivedMsg.style.marginTop = '-25px';
- archivedMsg.style.marginBottom = '20px';
- const messageText = settings.archivedMessageText || "THREAD ARCHIVED";
- const imageURL = settings.archivedImageURL || "https://i.imgur.com/LQHVLil.png";
- const fontSize = settings.archivedMessageFontSize || "14px";
- const imageSize = settings.archivedImageSize || "7%";
- const useHeight = settings.archivedImageUseHeight;
- archivedMsg.innerHTML = `
- <strong style="color: red; font-size: ${fontSize};">${messageText}</strong><br>
- <img src="${imageURL}" alt="Archived Image" style="margin-top: 5px; ${useHeight ? `height` : `width`}: ${imageSize};">
- `;
- postControlsForm.parentNode.insertBefore(archivedMsg, postControlsForm.nextSibling);
- }
- function initializeCurrentThreadId() {
- const match = window.location.pathname.match(/\/res\/(\d+)\.html/);
- if (match) {
- currentThreadId = match[1];
- }
- }
- (function(open) {
- XMLHttpRequest.prototype.open = function(method, url) {
- if (currentThreadId) {
- const target = `/res/${currentThreadId}.html`;
- this._monitored = url.includes(target) && url.indexOf(target) + target.length === url.length;
- } else {
- this._monitored = false;
- }
- return open.apply(this, arguments);
- };
- })(XMLHttpRequest.prototype.open);
- (function(send) {
- XMLHttpRequest.prototype.send = function() {
- if (this._monitored) {
- this.addEventListener('load', () => {
- if (this.status === 200) {
- syncPostStatus(this.responseText);
- } else if (this.status === 404) {
- if (enableFaviconChanges && changeFaviconOnArchive) {
- updateFaviconArchived();
- }
- if (showArchivedMessage && !document.getElementById('archived-msg')) {
- addArchivedMessage();
- }
- }
- });
- }
- return send.apply(this, arguments);
- };
- })(XMLHttpRequest.prototype.send);
- const justPostedIds = new Set();
- $(document).on('ajax_after_post', function(e, post_response) {
- if (post_response && post_response.id) {
- const idStr = String(post_response.id);
- justPostedIds.add(idStr);
- setTimeout(() => justPostedIds.delete(idStr), 10000);
- }
- });
- function syncPostStatus(responseText) {
- if (!currentThreadId) return;
- const parser = new DOMParser();
- const doc = parser.parseFromString(responseText, "text/html");
- const currentPosts = document.querySelectorAll('div.post.reply');
- const updatePosts = doc.querySelectorAll('div.post.reply');
- const postCount = updatePosts.length;
- if (postCount > 0) {
- const postDrop = lastPostCount - postCount;
- isLargeDrop = lastPostCount > 200 ? postDrop >= 100 : (postDrop / lastPostCount) >= 0.3;
- if (isLargeDrop && lastPostCount >= 10) {
- lowPostWarningCount++;
- if (lowPostWarningCount >= 2) {
- lastPostCount = postCount;
- updateThreadStatsActual();
- }
- } else {
- lowPostWarningCount = 0;
- lastPostCount = postCount;
- updateThreadStatsActual();
- }
- }
- if (postCount === 0) return;
- const updatePostIds = new Set();
- let seenRed = false;
- let seenWhite = false;
- let ownPostIds = new Set();
- if (enableFaviconChanges && notifyNewYou && alertState !== 'red') {
- try {
- const board = document.querySelector('input[name="board"]')?.value;
- const ownPosts = JSON.parse(localStorage.own_posts || '{}');
- ownPostIds = board && ownPosts[board] ? new Set(ownPosts[board]) : new Set();
- } catch (e) {
- }
- }
- for (let i = 0; i < updatePosts.length; i++) {
- const post = updatePosts[i];
- const postId = post.id.split('_')[1];
- updatePostIds.add(postId);
- if (Number(postId) > Number(lastSeenPostId)) {
- lastSeenPostId = postId;
- if (!hasUnreadLine) addUnreadLine();
- if (enableFaviconChanges) {
- if (notifyNewYou && alertState !== 'red') {
- const bodyLinks = post.querySelectorAll('div.body a:not([rel="nofollow"])');
- for (let j = 0; j < bodyLinks.length; j++) {
- const match = bodyLinks[j].textContent.match(/^>>(\d+)$/);
- if (match && ownPostIds.has(match[1])) {
- seenRed = true;
- break;
- }
- }
- }
- if (!seenRed && notifyNewPost) {
- seenWhite = true;
- }
- }
- }
- let currentPost = null;
- const updateBans = post.querySelector('span.public_ban');
- if (updateBans) {
- currentPost = currentPost || document.getElementById('reply_' + postId);
- if (currentPost && !currentPost.querySelector('span.public_ban')) {
- const currentBody = currentPost.querySelector('div.body');
- if (currentBody) {
- currentBody.appendChild(updateBans.cloneNode(true));
- }
- }
- }
- if (appendQuotes && !appendedPostIds.has(postId)) {
- currentPost = currentPost || document.getElementById('reply_' + postId);
- if (currentPost) {
- appendPosts(currentPost);
- }
- }
- }
- if (seenRed) {
- updateFavicon('red');
- } else if (seenWhite) {
- updateFavicon('white');
- }
- if ((hideDeleted || showDeletedIcon) && (!isLargeDrop || lowPostWarningCount >= 2)) {
- for (let i = 0; i < currentPosts.length; i++) {
- const post = currentPosts[i];
- if (post.closest('.post.qp.reply') || post.classList.contains('post-hover')) continue;
- const postId = post.id.split('_')[1];
- const threadEl = post.closest('.thread');
- if (!threadEl) continue;
- const xthreadId = threadEl.id.split('_')[1];
- if (xthreadId !== currentThreadId) continue;
- const inlineQuoteContainer = post.closest('.inline-quote-container');
- const refId = inlineQuoteContainer?.getAttribute('data-inlined-id') || postId;
- const isDeleted = !updatePostIds.has(refId) && !justPostedIds.has(refId);
- if (isDeleted) {
- if (hideDeleted) {
- if (!inlineQuoteContainer) {
- post.style.setProperty("display", "none", "important");
- const br = post.nextElementSibling;
- if (br?.tagName === "BR") {
- br.style.setProperty("display", "none", "important");
- }
- }
- } else {
- addDeletedIcon(post);
- }
- } else {
- post.style.removeProperty("display");
- const br = post.nextElementSibling;
- if (br?.tagName === "BR") {
- br.style.removeProperty("display");
- }
- if (!hideDeleted && post.querySelector('.deleted-post')) {
- removeDeletedIcon(post);
- }
- }
- }
- }
- }
- function addDeletedIcon(post) {
- if (!showDeletedIcon) return;
- if (!post.querySelector('.post-btn')) return;
- const postNoLink = post.querySelector('.post_no');
- if (!postNoLink || post.querySelector('.deleted-post')) return;
- if (showDeletedText) {
- const span = document.createElement('span');
- span.textContent = ' [Deleted]';
- span.className = 'deleted-post';
- span.style.color = 'red';
- span.style.fontWeight = 'bolder';
- postNoLink.parentNode.insertBefore(span, postNoLink.nextSibling?.nextSibling || null);
- } else {
- const icon = document.createElement('i');
- icon.classList.add('fa', 'fa-trash', 'deleted-post');
- icon.title = 'Deleted';
- icon.style.opacity = '0.5';
- icon.style.marginRight = '0px';
- postNoLink.parentNode.insertBefore(icon, postNoLink.nextSibling?.nextSibling || null);
- }
- }
- function removeDeletedIcon(post) {
- if (!showDeletedIcon) return;
- const postNoLink = post.querySelector('.post_no');
- const deletedPost = postNoLink?.nextSibling?.nextSibling;
- if (deletedPost?.classList.contains('deleted-post')) {
- deletedPost.remove();
- }
- }
- $(function () {
- if (typeof Options === "undefined") return;
- const SETTINGS_KEY = "Thread Settings";
- const settingsList = [
- { key: "showDeletedCounter", label: "Deleted Count", description: "Show deleted post counter" },
- { key: "hideDeletedPosts", label: "Hide Deleted Posts", description: "Hide posts upon deletion" },
- { key: "showDeletedIcon", label: "Deleted Icon", description: "Add an icon next to deleted posts" },
- { key: "faviconUpdater", label: "Favicon Updater", description: "Enable favicon changes" },
- { key: "showUnreadLine", label: "Unread Line", description: "Show a line below the last post" },
- { key: "appendQuotes", label: "Append Quotes", description: "Append '(OP)' '(You)' '→' to applicable quotes" },
- { key: "showArchivedMessage", label: "Archived Message", description: "Show archived message on post limit" }
- ];
- const subSettings = [
- { key: "showDeletedText", label: "Deleted Text", description: 'Add <span style="color:red;font-weight:bolder">[Deleted]</span> text instead', parentKey: "showDeletedIcon" },
- { key: "notifyNewPost", label: "New Post", description: "White circle in favicon on new posts", parentKey: "faviconUpdater" },
- { key: "notifyNewYou", label: "New (You)", description: "Red circle in favicon on new (You) quotes", parentKey: "faviconUpdater" },
- { key: "changeFaviconOnArchive", label: "Archived", description: "Favicon turns red on post limit", parentKey: "faviconUpdater" },
- { key: "appendCrossThread", label: "Append (Cross-thread)", description: "Use (Cross-thread) instead", parentKey: "appendQuotes" },
- { key: "archivedMessageText", label: "Text", parentKey: "showArchivedMessage", type: "text" },
- { key: "archivedImageURL", label: "Image URL", parentKey: "showArchivedMessage", type: "text" },
- { key: "archivedMessageFontSize", label: "Font Size", description: "Use with 'px' or '%'", parentKey: "showArchivedMessage", type: "text", size: "1", after: "archivedMessageText" },
- { key: "archivedImageSize", label: "Image Width", description: "Use with 'px' or '%'", parentKey: "showArchivedMessage", type: "text", size: "1", after: "archivedImageURL" },
- { key: "archivedImageUseHeight", label: "Use Height", description: "Instead of width for image", parentKey: "showArchivedMessage", after: "archivedImageSize" }
- ];
- const defaultSettings = {
- showDeletedCounter: true,
- showDeletedIcon: true,
- hideDeletedPosts: false,
- showArchivedMessage: true,
- faviconUpdater: true,
- showUnreadLine: true,
- appendQuotes: true,
- notifyNewPost: true,
- notifyNewYou: true,
- changeFaviconOnArchive: true,
- showDeletedText: false,
- appendCrossThread: false,
- archivedMessageText: "THREAD ARCHIVED",
- archivedImageURL: "https://i.imgur.com/LQHVLil.png",
- archivedMessageFontSize: "14px",
- archivedImageSize: "7%",
- archivedImageUseHeight: false,
- appendQuotesWarning: false
- };
- let threadSettings = {};
- try {
- threadSettings = JSON.parse(localStorage.getItem(SETTINGS_KEY)) || {};
- } catch {
- threadSettings = {};
- }
- for (const key in defaultSettings) {
- if (!(key in threadSettings)) {
- threadSettings[key] = defaultSettings[key];
- }
- }
- const saveSettings = () => {
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(threadSettings));
- };
- const content = $("<div></div>");
- settingsList.forEach(({ key, label, description }) => {
- const isChecked = threadSettings[key];
- const descSpan = description ? `<span class="description">: ${description}</span>` : "";
- const checkbox = $(`
- <div id="${key}-container">
- <label style="text-decoration: underline; cursor: pointer;">
- <input type="checkbox" id="${key}" ${isChecked ? "checked" : ""} name="${label}">${label}</label>${descSpan}
- </div>
- `);
- content.append(checkbox);
- });
- subSettings.forEach((s) => {
- const { key, label, description, type = "checkbox" } = s;
- const value = threadSettings[key];
- const descSpan = description ? `<span class="description">: ${description}</span>` : "";
- let input;
- if (type === "text") {
- const inputSize = s.size || "20";
- input = `<input type="text" id="${key}" value="${value}" size="${inputSize}" style="margin-right: 3px;">`;
- } else {
- input = `<input type="checkbox" id="${key}" ${value ? "checked" : ""}>`;
- }
- const container = $(`
- <div id="${key}-container" style="margin-left: 1.5em;">
- <label style="text-decoration: underline; cursor: pointer;">
- ${input}${label}</label>${descSpan}
- </div>
- `);
- content.append(container);
- });
- const previewWrapper = $(`
- <div id="archived-preview" style="
- position: absolute;
- bottom: 0px;
- right: 0px;
- width: 220px;
- height: 90px;
- overflow: hidden;
- pointer-events: none;
- transform-origin: top left;
- ">
- </div>
- `);
- content.css("position", "relative");
- content.append(previewWrapper);
- function renderArchivedPreview() {
- const rawFontSize = threadSettings.archivedMessageFontSize || defaultSettings.archivedMessageFontSize || "14px";
- const rawImageSize = threadSettings.archivedImageSize || defaultSettings.archivedImageSize || "7%";
- const useHeight = threadSettings.archivedImageUseHeight;
- const msg = threadSettings.archivedMessageText || defaultSettings.archivedMessageText || "THREAD ARCHIVED";
- const img = threadSettings.archivedImageURL || defaultSettings.archivedImageURL || "https://i.imgur.com/LQHVLil.png";
- const convertSize = (raw, isHeight = false) => {
- if (raw.endsWith('%')) {
- const percent = parseFloat(raw);
- const base = isHeight ? window.innerHeight : window.innerWidth;
- return `${(percent / 100) * base}px`;
- }
- return raw;
- };
- const fontSize = convertSize(rawFontSize);
- const imageSize = convertSize(rawImageSize, useHeight);
- const previewContent = $(`
- <div style="display: inline-block; white-space: nowrap;">
- <div style="display: inline-block;">
- <strong style="color: red; font-size: ${fontSize}; display: inline-block; white-space: nowrap;">${msg}</strong><br>
- <img src="${img}" style="margin-top: 5px; display: inline-block; ${useHeight ? 'height' : 'width'}: ${imageSize};">
- </div>
- </div>
- `);
- previewWrapper.empty().append(previewContent);
- const imageEl = previewContent.find('img')[0];
- const applyScale = (scale) => {
- previewContent.css({
- transform: `scale(${scale})`,
- transformOrigin: "top left"
- });
- };
- const tryScale = () => {
- const bounds = previewContent[0].getBoundingClientRect();
- const width = bounds.width;
- const height = bounds.height;
- if (width && height) {
- const scaleX = 220 / width;
- const scaleY = 90 / height;
- const scale = Math.min(scaleX, scaleY, 1);
- applyScale(scale);
- threadSettings.archivedPreviewScale = scale.toFixed(6);
- } else {
- const fallbackScale = parseFloat(threadSettings.archivedPreviewScale);
- if (fallbackScale && isFinite(fallbackScale)) {
- applyScale(fallbackScale);
- }
- }
- };
- if (imageEl.complete) {
- tryScale();
- } else {
- imageEl.onload = tryScale;
- }
- }
- Options.add_tab("thread-status", "cog", "Thread Options", content);
- subSettings.forEach(({ key, parentKey, after }) => {
- const parent = $(`#${parentKey}-container`);
- const insertAfter = after ? $(`#${after}-container`) : parent;
- $(`#${key}-container`).insertAfter(insertAfter);
- });
- settingsList.forEach(({ key }) => {
- $(`#${key}`).on("change", function () {
- threadSettings[key] = this.checked;
- saveSettings();
- subSettings.forEach(({ key: subKey, parentKey }) => {
- if (parentKey === key) {
- const disabled = !this.checked;
- const label = $(`#${subKey}`).closest("label");
- const desc = label.next(".description");
- $(`#${subKey}`).prop("disabled", disabled);
- label.css("opacity", disabled ? 0.5 : 1);
- desc.css("opacity", disabled ? 0.5 : 1);
- }
- if (key === "showArchivedMessage") {
- $("#archived-preview").toggle(this.checked);
- }
- });
- });
- });
- subSettings.forEach(({ key, type = "checkbox" }) => {
- const $input = $(`#${key}`);
- $input.on("change input", function () {
- if (type === "text") {
- const trimmed = this.value.trim();
- if (key === "archivedImageSize" && !trimmed) {
- threadSettings[key] = defaultSettings[key];
- threadSettings.archivedImageUseHeight = defaultSettings.archivedImageUseHeight;
- $(`#archivedImageUseHeight`).prop("checked", defaultSettings.archivedImageUseHeight);
- } else {
- threadSettings[key] = trimmed || defaultSettings[key];
- }
- } else {
- threadSettings[key] = this.checked;
- }
- saveSettings();
- renderArchivedPreview();
- });
- });
- $("#appendQuotes").on("change", function () {
- const checked = $(this).is(":checked");
- if (checked && !threadSettings.appendQuotesWarning) {
- const alert = $(`
- <div id="alert_handler">
- <div id="alert_background"></div>
- <div id="alert_div">
- <a id="alert_close" href="javascript:void(0)">
- <i class="fa fa-times"></i>
- </a>
- <div id="alert_message">
- <strong>⚠ Compatibility Notice</strong><br><br>
- This feature is compatible with the latest version of the <em>Inline Quoting</em> script.<br><br>
- Update to <strong>version 2.1</strong> or later if you are experiencing issues with inline quoting appended replies.
- </div>
- <div style="margin: 13px;">
- <label><input type="checkbox" id="appendQuotesWarning">Don't show this message again</label>
- </div>
- <div>
- <button class="button alert_button" id="appendQuotesOk">OK</button>
- </div>
- </div>
- </div>
- `);
- $("body").append(alert);
- $("#appendQuotesOk").on("click", function () {
- if ($("#appendQuotesWarning").is(":checked")) {
- threadSettings.appendQuotesWarning = true;
- saveSettings();
- }
- $("#alert_handler").remove();
- });
- $("#alert_close").on("click", function () {
- $("#appendQuotes").prop("checked", false);
- threadSettings.appendQuotes = false;
- saveSettings();
- $("#alert_handler").remove();
- });
- }
- });
- subSettings.forEach(({ key, parentKey }) => {
- const isParentChecked = threadSettings[parentKey];
- const label = $(`#${key}`).closest("label");
- const desc = label.next(".description");
- $(`#${key}`).prop("disabled", !isParentChecked);
- label.css("opacity", isParentChecked ? 1 : 0.5);
- desc.css("opacity", isParentChecked ? 1 : 0.5);
- $("#archived-preview").toggle(threadSettings.showArchivedMessage);
- });
- renderArchivedPreview();
- saveSettings();
- });
- if (document.readyState === 'loading') {
- window.addEventListener('DOMContentLoaded', () => {
- initializeCurrentThreadId();
- initializePosts();
- });
- } else {
- initializeCurrentThreadId();
- initializePosts();
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement