FPLStats watchlist

Updates the FPLStats websites to allow selection of players to a watchlists. Watchlist is toggleable. By default also displays every player now

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         FPLStats watchlist
// @namespace    http://tampermonkey.net/
// @version      1.1
// @license MIT
// @description  Updates the FPLStats websites to allow selection of players to a watchlists. Watchlist is toggleable. By default also displays every player now
// @author       DangerSalmon
// @match        http://www.fplstatistics.co.uk/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=fplstatistics.co.uk
// @grant       GM.setValue
// @grant       GM.getValue
// ==/UserScript==

// Currently I'm just editing the view on the page. This means its a little slow to update as it needs all the data to be displayed, then operations to happen.
// A potential improvement would be to make this a Chrome extension which pulls the data from network and skips the inital display. But likely FPLStats will add their
// own watchlist before I get that working :P Especially since they have the link ID now. But this added ability to watch certain players so I still think its useful

// I was thinking of having two selectable lists. One for your team and one for watchlist

// Also should add loading states but can't really be arsed right now

/*
// Example of how the data is stored in greasemonkey storage. Rare occasion where same name same club could duplicate the results, may see if better way to sort later
const myTeam = [
    {club: "Man City", name: "Haaland"},
    {club: "Chelsea",name: "Mendy"},
    {club: "Leicester",name: "Ward"},
    {club: "Newcastle",name: "Trippier"},
    {club: "Liverpool",name: "Salah"},
    {club: "Fulham",name: "Andreas"},
    {club: "Leicester",name: "Barnes"},
    {club: "Arsenal",name: "Jesus"},
]*/

let latestTableRows = [] //#myDataTable > tbody > tr
let isFiltered = false

/**********
The FPLstats site when first getting results shows an error table row. Need to wait for this to go away before filtering
**********/
const waitForElement = async (whereWait) => {
    await new Promise(r => setTimeout(r, 100));
}

const waitForNoTableError = async () => {
    await waitForElement('waitForNoTableError')
    const searchError = document.querySelectorAll('#myDataTable > tbody > tr')[0]
    if (searchError.textContent.includes('Error: Invalid search / IP Ban or initialising table')) return waitForNoTableError()
    else return true
}
/**********************************************/

/**** Function show all players in data *****/
const showAllPlayers = async () => {
    const newDropdownOption = document.querySelectorAll('select[name=myDataTable_length] option')[3]
    newDropdownOption.value = 700
    newDropdownOption.text = '700'

    const select = document.querySelector('select[name=myDataTable_length]')
    select.value = 700;
    select.dispatchEvent(new Event('change'));

    await waitForNoTableError()
    latestTableRows = document.querySelectorAll('#myDataTable > tbody > tr')
    return true
}
/**********************************************/


/**** Function to toggle filtering my team *****/
const toggleFilterWatchlist = async () => {
    const storedTeam = await GM.getValue('fplStats_storedTeam')
    if (isFiltered) {
        isFiltered = false
        document.querySelector('#watchlistFilter').style.backgroundColor = 'transparent'
        latestTableRows.forEach((playerRow, index) => {playerRow.style.display = 'table-row'})
    } else {
        isFiltered = true
        document.querySelector('#watchlistFilter').style.backgroundColor = '#b3ffaa'
        latestTableRows.forEach((playerRow, index) => {
            const playerName = playerRow.querySelectorAll('td')[1].innerText
            const playerClub = playerRow.querySelectorAll('td')[2].innerText
            const isIncluded = storedTeam.some((myTeamPlayer) => {
                return myTeamPlayer.name === playerName && myTeamPlayer.club === playerClub
            })
            if (!isIncluded) playerRow.style.display = 'none'
        })
    }
}
/**********************************************/

/**** Function to add toggle filtering my team button*****/
const addFilterButton = () => {
    const filterDiv = document.querySelector('div #myDataTable_length')
    const newElement = document.createElement('div');
    newElement.id = 'watchlistFilter'
    newElement.innerText = 'Watchlist'
    newElement.style.backgroundColor = isFiltered ? '#b3ffaan' : 'transparent'
    newElement.style.border = isFiltered ? '1px solid green' : '1px solid black'
    newElement.style.cursor = 'pointer'
    newElement.style.display = 'inline-block'
    newElement.style.marginLeft = '5px'
    newElement.style.marginRight = '5px'
    newElement.style.paddingLeft = '5px'
    newElement.style.paddingRight = '5px'
    newElement.onclick = () => {toggleFilterWatchlist()}
    filterDiv.parentNode.insertBefore(newElement, filterDiv.nextSibling);
}
/**********************************************/

/**** Functions to add/remove players from watchlist*****/
const AddPlayerToWatchlist = async (newPlayer) => {
    let storedTeam = await GM.getValue('fplStats_storedTeam')
    if (!storedTeam) {
        GM.setValue('fplStats_storedTeam', [{club: newPlayer.club, name: newPlayer.name}])
    }
    else if(storedTeam.some((myTeamPlayer) => {
        return myTeamPlayer.name === newPlayer.name && myTeamPlayer.club === newPlayer.club
    })) {
         return
    }
    else {
        storedTeam.push(newPlayer)
    }
    console.log(storedTeam)
    await GM.setValue('fplStats_storedTeam', storedTeam)
}

const removePlayerFromWatchlist = async (newPlayer) => {
    let storedTeam = await GM.getValue('fplStats_storedTeam')
    if (!storedTeam) {
        return
    }
    else {
        storedTeam = storedTeam.filter(player => {
            return player.name !== newPlayer.name && player.club !== newPlayer.club;
        });
    }
    console.log(storedTeam)
    await GM.setValue('fplStats_storedTeam', storedTeam)
}
/**********************************************/

/*******Function which adds an Add/Remove button beside each player ***********/
const addTogglePlayerToTeamButton = async () => {
    if (latestTableRows.length) {

        /** Add 'Watchlist' text to header **/
        const tableHeaderRow = document.querySelector('#myDataTable > thead > tr')
        const headerWatchlistElement = document.createElement('th');
        headerWatchlistElement.className = 'all sorting ui-state-default'
        headerWatchlistElement.alignItems = 'center'
        headerWatchlistElement.display = 'flex'
        headerWatchlistElement.height = '21px'
        headerWatchlistElement.innerText = 'Watchlist'
        headerWatchlistElement.style.margin = '0px 10xp'
        tableHeaderRow.insertAdjacentElement('beforeend', headerWatchlistElement);
        /**********************************/

        const storedTeam = await GM.getValue('fplStats_storedTeam')
        latestTableRows.forEach((playerRow) => {
            const playerName = playerRow.querySelectorAll('td')[1].innerText
            const playerClub = playerRow.querySelectorAll('td')[2].innerText
            const isIncluded = storedTeam.some((myTeamPlayer) => {
                return myTeamPlayer.name === playerName && myTeamPlayer.club === playerClub
            })
            const newElement = document.createElement('td');
            newElement.innerText = isIncluded ? 'Added' : 'Add'
            newElement.style.alignItems = 'center'
            newElement.style.backgroundColor = isIncluded ? '#b3ffaa' : 'transparent';
            newElement.style.border = isIncluded ? '1px solid green' : '1px solid black';
            newElement.style.cursor = 'pointer'
            newElement.style.display = 'flex'
            newElement.style.height = '21px'
            newElement.style.margin = '0px 10xp'
            newElement.style.position = 'relative'
            newElement.style.width = '50px'
            newElement.onclick = async (event, data = {element: newElement, newPlayer: {club: playerClub, name: playerName}}) => {
                event.stopPropagation();
                const {element, newPlayer} = {...data}
                const latestStoredTeam = await GM.getValue('fplStats_storedTeam')
                const isIncluded = latestStoredTeam.some((myTeamPlayer) => {
                    return myTeamPlayer.name === newPlayer.name && myTeamPlayer.club === newPlayer.club
                })
                if (isIncluded) {
                    await removePlayerFromWatchlist(newPlayer);
                    newElement.innerText = 'Add';
                    newElement.style.backgroundColor = 'transparent';
                    newElement.style.border = '1px solid black';
                } else {
                    await AddPlayerToWatchlist(newPlayer);
                    newElement.innerText = 'Added';
                    newElement.style.backgroundColor = '#b3ffaa'
                    newElement.style.border = '1px solid green';
                }
            }
              if(playerRow.querySelector('td')) {
                  playerRow.insertAdjacentElement('beforeend',newElement);
              }
        })
    }
}

/***********
Below is whats actually ran when the FPLStats site is launched.
***********/
window.onload = async function () {
    await showAllPlayers()
    await addFilterButton()
    await addTogglePlayerToTeamButton()
}
/**********************************************/