MediaWiki:CustomItemTracker.js: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| (6 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
mw.hook('wikipage.content').add(function () { | mw.hook('wikipage.content').add(function () { | ||
const container = document.getElementById("customItemTracker"); | const container = | ||
document.getElementById("customItemTracker"); | |||
if (!container) return; | if (!container) return; | ||
const allowedUsers = [ | const allowedUsers = [ | ||
| Line 9: | Line 11: | ||
]; | ]; | ||
const currentUser = mw.config.get("wgUserName"); | |||
const currentUser = | |||
mw.config.get("wgUserName"); | |||
let trackerData = { | let trackerData = { | ||
| Line 15: | Line 20: | ||
completed: {} | completed: {} | ||
}; | }; | ||
let images = {}; | |||
let searchValue = ""; | |||
function loadData() { | function loadData() { | ||
$.getJSON( | $.getJSON( | ||
| Line 29: | Line 42: | ||
} | } | ||
).done(function (data) { | ).done(function(data) { | ||
const page = | |||
data.query.pages[0]; | |||
if (!page.revisions) | if (!page.revisions) | ||
return; | return; | ||
try { | try { | ||
| Line 42: | Line 60: | ||
page.revisions[0].content | page.revisions[0].content | ||
); | ); | ||
} catch(e) { | |||
console.error( | |||
"Invalid tracker JSON", | |||
e | |||
); | |||
return; | |||
} | |||
loadImages(); | |||
}); | |||
} | |||
function loadImages() { | |||
const allItems = []; | |||
trackerData.tiers.forEach(function(tier) { | |||
tier.items.forEach(function(item) { | |||
allItems.push(item); | |||
}); | |||
}); | |||
const templates = | |||
allItems | |||
.map(function(item) { | |||
return "{{plinkp|" + | |||
item.name + | |||
"}}"; | |||
}) | |||
.join("\n"); | |||
$.post( | |||
"/api.php", | |||
{ | |||
action: "parse", | |||
text: templates, | |||
format: "json" | |||
} | |||
).done(function(data) { | |||
if (!data.parse) { | |||
console.warn( | |||
"Image parse failed", | |||
data | |||
); | |||
images = {}; | |||
render(); | render(); | ||
} | return; | ||
} | |||
} | const wrapper = | ||
document.createElement("div"); | |||
wrapper.innerHTML = | |||
data.parse.text["*"]; | |||
const parsedImages = | |||
Array.from( | |||
wrapper.querySelectorAll("img") | |||
); | |||
images = {}; | |||
allItems.forEach(function(item, index) { | |||
if (parsedImages[index]) { | |||
images[item.name] = | |||
parsedImages[index]; | |||
} | |||
}); | |||
render(); | |||
}); | }); | ||
} | } | ||
function render() { | |||
function render(searchTerm = "") { | |||
container.innerHTML = ""; | container.innerHTML = ""; | ||
trackerData.tiers.forEach(function (tier) { | |||
let total = 0; | |||
trackerData.tiers.forEach(function(tier) { | |||
total += tier.items.length; | |||
}); | }); | ||
let completed = 0; | let completed = 0; | ||
if (trackerData.completed[key]) | Object.keys( | ||
trackerData.completed | |||
).forEach(function(key) { | |||
if ( | |||
trackerData.completed[key] | |||
) { | |||
completed++; | completed++; | ||
} | |||
}); | }); | ||
const progress = | const progress = | ||
document.createElement("div"); | document.createElement("div"); | ||
progress.className = "trackerProgress"; | |||
progress.className = | |||
"trackerProgress"; | |||
progress.innerHTML = | progress.innerHTML = | ||
` | |||
Completed: | |||
<strong>${completed}/${total}</strong> | |||
(${total ? Math.floor((completed / total) * 100) : 0}%) | |||
`; | |||
container.appendChild(progress); | container.appendChild(progress); | ||
trackerData.tiers.forEach(function (tier) { | |||
const searchBox = | |||
document.createElement("input"); | |||
searchBox.type = | |||
"text"; | |||
searchBox.placeholder = | |||
"Search items..."; | |||
searchBox.className = | |||
"trackerSearch"; | |||
searchBox.value = | |||
searchTerm; | |||
container.appendChild(searchBox); | |||
searchBox.addEventListener( | |||
"input", | |||
function() { | |||
searchValue = | |||
this.value.toLowerCase(); | |||
render(searchValue); | |||
setTimeout(function() { | |||
const newSearch = | |||
container.querySelector(".trackerSearch"); | |||
if (newSearch) { | |||
newSearch.focus(); | |||
newSearch.setSelectionRange( | |||
newSearch.value.length, | |||
newSearch.value.length | |||
); | |||
} | |||
}, 0); | |||
} | |||
); | |||
let globalIndex = 0; | |||
trackerData.tiers.forEach(function(tier) { | |||
const filteredItems = | |||
tier.items.filter(function(item) { | |||
if (!searchTerm) | |||
return true; | |||
return item.name | |||
.toLowerCase() | |||
.includes(searchTerm); | |||
}); | |||
if (filteredItems.length === 0) | |||
return; | |||
const heading = | const heading = | ||
document.createElement(" | document.createElement("div"); | ||
heading.className = | |||
"trackerTierHeading"; | |||
heading.textContent = tier.name; | heading.textContent = | ||
tier.name; | |||
container.appendChild(heading); | container.appendChild(heading); | ||
const grid = | const grid = | ||
document.createElement("div"); | document.createElement("div"); | ||
grid.className = "trackerGrid"; | |||
grid.className = | |||
"trackerGrid"; | |||
container.appendChild(grid); | container.appendChild(grid); | ||
tier.items.forEach(function(item) { | |||
const index = | |||
trackerData.tiers | |||
.flatMap(t => t.items) | |||
.indexOf(item); | |||
if ( | |||
searchTerm && | |||
!item.name | |||
.toLowerCase() | |||
.includes(searchTerm) | |||
) { | |||
return; | |||
} | |||
const tile = | const tile = | ||
document.createElement("div"); | document.createElement("div"); | ||
tile.className = | |||
"trackerTile"; | |||
const | |||
if ( | |||
trackerData.completed[index] | |||
) { | |||
tile.classList.add( | |||
"completed" | |||
); | |||
} | |||
const imageBox = | |||
document.createElement("div"); | document.createElement("div"); | ||
tile.appendChild( | imageBox.className = | ||
"itemImage"; | |||
if ( | |||
images[item.name] | |||
) { | |||
const img = | |||
images[item.name] | |||
.cloneNode(true); | |||
img.style.maxWidth = | |||
"50px"; | |||
img.style.maxHeight = | |||
"50px"; | |||
img.style.width = | |||
"auto"; | |||
img.style.height = | |||
"auto"; | |||
img.style.objectFit = | |||
"contain"; | |||
imageBox.appendChild(img); | |||
} | |||
tile.appendChild(imageBox); | |||
const name = | const name = | ||
document.createElement("div"); | document.createElement("div"); | ||
name.className = "itemName"; | |||
name.textContent = item.name; | name.className = | ||
"itemName"; | |||
name.textContent = | |||
item.name; | |||
tile.appendChild(name); | tile.appendChild(name); | ||
tile.onclick = | |||
function() { | |||
if ( | |||
!allowedUsers.includes( | |||
currentUser | |||
) | |||
) { | |||
return; | |||
} | |||
trackerData.completed[index] = | |||
!trackerData.completed[index]; | |||
saveData(); | |||
}; | |||
grid.appendChild(tile); | |||
}); | |||
}); | }); | ||
} | } | ||
function saveData() { | function saveData() { | ||
$.post( | $.post( | ||
| Line 201: | Line 543: | ||
action: "edit", | action: "edit", | ||
title: "Module:CustomItemTracker/data.json", | title: | ||
"Module:CustomItemTracker/data.json", | |||
token: | |||
mw.user.tokens.get( | |||
"csrfToken" | |||
), | |||
format: "json", | format: "json", | ||
text: JSON.stringify( | |||
text: | |||
JSON.stringify( | |||
trackerData, | trackerData, | ||
null, | null, | ||
| Line 215: | Line 565: | ||
} | } | ||
).done(function () { | ).done(function() { | ||
render(searchValue); | |||
console.log( | console.log( | ||
"Tracker updated | "Custom Item Tracker updated" | ||
); | ); | ||
}); | }); | ||
} | } | ||
loadData(); | loadData(); | ||
}); | }); | ||
Latest revision as of 17:12, 30 July 2026
mw.hook('wikipage.content').add(function () {
const container =
document.getElementById("customItemTracker");
if (!container) return;
const allowedUsers = [
"Hefner"
];
const currentUser =
mw.config.get("wgUserName");
let trackerData = {
tiers: [],
completed: {}
};
let images = {};
let searchValue = "";
function loadData() {
$.getJSON(
mw.util.wikiScript("api"),
{
action: "query",
titles: "Module:CustomItemTracker/data.json",
prop: "revisions",
rvprop: "content",
format: "json",
formatversion: 2
}
).done(function(data) {
const page =
data.query.pages[0];
if (!page.revisions)
return;
try {
trackerData =
JSON.parse(
page.revisions[0].content
);
} catch(e) {
console.error(
"Invalid tracker JSON",
e
);
return;
}
loadImages();
});
}
function loadImages() {
const allItems = [];
trackerData.tiers.forEach(function(tier) {
tier.items.forEach(function(item) {
allItems.push(item);
});
});
const templates =
allItems
.map(function(item) {
return "{{plinkp|" +
item.name +
"}}";
})
.join("\n");
$.post(
"/api.php",
{
action: "parse",
text: templates,
format: "json"
}
).done(function(data) {
if (!data.parse) {
console.warn(
"Image parse failed",
data
);
images = {};
render();
return;
}
const wrapper =
document.createElement("div");
wrapper.innerHTML =
data.parse.text["*"];
const parsedImages =
Array.from(
wrapper.querySelectorAll("img")
);
images = {};
allItems.forEach(function(item, index) {
if (parsedImages[index]) {
images[item.name] =
parsedImages[index];
}
});
render();
});
}
function render(searchTerm = "") {
container.innerHTML = "";
let total = 0;
trackerData.tiers.forEach(function(tier) {
total += tier.items.length;
});
let completed = 0;
Object.keys(
trackerData.completed
).forEach(function(key) {
if (
trackerData.completed[key]
) {
completed++;
}
});
const progress =
document.createElement("div");
progress.className =
"trackerProgress";
progress.innerHTML =
`
Completed:
<strong>${completed}/${total}</strong>
(${total ? Math.floor((completed / total) * 100) : 0}%)
`;
container.appendChild(progress);
const searchBox =
document.createElement("input");
searchBox.type =
"text";
searchBox.placeholder =
"Search items...";
searchBox.className =
"trackerSearch";
searchBox.value =
searchTerm;
container.appendChild(searchBox);
searchBox.addEventListener(
"input",
function() {
searchValue =
this.value.toLowerCase();
render(searchValue);
setTimeout(function() {
const newSearch =
container.querySelector(".trackerSearch");
if (newSearch) {
newSearch.focus();
newSearch.setSelectionRange(
newSearch.value.length,
newSearch.value.length
);
}
}, 0);
}
);
let globalIndex = 0;
trackerData.tiers.forEach(function(tier) {
const filteredItems =
tier.items.filter(function(item) {
if (!searchTerm)
return true;
return item.name
.toLowerCase()
.includes(searchTerm);
});
if (filteredItems.length === 0)
return;
const heading =
document.createElement("div");
heading.className =
"trackerTierHeading";
heading.textContent =
tier.name;
container.appendChild(heading);
const grid =
document.createElement("div");
grid.className =
"trackerGrid";
container.appendChild(grid);
tier.items.forEach(function(item) {
const index =
trackerData.tiers
.flatMap(t => t.items)
.indexOf(item);
if (
searchTerm &&
!item.name
.toLowerCase()
.includes(searchTerm)
) {
return;
}
const tile =
document.createElement("div");
tile.className =
"trackerTile";
if (
trackerData.completed[index]
) {
tile.classList.add(
"completed"
);
}
const imageBox =
document.createElement("div");
imageBox.className =
"itemImage";
if (
images[item.name]
) {
const img =
images[item.name]
.cloneNode(true);
img.style.maxWidth =
"50px";
img.style.maxHeight =
"50px";
img.style.width =
"auto";
img.style.height =
"auto";
img.style.objectFit =
"contain";
imageBox.appendChild(img);
}
tile.appendChild(imageBox);
const name =
document.createElement("div");
name.className =
"itemName";
name.textContent =
item.name;
tile.appendChild(name);
tile.onclick =
function() {
if (
!allowedUsers.includes(
currentUser
)
) {
return;
}
trackerData.completed[index] =
!trackerData.completed[index];
saveData();
};
grid.appendChild(tile);
});
});
}
function saveData() {
$.post(
mw.util.wikiScript("api"),
{
action: "edit",
title:
"Module:CustomItemTracker/data.json",
token:
mw.user.tokens.get(
"csrfToken"
),
format: "json",
text:
JSON.stringify(
trackerData,
null,
4
)
}
).done(function() {
render(searchValue);
console.log(
"Custom Item Tracker updated"
);
});
}
loadData();
});