Upload files to "ICS"

This commit is contained in:
2026-09-04 16:09:44 -04:00
parent de702a832a
commit 1c3790e9ad
5 changed files with 2063 additions and 0 deletions
+444
View File
@@ -0,0 +1,444 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Initial Damage Assessment / Windshield Survey (Packet Radio)</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #eef2f7; color: #222; padding: 20px; margin: 0; }
.container { max-width: 980px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #b71c1c; color: white; padding: 12px; border-radius: 6px; text-align: center; margin-bottom: 18px; }
.header h2 { margin: 0; font-size: 1.3rem; letter-spacing: 1px; }
.header p { margin: 4px 0 0 0; font-size: 0.85rem; opacity: 0.9; }
fieldset { border: 1px solid #ef9a9a; border-radius: 6px; padding: 14px; margin-bottom: 14px; background: #fffbfb; }
legend { font-weight: bold; padding: 0 8px; font-size: 0.85rem; color: #b71c1c; }
.row { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 10px; }
.col { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
label { font-size: 0.8rem; font-weight: 600; color: #333; }
input[type="text"], select, textarea { padding: 7px 8px; font-size: 0.88rem; border: 1px solid #999; border-radius: 4px; font-family: inherit; width: 100%; }
.btn-now { background: #4a5568; color: #fff; padding: 4px 8px; font-size: 0.72rem; border-radius: 4px; border: none; cursor: pointer; }
.btn-now:hover { background: #2d3748; }
table.grid-table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 0.82rem; }
table.grid-table th, table.grid-table td { border: 1px solid #ccc; padding: 6px; text-align: center; }
table.grid-table th { background: #f0f0f0; }
table.grid-table input { font-size: 0.82rem; padding: 4px; text-align: center; }
.actions { display: flex; gap: 10px; margin: 18px 0; }
button.main-btn { flex: 1; padding: 12px; font-size: 0.95rem; font-weight: bold; border: none; border-radius: 6px; cursor: pointer; }
.btn-generate { background: #b71c1c; color: #fff; }
.btn-generate:hover { background: #7f0000; }
.btn-save { background: #5c6bc0; color: #fff; }
.btn-save:hover { background: #3f51b5; }
.btn-copy { background: #2e7d32; color: #fff; }
.btn-copy:hover { background: #1b5e20; }
.btn-clear { background: #555; color: #fff; flex: 0.35; }
.btn-clear:hover { background: #333; }
pre { background: #181c20; color: #39ff14; padding: 14px; border-radius: 6px; overflow-x: auto; font-family: "Courier New", Courier, monospace; font-size: 0.82rem; line-height: 1.32; min-height: 150px; }
.nav-bar { margin-bottom: 12px; font-size: 0.85rem; }
.nav-bar a { color: #b71c1c; text-decoration: none; font-weight: bold; }
/* Modal Save Dialog Window */
.save-modal-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.55); z-index: 99999; justify-content: center; align-items: center;
}
.save-modal-backdrop.active { display: flex; }
.save-modal-window {
background: #ffffff; padding: 24px 28px; border-radius: 10px; width: 92%; max-width: 480px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 1px solid #cbd5e1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.save-modal-window h3 { margin: 0 0 8px 0; font-size: 1.25rem; color: #1e293b; font-weight: bold; }
.save-modal-window p { margin: 0 0 16px 0; font-size: 0.88rem; color: #64748b; line-height: 1.4; }
.save-modal-window input[type="text"] {
width: 100%; padding: 10px 12px; font-size: 0.95rem; border: 2px solid #94a3b8; border-radius: 6px;
margin-bottom: 20px; font-family: inherit; box-sizing: border-box; text-transform: none;
}
.save-modal-window input[type="text"]:focus { border-color: #2563eb; outline: none; }
.save-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.save-modal-btn { padding: 9px 18px; font-size: 0.9rem; font-weight: bold; border-radius: 6px; border: none; cursor: pointer; }
.save-modal-btn-confirm { background: #2563eb; color: #ffffff; }
.save-modal-btn-confirm:hover { background: #1d4ed8; }
.save-modal-btn-cancel { background: #e2e8f0; color: #334155; }
.save-modal-btn-cancel:hover { background: #cbd5e1; }
</style>
</head>
<body>
<div class="container">
<div class="nav-bar"><a href="../index.html">&larr; Back to Packet Forms Hub</a></div>
<div class="header">
<h2>INITIAL DAMAGE ASSESSMENT / WINDSHIELD SURVEY</h2>
<p>Winlink / Packet Radio Rapid Field Damage & Loss Tally</p>
</div>
<form id="damageForm" onsubmit="event.preventDefault(); return false;">
<fieldset>
<legend>INCIDENT & SURVEY HEADER</legend>
<div class="row">
<div class="col" style="flex: 2;"><label for="jur">Jurisdiction</label><input type="text" id="jur" placeholder="e.g. Travis County OEM"></div>
<div class="col"><label for="misNum">Mission / Incident #</label><input type="text" id="misNum" placeholder="e.g. 2026-FLOOD-01"></div>
<div class="col"><label for="status">Exercise / Real</label>
<select id="status">
<option value="EXERCISE">EXERCISE</option>
<option value="REAL EVENT">REAL EVENT</option>
</select>
</div>
</div>
<div class="row">
<div class="col"><label for="event">Event Type</label>
<select id="event">
<option value="Hurricane">Hurricane</option>
<option value="Tropical Storm">Tropical Storm</option>
<option value="Tornado/Winds">Tornado/Winds</option>
<option value="Flood">Flood</option>
<option value="Earthquake">Earthquake</option>
<option value="Fire">Fire</option>
<option value="Haz Mat">Haz Mat</option>
<option value="OTHER">OTHER</option>
</select>
</div>
<div class="col"><label for="eventOther">If Other, Describe</label><input type="text" id="eventOther" placeholder="Describe other event"></div>
<div class="col"><label for="surArea">Survey Area</label><input type="text" id="surArea" placeholder="e.g. Sector 4 / North River Rd"></div>
<div class="col"><label for="surTeam">Survey Team / Calls</label><input type="text" id="surTeam" placeholder="Team Alpha / Callsigns"></div>
</div>
<div class="row">
<div class="col"><label for="eventDate">Start Date of Event</label><input type="text" id="eventDate" placeholder="YYYY-MM-DD"></div>
<div class="col">
<div class="label-row">
<label for="surDate">Date of this Survey</label>
<button type="button" class="btn-now" id="btnDateNow">Current UTC</button>
</div>
<input type="text" id="surDate" placeholder="YYYY-MM-DD">
</div>
</div>
</fieldset>
<fieldset>
<legend>DAMAGE CATEGORIES & COUNTS</legend>
<table class="grid-table" id="dmgTable">
<thead>
<tr>
<th style="text-align:left;">Category</th>
<th style="background:#c8e6c9;">Affected<br>(10%)</th>
<th style="background:#fff9c4;">Minor<br>(25%)</th>
<th style="background:#ffcdd2;">Major<br>(50%)</th>
<th style="background:#e0e0e0;">Totaled<br>(100%)</th>
<th>Count</th>
<th>Est. $ Loss</th>
</tr>
</thead>
<tbody id="dmgBody">
<!-- Populated by script -->
</tbody>
<tfoot>
<tr style="font-weight:bold; background:#f5f5f5;">
<td colspan="5" style="text-align:right;">Total Estimated Dollar Amount:</td>
<td id="grandCount">0</td>
<td><input type="text" id="grandLoss" readonly style="font-weight:bold; text-align:right;" value="$ 0"></td>
</tr>
</tfoot>
</table>
</fieldset>
<fieldset>
<legend>COMMENTS</legend>
<textarea id="comments" rows="3" placeholder="Brief summary of damages, access problems, or high-density destruction zones..."></textarea>
</fieldset>
<div class="actions">
<button type="button" class="main-btn btn-generate" id="btnGen">Generate Packet ASCII</button>
<button type="button" class="main-btn btn-save" id="btnSaveHtml">Save as HTML</button>
<button type="button" class="main-btn btn-copy" id="btnCopy">Copy ASCII</button>
<button type="button" class="main-btn btn-clear" id="btnClear">Reset</button>
</div>
</form>
<label style="font-weight:bold;">Formatted ASCII for Packet / Winlink / BBS Transmission:</label>
<pre id="outputPre">Fill in the fields above and click "Generate Packet ASCII"...</pre>
</div>
<script>
const categories = [
"HOUSES",
"APARTMENT COMPLEX",
"MOBILE HOMES",
"RESIDENTIAL HIGH RISE",
"COMMERCIAL HIGH RISE",
"PUBLIC BUILDINGS",
"SMALL BUSINESS",
"FACTORIES / INDUSTRIAL",
"ROADS",
"BRIDGES",
"ELECTRICAL DISTRIBUTION",
"SCHOOLS"
];
const tbody = document.getElementById('dmgBody');
categories.forEach(function(cat, idx) {
const tr = document.createElement('tr');
tr.innerHTML = '<td style="text-align:left; font-weight:600;">' + cat + '</td>' +
'<td><input type="text" class="c-aff" data-row="' + idx + '" value="0" oninput="calcRow(' + idx + ')"></td>' +
'<td><input type="text" class="c-min" data-row="' + idx + '" value="0" oninput="calcRow(' + idx + ')"></td>' +
'<td><input type="text" class="c-maj" data-row="' + idx + '" value="0" oninput="calcRow(' + idx + ')"></td>' +
'<td><input type="text" class="c-des" data-row="' + idx + '" value="0" oninput="calcRow(' + idx + ')"></td>' +
'<td><input type="text" class="c-tot" data-row="' + idx + '" value="0" readonly style="background:#eee;"></td>' +
'<td><input type="text" class="c-loss" data-row="' + idx + '" placeholder="0" oninput="calcTotalLoss()"></td>';
tbody.appendChild(tr);
});
function setUTC() {
const now = new Date();
const y = now.getUTCFullYear();
const m = String(now.getUTCMonth()+1).padStart(2,'0');
const d = String(now.getUTCDate()).padStart(2,'0');
document.getElementById('surDate').value = y + '-' + m + '-' + d;
if (!document.getElementById('eventDate').value) {
document.getElementById('eventDate').value = y + '-' + m + '-' + d;
}
}
function calcRow(idx) {
const row = tbody.children[idx];
const aff = parseInt(row.querySelector('.c-aff').value) || 0;
const min = parseInt(row.querySelector('.c-min').value) || 0;
const maj = parseInt(row.querySelector('.c-maj').value) || 0;
const des = parseInt(row.querySelector('.c-des').value) || 0;
row.querySelector('.c-tot').value = aff + min + maj + des;
calcTotalLoss();
}
function calcTotalLoss() {
let totCount = 0;
let totLoss = 0;
for (let i = 0; i < tbody.children.length; i++) {
const r = tbody.children[i];
totCount += parseInt(r.querySelector('.c-tot').value) || 0;
const rawLoss = (r.querySelector('.c-loss').value || '').replace(/[^0-9]/g, '');
totLoss += parseInt(rawLoss) || 0;
}
document.getElementById('grandCount').textContent = totCount;
document.getElementById('grandLoss').value = '$ ' + totLoss.toLocaleString();
}
function clean(id) {
const el = document.getElementById(id);
return el ? (el.value || '').trim() : '';
}
function pad(str, len) {
str = (str || '').toString();
return str + ' '.repeat(Math.max(0, len - str.length));
}
function generateASCII() {
try {
calcTotalLoss();
const div = '='.repeat(78);
const sub = '-'.repeat(78);
const jur = clean('jur').toUpperCase() || 'N/A';
const mis = clean('misNum').toUpperCase() || 'N/A';
const stat = clean('status').toUpperCase();
const evt = clean('event').toUpperCase();
const other = clean('eventOther').toUpperCase();
const area = clean('surArea').toUpperCase() || 'N/A';
const team = clean('surTeam').toUpperCase() || 'N/A';
const evDate = clean('eventDate') || 'N/A';
const surDate = clean('surDate') || 'N/A';
const cmt = clean('comments').toUpperCase() || 'NONE REPORTED';
let gridLines = [];
for (let i = 0; i < categories.length; i++) {
const r = tbody.children[i];
const cat = pad(categories[i], 24);
const aff = pad(r.querySelector('.c-aff').value || '0', 5);
const min = pad(r.querySelector('.c-min').value || '0', 5);
const maj = pad(r.querySelector('.c-maj').value || '0', 5);
const des = pad(r.querySelector('.c-des').value || '0', 5);
const tot = pad(r.querySelector('.c-tot').value || '0', 6);
const loss = pad(r.querySelector('.c-loss').value || '0', 12);
if (parseInt(tot.trim()) > 0 || loss.trim() !== '0') {
gridLines.push(cat + '| ' + aff + '| ' + min + '| ' + maj + '| ' + des + '| ' + tot + '| ' + loss);
}
}
if (gridLines.length === 0) {
gridLines.push(' NO REPORTED STRUCTURE OR INFRASTRUCTURE DAMAGE AT THIS TIME');
}
const out = div + '\n' +
'INITIAL DAMAGE ASSESSMENT / WINDSHIELD SURVEY (PACKET ASCII)\n' +
div + '\n' +
'JURISDICTION: ' + jur + ' MISSION #: ' + mis + '\n' +
'STATUS : ' + stat + ' EVENT : ' + evt + (other ? ' (' + other + ')' : '') + '\n' +
'SURVEY AREA : ' + area + '\n' +
'SURVEY TEAM : ' + team + '\n' +
'EVENT DATE : ' + evDate + ' SURVEY DATE: ' + surDate + '\n' +
sub + '\n' +
'CATEGORY | AFF | MIN | MAJ | TOTAL| COUNT | EST. $ LOSS\n' +
sub + '\n' +
gridLines.join('\n') + '\n' +
sub + '\n' +
'TOTAL DAMAGED STRUCTURES: ' + pad(document.getElementById('grandCount').textContent, 8) +
'ESTIMATED TOTAL LOSS: ' + document.getElementById('grandLoss').value + '\n' +
sub + '\n' +
'COMMENTS:\n ' + cmt + '\n' +
div;
document.getElementById('outputPre').textContent = out;
} catch(err) {
alert("Error generating text: " + err.message);
}
}
function copyASCII() {
const txt = document.getElementById('outputPre').textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(function() {
alert("Damage assessment copied to clipboard!");
}).catch(function() {
fallbackCopy();
});
} else {
fallbackCopy();
}
}
function fallbackCopy() {
const pre = document.getElementById('outputPre');
const range = document.createRange();
range.selectNode(pre);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
alert("Copied to clipboard!");
}
function clearForm() {
if(confirm("Reset Damage Assessment form?")) {
document.getElementById('damageForm').reset();
document.querySelectorAll('.c-tot').forEach(function(el){ el.value = '0'; });
document.getElementById('grandCount').textContent = '0';
document.getElementById('grandLoss').value = '$ 0';
document.getElementById('outputPre').textContent = 'Fill in the fields above and click "Generate Packet ASCII"...';
}
}
document.getElementById('btnDateNow').addEventListener('click', setUTC);
document.getElementById('btnGen').addEventListener('click', generateASCII);
document.getElementById('btnSaveHtml').addEventListener('click', openSaveModal);
document.getElementById('btnCopy').addEventListener('click', copyASCII);
document.getElementById('btnClear').addEventListener('click', clearForm);
// File Name Modal Window & HTML Exporter
function openSaveModal() {
var now = new Date();
var dStr = now.toISOString().slice(0, 10);
var defName = 'damage_assessment_' + dStr + '.html';
var modal = document.getElementById('saveModalBackdrop');
var input = document.getElementById('saveModalFileName');
if (input) input.value = defName;
if (modal) modal.classList.add('active');
setTimeout(function() {
if (input) { input.focus(); input.select(); }
}, 50);
}
function closeSaveModal() {
var modal = document.getElementById('saveModalBackdrop');
if (modal) modal.classList.remove('active');
}
function executeSaveHTML() {
var input = document.getElementById('saveModalFileName');
var chosenName = input ? input.value.trim() : '';
if (!chosenName) return;
if (!chosenName.toLowerCase().endsWith('.html') && !chosenName.toLowerCase().endsWith('.htm')) {
chosenName += '.html';
}
closeSaveModal();
document.querySelectorAll('input[type="text"]').forEach(function(el) { el.setAttribute('value', el.value); });
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(el) {
if (el.checked) el.setAttribute('checked', 'checked');
else el.removeAttribute('checked');
});
document.querySelectorAll('textarea').forEach(function(el) { el.textContent = el.value; });
document.querySelectorAll('select').forEach(function(el) {
Array.from(el.options).forEach(function(opt) {
if (opt.value === el.value) opt.setAttribute('selected', 'selected');
else opt.removeAttribute('selected');
});
});
var pre = document.getElementById('ascii-report') || document.getElementById('outputPre') || document.getElementById('preview') || document.getElementById('outputArea');
if (pre) pre.textContent = pre.textContent;
var clonedDoc = document.documentElement.cloneNode(true);
var modalInClone = clonedDoc.querySelector('#saveModalBackdrop');
if (modalInClone) modalInClone.classList.remove('active');
var htmlContent = '<!DOCTYPE html>\n' + clonedDoc.outerHTML;
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = chosenName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
window.addEventListener('DOMContentLoaded', function() {
var cancelBtn = document.getElementById('saveModalCancelBtn');
var confirmBtn = document.getElementById('saveModalSaveBtn');
var modalInput = document.getElementById('saveModalFileName');
var modalBackdrop = document.getElementById('saveModalBackdrop');
if (cancelBtn) cancelBtn.addEventListener('click', closeSaveModal);
if (confirmBtn) confirmBtn.addEventListener('click', executeSaveHTML);
if (modalInput) {
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); executeSaveHTML(); }
if (e.key === 'Escape') { e.preventDefault(); closeSaveModal(); }
});
}
if (modalBackdrop) {
modalBackdrop.addEventListener('click', function(e) {
if (e.target === modalBackdrop) closeSaveModal();
});
}
var btnSaveMain = document.getElementById('btnSaveHtml');
if (btnSaveMain) {
// Clear existing inline handlers just in case
btnSaveMain.onclick = null;
btnSaveMain.addEventListener('click', openSaveModal);
}
});
</script>
<!-- Custom File Name Modal Window -->
<div id="saveModalBackdrop" class="save-modal-backdrop">
<div class="save-modal-window">
<h3>Save Form as HTML</h3>
<p>Enter a name for the saved offline HTML file:</p>
<input type="text" id="saveModalFileName" spellcheck="false">
<div class="save-modal-actions">
<button type="button" class="save-modal-btn save-modal-btn-cancel" id="saveModalCancelBtn">Cancel</button>
<button type="button" class="save-modal-btn save-modal-btn-confirm" id="saveModalSaveBtn">Save File</button>
</div>
</div>
</div>
</body>
</html>
+380
View File
@@ -0,0 +1,380 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ICS 205 - Radio Communications Plan (Packet Radio)</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #f3f6f9; color: #222; padding: 20px; margin: 0; }
.container { max-width: 900px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #4a148c; color: white; padding: 12px; border-radius: 6px; text-align: center; margin-bottom: 18px; }
.header h2 { margin: 0; font-size: 1.3rem; letter-spacing: 1px; }
.header p { margin: 4px 0 0 0; font-size: 0.85rem; opacity: 0.9; }
fieldset { border: 1px solid #d1c4e9; border-radius: 6px; padding: 14px; margin-bottom: 14px; background: #faf8fd; }
legend { font-weight: bold; padding: 0 8px; font-size: 0.85rem; color: #4a148c; }
.row { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 10px; }
.col { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
label { font-size: 0.8rem; font-weight: 600; color: #333; }
input[type="text"] { padding: 7px 8px; font-size: 0.9rem; border: 1px solid #999; border-radius: 4px; font-family: inherit; }
.btn-now { background: #555; color: #fff; padding: 4px 8px; font-size: 0.72rem; border-radius: 4px; border: none; cursor: pointer; }
.btn-now:hover { background: #333; }
.actions { display: flex; gap: 10px; margin: 18px 0; }
button.main-btn { flex: 1; padding: 12px; font-size: 0.95rem; font-weight: bold; border: none; border-radius: 6px; cursor: pointer; }
.btn-generate { background: #4a148c; color: #fff; }
.btn-generate:hover { background: #311b92; }
.btn-copy { background: #2e7d32; color: #fff; }
.btn-copy:hover { background: #1b5e20; }
.btn-clear { background: #c62828; color: #fff; flex: 0.4; }
pre { background: #181c20; color: #39ff14; padding: 14px; border-radius: 6px; overflow-x: auto; font-family: "Courier New", Courier, monospace; font-size: 0.83rem; line-height: 1.3; min-height: 150px; }
.channel-row { display: flex; gap: 6px; margin-bottom: 6px; }
.channel-row input { font-size: 0.82rem; padding: 5px; }
.nav-bar { margin-bottom: 12px; font-size: 0.85rem; }
.nav-bar a { color: #4a148c; text-decoration: none; font-weight: bold; }
/* Modal Save Dialog Window */
.save-modal-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.55); z-index: 99999; justify-content: center; align-items: center;
}
.save-modal-backdrop.active { display: flex; }
.save-modal-window {
background: #ffffff; padding: 24px 28px; border-radius: 10px; width: 92%; max-width: 480px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 1px solid #cbd5e1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.save-modal-window h3 { margin: 0 0 8px 0; font-size: 1.25rem; color: #1e293b; font-weight: bold; }
.save-modal-window p { margin: 0 0 16px 0; font-size: 0.88rem; color: #64748b; line-height: 1.4; }
.save-modal-window input[type="text"] {
width: 100%; padding: 10px 12px; font-size: 0.95rem; border: 2px solid #94a3b8; border-radius: 6px;
margin-bottom: 20px; font-family: inherit; box-sizing: border-box; text-transform: none;
}
.save-modal-window input[type="text"]:focus { border-color: #2563eb; outline: none; }
.save-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.save-modal-btn { padding: 9px 18px; font-size: 0.9rem; font-weight: bold; border-radius: 6px; border: none; cursor: pointer; }
.save-modal-btn-confirm { background: #2563eb; color: #ffffff; }
.save-modal-btn-confirm:hover { background: #1d4ed8; }
.save-modal-btn-cancel { background: #e2e8f0; color: #334155; }
.save-modal-btn-cancel:hover { background: #cbd5e1; }
</style>
</head>
<body>
<div class="container">
<div class="nav-bar"><a href="../index.html">&larr; Back to Packet Forms Hub</a></div>
<div class="header">
<h2>ICS 205 - RADIO COMMUNICATIONS PLAN</h2>
<p>Incident Channel & Frequency Assignment Plan (Packet ASCII)</p>
</div>
<form id="ics205Form" onsubmit="event.preventDefault(); return false;">
<fieldset>
<legend>INCIDENT HEADER</legend>
<div class="row">
<div class="col" style="flex: 2;"><label for="incName">1. Incident Name</label><input type="text" id="incName" style="width: 100%;"></div>
<div class="col"><label for="opPeriod">2. Operational Period</label><input type="text" id="opPeriod" placeholder="Date/Time Span" style="width: 100%;"></div>
</div>
</fieldset>
<fieldset>
<legend>3. BASIC RADIO CHANNEL ASSIGNMENTS</legend>
<div style="font-size: 0.75rem; font-weight: bold; margin-bottom: 6px; color: #555;">
Zone / Ch# | Function | Channel Name | RX Freq / Tone | TX Freq / Tone | Mode / Remarks
</div>
<div id="channelContainer">
<div class="channel-row">
<input type="text" style="width: 75px;" placeholder="CH 01" value="CH 01">
<input type="text" style="width: 140px;" placeholder="COMMAND" value="COMMAND">
<input type="text" style="width: 120px;" placeholder="VHF TAC 1" value="TAC-1">
<input type="text" style="width: 130px;" placeholder="146.520 PL CSQ" value="146.520 CSQ">
<input type="text" style="width: 130px;" placeholder="146.520 PL CSQ" value="146.520 CSQ">
<input type="text" style="flex: 1;" placeholder="Simplex / Primary Net" value="SIMPLEX COMM">
</div>
<div class="channel-row">
<input type="text" style="width: 75px;" placeholder="CH 02" value="CH 02">
<input type="text" style="width: 140px;" placeholder="PACKET/DATA" value="PACKET/DATA">
<input type="text" style="width: 120px;" placeholder="BBS / RMS" value="RMS NODE">
<input type="text" style="width: 130px;" placeholder="145.090 Simp" value="145.090">
<input type="text" style="width: 130px;" placeholder="145.090 Simp" value="145.090">
<input type="text" style="flex: 1;" placeholder="1200 Baud AX.25 BBS" value="1200 BAUD PACKET">
</div>
<div class="channel-row">
<input type="text" style="width: 75px;" placeholder="CH 03" value="CH 03">
<input type="text" style="width: 140px;" placeholder="LOGISTICS" value="LOGISTICS">
<input type="text" style="width: 120px;" placeholder="RPT-1" value="COUNTY RPT">
<input type="text" style="width: 130px;" placeholder="147.120 +107.2" value="147.120 +">
<input type="text" style="width: 130px;" placeholder="147.720 107.2" value="107.2 HZ">
<input type="text" style="flex: 1;" placeholder="Repeater - Supply Net" value="SUPPLY / LOGISTICS">
</div>
</div>
<button type="button" class="btn-now" id="btnAddChannel" style="margin-top: 6px; padding: 6px 12px; font-size: 0.8rem;">+ Add Channel Row</button>
</fieldset>
<fieldset>
<legend>4. PREPARED BY</legend>
<div class="row">
<div class="col"><label for="prepName">Prepared By (COML / Unit Leader)</label><input type="text" id="prepName" style="width: 100%;"></div>
<div class="col">
<div class="label-row">
<label for="prepDateTime">Date / Time Prepared</label>
<button type="button" class="btn-now" id="btn205Now">Current UTC</button>
</div>
<input type="text" id="prepDateTime" style="width: 100%;">
</div>
</div>
</fieldset>
<div class="actions">
<button type="button" class="main-btn btn-generate" id="btnGen">Generate Packet ASCII</button>
<button type="button" class="main-btn btn-save" id="btnSaveHtml" style="background:#5c6bc0; color:#fff;">Save as HTML</button>
<button type="button" class="main-btn btn-copy" id="btnCopy">Copy ASCII</button>
<button type="button" class="main-btn btn-clear" id="btnClear">Reset</button>
</div>
</form>
<label style="font-weight:bold;">Formatted ASCII for Packet Transmission:</label>
<pre id="outputPre">Fill in the fields above and click "Generate Packet ASCII"...</pre>
</div>
<script>
function addChannelRow() {
const container = document.getElementById('channelContainer');
const div = document.createElement('div');
div.className = 'channel-row';
div.innerHTML = '<input type="text" style="width: 75px;" placeholder="CH #">' +
'<input type="text" style="width: 140px;" placeholder="FUNCTION">' +
'<input type="text" style="width: 120px;" placeholder="CHANNEL NAME">' +
'<input type="text" style="width: 130px;" placeholder="RX FREQ / TONE">' +
'<input type="text" style="width: 130px;" placeholder="TX FREQ / TONE">' +
'<input type="text" style="flex: 1;" placeholder="MODE / REMARKS">';
container.appendChild(div);
}
function setUTC() {
const now = new Date();
const y = now.getUTCFullYear();
const m = String(now.getUTCMonth()+1).padStart(2,'0');
const d = String(now.getUTCDate()).padStart(2,'0');
const hh = String(now.getUTCHours()).padStart(2,'0');
const mm = String(now.getUTCMinutes()).padStart(2,'0');
document.getElementById('prepDateTime').value = y + '-' + m + '-' + d + ' ' + hh + ':' + mm + 'Z';
}
function clean(id) {
const el = document.getElementById(id);
return el ? (el.value || '').trim() : '';
}
function pad(str, len) {
str = (str || '').toString();
return str + ' '.repeat(Math.max(0, len - str.length));
}
function generateASCII() {
try {
const div = '='.repeat(78);
const sub = '-'.repeat(78);
const inc = clean('incName').toUpperCase() || 'N/A';
const op = clean('opPeriod').toUpperCase() || 'N/A';
const prep = clean('prepName').toUpperCase() || 'N/A';
const dt = clean('prepDateTime').toUpperCase() || 'N/A';
let lines = [];
const rows = document.querySelectorAll('.channel-row');
rows.forEach(function(r) {
const inputs = r.querySelectorAll('input');
const ch = pad((inputs[0].value || '').trim().toUpperCase(), 6);
const fn = pad((inputs[1].value || '').trim().toUpperCase(), 12);
const name = pad((inputs[2].value || '').trim().toUpperCase(), 11);
const rx = pad((inputs[3].value || '').trim().toUpperCase(), 13);
const tx = pad((inputs[4].value || '').trim().toUpperCase(), 13);
const rem = (inputs[5].value || '').trim().toUpperCase();
if (ch.trim() || fn.trim() || name.trim()) {
lines.push(ch + '| ' + fn + '| ' + name + '| ' + rx + '| ' + tx + '| ' + rem);
}
});
const out = div + '\n' +
'ICS 205 - RADIO COMMUNICATIONS PLAN (PACKET ASCII)\n' +
div + '\n' +
'INCIDENT NAME : ' + inc + '\n' +
'OP PERIOD : ' + op + '\n' +
sub + '\n' +
'CH # | FUNCTION | NAME | RX FREQ/TONE | TX FREQ/TONE | REMARKS\n' +
sub + '\n' +
lines.join('\n') + '\n' +
sub + '\n' +
'PREPARED BY : ' + prep + '\n' +
'DATE/TIME : ' + dt + '\n' +
div;
document.getElementById('outputPre').textContent = out;
} catch(err) {
alert("Error generating text: " + err.message);
}
}
function copyASCII() {
const txt = document.getElementById('outputPre').textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(function() {
alert("ICS-205 plan copied to clipboard!");
}).catch(function() {
fallbackCopy();
});
} else {
fallbackCopy();
}
}
function fallbackCopy() {
const pre = document.getElementById('outputPre');
const range = document.createRange();
range.selectNode(pre);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
alert("Copied to clipboard!");
}
function clearForm() {
if(confirm("Reset form?")) {
document.getElementById('ics205Form').reset();
document.getElementById('outputPre').textContent = 'Fill in the fields above and click "Generate Packet ASCII"...';
}
}
document.getElementById('btnAddChannel').addEventListener('click', addChannelRow);
document.getElementById('btn205Now').addEventListener('click', setUTC);
document.getElementById('btnGen').addEventListener('click', generateASCII);
document.getElementById('btnCopy').addEventListener('click', copyASCII);
document.getElementById('btnClear').addEventListener('click', clearForm);
});
});
const pre = document.getElementById('outputPre') || document.getElementById('outputArea');
if (pre) {
pre.textContent = pre.textContent;
}
const doctype = '<!DOCTYPE html>\n';
const htmlContent = doctype + document.documentElement.outerHTML;
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
const url = URL.createObjectURL(blob);
const btnSave = document.getElementById('btnSaveHtml');
if (btnSave) {
btnSave.addEventListener('click', openSaveModal);
}
// File Name Modal Window & HTML Exporter
function openSaveModal() {
var now = new Date();
var dStr = now.toISOString().slice(0, 10);
var defName = 'ics_205_' + dStr + '.html';
var modal = document.getElementById('saveModalBackdrop');
var input = document.getElementById('saveModalFileName');
if (input) input.value = defName;
if (modal) modal.classList.add('active');
setTimeout(function() {
if (input) { input.focus(); input.select(); }
}, 50);
}
function closeSaveModal() {
var modal = document.getElementById('saveModalBackdrop');
if (modal) modal.classList.remove('active');
}
function executeSaveHTML() {
var input = document.getElementById('saveModalFileName');
var chosenName = input ? input.value.trim() : '';
if (!chosenName) return;
if (!chosenName.toLowerCase().endsWith('.html') && !chosenName.toLowerCase().endsWith('.htm')) {
chosenName += '.html';
}
closeSaveModal();
document.querySelectorAll('input[type="text"]').forEach(function(el) { el.setAttribute('value', el.value); });
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(el) {
if (el.checked) el.setAttribute('checked', 'checked');
else el.removeAttribute('checked');
});
document.querySelectorAll('textarea').forEach(function(el) { el.textContent = el.value; });
document.querySelectorAll('select').forEach(function(el) {
Array.from(el.options).forEach(function(opt) {
if (opt.value === el.value) opt.setAttribute('selected', 'selected');
else opt.removeAttribute('selected');
});
});
var pre = document.getElementById('ascii-report') || document.getElementById('outputPre') || document.getElementById('preview') || document.getElementById('outputArea');
if (pre) pre.textContent = pre.textContent;
var clonedDoc = document.documentElement.cloneNode(true);
var modalInClone = clonedDoc.querySelector('#saveModalBackdrop');
if (modalInClone) modalInClone.classList.remove('active');
var htmlContent = '<!DOCTYPE html>\n' + clonedDoc.outerHTML;
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = chosenName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
window.addEventListener('DOMContentLoaded', function() {
var cancelBtn = document.getElementById('saveModalCancelBtn');
var confirmBtn = document.getElementById('saveModalSaveBtn');
var modalInput = document.getElementById('saveModalFileName');
var modalBackdrop = document.getElementById('saveModalBackdrop');
if (cancelBtn) cancelBtn.addEventListener('click', closeSaveModal);
if (confirmBtn) confirmBtn.addEventListener('click', executeSaveHTML);
if (modalInput) {
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); executeSaveHTML(); }
if (e.key === 'Escape') { e.preventDefault(); closeSaveModal(); }
});
}
if (modalBackdrop) {
modalBackdrop.addEventListener('click', function(e) {
if (e.target === modalBackdrop) closeSaveModal();
});
}
var btnSaveMain = document.getElementById('btnSaveHtml');
if (btnSaveMain) {
// Clear existing inline handlers just in case
btnSaveMain.onclick = null;
btnSaveMain.addEventListener('click', openSaveModal);
}
});
</script>
<!-- Custom File Name Modal Window -->
<div id="saveModalBackdrop" class="save-modal-backdrop">
<div class="save-modal-window">
<h3>Save Form as HTML</h3>
<p>Enter a name for the saved offline HTML file:</p>
<input type="text" id="saveModalFileName" spellcheck="false">
<div class="save-modal-actions">
<button type="button" class="save-modal-btn save-modal-btn-cancel" id="saveModalCancelBtn">Cancel</button>
<button type="button" class="save-modal-btn save-modal-btn-confirm" id="saveModalSaveBtn">Save File</button>
</div>
</div>
</div>
</body>
</html>
+405
View File
@@ -0,0 +1,405 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ICS 213 - General Message (Packet Radio)</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #eef2f5; color: #222; padding: 20px; margin: 0; }
.container { max-width: 860px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #2f5496; color: white; padding: 12px; border-radius: 6px; text-align: center; margin-bottom: 18px; }
.header h2 { margin: 0; font-size: 1.3rem; letter-spacing: 1px; }
.header p { margin: 4px 0 0 0; font-size: 0.85rem; opacity: 0.9; }
fieldset { border: 1px solid #b4c6e7; border-radius: 6px; padding: 14px; margin-bottom: 14px; background: #fafcff; }
legend { font-weight: bold; padding: 0 8px; font-size: 0.85rem; color: #1f3864; }
.row { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 10px; }
.col { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
label { font-size: 0.8rem; font-weight: 600; color: #333; }
input[type="text"], textarea, select { padding: 7px 8px; font-size: 0.9rem; border: 1px solid #999; border-radius: 4px; font-family: inherit; width: 100%; }
textarea { resize: vertical; min-height: 80px; }
.btn-now { background: #4a5568; color: #fff; padding: 4px 8px; font-size: 0.72rem; border-radius: 4px; border: none; cursor: pointer; }
.btn-now:hover { background: #2d3748; }
.actions { display: flex; gap: 10px; margin: 18px 0; }
button.main-btn { flex: 1; padding: 12px; font-size: 0.95rem; font-weight: bold; border: none; border-radius: 6px; cursor: pointer; }
.btn-generate { background: #2f5496; color: #fff; }
.btn-generate:hover { background: #1f3864; }
.btn-copy { background: #2e7d32; color: #fff; }
.btn-copy:hover { background: #1b5e20; }
.btn-clear { background: #c62828; color: #fff; flex: 0.4; }
.btn-clear:hover { background: #8e0000; }
pre { background: #181c20; color: #39ff14; padding: 14px; border-radius: 6px; overflow-x: auto; font-family: "Courier New", Courier, monospace; font-size: 0.85rem; line-height: 1.35; min-height: 150px; }
.nav-bar { margin-bottom: 12px; font-size: 0.85rem; }
.nav-bar a { color: #2f5496; text-decoration: none; font-weight: bold; }
/* Modal Save Dialog Window */
.save-modal-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.55); z-index: 99999; justify-content: center; align-items: center;
}
.save-modal-backdrop.active { display: flex; }
.save-modal-window {
background: #ffffff; padding: 24px 28px; border-radius: 10px; width: 92%; max-width: 480px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 1px solid #cbd5e1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.save-modal-window h3 { margin: 0 0 8px 0; font-size: 1.25rem; color: #1e293b; font-weight: bold; }
.save-modal-window p { margin: 0 0 16px 0; font-size: 0.88rem; color: #64748b; line-height: 1.4; }
.save-modal-window input[type="text"] {
width: 100%; padding: 10px 12px; font-size: 0.95rem; border: 2px solid #94a3b8; border-radius: 6px;
margin-bottom: 20px; font-family: inherit; box-sizing: border-box; text-transform: none;
}
.save-modal-window input[type="text"]:focus { border-color: #2563eb; outline: none; }
.save-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.save-modal-btn { padding: 9px 18px; font-size: 0.9rem; font-weight: bold; border-radius: 6px; border: none; cursor: pointer; }
.save-modal-btn-confirm { background: #2563eb; color: #ffffff; }
.save-modal-btn-confirm:hover { background: #1d4ed8; }
.save-modal-btn-cancel { background: #e2e8f0; color: #334155; }
.save-modal-btn-cancel:hover { background: #cbd5e1; }
</style>
</head>
<body>
<div class="container">
<div class="nav-bar"><a href="../index.html">&larr; Back to Packet Forms Hub</a></div>
<div class="header">
<h2>ICS 213 - GENERAL MESSAGE</h2>
<p>Winlink / Packet Radio ASCII Transmit Form</p>
</div>
<form id="icsForm" onsubmit="event.preventDefault(); return false;">
<fieldset>
<legend>INCIDENT HEADER</legend>
<div class="row">
<div class="col" style="flex: 2;"><label for="incName">1. Incident Name</label><input type="text" id="incName"></div>
<div class="col"><label for="msgNum">Message #</label><input type="text" id="msgNum" placeholder="e.g. 001"></div>
<div class="col"><label for="precedence">Precedence</label>
<select id="precedence">
<option value="ROUTINE">ROUTINE</option>
<option value="PRIORITY">PRIORITY</option>
<option value="EMERGENCY">EMERGENCY</option>
</select>
</div>
</div>
<div class="row">
<div class="col">
<div class="label-row">
<label for="dateFiled">Date Filed</label>
<button type="button" class="btn-now" id="btnICSNow">Current UTC</button>
</div>
<input type="text" id="dateFiled" placeholder="YYYY-MM-DD">
</div>
<div class="col">
<div class="label-row">
<label for="timeFiled">Time Filed (UTC)</label>
</div>
<input type="text" id="timeFiled" placeholder="HHMMZ">
</div>
</div>
</fieldset>
<fieldset>
<legend>RECIPIENT & SENDER</legend>
<div class="row">
<div class="col"><label for="toNamePos">2. To (Name and Position)</label><input type="text" id="toNamePos"></div>
<div class="col"><label for="toAgency">Agency / Organization</label><input type="text" id="toAgency"></div>
</div>
<div class="row">
<div class="col"><label for="fromNamePos">3. From (Name and Position)</label><input type="text" id="fromNamePos"></div>
<div class="col"><label for="fromAgency">Agency / Callsign</label><input type="text" id="fromAgency"></div>
</div>
<div class="row">
<div class="col"><label for="subject">4. Subject</label><input type="text" id="subject"></div>
</div>
</fieldset>
<fieldset>
<legend>5. MESSAGE TEXT</legend>
<textarea id="messageBody" rows="6" placeholder="Enter message text... Keep clear, brief, and uppercase for packet reliability."></textarea>
</fieldset>
<fieldset>
<legend>6. APPROVAL / OPERATOR</legend>
<div class="row">
<div class="col"><label for="apprName">Approved By (Name)</label><input type="text" id="apprName"></div>
<div class="col"><label for="apprPos">Title / Position</label><input type="text" id="apprPos"></div>
<div class="col"><label for="opCall">Radio Operator Callsign</label><input type="text" id="opCall"></div>
</div>
</fieldset>
<fieldset>
<legend>7. REPLY (Optional)</legend>
<textarea id="replyBody" rows="3" placeholder="Enter reply if this is a message response..."></textarea>
<div class="row" style="margin-top: 8px;">
<div class="col"><label for="repBy">Replied By (Name / Position)</label><input type="text" id="repBy"></div>
<div class="col"><label for="repDateTime">Reply Date/Time</label><input type="text" id="repDateTime"></div>
</div>
</fieldset>
<div class="actions">
<button type="button" class="main-btn btn-generate" id="btnGen">Generate Packet ASCII</button>
<button type="button" class="main-btn btn-save" id="btnSaveHtml" style="background:#5c6bc0; color:#fff;">Save as HTML</button>
<button type="button" class="main-btn btn-copy" id="btnCopy">Copy ASCII</button>
<button type="button" class="main-btn btn-clear" id="btnClear">Reset</button>
</div>
</form>
<label style="font-weight:bold;">Formatted ASCII for Packet / Winlink / BBS Terminal:</label>
<pre id="outputPre">Fill in the fields above and click "Generate Packet ASCII"...</pre>
</div>
<script>
function setUTC() {
const now = new Date();
const y = now.getUTCFullYear();
const m = String(now.getUTCMonth()+1).padStart(2,'0');
const d = String(now.getUTCDate()).padStart(2,'0');
const hh = String(now.getUTCHours()).padStart(2,'0');
const mm = String(now.getUTCMinutes()).padStart(2,'0');
document.getElementById('dateFiled').value = y + '-' + m + '-' + d;
document.getElementById('timeFiled').value = hh + mm + 'Z';
}
function clean(id) {
const el = document.getElementById(id);
return el ? (el.value || '').trim() : '';
}
function wrapText(str, width) {
if (!str) return [];
let lines = [];
str.split('\n').forEach(function(paragraph) {
let words = paragraph.split(' ');
let cur = '';
words.forEach(function(w) {
if ((cur + (cur ? ' ' : '') + w).length <= width) {
cur += (cur ? ' ' : '') + w;
} else {
if (cur) lines.push(cur);
cur = w;
}
});
if (cur) lines.push(cur);
});
return lines;
}
function generateASCII() {
try {
const div = '='.repeat(74);
const sub = '-'.repeat(74);
const inc = clean('incName').toUpperCase();
const num = clean('msgNum').toUpperCase();
const prec = clean('precedence').toUpperCase();
const d = clean('dateFiled');
const t = clean('timeFiled');
const toName = clean('toNamePos').toUpperCase();
const toAg = clean('toAgency').toUpperCase();
const fromName = clean('fromNamePos').toUpperCase();
const fromAg = clean('fromAgency').toUpperCase();
const subj = clean('subject').toUpperCase();
const body = clean('messageBody').toUpperCase();
const apprN = clean('apprName').toUpperCase();
const apprP = clean('apprPos').toUpperCase();
const op = clean('opCall').toUpperCase();
const rep = clean('replyBody').toUpperCase();
const repBy = clean('repBy').toUpperCase();
const repDT = clean('repDateTime').toUpperCase();
let wrappedMsg = wrapText(body, 70).map(function(l) { return ' ' + l; }).join('\n') || ' (NONE)';
let wrappedRep = rep ? wrapText(rep, 70).map(function(l) { return ' ' + l; }).join('\n') : '';
let out = div + '\n' +
'ICS 213 - GENERAL MESSAGE (PACKET / WINLINK)\n' +
div + '\n' +
'INCIDENT NAME : ' + (inc || 'N/A') + '\n' +
'MSG NUMBER : ' + (num || 'N/A') + ' PRECEDENCE : ' + prec + '\n' +
'DATE FILED : ' + (d || 'N/A') + ' TIME FILED : ' + (t || 'N/A') + '\n' +
sub + '\n' +
'TO : ' + toName + ' | ' + toAg + '\n' +
'FROM : ' + fromName + ' | ' + fromAg + '\n' +
'SUBJECT : ' + subj + '\n' +
sub + '\n' +
'MESSAGE TEXT:\n' +
wrappedMsg + '\n' +
sub + '\n' +
'APPROVED BY : ' + apprN + ' (' + apprP + ')\n' +
'OPERATOR / CALL: ' + (op || 'N/A') + '\n' +
div;
if (rep) {
out += '\nREPLY:\n' + wrappedRep + '\n' +
'REPLIED BY : ' + repBy + '\n' +
'REPLY DATE/TIME: ' + repDT + '\n' +
div;
}
document.getElementById('outputPre').textContent = out;
} catch(err) {
alert("Error generating text: " + err.message);
}
}
function copyASCII() {
const txt = document.getElementById('outputPre').textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(function() {
alert("ICS-213 message copied to clipboard!");
}).catch(function() {
fallbackCopy();
});
} else {
fallbackCopy();
}
}
function fallbackCopy() {
const pre = document.getElementById('outputPre');
const range = document.createRange();
range.selectNode(pre);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
alert("Copied to clipboard!");
}
function clearForm() {
if(confirm("Reset all fields?")) {
document.getElementById('icsForm').reset();
document.getElementById('outputPre').textContent = 'Fill in the fields above and click "Generate Packet ASCII"...';
}
}
document.getElementById('btnICSNow').addEventListener('click', setUTC);
document.getElementById('btnGen').addEventListener('click', generateASCII);
document.getElementById('btnCopy').addEventListener('click', copyASCII);
document.getElementById('btnClear').addEventListener('click', clearForm);
});
});
const pre = document.getElementById('outputPre') || document.getElementById('outputArea');
if (pre) {
pre.textContent = pre.textContent;
}
const doctype = '<!DOCTYPE html>\n';
const htmlContent = doctype + document.documentElement.outerHTML;
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
const url = URL.createObjectURL(blob);
const btnSave = document.getElementById('btnSaveHtml');
if (btnSave) {
btnSave.addEventListener('click', openSaveModal);
}
// File Name Modal Window & HTML Exporter
function openSaveModal() {
var now = new Date();
var dStr = now.toISOString().slice(0, 10);
var defName = 'ics_213_' + dStr + '.html';
var modal = document.getElementById('saveModalBackdrop');
var input = document.getElementById('saveModalFileName');
if (input) input.value = defName;
if (modal) modal.classList.add('active');
setTimeout(function() {
if (input) { input.focus(); input.select(); }
}, 50);
}
function closeSaveModal() {
var modal = document.getElementById('saveModalBackdrop');
if (modal) modal.classList.remove('active');
}
function executeSaveHTML() {
var input = document.getElementById('saveModalFileName');
var chosenName = input ? input.value.trim() : '';
if (!chosenName) return;
if (!chosenName.toLowerCase().endsWith('.html') && !chosenName.toLowerCase().endsWith('.htm')) {
chosenName += '.html';
}
closeSaveModal();
document.querySelectorAll('input[type="text"]').forEach(function(el) { el.setAttribute('value', el.value); });
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(el) {
if (el.checked) el.setAttribute('checked', 'checked');
else el.removeAttribute('checked');
});
document.querySelectorAll('textarea').forEach(function(el) { el.textContent = el.value; });
document.querySelectorAll('select').forEach(function(el) {
Array.from(el.options).forEach(function(opt) {
if (opt.value === el.value) opt.setAttribute('selected', 'selected');
else opt.removeAttribute('selected');
});
});
var pre = document.getElementById('ascii-report') || document.getElementById('outputPre') || document.getElementById('preview') || document.getElementById('outputArea');
if (pre) pre.textContent = pre.textContent;
var clonedDoc = document.documentElement.cloneNode(true);
var modalInClone = clonedDoc.querySelector('#saveModalBackdrop');
if (modalInClone) modalInClone.classList.remove('active');
var htmlContent = '<!DOCTYPE html>\n' + clonedDoc.outerHTML;
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = chosenName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
window.addEventListener('DOMContentLoaded', function() {
var cancelBtn = document.getElementById('saveModalCancelBtn');
var confirmBtn = document.getElementById('saveModalSaveBtn');
var modalInput = document.getElementById('saveModalFileName');
var modalBackdrop = document.getElementById('saveModalBackdrop');
if (cancelBtn) cancelBtn.addEventListener('click', closeSaveModal);
if (confirmBtn) confirmBtn.addEventListener('click', executeSaveHTML);
if (modalInput) {
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); executeSaveHTML(); }
if (e.key === 'Escape') { e.preventDefault(); closeSaveModal(); }
});
}
if (modalBackdrop) {
modalBackdrop.addEventListener('click', function(e) {
if (e.target === modalBackdrop) closeSaveModal();
});
}
var btnSaveMain = document.getElementById('btnSaveHtml');
if (btnSaveMain) {
// Clear existing inline handlers just in case
btnSaveMain.onclick = null;
btnSaveMain.addEventListener('click', openSaveModal);
}
});
</script>
<!-- Custom File Name Modal Window -->
<div id="saveModalBackdrop" class="save-modal-backdrop">
<div class="save-modal-window">
<h3>Save Form as HTML</h3>
<p>Enter a name for the saved offline HTML file:</p>
<input type="text" id="saveModalFileName" spellcheck="false">
<div class="save-modal-actions">
<button type="button" class="save-modal-btn save-modal-btn-cancel" id="saveModalCancelBtn">Cancel</button>
<button type="button" class="save-modal-btn save-modal-btn-confirm" id="saveModalSaveBtn">Save File</button>
</div>
</div>
</div>
</body>
</html>
+362
View File
@@ -0,0 +1,362 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ICS 214 - Activity Log (Packet Radio)</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #fdfaf6; color: #222; padding: 20px; margin: 0; }
.container { max-width: 880px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #b25900; color: white; padding: 12px; border-radius: 6px; text-align: center; margin-bottom: 18px; }
.header h2 { margin: 0; font-size: 1.3rem; letter-spacing: 1px; }
.header p { margin: 4px 0 0 0; font-size: 0.85rem; opacity: 0.9; }
fieldset { border: 1px solid #fed8b1; border-radius: 6px; padding: 14px; margin-bottom: 14px; background: #fffdf9; }
legend { font-weight: bold; padding: 0 8px; font-size: 0.85rem; color: #803d00; }
.row { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 10px; }
.col { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
label { font-size: 0.8rem; font-weight: 600; color: #333; }
input[type="text"], textarea { padding: 7px 8px; font-size: 0.9rem; border: 1px solid #999; border-radius: 4px; font-family: inherit; width: 100%; }
.btn-now { background: #555; color: #fff; padding: 4px 8px; font-size: 0.72rem; border-radius: 4px; border: none; cursor: pointer; }
.btn-now:hover { background: #333; }
.actions { display: flex; gap: 10px; margin: 18px 0; }
button.main-btn { flex: 1; padding: 12px; font-size: 0.95rem; font-weight: bold; border: none; border-radius: 6px; cursor: pointer; }
.btn-generate { background: #b25900; color: #fff; }
.btn-generate:hover { background: #803d00; }
.btn-copy { background: #2e7d32; color: #fff; }
.btn-copy:hover { background: #1b5e20; }
.btn-clear { background: #c62828; color: #fff; flex: 0.4; }
pre { background: #181c20; color: #39ff14; padding: 14px; border-radius: 6px; overflow-x: auto; font-family: "Courier New", Courier, monospace; font-size: 0.85rem; line-height: 1.35; min-height: 150px; }
.log-entry { display: flex; gap: 10px; margin-bottom: 8px; align-items: center; }
.log-time { width: 110px !important; }
.log-desc { flex: 1; }
.nav-bar { margin-bottom: 12px; font-size: 0.85rem; }
.nav-bar a { color: #b25900; text-decoration: none; font-weight: bold; }
/* Modal Save Dialog Window */
.save-modal-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.55); z-index: 99999; justify-content: center; align-items: center;
}
.save-modal-backdrop.active { display: flex; }
.save-modal-window {
background: #ffffff; padding: 24px 28px; border-radius: 10px; width: 92%; max-width: 480px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 1px solid #cbd5e1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.save-modal-window h3 { margin: 0 0 8px 0; font-size: 1.25rem; color: #1e293b; font-weight: bold; }
.save-modal-window p { margin: 0 0 16px 0; font-size: 0.88rem; color: #64748b; line-height: 1.4; }
.save-modal-window input[type="text"] {
width: 100%; padding: 10px 12px; font-size: 0.95rem; border: 2px solid #94a3b8; border-radius: 6px;
margin-bottom: 20px; font-family: inherit; box-sizing: border-box; text-transform: none;
}
.save-modal-window input[type="text"]:focus { border-color: #2563eb; outline: none; }
.save-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.save-modal-btn { padding: 9px 18px; font-size: 0.9rem; font-weight: bold; border-radius: 6px; border: none; cursor: pointer; }
.save-modal-btn-confirm { background: #2563eb; color: #ffffff; }
.save-modal-btn-confirm:hover { background: #1d4ed8; }
.save-modal-btn-cancel { background: #e2e8f0; color: #334155; }
.save-modal-btn-cancel:hover { background: #cbd5e1; }
</style>
</head>
<body>
<div class="container">
<div class="nav-bar"><a href="../index.html">&larr; Back to Packet Forms Hub</a></div>
<div class="header">
<h2>ICS 214 - ACTIVITY LOG</h2>
<p>Unit / Individual Station Activity Log (Packet ASCII)</p>
</div>
<form id="ics214Form" onsubmit="event.preventDefault(); return false;">
<fieldset>
<legend>INCIDENT & UNIT HEADER</legend>
<div class="row">
<div class="col" style="flex: 2;"><label for="incName">1. Incident Name</label><input type="text" id="incName"></div>
<div class="col"><label for="opPeriod">2. Operational Period</label><input type="text" id="opPeriod" placeholder="e.g. OP-1 0700-1900"></div>
</div>
<div class="row">
<div class="col"><label for="stationCall">3. Name / Station Callsign</label><input type="text" id="stationCall"></div>
<div class="col"><label for="icsPos">4. ICS Position / Tactical</label><input type="text" id="icsPos" placeholder="e.g. STAGING COMM / SHELTER NET"></div>
<div class="col"><label for="agency">5. Agency / Home Org</label><input type="text" id="agency" placeholder="ARES / OEM"></div>
</div>
</fieldset>
<fieldset>
<legend>6. LOG ENTRIES (Time UTC & Major Event / Notable Activity)</legend>
<div id="logEntries">
<div class="log-entry"><input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary..."></div>
<div class="log-entry"><input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary..."></div>
<div class="log-entry"><input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary..."></div>
<div class="log-entry"><input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary..."></div>
<div class="log-entry"><input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary..."></div>
</div>
<button type="button" class="btn-now" id="btnAddRow" style="margin-top: 6px; padding: 6px 12px; font-size: 0.8rem;">+ Add Log Entry Row</button>
</fieldset>
<fieldset>
<legend>7. PREPARED BY</legend>
<div class="row">
<div class="col"><label for="prepName">Prepared By (Name & Title)</label><input type="text" id="prepName"></div>
<div class="col">
<div class="label-row">
<label for="prepDateTime">Date / Time Prepared</label>
<button type="button" class="btn-now" id="btn214Now">Current UTC</button>
</div>
<input type="text" id="prepDateTime">
</div>
</div>
</fieldset>
<div class="actions">
<button type="button" class="main-btn btn-generate" id="btnGen">Generate Packet ASCII</button>
<button type="button" class="main-btn btn-save" id="btnSaveHtml" style="background:#5c6bc0; color:#fff;">Save as HTML</button>
<button type="button" class="main-btn btn-copy" id="btnCopy">Copy ASCII</button>
<button type="button" class="main-btn btn-clear" id="btnClear">Reset</button>
</div>
</form>
<label style="font-weight:bold;">Formatted ASCII for Packet / BBS Transmission:</label>
<pre id="outputPre">Fill in the fields above and click "Generate Packet ASCII"...</pre>
</div>
<script>
function addLogRow() {
const container = document.getElementById('logEntries');
const div = document.createElement('div');
div.className = 'log-entry';
div.innerHTML = '<input type="text" class="log-time" placeholder="TIME (UTC)"><input type="text" class="log-desc" placeholder="Notable event / activity summary...">';
container.appendChild(div);
}
function setUTC() {
const now = new Date();
const y = now.getUTCFullYear();
const m = String(now.getUTCMonth()+1).padStart(2,'0');
const d = String(now.getUTCDate()).padStart(2,'0');
const hh = String(now.getUTCHours()).padStart(2,'0');
const mm = String(now.getUTCMinutes()).padStart(2,'0');
document.getElementById('prepDateTime').value = y + '-' + m + '-' + d + ' ' + hh + ':' + mm + 'Z';
}
function clean(id) {
const el = document.getElementById(id);
return el ? (el.value || '').trim() : '';
}
function pad(str, len) {
str = (str || '').toString();
return str + ' '.repeat(Math.max(0, len - str.length));
}
function generateASCII() {
try {
const div = '='.repeat(74);
const sub = '-'.repeat(74);
const inc = clean('incName').toUpperCase() || 'N/A';
const op = clean('opPeriod').toUpperCase() || 'N/A';
const call = clean('stationCall').toUpperCase() || 'N/A';
const pos = clean('icsPos').toUpperCase() || 'N/A';
const ag = clean('agency').toUpperCase() || 'N/A';
const prep = clean('prepName').toUpperCase() || 'N/A';
const prepDT = clean('prepDateTime').toUpperCase() || 'N/A';
let entries = [];
const rows = document.querySelectorAll('.log-entry');
rows.forEach(function(r) {
const t = (r.querySelector('.log-time').value || '').trim().toUpperCase();
const d = (r.querySelector('.log-desc').value || '').trim().toUpperCase();
if (t || d) {
entries.push(pad(t, 8) + ' | ' + d);
}
});
if (entries.length === 0) entries.push(' NO LOG ENTRIES RECORDED');
const out = div + '\n' +
'ICS 214 - ACTIVITY LOG (PACKET ASCII)\n' +
div + '\n' +
'INCIDENT NAME : ' + inc + '\n' +
'OP PERIOD : ' + op + '\n' +
'NAME / CALL : ' + call + '\n' +
'ICS POSITION : ' + pos + '\n' +
'AGENCY / ORG : ' + ag + '\n' +
sub + '\n' +
'TIME (Z) | MAJOR ACTIVITIES & EVENTS\n' +
sub + '\n' +
entries.join('\n') + '\n' +
sub + '\n' +
'PREPARED BY : ' + prep + '\n' +
'DATE/TIME : ' + prepDT + '\n' +
div;
document.getElementById('outputPre').textContent = out;
} catch(err) {
alert("Error generating text: " + err.message);
}
}
function copyASCII() {
const txt = document.getElementById('outputPre').textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(function() {
alert("Activity Log copied to clipboard!");
}).catch(function() {
fallbackCopy();
});
} else {
fallbackCopy();
}
}
function fallbackCopy() {
const pre = document.getElementById('outputPre');
const range = document.createRange();
range.selectNode(pre);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
alert("Copied to clipboard!");
}
function clearForm() {
if(confirm("Reset form?")) {
document.getElementById('ics214Form').reset();
document.getElementById('outputPre').textContent = 'Fill in the fields above and click "Generate Packet ASCII"...';
}
}
document.getElementById('btnAddRow').addEventListener('click', addLogRow);
document.getElementById('btn214Now').addEventListener('click', setUTC);
document.getElementById('btnGen').addEventListener('click', generateASCII);
document.getElementById('btnCopy').addEventListener('click', copyASCII);
document.getElementById('btnClear').addEventListener('click', clearForm);
});
});
const pre = document.getElementById('outputPre') || document.getElementById('outputArea');
if (pre) {
pre.textContent = pre.textContent;
}
const doctype = '<!DOCTYPE html>\n';
const htmlContent = doctype + document.documentElement.outerHTML;
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
const url = URL.createObjectURL(blob);
const btnSave = document.getElementById('btnSaveHtml');
if (btnSave) {
btnSave.addEventListener('click', openSaveModal);
}
// File Name Modal Window & HTML Exporter
function openSaveModal() {
var now = new Date();
var dStr = now.toISOString().slice(0, 10);
var defName = 'ics_214_' + dStr + '.html';
var modal = document.getElementById('saveModalBackdrop');
var input = document.getElementById('saveModalFileName');
if (input) input.value = defName;
if (modal) modal.classList.add('active');
setTimeout(function() {
if (input) { input.focus(); input.select(); }
}, 50);
}
function closeSaveModal() {
var modal = document.getElementById('saveModalBackdrop');
if (modal) modal.classList.remove('active');
}
function executeSaveHTML() {
var input = document.getElementById('saveModalFileName');
var chosenName = input ? input.value.trim() : '';
if (!chosenName) return;
if (!chosenName.toLowerCase().endsWith('.html') && !chosenName.toLowerCase().endsWith('.htm')) {
chosenName += '.html';
}
closeSaveModal();
document.querySelectorAll('input[type="text"]').forEach(function(el) { el.setAttribute('value', el.value); });
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(el) {
if (el.checked) el.setAttribute('checked', 'checked');
else el.removeAttribute('checked');
});
document.querySelectorAll('textarea').forEach(function(el) { el.textContent = el.value; });
document.querySelectorAll('select').forEach(function(el) {
Array.from(el.options).forEach(function(opt) {
if (opt.value === el.value) opt.setAttribute('selected', 'selected');
else opt.removeAttribute('selected');
});
});
var pre = document.getElementById('ascii-report') || document.getElementById('outputPre') || document.getElementById('preview') || document.getElementById('outputArea');
if (pre) pre.textContent = pre.textContent;
var clonedDoc = document.documentElement.cloneNode(true);
var modalInClone = clonedDoc.querySelector('#saveModalBackdrop');
if (modalInClone) modalInClone.classList.remove('active');
var htmlContent = '<!DOCTYPE html>\n' + clonedDoc.outerHTML;
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = chosenName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
window.addEventListener('DOMContentLoaded', function() {
var cancelBtn = document.getElementById('saveModalCancelBtn');
var confirmBtn = document.getElementById('saveModalSaveBtn');
var modalInput = document.getElementById('saveModalFileName');
var modalBackdrop = document.getElementById('saveModalBackdrop');
if (cancelBtn) cancelBtn.addEventListener('click', closeSaveModal);
if (confirmBtn) confirmBtn.addEventListener('click', executeSaveHTML);
if (modalInput) {
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); executeSaveHTML(); }
if (e.key === 'Escape') { e.preventDefault(); closeSaveModal(); }
});
}
if (modalBackdrop) {
modalBackdrop.addEventListener('click', function(e) {
if (e.target === modalBackdrop) closeSaveModal();
});
}
var btnSaveMain = document.getElementById('btnSaveHtml');
if (btnSaveMain) {
// Clear existing inline handlers just in case
btnSaveMain.onclick = null;
btnSaveMain.addEventListener('click', openSaveModal);
}
});
</script>
<!-- Custom File Name Modal Window -->
<div id="saveModalBackdrop" class="save-modal-backdrop">
<div class="save-modal-window">
<h3>Save Form as HTML</h3>
<p>Enter a name for the saved offline HTML file:</p>
<input type="text" id="saveModalFileName" spellcheck="false">
<div class="save-modal-actions">
<button type="button" class="save-modal-btn save-modal-btn-cancel" id="saveModalCancelBtn">Cancel</button>
<button type="button" class="save-modal-btn save-modal-btn-confirm" id="saveModalSaveBtn">Save File</button>
</div>
</div>
</div>
</body>
</html>
+472
View File
@@ -0,0 +1,472 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Incident Status Report (Packet Radio)</title>
<style>
* { box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace; background: #eef2f7; color: #222; padding: 20px; margin: 0; }
.container { max-width: 960px; margin: 0 auto; background: #fff; padding: 24px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #1a237e; color: white; padding: 12px; border-radius: 6px; text-align: center; margin-bottom: 18px; }
.header h2 { margin: 0; font-size: 1.3rem; letter-spacing: 1px; }
.header p { margin: 4px 0 0 0; font-size: 0.85rem; opacity: 0.9; }
fieldset { border: 1px solid #c5cae9; border-radius: 6px; padding: 14px; margin-bottom: 14px; background: #fafbff; }
legend { font-weight: bold; padding: 0 8px; font-size: 0.85rem; color: #1a237e; }
.row { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 10px; }
.col { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.label-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
label { font-size: 0.8rem; font-weight: 600; color: #333; }
input[type="text"], select, textarea { padding: 7px 8px; font-size: 0.88rem; border: 1px solid #999; border-radius: 4px; font-family: inherit; width: 100%; }
textarea { resize: vertical; min-height: 70px; }
.checkbox-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; font-size: 0.85rem; margin-top: 4px; }
.btn-now { background: #4a5568; color: #fff; padding: 4px 8px; font-size: 0.72rem; border-radius: 4px; border: none; cursor: pointer; }
.btn-now:hover { background: #2d3748; }
.actions { display: flex; gap: 10px; margin: 18px 0; }
button.main-btn { flex: 1; padding: 12px; font-size: 0.95rem; font-weight: bold; border: none; border-radius: 6px; cursor: pointer; }
.btn-generate { background: #1a237e; color: #fff; }
.btn-generate:hover { background: #0d1642; }
.btn-save { background: #5c6bc0; color: #fff; }
.btn-save:hover { background: #3f51b5; }
.btn-copy { background: #2e7d32; color: #fff; }
.btn-copy:hover { background: #1b5e20; }
.btn-clear { background: #555; color: #fff; flex: 0.35; }
.btn-clear:hover { background: #333; }
pre { background: #181c20; color: #39ff14; padding: 14px; border-radius: 6px; overflow-x: auto; font-family: "Courier New", Courier, monospace; font-size: 0.82rem; line-height: 1.32; min-height: 150px; }
.nav-bar { margin-bottom: 12px; font-size: 0.85rem; }
.nav-bar a { color: #1a237e; text-decoration: none; font-weight: bold; }
/* Modal Save Dialog Window */
.save-modal-backdrop {
display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.55); z-index: 99999; justify-content: center; align-items: center;
}
.save-modal-backdrop.active { display: flex; }
.save-modal-window {
background: #ffffff; padding: 24px 28px; border-radius: 10px; width: 92%; max-width: 480px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); border: 1px solid #cbd5e1; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.save-modal-window h3 { margin: 0 0 8px 0; font-size: 1.25rem; color: #1e293b; font-weight: bold; }
.save-modal-window p { margin: 0 0 16px 0; font-size: 0.88rem; color: #64748b; line-height: 1.4; }
.save-modal-window input[type="text"] {
width: 100%; padding: 10px 12px; font-size: 0.95rem; border: 2px solid #94a3b8; border-radius: 6px;
margin-bottom: 20px; font-family: inherit; box-sizing: border-box; text-transform: none;
}
.save-modal-window input[type="text"]:focus { border-color: #2563eb; outline: none; }
.save-modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.save-modal-btn { padding: 9px 18px; font-size: 0.9rem; font-weight: bold; border-radius: 6px; border: none; cursor: pointer; }
.save-modal-btn-confirm { background: #2563eb; color: #ffffff; }
.save-modal-btn-confirm:hover { background: #1d4ed8; }
.save-modal-btn-cancel { background: #e2e8f0; color: #334155; }
.save-modal-btn-cancel:hover { background: #cbd5e1; }
</style>
</head>
<body>
<div class="container">
<div class="nav-bar"><a href="../index.html">&larr; Back to Packet Forms Hub</a></div>
<div class="header">
<h2>INCIDENT STATUS REPORT</h2>
<p>Winlink Standard Emergency Operations Overview (Packet ASCII)</p>
</div>
<form id="statusForm" onsubmit="event.preventDefault(); return false;">
<fieldset>
<legend>1-4. INCIDENT IDENTIFICATION & REPORT VERSION</legend>
<div class="row">
<div class="col" style="flex: 2;"><label for="incName">1. Incident Name</label><input type="text" id="incName" placeholder="e.g. TRAVIS COUNTY FLOOD"></div>
<div class="col"><label for="webEOC">2. WebEOC Incident #</label><input type="text" id="webEOC" placeholder="e.g. EOC-2026-088"></div>
</div>
<div class="row">
<div class="col">
<div class="label-row">
<label for="incDT">3. Incident Date / Time</label>
<button type="button" class="btn-now" id="btnIncDT">Current UTC</button>
</div>
<input type="text" id="incDT" placeholder="YYYY-MM-DD HHMMZ">
</div>
<div class="col">
<label for="repVersion">4. Report Version</label>
<select id="repVersion">
<option value="INITIAL">INITIAL</option>
<option value="UPDATE">UPDATE</option>
<option value="FINAL">FINAL</option>
</select>
</div>
</div>
</fieldset>
<fieldset>
<legend>5. TYPE OF INCIDENT (Check all that apply)</legend>
<div class="checkbox-grid">
<label><input type="checkbox" id="t_storm" value="Severe Storm/Flood"> Severe Storm / Flood</label>
<label><input type="checkbox" id="t_event" value="Pre-Planned Event"> Pre-Planned Event</label>
<label><input type="checkbox" id="t_hazmat" value="HAZMAT"> HAZMAT</label>
<label><input type="checkbox" id="t_winter" value="Severe Winter Weather"> Severe Winter Weather</label>
<label><input type="checkbox" id="t_dam" value="Dam/Levee"> Dam / Levee</label>
<label><input type="checkbox" id="t_util" value="Utility Disruption"> Utility Disruption</label>
<label><input type="checkbox" id="t_health" value="Public Health"> Public Health</label>
<label><input type="checkbox" id="t_civil" value="Civil Disturbance"> Civil Disturbance</label>
<label><input type="checkbox" id="t_quake" value="Earthquake"> Earthquake</label>
<label><input type="checkbox" id="t_fire" value="Fire"> Fire</label>
<label><input type="checkbox" id="t_air" value="Aircraft Disaster"> Aircraft Disaster</label>
<label><input type="checkbox" id="t_other_chk" value="Other"> Other (Specify below)</label>
</div>
<div class="row" style="margin-top: 8px;">
<div class="col"><input type="text" id="t_other_txt" placeholder="Specify if 'Other' selected"></div>
</div>
</fieldset>
<fieldset>
<legend>6-7. SITUATION & FUTURE OUTLOOK</legend>
<div class="row">
<div class="col">
<label for="sitSum">6. Situation Summary as of Time of Report</label>
<textarea id="sitSum" rows="3" placeholder="Brief summary of event impact, ongoing operations, current hazards..."></textarea>
</div>
</div>
<div class="row">
<div class="col">
<label for="goalsIssues">7. Future Outlook / Goals / Needs / Issues</label>
<textarea id="goalsIssues" rows="2" placeholder="Next operational priorities, critical shortfalls, anticipated issues..."></textarea>
</div>
</div>
</fieldset>
<fieldset>
<legend>8-9. EOC STATUS & LOCAL DISASTER DECLARATION</legend>
<div class="row">
<div class="col">
<label for="eocStatus">8. County EOC Status</label>
<select id="eocStatus">
<option value="CLOSED">CLOSED</option>
<option value="ACTIVATED">ACTIVATED</option>
<option value="MONITORING">MONITORING (Minimal Staffing)</option>
</select>
</div>
<div class="col"><label for="eocHours">EOC Hours of Operation</label><input type="text" id="eocHours" placeholder="e.g. 24/7 or 0700-1900"></div>
</div>
<div class="row">
<div class="col">
<label for="decStatus">9. Local Disaster Declaration Status</label>
<select id="decStatus">
<option value="No declaration / not anticipated">No declaration / not anticipated</option>
<option value="Declaration anticipated">Declaration anticipated</option>
<option value="Local disaster declaration in effect">Local disaster declaration in effect</option>
</select>
</div>
<div class="col"><label for="decDT">Declaration Date / Time</label><input type="text" id="decDT" placeholder="YYYY-MM-DD HHMMZ"></div>
</div>
</fieldset>
<fieldset>
<legend>10-13. CASUALTIES, SHELTERS & EVACUATIONS</legend>
<div class="row">
<div class="col"><label for="injuries">10. Confirmed Injuries</label><input type="text" id="injuries" placeholder="0"></div>
<div class="col"><label for="fatalities">11. Confirmed Fatalities</label><input type="text" id="fatalities" placeholder="0"></div>
</div>
<div class="row">
<div class="col">
<label for="shelters">12. Shelters Established (Number and Locations)</label>
<textarea id="shelters" rows="2" placeholder="e.g. 2 Shelters open: Oak Ridge Middle School (pop 110), Northside Rec Center (pop 45)"></textarea>
</div>
</div>
<div class="row">
<div class="col">
<label for="evacStatus">13. Evacuations Implemented?</label>
<select id="evacStatus">
<option value="No / None anticipated">No / None anticipated</option>
<option value="YES - Mandatory">YES - Mandatory</option>
<option value="YES - Voluntary">YES - Voluntary</option>
<option value="Evacuations anticipated">Evacuations anticipated</option>
</select>
</div>
<div class="col" style="flex: 2;"><label for="evacDesc">Evacuation Description</label><input type="text" id="evacDesc" placeholder="Boundaries, evacuation routes, population ordered..."></div>
</div>
</fieldset>
<fieldset>
<legend>14-16. SUBMISSION & CONTACT INFO</legend>
<div class="row">
<div class="col">
<div class="label-row">
<label for="repDT">14. Date / Time of Report</label>
<button type="button" class="btn-now" id="btnRepDT">Current UTC</button>
</div>
<input type="text" id="repDT" placeholder="YYYY-MM-DD HHMMZ">
</div>
<div class="col"><label for="submittedBy">15. Report Submitted By</label><input type="text" id="submittedBy" placeholder="Name, Title, Callsign"></div>
<div class="col"><label for="contactInfo">16. Contact Info</label><input type="text" id="contactInfo" placeholder="Phone / Radio Call / Email"></div>
</div>
</fieldset>
<div class="actions">
<button type="button" class="main-btn btn-generate" id="btnGen">Generate Packet ASCII</button>
<button type="button" class="main-btn btn-save" id="btnSaveHtml">Save as HTML</button>
<button type="button" class="main-btn btn-copy" id="btnCopy">Copy ASCII</button>
<button type="button" class="main-btn btn-clear" id="btnClear">Reset</button>
</div>
</form>
<label style="font-weight:bold;">Formatted ASCII for Packet / BBS Transmission:</label>
<pre id="outputPre">Fill in the fields above and click "Generate Packet ASCII"...</pre>
</div>
<script>
function setUTC(fldId) {
const now = new Date();
const y = now.getUTCFullYear();
const m = String(now.getUTCMonth()+1).padStart(2,'0');
const d = String(now.getUTCDate()).padStart(2,'0');
const hh = String(now.getUTCHours()).padStart(2,'0');
const mm = String(now.getUTCMinutes()).padStart(2,'0');
document.getElementById(fldId).value = y + '-' + m + '-' + d + ' ' + hh + mm + 'Z';
}
function clean(id) {
const el = document.getElementById(id);
return el ? (el.value || '').trim() : '';
}
function wrapText(str, width) {
if (!str) return [];
let lines = [];
str.split('\n').forEach(function(paragraph) {
let words = paragraph.split(' ');
let cur = '';
words.forEach(function(w) {
if ((cur + (cur ? ' ' : '') + w).length <= width) {
cur += (cur ? ' ' : '') + w;
} else {
if (cur) lines.push(cur);
cur = w;
}
});
if (cur) lines.push(cur);
});
return lines;
}
function generateASCII() {
try {
const div = '='.repeat(78);
const sub = '-'.repeat(78);
const inc = clean('incName').toUpperCase() || 'N/A';
const web = clean('webEOC').toUpperCase() || 'N/A';
const idt = clean('incDT') || 'N/A';
const ver = clean('repVersion').toUpperCase();
// Gather types
let types = [];
document.querySelectorAll('.checkbox-grid input[type="checkbox"]').forEach(function(cb) {
if (cb.checked) {
if (cb.id === 't_other_chk' && clean('t_other_txt')) {
types.push('OTHER (' + clean('t_other_txt').toUpperCase() + ')');
} else {
types.push(cb.value.toUpperCase());
}
}
});
const typeStr = types.length ? types.join(', ') : 'NONE SPECIFIED';
const sit = clean('sitSum').toUpperCase() || 'NONE REPORTED';
const goals = clean('goalsIssues').toUpperCase() || 'NONE REPORTED';
const eoc = clean('eocStatus').toUpperCase();
const eocH = clean('eocHours').toUpperCase() || 'N/A';
const dec = clean('decStatus').toUpperCase();
const decD = clean('decDT') || 'N/A';
const inj = clean('injuries') || '0';
const fat = clean('fatalities') || '0';
const shlt = clean('shelters').toUpperCase() || 'NONE ESTABLISHED';
const evac = clean('evacStatus').toUpperCase();
const evacD = clean('evacDesc').toUpperCase();
const rdt = clean('repDT') || 'N/A';
const subBy = clean('submittedBy').toUpperCase() || 'N/A';
const cont = clean('contactInfo').toUpperCase() || 'N/A';
let wrappedSit = wrapText(sit, 72).map(function(l){ return ' ' + l; }).join('\n');
let wrappedGoals = wrapText(goals, 72).map(function(l){ return ' ' + l; }).join('\n');
let wrappedShlt = wrapText(shlt, 72).map(function(l){ return ' ' + l; }).join('\n');
const out = div + '\n' +
'INCIDENT STATUS REPORT (PACKET ASCII)\n' +
div + '\n' +
'1. INCIDENT NAME: ' + inc + ' 2. WEBEOC #: ' + web + '\n' +
'3. INCIDENT D/T: ' + idt + ' 4. REPORT VER: ' + ver + '\n' +
sub + '\n' +
'5. INCIDENT TYPE(S): ' + typeStr + '\n' +
sub + '\n' +
'6. SITUATION SUMMARY:\n' + wrappedSit + '\n' +
sub + '\n' +
'7. FUTURE OUTLOOK / GOALS / NEEDS / ISSUES:\n' + wrappedGoals + '\n' +
sub + '\n' +
'8. COUNTY EOC STATUS : ' + eoc + ' (HOURS: ' + eocH + ')\n' +
'9. DISASTER DECLARATION: ' + dec + (decD !== 'N/A' ? ' [DATE/TIME: ' + decD + ']' : '') + '\n' +
sub + '\n' +
'10. INJURIES: ' + inj + ' 11. FATALITIES: ' + fat + '\n' +
'12. SHELTERS ESTABLISHED:\n' + wrappedShlt + '\n' +
'13. EVACUATIONS: ' + evac + (evacD ? ' - ' + evacD : '') + '\n' +
sub + '\n' +
'14. REPORT DATE/TIME: ' + rdt + '\n' +
'15. SUBMITTED BY : ' + subBy + '\n' +
'16. CONTACT INFO : ' + cont + '\n' +
div;
document.getElementById('outputPre').textContent = out;
} catch(err) {
alert("Error generating text: " + err.message);
}
}
function copyASCII() {
const txt = document.getElementById('outputPre').textContent;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).then(function() {
alert("Incident Status copied to clipboard!");
}).catch(function() {
fallbackCopy();
});
} else {
fallbackCopy();
}
}
function fallbackCopy() {
const pre = document.getElementById('outputPre');
const range = document.createRange();
range.selectNode(pre);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
document.execCommand('copy');
alert("Copied to clipboard!");
}
function clearForm() {
if(confirm("Reset Incident Status form?")) {
document.getElementById('statusForm').reset();
document.getElementById('outputPre').textContent = 'Fill in the fields above and click "Generate Packet ASCII"...';
}
}
document.getElementById('btnIncDT').addEventListener('click', function(){ setUTC('incDT'); });
document.getElementById('btnRepDT').addEventListener('click', function(){ setUTC('repDT'); });
document.getElementById('btnGen').addEventListener('click', generateASCII);
document.getElementById('btnSaveHtml').addEventListener('click', openSaveModal);
document.getElementById('btnCopy').addEventListener('click', copyASCII);
document.getElementById('btnClear').addEventListener('click', clearForm);
// File Name Modal Window & HTML Exporter
function openSaveModal() {
var now = new Date();
var dStr = now.toISOString().slice(0, 10);
var defName = 'incident_status_' + dStr + '.html';
var modal = document.getElementById('saveModalBackdrop');
var input = document.getElementById('saveModalFileName');
if (input) input.value = defName;
if (modal) modal.classList.add('active');
setTimeout(function() {
if (input) { input.focus(); input.select(); }
}, 50);
}
function closeSaveModal() {
var modal = document.getElementById('saveModalBackdrop');
if (modal) modal.classList.remove('active');
}
function executeSaveHTML() {
var input = document.getElementById('saveModalFileName');
var chosenName = input ? input.value.trim() : '';
if (!chosenName) return;
if (!chosenName.toLowerCase().endsWith('.html') && !chosenName.toLowerCase().endsWith('.htm')) {
chosenName += '.html';
}
closeSaveModal();
document.querySelectorAll('input[type="text"]').forEach(function(el) { el.setAttribute('value', el.value); });
document.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(function(el) {
if (el.checked) el.setAttribute('checked', 'checked');
else el.removeAttribute('checked');
});
document.querySelectorAll('textarea').forEach(function(el) { el.textContent = el.value; });
document.querySelectorAll('select').forEach(function(el) {
Array.from(el.options).forEach(function(opt) {
if (opt.value === el.value) opt.setAttribute('selected', 'selected');
else opt.removeAttribute('selected');
});
});
var pre = document.getElementById('ascii-report') || document.getElementById('outputPre') || document.getElementById('preview') || document.getElementById('outputArea');
if (pre) pre.textContent = pre.textContent;
var clonedDoc = document.documentElement.cloneNode(true);
var modalInClone = clonedDoc.querySelector('#saveModalBackdrop');
if (modalInClone) modalInClone.classList.remove('active');
var htmlContent = '<!DOCTYPE html>\n' + clonedDoc.outerHTML;
var blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = chosenName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
window.addEventListener('DOMContentLoaded', function() {
var cancelBtn = document.getElementById('saveModalCancelBtn');
var confirmBtn = document.getElementById('saveModalSaveBtn');
var modalInput = document.getElementById('saveModalFileName');
var modalBackdrop = document.getElementById('saveModalBackdrop');
if (cancelBtn) cancelBtn.addEventListener('click', closeSaveModal);
if (confirmBtn) confirmBtn.addEventListener('click', executeSaveHTML);
if (modalInput) {
modalInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') { e.preventDefault(); executeSaveHTML(); }
if (e.key === 'Escape') { e.preventDefault(); closeSaveModal(); }
});
}
if (modalBackdrop) {
modalBackdrop.addEventListener('click', function(e) {
if (e.target === modalBackdrop) closeSaveModal();
});
}
var btnSaveMain = document.getElementById('btnSaveHtml');
if (btnSaveMain) {
// Clear existing inline handlers just in case
btnSaveMain.onclick = null;
btnSaveMain.addEventListener('click', openSaveModal);
}
});
</script>
<!-- Custom File Name Modal Window -->
<div id="saveModalBackdrop" class="save-modal-backdrop">
<div class="save-modal-window">
<h3>Save Form as HTML</h3>
<p>Enter a name for the saved offline HTML file:</p>
<input type="text" id="saveModalFileName" spellcheck="false">
<div class="save-modal-actions">
<button type="button" class="save-modal-btn save-modal-btn-cancel" id="saveModalCancelBtn">Cancel</button>
<button type="button" class="save-modal-btn save-modal-btn-confirm" id="saveModalSaveBtn">Save File</button>
</div>
</div>
</div>
</body>
</html>