-
-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(GitHub Files Filter) Feature suggestion: invert select #97
Comments
Hi @darkred! I'll see what I can do... what happens when someone Ctrl+clicks on the |
Upon further consideration, I think the best way to implement would be not with Ctrl+click, |
And, another suggestion, please, regarding the «ALL» button: |
Hmm, now that I read all that again, I'm confused 🤣 So what if I add a new button named "toggle"? Clicking it will invert the filters. So if you only want to see the files ending with "js", you click on that button (which hides the js files), then hit the invert and then only the "js" files are visible. Then I can store the selected filters in local storage so the next time you return to any PR files, only those filters will be enabled... hmm, I guess it'd have to be stored by PR number because not every PR will have the same file extensions being modified. And I'm still not sure what you are describing that needs changing for the «ALL» button. |
First, of all, sorry for the confusion and for not being consistent to my suggestion description.. 😟
Yes, exactly.
Yes, I think that's the best approach.
Currently, when you enable a filter, e.g. "JS", and so .js files are hidden, the status of that "JS" filter (=enabled) remains after you reload the page (F5). Something last, please: |
One more thing, please: I understand that you've written the script in order to be able to hide the non-important filetypes from the listings, but I find that it's more suitable to the script's title, 'GitHub Files Filter', if it had:
|
Here is a summary of my suggestions:
|
Yes, thanks! Sorry, I've been busy job hunting. Hopefully, everything will be settled soon and I'll have some free time to take care of this. I was actually thinking of replacing the ALL button with the TOGGLE action. |
No problem! I wish you every success ! 👍
Great idea! |
Busy weekend. I didn't forget about you, I just didn't get around to working on this script. It's high on my list now 😸 |
Ok try out this script; if it works like you want, I'll go ahead and commit it: Files-filter// ==UserScript==
// @name GitHub Files Filter
// @version 1.1.8
// @description A userscript that adds filters that toggle the view of repo files by extension
// @license MIT
// @author Rob Garrison
// @namespace https://github.com/Mottie
// @include https://github.com/*
// @run-at document-idle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=666427
// @icon https://github.githubassets.com/pinned-octocat.svg
// @updateURL https://raw.githubusercontent.com/Mottie/GitHub-userscripts/master/github-files-filter.user.js
// @downloadURL https://raw.githubusercontent.com/Mottie/GitHub-userscripts/master/github-files-filter.user.js
// ==/UserScript==
(() => {
"use strict";
// Emphasize selected buttons, disable hover when all selected and remove
// animation delay; See #46
GM_addStyle(`
.gff-filter .btn.selected { font-variant: small-caps; }
.gff-filter .btn:not(.selected):not(:first-child) {
text-decoration: line-through;
}
.gff-filter .gff-all:not(.selected):focus,
.gff-filter .gff-all:not(.selected) ~ .btn:focus,
.gff-filter .gff-all:not(.selected) ~ .btn.selected:focus,
.gff-filter .gff-all:not(.selected):hover,
.gff-filter .gff-all:not(.selected) ~ .btn:hover,
.gff-filter .gff-all:not(.selected) ~ .btn.selected:hover {
border-color: #777 !important;
}
.gff-filter .btn:before, .gff-filter .btn:after {
animation-delay: unset !important;
filter: invert(10%);
}
`);
let settings,
inverted = [],
list = {};
const types = {
// including ":" in key since it isn't allowed in a file name
":all": {
// return false to prevent adding files under this type
is: () => false,
text: "\u00ABtoggle\u00BB"
},
":noExt": {
is: name => !/\./.test(name),
text: "\u00ABno-ext\u00BB"
},
":dot": {
// this will include ".travis.yml"... should we add to "yml" instead?
is: name => /^\./.test(name),
text: "\u00ABdot-files\u00BB"
},
":min": {
is: name => /\.min\./.test(name),
text: "\u00ABmin\u00BB"
}
},
// TODO: add toggle for submodule and dot-folders
folderIconClasses = [
".octicon-file-directory",
".octicon-file-symlink-directory",
".octicon-file-submodule"
].join(",");
// default to all file types visible; remember settings between sessions
list[":all"] = true; // list gets cleared in buildList function
settings = GM_getValue("gff-filter-settings", list);
function updateFilter(event) {
event.preventDefault();
event.stopPropagation();
const el = event.target;
toggleBlocks(
el.getAttribute("data-ext"),
el.classList.contains("selected") ? "hide" : "show",
event.ctrlKey
);
}
function updateSettings(name, mode) {
settings[name] = mode === "show";
GM_setValue("gff-filter-settings", settings);
}
function toggleImagePreview(ext, mode) {
if ($(".ghip-image-previews")) {
let selector = "a",
hasType = types[ext];
if (!hasType) {
selector += `[href$="${ext}"]`;
}
$$(`.ghip-image-previews ${selector}`).forEach(el => {
if (!$(".ghip-folder, .ghip-up-tree", el)) {
if (hasType && ext !== ":all") {
// image preview includes the filename
let elm = $(".ghip-file-name", el);
if (elm && !hasType.is(elm.textContent)) {
return;
}
}
el.style.display = mode === "show" ? "" : "none";
}
});
}
}
function toggleRow(el, mode) {
const row = el.closest("tr.js-navigation-item");
// don't toggle folders
if (row && !$(folderIconClasses, row)) {
let state;
if (mode) {
state = mode === "show" ? "" : "none";
} else {
// toggle
state = row.style.display === "none" ? "" : "none";
}
row.style.display = state;
}
}
function toggleAll() {
const files = $(".file-wrap");
// Toggle all blocks
$$("td.content .js-navigation-open", files).forEach(el => {
toggleRow(el);
});
// update filter buttons
$$(".gff-filter .btn", files).forEach(el => {
el.classList.toggle("selected");
});
}
function toggleFilter(filter, mode) {
const files = $(".file-wrap"),
elm = $(`.gff-filter .btn[data-ext="${filter}"]`, files);
/* list[filter] contains an array of file names */
list[filter].forEach(name => {
const el = $(`a[title="${name}"]`, files);
if (el) {
toggleRow(el, mode);
}
});
if (elm) {
elm.classList.toggle("selected", mode === "show");
}
updateSettings(filter, mode);
}
function toggleBlocks(filter, mode) {
if (filter === ":all") {
toggleAll();
} else if (list[filter]) {
toggleFilter(filter, mode);
}
// update view for github-image-preview.user.js
toggleImagePreview(filter, mode);
}
function addExt(ext, txt) {
if (ext) {
if (!list[ext]) {
list[ext] = [];
}
list[ext].push(txt);
}
}
function buildList() {
list = {};
Object.keys(types).forEach(item => {
if (item !== ":all") {
list[item] = [];
}
});
// get all files
$$("table.files tr.js-navigation-item").forEach(file => {
if ($("td.icon .octicon-file", file)) {
let ext, parts, sub,
link = $("td.content .js-navigation-open", file),
txt = (link.title || link.textContent || "").trim(),
name = txt.split("/").slice(-1)[0];
// test extension types; fallback to regex extraction
ext = Object.keys(types).find(item => {
return types[item].is(name);
}) || /[^./\\]*$/.exec(name)[0];
parts = name.split(".");
if (!ext.startsWith(":") && parts.length > 2 && parts[0] !== "") {
sub = parts.slice(0, -1).join(".");
// Prevent version numbers & "vs. " from adding a filter button
// See https://github.com/tpn/pdfs
if (!/[()]/.test(sub) && !/[\b\w]\.[\b\d]/.test(sub)) {
addExt(ext, txt);
ext = parts.slice(-2).join(".");
}
}
addExt(ext, txt);
}
});
}
function sortList() {
return Object.keys(list).sort((a, b) => {
// move ":" filters to the beginning, then sort the rest of the
// extensions; test on https://github.com/rbsec/sslscan, where
// the ".1" extension *was* appearing between ":" filters
if (a[0] === ":") {
return -1;
}
if (b[0] === ":") {
return 1;
}
return a > b;
});
}
function makeFilter() {
let filters = 0;
// get length, but don't count empty arrays
Object.keys(list).forEach(ext => {
filters += list[ext].length > 0 ? 1 : 0;
});
// Don't bother if only one extension is found
const files = $(".file-wrap");
if (files && filters > 1) {
filters = $(".gff-filter-wrapper");
if (!filters) {
filters = document.createElement("div");
// "commitinfo" allows GitHub-Dark styling
filters.className = "gff-filter-wrapper commitinfo";
filters.style = "padding:3px 5px 2px;border-bottom:1px solid #eaecef";
files.insertBefore(filters, files.firstChild);
}
fixWidth();
buildHTML();
applyInitSettings();
}
}
function buildButton(name, label, ext, text) {
return `<button type="button" ` +
`class="btn btn-sm selected BtnGroup-item tooltipped tooltipped-n` +
(name ? name : "") + ` gff-btn" ` +
`data-ext="${ext}" aria-label="${label}">${text}</button>`;
}
function buildHTML() {
let len,
html = `<div class="BtnGroup gff-filter">` +
// add a filter "all" button to the beginning
buildButton(" gff-all", "Toggle all files", ":all", types[":all"].text);
sortList().forEach(ext => {
len = list[ext].length;
if (len) {
html += buildButton("", len, ext, types[ext] && types[ext].text || ext);
}
});
// prepend filter buttons
$(".gff-filter-wrapper").innerHTML = html + "</div>";
}
function getWidth(el) {
return parseFloat(window.getComputedStyle(el).width);
}
// lock-in the table cell widths, or the navigation up link jumps when you
// hide all files... using percentages in case someone is using GitHub wide
function fixWidth() {
let group, width,
html = "",
table = $("table.files"),
tableWidth = getWidth(table),
cells = $$("tbody:last-child tr:last-child td", table);
if (table && cells.length > 1 && !$("colgroup", table)) {
group = document.createElement("colgroup");
table.insertBefore(group, table.childNodes[0]);
cells.forEach(el => {
// keep two decimal point accuracy
width = parseInt(getWidth(el) / tableWidth * 1e4, 10) / 100;
html += `<col style="width:${width}%">`;
});
group.innerHTML = html;
}
}
function applyInitSettings() {
Object.keys(list).forEach(name => {
if (settings[name] === false) {
toggleBlocks(name, "hide");
}
});
}
function init() {
if ($("table.files")) {
buildList();
makeFilter();
}
}
function $(str, el) {
return (el || document).querySelector(str);
}
function $$(str, el) {
return Array.from((el || document).querySelectorAll(str));
}
document.addEventListener("click", e => {
if (e.target.classList.contains("gff-btn")) {
updateFilter(e);
}
});
document.addEventListener("ghmo:container", () => {
// init after a short delay to allow rendering of file list
setTimeout(() => {
init();
}, 200);
});
init();
})(); |
Thanks a lot for your effort! 👍 Unfortunately though, the new version doesn't do anything: no filter buttons group, no filtering, nothing. I've tried both latest Tampermonkey versions (TM 4.8.41 stable and TM 4.9.5971 beta) |
Hmm, you mentioned this before:
To me that is essentially what the toggle button does now; it inverts the selected state of all the buttons instead of the button action (matching). The results are the same - unless I'm utterly over-thinking this whole thing. |
Sorry for changing my mind once more (I've deleted my last comment), So, my final suggestion is that, the new «Toggle» button is useful as it is, so keep it (changing its name to «Invert», its tooltip to |
If I may facilitate you a bit, here are the few changes for my last suggestion that I managed to make:
buildButton(" gff-all", "Invert filters status", ":all", types[":all"].text);
document.addEventListener("click", e => {
if (e.target.classList.contains("gff-btn")) {
if (!event.ctrlKey) {
// plain click
updateFilter(e);
} else {
// Ctrl+click
showOnlyFilter(e); // New function
}
}
}); Now, what's left to be done (sorry I can't contribute more) :
|
I just updated the files filter userscript. I didn't:
|
Thank you so much!! It's great! 👍 |
Greetings @Mottie 🙂
Currently, 'GitHub Files Filter', only hides the files matching the activated filters.
My suggestion is to also be able to invert select, i.e. only show the matching files, e.g. with Ctrl+click.
For example, in your repo, when Ctrl+clicking
MD
:to only display .md files, i.e. to strikethrough the rest filters.
And, if you keep Ctrl+clicking, e.g. also Ctrl+click
«dot files»
to only display .md and dot files .
I hope you like my suggestion !
The text was updated successfully, but these errors were encountered: