/** * @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} Select2item * @property {number} id * @property {string} text */ /** * List of Soundbank data loaded from server * @type {SoundBank[]} */ window.soundbankdata = []; /** * Currently selected soundbank row in the table * @type {JQuery|null} */ window.selectedsoundrow = null; /** * Select2 data source * See https://select2.org/data-sources/formats * @type {Select2item[]} */ window.select2data = []; /** * Reload sound bank from server * @param {String} APIURL API URL endpoint, default "SoundBank/" */ function reloadSoundBank(APIURL = "SoundBank/") { window.soundbankdata = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { window.soundbankdata.push(...okdata); window.selectedsoundrow = null; fill_soundbanktablebody(window.soundbankdata); } }, (errdata) => { alert("Error loading soundbank : " + errdata.message); }); } /** * Fill soundbank table body with values * @param {SoundBank[]} vv values to fill */ function fill_soundbanktablebody(vv) { $('#soundbanktablebody').empty(); if (!Array.isArray(vv) || vv.length === 0) return; 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 (window.selectedsoundrow) { window.selectedsoundrow.find('td').css('background-color', ''); if (window.selectedsoundrow.is($(this))) { window.selectedsoundrow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $(this).find('td').css('background-color', '#ffeeba'); window.selectedsoundrow = $(this); $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); $('#tablesize').text("Table Size: " + vv.length); } /** * Reload soundbank files from server and filter by language, category, and voiceType * @param {String} language * @param {String} category * @param {String} voiceType * @param {Function} cb callback function when done */ function reloadSoundbankFiles(language, category, voiceType, cb=null) { window.select2data = []; $('#modalpath').empty().trigger('change'); if (language && language.length > 0) { if (category && category.length > 0) { if (voiceType && voiceType.length > 0) { fetchAPI(`ListFiles/${language}/${voiceType}/${category}`, "GET", {}, null, (okdata) => { console.log("reloadSoundbankFiles: got " + okdata.length + " items"); if (Array.isArray(okdata)){ window.select2data = okdata.map(p => ({id: getFilenameFromPath(p), text: getFilenameFromPath(p)})); $('#modalpath').select2({ data: window.select2data, placeholder: 'Select a sound file', allowClear: true, width: '100%', dropdownParent: $('#soundbankmodal') }); if (cb) cb(); } }, (errdata) => { alert("Error loading soundbank files : " + errdata.message); }); } } } } function getFilenameFromPath(path) { if (!path || path.length === 0) return ""; if (path.includes('\\')) { let parts = path.split('\\'); return parts[parts.length - 1]; } else if (!path.includes('/')) { let parts = path.split('/'); return parts[parts.length - 1]; } } $(document).ready(function () { console.log("soundbank.js loaded successfully"); $('#soundbanktablebody').empty(); window.selectedsoundrow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnRemove = $('#btnRemove'); let $btnEdit = $('#btnEdit'); let $btnExport = $('#btnExport'); let $btnImport = $('#btnImport'); $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); let APIURL = "SoundBank/"; let $modal = $('#soundbankmodal'); let $modalindex = $modal.find('#modalindex'); let $modaldescription = $modal.find('#modaldescription'); let $modaltag = $modal.find('#modaltag'); let $modalcategory = $modal.find('#modalcategory'); let $modallanguage = $modal.find('#modallanguage'); let $modalvoicetype = $modal.find('#modalvoicetype'); let selected_category = null; let selected_language = null; let selected_voicetype = null; /** * Clear soundbank modal inputs */ function clearSoundbankModal() { $modalindex.val('').prop('disabled', true); $modaldescription.val(''); $modaltag.val(''); // fill modalcategory options from categories[] $modalcategory.empty(); categories.forEach(cat => { $modalcategory.append(new Option(cat, cat)); }); $modalcategory.val(null); // fill modallanguage options from languages[] $modallanguage.empty(); languages.forEach(lang => { $modallanguage.append(new Option(lang, lang)); }); $modallanguage.val(null); // fill modalvoicetype options from voiceTypes[] $modalvoicetype.empty(); voiceTypes.forEach(vt => { $modalvoicetype.append(new Option(vt, vt)); }); $modalvoicetype.val(null); $('#modalpath').select2() } reloadSoundBank(APIURL); $('#findsoundbank').on('input', function () { let searchTerm = $(this).val().trim().toLowerCase(); if (searchTerm.length > 0) { window.selectedsoundrow = null; let filtered = window.soundbankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.tag.toLowerCase().includes(searchTerm) || item.path.toLowerCase().includes(searchTerm)); fill_soundbanktablebody(filtered); } else { window.selectedsoundrow = null; fill_soundbanktablebody(window.soundbankdata); } }); $btnClear.click(() => { DoClear(APIURL, "Soundbank", (okdata) => { reloadSoundBank(APIURL); alert("Success clear soundbank : " + okdata.message); }, (errdata) => { alert("Error clear soundbank : " + errdata.message); }); }); function SetupEventForCategoryLanguageVoiceType() { $modalcategory.off('change').on('change', function () { selected_category = $(this).val(); reloadSoundbankFiles(selected_language, selected_category, selected_voicetype); }); $modallanguage.off('change').on('change', function () { selected_language = $(this).val(); reloadSoundbankFiles(selected_language, selected_category, selected_voicetype); }); $modalvoicetype.off('change').on('change', function () { selected_voicetype = $(this).val(); reloadSoundbankFiles(selected_language, selected_category, selected_voicetype); }); } $btnAdd.click(() => { $modal.modal('show'); clearSoundbankModal(); // event on selection change of language, category, voiceType SetupEventForCategoryLanguageVoiceType(); // event on Click save button $modal.off('click.soundbanksave').on('click.soundbanksave', '#soundbanksave', function () { let description = $modaldescription.val().trim(); let tag = $modaltag.val().trim(); let category = $modalcategory.val(); let language = $modallanguage.val(); let voiceType = $modalvoicetype.val(); let path = $('#soundbankmodal #modalpath').val(); if (!description || description.length === 0) { alert("Description is required"); return; } if (!tag || tag.length === 0) { alert("Tag is required"); return; } if (!category || category.length === 0) { alert("Category is required"); return; } if (!language || language.length === 0) { alert("Language is required"); return; } if (!voiceType || voiceType.length === 0) { alert("Voice Type is required"); return; } if (!path || path.length === 0) { alert("Path is required"); return; } $modal.modal('hide'); /** * @type {SoundBank} */ let nsb = { index: 0, Description: description, TAG: tag, Category: category, Language: language, VoiceType: voiceType, Path: path } fetchAPI(APIURL + "Add", "POST", {}, nsb, (okdata) => { reloadSoundBank(APIURL); alert("Success add soundbank : " + okdata.message); }, (errdata) => { alert("Error add soundbank : " + errdata.message); }); }); // event on Click close button $modal.off('click.soundbankclose').on('click.soundbankclose', '#soundbankclose', function () { $modal.modal('hide'); }); }); $btnRemove.click(() => { if (window.selectedsoundrow) { let cells = window.selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: Number(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}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sb.index, "DELETE", {}, null, (okdata) => { reloadSoundBank(APIURL); alert("Success delete soundbank : " + okdata.message); }, (errdata) => { alert("Error delete soundbank : " + errdata.message); }); } } }); $btnEdit.click(() => { if (window.selectedsoundrow) { let cells = window.selectedsoundrow.find('td'); /** @type {SoundBank} */ let sb = { index: Number(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.modal('show'); clearSoundbankModal(); SetupEventForCategoryLanguageVoiceType(); $modalindex.val(sb.index).prop('disabled', true); $modaldescription.val(sb.Description); $modaltag.val(sb.TAG); $modalcategory.val(sb.Category); selected_category = sb.Category; $modallanguage.val(sb.Language); selected_language = sb.Language; $modalvoicetype.val(sb.VoiceType); selected_voicetype = sb.VoiceType; // load soundbank files for selected language, category, voiceType reloadSoundbankFiles(selected_language, selected_category, selected_voicetype, () => { // set selected path $('#modalpath').val(getFilenameFromPath(sb.Path)).trigger('change'); }); // event on Click save button $modal.off('click.soundbanksave').on('click.soundbanksave', '#soundbanksave', function () { let description = $modaldescription.val().trim(); let tag = $modaltag.val().trim(); let category = $modalcategory.val(); let language = $modallanguage.val(); let voiceType = $modalvoicetype.val(); let path = $('#soundbankmodal #modalpath').val(); if (!description || description.length === 0) { alert("Description is required"); return; } if (!tag || tag.length === 0) { alert("Tag is required"); return; } if (!category || category.length === 0) { alert("Category is required"); return; } if (!language || language.length === 0) { alert("Language is required"); return; } if (!voiceType || voiceType.length === 0) { alert("Voice Type is required"); return; } if (!path || path.length === 0) { alert("Path is required"); return; } if (description === sb.Description && tag === sb.TAG && category === sb.Category && language === sb.Language && voiceType === sb.VoiceType && path === sb.Path) { alert("No changes detected"); return; } sb.Description = description; sb.TAG = tag; sb.Category = category; sb.Language = language; sb.VoiceType = voiceType; sb.Path = path; fetchAPI(APIURL + "UpdateByIndex/" + sb.index, "PATCH", {}, sb, (okdata) => { reloadSoundBank(APIURL); alert("Success update soundbank : " + okdata.message); }, (errdata) => { alert("Error update soundbank : " + errdata.message); }); $modal.modal('hide'); }); // event on Click close button $modal.off('click.soundbankclose').on('click.soundbankclose', '#soundbankclose', function () { $modal.modal('hide'); }); } } }); $btnExport.click(() => { DoExport(APIURL, "soundbank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadSoundBank(APIURL); alert("Success import soundbank : " + okdata.message); }, (errdata) => { alert("Error importing soundbank from XLSX : " + errdata.message); }); }); });