Komica thread collapse

Let you collapse/expand threads on Komica

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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();

})();