17lands Draft Log Comments

Tool for making comments to a 17lands draft log.

目前為 2025-12-01 提交的版本,檢視 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         17lands Draft Log Comments
// @namespace    http://tampermonkey.net/
// @version      2025-11-30
// @description  Tool for making comments to a 17lands draft log.
// @author       [email protected] (@iluvatar777)
// @match        https://www.17lands.com/draft/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=17lands.com
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==

function init() {
    const userid = localStorage.getItem(getStorageKey('userid', true));

    // add html to dom
    const el=document.getElementById('app')?.children[1]?.children[0];
    const mainDiv = document.createElement('div');
    mainDiv.id = 'comment-main';
    mainDiv.innerHTML = `
     <div id='comment-text-area' style='position: absolute; bottom: 10px; left: 20px; z-index: 100; background: rgba(0, 0, 0, .5);'>
           <div id='comment-controls' style='margin: 3px 0 7px 0; background: rgba(0, 0, 0, .5)'>
               <span>Add comments to draft log</span>
               <button id='comment-button-export'>export</button>
               <button disabled id='comment-button-import'>import</button>
               <span id='comment-id-span' style='display: inline-block;' title='changing will clear existing comments'>
                   user id: <span id='comment-user-id' style='color:#CCCCFF; text-decoration: underline; cursor: pointer'>${userid}</span>
                   <input id='comment-user-id-input' style='display:none'></input>
               </span>
               <button id='comment-button-clear' style='float: right'>clear comment</button>
           </div>
           <textarea id='comment-textarea' rows='4' cols='100'></textarea>
       </div>
    `;
    el.appendChild(mainDiv);

    if (userid === null) {
        toggleLogin();
    }

    //add listenrs
    window.navigation.addEventListener('navigate', handleNav);
    window.addEventListener("beforeunload", function(e){
        localStorage.removeItem(getStorageKey('pick'))
    });

    const clearButton = document.getElementById('comment-button-clear')
    clearButton.addEventListener("click", clearCurrentComment, false);
    const exportButton = document.getElementById('comment-button-export')
    exportButton.addEventListener("click", exportComments, false);
    const userIdDisplay = document.getElementById('comment-user-id')
    userIdDisplay.addEventListener("click", toggleLogin, false);
    const userIdInput = document.getElementById('comment-user-id-input')
    userIdInput.addEventListener("blur", userIdUpdate, false);
    const testArea = document.getElementById('comment-textarea')
    testArea.addEventListener("focus", highlightLogin, false);
}

function handleNav(event) {
    const url = event.destination.url.split('/');
    if (url.length !== 7) {
        //pick not in URL, ignore
        return;
    }
    const userid = localStorage.getItem(getStorageKey('userid', true));
    const oldPick = localStorage.getItem(getStorageKey('pick'))
    const newPick = 'p' + url[5] + 'p' + url[6];
    const draftid = url[4];
    localStorage.setItem(getStorageKey('pick'), newPick)

    if ((oldPick === newPick) || !oldPick) return;

    const allComments = loadCommentsFromStorage(draftid) || {};
    const newPickComments = allComments[newPick] || {};
    const oldPickText = document.getElementById('comment-textarea').value;
    document.getElementById('comment-textarea').value = JSON.stringify((newPickComments[userid]) || '').slice(1, -1);

    storeText(draftid, oldPick, userid, oldPickText);
}

function clearCurrentComment() {
    const url = window.location.href.split('/');
    const userid = localStorage.getItem(getStorageKey('userid', true));
    const pick = 'p' + url[5] + 'p' + url[6];
    const draftid = url[4];
    storeText(draftid, pick, userid, '');
    document.getElementById('comment-textarea').value = '';
}

function storeText(draftid, pick, userid, text) {
    const allComments = loadCommentsFromStorage(draftid) || {};
    const oldPickComments = allComments[pick] || {};
    if ((text === '') && (allComments[pick] !== undefined)) {
        delete allComments[pick][userid];
        console.log(allComments[pick])
    } else {
        oldPickComments[userid] = text;
        allComments[pick] = oldPickComments;
    }
    console.log('allComments', allComments)
    setCommentsFromStorage(draftid, allComments);
}

function loadCommentsFromStorage(draftid) {
    return JSON.parse(localStorage.getItem(getStorageKey('comments')));
}

function setCommentsFromStorage(draftid, comments) {
    return localStorage.setItem(getStorageKey('comments'), JSON.stringify(comments));
}

function getCurrentPick(padded = false) {
    const url = window.location.href.split('/');
    if (url.length !== 7) { //pick not in URL, ignore
        return;
    }
    return 'p' + url[5] + 'p' + url[6] + (padded && url[6] < 10 ? ' ' : '');
}

function getStorageKey(item = '', global = false) {
    const url = window.location.href.split('/');
    if ((!global) && (url.length !== 7)) { //pick not in URL, ignore for draft specific
        return;
    }
    return '17lcomments' + (global ? '' : '|' + url[4]) + (item !== '' ? '|' + item : '');
}

function exportComments() {
    const userid = localStorage.getItem(getStorageKey('userid', true));
    const url = window.location.href.split('/');
    const draftid = url[4];

    const allComments = loadCommentsFromStorage(draftid);
    const allUsers = [userid];
    const out = [];
    out.push('17lands|' + draftid + '|' + userid)

    for (let key of Object.keys(allComments).reverse()) {
        if (key[0] !== 'p') continue;
        //TODO don't assume only one user
        if (allComments[key][userid]) {
            out.push(key + (key.length < 5 ? ' ' : '') + ': ' + allComments[key][userid])
        }
    }
    copyToClipboard(out.join('\n'));
}

function copyToClipboard(text) {
    if (navigator.clipboard && navigator.clipboard.writeText) {
        navigator.clipboard.writeText(text)
        .then(() => console.log('Comments copied to clipboard!'))
        .catch(err => console.error('Failed to copy text: ', err));
     } else {
         console.log('clipboard not supported')
     }
}

function toggleLogin(forceDisplayMode = false) {
    const nameDisplay = document.getElementById('comment-user-id');
    const nameInput = document.getElementById('comment-user-id-input');
    const idSpan = document.getElementById('comment-id-span');
    const textArea = document.getElementById('comment-textarea');
    const userid = localStorage.getItem(getStorageKey('userid', true));

    const inputMode = nameDisplay.style && (nameDisplay.style.display === 'none');
    console.log('toggleLogin', inputMode, forceDisplayMode)
    if (inputMode || (forceDisplayMode === true)) {
        nameDisplay.innerHTML = userid;
        nameDisplay.style.display = null;
        nameInput.style = 'display: none';
        idSpan.style.border = '';
        idSpan.style.margin = '';
        textArea.disabled = false;
    } else {
        nameDisplay.style.display = 'none';
        nameInput.style = null;
        nameInput.value = userid;
    }
}

function userIdUpdate() {
    const userId = document.getElementById('comment-user-id-input').value;
    console.log('userIdUpdate', userId)
    if (userId !== '' ) {
        console.log()
        localStorage.setItem(getStorageKey('userid', true), userId);
        toggleLogin(true);
    }
}

function highlightLogin(){
    const userInput = document.getElementById('comment-user-id-input').value;
    if (userInput !== '') {
        userIdUpdate();
    }
    const userid = localStorage.getItem(getStorageKey('userid', true));
    const idSpan = document.getElementById('comment-id-span');
    const textArea = document.getElementById('comment-textarea');
    if (userid === null) {
        idSpan.style.border = '3px solid yellow';
        idSpan.style.margin = '-3px';
        textArea.disabled = true;
    } else {
        idSpan.style.border = '';
        idSpan.style.margin = '';
        textArea.disabled = false;
    }
}

(function() {
    'use strict';
    init();
})();