WGSM - PluginParty

It's a plugin party! List all available WindowsGSM plugins on a single page and filter through them with a searchbar!

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        WGSM - PluginParty
// @author      WirlyWirly
// @version     0.8
// @namespace   https://github.com/WirlyWirly

// @match       https://windowsgsm.com/*

// @icon        https://windowsgsm.com/favicon.ico
// @description It's a plugin party! List all available WindowsGSM plugins on a single page and filter through them with a searchbar!

// @homepage    https://gist.github.com/WirlyWirly/fb6fce9864eb8d1701cb226b6f83cb45/

// @grant       GM_xmlhttpRequest

// @run-at 		document-end
// ==/UserScript==

function pluginParty() {
    // The main pluginParty function; Load each plugins-page and then list all available plugins onto the current page
    
    let mainListElement = document.querySelector("main div.mx-auto")
    let navBarElement = mainListElement.querySelector("nav[aria-label='Page navigation']").parentElement

    // let pluginCount = mainListElement.childNodes[0].querySelector('span')
    let pluginCount = mainListElement.childNodes[0].querySelectorAll('span')[2].innerText
    mainListElement.childNodes[0].innerHTML = `<span class="font-semibold text-gray-900 dark:text-white"><a href="https://gist.github.com/WirlyWirly/fb6fce9864eb8d1701cb226b6f83cb45">PluginParty</a></span> [v${GM_info.script.version}] - Showing All <span class="font-semibold text-gray-900 dark:text-white">${pluginCount}</span> Plugins`

    // Clean the current page by removing all listed plugins
    mainListElement.querySelectorAll("a[target='_blank']").forEach((item) => item.remove())

    let pageElements = navBarElement.querySelectorAll("li a")
    for (let element of pageElements) {
        // Create a placeholder element so that page results are displayed in-order

        let pageNumber = element.innerText
        let placeholder = document.createElement('div')
        placeholder.id = `placeholder${pageNumber}`

        mainListElement.insertBefore(placeholder, navBarElement)
    }

    for (let element of pageElements) {
        // Asychronous: For each page, get and append its list of plugins into the current page

        let placeholder = mainListElement.querySelector(`#placeholder${element.innerText}`)

        GM_xmlhttpRequest({
            'url': element.href,
            'method': 'GET',
            'onload': function(response) {
                let pageDOM = response.responseXML
                
                // The plugin elements for each page
                let pluginElements = pageDOM.querySelectorAll("main div.mx-auto a[target='_blank']")

                // Insert the plugins into the current page, above their corresponding placeholder
                for (let item of pluginElements) {
                    try{
                        // Remove 'WindowsGSM.' from the plugin title
                        let cleanedTitle = item.querySelector('h2').innerText.match(/^WindowsGSM\.(.*)/i, '')
                        item.querySelector('h2').innerText = cleanedTitle[1]
                    } catch(error) {
                        // console.log(error, item)
                    }

                    // Set the matching 'searchterm' attribute now so that searches are faster later
                    item.setAttribute('data-searchterm', item.querySelector('h2').innerText.toLowerCase())

                    mainListElement.insertBefore(item, placeholder)
                }

                // pluginCount.innerText++
                placeholder.remove()
            }
        })

    }

    // Remove the pageNavBar so that users don't constantly load dupe pages
    navBarElement.remove()

    // Create and inject the search bar above the plugins listing
    let searchBar = document.createElement('input')
    searchBar.id = 'searchBar'
    searchBar.type = 'text'
    searchBar.className = 'mb-4 w-full dark:bg-gray-800 text-gray-500 dark:text-gray-400 rounded-lg dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-700'
    searchBar.placeholder = 'Search Plugins...'

    mainListElement.insertBefore(searchBar, mainListElement.childNodes[0].nextSibling)
    let pluginElements = searchBar.addEventListener('click', function() {
        // When the search bar is clicked into, collect a list of all available plugins
        return pluginElements = mainListElement.querySelectorAll("a[target='_blank']")
    })

    searchBar.addEventListener('keyup', function() {
        // When a key is entered, filter the results based on each plugin-elements 'searchterm' attribute
        let term = searchBar.value.toLowerCase()

        pluginElements.forEach((item) => {
            if (item.dataset['searchterm'].includes(term)) {
                item.hidden = false
            } else {
                item.hidden = true
            }
        })
    })
}

let observer = new MutationObserver(function(mutation) {
    // Code to run when page changes are detected

    if (document.URL.match(/.+windowsgsm-plugins.*/)) {
        // The current webpage IS the plugins page, so run pluginParty...
        pluginParty()
    } else {
        // The current webpage is NOT the plugins page, so do nothing...
        return
    }
})

// --------------- START ---------------

let target = document.querySelector('main')
let config = { childList: true }

if (document.URL.match(/.+windowsgsm-plugins.*/)) {
    // The current webpage IS the plugins page, so run pluginParty...
    pluginParty()
    observer.observe(target, config)
} else {
    // The current webpage is NOT the plugins page, so wait for changes...
    observer.observe(target, config)
}