[Deprecated] Kanka Gallery Alphabetical Sort

Sorts folders and images alphabetically in the Kanka Gallery, keeping folders first.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         [Deprecated] Kanka Gallery Alphabetical Sort
// @namespace    http://tampermonkey.net/
// @version      4
// @description  Sorts folders and images alphabetically in the Kanka Gallery, keeping folders first.
// @author       Salvatos
// @license      MIT
// @match        https://app.kanka.io/*/gallery*
// @icon         https://www.google.com/s2/favicons?domain=kanka.io
// ==/UserScript==

// Gallery items are loaded in asynchronously, so wait until they appear on the page
observeGallery();

function observeGallery(prev) {
    let observer = new MutationObserver(function(mutations) {
        // Keep watching if only the "loading" temp div is in place
        if (!document.querySelector("#gallery > div > div:nth-child(3).text-center")) {
            observer.disconnect();
            var b = Date.now();
            sortList(b, prev);
        }
    });
    observer.observe(document.getElementById("gallery"), {attributes: false, childList: true, characterData: false, subtree: true});
}

function sortList(b, prev) {
    /* Give the info tile a title so it can be included in the sort */
    document.querySelector("#gallery div.grid > div:has(i.fa-image)").setAttribute("title", "_Info");

	/* To keep folders and images grouped, we prepend to their titles a keyword that will conveniently put folders first alphabetically (skipping those we've already processed in the case of a search's "load more" operation) */
	var folders = document.querySelectorAll("#gallery div.grid > div:has(.md\\\:h-32:not(.cover-background):not([title]))");
	var images = document.querySelectorAll("#gallery div.grid > div:has(:is(.w-full.h-20.md\\\:h-32, .h-16.cover-background)):not([title])");

    // We also add a timestamp so that when pressing "Load more" on a search with many results, each new batch is only sorted internally rather than re-sorting everything and losing track of the new results
	folders.forEach((child) => child.setAttribute("title", "Folders_" + b + ": " + child.querySelector(".grow.truncate").innerText));
	images.forEach((child) => child.setAttribute("title", "Images_" + b + ": " + child.querySelector(".grow.truncate").innerText));

	/* Sort tiles by title */
    var thumbs = document.querySelector("#gallery div.grid");
    [...thumbs.children]
        .sort((a, b) => a.getAttribute("title").localeCompare(b.getAttribute("title")))
        .forEach(el => thumbs.appendChild(el));

    // Create an anchor on the last result to scroll back to when "Load more" is clicked
    document.querySelector("#gallery div.grid > :nth-last-child(2)").id = b;

    if (prev) {
        location.hash = "#" + prev;
    }

    /* Restart the observer to catch navigation between folders */
    observeGallery(b);
}