GreasyFork Moderator Actions Log Viewer

to view GreasyFork Moderator Actions Log Table

Устаревшая версия за 24.05.2023. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==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://greatest.deepsurf.us/*/moderator_actions*
// @icon          https://www.google.com/s2/favicons?sz=64&domain=greatest.deepsurf.us
// @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://greatest.deepsurf.us/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...
})();