// ==UserScript==
// @name Floating Subs List
// @namespace http://tampermonkey.net/
// @version 0.6
// @description Adds a floating list of subscribed magazines to the left of the page
// @author raltsm4k
// @match *://kbin.social/*
// @match *://fedia.io/*
// @match *://karab.in/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=kbin.social
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @license MIT
// ==/UserScript==
let user;
(function() {
'use strict';
const a_login = document.querySelector("#header a.login");
user = a_login.getAttribute("href");
if (user !== "/login") {
const div_head = document.querySelector('#header');
const div_subs = document.createElement('div');
const div_subs_s = document.createElement('section');
const div_subs_c = document.createElement('div');
const button_recent = Object.assign(document.createElement("a"), {
className: "icon sort-button",
id: "sort-recent",
title: "Sort by recent",
}).appendChild(Object.assign(document.createElement("i"), {
className: "fa-solid fa-clock-rotate-left"
})).parentNode;
const button_alpha = Object.assign(document.createElement("a"), {
className: "icon sort-button",
id: "sort-alpha",
title: "Sort alphabetically",
}).appendChild(Object.assign(document.createElement("i"), {
className: "fa-solid fa-arrow-down-a-z"
})).parentNode;
const button_filter = Object.assign(document.createElement("a"), {
className: "icon sort-button",
id: "button-filter",
title: "Filter by name",
}).appendChild(Object.assign(document.createElement("i"), {
className: "fa-solid fa-magnifying-glass"
})).parentNode;
const input_filter = Object.assign(document.createElement("input"), {
id: "subs-filter",
name: "subs-filter",
type: "text",
title: "Filter by name",
style: "display:none;"
});
const button_collapse = Object.assign(document.createElement("button"), {
id: "subs-sticky-collapse",
title: "Collapse/expand",
textContent: "<"
});
const ul_main = Object.assign(document.createElement("ul"), {
id: "subs-sticky-main"
});
const ul_pins = Object.assign(document.createElement("ul"), {
id: "subs-sticky-pins"
});
const div_dummy = document.createElement('div');
div_dummy.className = 'dummy';
button_recent.addEventListener('click', async () => { await localStorage.setItem('sort_alpha', false); populate(); });
button_alpha.addEventListener('click', async () => { await localStorage.setItem('sort_alpha', true); populate(); });
button_filter.addEventListener('click', () => {
const search_box = $('#subs-filter');
search_box.toggle();
if (search_box.is(':visible')) {
$('#button-filter').addClass('active');
search_box.focus();
} else {
$('#button-filter').removeClass('active');
search_box.val('');
filter();
}
});
input_filter.addEventListener('input', function() { filter(); });
button_collapse.addEventListener('click', async () => { await localStorage.setItem('subs_collapsed', localStorage.getItem('subs_collapsed') !== 'true'); collapse(); });
const sub_button = document.querySelector('.magazine__subscribe button[data-action="subs#send"]');
if (sub_button !== null) sub_button.addEventListener('click', () => { localStorage.removeItem('cached_subs'); });
$('<style>').text(`#subs-sticky { display: none; }
@media only screen and (min-width: 1136px) {
#middle > .kbin-container {
margin: 0 auto 0 max(calc(200px + 1rem), calc(50vw - 720px + 1rem));
}
#middle > .kbin-container.collapsed-subs {
margin: 0 auto;
}
#subs-sticky {
display: block;
position: fixed;
top: 3.1625rem;
left: max(.5rem, calc(50vw - 680px - 200px - 2rem));
}
.fixed-navbar #subs-sticky {
position: absolute;
}
#subs-sticky.collapsed-subs {
left: 0;
}
#subs-sticky.collapsed-subs .section {
width: 0px;
padding: 0;
border: none;
}
#subs-sticky-collapse {
cursor: pointer;
height: min(200px, 20%);
width: .5rem;
position: absolute;
top: calc(50% - min(200px, 20%));
left: 100%;
border: var(--kbin-button-primary-border);
border-left: none;
background: var(--kbin-button-primary-bg);
padding: 0;
color: var(--kbin-text-muted-color);
}
#subs-sticky-collapse:hover {
background: var(--kbin-button-primary-hover-bg);
}
a.sort-button {
position: relative;
float: right;
padding-left: .5rem;
}
a.sort-button:hover {
cursor: pointer;
}
a.sort-button:not(.active) {
opacity: 50%;
}
a#button-filter {
margin-right: -.25rem;
padding-right: .25rem;
border-right: var(--kbin-meta-border);
}
#subs-sticky a {
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
overflow-x: hidden;
overflow-y: hidden;
display: inherit;
}
#subs-sticky h3 {
border-bottom: var(--kbin-sidebar-header-border);
color: var(--kbin-sidebar-header-text-color);
font-size: .8rem;
margin: 0 0 .5rem;
text-transform: uppercase;
}
#subs-sticky .section {
padding: .5rem .5rem 1rem;
margin: 0;
width: 200px;
max-height: calc(100vh - 6.325rem);
overflow-y: auto;
}
.fixed-navbar #subs-sticky .section {
max-height: calc(100vh - 3.5rem);
}
#subs-sticky .section a {
color: var(--kbin-meta-link-color);
}
#subs-sticky .section a:hover {
color: var(--kbin-meta-link-hover-color);
}
#subs-sticky ul {
list-style-type: none;
padding: 0;
margin: 0;
}
#subs-sticky ul li small {
display: none;
}
#subs-sticky ul div {
position: relative;
}
#subs-sticky ul div .pin-button {
position: absolute;
top: -2px;
left: -2px;
cursor: pointer;
opacity: 0%;
text-shadow: 2px 2px 5px black;
z-index: 20;
}
a.icon.pin-button i {
font-size: small;
}
#subs-sticky ul div:hover .pin-button {
opacity: 25%;
}
#subs-sticky-pins .pin-button {
color: #bf5ded!important;
opacity: 100%!important;
}
#subs-sticky ul div .pin-button:hover {
opacity: 100%;
}
#subs-sticky-pins .pin-button:hover {
color: #df7dff!important;
}
#subs-sticky-pins {
display: none;
border-bottom: var(--kbin-meta-border);
margin-bottom: .25rem!important;
}
#subs-sticky figure {
display: inline-block;
vertical-align: middle;
margin: 0 4px 4px 0;
height: 24px;
width: 24px;
}
#subs-sticky figure, #subs-sticky img {
border-radius: 100%;
}
#subs-filter {
display: block;
padding: .25rem;
margin-bottom: .5rem;
}
#subs-sticky .section::-webkit-scrollbar {
width: 8px;
}
#subs-sticky .section::-webkit-scrollbar-track {
background: var(--kbin-bg-nth);
border-left: var(--kbin-section-border);
}
#subs-sticky .section::-webkit-scrollbar-thumb {
background: var(--kbin-section-bg);
border-left: var(--kbin-section-border);
}
#subs-sticky .section::-webkit-scrollbar-thumb:hover {
background: var(--kbin-primary-color);
}
#subs-sticky .dummy {
display: none;
}
}`).appendTo(document.head);
div_subs_c.className = 'container';
div_subs_c.appendChild(ul_pins);
div_subs_c.appendChild(ul_main);
div_subs_s.className = 'section';
div_subs_s.appendChild(button_recent);
div_subs_s.appendChild(button_alpha);
div_subs_s.appendChild(button_filter);
div_subs_s.appendChild(Object.assign(document.createElement('h3'), {
textContent: "Subscribed"
}));
div_subs_s.appendChild(input_filter);
div_subs_s.appendChild(div_subs_c);
div_subs.appendChild(div_subs_s);
div_subs.appendChild(div_dummy);
div_subs.appendChild(button_collapse);
div_subs.setAttribute('id', 'subs-sticky');
div_head.appendChild(div_subs);
// Stop the panel before it collides with the footer when scrolling
// Not happy with this yet, uncomment if you want to use it
/*if ($('.fixed-navbar').length == 0) {
$(window).scroll(function(){
$('#subs-sticky').css('top', Math.min(rem_to_px(3.1625) + $(window).scrollTop(), $(document).outerHeight() - $('#footer').outerHeight() - $('#subs-sticky').outerHeight() - rem_to_px(3.5)));
});
} else {
$(window).scroll(function(){
$('#subs-sticky').css('top', Math.min(rem_to_px(3.1625), $(document).outerHeight() - $('#footer').outerHeight() - $('#subs-sticky').outerHeight() - $(window).scrollTop() - rem_to_px(3.5)));
});
}*/
populate();
}
})();
function collapse() {
const is_collapsed = localStorage.getItem('subs_collapsed');
if (is_collapsed === 'true') {
$('#middle .kbin-container').addClass('collapsed-subs');
$('#subs-sticky').addClass('collapsed-subs');
$('#subs-sticky-collapse').text('>');
} else {
$('#middle .kbin-container').removeClass('collapsed-subs');
$('#subs-sticky').removeClass('collapsed-subs');
$('#subs-sticky-collapse').text('<');
}
}
function sort() {
const ul_pins = $('#subs-sticky-pins');
ul_pins.hide();
ul_pins.children('li').appendTo($('#subs-sticky-main'));
ul_pins.children('li').remove();
const do_sort = localStorage.getItem('sort_alpha');
const button_recent = $('#sort-recent');
const button_alpha = $('#sort-alpha');
if (do_sort === 'true') {
sort_alpha($('#subs-sticky-main'));
button_alpha.addClass('active');
button_recent.removeClass('active');
} else {
button_recent.addClass('active');
button_alpha.removeClass('active');
}
let pins = localStorage.getItem('pinned_subs');
if (pins !== null && (pins = JSON.parse(pins)).length > 0) {
$('#subs-sticky-main > li').each(function() {
if (pins.includes($(this).find('a:nth-child(2)').attr('href'))) {
$(this).appendTo($('#subs-sticky-pins'));
}
});
ul_pins.show();
}
filter();
}
function fetch_next(p) {
let i = 0;
$('#subs-sticky .dummy li').remove();
$('#subs-sticky .dummy').load(window.location.origin + user + "/subscriptions?p=" + p + " #content .magazines ul", function(){
var els = $('#subs-sticky .dummy li');
els.each(function() {
i++;
const div = $(this).find('div');
const a = $(this).find('a');
const fig = $(this).find('figure');
$(this).find('small').remove();
if (fig.length > 0) {
fig.find('img').css({'height': '24px', 'width': '24px'});
a.prepend(fig);
} else {
a.prepend(`<figure style="background-color: rgba(128, 128, 128, 0.5); text-align: center;">
<i class="fa-solid fa-newspaper" style="opacity:50%;"></i></figure>`);
}
a.removeClass();
div.prepend(`<a class="icon pin-button" title="Pin magazine" aria-label="Pin magazine"><i class="fa-solid fa-thumbtack"></i></a>`);
$('#subs-sticky-main').append($(this));
});
if (i > 0) { fetch_next(p+1); }
else { localStorage.setItem('cached_subs', JSON.stringify({html: $('#subs-sticky-main').html(), expire: Date.now() + 15 * 60 * 1000})); sort(); collapse(); assign_pins(); }
});
}
function populate() {
var cached = JSON.parse(localStorage.getItem('cached_subs'));
if (cached === null || Date.now() >= cached.expire) { regen(); }
else { $('#subs-sticky-main').html(cached.html); $('#subs-sticky-pins').html(''); console.log("Fetched from cache"); sort(); collapse(); assign_pins(); }
}
function regen() {
$('#subs-sticky li').remove();
fetch_next(1);
}
function sort_alpha(list) {
const elems = list.children('li').detach().sort(function (a, b) {
return ($(a).text().trim().toLowerCase() < $(b).text().trim().toLowerCase() ? -1
: $(a).text().trim().toLowerCase() > $(b).text().trim().toLowerCase() ? 1 : 0);
});
list.append(elems);
}
function filter() {
const filter = $('#subs-filter').val();
const elems = $('#subs-sticky li');
elems.each(function() {
$(this).show();
if ($(this).text().trim().toLowerCase().indexOf(filter.trim().toLowerCase()) == -1) $(this).hide();
});
}
function assign_pins() {
$('.pin-button').on('click', function() {
const href = $(this).parent().children('a').eq(1).attr('href');
let pins = localStorage.getItem('pinned_subs');
if (pins !== null && (pins = JSON.parse(pins)).length > 0) {
if (pins.includes(href)) {
pins.splice(pins.indexOf(href), 1);
} else {
pins.push(href);
}
} else {
pins = [href];
}
localStorage.setItem('pinned_subs', JSON.stringify(pins));
sort();
});
}
function rem_to_px(rem) {
return parseFloat(rem) * parseFloat(getComputedStyle(document.documentElement).fontSize);
}