/** * @typedef {Object} SoundBank * @property {number} index * @property {string} description * @property {string} tag * @property {string} category * @property {string} language * @property {string} voiceType * @property {string} path */ /** * @typedef {Object} MessageBank * @property {number} index * @property {string} description * @property {string} language * @property {number} aNN_ID * @property {string} voice_Type * @property {string} message_Detail * @property {string} message_TAGS */ /** * @typedef {Object} LanguageBank * @property {number} index * @property {string} tag * @property {string} language * @ */ /** * @typedef {Object} ScheduleBank * @property {number} index * @property {string} description * @property {string} day * @property {string} time * @property {string} soundpath * @property {number} repeat * @property {boolean} enable * @property {string} broadcastZones * @property {string} language */ /** * @typedef {Object} Log * @property {number} index * @property {string} datenya * @property {string} timenya * @property {string} machine * @property {string} description */ $(document).ready(function () { document.title = "Automatic Announcement System" $('#onlineindicator').attr('src', '/assets/img/red_circle.png'); let soundbankdata = []; let selectedsoundrow = null; let messagebankdata = []; let selectedmessagerow = null; let languagebankdata = []; let selectedlanguagerow = null; let schedulebankdata = []; let selectedschedulerow = null; let logdata = []; /** * Fill soundbank table body with values * @param {SoundBank[]} vv values to fill */ function fill_soundbanktablebody(vv) { $('#soundbanktablebody').empty(); vv.forEach(item => { const row = ` ${item.index} ${item.description} ${item.tag} ${item.category} ${item.language} ${item.voiceType} ${item.path} `; $('#soundbanktablebody').append(row); let $addedrow = $('#soundbanktablebody tr:last'); $addedrow.on('click', function () { if (selectedsoundrow) { selectedsoundrow.find('td').css('background-color', ''); if (selectedsoundrow.is($(this))) { selectedsoundrow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $(this).find('td').css('background-color', '#ffeeba'); selectedsoundrow = $(this); $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); $('#tablesize').text("Table Size: " + vv.length); } /** * Fill messagebank table body with values * @param {MessageBank[]} vv values to fill */ function fill_messagebanktablebody(vv) { $('#messagebanktablebody').empty(); vv.forEach(item => { const row = ` ${item.index} ${item.description} ${item.language} ${item.aNN_ID} ${item.voice_Type} ${item.message_Detail} ${item.message_TAGS} `; $('#messagebanktablebody').append(row); let $addedrow = $('#messagebanktablebody tr:last'); $addedrow.click(function () { if (selectedmessagerow) { selectedmessagerow.find('td').css('background-color', ''); if (selectedmessagerow.is($(this))) { selectedmessagerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); selectedmessagerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); console.log("loaded " + vv.length + " messagebank items"); } /** * Fill languagebank table body with values * @param {LanguageBank[]} vv values to fill */ function fill_languagebanktablebody(vv) { $('#languagebanktablebody').empty(); vv.forEach(item => { const row = ` ${item.index} ${item.tag} ${item.language} `; $('#languagebanktablebody').append(row); let $addedrow = $('#languagebanktablebody tr:last'); $addedrow.click(function () { if (selectedlanguagerow) { selectedlanguagerow.find('td').css('background-color', ''); if (selectedlanguagerow.is($(this))) { selectedlanguagerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); selectedlanguagerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); console.log("loaded " + vv.length + " languagebank items"); } /** * Fill schedulebank table body with values * @param {ScheduleBank[]} vv values to fill */ function fill_schedulebanktablebody(vv) { $('#schedulebanktablebody').empty(); vv.forEach(item => { const row = ` ${item.index} ${item.description} ${item.day} ${item.time} ${item.soundpath} ${item.repeat} ${item.enable} ${item.broadcastZones} ${item.language} `; $('#schedulebanktablebody').append(row); let $addedrow = $('#schedulebanktablebody tr:last'); $addedrow.click(function () { if (selectedschedulerow) { selectedschedulerow.find('td').css('background-color', ''); if (selectedschedulerow.is($(this))) { selectedschedulerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); selectedschedulerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); console.log("loaded " + vv.length + " schedulebank items"); } /** * Fill log table body with values * @param {Log[]} vv values to fill */ function fill_logtablebody(vv) { $('#logtablebody').empty(); vv.forEach(item => { const row = ` ${item.index} ${item.datenya} ${item.timenya} ${item.machine} ${item.description} `; $('#logtablebody').append(row); }); console.log("loaded " + vv.length + " log items"); } const ws = new WebSocket(window.location.pathname + '/ws'); ws.onopen = () => { console.log('WebSocket connection established'); $('#onlineindicator').attr('src', '/assets/img/green_circle.png'); }; ws.onmessage = (event) => { let rep = JSON.parse(event.data); let cmd = rep.reply let data = rep.data; if (cmd && cmd.length > 0) { switch (cmd) { case "getCPUStatus": $('#cpustatus').text("CPU Usage: " + data) break; case "getMemoryStatus": $('#ramstatus').text("Memory Usage: " + data) break; case "getDiskStatus": $('#diskstatus').text("Disk Usage: " + data) break; case "getNetworkStatus": $('#networkstatus').text("Network Usage: " + data) break; case "getSystemTime": $('#datetimetext').text(data) break; case "getSoundBankList": let $soundbankfilter = $('#findsoundbank'); $soundbankfilter.empty(); soundbankdata = []; fill_soundbanktablebody(soundbankdata) let xx = JSON.parse(data); if (Array.isArray(xx) && xx.length > 0) { soundbankdata = xx; fill_soundbanktablebody(soundbankdata); $soundbankfilter.prop('disabled', false); $soundbankfilter.off('input').on('input', function () { const filterText = $(this).val().toLowerCase(); if (filterText.length === 0) { fill_soundbanktablebody(soundbankdata); return; } else { const filtered = soundbankdata.filter(item => item.description && item.description.toLowerCase().startsWith(filterText) ); fill_soundbanktablebody(filtered); } }); } else { $soundbankfilter.prop('disabled', true); alert("No soundbank data available"); } break; case "getMessageBankList": messagebankdata = []; fill_messagebanktablebody(messagebankdata); let yy = JSON.parse(data); if (Array.isArray(yy) && yy.length > 0) { messagebankdata = yy; fill_messagebanktablebody(messagebankdata); } else alert("No messagebank data available"); break; case "getLanguageList": languagebankdata = [] fill_languagebanktablebody(languagebankdata); let zz = JSON.parse(data); if (Array.isArray(zz) && zz.length > 0) { languagebankdata = zz; fill_languagebanktablebody(languagebankdata); } else alert("No language data available"); break; case "getTimerList": schedulebankdata = [] fill_schedulebanktablebody(schedulebankdata); let aa = JSON.parse(data); if (Array.isArray(aa) && aa.length > 0) { schedulebankdata = aa; fill_schedulebanktablebody(schedulebankdata); } else alert("No schedule data available"); break; case "getLog": let $logfilter = $('#searchfilter'); logdata = []; fill_logtablebody(logdata); let bb = JSON.parse(data); if (Array.isArray(bb) && bb.length > 0) { logdata = bb; fill_logtablebody(logdata); } else alert("No log data available"); break; case "getSetting": console.log("Setting:"); console.log(data); break; case "clearSoundBank": soundbankdata = []; selectedsoundrow = null; fill_soundbanktablebody(soundbankdata); alert(`Clear SoundBank Result : ${data}`); break; case "clearMessageBank": messagebankdata = []; selectedmessagerow = null; fill_messagebanktablebody(messagebankdata); alert(`Clear MessageBank Result : ${data}`); break; case "clearLanguageBank": languagebankdata = []; selectedlanguagerow = null; fill_languagebanktablebody(languagebankdata); alert(`Clear LanguageBank Result : ${data}`); break; case "clearTimerBank": schedulebankdata = []; selectedschedulerow = null; fill_schedulebanktablebody(schedulebankdata); alert(`Clear ScheduleBank Result : ${data}`); break; } } }; ws.onclose = () => { console.log('WebSocket connection closed'); $('#onlineindicator').attr('src', '/assets/img/red_circle.png'); }; // ws.onerror = (error) => { // console.error('WebSocket error:', error); // }; /** * Send a command to the WebSocket server. * @param {String} command command to send * @param {String} data data to send */ function sendCommand(command, data) { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ command, data })); } else { console.error('WebSocket is not open'); } } setInterval(() => { sendCommand("getCPUStatus", "") sendCommand("getMemoryStatus", "") sendCommand("getDiskStatus", "") sendCommand("getNetworkStatus", "") sendCommand("getSystemTime", "") }, 1000) let sidemenu = new bootstrap.Offcanvas('#offcanvas-menu'); $('#showmenu').click(() => { sidemenu.show(); }) $('#soundbanklink').click(() => { sidemenu.hide(); $('#content').load('soundbank.html', function (response, status, xhr) { if (status === "success") { console.log("Soundbank content loaded successfully"); // initialize first state of buttons and text input $('#soundbanktablebody').empty(); selectedsoundrow = null; const $btnRemove = $('#btnRemove'); const $btnEdit = $('#btnEdit'); const $modal = $('#soundbankmodal'); const modalEl = $modal[0]; const modal = bootstrap.Modal.getOrCreateInstance(modalEl); // creates or reuses $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); sendCommand("getSoundBankList", ""); $('#btnClear').click(() => { if (confirm(`Are you sure want to clear Soundbank ? This procedure is not reversible`)) { sendCommand("clearSoundBank", ""); } }); $('#btnAdd').click(() => { modal.show(); $modal.off('hidden.bs.modal').on('hidden.bs.modal', function () { const desc = $('#description').val(); console.log('Description input value:', desc); // You can use desc here (e.g., send to server) }); }); $btnRemove.click(() => { if (selectedsoundrow) { let cells = selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: cells.eq(0).text(), description: cells.eq(1).text(), tag: cells.eq(2).text(), category: cells.eq(3).text(), language: cells.eq(4).text(), voiceType: cells.eq(5).text(), path: cells.eq(6).text() } if (confirm(`Are you sure to delete soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { sendCommand("deleteSoundBank", sb); } } }); $btnEdit.click(() => { if (selectedsoundrow) { let cells = selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: cells.eq(0).text(), description: cells.eq(1).text(), tag: cells.eq(2).text(), category: cells.eq(3).text(), language: cells.eq(4).text(), voiceType: cells.eq(5).text(), path: cells.eq(6).text() } if (confirm(`Are you sure to edit soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { modal.show(); $modal.off('hidden.bs.modal').on('hidden.bs.modal', function () { const desc = $('#description').val(); console.log('Description input value:', desc); // You can use desc here (e.g., send to server) }); } } }); $('#btnExport').click(() => { alert("Feature disabled for now"); }); $('#btnImport').click(() => { alert("Feature disabled for now"); }); } else { console.error("Error loading soundbank content:", xhr.status, xhr.statusText); } }); }) $('#messagebanklink').click(() => { sidemenu.hide(); $('#content').load('messagebank.html', function (response, status, xhr) { if (status === "success") { console.log("Messagebank content loaded successfully"); // initialize first state of buttons and text input $('#messagebanktablebody').empty(); selectedmessagerow = null; let $btnRemove = $('#btnRemove'); let $btnEdit = $('#btnEdit'); $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); sendCommand("getMessageBankList", ""); $('#btnClear').click(() => { if (confirm(`Are you sure want to clear Messagebank ? This procedure is not reversible`)) { sendCommand("clearMessageBank", ""); } }); $('#btnAdd').click(() => { //TODO form add messagebank }); $btnRemove.click(() => { if (selectedmessagerow) { let cells = selectedmessagerow.find('td'); /** @type {MessageBank} */ let mb = { index: cells.eq(0).text(), description: cells.eq(1).text(), language: cells.eq(2).text(), aNN_ID: parseInt(cells.eq(3).text()), voice_Type: cells.eq(4).text(), message_Detail: cells.eq(5).text(), message_TAGS: cells.eq(6).text() } if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) { sendCommand("deleteMessageBank", mb); } } }); $btnEdit.click(() => { if (selectedmessagerow) { let cells = selectedmessagerow.find('td'); /** @type {MessageBank} */ let mb = { index: cells.eq(0).text(), description: cells.eq(1).text(), language: cells.eq(2).text(), aNN_ID: parseInt(cells.eq(3).text()), voice_Type: cells.eq(4).text(), message_Detail: cells.eq(5).text(), message_TAGS: cells.eq(6).text() } if (confirm(`Are you sure to edit messagebank [${mb.index}] Description=${mb.description} ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) { //TODO send edit command } } }); $('#btnExport').click(() => { alert("Feature disabled for now"); }); $('#btnImport').click(() => { alert("Feature disabled for now"); }); } else { console.error("Error loading messagebank content:", xhr.status, xhr.statusText); } }); }) $('#languagelink').click(() => { sidemenu.hide(); $('#content').load('language.html', function (response, status, xhr) { if (status === "success") { console.log("Language content loaded successfully"); // initialize first state of buttons and text input $('#languagebanktablebody').empty(); selectedlanguagerow = null; let $btnRemove = $('#btnRemove'); let $btnEdit = $('#btnEdit'); $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); sendCommand("getLanguageList", ""); $('#btnClear').click(() => { if (confirm(`Are you sure want to clear Languagebank ? This procedure is not reversible`)) { sendCommand("clearLanguageBank", ""); } }); $('#btnAdd').click(() => { //TODO form add language }); $btnRemove.click(() => { if (selectedlanguagerow) { let cells = selectedlanguagerow.find('td'); /** @type {Language} */ let ll = { index: cells.eq(0).text(), tag: cells.eq(1).text(), language: cells.eq(2).text() } if (confirm(`Are you sure to delete language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { sendCommand("deleteLanguage", ll); } } }); $btnEdit.click(() => { if (selectedlanguagerow) { let cells = selectedlanguagerow.find('td'); /** @type {Language} */ let ll = { index: cells.eq(0).text(), tag: cells.eq(1).text(), language: cells.eq(2).text() } if (confirm(`Are you sure to edit language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { //TODO send edit command } } }); $('#btnExport').click(() => { alert("Feature disabled for now"); }); $('#btnImport').click(() => { alert("Feature disabled for now"); }); } else { console.error("Error loading language content:", xhr.status, xhr.statusText); } }); }) $('#timerlink').click(() => { sidemenu.hide(); $('#content').load('timer.html', function (response, status, xhr) { if (status === "success") { console.log("Timer content loaded successfully"); // initialize first state of buttons and text input $('#schedulebanktablebody').empty(); selectedschedulerow = null; let $btnEdit = $('#btnEdit'); let $btnRemove = $('#btnRemove'); $btnEdit.prop('disabled', true); $btnRemove.prop('disabled', true); sendCommand("getTimerList", ""); $('#btnClear').click(() => { if (confirm(`Are you sure want to clear Timerbank ? This procedure is not reversible`)) { sendCommand("clearTimerBank", ""); } }); $('#btnAdd').click(() => { //TODO form add timer }); $btnRemove.click(() => { if (selectedtimerow) { let cells = selectedtimerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: cells.eq(0).text(), description: cells.eq(1).text(), day: cells.eq(2).text(), time: cells.eq(3).text(), soundpath: cells.eq(4).text(), repeat: cells.eq(5).text(), enable: cells.eq(6).text(), broadcastZones: cells.eq(7).text(), language: cells.eq(8).text() } if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { sendCommand("deleteSchedule", sr); } } }); $btnEdit.click(() => { if (selectedtimerow) { let cells = selectedtimerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: cells.eq(0).text(), description: cells.eq(1).text(), day: cells.eq(2).text(), time: cells.eq(3).text(), soundpath: cells.eq(4).text(), repeat: cells.eq(5).text(), enable: cells.eq(6).text(), broadcastZones: cells.eq(7).text(), language: cells.eq(8).text() } if (confirm(`Are you sure to edit schedule [${sr.index}] Description=${sr.description}?`)) { //TODO send edit command } } }); $('#btnExport').click(() => { alert("Feature disabled for now"); }); $('#btnImport').click(() => { alert("Feature disabled for now"); }); } else { console.error("Error loading timer content:", xhr.status, xhr.statusText); } }); }) $('#loglink').click(() => { sidemenu.hide(); $('#content').load('log.html', function (response, status, xhr) { if (status === "success") { console.log("Log content loaded successfully"); const $logdate = $('#logdate'); const $searchfilter = $('#searchfilter'); if (!$logdate.val()) { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); $logdate.val(`${yyyy}-${mm}-${dd}`); } $logdate.off('change').on('change', function () { const selected = $(this).val(); if (selected) { const [year, month, day] = selected.split('-'); const formatted = `${day}/${month}/${year}`; sendCommand("getLog", logRequstData(formatted, $searchfilter.val())); } }); const selected = $logdate.val(); if (selected) { const [year, month, day] = selected.split('-'); const formatted = `${day}/${month}/${year}`; sendCommand("getLog", logRequstData(formatted, $searchfilter.val())); } } else { console.error("Error loading log content:", xhr.status, xhr.statusText); } }); }) $('#settinglink').click(() => { sidemenu.hide(); $('#content').load('setting.html', function (response, status, xhr) { if (status === "success") { console.log("Setting content loaded successfully"); sendCommand("getSetting", ""); } else { console.error("Error loading setting content:", xhr.status, xhr.statusText); } }); }) $('#logoutlink').click(() => { window.location.href = "login.html" }) /** * Create log Request Data * @param {String} logdate in format dd/mm/yyyy * @param {String} logfilter * @returns JSON string of log Request data */ function logRequstData(logdate, logfilter) { if (logdate && logdate.length > 0) { const dateRegex = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/; if (dateRegex.test(logdate)) { // logdate is valid return JSON.stringify({ date: logdate, filter: logfilter }) } } return "" } });