/*
Interactive Tiers
Original code from: https://github.com/silverweed/tiers
Modified by: pinapelz
Licensed Under WTFPL
*/
'use strict';
const MAX_NAME_LEN = 200;
const DEFAULT_TIERS = ['S', 'A', 'B', 'C', 'D', 'E', 'F'];
const TIER_COLORS = [
'#ff6666',
'#f0a731',
'#f4d95b',
'#66ff66',
'#58c8f4',
'#5b76f4',
'#f45bed'
];
let unique_id = 0;
let unsaved_changes = false;
const LAYOUT_HORIZONTAL = 0;
const LAYOUT_VERTICAL = 1;
let cur_layout = LAYOUT_HORIZONTAL;
let all_headers = [];
let headers_orig_min_width;
let untiered_images;
let tierlist_div;
let dragged_image;
function reset_row(row) {
row.querySelectorAll('span.item').forEach((item) => {
for (let i = 0; i < item.children.length; ++i) {
let img = item.children[i];
item.removeChild(img);
untiered_images.appendChild(img);
}
item.parentNode.removeChild(item);
});
}
function hard_reset_list() {
tierlist_div.innerHTML = '';
untiered_images.innerHTML = '';
}
function soft_reset_list() {
tierlist_div.querySelectorAll('.row').forEach(reset_row);
unsaved_changes = true;
}
window.addEventListener('load', () => {
untiered_images = document.querySelector('.images');
tierlist_div = document.querySelector('.tierlist');
for (let i = 0; i < DEFAULT_TIERS.length; ++i) {
add_row(i, DEFAULT_TIERS[i]);
}
recompute_header_colors();
headers_orig_min_width = all_headers[0][0].clientWidth;
make_accept_drop(document.querySelector('.images'));
bind_title_events();
document.getElementById('load-img-input').addEventListener('input', (evt) => {
let images = document.querySelector('.images');
for (let file of evt.target.files) {
let reader = new FileReader();
reader.addEventListener('load', (load_evt) => {
let img = create_img_with_src(load_evt.target.result);
images.appendChild(img);
unsaved_changes = true;
});
reader.readAsDataURL(file);
}
});
document.onpaste = (evt) => {
let clip_data = evt.clipboardData || evt.originalEvent.clipboardData;
let items = clip_data.items;
let images = document.querySelector('.images');
for (let item of items) {
if (item.kind === 'file') {
let blob = item.getAsFile();
let reader = new FileReader();
reader.onload = (load_evt) => {
let img = create_img_with_src(load_evt.target.result);
images.appendChild(img);
unsaved_changes = true;
};
reader.readAsDataURL(blob);
}
}
};
document.getElementById('reset-list-input').addEventListener('click', () => {
if (confirm('Reset Tierlist? (this will place all images back in the pool)')) {
soft_reset_list();
}
});
document.getElementById('export-input').addEventListener('click', () => {
let name = prompt('Please give a name to the file. This will export your tiers as a JSON file so you can continue working on it later');
if (name) {
save_tierlist(`${name}.json`);
}
});
document.getElementById('export-input-html').addEventListener('click', () => {
let name = prompt('This will export your tiers as a single interactive HTML file. Please give a name to the file');
if (name) {
save_tierlist_with_template(`${name}.html`);
}
});
document.getElementById('import-input').addEventListener('input', (evt) => {
if (!evt.target.files) {
return;
}
let file = evt.target.files[0];
let reader = new FileReader();
reader.addEventListener('load', (load_evt) => {
let raw = load_evt.target.result;
let parsed = JSON.parse(raw);
if (!parsed) {
alert("Failed to parse data");
return;
}
hard_reset_list();
load_tierlist(parsed);
});
reader.readAsText(file);
});
bind_trash_events();
bind_toggle_layout_events();
window.addEventListener('beforeunload', (evt) => {
if (!unsaved_changes) return null;
var msg = "You have unsaved changes. Leave anyway?";
(evt || window.event).returnValue = msg;
return msg;
});
void try_load_tierlist_json();
const modal = document.getElementById('image-modal');
const modalImg = document.getElementById('modal-img');
const modalTitle = document.getElementById('modal-title');
const modalDesc = document.getElementById('modal-description');
const modalSave = document.getElementById('modal-save');
const modalClose = document.querySelector('.modal .close');
let currentModalImage = null;
function showModal(img) {
currentModalImage = img;
document.body.style.overflow = 'hidden';
modal.style.display = 'flex';
modalImg.src = img.src;
modalTitle.value = img.dataset.title || '';
modalDesc.value = img.dataset.description || '';
}
modalClose.addEventListener('click', () => {
modal.style.display = 'none';
document.body.style.overflow = 'hidden';
});
modalSave.addEventListener('click', () => {
if (currentModalImage) {
currentModalImage.dataset.title = modalTitle.value;
currentModalImage.dataset.description = modalDesc.value;
}
modal.style.display = 'none';
document.body.style.overflow = 'auto';
});
window.addEventListener('click', (evt) => {
if (evt.target == modal) {
modal.style.display = 'none';
document.body.style.overflow = 'auto';
}
});
tierlist_div.addEventListener('click', (evt) => {
if (evt.target.tagName.toUpperCase() === 'IMG') {
showModal(evt.target);
}
});
});
function create_img_with_src(src) {
let img = document.createElement('img');
img.src = src;
img.style.userSelect = 'none';
img.classList.add('draggable');
img.draggable = true;
img.addEventListener("dragstart", (evt) => {
evt.dataTransfer.setData("text/plain", null);
dragged_image = evt.target;
dragged_image.classList.add("dragged");
});
img.addEventListener("mouseenter", (evt) => {
const title = evt.target.dataset.title;
if (title) {
evt.target.title = title;
}
});
img.addEventListener("dragend", (evt) => {
if (dragged_image) {
dragged_image.classList.remove("dragged");
}
dragged_image = null;
});
return img;
}
function save(filename, text) {
unsaved_changes = false;
var el = document.createElement('a');
el.setAttribute('href', 'data:text/html;charset=utf-8,' + encodeURIComponent(text));
el.setAttribute('download', filename);
el.style.display = 'none';
document.body.appendChild(el);
el.click();
document.body.removeChild(el);
}
function save_tierlist(filename) {
let serialized_tierlist = {
title: document.querySelector('.title-label').innerText,
rows: [],
};
tierlist_div.querySelectorAll('.row').forEach((row, i) => {
serialized_tierlist.rows.push({
name: row.querySelector('.header label').innerText.substr(0, MAX_NAME_LEN)
});
serialized_tierlist.rows[i].imgs = [];
row.querySelectorAll('img').forEach((img) => {
serialized_tierlist.rows[i].imgs.push({
src: img.src,
title: img.dataset.title || '',
description: img.dataset.description || ''
});
});
});
let untiered_imgs = document.querySelectorAll('.images img');
if (untiered_imgs.length > 0) {
serialized_tierlist.untiered = [];
untiered_imgs.forEach((img) => {
serialized_tierlist.untiered.push({
src: img.src,
title: img.dataset.title || '',
description: img.dataset.description || ''
});
});
}
save(filename, JSON.stringify(serialized_tierlist));
}
async function save_tierlist_with_template(filename) {
let serialized_tierlist = {
title: document.querySelector('.title-label').innerText,
rows: []
};
tierlist_div.querySelectorAll('.row').forEach((row, i) => {
serialized_tierlist.rows.push({
name: row.querySelector('.header').innerText.substr(0, MAX_NAME_LEN)
});
serialized_tierlist.rows[i].imgs = [];
row.querySelectorAll('img').forEach((img) => {
serialized_tierlist.rows[i].imgs.push({
src: img.src,
title: img.dataset.title || '',
description: img.dataset.description || ''
});
});
});
let untiered_imgs = document.querySelectorAll('.images img');
if (untiered_imgs.length > 0) {
serialized_tierlist.untiered = [];
untiered_imgs.forEach((img) => {
serialized_tierlist.untiered.push({
src: img.src,
title: img.dataset.title || '',
description: img.dataset.description || ''
});
});
}
try {
// Fetch resources
let [templateResponse, jsResponse, cssResponse] = await Promise.all([
fetch('/tiers.html'),
fetch('/tiers.js'),
fetch('/tiers.css')
]);
let [templateHTML, scriptContent, styleContent] = await Promise.all([
templateResponse.text(),
jsResponse.text(),
cssResponse.text()
]);
// Inject the EMBEDDED_JSON inside a script tag
let jsonScript = ``;
let inlineScript = ``;
let inlineCSS = ``;
templateHTML = templateHTML.replace("", inlineCSS + "\n");
let updatedHTML = templateHTML.replace("