I've been working on a simple character viewer.
I'll post the code below. Features so far are:
- Simple search and overview for Warmane characters
- Tooltips from wotlkdb.com, so you can inspect people when COT is down
- Uses localStorage to cache any character you last inspected
There is still a lot of info missing, like gems, enchants, professions, etc.
Some info can be added, but things like enchants are simply not provided by the API.
Now for the best part, the code:
index.php
Code:
<?php
declare(strict_types=1);
ini_set('display_errors', 'true');
error_reporting(E_ALL);
if('POST' === $_SERVER['REQUEST_METHOD'])
{
header('Content-type: application/json');
$post = json_decode(file_get_contents('php://input'), true);
$url = sprintf(
'https://armory.warmane.com/api/character/%s/%s/summary',
urlencode($post['name']),
urlencode($post['realm'])
);
$raw = file_get_contents($url);
if(json_decode($raw)) {
exit($raw);
}
exit('{"error": "Response was not JSON"}');
}
?><!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Warmane armoury</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='main.css'>
</head>
<body>
<h1>Warmane simple character viewer</h1>
<form id="searchform">
<label>
<input name="search" />
<select name="realm">
<option value="Outland">Outland</option>
<option value="Frostmourne">Frostmourne</option>
<option value="Lordaeron">Lordaeron</option>
<option value="Icecrown">Icecrown</option>
<option value="Blackrock">Blackrock</option>
<option value="Frostwolf">Frostwolf</option>
</select>
<button>Search</button>
</label>
<p id="statusbar">Status: <span id="status">Initializing</span></p>
<div class="char-template">
<h2 class="name"></h2>
<h3 class="guild"></h3>
<p>Level <span class="level"></span> <span class="race"></span> <span class="class"></span></p>
<h4>Equipment</h4>
<div class="equipment-container"></div>
</div>
</form>
<script type="text/javascript" src="https://wotlkdb.com/static/widgets/power.js"></script>
<script>var aowow_tooltips = { "colorlinks": true, "iconizelinks": true, "renamelinks": true }</script>
<script src='main.js'></script>
</body>
</html>
main.css
Code:
:root {
--container-width: 40vw;
}
html {
height: 100%;
}
body {
font-size: 100%;
min-height: 100%;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
* {
margin: 0;
}
h1,
#statusbar {
text-align: center;
}
#statusbar {
font-size: 0.7em;
}
#searchform label {
display: grid;
max-width: var(--container-width);
margin: 0 auto;
}
#searchform label input,
#searchform label select,
#searchform label button {
padding: 5px;
}
.char-template {
display: none;
}
.character {
max-width: var(--container-width);
margin: 0 auto;
}
.character h4 {
margin-top: 1em;
}
.equipment-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 10px;
max-width: var(--container-width);
margin: 1em auto;
}
.equipment-container a {
border: solid 1px silver;
padding: 5px;
}
main.js
Code:
"use strict";
document.addEventListener('DOMContentLoaded', () => {
let form = document.getElementById('searchform'),
search = form.elements.search,
realm = form.elements.realm,
status = document.getElementById('status'),
lastFound = localStorage.getItem('lastfound'),
charTemplate = document.querySelector('.char-template');
lastFound = lastFound ? JSON.parse(lastFound) : null;
function showCharacter(name, json) {
console.log(json);
if (json.error) {
return status.textContent = json.error;
}
localStorage.setItem('lastfound', JSON.stringify(json));
status.textContent = 'Found ' + name;
let char = charTemplate.cloneNode(true),
binding;
char.className = 'character';
for (let key in json) {
binding = char.querySelector('.' + key);
if (binding) {
binding.textContent = json[key];
}
}
let item;
for (let i = 0, l = json.equipment.length; i < l; i++) {
console.log(json.equipment[i].name);
item = document.createElement('a');
item.textContent = json.equipment[i].name;
item.setAttribute('rel', 'item=' + json.equipment[i].item);
char.querySelector('.equipment-container').appendChild(item);
}
document.body.appendChild(char);
}
function fetchCharacter(name, realm) {
fetch('index.php', {
method: 'POST',
body: JSON.stringify({
name: name,
realm: realm
})
}).then(
response => response.json()
).then(
json => {
json.fetchDate = new Date;
showCharacter(name, json);
}
).catch(
e => status.textContent = e.message
);
}
status.textContent = 'Ready';
if (lastFound) {
search.value = lastFound.name;
realm.value = lastFound.realm;
showCharacter(lastFound.name, lastFound);
}
form.addEventListener('submit', (evt) => {
evt.preventDefault();
search.value = search.value.trim();
if (search.value) {
status.textContent = 'Fetching ' + search.value;
fetchCharacter(search.value, realm.value);
} else {
status.textContent = 'Invalid name';
}
});
});