Let you collapse/expand threads on Komica
// ==UserScript==
// @name Komica thread collapse
// @version 1.0.7
// @description Let you collapse/expand threads on Komica
// @author peng-devs
// @match https://*.komica.org/*/*.htm*
// @match https://*.komica1.org/*/*.htm*
// @match https://*.komica2.net/*/*.htm*
// @match https://*.komica2.cc/*/*.htm*
// @exclude-match https://2cat.komica.org/*
// @icon https://komica1.org/favicon.ico
// @grant none
// @allFrames true
// @license MIT
// @namespace https://greasyfork.org/users/57176
// ==/UserScript==
(function() {
'use strict';
const NAME = 'Komica thread collapse';
function main() {
console.log(`[${NAME}] Initializing...`);
inject_custom_style(`
.collapsed_thread {
opacity: 0.5;
}
.thread-collapse-button {
float: left;
margin-right: 5px;
}
.thread.collapsed {
display: none !important;
}
.thread.ngid-ngthread > .thread-collapse-button {
display: none;
}
`);
const storage = get_storage();
const threads = document.querySelectorAll('div.thread');
[...threads].forEach(thread => {
const thread_collapse_button = create_thread_collapse_button(thread);
thread.prepend(thread_collapse_button);
const data_no = thread.getAttribute('data-no');
if (storage.includes(data_no)) {
thread_collapse(thread);
}
});
console.log(`[${NAME}] Loaded`);
}
/// private
function inject_custom_style(css) {
const style = document.createElement("style");
document.head.append(style);
style.dataset.source = NAME;
style.innerHTML = css;
}
function get_storage() {
return window.localStorage.getItem('collapsed_threads') || '';
}
function save_to_storage(data_no) {
let storage = get_storage();
if (storage.includes(data_no)) return;
if ((storage.match(/,/g) || []).length > 100) {
storage = storage.slice(storage.indexOf(',') + 1);
}
window.localStorage.setItem('collapsed_threads', `${storage}${data_no},`);
}
function remove_from_storage(data_no) {
const storage = get_storage();
window.localStorage.setItem('collapsed_threads', storage.replaceAll(`${data_no},`, ''));
}
function get_thread(data_no, collapsed = false) {
return document.querySelector(`div.${collapsed ? 'collapsed_thread' : 'thread'}[data-no="${data_no}"`);
}
function create_collapsed_thread(thread) {
const data_no = thread.getAttribute('data-no');
const thread_collapse_button = create_thread_collapse_button(thread, true);
const head = thread.querySelector('div.post-head').cloneNode(true);
const hr = document.createElement('hr');
const collapsed_thread = document.createElement('div');
collapsed_thread.className = 'collapsed_thread';
collapsed_thread.setAttribute('data-no', data_no);
collapsed_thread.appendChild(thread_collapse_button);
collapsed_thread.appendChild(head);
collapsed_thread.appendChild(hr);
return collapsed_thread;
}
function thread_collapse(thread) {
thread.classList.add('collapsed');
const collapsed_thread = create_collapsed_thread(thread);
thread.before(collapsed_thread);
const data_no = thread.getAttribute('data-no');
save_to_storage(data_no);
console.log(`[${NAME}] thread ${data_no} collapsed`);
}
function thread_expand(thread) {
thread.classList.remove('collapsed');
const collapsed_thread = thread.previousElementSibling;
if (collapsed_thread?.classList.contains('collapsed_thread')) {
collapsed_thread.remove();
}
const data_no = thread.getAttribute('data-no');
remove_from_storage(data_no);
console.log(`[${NAME}] thread ${data_no} expanded`);
}
function create_thread_collapse_button(thread, collapsed = false) {
const thread_collapse_button = document.createElement('a');
thread_collapse_button.className = 'thread-collapse-button';
thread_collapse_button.innerText = `[${collapsed ? '+' : '–'}]`;
thread_collapse_button.addEventListener(
'click',
collapsed
? () => thread_expand(thread)
: () => thread_collapse(thread)
);
return thread_collapse_button;
}
main();
})();