Skip to content

Commit

Permalink
add support for zone/mark echo lines, macro splits, and copy button
Browse files Browse the repository at this point in the history
  • Loading branch information
wexxlee committed May 17, 2024
1 parent 7f1a60c commit a050196
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 25 deletions.
26 changes: 21 additions & 5 deletions index.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,25 @@ div {
font-weight: 800;
}

#macroText {
display: flex;
#macroContainer {
color: #148c3b;
font-size: 14px;
font-weight: 800;
}
font-size: 13px;
font-weight: 700;
}

.macroText {
position: relative;
margin-bottom: 20px;
padding: 10px;
padding-right: 70px;
border: 1px solid darkgreen;
display: table;
min-width: 400px;
}

.copyButton {
position: absolute;
top: 10px;
right: 10px;
}

14 changes: 12 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@
</div>
</fieldset>
<br />
<fieldset>
<legend>Options</legend>
<div>
<input type="checkbox" id="includeZoneName" />
<label for="includeZoneName">Add zone name headers to macro</label>
<br />
<input type="checkbox" id="includeMarkName" />
<label for="includeMarkName">Add mark names to macro</label>
</div>
</fieldset>
<fieldset>
<legend>Scouting Report</legend>
<div>
Expand All @@ -52,8 +62,8 @@
<div class="outputbar" id="errorHeader">Errors</div>
<div id="errorText"> </div>
<br />
<div class="outputbar" id="macroHeader">Macro</div>
<div id="macroText" style="color:darkgreen; font-size: larger"> </div>
<div class="outputbar" id="macroHeader">Macros</div>
<div id="macroContainer"> </div>
</td>
</tr>
</table>
Expand Down
136 changes: 118 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@

const _CMD_PREFIX = '/coord';
const _ECHO_PREFIX = '/e';
const _MAX_LINES_PER_MACRO = 15;
let lastClickedButton = null;
function generateMacro() {
clearOutput();

const _PREFIX = '/coord';
const regex = {
siren: /\(Maybe:\s*(?<mark>[^)]+)\)\s*.(?<zone>[\w ]+)\s*\(\s*(?<x>[0-9\.]+)\s*,\s*(?<y>[0-9\.]+)\s*\)/,
prime: /(?<mark>[\w ]+)\s+\((?<x>[0-9\.]+)\s*,\s*(?<y>[0-9\.]+)\s*\)/,
prime: /(?<mark>[^(]+)\s+\((?<x>[0-9\.]+)\s*,\s*(?<y>[0-9\.]+)\s*\)/,
primeZoneOnly: /^(?<zone>[\w\'\- ]+)$/,
bear: /(?<zone>[\w ]+)\s+\(\s*(?<x>[0-9\.]+)\s*,\s*(?<y>[0-9\.]+)\s*\)\s*(?<mark>[\w ]+)/,
}

Expand All @@ -26,56 +29,153 @@ function generateMacro() {
return;
}

const includeZoneName = document.getElementById('includeZoneName').checked;
const includeMarkName = document.getElementById('includeMarkName').checked;

let trainName = document.getElementById('trainName').value;
trainName = trainName === '' ? 'My Train' : trainName;
const trainHeader = `/e &nbsp;&nbsp;&nbsp;&nbsp;${trainName.toUpperCase()}&nbsp;&nbsp;&nbsp;&nbsp;`

let output = '';
const output = [trainHeader];
let zoneName = '';
let errors = '';
let zoneMarkCount = 0;
let zoneMarkCoordCache = [];
let zoneMarkNameCache = [];

// TODO: Add support for multiple instances (need to confirm output format from scout tools).
for (const mark of scoutMarks) {
if (mark.length < 3) // probably a newline
continue;
if (scoutSrc === 'prime') { // needs special handling
const zoneTestRegex = /^(?<zone>[\w\'\- ]+)$/;
const zoneTestMatch = mark.match(zoneTestRegex);

// if using prime, new zones will appear on a line by themselves
// so we need to use a different regex to detect the change in zone,
// and based on that, dump the previous zone's cached marks into `output`.
if (scoutSrc === 'prime') {
const zoneTestMatch = mark.match(regex.primeZoneOnly);
if (zoneTestMatch) {
// this could be the beginning of a new zone, or it could be
// an inadvertent header row that was copied (e.g. 'Endwalker').
// If MarkCount=0, that means we cached no marks for the last zone, so just
// set the new zone and move on. If we do have cached marks, process the prior zone.
if (zoneMarkCount > 0) {
const zoneHeader = getHeaderLine(zoneName, includeZoneName, zoneMarkNameCache, includeMarkName);
if (zoneHeader)
output.push(zoneHeader);
output.push(...zoneMarkCoordCache);
}
zoneMarkCount = 0;
zoneMarkCoordCache = [];
zoneMarkNameCache = [];
zoneName = zoneTestMatch.groups.zone;
continue;
}
}

const match = mark.match(scoutRegex);
const markName = match?.groups?.mark;
const markName = (match?.groups?.mark ?? '').trim();
const x = match?.groups?.x;
const y = match?.groups?.y;
const nonPrimeZoneName = match?.groups?.zone;

// handle output of previous zone here for non-prime scouts
if (
scoutSrc !== 'prime' &&
zoneName !== '' &&
nonPrimeZoneName &&
zoneName !== nonPrimeZoneName
) {
const zoneHeader = getHeaderLine(zoneName, includeZoneName, zoneMarkNameCache, includeMarkName);
if (zoneHeader)
output.push(zoneHeader);
output.push(...zoneMarkCoordCache);
zoneMarkCount = 0;
zoneMarkCoordCache = [];
zoneMarkNameCache = [];
}

if (scoutSrc !== 'prime')
zoneName = match?.groups?.zone;
zoneName = nonPrimeZoneName;

if (!markName || !x || !y || !zoneName) {
displayError(`Invalid mark format: ${mark}. Is the correct scouting tool selected?`);
continue;
}
output += `${_PREFIX} ${x} ${y} : ${zoneName}<br \>`;

zoneMarkCount++;
zoneMarkNameCache.push(markName);
zoneMarkCoordCache.push(`${_CMD_PREFIX} ${x} ${y} : ${zoneName}`);
}

displayMacro(trainHeader, output);
// push the final zone's marks, since the loop has ended
if (zoneMarkCount > 0) {
const zoneHeader = getHeaderLine(zoneName, includeZoneName, zoneMarkNameCache, includeMarkName);
if (zoneHeader)
output.push(zoneHeader);
output.push(...zoneMarkCoordCache);
}

displayMacro(output);
}

function displayMacro(trainHeader, output) {
if (output === '') {
function getHeaderLine(zoneName, includeZone, markNames, includeMarks) {
if (!includeZone && !includeMarks)
return;

let headerEcho = `${_ECHO_PREFIX}  `;
if (includeZone)
headerEcho += includeMarks ? `${zoneName}: ` : `${zoneName} `;
if (includeMarks)
headerEcho += `[${markNames.join(' → ')}] `;

return headerEcho;
}

function displayMacro(output) {
if (output.length <= 1) {
displayError('No macro generated.');
return;
}
document.getElementById('macroHeader').style.visibility = 'visible';
document.getElementById('macroText').innerHTML = `${trainHeader}<br />${output}`;
document.getElementById('macroContainer').innerHTML = getFormattedMacro(output);
}

function getFormattedMacro(output) {
let brokenOutput = '';
for (let i = 0; i < output.length; i++) {
if (i % _MAX_LINES_PER_MACRO === 0) {
if (i !== 0) {
brokenOutput += '</div>';
}
brokenOutput += `<div class="macroText"><button class="copyButton" onclick="copyToClipboard(this)">Copy to Clipboard</button>`;
}
brokenOutput += output[i];
if ((i + 1) % _MAX_LINES_PER_MACRO !== 0 || i !== output.length - 1)
brokenOutput += '<br />\n';
}
brokenOutput += '</div>';
return brokenOutput;
}

function copyToClipboard(button) {
if (lastClickedButton)
lastClickedButton.innerHTML = 'Copy to Clipboard';

let text = button.parentNode.textContent.replace('Copy to Clipboard', '');
navigator.clipboard.writeText(text).then(function () {
button.innerHTML = '<span style="color:green;">&#10004;</span> Copied!';
lastClickedButton = button;
}, function (err) {
displayError('Could not copy text: ', err);
});
}

function clearOutput() {
document.getElementById('errorText').innerHTML = '';
document.getElementById('macroText').innerHTML = '';
document.getElementById('errorHeader').style.visibility = 'hidden';
document.getElementById('macroContainer').innerHTML = '';
document.getElementById('errorHeader').style.visibility = 'hidden';
document.getElementById('macroHeader').style.visibility = 'hidden';
}
function displayError(msg) {
document.getElementById('errorHeader').style.visibility = 'visible';
document.getElementById('errorText').innerHTML += `Error: ${msg}<br>`;
document.getElementById('errorText').innerHTML += `Error: ${msg}<br />`;
}

0 comments on commit a050196

Please sign in to comment.