Diferenças entre edições de "MediaWiki:Script/Tabber.js"
(Criou a página com "function changeDisplay(button, textContainer, method) { button.classList[method]("tabber-active"); textContainer.children[button.dataset.position].classList[method]("tab...") |
|||
| Linha 56: | Linha 56: | ||
updateTabberWithUrlChange(); | updateTabberWithUrlChange(); | ||
})(); | })(); | ||
| + | |||
| + | /* NOVO */ | ||
| + | |||
| + | class SpawnLayerManager { | ||
| + | static SPAWN_COLOR_KEY = "mt2.spawn.color"; | ||
| + | static OPTION_MAPPING = { | ||
| + | 0: "🟥 Vermelho", | ||
| + | 50: "🟫 Castanho", | ||
| + | 140: "🟩 Verde", | ||
| + | 230: "🟦 Azul", | ||
| + | 290: "🟪 Roxo", | ||
| + | black: "⬛ Preto", | ||
| + | white: "⬜ Branco", | ||
| + | }; | ||
| + | static STYLE_MAPPING = { | ||
| + | position: "absolute", | ||
| + | top: "0", | ||
| + | left: "0", | ||
| + | margin: "4px", | ||
| + | background: "#434242b3", | ||
| + | color: "white", | ||
| + | borderRadius: "5px", | ||
| + | cursor: "pointer", | ||
| + | border: "1px white solid", | ||
| + | }; | ||
| + | |||
| + | constructor(containerSelector = ".spawn-map-container") { | ||
| + | this.containerSelector = containerSelector; | ||
| + | this.currentFilter = null; | ||
| + | this.selects = []; | ||
| + | this.spawnLayers = []; | ||
| + | this.isClipboardImageSupported = this._isClipboardImageSupported(); | ||
| + | this._initialize(); | ||
| + | } | ||
| + | |||
| + | _isClipboardImageSupported() { | ||
| + | const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); | ||
| + | return !!(navigator.clipboard?.write && window.ClipboardItem) && !isSafari; | ||
| + | } | ||
| + | |||
| + | _initialize() { | ||
| + | const containers = this._getContainers(); | ||
| + | if (!containers.length) return; | ||
| + | |||
| + | containers.forEach((container) => this._setupContainer(container)); | ||
| + | |||
| + | const savedColor = this._getSavedColor(); | ||
| + | if (savedColor) this._applyColor(savedColor); | ||
| + | } | ||
| + | |||
| + | _getContainers() { | ||
| + | return document.querySelectorAll(this.containerSelector); | ||
| + | } | ||
| + | |||
| + | _getSavedColor() { | ||
| + | return localStorage.getItem(SpawnLayerManager.SPAWN_COLOR_KEY); | ||
| + | } | ||
| + | |||
| + | _saveColor(value) { | ||
| + | localStorage.setItem(SpawnLayerManager.SPAWN_COLOR_KEY, value); | ||
| + | } | ||
| + | |||
| + | _setupContainer(container) { | ||
| + | const [mapContainer, spawnContainer] = container.children; | ||
| + | |||
| + | if (!mapContainer || !spawnContainer) return; | ||
| + | |||
| + | const map = mapContainer.querySelector("img"); | ||
| + | const spawnLayer = spawnContainer.querySelector("img"); | ||
| + | |||
| + | if (!map || !spawnLayer) return; | ||
| + | |||
| + | const select = this._createColorSelect(); | ||
| + | spawnContainer.appendChild(select); | ||
| + | |||
| + | this.selects.push(select); | ||
| + | this.spawnLayers.push(spawnLayer); | ||
| + | |||
| + | select.addEventListener("change", (e) => this._onColorChange(e)); | ||
| + | |||
| + | if (this.isClipboardImageSupported) { | ||
| + | this._setupCopyButton(spawnContainer, map, spawnLayer); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | _createColorSelect() { | ||
| + | const select = document.createElement("select"); | ||
| + | |||
| + | for (const [value, label] of Object.entries( | ||
| + | SpawnLayerManager.OPTION_MAPPING | ||
| + | )) { | ||
| + | const option = document.createElement("option"); | ||
| + | option.value = value; | ||
| + | option.textContent = label; | ||
| + | select.appendChild(option); | ||
| + | } | ||
| + | |||
| + | Object.assign(select.style, SpawnLayerManager.STYLE_MAPPING); | ||
| + | return select; | ||
| + | } | ||
| + | |||
| + | _onColorChange(event) { | ||
| + | const value = event.target.value; | ||
| + | this._applyColor(value); | ||
| + | } | ||
| + | |||
| + | _applyColor(value) { | ||
| + | if (!SpawnLayerManager.OPTION_MAPPING.hasOwnProperty(value)) return; | ||
| + | |||
| + | const filter = this._getFilterForValue(value); | ||
| + | this.currentFilter = filter; | ||
| + | |||
| + | this.selects.forEach((select) => (select.value = value)); | ||
| + | this.spawnLayers.forEach((layer) => (layer.style.filter = filter)); | ||
| + | this._saveColor(value); | ||
| + | } | ||
| + | |||
| + | _getFilterForValue(value) { | ||
| + | switch (value) { | ||
| + | case "black": | ||
| + | return "invert(1) brightness(0) contrast(100%)"; | ||
| + | case "white": | ||
| + | return "invert(1) sepia(1) saturate(100%) brightness(3)"; | ||
| + | default: | ||
| + | return `hue-rotate(${value}deg)`; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | _setupCopyButton(spawnContainer, map, spawnLayer) { | ||
| + | const copyButton = spawnContainer.querySelector(".copy-to-clipboard"); | ||
| + | |||
| + | if (!copyButton) return; | ||
| + | |||
| + | const defaultEmoji = copyButton.querySelector("[data-default]"); | ||
| + | const clickedEmoji = copyButton.querySelector("[data-clicked]"); | ||
| + | |||
| + | if (!defaultEmoji || !clickedEmoji) return; | ||
| + | |||
| + | showElement(copyButton); | ||
| + | |||
| + | copyButton.addEventListener("click", () => { | ||
| + | this._copyCombinedImageToClipboard(map, spawnLayer); | ||
| + | this._copyAnimation(defaultEmoji, clickedEmoji); | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | _copyCombinedImageToClipboard(map, spawnLayer) { | ||
| + | const canvas = document.createElement("canvas"); | ||
| + | canvas.width = Math.max(map.naturalWidth, spawnLayer.naturalWidth); | ||
| + | canvas.height = Math.max(map.naturalHeight, spawnLayer.naturalHeight); | ||
| + | |||
| + | const ctx = canvas.getContext("2d"); | ||
| + | ctx.drawImage(map, 0, 0); | ||
| + | |||
| + | const filteredLayer = this._drawFilteredLayer(spawnLayer); | ||
| + | ctx.drawImage(filteredLayer, 0, 0); | ||
| + | |||
| + | this._copyCanvasContentsToClipboard(canvas); | ||
| + | } | ||
| + | |||
| + | _drawFilteredLayer(layer) { | ||
| + | const canvas = document.createElement("canvas"); | ||
| + | canvas.width = layer.naturalWidth; | ||
| + | canvas.height = layer.naturalHeight; | ||
| + | |||
| + | const ctx = canvas.getContext("2d"); | ||
| + | ctx.filter = this.currentFilter || "none"; | ||
| + | ctx.drawImage(layer, 0, 0); | ||
| + | |||
| + | return canvas; | ||
| + | } | ||
| + | |||
| + | async _getBlobFromCanvas(canvas) { | ||
| + | return new Promise((resolve, reject) => { | ||
| + | canvas.toBlob((blob) => { | ||
| + | if (blob) { | ||
| + | resolve(blob); | ||
| + | } else { | ||
| + | reject(new Error("Canvas toBlob failed")); | ||
| + | } | ||
| + | }); | ||
| + | }); | ||
| + | } | ||
| + | |||
| + | async _copyCanvasContentsToClipboard(canvas) { | ||
| + | try { | ||
| + | const blob = await this._getBlobFromCanvas(canvas); | ||
| + | const data = [new ClipboardItem({ [blob.type]: blob })]; | ||
| + | await navigator.clipboard.write(data); | ||
| + | } catch (error) { | ||
| + | console.error(error); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | _copyAnimation(defaultEmoji, clickedEmoji) { | ||
| + | hideElement(defaultEmoji); | ||
| + | showElement(clickedEmoji); | ||
| + | |||
| + | setTimeout(() => { | ||
| + | hideElement(clickedEmoji); | ||
| + | showElement(defaultEmoji); | ||
| + | }, 1500); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | new SpawnLayerManager(); | ||
Edição atual desde as 20h52min de 17 de janeiro de 2026
function changeDisplay(button, textContainer, method) {
button.classList[method]("tabber-active");
textContainer.children[button.dataset.position].classList[method]("tabber-active");
}
function globalChange(button, allButton, allText, toggleButton, changeUrl, bool = false) {
var activeButton = allButton.querySelector(".tabber-active");
if (toggleButton || button !== activeButton) {
if (bool && changeUrl) {
var newHash = "#"+button.id;
history.pushState({}, "", newHash);
}
changeDisplay(button, allText, "toggle");
if (button !== activeButton && activeButton !== null) {
changeDisplay(activeButton, allText, "remove");
}
}
}
function updateTabber(buttonContainer, textContainer, toggleButton, changeUrl) {
var targetButton = buttonContainer.querySelector(":target");
if (targetButton !== null && targetButton.classList.contains("button")) {
globalChange(targetButton, buttonContainer, textContainer, false, false);
}
buttonContainer.addEventListener("click", function(event) {
var target = event.target.closest(".button");
if (target) {
globalChange(target, buttonContainer, textContainer, toggleButton, changeUrl, true);
}
});
}
function updateTabberWithUrlChange() {
window.addEventListener("hashchange", function(e) {
var newHash = e.target.location.hash;
if (newHash !== "") {
var targetButton = document.getElementById(newHash.slice(1));
if (targetButton) {
if (targetButton.classList.contains("button")) {
var [buttonContainer, textContainer] = targetButton.parentElement.parentElement.children;
globalChange(targetButton, buttonContainer, textContainer, false, false);
}
}
}
});
}
(function() {
var tabberContainer = document.querySelectorAll("div.tabber-container");
tabberContainer.forEach(function(tabber) {
var [buttonContainer, textContainer] = tabber.children;
var toggleButton = tabber.dataset.toggle === "1";
var changeUrl = tabber.dataset.url === "1";
updateTabber(buttonContainer, textContainer, toggleButton, changeUrl);
});
updateTabberWithUrlChange();
})();
/* NOVO */
class SpawnLayerManager {
static SPAWN_COLOR_KEY = "mt2.spawn.color";
static OPTION_MAPPING = {
0: "🟥 Vermelho",
50: "🟫 Castanho",
140: "🟩 Verde",
230: "🟦 Azul",
290: "🟪 Roxo",
black: "⬛ Preto",
white: "⬜ Branco",
};
static STYLE_MAPPING = {
position: "absolute",
top: "0",
left: "0",
margin: "4px",
background: "#434242b3",
color: "white",
borderRadius: "5px",
cursor: "pointer",
border: "1px white solid",
};
constructor(containerSelector = ".spawn-map-container") {
this.containerSelector = containerSelector;
this.currentFilter = null;
this.selects = [];
this.spawnLayers = [];
this.isClipboardImageSupported = this._isClipboardImageSupported();
this._initialize();
}
_isClipboardImageSupported() {
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
return !!(navigator.clipboard?.write && window.ClipboardItem) && !isSafari;
}
_initialize() {
const containers = this._getContainers();
if (!containers.length) return;
containers.forEach((container) => this._setupContainer(container));
const savedColor = this._getSavedColor();
if (savedColor) this._applyColor(savedColor);
}
_getContainers() {
return document.querySelectorAll(this.containerSelector);
}
_getSavedColor() {
return localStorage.getItem(SpawnLayerManager.SPAWN_COLOR_KEY);
}
_saveColor(value) {
localStorage.setItem(SpawnLayerManager.SPAWN_COLOR_KEY, value);
}
_setupContainer(container) {
const [mapContainer, spawnContainer] = container.children;
if (!mapContainer || !spawnContainer) return;
const map = mapContainer.querySelector("img");
const spawnLayer = spawnContainer.querySelector("img");
if (!map || !spawnLayer) return;
const select = this._createColorSelect();
spawnContainer.appendChild(select);
this.selects.push(select);
this.spawnLayers.push(spawnLayer);
select.addEventListener("change", (e) => this._onColorChange(e));
if (this.isClipboardImageSupported) {
this._setupCopyButton(spawnContainer, map, spawnLayer);
}
}
_createColorSelect() {
const select = document.createElement("select");
for (const [value, label] of Object.entries(
SpawnLayerManager.OPTION_MAPPING
)) {
const option = document.createElement("option");
option.value = value;
option.textContent = label;
select.appendChild(option);
}
Object.assign(select.style, SpawnLayerManager.STYLE_MAPPING);
return select;
}
_onColorChange(event) {
const value = event.target.value;
this._applyColor(value);
}
_applyColor(value) {
if (!SpawnLayerManager.OPTION_MAPPING.hasOwnProperty(value)) return;
const filter = this._getFilterForValue(value);
this.currentFilter = filter;
this.selects.forEach((select) => (select.value = value));
this.spawnLayers.forEach((layer) => (layer.style.filter = filter));
this._saveColor(value);
}
_getFilterForValue(value) {
switch (value) {
case "black":
return "invert(1) brightness(0) contrast(100%)";
case "white":
return "invert(1) sepia(1) saturate(100%) brightness(3)";
default:
return `hue-rotate(${value}deg)`;
}
}
_setupCopyButton(spawnContainer, map, spawnLayer) {
const copyButton = spawnContainer.querySelector(".copy-to-clipboard");
if (!copyButton) return;
const defaultEmoji = copyButton.querySelector("[data-default]");
const clickedEmoji = copyButton.querySelector("[data-clicked]");
if (!defaultEmoji || !clickedEmoji) return;
showElement(copyButton);
copyButton.addEventListener("click", () => {
this._copyCombinedImageToClipboard(map, spawnLayer);
this._copyAnimation(defaultEmoji, clickedEmoji);
});
}
_copyCombinedImageToClipboard(map, spawnLayer) {
const canvas = document.createElement("canvas");
canvas.width = Math.max(map.naturalWidth, spawnLayer.naturalWidth);
canvas.height = Math.max(map.naturalHeight, spawnLayer.naturalHeight);
const ctx = canvas.getContext("2d");
ctx.drawImage(map, 0, 0);
const filteredLayer = this._drawFilteredLayer(spawnLayer);
ctx.drawImage(filteredLayer, 0, 0);
this._copyCanvasContentsToClipboard(canvas);
}
_drawFilteredLayer(layer) {
const canvas = document.createElement("canvas");
canvas.width = layer.naturalWidth;
canvas.height = layer.naturalHeight;
const ctx = canvas.getContext("2d");
ctx.filter = this.currentFilter || "none";
ctx.drawImage(layer, 0, 0);
return canvas;
}
async _getBlobFromCanvas(canvas) {
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {
if (blob) {
resolve(blob);
} else {
reject(new Error("Canvas toBlob failed"));
}
});
});
}
async _copyCanvasContentsToClipboard(canvas) {
try {
const blob = await this._getBlobFromCanvas(canvas);
const data = [new ClipboardItem({ [blob.type]: blob })];
await navigator.clipboard.write(data);
} catch (error) {
console.error(error);
}
}
_copyAnimation(defaultEmoji, clickedEmoji) {
hideElement(defaultEmoji);
showElement(clickedEmoji);
setTimeout(() => {
hideElement(clickedEmoji);
showElement(defaultEmoji);
}, 1500);
}
}
new SpawnLayerManager();