MediaWiki:Gadget-PasswordGenerator/Runtime.js

/** * Creates the frontend for the PG password tools. * Created by Cuyler on Nookipedia (https://nookipedia.com/wiki/User:Cuyler) * Licensed under CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0/) **/

(function {	"use strict";

// Set title of page as it appears in the browser tab: const PAGETITLE = "Animal Crossing Password Tools - Animal Crossing Wiki - Nookipedia";

document.title = PAGETITLE; $('#firstHeading').html('Password Tools');

const inputHTML = ` Input Code Type  Famicom Popular CardE Magazine User CardEMini Player Name (String #1)  Town Name (String #2)  Item  Generate Password   `;

const resultHTML = ` Output Password  `;

$('#ooui-2').empty; $('#ooui-2').append(inputHTML); $('#ooui-2').append(resultHTML);

// Main logic

// Font image const fontImg = new Image; fontImg.src = 'https://dodo.ac/np/images/8/8a/Animal_Crossing_PAL_Font.svg';

// Map between item name (string) and id (number) const item_map = new Map;

// Currently selected canvas "textbox" info var selected_box = null; var selected_buf = null; var selected_box_cols = 0; var selected_box_rows = 0; var selected_box_char_idx = 0;

// Array which holds the current string0 param var nameBytes = new Uint8Array(8); nameBytes.fill(0x20);

// Array which holds the current string1 param var townBytes = new Uint8Array(8); townBytes.fill(0x20);

// Array which holds the current password string var passwordBuffer = new Uint8Array(28); passwordBuffer.fill(0x20);

function clearCanvas(canvas) { const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); }

function getElementOffset(el) { const rect = el.getBoundingClientRect; return { left: rect.left + window.scrollX, top: rect.top + window.scrollY }; }

function canvasSetCharacterPos(canvas, buf, e, chars_per_row, chars_per_col) { if (canvas === null) { return; }

// Reset previously selected box highlight if (selected_box !== null && canvas != selected_box) { clearCanvas(selected_box); drawStringToCanvas(selected_buf, selected_box, 8, 1); }

selected_box = canvas; selected_box_cols = chars_per_row; selected_box_rows = chars_per_col; selected_buf = buf; const ofs = getElementOffset(canvas);

var x = (e.pageX - ofs.left) + $(window).scrollLeft; var y = (e.pageY - ofs.top) + $(window).scrollTop;

const char_width = canvas.width / chars_per_row; const char_height = canvas.height / chars_per_col;

x = Math.floor(x / char_width); y = Math.floor(y / char_height);

selected_box_char_idx = x + y * chars_per_row; }

function drawStringToCanvas(buf, canvas, chars_per_row, chars_per_col) { const font_char_width = fontImg.width / 16; const font_char_height = fontImg.height / 16;

const char_width = canvas.width / chars_per_row; const char_height = canvas.height / chars_per_col;

const ctx = canvas.getContext('2d'); for (var i = 0; i < buf.length; i++) { const row = Math.floor(i / chars_per_row); const font_x_ofs = Math.floor(buf[i] % 16); const font_y_ofs = Math.floor(buf[i] / 16);

const sx = font_x_ofs * font_char_width; const sy = font_y_ofs * font_char_height; const sw = font_char_width; const sh = font_char_height;

const dx = char_width * Math.floor(i % chars_per_row); const dy = char_height * row; const dw = char_width; const dh = char_height;

ctx.drawImage(fontImg, sx, sy, sw, sh, dx, dy, dw, dh); } }

function highlightCurrentCharacter(canvas, e, chars_per_col, chars_per_row) { const ctx = canvas.getContext('2d'); const ofs = getElementOffset(canvas);

var x = (e.pageX - ofs.left) + $(window).scrollLeft; var y = (e.pageY - ofs.top) + $(window).scrollTop;

const char_width = canvas.width / chars_per_row; const char_height = canvas.height / chars_per_col;

x = Math.floor(x / char_width); y = Math.floor(y / char_height);

ctx.strokeStyle = "red"; ctx.strokeRect(x * char_width, y * char_height + 2, char_width, char_height - 4); }

function highlightSelectedCharacter(canvas, chars_per_col, chars_per_row) { if (selected_box != canvas) { return; }

const ctx = canvas.getContext('2d'); const x = selected_box_char_idx % chars_per_row; const y = Math.floor(selected_box_char_idx / chars_per_row);

const char_width = canvas.width / chars_per_row; const char_height = canvas.height / chars_per_col;

ctx.fillStyle = "yellow"; ctx.globalAlpha = 0.5; ctx.fillRect(x * char_width, y * char_height, char_width, char_height); ctx.globalAlpha = 1.0; }

function fontCanvasGetCharFromPos(canvas, e) { const ofs = getElementOffset(canvas);

var x = (e.pageX - ofs.left) + $(window).scrollLeft; var y = (e.pageY - ofs.top) + $(window).scrollTop;

const char_width = canvas.width / 16; const char_height = canvas.height / 16;

return Math.floor(x / char_width) + Math.floor(y / char_height) * 16; }

function addCharacterToBuffer(buf, pos, char) { console.log(buf, pos, char, selected_buf); buf[pos] = char; if (buf == selected_buf) { const max = selected_box_rows * selected_box_cols; if (selected_box_char_idx < max - 1) { selected_box_char_idx++; }   }  }

function init { var nameCanvas = document.getElementById('nameCanvas'); nameCanvas.getContext('2d').canvas.width = nameCanvas.offsetWidth; // sync canvas width with element width nameCanvas.addEventListener("mousemove", function(e) {     clearCanvas(nameCanvas);      highlightSelectedCharacter(nameCanvas, 1, 8);      drawStringToCanvas(nameBytes, nameCanvas, 8, 1);      highlightCurrentCharacter(nameCanvas, e, 1, PARAM_STRING_SIZE);    }); nameCanvas.addEventListener("mouseout", function {     clearCanvas(nameCanvas);      highlightSelectedCharacter(nameCanvas, 1, 8);      drawStringToCanvas(nameBytes, nameCanvas, 8, 1);    }); nameCanvas.addEventListener("mousedown", function(e) {     clearCanvas(nameCanvas);      canvasSetCharacterPos(nameCanvas, nameBytes, e, 8, 1);      highlightSelectedCharacter(nameCanvas, 1, 8);      drawStringToCanvas(nameBytes, nameCanvas, 8, 1);      highlightCurrentCharacter(nameCanvas, e, 1, PARAM_STRING_SIZE);    });

var townCanvas = document.getElementById('townCanvas'); townCanvas.getContext('2d').canvas.width = townCanvas.offsetWidth; // sync canvas width with element width townCanvas.addEventListener("mousemove", function(e) {     clearCanvas(townCanvas);      highlightSelectedCharacter(townCanvas, 1, 8);      drawStringToCanvas(townBytes, townCanvas, 8, 1);      highlightCurrentCharacter(townCanvas, e, 1, PARAM_STRING_SIZE);    }); townCanvas.addEventListener("mouseout", function {     clearCanvas(townCanvas);      highlightSelectedCharacter(townCanvas, 1, 8);      drawStringToCanvas(townBytes, townCanvas, 8, 1);    }); townCanvas.addEventListener("mousedown", function(e) {     clearCanvas(townCanvas);      canvasSetCharacterPos(townCanvas, townBytes, e, 8, 1);      highlightSelectedCharacter(townCanvas, 1, 8);      drawStringToCanvas(townBytes, townCanvas, 8, 1);      highlightCurrentCharacter(townCanvas, e, 1, PARAM_STRING_SIZE);    });

var generatorInputCanvas = document.getElementById('generatorCanvas'); generatorInputCanvas.getContext('2d').canvas.width = generatorInputCanvas.offsetWidth; // sync canvas width with element width generatorInputCanvas.getContext('2d').canvas.height = generatorInputCanvas.offsetHeight; generatorInputCanvas.addEventListener("mousemove", function(e) {     clearCanvas(generatorInputCanvas);      highlightCurrentCharacter(generatorInputCanvas, e, 16, 16);    }); generatorInputCanvas.addEventListener("mouseout", function {     generatorInputCanvas.getContext('2d').clearRect(0, 0, generatorInputCanvas.width, generatorInputCanvas.height);    }); generatorInputCanvas.addEventListener("mousedown", function(e) {     const char = fontCanvasGetCharFromPos(generatorInputCanvas, e);      addCharacterToBuffer(selected_buf, selected_box_char_idx, char);      clearCanvas(selected_box);      highlightSelectedCharacter(selected_box, selected_box_rows, selected_box_cols);      drawStringToCanvas(selected_buf, selected_box, selected_box_cols, selected_box_rows);    });

const passwordCanvas = document.getElementById('outPwdCanvas'); passwordCanvas.getContext('2d').canvas.width = passwordCanvas.offsetWidth; // sync canvas width with element width passwordCanvas.getContext('2d').canvas.height = passwordCanvas.offsetHeight;

const genButton = document.getElementById('genButton'); genButton.addEventListener('click', function {     const codetype_select = document.getElementById('codetype');      console.log(codetype_select.value);      const code_type = Number(codetype_select.value);      console.log(code_type);      if (isNaN(code_type) || code_type < CODE_TYPES.Famicom || code_type > CODE_TYPES.CardEMini) {        alert("Invalid code type! Please select a valid code type!");        return;      }

const item_name = document.getElementById('iteminput').value; // Check if the item name field was set if (!item_name) { alert("You must select an item before generating a password!"); return; }

const item_id = item_map.get(item_name); // Check if the item name supplied is valid if (item_id === undefined) { alert("Unknown item selected! Please use the auto-complete list to select a valid item for this password!"); return; }

// Generate password & update password canvas passwordBuffer = MakePassword(code_type, 0, nameBytes, townBytes, item_id, 0, 0); clearCanvas(passwordCanvas); drawStringToCanvas(passwordBuffer, passwordCanvas, 14, 2); });

selected_box = nameCanvas; selected_buf = nameBytes; selected_box_cols = 8; selected_box_rows = 1; highlightSelectedCharacter(nameCanvas, 1, 8); }

mw.loader.getScript('https://nookipedia.com/w/index.php?title=User:Cuyler/ACItemDatabase.json&ctype=application/json&action=raw') .fail(function(err) {     console.log("Error loading AC item database: " + err.message);    }) .done(function (data) {     const itemlist = document.getElementById('itemlist');      const item_data_array = JSON.parse(data);      for (var i = 0; i < item_data_array.length; i++) {        const id = Number("0x" + item_data_array[i].id);

// Generate item option itemlist.appendChild(new Option(id, item_data_array[i].name));

// Set the name-id pair in the item map item_map.set(item_data_array[i].name, id); }   });

mw.loader.getScript('https://nookipedia.com/w/index.php?title=User:Cuyler/passwordGenerator.js&ctype=text/javascript&action=raw') .fail(function(err) {       console.log("Error loading AC Password script: " + err.message);      }) .done(function(data) {       init;      }); });