Greasy Fork

Greasy Fork is available in English.

Sort directories before files

Sort directories before files in repository tree view

当前为 2025-04-09 提交的版本,查看 最新版本

// ==UserScript==
// @name        Sort directories before files
// @description Sort directories before files in repository tree view
// @author      anhkhoakz
// @version     1.0.0
// @match       *://git.sr.ht/*/tree(?:/*)?
// @namespace   anhkhoakz
// @icon        https://git.sr.ht/static/logo.png
// @license     GPL-3.0; https://www.gnu.org/licenses/gpl-3.0.html
// ==/UserScript==

(() => {
	"use strict";

	/**
	 * The container element for the tree list.
	 * @type {HTMLElement|null}
	 */
	const tree_list = document.querySelector(".tree-list");
	if (!tree_list) {
		// Exit if the tree list is not found.
		return;
	}

	/**
	 * Indices of directory rows.
	 * @type {number[]}
	 */
	const trees = [];
	/**
	 * Indices of file rows.
	 * @type {number[]}
	 */
	const blobs = [];
	/**
	 * List of name elements in the tree list.
	 * @type {NodeListOf<HTMLElement>}
	 */
	const names = tree_list.querySelectorAll(".name");

	for (let index = 0; index < names.length; index++) {
		const name = names[index];
		if (name.classList.contains("tree")) {
			trees.push(index);
		} else if (name.classList.contains("blob")) {
			blobs.push(index);
		}
	}

	/**
	 * Total number of cells in the tree list.
	 * @type {number}
	 */
	const num_cells = tree_list.children.length;
	/**
	 * Total number of rows in the tree list.
	 * @type {number}
	 */
	const num_rows = names.length;
	/**
	 * Number of columns in the tree list.
	 * @type {number}
	 */
	const num_columns = num_cells / num_rows;

	if (num_columns * num_rows !== num_cells) {
		return;
	}

	/**
	 * Sorted list of tree list children.
	 * @type {Element[]}
	 */
	const tree_list_sorted = Array.from(tree_list.children).sort((a, b) => {
		/**
		 * Index of element `a` in the tree list.
		 * @type {number}
		 */
		const index_a = Array.prototype.indexOf.call(tree_list.children, a);
		/**
		 * Index of element `b` in the tree list.
		 * @type {number}
		 */
		const index_b = Array.prototype.indexOf.call(tree_list.children, b);

		/**
		 * Row index of element `a`.
		 * @type {number}
		 */
		const row_a = Math.trunc(index_a / num_columns);
		/**
		 * Row index of element `b`.
		 * @type {number}
		 */
		const row_b = Math.trunc(index_b / num_columns);

		/**
		 * Whether row `a` is a directory.
		 * @type {boolean}
		 */
		const row_a_is_dir = trees.indexOf(row_a) !== -1;
		/**
		 * Whether row `b` is a directory.
		 * @type {boolean}
		 */
		const row_b_is_dir = trees.indexOf(row_b) !== -1;

		if (row_a_is_dir !== row_b_is_dir) {
			return row_a_is_dir ? -1 : 1;
		}

		return index_a - index_b;
	});

	for (const child of tree_list_sorted) {
		tree_list.appendChild(child);
	}
})();