Greasy Fork is available in English.

Blue Archive: Ranking List

Convert character profiles into modals that pop up when you click their name. Greatly improves readability. https://www.levelwinner.com/blue-archive-tier-list-ranking-the-best-students-in-the-game/

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         Blue Archive: Ranking List
// @namespace    mailto:daegon.xzing@gmail.com
// @version      1.2
// @description  Convert character profiles into modals that pop up when you click their name. Greatly improves readability. https://www.levelwinner.com/blue-archive-tier-list-ranking-the-best-students-in-the-game/
// @author       Daegon Xzing
// @match        https://www.levelwinner.com/blue-archive-tier-list-ranking-the-best-students-in-the-game/
// @icon         https://play-lh.googleusercontent.com/fvO6BfEpj5XFDbxD8OFRivcj5yEaUWTvxRlzczB1j5KidRAfEnTrzMFAsJhmzdgZJk0A=s96-rw
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Transparent background overlay
    const overlay = document.createElement("div")
    overlay.style.position = "fixed"
    overlay.style.top = 0
    overlay.style.bottom = 0
    overlay.style.left = 0
    overlay.style.right = 0
    overlay.style.backgroundColor = "white"
    overlay.style.opacity = 0.7
    overlay.style.zIndex = 100
    overlay.style.display = "none"
    document.body.append(overlay)

    // hide modals, enable scrolling
    const hideAllModals = (event) => {
        event?.preventDefault()
        const characterEls = [...document.querySelectorAll(".character")]
        characterEls.forEach((el) => {
            el.style.display = "none"
        })
        overlay.style.display = 'none'
        document.documentElement.style.overflow = 'scroll'
        document.body.scroll = "yes"
    }

    // show character modal, disable scrolling
    const showCharacter = (name) => {
        console.log("showCharacter", {name})
        const sanitizedName = name.replace(/[\*,]/g, "")

        // names sometimes were mis-typed, so we do a bit of fuzzy matching
        const namePossibilities = [
            sanitizedName,
            sanitizedName.replace("(Hot Spring)", "(Hot Springs)"),
            sanitizedName.replace("(Swimsuit)", "(Hot Springs)")
        ]

        hideAllModals()

        let match = undefined
        namePossibilities.forEach((namePossibility) => {
            match ||= document.querySelector(`.character[data-char-part-name='${namePossibility}'], .character[data-char-full-name='${namePossibility}']`)
        })

        console.log("match", {match})

        if (match) {
            match.style.display = "flex"
            overlay.style.display = "block"
            document.documentElement.style.overflow = 'hidden'
            document.body.scroll = "no"
        }

    }

    // convert comma-separated name text into clickable names
    const nameLists = [...document.querySelectorAll(".tablepress tr td:nth-child(2) strong")]
    nameLists.forEach((el) => {
        const names = el.innerText.replace("Kayoko (New Year) Ui", "Kayoko (New Year), Ui").split(", ")
        el.innerHTML = ""
        names.forEach((name, index) => {
            const nameNode = document.createElement("span")
            nameNode.onclick = (event) => {
                event.preventDefault()
                const name = event.target.innerText

                showCharacter(name)
            }
            nameNode.innerText = name
            nameNode.style.cursor = "pointer"
            el.appendChild(nameNode)

            if (index < names.length - 1) {
                const comma = document.createTextNode(", ")
                el.appendChild(comma)
            }
        })

    })

    // flag the start of each character's profile
    const profilePics = [...document.querySelectorAll(".wp-block-image")]
    profilePics.forEach((el) => {
        const startingElement = el.previousElementSibling
        startingElement.setAttribute("data-start-element", true)
    })

    // shove character profiles into hidden modal divs
    const charNames = [...document.querySelectorAll("[data-start-element]")]
    charNames.forEach((startingElement) => {
        const fullName = startingElement.innerText.trim()
        const partName = fullName.substr(fullName.indexOf(" ") + 1).trim()
        console.log({fullName}, {partName})

        const wrapper = document.createElement("div")
        wrapper.classList.add("character")
        wrapper.setAttribute("data-char-full-name", fullName)
        wrapper.setAttribute("data-char-part-name", partName)
        wrapper.style.display = "none"
        wrapper.style.flex = 1
        wrapper.style.position = "fixed"
        wrapper.style.left = 0
        wrapper.style.top = 0
        wrapper.style.bottom = 0
        wrapper.style.right = 0
        wrapper.style.alignItems = "stretch"
        wrapper.style.justifyContent = "center"
        wrapper.style.zIndex = 101
        wrapper.onclick = hideAllModals
        startingElement.insertAdjacentElement("beforebegin", wrapper)

        const innerWrapper = document.createElement("div")
        innerWrapper.style.backgroundColor = "white"
        innerWrapper.style.display = "flex"
        innerWrapper.style.flex = 1
        innerWrapper.style.flexGrow = 1
        innerWrapper.style.flexDirection = "column"
        innerWrapper.style.maxWidth = "700px"
        innerWrapper.style.borderLeftWidth = "1px"
        innerWrapper.style.borderRightWidth = "1px"
        innerWrapper.style.borderColor = "#CCC"
        innerWrapper.style.borderStyle = "solid"
        innerWrapper.onclick = (event) => event.stopPropagation()
        wrapper.append(innerWrapper)

        const closeBtn = document.createElement("a")
        closeBtn.setAttribute("href", "#")
        closeBtn.innerText = "Close"
        closeBtn.onclick = hideAllModals
        closeBtn.style.textAlign = "center"
        closeBtn.style.padding = "20px"
        innerWrapper.append(closeBtn)

        const innerContent = document.createElement("div")
        innerContent.style.display = "flex"
        innerContent.style.flexGrow = 1
        innerContent.style.flexDirection = "column"
        innerContent.style.overflow = "scroll"
        innerContent.style.paddingTop = "10px"
        innerContent.style.paddingBottom = "30px"
        innerContent.style.paddingLeft = "50px"
        innerContent.style.paddingRight = "50px"
        innerWrapper.append(innerContent)

        // keep shoving consecutive elements into the modal div until you run into
        // the start of the next character (or the end)
        let current = startingElement
        while (current) {
            const next = current.nextElementSibling
            innerContent.append(current)

            if (next.tagName === "H3" || next.hasAttribute("data-start-element")) {
                current = null
            } else {
                current = next
            }
        }

    })

    // remove all the tier headings
    const tierHeadings = [...document.querySelectorAll("h3")]
    tierHeadings.forEach((el) => {
        if (el.innerText.match(/.-Tier$/)) {
            el.remove()
        }
    })
})();