您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Track preordered non-MFC items on collection screen
// ==UserScript== // @name Add non-MFC figure // @namespace https://tharglet.me.uk // @version 2.6 // @description Track preordered non-MFC items on collection screen // @author Tharglet // @match https://myfigurecollection.net/?*mode=view&*tab=collection&* // @icon https://www.google.com/s2/favicons?sz=64&domain=myfigurecollection.net // @grant GM_addStyle // @license CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/ // @grant GM_setValue // @grant GM_getValue // ==/UserScript== //Polyfill for GM_addStyle for Greasemonkey... if(typeof GM_addStyle == 'undefined') { GM_addStyle = (aCss) => { 'use strict'; let head = document.getElementsByTagName('head')[0]; if (head) { let style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.textContent = aCss; head.appendChild(style); return style; } return null; }; } GM_addStyle(` .non-mfc-item__tray-icon { border: green 1px solid; display: block; margin: 8px; padding: 1px; } .non-mfc-item__icon-container { float: left; margin-bottom: 20px; } .non-mfc-item__tray-icon img { width: 60px; height: 60px; border-radius: 2px; } .non-mfc-item__edit, .non-mfc-item__delete { display: inline-block; } .non-mfc-item__edit span, .non-mfc-item__delete span { font-size: 16px; margin: 0 4px; } /* Pip styles */ .item-custompip { display: block; position: absolute; right: 1px; bottom: 1px; height: 16px; padding: 1px 2px 2px 3px; line-height: 16px; color: white; } .item-is-paid { background-color: green; } .item-is-shipped { background-color: gold; } .item-is-stored { background-color: orangered; } .icon-dollar:before { font-family: serif !important; content: "$"; font-weight: bolder !important; } .icon-plane:before { font-family: serif !important; content: "🛩️"; font-weight: bolder !important; } .icon-stored:before { font-family: serif !important; content: "🏭"; font-weight: bolder !important; } `); (function() { 'use strict'; /** Amout of figures user has already preordered */ let BASE_COUNT = 0; /** Parameter value for detailed list */ const DETAILED_LIST = '0'; /** Array of non-MFC figures the user has preordered */ let additionalFigures = JSON.parse(GM_getValue("additionalFigures", "[]")); /** Pips for paid and shipped */ const PAID_PIP = '<span class="item-custompip item-is-paid"><span class="tiny-icon-only icon-dollar"></span></span>'; const SHIPPED_PIP = '<span class="item-custompip item-is-shipped"><span class="tiny-icon-only icon-plane"></span></span>'; const STORED_PIP = '<span class="item-custompip item-is-stored"><span class="tiny-icon-only icon-stored"></span></span>'; const ORDERED_COUNT_SELECTOR = '.result-tabs .tab .selected .count'; /** * Converts string to HTML elements */ const htmlToElement = (html) => { let template = document.createElement('template'); html = html.trim(); template.innerHTML = `${html}`; return template.content; } /** * Tests if we're viewing the logged in user's preorders page */ const isUsersPreorderPage = () => { const urlParams = new URLSearchParams(window.location.search); const status = urlParams.get('status'); if(status == 1) { let loggedInUser = document.querySelector('.user-menu .handle'); if(loggedInUser) { let userLink = loggedInUser.getAttribute('href'); if(userLink === '/session/signup') { return false; } else { let userParam; const windowLocation = window.location.href; if(windowLocation.startsWith('https://myfigurecollection.net/profile/')) { userParam = windowLocation.match(/https:\/\/myfigurecollection\.net\/profile\/([^\/]*)/)[1]; } else { const urlParams = new URLSearchParams(window.location.search); userParam = urlParams.get('username'); } return userParam === userLink.substring('9'); } } else { return false; } } else { return false; } }; /** Helper function to reset out MFC item form */ const resetNonMfcItemForm = () => { document.getElementById('non-mfc-item__form-title').innerText = 'Add non-MFC figure'; document.getElementById('addNonMfcItem').innerText = 'Add'; document.getElementById('nonMfcItemEditId').value = ''; document.getElementById('nonMfcItemName').value = ''; document.getElementById('nonMfcItemImage').value = ''; document.getElementById('nonMfcItemLink').value = ''; document.getElementById('nonMfcItemReleaseDate').value = ''; document.getElementById('nonMfcItemHasShipped').checked = false; document.getElementById('nonMfcItemIsStored').checked = false; document.getElementById('nonMfcItemHasPaid').checked = false; } const drawAdditionalFigures = () => { const urlParams = new URLSearchParams(window.location.search); const groupBy = urlParams.get('groupBy'); const output = urlParams.get('output'); //Clear all additions before redo const additions = document.getElementById('nonMfcAdditions'); if(additions) { additions.remove(); } document.querySelectorAll('.non-mfc-item__icon').forEach(e => e.remove()); document.querySelectorAll('.non-mfc-item__edit').forEach(e => e.remove()); document.querySelectorAll('.non-mfc-item__delete').forEach(e => e.remove()); document.querySelectorAll('.non-mfc-item__year-header').forEach(e => e.remove()); //Create a lookup list of existing date headings and their associated object //Created so we can splice and keep track of new entries const dateHeadingsList = []; if(groupBy == 'releaseDates') { let dateHeadings; if(output === '0') { dateHeadings = document.querySelectorAll('div.results-title'); } else { dateHeadings = document.querySelectorAll('.item-group-by h3'); } dateHeadings.forEach((heading) => { const dateHeadingElement = {}; dateHeadingElement.year = heading.innerText.substring(0,4); dateHeadingElement.month = heading.innerText.substring(5); dateHeadingElement.element = heading; dateHeadingsList.push(dateHeadingElement); }); } if(additionalFigures.length > 0) { //update item count let totalFigureCount = BASE_COUNT + additionalFigures.length; document.querySelector(ORDERED_COUNT_SELECTOR).innerText = totalFigureCount; document.querySelector('.results-count-value').lastChild.nodeValue = `${totalFigureCount} items`; //Pre-add setup const addList = document.querySelector('#nonMfcFigureList'); if(groupBy !== 'releaseDates' && !!groupBy) { if(output === DETAILED_LIST) { document.querySelector('.results').append(htmlToElement('<div id="nonMfcAdditions" class="results-title">Non-MFC</div>')); } else { document.querySelector('.result .item-icons').prepend(htmlToElement('<div class="item-group-by" id="nonMfcAdditions"><h3>Non-MFC</h3></div>')); } } //Add icons to page and delete box additionalFigures.forEach((fig, idx) => { let linkLine; const figYear = fig.date.substring(0, 4); const figMonth = fig.date.substring(5); let pip = ''; if(fig.hasShipped) { pip += SHIPPED_PIP; } else if(fig.isStored) { pip += STORED_PIP; } else if(fig.hasPaid) { pip += PAID_PIP; } const figureThumb = `<span class="non-mfc-item__icon item-icon"> <a href="${fig.link}" class="anchor tbx-tooltip item-root-0 item-category-1"> <img src="${fig.image}"/> ${pip} </a> </span>`; if(output === DETAILED_LIST) { linkLine = `<div class="result"> <div class="dgst item-dgst item-stamp"> <div class="dgst-wrapper"> <a href="${fig.link}" class="dgst-icon has-flags"> <img src="${fig.image}" alt="${fig.name}"> </a> <div class="dgst-data"> <div class="dgst-anchor"> <a href="${fig.link}" title="${fig.name}">${fig.name}</a> </div> <div class="dgst-meta"> <span class="meta category item-category-1" href="#">Non-MFC</span> </div> <div class="dgst-meta"> <span class="meta time">${fig.date}</span> </div></div></div></div></div>` } addList.append(htmlToElement(`<span class='non-mfc-item__icon-container'> <span class="non-mfc-item__icon non-mfc-item__tray-icon"> <a href="${fig.link}" class="tbx-tooltip item-root-0 item-category-1"> <img src="${fig.image}"/> </a> </span> <a href="#" class='non-mfc-item__edit' title="Edit" data-index="${idx}"><span class="tiny-icon-only icon-pencil-square-o" data-index="${idx}"></span></a> <a href="#" class='non-mfc-item__delete' title="Delete" data-index="${idx}"><span class="tiny-icon-only icon-trash-o" data-index="${idx}"></span></a> </span>`)); let toAppend = true; const yearMonthString = `${figYear}-${figMonth}`; if(groupBy == 'releaseDates') { dateHeadingsList.forEach((heading, headingIndex) => { if(toAppend) { const headingYear = heading.year; const headingMonth = heading.month; if(figYear == headingYear && figMonth == headingMonth) { if(output === DETAILED_LIST) { heading.element.after(htmlToElement(linkLine)); } else { heading.element.after(htmlToElement(figureThumb)); } toAppend = false; } else if(new Date(figYear, figMonth, 1) > new Date(headingYear, headingMonth, 1)) { if(output === DETAILED_LIST) { const newHeading = `<div class="results-title non-mfc-item__year-header" id='nhi_${yearMonthString}'>${yearMonthString}</div>` heading.element.before(htmlToElement(newHeading + linkLine)); } else { const newHeading = `<div class="item-group-by"><h3 class="non-mfc-item__year-header" id='nhi_${yearMonthString}'>${yearMonthString}</h3></div>` heading.element.parentElement.parentElement.insertBefore(htmlToElement(newHeading), heading.element.parentElement); document.querySelector(`#nhi_${yearMonthString}`).after(htmlToElement(figureThumb)); } dateHeadingsList.splice( headingIndex, 0, { year: figYear, month: figMonth, element: document.querySelector(`#nhi_${yearMonthString}`) } ); toAppend = false; } } }); //Append if trailing if(toAppend) { if(output === DETAILED_LIST) { const newHeading = `<div class="results-title non-mfc-item__year-header" id='nhi_${yearMonthString}'>${yearMonthString}</div>` document.querySelector('.results').append(htmlToElement('<div class="item-group-by">' + newHeading + linkLine + '</div>')); } else { const newHeading = `<h3 class="non-mfc-item__year-header" id='nhi_${yearMonthString}'>${yearMonthString}</h3>` document.querySelector('.item-group-by:last-child').after(htmlToElement('<div class="item-group-by">' + newHeading + figureThumb + '</div>')); } dateHeadingsList.push({ year: figYear, month: figMonth, element: document.querySelector(`#nhi_${yearMonthString}`) }); } } else if(!!groupBy) { if(output === DETAILED_LIST) { document.getElementById('nonMfcAdditions').after(htmlToElement(linkLine)) } else { document.querySelector('#nonMfcAdditions h3').after(htmlToElement(figureThumb)); } } else { if(output === DETAILED_LIST) { document.querySelector('.results').append(htmlToElement(linkLine)); } else { document.querySelector('.result .item-icons').prepend(htmlToElement(figureThumb)); } } }); document.querySelectorAll('.non-mfc-item__delete').forEach(ele => { ele.addEventListener('click', (evt) => { evt.preventDefault(); if(confirm('Delete this figure?')) { additionalFigures.splice(evt.target.getAttribute('data-index'), 1); additionalFigures.sort((a, b) => (a.date < b.date) ? 1 : -1); GM_setValue("additionalFigures", JSON.stringify(additionalFigures)); drawAdditionalFigures(); resetNonMfcItemForm(); } }); }); document.querySelectorAll('.non-mfc-item__edit').forEach(ele => { ele.addEventListener('click', (evt) => { evt.preventDefault(); const itemIndex = evt.target.getAttribute('data-index'); const figToEdit = additionalFigures[itemIndex]; document.getElementById('non-mfc-item__form-title').innerText = `Editing ${figToEdit.name}`; document.getElementById('addNonMfcItem').innerText = 'Edit'; document.getElementById('nonMfcItemEditId').value = itemIndex; document.getElementById('nonMfcItemName').value = figToEdit.name; document.getElementById('nonMfcItemImage').value = figToEdit.image; document.getElementById('nonMfcItemLink').value = figToEdit.link; document.getElementById('nonMfcItemReleaseDate').value = figToEdit.date; document.getElementById('nonMfcItemHasShipped').checked = figToEdit.hasShipped; document.getElementById('nonMfcItemIsStored').checked = figToEdit.isStored; document.getElementById('nonMfcItemHasPaid').checked = figToEdit.hasPaid; window.scrollTo( document.getElementById('non-mfc-item__section').offsetLeft, document.getElementById('non-mfc-item__section').offsetTop - 100 ); }); }); } } // Initialise non-MFC BASE_COUNT = parseInt(document.querySelector(ORDERED_COUNT_SELECTOR).innerText); if(isUsersPreorderPage()) { const addSection = `<section id='non-mfc-item__section'> <h2 id='non-mfc-item__form-title'>Add non-MFC figure</h2> <div class='form'> <input type='hidden' id='nonMfcItemEditId' value=''/> <div class='bigchar form-field'> <div class='form-label'>Figure name</div> <div class='form-input'><input type='text' id='nonMfcItemName'/></div> </div> <div class='bigchar form-field'> <div class='form-label'>Image URL *</div> <div class='form-input'><input type='text' id='nonMfcItemImage'/></div> </div> <div class='bigchar form-field'> <div class='form-label'>Item link *</div> <div class='form-input'><input type='text' id='nonMfcItemLink'/></div> </div> <div class='bigchar form-field'> <div class='form-label'>Release date (YYYY-MM) *</div> <div class='form-input'><input type='text' id='nonMfcItemReleaseDate'/></div> </div> <div class="checkbox form-field"> <div class="form-input"> <input id="nonMfcItemHasPaid" type="checkbox"> <label for="nonMfcItemHasPaid">Paid?</label> </div> </div> <div class="checkbox form-field"> <div class="form-input"> <input id="nonMfcItemIsStored" type="checkbox"> <label for="nonMfcItemIsStored">Stored?</label> </div> </div> <div class="checkbox form-field"> <div class="form-input"> <input id="nonMfcItemHasShipped" type="checkbox"> <label for="nonMfcItemHasShipped">Shipped?</label> </div> </div> <div class='form-field'> <div class='form-input'> <button id='addNonMfcItem'>Add</button> <button id='cancelNonMfcItem'>Cancel</button> </div> </div> </div> </section> <section> <h2>Added non-MFC figures</h2> <div class='form'> <div id='nonMfcFigureList' class='item-icons'> </div> </div> </section>`; const sidebar = document.querySelectorAll('#side section'); const lastSidebarSection = sidebar[sidebar.length - 1] lastSidebarSection.after(htmlToElement(addSection)); drawAdditionalFigures(); document.getElementById('addNonMfcItem').addEventListener('click', (evt) => { evt.preventDefault(); const name = document.getElementById('nonMfcItemName').value || 'Non-MFC figure'; const image = document.getElementById('nonMfcItemImage').value; const link = document.getElementById('nonMfcItemLink').value; const date = document.getElementById('nonMfcItemReleaseDate').value; const editId = document.getElementById('nonMfcItemEditId').value; const hasShipped = document.getElementById('nonMfcItemHasShipped').checked; const isStored = document.getElementById('nonMfcItemIsStored').checked; const hasPaid = document.getElementById('nonMfcItemHasPaid').checked; if(image && link && date && name) { if(date.match(/^\d{4}-0[1-9]|1[0-2]$/)) { if(editId) { additionalFigures[editId] = { name, image, link, date, hasPaid, isStored, hasShipped } } else { additionalFigures.push({ name, image, link, date, hasPaid, isStored, hasShipped }); } additionalFigures.sort((a, b) => (a.date < b.date) ? 1 : -1); GM_setValue('additionalFigures', JSON.stringify(additionalFigures)); drawAdditionalFigures(); resetNonMfcItemForm(); } else { alert('Please enter a valid date in YYYY-MM format'); } } else { alert('Please fill in all mandatory fields'); } }); const cancelButton = document.getElementById('cancelNonMfcItem'); cancelButton.addEventListener('click', (evt) => { evt.preventDefault(); if(confirm('Are you sure you want to cancel?')) { resetNonMfcItemForm(); } }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址