110 lines
3.4 KiB
JavaScript
110 lines
3.4 KiB
JavaScript
import counters from './assets/images/counters.svg';
|
|
import mapsheets from './assets/images/mapsheets.svg';
|
|
|
|
async function loadScript(scenario, svg, script) {
|
|
return new Promise((resolve, reject) => {
|
|
const scriptEl = document.createElementNS("http://www.w3.org/2000/svg", 'script');
|
|
|
|
scriptEl.onload = () => {
|
|
console.log(`${script}.js loaded`);
|
|
resolve();
|
|
};
|
|
|
|
scriptEl.onerror = () => {
|
|
reject(Error('Script failed to load.'));
|
|
};
|
|
|
|
const dataset = scenario.querySelector('script')?.dataset || {};
|
|
Object.entries(dataset).forEach(([k, v]) => scriptEl.dataset[k] = v);
|
|
|
|
scriptEl.setAttributeNS(null, 'href', `../../${script}.js`);
|
|
svg.append(scriptEl);
|
|
});
|
|
}
|
|
|
|
export async function requestResource(url) {
|
|
return new Promise((resolve, reject) => {
|
|
const request = new XMLHttpRequest();
|
|
request.open('GET', url, true);
|
|
request.responseType = 'document';
|
|
|
|
request.onload = function() {
|
|
if (request.status === 200) {
|
|
resolve(request.response);
|
|
} else {
|
|
reject(Error('Image didn\'t load successfully; error code:' + request.statusText));
|
|
}
|
|
};
|
|
|
|
request.onerror = function() {
|
|
reject(Error('There was a network error.'));
|
|
};
|
|
|
|
request.send();
|
|
});
|
|
}
|
|
|
|
export async function build(svg, request) {
|
|
const defs = svg.querySelector('defs');
|
|
const gb = svg.querySelector('.gameboard');
|
|
const grid = svg.querySelector('.grid');
|
|
|
|
const scenario = await request;
|
|
const startLocs = scenario.querySelector('.start-locations');
|
|
const externalResourceEls = Array.from(scenario.querySelectorAll('use[href*=".svg"'));
|
|
|
|
scenario.querySelectorAll('defs > *').forEach(el => defs.append(svg.ownerDocument.importNode(el, true)));
|
|
|
|
const refs = externalResourceEls.reduce((acc, el) => {
|
|
const href = el.getAttributeNS(null, 'href');
|
|
const [filename] = href.match(/.+\.svg/);
|
|
const fragmentIdentifier = href.split('.svg').pop();
|
|
|
|
(acc[filename] ??= new Set()).add(fragmentIdentifier);
|
|
el.setAttributeNS(null, 'href', fragmentIdentifier);
|
|
|
|
return acc;
|
|
}, {});
|
|
|
|
const hashedFilenames = {
|
|
'counters.svg': counters,
|
|
'mapsheets.svg': mapsheets
|
|
}
|
|
|
|
await Promise.all(
|
|
Object.keys(refs).map(filename => requestResource(hashedFilenames[filename]))
|
|
).then(result => {
|
|
Object.keys(refs).forEach((filename, index) => {
|
|
const external = result[index];
|
|
|
|
refs[filename].forEach(fragmentIdentifier => {
|
|
external
|
|
.querySelectorAll(`${fragmentIdentifier} use`)
|
|
.forEach(el => refs[filename].add(el.getAttributeNS(null, 'href')));
|
|
});
|
|
|
|
const refsQuery = [...refs[filename]].join(', ');
|
|
|
|
external.querySelectorAll(refsQuery).forEach(node =>
|
|
defs.append(svg.ownerDocument.importNode(node, true))
|
|
);
|
|
});
|
|
});
|
|
|
|
//if (startLocs) grid.before(svg.ownerDocument.importNode(startLocs, true));
|
|
|
|
const scenarioGrid = scenario.querySelector('.grid');
|
|
const scenarioBuildings = scenario.querySelector('.gameboard .buildings');
|
|
|
|
if (scenarioGrid) {
|
|
const frontmost = grid.querySelector('.frontmost');
|
|
[...scenarioGrid.children].forEach(child => frontmost.before(svg.ownerDocument.importNode(child, true)));
|
|
}
|
|
|
|
if (scenarioBuildings)
|
|
svg.querySelector('.gameboard .buildings').replaceWith(svg.ownerDocument.importNode(scenarioBuildings, true));
|
|
|
|
await loadScript(scenario, svg, 'radial')
|
|
return loadScript(scenario, svg, 'map');
|
|
}
|