Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Catalog list view
- // @namespace https://codeforces.com/profile/-is-this-fft-
- // @version 1.0
- // @description List view in Codeforces catalog
- // @author -is-this-fft-
- // @match https://codeforces.com/catalog*
- // @icon https://www.google.com/s2/favicons?domain=codeforces.com
- // @require https://cdn.datatables.net/1.11.4/js/jquery.dataTables.min.js
- // @resource DATATABLES_CSS https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css
- // @grant GM_getResourceText
- // @grant GM_addStyle
- // ==/UserScript==
- (function() {
- 'use strict';
- function init() {
- if (document.getElementsByClassName("_CatalogViewFrame_topManagementBar")[0] != undefined) {
- // disable the userscript in management mode
- return;
- }
- const dataTablesCss = GM_getResourceText("DATATABLES_CSS");
- GM_addStyle(dataTablesCss);
- // oh the humanity
- GM_addStyle(`
- #clvContentTable ._name a {
- font-size: 1.3rem;
- font-weight: initial;
- }
- .dataTables_wrapper {
- clear: unset;
- }
- table.dataTable {
- clear: unset;
- }
- #clvContentTable_wrapper {
- margin-top: -3rem;
- }
- #clvContentTable tbody td:nth-child(2) {
- text-align: left;
- }
- #clvContentTable ._name {
- padding-left: 0;
- padding-right: 0;
- }
- #clvContentTable ._name small {
- margin-top: 0.5rem;
- }
- table.dataTable.cell-border thead th:first-child {
- border-left: 1px solid #ddd;
- }
- #clvListViewButton {
- margin-left: 1rem;
- z-index: 1000;
- position: relative;
- }`);
- addCatalogTableViewElement();
- const blogItems = getAllBlogItems();
- $("#clvContentTable").DataTable({
- data: blogItems,
- columns: [
- {
- title: "Author",
- data: "author",
- render: data => `<a href="/profile/${data.name}" class="${data.class}">${data.name}</a>`
- },
- {
- title: "Title",
- data: "title",
- render: data => {
- let html = `<span class="_name"><a href="${data.href}">${data.title}</a>`;
- if (data.description != null) {
- html += `<br /><small>${data.description}</small>`;
- }
- html += "</span>";
- return html;
- }
- },
- {
- title: "Creation time",
- data: "blogCreationTime",
- render: data => getFormattedDate(data)
- },
- {
- title: "Catalog update",
- data: "catalogUpdateTime",
- render: data => getFormattedDate(data)
- }
- ],
- order: [2, "desc"], // by creation time descending
- paging: false,
- });
- $("#clvContentTable_wrapper").toggle();
- if (document.cookie.split("; ").find(row => row.startsWith("catalogListView"))) {
- toggleDisplay(false);
- }
- const captionElement = document.querySelector("#pageContent .caption");
- const listViewLink = document.createElement("a");
- listViewLink.setAttribute("href", "#");
- listViewLink.setAttribute("id", "clvListViewButton");
- listViewLink.appendChild(document.createTextNode("Switch view"));
- listViewLink.addEventListener("click", () => {
- toggleDisplay(true);
- });
- captionElement.insertBefore(listViewLink, null);
- }
- function toggleDisplay(updateCookie) {
- $("#clvContentTable_wrapper").toggle();
- $("._CatalogViewFrame_catalog").toggle();
- $("._CatalogViewFrame_title_actions").toggle();
- if (updateCookie) {
- if ($("#clvContentTable_wrapper").is(":visible")) {
- document.cookie = "catalogListView=true; expires=Fri, 31 Dec 9999 23:59:59 GMT";
- } else {
- document.cookie = "catalogListView=false; expires=Thu, 01 Jan 1970 00:00:00 GMT";
- }
- }
- }
- function addCatalogTableViewElement() {
- const catalogTable = document.createElement("table");
- catalogTable.setAttribute("id", "clvContentTable");
- catalogTable.setAttribute("class", "row-border cell-border hover");
- const pageContentDiv = document.getElementById("pageContent");
- const catalogSection = document.getElementById("_CatalogViewFrame_catalog");
- pageContentDiv.insertBefore(catalogTable, catalogSection);
- }
- function getAllBlogItems() {
- const blogItemDivs = document.getElementsByClassName("_catalogBlogEntry");
- return Array.from(blogItemDivs, convertBlogDivToBlogItem);
- }
- function convertBlogDivToBlogItem(blogDiv) {
- const catalogUpdateTimeMillis = blogDiv.getAttribute("data-updatetimemillis");
- const catalogUpdateTime = new Date(parseInt(catalogUpdateTimeMillis, 10));
- const blogAddress = blogDiv.getElementsByTagName("a")[0].getAttribute("href");
- const blogTitle = blogDiv.getElementsByClassName("_nameContent")[0].innerHTML;
- const descriptionElement = blogDiv.getElementsByTagName("small")[0];
- const blogDescription = descriptionElement == undefined ? null : descriptionElement.innerText;
- const authorLinkElement = blogDiv.getElementsByTagName("a")[1];
- const author = authorLinkElement.getAttribute("href").substring("/profile/".length);
- const authorClass = authorLinkElement.getAttribute("class");
- const creationTimeFormatted = blogDiv.getElementsByClassName("format-humantime")[0].getAttribute("title");
- const creationTime = convertCodeforcesDate(creationTimeFormatted);
- return {
- title: {title: blogTitle, description: blogDescription, href: blogAddress},
- author: {name: author, class: authorClass},
- blogCreationTime: creationTime,
- catalogUpdateTime: catalogUpdateTime
- };
- }
- function convertCodeforcesDate(dateString) {
- // codeforces format is "May/21/2020 17:51 UTC+2" (English)
- // or "21.05.2020 17:51 UTC+2" (Russian)
- // we will convert it to a javascript date object
- // doing it manually is a stupid hack but it is such a
- // small thing in this case, using a lib is equally annoying.
- if (dateString.indexOf('/') != -1) {
- return convertEnglishDate(dateString);
- } else {
- return convertRussianDate(dateString);
- }
- }
- const monthDict = {
- "Jan": 0,
- "Feb": 1,
- "Mar": 2,
- "Apr": 3,
- "May": 4,
- "Jun": 5,
- "Jul": 6,
- "Aug": 7,
- "Sep": 8,
- "Oct": 9,
- "Nov": 10,
- "Dec": 11
- };
- function convertEnglishDate(dateString) {
- const datePart = dateString.split(' ')[0];
- const dateComponents = datePart.split('/');
- const monthAbbrev = dateComponents[0];
- const day = parseInt(dateComponents[1], 10);
- const year = parseInt(dateComponents[2], 10);
- const month = monthDict[monthAbbrev];
- return new Date(year, month, day);
- }
- function convertRussianDate(dateString) {
- const datePart = dateString.split(' ')[0];
- const dateComponents = datePart.split('.');
- const day = parseInt(dateComponents[0], 10);
- const month = parseInt(dateComponents[1], 10) - 1;
- const year = parseInt(dateComponents[2], 10);
- return new Date(year, month, day);
- }
- function getFormattedDate(date) {
- return `${date.getFullYear()}/${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getDate().toString().padStart(2, '0')}`;
- }
- init();
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement