- // ==UserScript==
- // @name GreasyFork Moderator Actions Log Viewer
- // @namespace http://tampermonkey.net/
- // @version 0.2.0
- // @description to view GreasyFork Moderator Actions Log Table
- // @author CY Fung
- // @match https://greasyfork.org/*/moderator_actions*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
- // @grant none
- // @run-at document-idle
- // @license MIT
- // ==/UserScript==
-
- (function () {
- 'use strict';
-
- function formatDateToCustomFormat(date) {
- var year = date.getFullYear();
- var month = padZero(date.getMonth() + 1);
- var day = padZero(date.getDate());
- var hours = padZero(date.getHours());
- var minutes = padZero(date.getMinutes());
- var timeZoneOffset = getTimeZoneOffsetString();
-
- return year + '.' + month + '.' + day + ' ' + hours + ':' + minutes + ' (GMT' + timeZoneOffset + ')';
- }
-
- function padZero(value) {
- return value.toString().padStart(2, '0');
- }
-
- function getTimeZoneOffsetString() {
- var offsetMinutes = new Date().getTimezoneOffset();
- var sign = offsetMinutes > 0 ? '-' : '+';
- var offsetHours = Math.floor(Math.abs(offsetMinutes) / 60);
-
- return sign + offsetHours;
- }
-
-
- function setupTableContent() {
-
- for (const s of document.querySelectorAll('.log-table td:nth-child(1) relative-time:not(.jsm)')) {
-
- s.classList.add('jsm')
-
- let date = s.date;
- if (date) {
-
- let e = document.createElement('div');
- let q = formatDateToCustomFormat(date);
- q = q.split(' ');
- // e.textContent = formatDateToCustomFormat(date);
- e.className = 'date-entry';
- s.classList.add('jsm-hidden')
- s.after(e)
-
- e.appendChild(Object.assign(document.createElement('span'), {
- className: 'date-entry-date',
-
- textContent: q[0]
- }));
-
- e.appendChild(Object.assign(document.createElement('span'), {
- className: 'date-entry-time',
-
- textContent: q[1]
- }));
-
- e.appendChild(Object.assign(document.createElement('span'), {
- className: 'date-entry-gmt',
- textContent: q[2]
- }));
- }
-
-
- }
-
-
- for (const s of document.querySelectorAll('.log-table td:nth-child(3) a[href*="/scripts/"]:not(.jsm)')) {
-
-
-
- s.classList.add('jsm')
- let m = /\/scripts\/(\d+)/.exec(s.href);
- if (m) {
- let e = document.createElement('div');
- e.className = 'script-entry';
- s.replaceWith(e);
- e.appendChild(s);
-
- let span = document.createElement('span');
- span.className = 'entry-rid';
- span.textContent = m[1]
- e.prepend(span)
- }
-
-
- }
-
-
- for (const s of document.querySelectorAll('.log-table td:nth-child(3) a[href*="/users/"]:not(.jsm)')) {
-
-
-
- s.classList.add('jsm')
- let m = /\/users\/(\d+)/.exec(s.href);
- if (m) {
- let e = document.createElement('div');
- e.className = 'user-entry';
- s.replaceWith(e);
- e.appendChild(s);
-
- let span = document.createElement('span');
- span.className = 'entry-rid';
- span.textContent = m[1]
- e.prepend(span)
- }
-
-
- }
-
-
- for (const s of document.querySelectorAll('.log-table td:nth-child(4)')) {
-
- convertToBadges(s);
-
-
- }
-
-
- for (const s of document.querySelectorAll('.log-table td:nth-child(5)')) {
-
- convertHyperlinks(s);
-
-
- }
-
- }
- function convertHyperlinks(elm) {
- var walker = document.createTreeWalker(elm, NodeFilter.SHOW_TEXT, null, false);
-
- while (walker.nextNode()) {
- var textNode = walker.currentNode;
- var parentNode = textNode.parentNode;
-
- var text = textNode.nodeValue.trim();
- if (text.length > 0 && parentNode.tagName !== 'A') {
- var match = text.match(/(https?:\/\/[^\s]+)/);
-
- if (match) {
- var link = document.createElement('a');
- link.href = match[0];
- link.textContent = match[0].replace('https://greasyfork.org/scripts/', 'scripts/');
-
- var before = document.createTextNode(text.substring(0, match.index));
- var after = document.createTextNode(text.substring(match.index + match[0].length));
-
- parentNode.insertBefore(before, textNode);
- parentNode.insertBefore(link, textNode);
- parentNode.insertBefore(after, textNode);
-
- parentNode.removeChild(textNode);
- }
- }
- }
- }
-
-
- function convertToBadges(elm) {
-
- const converts = {
- 'Ban': () => Object.assign(document.createElement('img'), {
- src: `https://img.shields.io/badge/action-ban-FF5C5C`
- }),
- 'Delete and lock': () => Object.assign(document.createElement('img'), {
- src: `https://img.shields.io/badge/action-delete-FF9933`
- }),
- 'Undelete': () => Object.assign(document.createElement('img'), {
- src: `https://img.shields.io/badge/action-undelete-66CC66`
- }),
-
- }
-
- var walker = document.createTreeWalker(elm, NodeFilter.SHOW_TEXT, null, false);
-
- while (walker.nextNode()) {
- var textNode = walker.currentNode;
- var parentNode = textNode.parentNode;
-
- var text = textNode.nodeValue.trim();
- if (text.length > 0 && parentNode.tagName !== 'A' && parentNode.tagName !== 'IMG') {
- let t = text.trim();
- if (converts[t]) textNode.replaceWith(converts[t]());
- }
- }
- }
-
-
-
- function convertToAdvancedTable(tableSelector) {
-
- setupTableContent();
- // Get the table element
- var table = document.querySelector(tableSelector);
-
- // Add classes to the table and its components
- table.classList.add('advanced-table');
- table.tHead.classList.add('advanced-table-head');
- table.tBodies[0].classList.add('advanced-table-body');
-
- // Get the table headers
- var headers = Array.from(table.tHead.rows[0].cells);
-
- var sortOrder = []; // Track sort order for each column
-
- // Add classes and event listeners to enable sorting
- headers.forEach(function (header, index) {
- header.classList.add('sortable');
- header.addEventListener('click', function (event) {
- if (!event.target.classList.contains('search-input')) {
- sortTable(table, index, sortOrder);
- sortOrder[index] = !sortOrder[index]; // Toggle sort order
- }
- });
-
- // Create search input element
- var searchInput = document.createElement('input');
- searchInput.setAttribute('type', 'text');
- searchInput.setAttribute('placeholder', 'Search');
- searchInput.classList.add('search-input');
- searchInput.addEventListener('input', function () {
- filterTable(table, index);
- });
- header.appendChild(searchInput);
-
- // Create sort icon element
- var sortIcon = document.createElement('span');
- sortIcon.classList.add('sort-icon');
- header.appendChild(sortIcon);
- });
- }
-
- // Function to sort the table by column index
- function sortTable(table, columnIndex, sortOrder) {
- var rows = Array.from(table.tBodies[0].rows);
-
- rows.sort(function (a, b) {
- var cellA = a.cells[columnIndex].textContent.toLowerCase();
- var cellB = b.cells[columnIndex].textContent.toLowerCase();
-
- if (sortOrder[columnIndex]) {
- // Sort in descending order
- if (cellA < cellB) return 1;
- if (cellA > cellB) return -1;
- return 0;
- } else {
- // Sort in ascending order
- if (cellA < cellB) return -1;
- if (cellA > cellB) return 1;
- return 0;
- }
- });
-
- table.tBodies[0].innerHTML = '';
- rows.forEach(function (row) {
- table.tBodies[0].appendChild(row);
- });
- }
-
- // Function to filter the table by column index
- function filterTable(table, columnIndex) {
- var filterValue = table.tHead.rows[0].cells[columnIndex].querySelector('.search-input').value.toLowerCase();
- var rows = Array.from(table.tBodies[0].rows);
-
- rows.forEach(function (row) {
- var cellValue = row.cells[columnIndex].textContent.toLowerCase();
- row.style.display = cellValue.includes(filterValue) ? '' : 'none';
- });
- }
-
-
- const colsize = (idx) => `.log-table th:nth-child(${idx}), .log-table td:nth-child(${idx}){width:${colsizes[idx - 1]}; max-width:${colsizes[idx - 1]};}`
-
- let colsizes = [36, 32, 120, 32, 64];
- let colsizeSum = colsizes.reduce((a, b) => a + b, 0);
- colsizes = colsizes.map(t => (t / colsizeSum * 100).toFixed(2) + '%');
-
- document.head.appendChild(document.createElement('style')).textContent = `
-
- .log-table.advanced-table td img{
- display:block;
- }
-
- .advanced-table-head th {
- position: relative;
- padding: 8px;
- }
-
- .sortable {
- cursor: pointer;
- }
-
- .sort-icon {
- position: absolute;
- top: 50%;
- right: 8px;
- transform: translateY(-50%);
- width: 8px;
- height: 8px;
- border-left: 4px solid transparent;
- border-right: 4px solid transparent;
- transition: transform 0.2s ease;
- }
-
- .sortable.asc .sort-icon {
- border-bottom: 4px solid #000;
- }
-
- .sortable.desc .sort-icon {
- border-top: 4px solid #000;
- }
-
- .search-input {
- width: 100%;
- box-sizing: border-box;
- padding: 4px;
- border: 1px solid #ccc;
- border-radius: 4px;
- }
-
-
-
- ${colsize(1)}
- ${colsize(2)}
- ${colsize(3)}
- ${colsize(4)}
- ${colsize(5)}
-
- .entry-rid{
- font-size:80%;
- font-family: 'Open Sans',sans-serif,"Segoe UI Emoji";
- }
- .date-entry{
- font-family: 'Open Sans',sans-serif,"Segoe UI Emoji";
-
- }
-
- .user-entry, .script-entry{
- display: flex;
- column-gap: 4px;
- place-items: center;
- }
-
- .script-entry a[href]{
- overflow: hidden;
- white-space: nowrap;
- width: 24em;
- text-overflow: ellipsis;
- }
-
-
- /* Shared styles for both ".user-entry > .entry-rid" and ".script-entry > .entry-rid" */
- .user-entry > .entry-rid,
- .script-entry > .entry-rid {
-
- display: inline-flex;
- place-content: center;
- padding: 4px 8px;
- color: #fff; /* Set an appropriate white text color */
- border-radius: 8px; /* Set the desired border radius */
- transition: background-color 0.3s; /* Add transition effect */
- min-width: 4em;
- }
-
- /* Styles for ".user-entry > .entry-rid" */
- .user-entry > .entry-rid {
- background-color: #4A90E2; /* Set your desired background color */
- }
-
- .user-entry > .entry-rid:hover {
- background-color: #77B5FF; /* Set your desired hover background color */
- }
-
- /* Styles for ".script-entry > .entry-rid" */
- .script-entry > .entry-rid {
- background-color: #B146C2; /* Set your desired background color */
- }
-
- .script-entry > .entry-rid:hover {
- background-color: #D27BFF; /* Set your desired hover background color */
- }
-
- relative-time.jsm-hidden {
- display:none;
- }
-
- .date-entry-date{
-
- display: inline-block;
- padding: 4px 8px;
- color: #fff; /* Set an appropriate white text color */
- border-radius: 8px; /* Set the desired border radius */
- transition: background-color 0.3s; /* Add transition effect */
- font-size:70%;
- background-color: #336699;
- }
-
-
- .date-entry-time{
-
- display: inline-block;
- padding: 4px 8px;
- color: #fff; /* Set an appropriate white text color */
- border-radius: 8px; /* Set the desired border radius */
- transition: background-color 0.3s; /* Add transition effect */
- font-size:70%;
- background-color: #663366;
- }
-
- .date-entry-gmt{
-
- display: inline-block;
- padding: 4px 8px;
- color: #fff; /* Set an appropriate white text color */
- border-radius: 8px; /* Set the desired border radius */
- transition: background-color 0.3s; /* Add transition effect */
- font-size:40%;
- background-color: #336633;
-
- }
-
- `
-
- setInterval(() => {
-
- let table = document.querySelector('table.log-table:not(.advanced-table)')
- if (table) {
- requestAnimationFrame(() => {
- if (table.classList.contains('advanced-table')) return;
- table = null;
- convertToAdvancedTable('table.log-table')
- });
- }
-
- }, 100);
-
-
-
- // Your code here...
- })();