From 40f462ce79def9ec0df8e3bcd91dea34e18144e1 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Tue, 9 Sep 2025 15:54:42 +0700 Subject: [PATCH] commit 09/09/2025 --- .idea/copilot.data.migration.agent.xml | 6 + .idea/copilot.data.migration.edit.xml | 6 + .idea/jarRepositories.xml | 20 + AAS_NewGen.iml | 17 +- .../assets/css/Login-Form-Basic-icons.css | 5 + html/webpage/assets/css/styles.css | 190 + html/webpage/assets/img/logogtc-grey.png | Bin 0 -> 55099 bytes html/webpage/assets/img/logogtc.png | Bin 0 -> 75887 bytes html/webpage/assets/js/script.js | 1165 +++- html/webpage/assets/js/select2.js | 6108 +++++++++++++++++ html/webpage/home.html | 81 +- html/webpage/language.html | 35 +- html/webpage/log.html | 29 +- html/webpage/login.html | 16 +- html/webpage/messagebank.html | 81 +- html/webpage/overview.html | 1325 ++++ html/webpage/setting.html | 8 +- html/webpage/soundbank.html | 67 +- html/webpage/streamerstatus.html | 34 + html/webpage/timer.html | 52 +- src/barix/BarixConnection.kt | 4 + src/barix/TCP_Barix_Command_Server.kt | 101 + src/codes/Somecodes.kt | 29 + src/web/WebApp.kt | 47 +- 24 files changed, 8923 insertions(+), 503 deletions(-) create mode 100644 .idea/copilot.data.migration.agent.xml create mode 100644 .idea/copilot.data.migration.edit.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 html/webpage/assets/css/styles.css create mode 100644 html/webpage/assets/img/logogtc-grey.png create mode 100644 html/webpage/assets/img/logogtc.png create mode 100644 html/webpage/assets/js/select2.js create mode 100644 html/webpage/overview.html create mode 100644 html/webpage/streamerstatus.html create mode 100644 src/barix/BarixConnection.kt create mode 100644 src/barix/TCP_Barix_Command_Server.kt diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml new file mode 100644 index 0000000..4ea72a9 --- /dev/null +++ b/.idea/copilot.data.migration.agent.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 0000000..8648f94 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..ed4f5a9 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/AAS_NewGen.iml b/AAS_NewGen.iml index f74f693..9040d70 100644 --- a/AAS_NewGen.iml +++ b/AAS_NewGen.iml @@ -25,19 +25,14 @@ - + - - - - - - - - - - + + + + + diff --git a/html/webpage/assets/css/Login-Form-Basic-icons.css b/html/webpage/assets/css/Login-Form-Basic-icons.css index b6e79a3..7bf803b 100644 --- a/html/webpage/assets/css/Login-Form-Basic-icons.css +++ b/html/webpage/assets/css/Login-Form-Basic-icons.css @@ -55,3 +55,8 @@ border-radius: 50%; } +.pad-icon { + display: flex; + align-items: center; +} + diff --git a/html/webpage/assets/css/styles.css b/html/webpage/assets/css/styles.css new file mode 100644 index 0000000..bb49fba --- /dev/null +++ b/html/webpage/assets/css/styles.css @@ -0,0 +1,190 @@ +body { + background-color: #f8f9fd; + overflow-x: hidden; + width: 100%; +} + +.pad-header { + padding: 1em; +} + +.pad-button { + margin-bottom: 0.5em; +} + +.search { + display: flex; + align-items: center; +} + +.text-header { + color: #2d3578; +} + +.bg-header { + background-color: #f0f2ff !important; +} + +.text-right { + text-align: right; +} + +.bg-status-1 { + background-color: #ffffff; +} + +.bg-status-2 { + background-color: #dce5f4; +} + +.neu-button { + background-color: #f5f5f5; + border-radius: 20px; + box-shadow: inset 4px 4px 10px #88a5bf7b, inset -4px -4px 10px #ffffff; + /*color: #4d4d4d;*/ + cursor: pointer; + font-size: 16px; + /*padding: 15px 40px;*/ + transition: all 0.2s ease-in-out; + border: 1px solid #88a5bf7b; +} + +.neu-button:hover { + box-shadow: inset 2px 2px 5px #bcbcbc, inset -2px -2px 5px #ffffff, 2px 2px 5px #bcbcbc, -2px -2px 5px #ffffff; +} + +.neu-button:focus { + outline: none; + box-shadow: inset 2px 2px 5px #bcbcbc, inset -2px -2px 5px #ffffff, 2px 2px 5px #bcbcbc, -2px -2px 5px #ffffff; +} + +.btn-round-basic:focus { + background-color: #f5f5f5; + border-radius: 20px; + box-shadow: inset 4px 4px 10px #88a5bf7b, inset -4px -4px 10px #ffffff; + color: #4d4d4d; + cursor: pointer; + font-size: 16px; + transition: all 0.2s ease-in-out; + border: 1px solid #88a5bf7b; +} + +.btn-round-basic { + border-radius: 20px; + box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px; + --bs-btn-hover-bg: #ffffff; +} + +.btn-round-basic:hover { + outline: none; + box-shadow: inset 2px 2px 5px #bcbcbc, inset -2px -2px 5px #ffffff, 2px 2px 5px #bcbcbc, -2px -2px 5px #ffffff; +} + +.color-import { + color: var(--bs-teal); +} + +.color-remove { + color: var(--bs-danger); +} + +.color-edit { + color: var(--bs-primary-text-emphasis); +} + +.color-add { + color: var(--bs-primary); +} + +.input-login { + border-radius: 50px; + box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; +} + +.btn-login { + border-radius: 20px; + box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px; + --bs-btn-hover-bg: #5780f2; + background-color: #5278e1; +} + +.input-add { + border-radius: 8px; + padding: .375rem .75rem; + margin: 0.3rem 0; +} + +.text-add { + margin: 0.6rem 0; +} + +.display-show { + display: block; +} + +.class25 { + width: 25%; +} + +.card-login { + background-color: white; + box-shadow: rgba(0, 0, 0, 0.15) 0px 15px 25px, rgba(0, 0, 0, 0.05) 0px 5px 10px; + border-radius: 20px; + border: none; +} + +.icon-menu { + color: #2c316d; +} + +.text-menu { + color: #2c316d !important; +} + +nav-item:hover { + background-color: #2d3578; + color: white; +} + +nav-item:focus { + background-color: #4450b1; + color: white; +} + +.img-indicator { + display: block; + margin-left: auto; + max-width: 100%; +} + +.font-top-menu { + font-size: 2em!important; + font-weight: 200; + padding-left: 0.5em; +} + +.card-status { + background-color: var(--card-color); + box-shadow: rgba(0, 0, 0, 0.1) -4px 9px 25px -6px; + text-align: center; + width: 100%; + padding: 15px; + margin: 10px; + border-radius: 8px; + cursor: pointer; + margin-bottom: 0rem; +} + +.text-status { + margin-bottom: 0rem !important; +} + +.pad-container { + padding-top: 1em; +} + +.bread-menu { + background: #2d3578; + border: none; +} + diff --git a/html/webpage/assets/img/logogtc-grey.png b/html/webpage/assets/img/logogtc-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9e412ca28fd55645e9efc2a316befd2bf2ee7b GIT binary patch literal 55099 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

x3YvI6SxVPu?wF4HUg%4;254=df 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 E09o||)&Kwi literal 0 HcmV?d00001 diff --git a/html/webpage/assets/js/script.js b/html/webpage/assets/js/script.js index a1497fd..bd53ee3 100644 --- a/html/webpage/assets/js/script.js +++ b/html/webpage/assets/js/script.js @@ -50,188 +50,580 @@ * @property {string} description */ -$(document).ready(function () { - document.title = "Automatic Announcement System" - $('#onlineindicator').attr('src', '/assets/img/red_circle.png'); +/** + * @typedef {Object} Select2item + * @property {number} id + * @property {string} text + */ - let soundbankdata = []; - let selectedsoundrow = null; - let messagebankdata = []; - let selectedmessagerow = null; - let languagebankdata = []; - let selectedlanguagerow = null; - let schedulebankdata = []; - let selectedschedulerow = null; - let logdata = []; +/** + * List of Soundbank data loaded from server + * @type {SoundBank[]} + */ +let soundbankdata = []; +/** + * Currently selected soundbank row in the table + * @type {JQuery|null} + */ +let selectedsoundrow = null; +/** + * List of Messagebank data loaded from server + * @type {MessageBank[]} + */ +let messagebankdata = []; +/** + * Currently selected messagebank row in the table + * @type {JQuery|null} + */ +let selectedmessagerow = null; +/** List of Languagebank data loaded from server + * @type {LanguageBank[]} + */ +let languagebankdata = []; +/** + * Currently selected languagebank row in the table + * @type {JQuery|null} + */ +let selectedlanguagerow = null; +/** List of Schedulebank data loaded from server + * @type {ScheduleBank[]} + */ +let schedulebankdata = []; +/** + * Currently selected schedulebank row in the table + * @type {JQuery|null} + */ +let selectedschedulerow = null; +/** List of Log data loaded from server + * @type {Log[]} + */ +let logdata = []; +/** + * List of sound files in the soundbank directory, that ends with .wav or .mp3 + * @type {string[]} + */ +let soundbankfiles = []; +/** + * Select2 data source + * See https://select2.org/data-sources/formats + * @type {Object} + * @property {Select2item[]} results + */ +let select2results = { + results: [] +}; - /** +/** + * List of voice types available + * @type {string[]} + */ +let voiceTypes = []; +/** + * List of categories available + * @type {string[]} + */ +let categories = []; +/** + * List of languages available + * @type {string[]} + */ +let languages = []; + +/** + * List of scheduled days available + * @type {string[]} + */ +let scheduledays = [] + + +/** * 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; - } +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 (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); - }); + } + $(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} + + $('#tablesize').text("Table Size: " + vv.length); +} + +/** + * Fill messagebank table body with values +* @param {MessageBank[]} vv values to fill +*/ +function fill_messagebanktablebody(vv) { + $('#messagebanktablebody').empty(); + if (!Array.isArray(vv) || vv.length === 0) return; + 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; - } + $('#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); - }); + } + $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; - } + 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(); + if (!Array.isArray(vv) || vv.length === 0) return; + 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); - }); + } + $addedrow.find('td').css('background-color', '#ffeeba'); + selectedlanguagerow = $addedrow; + $('#btnRemove').prop('disabled', false); + $('#btnEdit').prop('disabled', false); }); - console.log("loaded " + vv.length + " languagebank items"); - } + }); + 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; - } +/** + * Fill schedulebank table body with values + * @param {ScheduleBank[]} vv values to fill + */ +function fill_schedulebanktablebody(vv) { + $('#schedulebanktablebody').empty(); + if (!Array.isArray(vv) || vv.length === 0) return; + 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); - }); + } + $addedrow.find('td').css('background-color', '#ffeeba'); + selectedschedulerow = $addedrow; + $('#btnRemove').prop('disabled', false); + $('#btnEdit').prop('disabled', false); }); - console.log("loaded " + vv.length + " schedulebank items"); - } + }); + 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); +/** + * Fill log table body with values + * @param {Log[]} vv values to fill + */ +function fill_logtablebody(vv) { + $('#logtablebody').empty(); + if (!Array.isArray(vv) || vv.length === 0) return; + 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"); +} + +/** + * WebSocket connection + * @type {WebSocket} + */ +let ws = null; + +/** + * 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'); + } +} + +/** + * Fetch API helper function + * @param {string} endpoint Endpoint URL + * @param {string} method Method (GET, POST, etc.) + * @param {Object} headers Headers to include in the request + * @param {Object} body Body of the request + * @param {Function} cbOK Callback function for successful response + * @param {Function} cbError Callback function for error response + */ +function fetchAPI(endpoint, method, headers = {}, body = null, cbOK, cbError) { + let url = window.location.origin + "/api/" + endpoint; + let options = { + method: method, + headers: headers + } + if (body !== null) { + options.body = JSON.stringify(body); + if (!options.headers['Content-Type']) { + options.headers['Content-Type'] = 'application/json'; + } + } + console.log("About to fetch from " + url + " with options", options); + fetch(url, options) + .then(response => { + console.log("fetchAPI: received response", response); + if (!response.ok) { + throw new Error('Network response was not ok ' + response.statusText); + } + return response.json(); + }) + .then(data => { + console.log("fetchAPI: received data", data); + cbOK(data); + }) + .catch(error => { + console.error('There was a problem with the fetch operation:', error); + cbError(error); }); - console.log("loaded " + vv.length + " log items"); - } +} + +/** + * Reload sound bank from server + * @param {String} APIURL API URL endpoint + */ +function reloadSoundBank(APIURL) { + soundbankdata = []; + console.log("reloadSoundBank: fetching from " + APIURL + "List"); + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + console.log("reloadSoundBank: received data", okdata); + if (Array.isArray(okdata)) { + soundbankdata = okdata; + selectedsoundrow = null; + fill_soundbanktablebody(soundbankdata); + } + }, (errdata) => { + alert("Error loading soundbank: " + errdata.message); + }); +} + +/** +* Reload message bank from server +* @param {string} APIURL API URL endpoint +*/ +function reloadMessageBank(APIURL) { + messagebankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + messagebankdata = okdata; + selectedmessagerow = null; + fill_messagebanktablebody(messagebankdata); + } + }, (errdata) => { + alert("Error loading messagebank: " + errdata.message); + }); +} + +/** + * Reload language bank from server + * @param {string} APIURL API URL endpoint + */ +function reloadLanguageBank(APIURL) { + languagebankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + languagebankdata = okdata; + selectedlanguagerow = null; + fill_languagebanktablebody(languagebankdata); + } + }, (errdata) => { + alert("Error loading languagebank: " + errdata.message); + }); +} + +/** + * Reload timer bank from server + * @param {string} APIURL API URL endpoint + */ +function reloadTimerBank(APIURL) { + schedulebankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + schedulebankdata = okdata.data; + selectedschedulerow = null; + fill_schedulebanktablebody(schedulebankdata); + } + }, (errdata) => { + alert("Error loading schedulebank: " + errdata.message); + }); +} + +/** + * Reload logs from server with date and filter + * @param {String} APIURL API URL endpoint + * @param {String} date date in format dd/MM/yyyy + * @param {String} filter log filter text + */ +function reloadLogs(APIURL, date, filter) { + fetchAPI(APIURL + "List/" + date + "/" + filter, "GET", {}, null, (okdata) => { + $('#logcontent').val(okdata.data); + }, (errdata) => { + alert("Error loading logs: " + errdata.message); + }); +} + +/** + * Reload soundbank files from server + * @param {String} APIURL API URL endpoint (default "SoundBank/") + */ +function regetSoundbankFiles(APIURL = "SoundBank/") { + soundbankfiles = []; + fetchAPI(APIURL + "ListFiles", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + soundbankfiles = okdata.filter(item => item.trim().length > 0); + //console.log("Loaded " + soundbankfiles.length + " sound files : " + soundbankfiles.join(", ") ); + + // refill select2results + select2results.results = soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); + } else console.log("regetSoundbankFiles: okdata is not array"); + }, (errdata) => { + alert("Error loading soundbank files: " + errdata.message); + }); +} + +/** + * Reload voice types from server + */ +function getVoiceTypes() { + voiceTypes = []; + fetchAPI("VoiceType", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + voiceTypes = okdata.filter(item => item.trim().length > 0); + //console.log("Loaded " + voiceTypes.length + " voice types : " + voiceTypes.join(", ")); + } else console.log("getVoiceTypes: okdata is not array"); + }, (errdata) => { + alert("Error loading voice types: " + errdata.message); + }); +} + +/** + * Reload categories from server + */ +function getCategories() { + categories = []; + fetchAPI("Category", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + categories = okdata.filter(item => item.trim().length > 0); + //console.log("Loaded " + categories.length + " categories : " + categories.join(", ")); + } else console.log("getCategories: okdata is not array"); + }, (errdata) => { + alert("Error loading categories: " + errdata.message); + }); +} + +/** + * Reload languages from server + */ +function getLanguages() { + languages = []; + fetchAPI("Language", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + languages = okdata.filter(item => item.trim().length > 0); + //console.log("Loaded " + languages.length + " languages : " + languages.join(", ") ); + } else console.log("getLanguages: okdata is not array"); + }, (errdata) => { + alert("Error loading languages: " + errdata.message); + }); +} + +/** + * Reload scheduled days from server + */ +function getScheduledDays() { + scheduledays = []; + fetchAPI("ScheduleDay", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + scheduledays = okdata.filter(item => item.trim().length > 0); + //console.log("Loaded " + scheduledays.length + " scheduled days : " + scheduledays.join(", ") ); + } else console.log("getScheduledDays: okdata is not array"); + }, (errdata) => { + alert("Error loading scheduled days: " + errdata.message); + }); +} + +/** + * Export mechanism to XLSX file + * @param {String} APIURL API URL endpoint + * @param {String} filename target filename + */ +function DoExport(APIURL, filename) { + // send GET request to APIURL + "ExportXLSX" + // reply Content-Type is application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + // reply Content-Disposition: attachment; filename=filename + // Use fetch to download the XLSX file as a blob and trigger download + fetch("/api/" + APIURL + "ExportXLSX", { + method: "GET", + headers: {} + }) + .then(response => { + if (!response.ok) throw new Error('Network response was not ok ' + response.statusText); + return response.blob(); + }) + .then(blob => { + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + a.remove(); + window.URL.revokeObjectURL(url); + }) + .catch(error => { + alert("Error export to " + filename + ": " + error.message); + }); + return; // prevent the rest of the function from running - const ws = new WebSocket(window.location.pathname + '/ws'); + +} +/** + * Import mechanism from XLSX file + * @param {String} APIURL API URL endpoint + * @param {Function} cbOK function that accept object data + * @param {Function} cbError function that accept error object + */ +function DoImport(APIURL, cbOK, cbError) { + // Open file selection dialog that accepts only .xlsx files + // then upload to server using fetchAPI at "api/ImportXLSX" with POST method + let fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = '.xlsx'; + fileInput.onchange = e => { + let file = e.target.files[0]; + if (file) { + let formData = new FormData(); + formData.append('file', file); + fetch("/api/" + APIURL + "ImportXLSX", { method: 'POST', body: formData }) + .then(response => { + if (!response.ok) { throw new Error('Network response was not ok ' + response.statusText); } + return response.json(); + }) + .then(data => { + cbOK(data); + }) + .catch(error => { + cbError(error); + }); + } else { + cbError(new Error("No file selected")); + } + }; + fileInput.click(); + fileInput.remove(); +} + + +/** + * App entry point + */ +$(document).ready(function () { + document.title = "Automatic Announcement System" + $('#onlineindicator').attr('src', '/assets/img/red_circle.png'); + getVoiceTypes(); + getCategories(); + getLanguages(); + getScheduledDays(); + regetSoundbankFiles(); + + // Initialize WebSocket connection + ws = new WebSocket(window.location.pathname + '/ws'); ws.onopen = () => { console.log('WebSocket connection established'); @@ -258,99 +650,7 @@ $(document).ready(function () { 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; } } }; @@ -362,18 +662,7 @@ $(document).ready(function () { // 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", "") @@ -386,7 +675,14 @@ $(document).ready(function () { let sidemenu = new bootstrap.Offcanvas('#offcanvas-menu'); $('#showmenu').click(() => { sidemenu.show(); }) - + $('#homelink').click(() => { + sidemenu.hide(); + $('#content').load('overview.html', function (response, status, xhr) { + if (status === "success") { + console.log("Overview content loaded successfully"); + } + }); + }); $('#soundbanklink').click(() => { sidemenu.hide(); $('#content').load('soundbank.html', function (response, status, xhr) { @@ -395,30 +691,45 @@ $(document).ready(function () { // 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 + let $btnClear = $('#btnClear'); + let $btnAdd = $('#btnAdd'); + let $btnRemove = $('#btnRemove'); + let $btnEdit = $('#btnEdit'); + let $btnExport = $('#btnExport'); + let $btnImport = $('#btnImport'); + let $modal = $('#soundbankmodal'); $btnRemove.prop('disabled', true); $btnEdit.prop('disabled', true); + let APIURL = "SoundBank/"; - - - - sendCommand("getSoundBankList", ""); - $('#btnClear').click(() => { + reloadSoundBank(APIURL); + $btnClear.click(() => { if (confirm(`Are you sure want to clear Soundbank ? This procedure is not reversible`)) { - sendCommand("clearSoundBank", ""); + fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => { + alert("Success clear soundbank" + okdata.message); + soundbankdata = [] + selectedsoundrow = null; + fill_soundbanktablebody(soundbankdata); + }, (errdata) => { + alert("Error clear soundbank: " + errdata.message); + }); } }); - $('#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) + $btnAdd.click(() => { + $('.js-example-basic-single').select2({ + placeholder: 'Select a sound file', + closeOnSelect: true, + data: select2results, + }); + $modal.modal('show'); + // event on Click save button + $modal.off('click.soundbanksave').on('click.soundbanksave', '#soundbanksave', function () { + $modal.modal('hide'); + }); + // event on Click close button + $modal.off('click.soundbankclose').on('click.soundbankclose', '#soundbankclose', function () { + $modal.modal('hide'); }); }); $btnRemove.click(() => { @@ -435,7 +746,14 @@ $(document).ready(function () { path: cells.eq(6).text() } if (confirm(`Are you sure to delete soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { - sendCommand("deleteSoundBank", sb); + fetchAPI(APIURL + "DeleteByIndex/" + sb.index, "DELETE", {}, null, (okdata) => { + alert("Success delete soundbank" + okdata.message); + soundbankdata = soundbankdata.filter(item => item.index !== sb.index); + selectedsoundrow = null; + fill_soundbanktablebody(soundbankdata); + }, (errdata) => { + alert("Error delete soundbank: " + errdata.message); + }); } } }); @@ -453,7 +771,7 @@ $(document).ready(function () { path: cells.eq(6).text() } if (confirm(`Are you sure to edit soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { - modal.show(); + $modal.modal('show'); $modal.off('hidden.bs.modal').on('hidden.bs.modal', function () { const desc = $('#description').val(); console.log('Description input value:', desc); @@ -462,11 +780,15 @@ $(document).ready(function () { } } }); - $('#btnExport').click(() => { - alert("Feature disabled for now"); + $btnExport.click(() => { + DoExport(APIURL, "soundbank.xlsx"); }); - $('#btnImport').click(() => { - alert("Feature disabled for now"); + $btnImport.click(() => { + DoImport(APIURL, (okdata) => { + reloadSoundBank(APIURL); + }, (errdata) => { + alert("Error importing soundbank from XLSX: " + errdata.message); + }); }); } else { console.error("Error loading soundbank content:", xhr.status, xhr.statusText); @@ -482,19 +804,46 @@ $(document).ready(function () { // initialize first state of buttons and text input $('#messagebanktablebody').empty(); selectedmessagerow = 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 = "MessageBank/"; - sendCommand("getMessageBankList", ""); - $('#btnClear').click(() => { + + reloadMessageBank(APIURL); + $btnClear.click(() => { if (confirm(`Are you sure want to clear Messagebank ? This procedure is not reversible`)) { - sendCommand("clearMessageBank", ""); + fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => { + alert("Success clear messagebank" + okdata.message); + messagebankdata = [] + selectedmessagerow = null; + fill_messagebanktablebody(messagebankdata); + }, (errdata) => { + alert("Error clear messagebank: " + errdata.message); + }); } }); - $('#btnAdd').click(() => { - //TODO form add messagebank + $btnAdd.click(() => { + let $modal = $('#messagebankmodal'); + $modal.modal('show'); + $modal.off('click.messagebanksave').on('click.messagebanksave', '#messagebanksave', function () { + const index = $('#messageindex').val(); + const description = $('#messagedescription').val(); + const language = $('#messagelanguage').val(); + const ann_id = parseInt($('#messageannid').val()); + const voice_type = $('#messagevoicetype').val(); + + + $modal.modal('hide'); + }); + $modal.off('click.messagebankclose').on('click.messagebankclose', '#messagebankclose', function () { + $modal.modal('hide'); + }); }); $btnRemove.click(() => { if (selectedmessagerow) { @@ -511,7 +860,14 @@ $(document).ready(function () { } 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); + fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => { + alert("Success delete messagebank" + okdata.message); + messagebankdata = messagebankdata.filter(item => item.index !== mb.index); + selectedmessagerow = null; + fill_messagebanktablebody(messagebankdata); + }, (errdata) => { + alert("Error delete messagebank: " + errdata.message); + }); } } }); @@ -533,11 +889,15 @@ $(document).ready(function () { } } }); - $('#btnExport').click(() => { - alert("Feature disabled for now"); + $btnExport.click(() => { + DoExport(APIURL, "messagebank.xlsx"); }); - $('#btnImport').click(() => { - alert("Feature disabled for now"); + $btnImport.click(() => { + DoImport(APIURL, (okdata) => { + reloadMessageBank(APIURL); + }, (errdata) => { + alert("Error importing messagebank from XLSX: " + errdata.message); + }); }); } else { console.error("Error loading messagebank content:", xhr.status, xhr.statusText); @@ -553,19 +913,74 @@ $(document).ready(function () { // initialize first state of buttons and text input $('#languagebanktablebody').empty(); selectedlanguagerow = 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 = "LanguageBank/"; - sendCommand("getLanguageList", ""); - $('#btnClear').click(() => { + + + reloadLanguageBank(APIURL); + $btnClear.click(() => { if (confirm(`Are you sure want to clear Languagebank ? This procedure is not reversible`)) { - sendCommand("clearLanguageBank", ""); + fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => { + alert("Success clear languagebank" + okdata.message); + languagebankdata = [] + selectedlanguagerow = null; + fill_languagebanktablebody(languagebankdata); + }, (errdata) => { + alert("Error clear languagebank: " + errdata.message); + }); } }); - $('#btnAdd').click(() => { - //TODO form add language + $btnAdd.click(() => { + // show modal with id 'languagemodal' + let $modal = $('#languagemodal'); + $modal.modal('show'); + // save button click event + $modal.off('click.languagelinksave').on('click.languagelinksave', '#languagelinksave', function () { + const tag = $('#languagelinktag').val(); + const langs = []; + if ($('#langID').is(':checked')) langs.push('INDONESIA'); + if ($('#langLocal').is(':checked')) langs.push('LOCAL'); + if ($('#langEN').is(':checked')) langs.push('ENGLISH'); + if ($('#langARB').is(':checked')) langs.push('ARABIC'); + if ($('#langJAP').is(':checked')) langs.push('JAPANESE'); + if ($('#langCHI').is(':checked')) langs.push('CHINESE'); + + if (tag.length === 0) { + alert("Tag cannot be empty"); + return; + } + if (langs.length === 0) { + alert("At least one language must be selected"); + return; + } + + const langString = langs.join(';'); + let ll = { + tag: tag, + language: langString + } + fetchAPI(APIURL + "Add", "POST", {}, ll, (okdata) => { + alert("Success add language" + okdata.message); + reloadLanguageBank(APIURL); + }, (errdata) => { + alert("Error add language: " + errdata.message); + }); + $modal.modal('hide'); + + + }); + // close button click event + $modal.off('click.languagelinkclose').on('click.languagelinkclose', '#languagelinkclose', function () { + $modal.modal('hide'); + }); }); $btnRemove.click(() => { if (selectedlanguagerow) { @@ -577,7 +992,14 @@ $(document).ready(function () { language: cells.eq(2).text() } if (confirm(`Are you sure to delete language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { - sendCommand("deleteLanguage", ll); + fetchAPI(APIURL + "DeleteByIndex/" + ll.index, "DELETE", {}, null, (okdata) => { + alert("Success delete language" + okdata.message); + languagebankdata = languagebankdata.filter(item => item.index !== ll.index); + selectedlanguagerow = null; + fill_languagebanktablebody(languagebankdata); + }, (errdata) => { + alert("Error delete language: " + errdata.message); + }); } } }); @@ -591,15 +1013,73 @@ $(document).ready(function () { 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 + let $modal = $('#languagemodal'); + $modal.find('#languagelinkindex').val(ll.index); + $modal.find('#languagelinktag').val(ll.tag); + let langs = ll.language.split(';'); + $modal.find('#langID').prop('checked', langs.includes('INDONESIA')); + $modal.find('#langLocal').prop('checked', langs.includes('LOCAL')); + $modal.find('#langEN').prop('checked', langs.includes('ENGLISH')); + $modal.find('#langARB').prop('checked', langs.includes('ARABIC')); + $modal.find('#langJAP').prop('checked', langs.includes('JAPANESE')); + $modal.find('#langCHI').prop('checked', langs.includes('CHINESE')); + $modal.modal('show'); + // save button click event + $modal.off('click.languagelinksave').on('click.languagelinksave', '#languagelinksave', function () { + const tag = $('#languagelinktag').val(); + const langs = []; + if ($('#langID').is(':checked')) langs.push('INDONESIA'); + if ($('#langLocal').is(':checked')) langs.push('LOCAL'); + if ($('#langEN').is(':checked')) langs.push('ENGLISH'); + if ($('#langARB').is(':checked')) langs.push('ARABIC'); + if ($('#langJAP').is(':checked')) langs.push('JAPANESE'); + if ($('#langCHI').is(':checked')) langs.push('CHINESE'); + if (tag.length === 0) { + alert("Tag cannot be empty"); + return; + } + if (langs.length === 0) { + alert("At least one language must be selected"); + return; + } + const langString = langs.join(';'); + if (ll.tag === tag && ll.language === langString) { + alert("No changes detected"); + $modal.modal('hide'); + return; + } + + ll.tag = tag; + ll.language = langString; + fetchAPI(APIURL + "UpdateByIndex/" + ll.index, "PATCH", {}, ll, (okdata) => { + alert("Success edit language" + okdata.message); + reloadLanguageBank(APIURL); + }, (errdata) => { + alert("Error edit language: " + errdata.message); + }); + + $modal.modal('hide'); + }); + // close button click event + $modal.off('click.languagelinkclose').on('click.languagelinkclose', '#languagelinkclose', function () { + $modal.modal('hide'); + }); + + } } }); - $('#btnExport').click(() => { - alert("Feature disabled for now"); + $btnExport.click(() => { + DoExport(APIURL, "languagebank.xlsx"); + }); - $('#btnImport').click(() => { - alert("Feature disabled for now"); + $btnImport.click(() => { + DoImport(APIURL, (okdata) => { + reloadLanguageBank(APIURL); + }, (errdata) => { + alert("Error importing languagebank from XLSX: " + errdata.message); + }); + }); } else { console.error("Error loading language content:", xhr.status, xhr.statusText); @@ -614,18 +1094,31 @@ $(document).ready(function () { // initialize first state of buttons and text input $('#schedulebanktablebody').empty(); selectedschedulerow = null; + let $btnClear = $('#btnClear'); + let $btnAdd = $('#btnAdd'); let $btnEdit = $('#btnEdit'); let $btnRemove = $('#btnRemove'); + let $btnExport = $('#btnExport'); + let $btnImport = $('#btnImport'); $btnEdit.prop('disabled', true); $btnRemove.prop('disabled', true); + let APIURL = "ScheduleBank/"; - sendCommand("getTimerList", ""); - $('#btnClear').click(() => { + + reloadTimerBank(APIURL); + $btnClear.click(() => { if (confirm(`Are you sure want to clear Timerbank ? This procedure is not reversible`)) { - sendCommand("clearTimerBank", ""); + fetchAPI(APIURL + "List", "DELETE", {}, null, (okdata) => { + alert("Success clear schedulebank" + okdata.message); + schedulebankdata = [] + selectedschedulerow = null; + fill_schedulebanktablebody(schedulebankdata); + }, (errdata) => { + alert("Error clear schedulebank: " + errdata.message); + }); } }); - $('#btnAdd').click(() => { + $btnAdd.click(() => { //TODO form add timer }); $btnRemove.click(() => { @@ -644,7 +1137,14 @@ $(document).ready(function () { language: cells.eq(8).text() } if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { - sendCommand("deleteSchedule", sr); + fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => { + alert("Success delete schedule" + okdata.message); + schedulebankdata = schedulebankdata.filter(item => item.index !== sr.index); + selectedtimerow = null; + fill_schedulebanktablebody(schedulebankdata); + }, (errdata) => { + alert("Error delete schedule: " + errdata.message); + }); } } }); @@ -668,11 +1168,15 @@ $(document).ready(function () { } } }); - $('#btnExport').click(() => { - alert("Feature disabled for now"); + $btnExport.click(() => { + DoExport(APIURL, "schedulebank.xlsx"); }); - $('#btnImport').click(() => { - alert("Feature disabled for now"); + $btnImport.click(() => { + DoImport(APIURL, (okdata) => { + reloadTimerBank(APIURL); + }, (errdata) => { + alert("Error importing schedulebank from XLSX: " + errdata.message); + }); }); } else { console.error("Error loading timer content:", xhr.status, xhr.statusText); @@ -686,39 +1190,44 @@ $(document).ready(function () { console.log("Log content loaded successfully"); const $logdate = $('#logdate'); const $searchfilter = $('#searchfilter'); + let selectedlogdate = ""; + let logfilter = ""; + let APIURL = "/api/Logs/"; + + 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}`); + selectedlogdate = `${dd}/${mm}/${yyyy}`; } $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())); + selectedlogdate = `${day}/${month}/${year}`; + reloadLogs(APIURL, selectedlogdate, logfilter); } }); - const selected = $logdate.val(); - if (selected) { - const [year, month, day] = selected.split('-'); - const formatted = `${day}/${month}/${year}`; - sendCommand("getLog", logRequstData(formatted, $searchfilter.val())); - } + + $searchfilter.off('input').on('input', function () { + logfilter = $(this).val(); + reloadLogs(APIURL, selectedlogdate, logfilter); + }); + } 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", ""); + //sendCommand("getSetting", ""); } else { console.error("Error loading setting content:", xhr.status, xhr.statusText); } diff --git a/html/webpage/assets/js/select2.js b/html/webpage/assets/js/select2.js new file mode 100644 index 0000000..fcfb5ab --- /dev/null +++ b/html/webpage/assets/js/select2.js @@ -0,0 +1,6108 @@ +/*! + * Select2 4.0.13 + * https://select2.github.io + * + * Released under the MIT license + * https://github.com/select2/select2/blob/master/LICENSE.md + */ +;(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function (root, jQuery) { + if (jQuery === undefined) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if (typeof window !== 'undefined') { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + factory(jQuery); + return jQuery; + }; + } else { + // Browser globals + factory(jQuery); + } +} (function (jQuery) { + // This is needed so we can catch the AMD loader configuration and use it + // The inner file should be wrapped (by `banner.start.js`) in a function that + // returns the AMD loader references. + var S2 =(function () { + // Restore the Select2 AMD loader so it can be used + // Needed mostly in the language files, where the loader is not inserted + if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) { + var S2 = jQuery.fn.select2.amd; + } +var S2;(function () { if (!S2 || !S2.requirejs) { +if (!S2) { S2 = {}; } else { require = S2; } +/** + * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. + * Released under MIT license, http://github.com/requirejs/almond/LICENSE + */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. +/*global setTimeout: false */ + +var requirejs, require, define; +(function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, + foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, + baseParts = baseName && baseName.split("/"), + map = config.map, + starMap = (map && map['*']) || {}; + + //Adjust any relative paths. + if (name) { + name = name.split('/'); + lastIndex = name.length - 1; + + // If wanting node ID compatibility, strip .js from end + // of IDs. Have to do this here, and not in nameToUrl + // because node allows either .js or non .js to map + // to same file. + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + // Starts with a '.' so need the baseName + if (name[0].charAt(0) === '.' && baseParts) { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + name = normalizedBaseParts.concat(name); + } + + //start trimDots + for (i = 0; i < name.length; i++) { + part = name[i]; + if (part === '.') { + name.splice(i, 1); + i -= 1; + } else if (part === '..') { + // If at the start, or previous value is still .., + // keep them so that when converted to a path it may + // still work when converted to a path, even though + // as an ID it is less than ideal. In larger point + // releases, may be better to just kick out an error. + if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') { + continue; + } else if (i > 0) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + //end trimDots + + name = name.join('/'); + } + + //Apply map config if available. + if ((baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function makeRequire(relName, forceSync) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + var args = aps.call(arguments, 0); + + //If first arg is not require('string'), and there is only + //one arg, it is the array form without a callback. Insert + //a null so that the following concat is correct. + if (typeof args[0] !== 'string' && args.length === 1) { + args.push(null); + } + return req.apply(undef, args.concat([relName, forceSync])); + }; + } + + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(depName) { + return function (value) { + defined[depName] = value; + }; + } + + function callDep(name) { + if (hasProp(waiting, name)) { + var args = waiting[name]; + delete waiting[name]; + defining[name] = true; + main.apply(undef, args); + } + + if (!hasProp(defined, name) && !hasProp(defining, name)) { + throw new Error('No ' + name); + } + return defined[name]; + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + //Creates a parts array for a relName where first part is plugin ID, + //second part is resource ID. Assumes relName has already been normalized. + function makeRelParts(relName) { + return relName ? splitPrefix(relName) : []; + } + + /** + * Makes a name map, normalizing the name, and using a plugin + * for normalization if necessary. Grabs a ref to plugin + * too, as an optimization. + */ + makeMap = function (name, relParts) { + var plugin, + parts = splitPrefix(name), + prefix = parts[0], + relResourceName = relParts[1]; + + name = parts[1]; + + if (prefix) { + prefix = normalize(prefix, relResourceName); + plugin = callDep(prefix); + } + + //Normalize according + if (prefix) { + if (plugin && plugin.normalize) { + name = plugin.normalize(name, makeNormalize(relResourceName)); + } else { + name = normalize(name, relResourceName); + } + } else { + name = normalize(name, relResourceName); + parts = splitPrefix(name); + prefix = parts[0]; + name = parts[1]; + if (prefix) { + plugin = callDep(prefix); + } + } + + //Using ridiculous property names for space reasons + return { + f: prefix ? prefix + '!' + name : name, //fullName + n: name, + pr: prefix, + p: plugin + }; + }; + + function makeConfig(name) { + return function () { + return (config && config.config && config.config[name]) || {}; + }; + } + + handlers = { + require: function (name) { + return makeRequire(name); + }, + exports: function (name) { + var e = defined[name]; + if (typeof e !== 'undefined') { + return e; + } else { + return (defined[name] = {}); + } + }, + module: function (name) { + return { + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) + }; + } + }; + + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, relParts, + args = [], + callbackType = typeof callback, + usingExports; + + //Use name if no relName + relName = relName || name; + relParts = makeRelParts(relName); + + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + //Default to [require, exports, module] if no deps + deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; + for (i = 0; i < deps.length; i += 1) { + map = makeMap(deps[i], relParts); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } + } + + ret = callback ? callback.apply(defined[name], args) : undefined; + + if (name) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } + } + } else if (name) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + defined[name] = callback; + } + }; + + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { + if (handlers[deps]) { + //callback in this case is really relName + return handlers[deps](callback); + } + //Just return the module wanted. In this scenario, the + //deps arg is the module name, and second arg (if passed) + //is just the relName. + //Normalize module name, if it contains . or .. + return callDep(makeMap(deps, makeRelParts(callback)).f); + } else if (!deps.splice) { + //deps is a config object, not an array. + config = deps; + if (config.deps) { + req(config.deps, config.callback); + } + if (!callback) { + return; + } + + if (callback.splice) { + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; + } else { + deps = undef; + } + } + + //Support require(['a']) + callback = callback || function () {}; + + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { + relName = forceSync; + forceSync = alt; + } + + //Simulate async callback; + if (forceSync) { + main(undef, deps, callback, relName); + } else { + //Using a non-zero value because of concern for what old browsers + //do, and latest browsers "upgrade" to 4 if lower value is used: + //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: + //If want a value immediately, use require('id') instead -- something + //that works in almond on the global level, but not guaranteed and + //unlikely to work in other AMD implementations. + setTimeout(function () { + main(undef, deps, callback, relName); + }, 4); + } + + return req; + }; + + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; + + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; + + define = function (name, deps, callback) { + if (typeof name !== 'string') { + throw new Error('See almond README: incorrect module build, no module name'); + } + + //This module may not have dependencies + if (!deps.splice) { + //deps is not an array, so probably means + //an object literal or factory function for + //the value. Adjust args. + callback = deps; + deps = []; + } + + if (!hasProp(defined, name) && !hasProp(waiting, name)) { + waiting[name] = [name, deps, callback]; + } + }; + + define.amd = { + jQuery: true + }; +}()); + +S2.requirejs = requirejs;S2.require = require;S2.define = define; +} +}()); +S2.define("almond", function(){}); + +/* global jQuery:false, $:false */ +S2.define('jquery',[],function () { + var _$ = jQuery || $; + + if (_$ == null && console && console.error) { + console.error( + 'Select2: An instance of jQuery or a jQuery-compatible library was not ' + + 'found. Make sure that you are including jQuery before Select2 on your ' + + 'web page.' + ); + } + + return _$; +}); + +S2.define('select2/utils',[ + 'jquery' +], function ($) { + var Utils = {}; + + Utils.Extend = function (ChildClass, SuperClass) { + var __hasProp = {}.hasOwnProperty; + + function BaseConstructor () { + this.constructor = ChildClass; + } + + for (var key in SuperClass) { + if (__hasProp.call(SuperClass, key)) { + ChildClass[key] = SuperClass[key]; + } + } + + BaseConstructor.prototype = SuperClass.prototype; + ChildClass.prototype = new BaseConstructor(); + ChildClass.__super__ = SuperClass.prototype; + + return ChildClass; + }; + + function getMethods (theClass) { + var proto = theClass.prototype; + + var methods = []; + + for (var methodName in proto) { + var m = proto[methodName]; + + if (typeof m !== 'function') { + continue; + } + + if (methodName === 'constructor') { + continue; + } + + methods.push(methodName); + } + + return methods; + } + + Utils.Decorate = function (SuperClass, DecoratorClass) { + var decoratedMethods = getMethods(DecoratorClass); + var superMethods = getMethods(SuperClass); + + function DecoratedClass () { + var unshift = Array.prototype.unshift; + + var argCount = DecoratorClass.prototype.constructor.length; + + var calledConstructor = SuperClass.prototype.constructor; + + if (argCount > 0) { + unshift.call(arguments, SuperClass.prototype.constructor); + + calledConstructor = DecoratorClass.prototype.constructor; + } + + calledConstructor.apply(this, arguments); + } + + DecoratorClass.displayName = SuperClass.displayName; + + function ctr () { + this.constructor = DecoratedClass; + } + + DecoratedClass.prototype = new ctr(); + + for (var m = 0; m < superMethods.length; m++) { + var superMethod = superMethods[m]; + + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; + } + + var calledMethod = function (methodName) { + // Stub out the original method if it's not decorating an actual method + var originalMethod = function () {}; + + if (methodName in DecoratedClass.prototype) { + originalMethod = DecoratedClass.prototype[methodName]; + } + + var decoratedMethod = DecoratorClass.prototype[methodName]; + + return function () { + var unshift = Array.prototype.unshift; + + unshift.call(arguments, originalMethod); + + return decoratedMethod.apply(this, arguments); + }; + }; + + for (var d = 0; d < decoratedMethods.length; d++) { + var decoratedMethod = decoratedMethods[d]; + + DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod); + } + + return DecoratedClass; + }; + + var Observable = function () { + this.listeners = {}; + }; + + Observable.prototype.on = function (event, callback) { + this.listeners = this.listeners || {}; + + if (event in this.listeners) { + this.listeners[event].push(callback); + } else { + this.listeners[event] = [callback]; + } + }; + + Observable.prototype.trigger = function (event) { + var slice = Array.prototype.slice; + var params = slice.call(arguments, 1); + + this.listeners = this.listeners || {}; + + // Params should always come in as an array + if (params == null) { + params = []; + } + + // If there are no arguments to the event, use a temporary object + if (params.length === 0) { + params.push({}); + } + + // Set the `_type` of the first object to the event + params[0]._type = event; + + if (event in this.listeners) { + this.invoke(this.listeners[event], slice.call(arguments, 1)); + } + + if ('*' in this.listeners) { + this.invoke(this.listeners['*'], arguments); + } + }; + + Observable.prototype.invoke = function (listeners, params) { + for (var i = 0, len = listeners.length; i < len; i++) { + listeners[i].apply(this, params); + } + }; + + Utils.Observable = Observable; + + Utils.generateChars = function (length) { + var chars = ''; + + for (var i = 0; i < length; i++) { + var randomChar = Math.floor(Math.random() * 36); + chars += randomChar.toString(36); + } + + return chars; + }; + + Utils.bind = function (func, context) { + return function () { + func.apply(context, arguments); + }; + }; + + Utils._convertData = function (data) { + for (var originalKey in data) { + var keys = originalKey.split('-'); + + var dataLevel = data; + + if (keys.length === 1) { + continue; + } + + for (var k = 0; k < keys.length; k++) { + var key = keys[k]; + + // Lowercase the first letter + // By default, dash-separated becomes camelCase + key = key.substring(0, 1).toLowerCase() + key.substring(1); + + if (!(key in dataLevel)) { + dataLevel[key] = {}; + } + + if (k == keys.length - 1) { + dataLevel[key] = data[originalKey]; + } + + dataLevel = dataLevel[key]; + } + + delete data[originalKey]; + } + + return data; + }; + + Utils.hasScroll = function (index, el) { + // Adapted from the function created by @ShadowScripter + // and adapted by @BillBarry on the Stack Exchange Code Review website. + // The original code can be found at + // http://codereview.stackexchange.com/q/13338 + // and was designed to be used with the Sizzle selector engine. + + var $el = $(el); + var overflowX = el.style.overflowX; + var overflowY = el.style.overflowY; + + //Check both x and y declarations + if (overflowX === overflowY && + (overflowY === 'hidden' || overflowY === 'visible')) { + return false; + } + + if (overflowX === 'scroll' || overflowY === 'scroll') { + return true; + } + + return ($el.innerHeight() < el.scrollHeight || + $el.innerWidth() < el.scrollWidth); + }; + + Utils.escapeMarkup = function (markup) { + var replaceMap = { + '\\': '\', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '/': '/' + }; + + // Do not try to escape the markup if it's not a string + if (typeof markup !== 'string') { + return markup; + } + + return String(markup).replace(/[&<>"'\/\\]/g, function (match) { + return replaceMap[match]; + }); + }; + + // Append an array of jQuery nodes to a given element. + Utils.appendMany = function ($element, $nodes) { + // jQuery 1.7.x does not support $.fn.append() with an array + // Fall back to a jQuery object collection using $.fn.add() + if ($.fn.jquery.substr(0, 3) === '1.7') { + var $jqNodes = $(); + + $.map($nodes, function (node) { + $jqNodes = $jqNodes.add(node); + }); + + $nodes = $jqNodes; + } + + $element.append($nodes); + }; + + // Cache objects in Utils.__cache instead of $.data (see #4346) + Utils.__cache = {}; + + var id = 0; + Utils.GetUniqueElementId = function (element) { + // Get a unique element Id. If element has no id, + // creates a new unique number, stores it in the id + // attribute and returns the new id. + // If an id already exists, it simply returns it. + + var select2Id = element.getAttribute('data-select2-id'); + if (select2Id == null) { + // If element has id, use it. + if (element.id) { + select2Id = element.id; + element.setAttribute('data-select2-id', select2Id); + } else { + element.setAttribute('data-select2-id', ++id); + select2Id = id.toString(); + } + } + return select2Id; + }; + + Utils.StoreData = function (element, name, value) { + // Stores an item in the cache for a specified element. + // name is the cache key. + var id = Utils.GetUniqueElementId(element); + if (!Utils.__cache[id]) { + Utils.__cache[id] = {}; + } + + Utils.__cache[id][name] = value; + }; + + Utils.GetData = function (element, name) { + // Retrieves a value from the cache by its key (name) + // name is optional. If no name specified, return + // all cache items for the specified element. + // and for a specified element. + var id = Utils.GetUniqueElementId(element); + if (name) { + if (Utils.__cache[id]) { + if (Utils.__cache[id][name] != null) { + return Utils.__cache[id][name]; + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } else { + return Utils.__cache[id]; + } + }; + + Utils.RemoveData = function (element) { + // Removes all cached items for a specified element. + var id = Utils.GetUniqueElementId(element); + if (Utils.__cache[id] != null) { + delete Utils.__cache[id]; + } + + element.removeAttribute('data-select2-id'); + }; + + return Utils; +}); + +S2.define('select2/results',[ + 'jquery', + './utils' +], function ($, Utils) { + function Results ($element, options, dataAdapter) { + this.$element = $element; + this.data = dataAdapter; + this.options = options; + + Results.__super__.constructor.call(this); + } + + Utils.Extend(Results, Utils.Observable); + + Results.prototype.render = function () { + var $results = $( + '
    ' + ); + + if (this.options.get('multiple')) { + $results.attr('aria-multiselectable', 'true'); + } + + this.$results = $results; + + return $results; + }; + + Results.prototype.clear = function () { + this.$results.empty(); + }; + + Results.prototype.displayMessage = function (params) { + var escapeMarkup = this.options.get('escapeMarkup'); + + this.clear(); + this.hideLoading(); + + var $message = $( + '' + ); + + var message = this.options.get('translations').get(params.message); + + $message.append( + escapeMarkup( + message(params.args) + ) + ); + + $message[0].className += ' select2-results__message'; + + this.$results.append($message); + }; + + Results.prototype.hideMessages = function () { + this.$results.find('.select2-results__message').remove(); + }; + + Results.prototype.append = function (data) { + this.hideLoading(); + + var $options = []; + + if (data.results == null || data.results.length === 0) { + if (this.$results.children().length === 0) { + this.trigger('results:message', { + message: 'noResults' + }); + } + + return; + } + + data.results = this.sort(data.results); + + for (var d = 0; d < data.results.length; d++) { + var item = data.results[d]; + + var $option = this.option(item); + + $options.push($option); + } + + this.$results.append($options); + }; + + Results.prototype.position = function ($results, $dropdown) { + var $resultsContainer = $dropdown.find('.select2-results'); + $resultsContainer.append($results); + }; + + Results.prototype.sort = function (data) { + var sorter = this.options.get('sorter'); + + return sorter(data); + }; + + Results.prototype.highlightFirstItem = function () { + var $options = this.$results + .find('.select2-results__option[aria-selected]'); + + var $selected = $options.filter('[aria-selected=true]'); + + // Check if there are any selected options + if ($selected.length > 0) { + // If there are selected options, highlight the first + $selected.first().trigger('mouseenter'); + } else { + // If there are no selected options, highlight the first option + // in the dropdown + $options.first().trigger('mouseenter'); + } + + this.ensureHighlightVisible(); + }; + + Results.prototype.setClasses = function () { + var self = this; + + this.data.current(function (selected) { + var selectedIds = $.map(selected, function (s) { + return s.id.toString(); + }); + + var $options = self.$results + .find('.select2-results__option[aria-selected]'); + + $options.each(function () { + var $option = $(this); + + var item = Utils.GetData(this, 'data'); + + // id needs to be converted to a string when comparing + var id = '' + item.id; + + if ((item.element != null && item.element.selected) || + (item.element == null && $.inArray(id, selectedIds) > -1)) { + $option.attr('aria-selected', 'true'); + } else { + $option.attr('aria-selected', 'false'); + } + }); + + }); + }; + + Results.prototype.showLoading = function (params) { + this.hideLoading(); + + var loadingMore = this.options.get('translations').get('searching'); + + var loading = { + disabled: true, + loading: true, + text: loadingMore(params) + }; + var $loading = this.option(loading); + $loading.className += ' loading-results'; + + this.$results.prepend($loading); + }; + + Results.prototype.hideLoading = function () { + this.$results.find('.loading-results').remove(); + }; + + Results.prototype.option = function (data) { + var option = document.createElement('li'); + option.className = 'select2-results__option'; + + var attrs = { + 'role': 'option', + 'aria-selected': 'false' + }; + + var matches = window.Element.prototype.matches || + window.Element.prototype.msMatchesSelector || + window.Element.prototype.webkitMatchesSelector; + + if ((data.element != null && matches.call(data.element, ':disabled')) || + (data.element == null && data.disabled)) { + delete attrs['aria-selected']; + attrs['aria-disabled'] = 'true'; + } + + if (data.id == null) { + delete attrs['aria-selected']; + } + + if (data._resultId != null) { + option.id = data._resultId; + } + + if (data.title) { + option.title = data.title; + } + + if (data.children) { + attrs.role = 'group'; + attrs['aria-label'] = data.text; + delete attrs['aria-selected']; + } + + for (var attr in attrs) { + var val = attrs[attr]; + + option.setAttribute(attr, val); + } + + if (data.children) { + var $option = $(option); + + var label = document.createElement('strong'); + label.className = 'select2-results__group'; + + var $label = $(label); + this.template(data, label); + + var $children = []; + + for (var c = 0; c < data.children.length; c++) { + var child = data.children[c]; + + var $child = this.option(child); + + $children.push($child); + } + + var $childrenContainer = $('
      ', { + 'class': 'select2-results__options select2-results__options--nested' + }); + + $childrenContainer.append($children); + + $option.append(label); + $option.append($childrenContainer); + } else { + this.template(data, option); + } + + Utils.StoreData(option, 'data', data); + + return option; + }; + + Results.prototype.bind = function (container, $container) { + var self = this; + + var id = container.id + '-results'; + + this.$results.attr('id', id); + + container.on('results:all', function (params) { + self.clear(); + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + self.highlightFirstItem(); + } + }); + + container.on('results:append', function (params) { + self.append(params.data); + + if (container.isOpen()) { + self.setClasses(); + } + }); + + container.on('query', function (params) { + self.hideMessages(); + self.showLoading(params); + }); + + container.on('select', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } + }); + + container.on('unselect', function () { + if (!container.isOpen()) { + return; + } + + self.setClasses(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } + }); + + container.on('open', function () { + // When the dropdown is open, aria-expended="true" + self.$results.attr('aria-expanded', 'true'); + self.$results.attr('aria-hidden', 'false'); + + self.setClasses(); + self.ensureHighlightVisible(); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expended="false" + self.$results.attr('aria-expanded', 'false'); + self.$results.attr('aria-hidden', 'true'); + self.$results.removeAttr('aria-activedescendant'); + }); + + container.on('results:toggle', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + $highlighted.trigger('mouseup'); + }); + + container.on('results:select', function () { + var $highlighted = self.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var data = Utils.GetData($highlighted[0], 'data'); + + if ($highlighted.attr('aria-selected') == 'true') { + self.trigger('close', {}); + } else { + self.trigger('select', { + data: data + }); + } + }); + + container.on('results:previous', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + // If we are already at the top, don't move further + // If no options, currentIndex will be -1 + if (currentIndex <= 0) { + return; + } + + var nextIndex = currentIndex - 1; + + // If none are highlighted, highlight the first + if ($highlighted.length === 0) { + nextIndex = 0; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top; + var nextTop = $next.offset().top; + var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset); + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextTop - currentOffset < 0) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:next', function () { + var $highlighted = self.getHighlightedResults(); + + var $options = self.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var nextIndex = currentIndex + 1; + + // If we are at the last option, stay there + if (nextIndex >= $options.length) { + return; + } + + var $next = $options.eq(nextIndex); + + $next.trigger('mouseenter'); + + var currentOffset = self.$results.offset().top + + self.$results.outerHeight(false); + var nextBottom = $next.offset().top + $next.outerHeight(false); + var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset; + + if (nextIndex === 0) { + self.$results.scrollTop(0); + } else if (nextBottom > currentOffset) { + self.$results.scrollTop(nextOffset); + } + }); + + container.on('results:focus', function (params) { + params.element.addClass('select2-results__option--highlighted'); + }); + + container.on('results:message', function (params) { + self.displayMessage(params); + }); + + if ($.fn.mousewheel) { + this.$results.on('mousewheel', function (e) { + var top = self.$results.scrollTop(); + + var bottom = self.$results.get(0).scrollHeight - top + e.deltaY; + + var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0; + var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height(); + + if (isAtTop) { + self.$results.scrollTop(0); + + e.preventDefault(); + e.stopPropagation(); + } else if (isAtBottom) { + self.$results.scrollTop( + self.$results.get(0).scrollHeight - self.$results.height() + ); + + e.preventDefault(); + e.stopPropagation(); + } + }); + } + + this.$results.on('mouseup', '.select2-results__option[aria-selected]', + function (evt) { + var $this = $(this); + + var data = Utils.GetData(this, 'data'); + + if ($this.attr('aria-selected') === 'true') { + if (self.options.get('multiple')) { + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } else { + self.trigger('close', {}); + } + + return; + } + + self.trigger('select', { + originalEvent: evt, + data: data + }); + }); + + this.$results.on('mouseenter', '.select2-results__option[aria-selected]', + function (evt) { + var data = Utils.GetData(this, 'data'); + + self.getHighlightedResults() + .removeClass('select2-results__option--highlighted'); + + self.trigger('results:focus', { + data: data, + element: $(this) + }); + }); + }; + + Results.prototype.getHighlightedResults = function () { + var $highlighted = this.$results + .find('.select2-results__option--highlighted'); + + return $highlighted; + }; + + Results.prototype.destroy = function () { + this.$results.remove(); + }; + + Results.prototype.ensureHighlightVisible = function () { + var $highlighted = this.getHighlightedResults(); + + if ($highlighted.length === 0) { + return; + } + + var $options = this.$results.find('[aria-selected]'); + + var currentIndex = $options.index($highlighted); + + var currentOffset = this.$results.offset().top; + var nextTop = $highlighted.offset().top; + var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset); + + var offsetDelta = nextTop - currentOffset; + nextOffset -= $highlighted.outerHeight(false) * 2; + + if (currentIndex <= 2) { + this.$results.scrollTop(0); + } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) { + this.$results.scrollTop(nextOffset); + } + }; + + Results.prototype.template = function (result, container) { + var template = this.options.get('templateResult'); + var escapeMarkup = this.options.get('escapeMarkup'); + + var content = template(result, container); + + if (content == null) { + container.style.display = 'none'; + } else if (typeof content === 'string') { + container.innerHTML = escapeMarkup(content); + } else { + $(container).append(content); + } + }; + + return Results; +}); + +S2.define('select2/keys',[ + +], function () { + var KEYS = { + BACKSPACE: 8, + TAB: 9, + ENTER: 13, + SHIFT: 16, + CTRL: 17, + ALT: 18, + ESC: 27, + SPACE: 32, + PAGE_UP: 33, + PAGE_DOWN: 34, + END: 35, + HOME: 36, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + DELETE: 46 + }; + + return KEYS; +}); + +S2.define('select2/selection/base',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function BaseSelection ($element, options) { + this.$element = $element; + this.options = options; + + BaseSelection.__super__.constructor.call(this); + } + + Utils.Extend(BaseSelection, Utils.Observable); + + BaseSelection.prototype.render = function () { + var $selection = $( + '' + ); + + this._tabindex = 0; + + if (Utils.GetData(this.$element[0], 'old-tabindex') != null) { + this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex'); + } else if (this.$element.attr('tabindex') != null) { + this._tabindex = this.$element.attr('tabindex'); + } + + $selection.attr('title', this.$element.attr('title')); + $selection.attr('tabindex', this._tabindex); + $selection.attr('aria-disabled', 'false'); + + this.$selection = $selection; + + return $selection; + }; + + BaseSelection.prototype.bind = function (container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + this.container = container; + + this.$selection.on('focus', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('blur', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', function (evt) { + self.trigger('keypress', evt); + + if (evt.which === KEYS.SPACE) { + evt.preventDefault(); + } + }); + + container.on('results:focus', function (params) { + self.$selection.attr('aria-activedescendant', params.data._resultId); + }); + + container.on('selection:update', function (params) { + self.update(params.data); + }); + + container.on('open', function () { + // When the dropdown is open, aria-expanded="true" + self.$selection.attr('aria-expanded', 'true'); + self.$selection.attr('aria-owns', resultsId); + + self._attachCloseHandler(container); + }); + + container.on('close', function () { + // When the dropdown is closed, aria-expanded="false" + self.$selection.attr('aria-expanded', 'false'); + self.$selection.removeAttr('aria-activedescendant'); + self.$selection.removeAttr('aria-owns'); + + self.$selection.trigger('focus'); + + self._detachCloseHandler(container); + }); + + container.on('enable', function () { + self.$selection.attr('tabindex', self._tabindex); + self.$selection.attr('aria-disabled', 'false'); + }); + + container.on('disable', function () { + self.$selection.attr('tabindex', '-1'); + self.$selection.attr('aria-disabled', 'true'); + }); + }; + + BaseSelection.prototype._handleBlur = function (evt) { + var self = this; + + // This needs to be delayed as the active element is the body when the tab + // key is pressed, possibly along with others. + window.setTimeout(function () { + // Don't trigger `blur` if the focus is still in the selection + if ( + (document.activeElement == self.$selection[0]) || + ($.contains(self.$selection[0], document.activeElement)) + ) { + return; + } + + self.trigger('blur', evt); + }, 1); + }; + + BaseSelection.prototype._attachCloseHandler = function (container) { + + $(document.body).on('mousedown.select2.' + container.id, function (e) { + var $target = $(e.target); + + var $select = $target.closest('.select2'); + + var $all = $('.select2.select2-container--open'); + + $all.each(function () { + if (this == $select[0]) { + return; + } + + var $element = Utils.GetData(this, 'element'); + + $element.select2('close'); + }); + }); + }; + + BaseSelection.prototype._detachCloseHandler = function (container) { + $(document.body).off('mousedown.select2.' + container.id); + }; + + BaseSelection.prototype.position = function ($selection, $container) { + var $selectionContainer = $container.find('.selection'); + $selectionContainer.append($selection); + }; + + BaseSelection.prototype.destroy = function () { + this._detachCloseHandler(this.container); + }; + + BaseSelection.prototype.update = function (data) { + throw new Error('The `update` method must be defined in child classes.'); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + BaseSelection.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + BaseSelection.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + + return BaseSelection; +}); + +S2.define('select2/selection/single',[ + 'jquery', + './base', + '../utils', + '../keys' +], function ($, BaseSelection, Utils, KEYS) { + function SingleSelection () { + SingleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(SingleSelection, BaseSelection); + + SingleSelection.prototype.render = function () { + var $selection = SingleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--single'); + + $selection.html( + '' + + '' + + '' + + '' + ); + + return $selection; + }; + + SingleSelection.prototype.bind = function (container, $container) { + var self = this; + + SingleSelection.__super__.bind.apply(this, arguments); + + var id = container.id + '-container'; + + this.$selection.find('.select2-selection__rendered') + .attr('id', id) + .attr('role', 'textbox') + .attr('aria-readonly', 'true'); + this.$selection.attr('aria-labelledby', id); + + this.$selection.on('mousedown', function (evt) { + // Only respond to left clicks + if (evt.which !== 1) { + return; + } + + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on('focus', function (evt) { + // User focuses on the container + }); + + this.$selection.on('blur', function (evt) { + // User exits the container + }); + + container.on('focus', function (evt) { + if (!container.isOpen()) { + self.$selection.trigger('focus'); + } + }); + }; + + SingleSelection.prototype.clear = function () { + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); // clear tooltip on empty + }; + + SingleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + SingleSelection.prototype.selectionContainer = function () { + return $(''); + }; + + SingleSelection.prototype.update = function (data) { + if (data.length === 0) { + this.clear(); + return; + } + + var selection = data[0]; + + var $rendered = this.$selection.find('.select2-selection__rendered'); + var formatted = this.display(selection, $rendered); + + $rendered.empty().append(formatted); + + var title = selection.title || selection.text; + + if (title) { + $rendered.attr('title', title); + } else { + $rendered.removeAttr('title'); + } + }; + + return SingleSelection; +}); + +S2.define('select2/selection/multiple',[ + 'jquery', + './base', + '../utils' +], function ($, BaseSelection, Utils) { + function MultipleSelection ($element, options) { + MultipleSelection.__super__.constructor.apply(this, arguments); + } + + Utils.Extend(MultipleSelection, BaseSelection); + + MultipleSelection.prototype.render = function () { + var $selection = MultipleSelection.__super__.render.call(this); + + $selection.addClass('select2-selection--multiple'); + + $selection.html( + '
        ' + ); + + return $selection; + }; + + MultipleSelection.prototype.bind = function (container, $container) { + var self = this; + + MultipleSelection.__super__.bind.apply(this, arguments); + + this.$selection.on('click', function (evt) { + self.trigger('toggle', { + originalEvent: evt + }); + }); + + this.$selection.on( + 'click', + '.select2-selection__choice__remove', + function (evt) { + // Ignore the event if it is disabled + if (self.isDisabled()) { + return; + } + + var $remove = $(this); + var $selection = $remove.parent(); + + var data = Utils.GetData($selection[0], 'data'); + + self.trigger('unselect', { + originalEvent: evt, + data: data + }); + } + ); + }; + + MultipleSelection.prototype.clear = function () { + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); + }; + + MultipleSelection.prototype.display = function (data, container) { + var template = this.options.get('templateSelection'); + var escapeMarkup = this.options.get('escapeMarkup'); + + return escapeMarkup(template(data, container)); + }; + + MultipleSelection.prototype.selectionContainer = function () { + var $container = $( + '
      • ' + + '' + + '×' + + '' + + '
      • ' + ); + + return $container; + }; + + MultipleSelection.prototype.update = function (data) { + this.clear(); + + if (data.length === 0) { + return; + } + + var $selections = []; + + for (var d = 0; d < data.length; d++) { + var selection = data[d]; + + var $selection = this.selectionContainer(); + var formatted = this.display(selection, $selection); + + $selection.append(formatted); + + var title = selection.title || selection.text; + + if (title) { + $selection.attr('title', title); + } + + Utils.StoreData($selection[0], 'data', selection); + + $selections.push($selection); + } + + var $rendered = this.$selection.find('.select2-selection__rendered'); + + Utils.appendMany($rendered, $selections); + }; + + return MultipleSelection; +}); + +S2.define('select2/selection/placeholder',[ + '../utils' +], function (Utils) { + function Placeholder (decorated, $element, options) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options); + } + + Placeholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + Placeholder.prototype.createPlaceholder = function (decorated, placeholder) { + var $placeholder = this.selectionContainer(); + + $placeholder.html(this.display(placeholder)); + $placeholder.addClass('select2-selection__placeholder') + .removeClass('select2-selection__choice'); + + return $placeholder; + }; + + Placeholder.prototype.update = function (decorated, data) { + var singlePlaceholder = ( + data.length == 1 && data[0].id != this.placeholder.id + ); + var multipleSelections = data.length > 1; + + if (multipleSelections || singlePlaceholder) { + return decorated.call(this, data); + } + + this.clear(); + + var $placeholder = this.createPlaceholder(this.placeholder); + + this.$selection.find('.select2-selection__rendered').append($placeholder); + }; + + return Placeholder; +}); + +S2.define('select2/selection/allowClear',[ + 'jquery', + '../keys', + '../utils' +], function ($, KEYS, Utils) { + function AllowClear () { } + + AllowClear.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + if (this.placeholder == null) { + if (this.options.get('debug') && window.console && console.error) { + console.error( + 'Select2: The `allowClear` option should be used in combination ' + + 'with the `placeholder` option.' + ); + } + } + + this.$selection.on('mousedown', '.select2-selection__clear', + function (evt) { + self._handleClear(evt); + }); + + container.on('keypress', function (evt) { + self._handleKeyboardClear(evt, container); + }); + }; + + AllowClear.prototype._handleClear = function (_, evt) { + // Ignore the event if it is disabled + if (this.isDisabled()) { + return; + } + + var $clear = this.$selection.find('.select2-selection__clear'); + + // Ignore the event if nothing has been selected + if ($clear.length === 0) { + return; + } + + evt.stopPropagation(); + + var data = Utils.GetData($clear[0], 'data'); + + var previousVal = this.$element.val(); + this.$element.val(this.placeholder.id); + + var unselectData = { + data: data + }; + this.trigger('clear', unselectData); + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } + + for (var d = 0; d < data.length; d++) { + unselectData = { + data: data[d] + }; + + // Trigger the `unselect` event, so people can prevent it from being + // cleared. + this.trigger('unselect', unselectData); + + // If the event was prevented, don't clear it out. + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } + } + + this.$element.trigger('input').trigger('change'); + + this.trigger('toggle', {}); + }; + + AllowClear.prototype._handleKeyboardClear = function (_, evt, container) { + if (container.isOpen()) { + return; + } + + if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) { + this._handleClear(evt); + } + }; + + AllowClear.prototype.update = function (decorated, data) { + decorated.call(this, data); + + if (this.$selection.find('.select2-selection__placeholder').length > 0 || + data.length === 0) { + return; + } + + var removeAll = this.options.get('translations').get('removeAllItems'); + + var $remove = $( + '' + + '×' + + '' + ); + Utils.StoreData($remove[0], 'data', data); + + this.$selection.find('.select2-selection__rendered').prepend($remove); + }; + + return AllowClear; +}); + +S2.define('select2/selection/search',[ + 'jquery', + '../utils', + '../keys' +], function ($, Utils, KEYS) { + function Search (decorated, $element, options) { + decorated.call(this, $element, options); + } + + Search.prototype.render = function (decorated) { + var $search = $( + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + var $rendered = decorated.call(this); + + this._transferTabIndex(); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + container.on('open', function () { + self.$search.attr('aria-controls', resultsId); + self.$search.trigger('focus'); + }); + + container.on('close', function () { + self.$search.val(''); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + self.$search.trigger('focus'); + }); + + container.on('enable', function () { + self.$search.prop('disabled', false); + + self._transferTabIndex(); + }); + + container.on('disable', function () { + self.$search.prop('disabled', true); + }); + + container.on('focus', function (evt) { + self.$search.trigger('focus'); + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + + this.$selection.on('focusin', '.select2-search--inline', function (evt) { + self.trigger('focus', evt); + }); + + this.$selection.on('focusout', '.select2-search--inline', function (evt) { + self._handleBlur(evt); + }); + + this.$selection.on('keydown', '.select2-search--inline', function (evt) { + evt.stopPropagation(); + + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + + var key = evt.which; + + if (key === KEYS.BACKSPACE && self.$search.val() === '') { + var $previousChoice = self.$searchContainer + .prev('.select2-selection__choice'); + + if ($previousChoice.length > 0) { + var item = Utils.GetData($previousChoice[0], 'data'); + + self.searchRemoveChoice(item); + + evt.preventDefault(); + } + } + }); + + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + + // Try to detect the IE version should the `documentMode` property that + // is stored on the document. This is only implemented in IE and is + // slightly cleaner than doing a user agent check. + // This property is not available in Edge, but Edge also doesn't have + // this bug. + var msie = document.documentMode; + var disableInputEvents = msie && msie <= 11; + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$selection.on( + 'input.searchcheck', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents) { + self.$selection.off('input.search input.searchcheck'); + return; + } + + // Unbind the duplicated `keyup` event + self.$selection.off('keyup.search'); + } + ); + + this.$selection.on( + 'keyup.search input.search', + '.select2-search--inline', + function (evt) { + // IE will trigger the `input` event when a placeholder is used on a + // search box. To get around this issue, we are forced to ignore all + // `input` events in IE and keep using `keyup`. + if (disableInputEvents && evt.type === 'input') { + self.$selection.off('input.search input.searchcheck'); + return; + } + + var key = evt.which; + + // We can freely ignore events from modifier keys + if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) { + return; + } + + // Tabbing will be handled during the `keydown` phase + if (key == KEYS.TAB) { + return; + } + + self.handleSearch(evt); + } + ); + }; + + /** + * This method will transfer the tabindex attribute from the rendered + * selection to the search box. This allows for the search box to be used as + * the primary focus instead of the selection container. + * + * @private + */ + Search.prototype._transferTabIndex = function (decorated) { + this.$search.attr('tabindex', this.$selection.attr('tabindex')); + this.$selection.attr('tabindex', '-1'); + }; + + Search.prototype.createPlaceholder = function (decorated, placeholder) { + this.$search.attr('placeholder', placeholder.text); + }; + + Search.prototype.update = function (decorated, data) { + var searchHadFocus = this.$search[0] == document.activeElement; + + this.$search.attr('placeholder', ''); + + decorated.call(this, data); + + this.$selection.find('.select2-selection__rendered') + .append(this.$searchContainer); + + this.resizeSearch(); + if (searchHadFocus) { + this.$search.trigger('focus'); + } + }; + + Search.prototype.handleSearch = function () { + this.resizeSearch(); + + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.searchRemoveChoice = function (decorated, item) { + this.trigger('unselect', { + data: item + }); + + this.$search.val(item.text); + this.handleSearch(); + }; + + Search.prototype.resizeSearch = function () { + this.$search.css('width', '25px'); + + var width = ''; + + if (this.$search.attr('placeholder') !== '') { + width = this.$selection.find('.select2-selection__rendered').width(); + } else { + var minimumWidth = this.$search.val().length + 1; + + width = (minimumWidth * 0.75) + 'em'; + } + + this.$search.css('width', width); + }; + + return Search; +}); + +S2.define('select2/selection/eventRelay',[ + 'jquery' +], function ($) { + function EventRelay () { } + + EventRelay.prototype.bind = function (decorated, container, $container) { + var self = this; + var relayEvents = [ + 'open', 'opening', + 'close', 'closing', + 'select', 'selecting', + 'unselect', 'unselecting', + 'clear', 'clearing' + ]; + + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; + + decorated.call(this, container, $container); + + container.on('*', function (name, params) { + // Ignore events that should not be relayed + if ($.inArray(name, relayEvents) === -1) { + return; + } + + // The parameters should always be an object + params = params || {}; + + // Generate the jQuery event for the Select2 event + var evt = $.Event('select2:' + name, { + params: params + }); + + self.$element.trigger(evt); + + // Only handle preventable events if it was one + if ($.inArray(name, preventableEvents) === -1) { + return; + } + + params.prevented = evt.isDefaultPrevented(); + }); + }; + + return EventRelay; +}); + +S2.define('select2/translation',[ + 'jquery', + 'require' +], function ($, require) { + function Translation (dict) { + this.dict = dict || {}; + } + + Translation.prototype.all = function () { + return this.dict; + }; + + Translation.prototype.get = function (key) { + return this.dict[key]; + }; + + Translation.prototype.extend = function (translation) { + this.dict = $.extend({}, translation.all(), this.dict); + }; + + // Static functions + + Translation._cache = {}; + + Translation.loadPath = function (path) { + if (!(path in Translation._cache)) { + var translations = require(path); + + Translation._cache[path] = translations; + } + + return new Translation(Translation._cache[path]); + }; + + return Translation; +}); + +S2.define('select2/diacritics',[ + +], function () { + var diacritics = { + '\u24B6': 'A', + '\uFF21': 'A', + '\u00C0': 'A', + '\u00C1': 'A', + '\u00C2': 'A', + '\u1EA6': 'A', + '\u1EA4': 'A', + '\u1EAA': 'A', + '\u1EA8': 'A', + '\u00C3': 'A', + '\u0100': 'A', + '\u0102': 'A', + '\u1EB0': 'A', + '\u1EAE': 'A', + '\u1EB4': 'A', + '\u1EB2': 'A', + '\u0226': 'A', + '\u01E0': 'A', + '\u00C4': 'A', + '\u01DE': 'A', + '\u1EA2': 'A', + '\u00C5': 'A', + '\u01FA': 'A', + '\u01CD': 'A', + '\u0200': 'A', + '\u0202': 'A', + '\u1EA0': 'A', + '\u1EAC': 'A', + '\u1EB6': 'A', + '\u1E00': 'A', + '\u0104': 'A', + '\u023A': 'A', + '\u2C6F': 'A', + '\uA732': 'AA', + '\u00C6': 'AE', + '\u01FC': 'AE', + '\u01E2': 'AE', + '\uA734': 'AO', + '\uA736': 'AU', + '\uA738': 'AV', + '\uA73A': 'AV', + '\uA73C': 'AY', + '\u24B7': 'B', + '\uFF22': 'B', + '\u1E02': 'B', + '\u1E04': 'B', + '\u1E06': 'B', + '\u0243': 'B', + '\u0182': 'B', + '\u0181': 'B', + '\u24B8': 'C', + '\uFF23': 'C', + '\u0106': 'C', + '\u0108': 'C', + '\u010A': 'C', + '\u010C': 'C', + '\u00C7': 'C', + '\u1E08': 'C', + '\u0187': 'C', + '\u023B': 'C', + '\uA73E': 'C', + '\u24B9': 'D', + '\uFF24': 'D', + '\u1E0A': 'D', + '\u010E': 'D', + '\u1E0C': 'D', + '\u1E10': 'D', + '\u1E12': 'D', + '\u1E0E': 'D', + '\u0110': 'D', + '\u018B': 'D', + '\u018A': 'D', + '\u0189': 'D', + '\uA779': 'D', + '\u01F1': 'DZ', + '\u01C4': 'DZ', + '\u01F2': 'Dz', + '\u01C5': 'Dz', + '\u24BA': 'E', + '\uFF25': 'E', + '\u00C8': 'E', + '\u00C9': 'E', + '\u00CA': 'E', + '\u1EC0': 'E', + '\u1EBE': 'E', + '\u1EC4': 'E', + '\u1EC2': 'E', + '\u1EBC': 'E', + '\u0112': 'E', + '\u1E14': 'E', + '\u1E16': 'E', + '\u0114': 'E', + '\u0116': 'E', + '\u00CB': 'E', + '\u1EBA': 'E', + '\u011A': 'E', + '\u0204': 'E', + '\u0206': 'E', + '\u1EB8': 'E', + '\u1EC6': 'E', + '\u0228': 'E', + '\u1E1C': 'E', + '\u0118': 'E', + '\u1E18': 'E', + '\u1E1A': 'E', + '\u0190': 'E', + '\u018E': 'E', + '\u24BB': 'F', + '\uFF26': 'F', + '\u1E1E': 'F', + '\u0191': 'F', + '\uA77B': 'F', + '\u24BC': 'G', + '\uFF27': 'G', + '\u01F4': 'G', + '\u011C': 'G', + '\u1E20': 'G', + '\u011E': 'G', + '\u0120': 'G', + '\u01E6': 'G', + '\u0122': 'G', + '\u01E4': 'G', + '\u0193': 'G', + '\uA7A0': 'G', + '\uA77D': 'G', + '\uA77E': 'G', + '\u24BD': 'H', + '\uFF28': 'H', + '\u0124': 'H', + '\u1E22': 'H', + '\u1E26': 'H', + '\u021E': 'H', + '\u1E24': 'H', + '\u1E28': 'H', + '\u1E2A': 'H', + '\u0126': 'H', + '\u2C67': 'H', + '\u2C75': 'H', + '\uA78D': 'H', + '\u24BE': 'I', + '\uFF29': 'I', + '\u00CC': 'I', + '\u00CD': 'I', + '\u00CE': 'I', + '\u0128': 'I', + '\u012A': 'I', + '\u012C': 'I', + '\u0130': 'I', + '\u00CF': 'I', + '\u1E2E': 'I', + '\u1EC8': 'I', + '\u01CF': 'I', + '\u0208': 'I', + '\u020A': 'I', + '\u1ECA': 'I', + '\u012E': 'I', + '\u1E2C': 'I', + '\u0197': 'I', + '\u24BF': 'J', + '\uFF2A': 'J', + '\u0134': 'J', + '\u0248': 'J', + '\u24C0': 'K', + '\uFF2B': 'K', + '\u1E30': 'K', + '\u01E8': 'K', + '\u1E32': 'K', + '\u0136': 'K', + '\u1E34': 'K', + '\u0198': 'K', + '\u2C69': 'K', + '\uA740': 'K', + '\uA742': 'K', + '\uA744': 'K', + '\uA7A2': 'K', + '\u24C1': 'L', + '\uFF2C': 'L', + '\u013F': 'L', + '\u0139': 'L', + '\u013D': 'L', + '\u1E36': 'L', + '\u1E38': 'L', + '\u013B': 'L', + '\u1E3C': 'L', + '\u1E3A': 'L', + '\u0141': 'L', + '\u023D': 'L', + '\u2C62': 'L', + '\u2C60': 'L', + '\uA748': 'L', + '\uA746': 'L', + '\uA780': 'L', + '\u01C7': 'LJ', + '\u01C8': 'Lj', + '\u24C2': 'M', + '\uFF2D': 'M', + '\u1E3E': 'M', + '\u1E40': 'M', + '\u1E42': 'M', + '\u2C6E': 'M', + '\u019C': 'M', + '\u24C3': 'N', + '\uFF2E': 'N', + '\u01F8': 'N', + '\u0143': 'N', + '\u00D1': 'N', + '\u1E44': 'N', + '\u0147': 'N', + '\u1E46': 'N', + '\u0145': 'N', + '\u1E4A': 'N', + '\u1E48': 'N', + '\u0220': 'N', + '\u019D': 'N', + '\uA790': 'N', + '\uA7A4': 'N', + '\u01CA': 'NJ', + '\u01CB': 'Nj', + '\u24C4': 'O', + '\uFF2F': 'O', + '\u00D2': 'O', + '\u00D3': 'O', + '\u00D4': 'O', + '\u1ED2': 'O', + '\u1ED0': 'O', + '\u1ED6': 'O', + '\u1ED4': 'O', + '\u00D5': 'O', + '\u1E4C': 'O', + '\u022C': 'O', + '\u1E4E': 'O', + '\u014C': 'O', + '\u1E50': 'O', + '\u1E52': 'O', + '\u014E': 'O', + '\u022E': 'O', + '\u0230': 'O', + '\u00D6': 'O', + '\u022A': 'O', + '\u1ECE': 'O', + '\u0150': 'O', + '\u01D1': 'O', + '\u020C': 'O', + '\u020E': 'O', + '\u01A0': 'O', + '\u1EDC': 'O', + '\u1EDA': 'O', + '\u1EE0': 'O', + '\u1EDE': 'O', + '\u1EE2': 'O', + '\u1ECC': 'O', + '\u1ED8': 'O', + '\u01EA': 'O', + '\u01EC': 'O', + '\u00D8': 'O', + '\u01FE': 'O', + '\u0186': 'O', + '\u019F': 'O', + '\uA74A': 'O', + '\uA74C': 'O', + '\u0152': 'OE', + '\u01A2': 'OI', + '\uA74E': 'OO', + '\u0222': 'OU', + '\u24C5': 'P', + '\uFF30': 'P', + '\u1E54': 'P', + '\u1E56': 'P', + '\u01A4': 'P', + '\u2C63': 'P', + '\uA750': 'P', + '\uA752': 'P', + '\uA754': 'P', + '\u24C6': 'Q', + '\uFF31': 'Q', + '\uA756': 'Q', + '\uA758': 'Q', + '\u024A': 'Q', + '\u24C7': 'R', + '\uFF32': 'R', + '\u0154': 'R', + '\u1E58': 'R', + '\u0158': 'R', + '\u0210': 'R', + '\u0212': 'R', + '\u1E5A': 'R', + '\u1E5C': 'R', + '\u0156': 'R', + '\u1E5E': 'R', + '\u024C': 'R', + '\u2C64': 'R', + '\uA75A': 'R', + '\uA7A6': 'R', + '\uA782': 'R', + '\u24C8': 'S', + '\uFF33': 'S', + '\u1E9E': 'S', + '\u015A': 'S', + '\u1E64': 'S', + '\u015C': 'S', + '\u1E60': 'S', + '\u0160': 'S', + '\u1E66': 'S', + '\u1E62': 'S', + '\u1E68': 'S', + '\u0218': 'S', + '\u015E': 'S', + '\u2C7E': 'S', + '\uA7A8': 'S', + '\uA784': 'S', + '\u24C9': 'T', + '\uFF34': 'T', + '\u1E6A': 'T', + '\u0164': 'T', + '\u1E6C': 'T', + '\u021A': 'T', + '\u0162': 'T', + '\u1E70': 'T', + '\u1E6E': 'T', + '\u0166': 'T', + '\u01AC': 'T', + '\u01AE': 'T', + '\u023E': 'T', + '\uA786': 'T', + '\uA728': 'TZ', + '\u24CA': 'U', + '\uFF35': 'U', + '\u00D9': 'U', + '\u00DA': 'U', + '\u00DB': 'U', + '\u0168': 'U', + '\u1E78': 'U', + '\u016A': 'U', + '\u1E7A': 'U', + '\u016C': 'U', + '\u00DC': 'U', + '\u01DB': 'U', + '\u01D7': 'U', + '\u01D5': 'U', + '\u01D9': 'U', + '\u1EE6': 'U', + '\u016E': 'U', + '\u0170': 'U', + '\u01D3': 'U', + '\u0214': 'U', + '\u0216': 'U', + '\u01AF': 'U', + '\u1EEA': 'U', + '\u1EE8': 'U', + '\u1EEE': 'U', + '\u1EEC': 'U', + '\u1EF0': 'U', + '\u1EE4': 'U', + '\u1E72': 'U', + '\u0172': 'U', + '\u1E76': 'U', + '\u1E74': 'U', + '\u0244': 'U', + '\u24CB': 'V', + '\uFF36': 'V', + '\u1E7C': 'V', + '\u1E7E': 'V', + '\u01B2': 'V', + '\uA75E': 'V', + '\u0245': 'V', + '\uA760': 'VY', + '\u24CC': 'W', + '\uFF37': 'W', + '\u1E80': 'W', + '\u1E82': 'W', + '\u0174': 'W', + '\u1E86': 'W', + '\u1E84': 'W', + '\u1E88': 'W', + '\u2C72': 'W', + '\u24CD': 'X', + '\uFF38': 'X', + '\u1E8A': 'X', + '\u1E8C': 'X', + '\u24CE': 'Y', + '\uFF39': 'Y', + '\u1EF2': 'Y', + '\u00DD': 'Y', + '\u0176': 'Y', + '\u1EF8': 'Y', + '\u0232': 'Y', + '\u1E8E': 'Y', + '\u0178': 'Y', + '\u1EF6': 'Y', + '\u1EF4': 'Y', + '\u01B3': 'Y', + '\u024E': 'Y', + '\u1EFE': 'Y', + '\u24CF': 'Z', + '\uFF3A': 'Z', + '\u0179': 'Z', + '\u1E90': 'Z', + '\u017B': 'Z', + '\u017D': 'Z', + '\u1E92': 'Z', + '\u1E94': 'Z', + '\u01B5': 'Z', + '\u0224': 'Z', + '\u2C7F': 'Z', + '\u2C6B': 'Z', + '\uA762': 'Z', + '\u24D0': 'a', + '\uFF41': 'a', + '\u1E9A': 'a', + '\u00E0': 'a', + '\u00E1': 'a', + '\u00E2': 'a', + '\u1EA7': 'a', + '\u1EA5': 'a', + '\u1EAB': 'a', + '\u1EA9': 'a', + '\u00E3': 'a', + '\u0101': 'a', + '\u0103': 'a', + '\u1EB1': 'a', + '\u1EAF': 'a', + '\u1EB5': 'a', + '\u1EB3': 'a', + '\u0227': 'a', + '\u01E1': 'a', + '\u00E4': 'a', + '\u01DF': 'a', + '\u1EA3': 'a', + '\u00E5': 'a', + '\u01FB': 'a', + '\u01CE': 'a', + '\u0201': 'a', + '\u0203': 'a', + '\u1EA1': 'a', + '\u1EAD': 'a', + '\u1EB7': 'a', + '\u1E01': 'a', + '\u0105': 'a', + '\u2C65': 'a', + '\u0250': 'a', + '\uA733': 'aa', + '\u00E6': 'ae', + '\u01FD': 'ae', + '\u01E3': 'ae', + '\uA735': 'ao', + '\uA737': 'au', + '\uA739': 'av', + '\uA73B': 'av', + '\uA73D': 'ay', + '\u24D1': 'b', + '\uFF42': 'b', + '\u1E03': 'b', + '\u1E05': 'b', + '\u1E07': 'b', + '\u0180': 'b', + '\u0183': 'b', + '\u0253': 'b', + '\u24D2': 'c', + '\uFF43': 'c', + '\u0107': 'c', + '\u0109': 'c', + '\u010B': 'c', + '\u010D': 'c', + '\u00E7': 'c', + '\u1E09': 'c', + '\u0188': 'c', + '\u023C': 'c', + '\uA73F': 'c', + '\u2184': 'c', + '\u24D3': 'd', + '\uFF44': 'd', + '\u1E0B': 'd', + '\u010F': 'd', + '\u1E0D': 'd', + '\u1E11': 'd', + '\u1E13': 'd', + '\u1E0F': 'd', + '\u0111': 'd', + '\u018C': 'd', + '\u0256': 'd', + '\u0257': 'd', + '\uA77A': 'd', + '\u01F3': 'dz', + '\u01C6': 'dz', + '\u24D4': 'e', + '\uFF45': 'e', + '\u00E8': 'e', + '\u00E9': 'e', + '\u00EA': 'e', + '\u1EC1': 'e', + '\u1EBF': 'e', + '\u1EC5': 'e', + '\u1EC3': 'e', + '\u1EBD': 'e', + '\u0113': 'e', + '\u1E15': 'e', + '\u1E17': 'e', + '\u0115': 'e', + '\u0117': 'e', + '\u00EB': 'e', + '\u1EBB': 'e', + '\u011B': 'e', + '\u0205': 'e', + '\u0207': 'e', + '\u1EB9': 'e', + '\u1EC7': 'e', + '\u0229': 'e', + '\u1E1D': 'e', + '\u0119': 'e', + '\u1E19': 'e', + '\u1E1B': 'e', + '\u0247': 'e', + '\u025B': 'e', + '\u01DD': 'e', + '\u24D5': 'f', + '\uFF46': 'f', + '\u1E1F': 'f', + '\u0192': 'f', + '\uA77C': 'f', + '\u24D6': 'g', + '\uFF47': 'g', + '\u01F5': 'g', + '\u011D': 'g', + '\u1E21': 'g', + '\u011F': 'g', + '\u0121': 'g', + '\u01E7': 'g', + '\u0123': 'g', + '\u01E5': 'g', + '\u0260': 'g', + '\uA7A1': 'g', + '\u1D79': 'g', + '\uA77F': 'g', + '\u24D7': 'h', + '\uFF48': 'h', + '\u0125': 'h', + '\u1E23': 'h', + '\u1E27': 'h', + '\u021F': 'h', + '\u1E25': 'h', + '\u1E29': 'h', + '\u1E2B': 'h', + '\u1E96': 'h', + '\u0127': 'h', + '\u2C68': 'h', + '\u2C76': 'h', + '\u0265': 'h', + '\u0195': 'hv', + '\u24D8': 'i', + '\uFF49': 'i', + '\u00EC': 'i', + '\u00ED': 'i', + '\u00EE': 'i', + '\u0129': 'i', + '\u012B': 'i', + '\u012D': 'i', + '\u00EF': 'i', + '\u1E2F': 'i', + '\u1EC9': 'i', + '\u01D0': 'i', + '\u0209': 'i', + '\u020B': 'i', + '\u1ECB': 'i', + '\u012F': 'i', + '\u1E2D': 'i', + '\u0268': 'i', + '\u0131': 'i', + '\u24D9': 'j', + '\uFF4A': 'j', + '\u0135': 'j', + '\u01F0': 'j', + '\u0249': 'j', + '\u24DA': 'k', + '\uFF4B': 'k', + '\u1E31': 'k', + '\u01E9': 'k', + '\u1E33': 'k', + '\u0137': 'k', + '\u1E35': 'k', + '\u0199': 'k', + '\u2C6A': 'k', + '\uA741': 'k', + '\uA743': 'k', + '\uA745': 'k', + '\uA7A3': 'k', + '\u24DB': 'l', + '\uFF4C': 'l', + '\u0140': 'l', + '\u013A': 'l', + '\u013E': 'l', + '\u1E37': 'l', + '\u1E39': 'l', + '\u013C': 'l', + '\u1E3D': 'l', + '\u1E3B': 'l', + '\u017F': 'l', + '\u0142': 'l', + '\u019A': 'l', + '\u026B': 'l', + '\u2C61': 'l', + '\uA749': 'l', + '\uA781': 'l', + '\uA747': 'l', + '\u01C9': 'lj', + '\u24DC': 'm', + '\uFF4D': 'm', + '\u1E3F': 'm', + '\u1E41': 'm', + '\u1E43': 'm', + '\u0271': 'm', + '\u026F': 'm', + '\u24DD': 'n', + '\uFF4E': 'n', + '\u01F9': 'n', + '\u0144': 'n', + '\u00F1': 'n', + '\u1E45': 'n', + '\u0148': 'n', + '\u1E47': 'n', + '\u0146': 'n', + '\u1E4B': 'n', + '\u1E49': 'n', + '\u019E': 'n', + '\u0272': 'n', + '\u0149': 'n', + '\uA791': 'n', + '\uA7A5': 'n', + '\u01CC': 'nj', + '\u24DE': 'o', + '\uFF4F': 'o', + '\u00F2': 'o', + '\u00F3': 'o', + '\u00F4': 'o', + '\u1ED3': 'o', + '\u1ED1': 'o', + '\u1ED7': 'o', + '\u1ED5': 'o', + '\u00F5': 'o', + '\u1E4D': 'o', + '\u022D': 'o', + '\u1E4F': 'o', + '\u014D': 'o', + '\u1E51': 'o', + '\u1E53': 'o', + '\u014F': 'o', + '\u022F': 'o', + '\u0231': 'o', + '\u00F6': 'o', + '\u022B': 'o', + '\u1ECF': 'o', + '\u0151': 'o', + '\u01D2': 'o', + '\u020D': 'o', + '\u020F': 'o', + '\u01A1': 'o', + '\u1EDD': 'o', + '\u1EDB': 'o', + '\u1EE1': 'o', + '\u1EDF': 'o', + '\u1EE3': 'o', + '\u1ECD': 'o', + '\u1ED9': 'o', + '\u01EB': 'o', + '\u01ED': 'o', + '\u00F8': 'o', + '\u01FF': 'o', + '\u0254': 'o', + '\uA74B': 'o', + '\uA74D': 'o', + '\u0275': 'o', + '\u0153': 'oe', + '\u01A3': 'oi', + '\u0223': 'ou', + '\uA74F': 'oo', + '\u24DF': 'p', + '\uFF50': 'p', + '\u1E55': 'p', + '\u1E57': 'p', + '\u01A5': 'p', + '\u1D7D': 'p', + '\uA751': 'p', + '\uA753': 'p', + '\uA755': 'p', + '\u24E0': 'q', + '\uFF51': 'q', + '\u024B': 'q', + '\uA757': 'q', + '\uA759': 'q', + '\u24E1': 'r', + '\uFF52': 'r', + '\u0155': 'r', + '\u1E59': 'r', + '\u0159': 'r', + '\u0211': 'r', + '\u0213': 'r', + '\u1E5B': 'r', + '\u1E5D': 'r', + '\u0157': 'r', + '\u1E5F': 'r', + '\u024D': 'r', + '\u027D': 'r', + '\uA75B': 'r', + '\uA7A7': 'r', + '\uA783': 'r', + '\u24E2': 's', + '\uFF53': 's', + '\u00DF': 's', + '\u015B': 's', + '\u1E65': 's', + '\u015D': 's', + '\u1E61': 's', + '\u0161': 's', + '\u1E67': 's', + '\u1E63': 's', + '\u1E69': 's', + '\u0219': 's', + '\u015F': 's', + '\u023F': 's', + '\uA7A9': 's', + '\uA785': 's', + '\u1E9B': 's', + '\u24E3': 't', + '\uFF54': 't', + '\u1E6B': 't', + '\u1E97': 't', + '\u0165': 't', + '\u1E6D': 't', + '\u021B': 't', + '\u0163': 't', + '\u1E71': 't', + '\u1E6F': 't', + '\u0167': 't', + '\u01AD': 't', + '\u0288': 't', + '\u2C66': 't', + '\uA787': 't', + '\uA729': 'tz', + '\u24E4': 'u', + '\uFF55': 'u', + '\u00F9': 'u', + '\u00FA': 'u', + '\u00FB': 'u', + '\u0169': 'u', + '\u1E79': 'u', + '\u016B': 'u', + '\u1E7B': 'u', + '\u016D': 'u', + '\u00FC': 'u', + '\u01DC': 'u', + '\u01D8': 'u', + '\u01D6': 'u', + '\u01DA': 'u', + '\u1EE7': 'u', + '\u016F': 'u', + '\u0171': 'u', + '\u01D4': 'u', + '\u0215': 'u', + '\u0217': 'u', + '\u01B0': 'u', + '\u1EEB': 'u', + '\u1EE9': 'u', + '\u1EEF': 'u', + '\u1EED': 'u', + '\u1EF1': 'u', + '\u1EE5': 'u', + '\u1E73': 'u', + '\u0173': 'u', + '\u1E77': 'u', + '\u1E75': 'u', + '\u0289': 'u', + '\u24E5': 'v', + '\uFF56': 'v', + '\u1E7D': 'v', + '\u1E7F': 'v', + '\u028B': 'v', + '\uA75F': 'v', + '\u028C': 'v', + '\uA761': 'vy', + '\u24E6': 'w', + '\uFF57': 'w', + '\u1E81': 'w', + '\u1E83': 'w', + '\u0175': 'w', + '\u1E87': 'w', + '\u1E85': 'w', + '\u1E98': 'w', + '\u1E89': 'w', + '\u2C73': 'w', + '\u24E7': 'x', + '\uFF58': 'x', + '\u1E8B': 'x', + '\u1E8D': 'x', + '\u24E8': 'y', + '\uFF59': 'y', + '\u1EF3': 'y', + '\u00FD': 'y', + '\u0177': 'y', + '\u1EF9': 'y', + '\u0233': 'y', + '\u1E8F': 'y', + '\u00FF': 'y', + '\u1EF7': 'y', + '\u1E99': 'y', + '\u1EF5': 'y', + '\u01B4': 'y', + '\u024F': 'y', + '\u1EFF': 'y', + '\u24E9': 'z', + '\uFF5A': 'z', + '\u017A': 'z', + '\u1E91': 'z', + '\u017C': 'z', + '\u017E': 'z', + '\u1E93': 'z', + '\u1E95': 'z', + '\u01B6': 'z', + '\u0225': 'z', + '\u0240': 'z', + '\u2C6C': 'z', + '\uA763': 'z', + '\u0386': '\u0391', + '\u0388': '\u0395', + '\u0389': '\u0397', + '\u038A': '\u0399', + '\u03AA': '\u0399', + '\u038C': '\u039F', + '\u038E': '\u03A5', + '\u03AB': '\u03A5', + '\u038F': '\u03A9', + '\u03AC': '\u03B1', + '\u03AD': '\u03B5', + '\u03AE': '\u03B7', + '\u03AF': '\u03B9', + '\u03CA': '\u03B9', + '\u0390': '\u03B9', + '\u03CC': '\u03BF', + '\u03CD': '\u03C5', + '\u03CB': '\u03C5', + '\u03B0': '\u03C5', + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' + }; + + return diacritics; +}); + +S2.define('select2/data/base',[ + '../utils' +], function (Utils) { + function BaseAdapter ($element, options) { + BaseAdapter.__super__.constructor.call(this); + } + + Utils.Extend(BaseAdapter, Utils.Observable); + + BaseAdapter.prototype.current = function (callback) { + throw new Error('The `current` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.query = function (params, callback) { + throw new Error('The `query` method must be defined in child classes.'); + }; + + BaseAdapter.prototype.bind = function (container, $container) { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.destroy = function () { + // Can be implemented in subclasses + }; + + BaseAdapter.prototype.generateResultId = function (container, data) { + var id = container.id + '-result-'; + + id += Utils.generateChars(4); + + if (data.id != null) { + id += '-' + data.id.toString(); + } else { + id += '-' + Utils.generateChars(4); + } + return id; + }; + + return BaseAdapter; +}); + +S2.define('select2/data/select',[ + './base', + '../utils', + 'jquery' +], function (BaseAdapter, Utils, $) { + function SelectAdapter ($element, options) { + this.$element = $element; + this.options = options; + + SelectAdapter.__super__.constructor.call(this); + } + + Utils.Extend(SelectAdapter, BaseAdapter); + + SelectAdapter.prototype.current = function (callback) { + var data = []; + var self = this; + + this.$element.find(':selected').each(function () { + var $option = $(this); + + var option = self.item($option); + + data.push(option); + }); + + callback(data); + }; + + SelectAdapter.prototype.select = function (data) { + var self = this; + + data.selected = true; + + // If data.element is a DOM node, use it instead + if ($(data.element).is('option')) { + data.element.selected = true; + + this.$element.trigger('input').trigger('change'); + + return; + } + + if (this.$element.prop('multiple')) { + this.current(function (currentData) { + var val = []; + + data = [data]; + data.push.apply(data, currentData); + + for (var d = 0; d < data.length; d++) { + var id = data[d].id; + + if ($.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + self.$element.trigger('input').trigger('change'); + }); + } else { + var val = data.id; + + this.$element.val(val); + this.$element.trigger('input').trigger('change'); + } + }; + + SelectAdapter.prototype.unselect = function (data) { + var self = this; + + if (!this.$element.prop('multiple')) { + return; + } + + data.selected = false; + + if ($(data.element).is('option')) { + data.element.selected = false; + + this.$element.trigger('input').trigger('change'); + + return; + } + + this.current(function (currentData) { + var val = []; + + for (var d = 0; d < currentData.length; d++) { + var id = currentData[d].id; + + if (id !== data.id && $.inArray(id, val) === -1) { + val.push(id); + } + } + + self.$element.val(val); + + self.$element.trigger('input').trigger('change'); + }); + }; + + SelectAdapter.prototype.bind = function (container, $container) { + var self = this; + + this.container = container; + + container.on('select', function (params) { + self.select(params.data); + }); + + container.on('unselect', function (params) { + self.unselect(params.data); + }); + }; + + SelectAdapter.prototype.destroy = function () { + // Remove anything added to child elements + this.$element.find('*').each(function () { + // Remove any custom data set by Select2 + Utils.RemoveData(this); + }); + }; + + SelectAdapter.prototype.query = function (params, callback) { + var data = []; + var self = this; + + var $options = this.$element.children(); + + $options.each(function () { + var $option = $(this); + + if (!$option.is('option') && !$option.is('optgroup')) { + return; + } + + var option = self.item($option); + + var matches = self.matches(params, option); + + if (matches !== null) { + data.push(matches); + } + }); + + callback({ + results: data + }); + }; + + SelectAdapter.prototype.addOptions = function ($options) { + Utils.appendMany(this.$element, $options); + }; + + SelectAdapter.prototype.option = function (data) { + var option; + + if (data.children) { + option = document.createElement('optgroup'); + option.label = data.text; + } else { + option = document.createElement('option'); + + if (option.textContent !== undefined) { + option.textContent = data.text; + } else { + option.innerText = data.text; + } + } + + if (data.id !== undefined) { + option.value = data.id; + } + + if (data.disabled) { + option.disabled = true; + } + + if (data.selected) { + option.selected = true; + } + + if (data.title) { + option.title = data.title; + } + + var $option = $(option); + + var normalizedData = this._normalizeItem(data); + normalizedData.element = option; + + // Override the option's data with the combined data + Utils.StoreData(option, 'data', normalizedData); + + return $option; + }; + + SelectAdapter.prototype.item = function ($option) { + var data = {}; + + data = Utils.GetData($option[0], 'data'); + + if (data != null) { + return data; + } + + if ($option.is('option')) { + data = { + id: $option.val(), + text: $option.text(), + disabled: $option.prop('disabled'), + selected: $option.prop('selected'), + title: $option.prop('title') + }; + } else if ($option.is('optgroup')) { + data = { + text: $option.prop('label'), + children: [], + title: $option.prop('title') + }; + + var $children = $option.children('option'); + var children = []; + + for (var c = 0; c < $children.length; c++) { + var $child = $($children[c]); + + var child = this.item($child); + + children.push(child); + } + + data.children = children; + } + + data = this._normalizeItem(data); + data.element = $option[0]; + + Utils.StoreData($option[0], 'data', data); + + return data; + }; + + SelectAdapter.prototype._normalizeItem = function (item) { + if (item !== Object(item)) { + item = { + id: item, + text: item + }; + } + + item = $.extend({}, { + text: '' + }, item); + + var defaults = { + selected: false, + disabled: false + }; + + if (item.id != null) { + item.id = item.id.toString(); + } + + if (item.text != null) { + item.text = item.text.toString(); + } + + if (item._resultId == null && item.id && this.container != null) { + item._resultId = this.generateResultId(this.container, item); + } + + return $.extend({}, defaults, item); + }; + + SelectAdapter.prototype.matches = function (params, data) { + var matcher = this.options.get('matcher'); + + return matcher(params, data); + }; + + return SelectAdapter; +}); + +S2.define('select2/data/array',[ + './select', + '../utils', + 'jquery' +], function (SelectAdapter, Utils, $) { + function ArrayAdapter ($element, options) { + this._dataToConvert = options.get('data') || []; + + ArrayAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(ArrayAdapter, SelectAdapter); + + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + + ArrayAdapter.prototype.select = function (data) { + var $option = this.$element.find('option').filter(function (i, elm) { + return elm.value == data.id.toString(); + }); + + if ($option.length === 0) { + $option = this.option(data); + + this.addOptions($option); + } + + ArrayAdapter.__super__.select.call(this, data); + }; + + ArrayAdapter.prototype.convertToOptions = function (data) { + var self = this; + + var $existing = this.$element.find('option'); + var existingIds = $existing.map(function () { + return self.item($(this)).id; + }).get(); + + var $options = []; + + // Filter out all items except for the one passed in the argument + function onlyItem (item) { + return function () { + return $(this).val() == item.id; + }; + } + + for (var d = 0; d < data.length; d++) { + var item = this._normalizeItem(data[d]); + + // Skip items which were pre-loaded, only merge the data + if ($.inArray(item.id, existingIds) >= 0) { + var $existingOption = $existing.filter(onlyItem(item)); + + var existingData = this.item($existingOption); + var newData = $.extend(true, {}, item, existingData); + + var $newOption = this.option(newData); + + $existingOption.replaceWith($newOption); + + continue; + } + + var $option = this.option(item); + + if (item.children) { + var $children = this.convertToOptions(item.children); + + Utils.appendMany($option, $children); + } + + $options.push($option); + } + + return $options; + }; + + return ArrayAdapter; +}); + +S2.define('select2/data/ajax',[ + './array', + '../utils', + 'jquery' +], function (ArrayAdapter, Utils, $) { + function AjaxAdapter ($element, options) { + this.ajaxOptions = this._applyDefaults(options.get('ajax')); + + if (this.ajaxOptions.processResults != null) { + this.processResults = this.ajaxOptions.processResults; + } + + AjaxAdapter.__super__.constructor.call(this, $element, options); + } + + Utils.Extend(AjaxAdapter, ArrayAdapter); + + AjaxAdapter.prototype._applyDefaults = function (options) { + var defaults = { + data: function (params) { + return $.extend({}, params, { + q: params.term + }); + }, + transport: function (params, success, failure) { + var $request = $.ajax(params); + + $request.then(success); + $request.fail(failure); + + return $request; + } + }; + + return $.extend({}, defaults, options, true); + }; + + AjaxAdapter.prototype.processResults = function (results) { + return results; + }; + + AjaxAdapter.prototype.query = function (params, callback) { + var matches = []; + var self = this; + + if (this._request != null) { + // JSONP requests cannot always be aborted + if ($.isFunction(this._request.abort)) { + this._request.abort(); + } + + this._request = null; + } + + var options = $.extend({ + type: 'GET' + }, this.ajaxOptions); + + if (typeof options.url === 'function') { + options.url = options.url.call(this.$element, params); + } + + if (typeof options.data === 'function') { + options.data = options.data.call(this.$element, params); + } + + function request () { + var $request = options.transport(options, function (data) { + var results = self.processResults(data, params); + + if (self.options.get('debug') && window.console && console.error) { + // Check to make sure that the response included a `results` key. + if (!results || !results.results || !$.isArray(results.results)) { + console.error( + 'Select2: The AJAX results did not return an array in the ' + + '`results` key of the response.' + ); + } + } + + callback(results); + }, function () { + // Attempt to detect if a request was aborted + // Only works if the transport exposes a status property + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { + return; + } + + self.trigger('results:message', { + message: 'errorLoading' + }); + }); + + self._request = $request; + } + + if (this.ajaxOptions.delay && params.term != null) { + if (this._queryTimeout) { + window.clearTimeout(this._queryTimeout); + } + + this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay); + } else { + request(); + } + }; + + return AjaxAdapter; +}); + +S2.define('select2/data/tags',[ + 'jquery' +], function ($) { + function Tags (decorated, $element, options) { + var tags = options.get('tags'); + + var createTag = options.get('createTag'); + + if (createTag !== undefined) { + this.createTag = createTag; + } + + var insertTag = options.get('insertTag'); + + if (insertTag !== undefined) { + this.insertTag = insertTag; + } + + decorated.call(this, $element, options); + + if ($.isArray(tags)) { + for (var t = 0; t < tags.length; t++) { + var tag = tags[t]; + var item = this._normalizeItem(tag); + + var $option = this.option(item); + + this.$element.append($option); + } + } + } + + Tags.prototype.query = function (decorated, params, callback) { + var self = this; + + this._removeOldTags(); + + if (params.term == null || params.page != null) { + decorated.call(this, params, callback); + return; + } + + function wrapper (obj, child) { + var data = obj.results; + + for (var i = 0; i < data.length; i++) { + var option = data[i]; + + var checkChildren = ( + option.children != null && + !wrapper({ + results: option.children + }, true) + ); + + var optionText = (option.text || '').toUpperCase(); + var paramsTerm = (params.term || '').toUpperCase(); + + var checkText = optionText === paramsTerm; + + if (checkText || checkChildren) { + if (child) { + return false; + } + + obj.data = data; + callback(obj); + + return; + } + } + + if (child) { + return true; + } + + var tag = self.createTag(params); + + if (tag != null) { + var $option = self.option(tag); + $option.attr('data-select2-tag', true); + + self.addOptions([$option]); + + self.insertTag(data, tag); + } + + obj.results = data; + + callback(obj); + } + + decorated.call(this, params, wrapper); + }; + + Tags.prototype.createTag = function (decorated, params) { + var term = $.trim(params.term); + + if (term === '') { + return null; + } + + return { + id: term, + text: term + }; + }; + + Tags.prototype.insertTag = function (_, data, tag) { + data.unshift(tag); + }; + + Tags.prototype._removeOldTags = function (_) { + var $options = this.$element.find('option[data-select2-tag]'); + + $options.each(function () { + if (this.selected) { + return; + } + + $(this).remove(); + }); + }; + + return Tags; +}); + +S2.define('select2/data/tokenizer',[ + 'jquery' +], function ($) { + function Tokenizer (decorated, $element, options) { + var tokenizer = options.get('tokenizer'); + + if (tokenizer !== undefined) { + this.tokenizer = tokenizer; + } + + decorated.call(this, $element, options); + } + + Tokenizer.prototype.bind = function (decorated, container, $container) { + decorated.call(this, container, $container); + + this.$search = container.dropdown.$search || container.selection.$search || + $container.find('.select2-search__field'); + }; + + Tokenizer.prototype.query = function (decorated, params, callback) { + var self = this; + + function createAndSelect (data) { + // Normalize the data object so we can use it for checks + var item = self._normalizeItem(data); + + // Check if the data object already exists as a tag + // Select it if it doesn't + var $existingOptions = self.$element.find('option').filter(function () { + return $(this).val() === item.id; + }); + + // If an existing option wasn't found for it, create the option + if (!$existingOptions.length) { + var $option = self.option(item); + $option.attr('data-select2-tag', true); + + self._removeOldTags(); + self.addOptions([$option]); + } + + // Select the item, now that we know there is an option for it + select(item); + } + + function select (data) { + self.trigger('select', { + data: data + }); + } + + params.term = params.term || ''; + + var tokenData = this.tokenizer(params, this.options, createAndSelect); + + if (tokenData.term !== params.term) { + // Replace the search term if we have the search box + if (this.$search.length) { + this.$search.val(tokenData.term); + this.$search.trigger('focus'); + } + + params.term = tokenData.term; + } + + decorated.call(this, params, callback); + }; + + Tokenizer.prototype.tokenizer = function (_, params, options, callback) { + var separators = options.get('tokenSeparators') || []; + var term = params.term; + var i = 0; + + var createTag = this.createTag || function (params) { + return { + id: params.term, + text: params.term + }; + }; + + while (i < term.length) { + var termChar = term[i]; + + if ($.inArray(termChar, separators) === -1) { + i++; + + continue; + } + + var part = term.substr(0, i); + var partParams = $.extend({}, params, { + term: part + }); + + var data = createTag(partParams); + + if (data == null) { + i++; + continue; + } + + callback(data); + + // Reset the term to not include the tokenized portion + term = term.substr(i + 1) || ''; + i = 0; + } + + return { + term: term + }; + }; + + return Tokenizer; +}); + +S2.define('select2/data/minimumInputLength',[ + +], function () { + function MinimumInputLength (decorated, $e, options) { + this.minimumInputLength = options.get('minimumInputLength'); + + decorated.call(this, $e, options); + } + + MinimumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (params.term.length < this.minimumInputLength) { + this.trigger('results:message', { + message: 'inputTooShort', + args: { + minimum: this.minimumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MinimumInputLength; +}); + +S2.define('select2/data/maximumInputLength',[ + +], function () { + function MaximumInputLength (decorated, $e, options) { + this.maximumInputLength = options.get('maximumInputLength'); + + decorated.call(this, $e, options); + } + + MaximumInputLength.prototype.query = function (decorated, params, callback) { + params.term = params.term || ''; + + if (this.maximumInputLength > 0 && + params.term.length > this.maximumInputLength) { + this.trigger('results:message', { + message: 'inputTooLong', + args: { + maximum: this.maximumInputLength, + input: params.term, + params: params + } + }); + + return; + } + + decorated.call(this, params, callback); + }; + + return MaximumInputLength; +}); + +S2.define('select2/data/maximumSelectionLength',[ + +], function (){ + function MaximumSelectionLength (decorated, $e, options) { + this.maximumSelectionLength = options.get('maximumSelectionLength'); + + decorated.call(this, $e, options); + } + + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + + MaximumSelectionLength.prototype.query = + function (decorated, params, callback) { + var self = this; + + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + + this.current(function (currentData) { + var count = currentData != null ? currentData.length : 0; + if (self.maximumSelectionLength > 0 && + count >= self.maximumSelectionLength) { + self.trigger('results:message', { + message: 'maximumSelected', + args: { + maximum: self.maximumSelectionLength + } + }); + return; + } + + if (successCallback) { + successCallback(); + } + }); + }; + + return MaximumSelectionLength; +}); + +S2.define('select2/dropdown',[ + 'jquery', + './utils' +], function ($, Utils) { + function Dropdown ($element, options) { + this.$element = $element; + this.options = options; + + Dropdown.__super__.constructor.call(this); + } + + Utils.Extend(Dropdown, Utils.Observable); + + Dropdown.prototype.render = function () { + var $dropdown = $( + '' + + '' + + '' + ); + + $dropdown.attr('dir', this.options.get('dir')); + + this.$dropdown = $dropdown; + + return $dropdown; + }; + + Dropdown.prototype.bind = function () { + // Should be implemented in subclasses + }; + + Dropdown.prototype.position = function ($dropdown, $container) { + // Should be implemented in subclasses + }; + + Dropdown.prototype.destroy = function () { + // Remove the dropdown from the DOM + this.$dropdown.remove(); + }; + + return Dropdown; +}); + +S2.define('select2/dropdown/search',[ + 'jquery', + '../utils' +], function ($, Utils) { + function Search () { } + + Search.prototype.render = function (decorated) { + var $rendered = decorated.call(this); + + var $search = $( + '' + + '' + + '' + ); + + this.$searchContainer = $search; + this.$search = $search.find('input'); + + $rendered.prepend($search); + + return $rendered; + }; + + Search.prototype.bind = function (decorated, container, $container) { + var self = this; + + var resultsId = container.id + '-results'; + + decorated.call(this, container, $container); + + this.$search.on('keydown', function (evt) { + self.trigger('keypress', evt); + + self._keyUpPrevented = evt.isDefaultPrevented(); + }); + + // Workaround for browsers which do not support the `input` event + // This will prevent double-triggering of events for browsers which support + // both the `keyup` and `input` events. + this.$search.on('input', function (evt) { + // Unbind the duplicated `keyup` event + $(this).off('keyup'); + }); + + this.$search.on('keyup input', function (evt) { + self.handleSearch(evt); + }); + + container.on('open', function () { + self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); + + self.$search.trigger('focus'); + + window.setTimeout(function () { + self.$search.trigger('focus'); + }, 0); + }); + + container.on('close', function () { + self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); + + self.$search.val(''); + self.$search.trigger('blur'); + }); + + container.on('focus', function () { + if (!container.isOpen()) { + self.$search.trigger('focus'); + } + }); + + container.on('results:all', function (params) { + if (params.query.term == null || params.query.term === '') { + var showSearch = self.showSearch(params); + + if (showSearch) { + self.$searchContainer.removeClass('select2-search--hide'); + } else { + self.$searchContainer.addClass('select2-search--hide'); + } + } + }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); + }; + + Search.prototype.handleSearch = function (evt) { + if (!this._keyUpPrevented) { + var input = this.$search.val(); + + this.trigger('query', { + term: input + }); + } + + this._keyUpPrevented = false; + }; + + Search.prototype.showSearch = function (_, params) { + return true; + }; + + return Search; +}); + +S2.define('select2/dropdown/hidePlaceholder',[ + +], function () { + function HidePlaceholder (decorated, $element, options, dataAdapter) { + this.placeholder = this.normalizePlaceholder(options.get('placeholder')); + + decorated.call(this, $element, options, dataAdapter); + } + + HidePlaceholder.prototype.append = function (decorated, data) { + data.results = this.removePlaceholder(data.results); + + decorated.call(this, data); + }; + + HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) { + if (typeof placeholder === 'string') { + placeholder = { + id: '', + text: placeholder + }; + } + + return placeholder; + }; + + HidePlaceholder.prototype.removePlaceholder = function (_, data) { + var modifiedData = data.slice(0); + + for (var d = data.length - 1; d >= 0; d--) { + var item = data[d]; + + if (this.placeholder.id === item.id) { + modifiedData.splice(d, 1); + } + } + + return modifiedData; + }; + + return HidePlaceholder; +}); + +S2.define('select2/dropdown/infiniteScroll',[ + 'jquery' +], function ($) { + function InfiniteScroll (decorated, $element, options, dataAdapter) { + this.lastParams = {}; + + decorated.call(this, $element, options, dataAdapter); + + this.$loadingMore = this.createLoadingMore(); + this.loading = false; + } + + InfiniteScroll.prototype.append = function (decorated, data) { + this.$loadingMore.remove(); + this.loading = false; + + decorated.call(this, data); + + if (this.showLoadingMore(data)) { + this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); + } + }; + + InfiniteScroll.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('query', function (params) { + self.lastParams = params; + self.loading = true; + }); + + container.on('query:append', function (params) { + self.lastParams = params; + self.loading = true; + }); + + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; + + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); + + if (this.loading || !isLoadMoreVisible) { + return; + } + + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } + }; + + InfiniteScroll.prototype.loadMore = function () { + this.loading = true; + + var params = $.extend({}, {page: 1}, this.lastParams); + + params.page++; + + this.trigger('query:append', params); + }; + + InfiniteScroll.prototype.showLoadingMore = function (_, data) { + return data.pagination && data.pagination.more; + }; + + InfiniteScroll.prototype.createLoadingMore = function () { + var $option = $( + '
      • ' + ); + + var message = this.options.get('translations').get('loadingMore'); + + $option.html(message(this.lastParams)); + + return $option; + }; + + return InfiniteScroll; +}); + +S2.define('select2/dropdown/attachBody',[ + 'jquery', + '../utils' +], function ($, Utils) { + function AttachBody (decorated, $element, options) { + this.$dropdownParent = $(options.get('dropdownParent') || document.body); + + decorated.call(this, $element, options); + } + + AttachBody.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('open', function () { + self._showDropdown(); + self._attachPositioningHandler(container); + + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); + }); + + container.on('close', function () { + self._hideDropdown(); + self._detachPositioningHandler(container); + }); + + this.$dropdownContainer.on('mousedown', function (evt) { + evt.stopPropagation(); + }); + }; + + AttachBody.prototype.destroy = function (decorated) { + decorated.call(this); + + this.$dropdownContainer.remove(); + }; + + AttachBody.prototype.position = function (decorated, $dropdown, $container) { + // Clone all of the container classes + $dropdown.attr('class', $container.attr('class')); + + $dropdown.removeClass('select2'); + $dropdown.addClass('select2-container--open'); + + $dropdown.css({ + position: 'absolute', + top: -999999 + }); + + this.$container = $container; + }; + + AttachBody.prototype.render = function (decorated) { + var $container = $(''); + + var $dropdown = decorated.call(this); + $container.append($dropdown); + + this.$dropdownContainer = $container; + + return $container; + }; + + AttachBody.prototype._hideDropdown = function (decorated) { + this.$dropdownContainer.detach(); + }; + + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + + AttachBody.prototype._attachPositioningHandler = + function (decorated, container) { + var self = this; + + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.each(function () { + Utils.StoreData(this, 'select2-scroll-position', { + x: $(this).scrollLeft(), + y: $(this).scrollTop() + }); + }); + + $watchers.on(scrollEvent, function (ev) { + var position = Utils.GetData(this, 'select2-scroll-position'); + $(this).scrollTop(position.y); + }); + + $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent, + function (e) { + self._positionDropdown(); + self._resizeDropdown(); + }); + }; + + AttachBody.prototype._detachPositioningHandler = + function (decorated, container) { + var scrollEvent = 'scroll.select2.' + container.id; + var resizeEvent = 'resize.select2.' + container.id; + var orientationEvent = 'orientationchange.select2.' + container.id; + + var $watchers = this.$container.parents().filter(Utils.hasScroll); + $watchers.off(scrollEvent); + + $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent); + }; + + AttachBody.prototype._positionDropdown = function () { + var $window = $(window); + + var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above'); + var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below'); + + var newDirection = null; + + var offset = this.$container.offset(); + + offset.bottom = offset.top + this.$container.outerHeight(false); + + var container = { + height: this.$container.outerHeight(false) + }; + + container.top = offset.top; + container.bottom = offset.top + container.height; + + var dropdown = { + height: this.$dropdown.outerHeight(false) + }; + + var viewport = { + top: $window.scrollTop(), + bottom: $window.scrollTop() + $window.height() + }; + + var enoughRoomAbove = viewport.top < (offset.top - dropdown.height); + var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height); + + var css = { + left: offset.left, + top: container.bottom + }; + + // Determine what the parent element is to use for calculating the offset + var $offsetParent = this.$dropdownParent; + + // For statically positioned elements, we need to get the element + // that is determining the offset + if ($offsetParent.css('position') === 'static') { + $offsetParent = $offsetParent.offsetParent(); + } + + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } + + css.top -= parentOffset.top; + css.left -= parentOffset.left; + + if (!isCurrentlyAbove && !isCurrentlyBelow) { + newDirection = 'below'; + } + + if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) { + newDirection = 'above'; + } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) { + newDirection = 'below'; + } + + if (newDirection == 'above' || + (isCurrentlyAbove && newDirection !== 'below')) { + css.top = container.top - parentOffset.top - dropdown.height; + } + + if (newDirection != null) { + this.$dropdown + .removeClass('select2-dropdown--below select2-dropdown--above') + .addClass('select2-dropdown--' + newDirection); + this.$container + .removeClass('select2-container--below select2-container--above') + .addClass('select2-container--' + newDirection); + } + + this.$dropdownContainer.css(css); + }; + + AttachBody.prototype._resizeDropdown = function () { + var css = { + width: this.$container.outerWidth(false) + 'px' + }; + + if (this.options.get('dropdownAutoWidth')) { + css.minWidth = css.width; + css.position = 'relative'; + css.width = 'auto'; + } + + this.$dropdown.css(css); + }; + + AttachBody.prototype._showDropdown = function (decorated) { + this.$dropdownContainer.appendTo(this.$dropdownParent); + + this._positionDropdown(); + this._resizeDropdown(); + }; + + return AttachBody; +}); + +S2.define('select2/dropdown/minimumResultsForSearch',[ + +], function () { + function countResults (data) { + var count = 0; + + for (var d = 0; d < data.length; d++) { + var item = data[d]; + + if (item.children) { + count += countResults(item.children); + } else { + count++; + } + } + + return count; + } + + function MinimumResultsForSearch (decorated, $element, options, dataAdapter) { + this.minimumResultsForSearch = options.get('minimumResultsForSearch'); + + if (this.minimumResultsForSearch < 0) { + this.minimumResultsForSearch = Infinity; + } + + decorated.call(this, $element, options, dataAdapter); + } + + MinimumResultsForSearch.prototype.showSearch = function (decorated, params) { + if (countResults(params.data.results) < this.minimumResultsForSearch) { + return false; + } + + return decorated.call(this, params); + }; + + return MinimumResultsForSearch; +}); + +S2.define('select2/dropdown/selectOnClose',[ + '../utils' +], function (Utils) { + function SelectOnClose () { } + + SelectOnClose.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('close', function (params) { + self._handleSelectOnClose(params); + }); + }; + + SelectOnClose.prototype._handleSelectOnClose = function (_, params) { + if (params && params.originalSelect2Event != null) { + var event = params.originalSelect2Event; + + // Don't select an item if the close event was triggered from a select or + // unselect event + if (event._type === 'select' || event._type === 'unselect') { + return; + } + } + + var $highlightedResults = this.getHighlightedResults(); + + // Only select highlighted results + if ($highlightedResults.length < 1) { + return; + } + + var data = Utils.GetData($highlightedResults[0], 'data'); + + // Don't re-select already selected resulte + if ( + (data.element != null && data.element.selected) || + (data.element == null && data.selected) + ) { + return; + } + + this.trigger('select', { + data: data + }); + }; + + return SelectOnClose; +}); + +S2.define('select2/dropdown/closeOnSelect',[ + +], function () { + function CloseOnSelect () { } + + CloseOnSelect.prototype.bind = function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function (evt) { + self._selectTriggered(evt); + }); + + container.on('unselect', function (evt) { + self._selectTriggered(evt); + }); + }; + + CloseOnSelect.prototype._selectTriggered = function (_, evt) { + var originalEvent = evt.originalEvent; + + // Don't close if the control key is being held + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { + return; + } + + this.trigger('close', { + originalEvent: originalEvent, + originalSelect2Event: evt + }); + }; + + return CloseOnSelect; +}); + +S2.define('select2/i18n/en',[],function () { + // English + return { + errorLoading: function () { + return 'The results could not be loaded.'; + }, + inputTooLong: function (args) { + var overChars = args.input.length - args.maximum; + + var message = 'Please delete ' + overChars + ' character'; + + if (overChars != 1) { + message += 's'; + } + + return message; + }, + inputTooShort: function (args) { + var remainingChars = args.minimum - args.input.length; + + var message = 'Please enter ' + remainingChars + ' or more characters'; + + return message; + }, + loadingMore: function () { + return 'Loading more results…'; + }, + maximumSelected: function (args) { + var message = 'You can only select ' + args.maximum + ' item'; + + if (args.maximum != 1) { + message += 's'; + } + + return message; + }, + noResults: function () { + return 'No results found'; + }, + searching: function () { + return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; + } + }; +}); + +S2.define('select2/defaults',[ + 'jquery', + 'require', + + './results', + + './selection/single', + './selection/multiple', + './selection/placeholder', + './selection/allowClear', + './selection/search', + './selection/eventRelay', + + './utils', + './translation', + './diacritics', + + './data/select', + './data/array', + './data/ajax', + './data/tags', + './data/tokenizer', + './data/minimumInputLength', + './data/maximumInputLength', + './data/maximumSelectionLength', + + './dropdown', + './dropdown/search', + './dropdown/hidePlaceholder', + './dropdown/infiniteScroll', + './dropdown/attachBody', + './dropdown/minimumResultsForSearch', + './dropdown/selectOnClose', + './dropdown/closeOnSelect', + + './i18n/en' +], function ($, require, + + ResultsList, + + SingleSelection, MultipleSelection, Placeholder, AllowClear, + SelectionSearch, EventRelay, + + Utils, Translation, DIACRITICS, + + SelectData, ArrayData, AjaxData, Tags, Tokenizer, + MinimumInputLength, MaximumInputLength, MaximumSelectionLength, + + Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll, + AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect, + + EnglishTranslation) { + function Defaults () { + this.reset(); + } + + Defaults.prototype.apply = function (options) { + options = $.extend(true, {}, this.defaults, options); + + if (options.dataAdapter == null) { + if (options.ajax != null) { + options.dataAdapter = AjaxData; + } else if (options.data != null) { + options.dataAdapter = ArrayData; + } else { + options.dataAdapter = SelectData; + } + + if (options.minimumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MinimumInputLength + ); + } + + if (options.maximumInputLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumInputLength + ); + } + + if (options.maximumSelectionLength > 0) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + MaximumSelectionLength + ); + } + + if (options.tags) { + options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags); + } + + if (options.tokenSeparators != null || options.tokenizer != null) { + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Tokenizer + ); + } + + if (options.query != null) { + var Query = require(options.amdBase + 'compat/query'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + Query + ); + } + + if (options.initSelection != null) { + var InitSelection = require(options.amdBase + 'compat/initSelection'); + + options.dataAdapter = Utils.Decorate( + options.dataAdapter, + InitSelection + ); + } + } + + if (options.resultsAdapter == null) { + options.resultsAdapter = ResultsList; + + if (options.ajax != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + InfiniteScroll + ); + } + + if (options.placeholder != null) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + HidePlaceholder + ); + } + + if (options.selectOnClose) { + options.resultsAdapter = Utils.Decorate( + options.resultsAdapter, + SelectOnClose + ); + } + } + + if (options.dropdownAdapter == null) { + if (options.multiple) { + options.dropdownAdapter = Dropdown; + } else { + var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch); + + options.dropdownAdapter = SearchableDropdown; + } + + if (options.minimumResultsForSearch !== 0) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + MinimumResultsForSearch + ); + } + + if (options.closeOnSelect) { + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + CloseOnSelect + ); + } + + if ( + options.dropdownCssClass != null || + options.dropdownCss != null || + options.adaptDropdownCssClass != null + ) { + var DropdownCSS = require(options.amdBase + 'compat/dropdownCss'); + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + DropdownCSS + ); + } + + options.dropdownAdapter = Utils.Decorate( + options.dropdownAdapter, + AttachBody + ); + } + + if (options.selectionAdapter == null) { + if (options.multiple) { + options.selectionAdapter = MultipleSelection; + } else { + options.selectionAdapter = SingleSelection; + } + + // Add the placeholder mixin if a placeholder was specified + if (options.placeholder != null) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + Placeholder + ); + } + + if (options.allowClear) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + AllowClear + ); + } + + if (options.multiple) { + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + SelectionSearch + ); + } + + if ( + options.containerCssClass != null || + options.containerCss != null || + options.adaptContainerCssClass != null + ) { + var ContainerCSS = require(options.amdBase + 'compat/containerCss'); + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + ContainerCSS + ); + } + + options.selectionAdapter = Utils.Decorate( + options.selectionAdapter, + EventRelay + ); + } + + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); + + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); + } + } + + options.language = uniqueLanguages; + + options.translations = this._processTranslations( + options.language, + options.debug + ); + + return options; + }; + + Defaults.prototype.reset = function () { + function stripDiacritics (text) { + // Used 'uni range + named function' from http://jsperf.com/diacritics/18 + function match(a) { + return DIACRITICS[a] || a; + } + + return text.replace(/[^\u0000-\u007E]/g, match); + } + + function matcher (params, data) { + // Always return the object if there is nothing to compare + if ($.trim(params.term) === '') { + return data; + } + + // Do a recursive check for options with children + if (data.children && data.children.length > 0) { + // Clone the data object if there are children + // This is required as we modify the object to remove any non-matches + var match = $.extend(true, {}, data); + + // Check each child of the option + for (var c = data.children.length - 1; c >= 0; c--) { + var child = data.children[c]; + + var matches = matcher(params, child); + + // If there wasn't a match, remove the object in the array + if (matches == null) { + match.children.splice(c, 1); + } + } + + // If any children matched, return the new object + if (match.children.length > 0) { + return match; + } + + // If there were no matching children, check just the plain object + return matcher(params, match); + } + + var original = stripDiacritics(data.text).toUpperCase(); + var term = stripDiacritics(params.term).toUpperCase(); + + // Check if the text contains the term + if (original.indexOf(term) > -1) { + return data; + } + + // If it doesn't contain the term, don't return anything + return null; + } + + this.defaults = { + amdBase: './', + amdLanguageBase: './i18n/', + closeOnSelect: true, + debug: false, + dropdownAutoWidth: false, + escapeMarkup: Utils.escapeMarkup, + language: {}, + matcher: matcher, + minimumInputLength: 0, + maximumInputLength: 0, + maximumSelectionLength: 0, + minimumResultsForSearch: 0, + selectOnClose: false, + scrollAfterSelect: false, + sorter: function (data) { + return data; + }, + templateResult: function (result) { + return result.text; + }, + templateSelection: function (selection) { + return selection.text; + }, + theme: 'default', + width: 'resolve' + }; + }; + + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + + Defaults.prototype.set = function (key, value) { + var camelKey = $.camelCase(key); + + var data = {}; + data[camelKey] = value; + + var convertedData = Utils._convertData(data); + + $.extend(true, this.defaults, convertedData); + }; + + var defaults = new Defaults(); + + return defaults; +}); + +S2.define('select2/options',[ + 'require', + 'jquery', + './defaults', + './utils' +], function (require, $, Defaults, Utils) { + function Options (options, $element) { + this.options = options; + + if ($element != null) { + this.fromElement($element); + } + + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + + this.options = Defaults.apply(this.options); + + if ($element && $element.is('input')) { + var InputCompat = require(this.get('amdBase') + 'compat/inputData'); + + this.options.dataAdapter = Utils.Decorate( + this.options.dataAdapter, + InputCompat + ); + } + } + + Options.prototype.fromElement = function ($e) { + var excludedData = ['select2']; + + if (this.options.multiple == null) { + this.options.multiple = $e.prop('multiple'); + } + + if (this.options.disabled == null) { + this.options.disabled = $e.prop('disabled'); + } + + if (this.options.dir == null) { + if ($e.prop('dir')) { + this.options.dir = $e.prop('dir'); + } else if ($e.closest('[dir]').prop('dir')) { + this.options.dir = $e.closest('[dir]').prop('dir'); + } else { + this.options.dir = 'ltr'; + } + } + + $e.prop('disabled', this.options.disabled); + $e.prop('multiple', this.options.multiple); + + if (Utils.GetData($e[0], 'select2Tags')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-select2-tags` attribute has been changed to ' + + 'use the `data-data` and `data-tags="true"` attributes and will be ' + + 'removed in future versions of Select2.' + ); + } + + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); + } + + if (Utils.GetData($e[0], 'ajaxUrl')) { + if (this.options.debug && window.console && console.warn) { + console.warn( + 'Select2: The `data-ajax-url` attribute has been changed to ' + + '`data-ajax--url` and support for the old attribute will be removed' + + ' in future versions of Select2.' + ); + } + + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); + } + + var dataset = {}; + + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + + // Prefer the element's `dataset` attribute if it exists + // jQuery 1.x does not correctly handle data attributes with multiple dashes + if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { + dataset = $.extend(true, {}, $e[0].dataset, dataset); + } + + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); + + data = Utils._convertData(data); + + for (var key in data) { + if ($.inArray(key, excludedData) > -1) { + continue; + } + + if ($.isPlainObject(this.options[key])) { + $.extend(this.options[key], data[key]); + } else { + this.options[key] = data[key]; + } + } + + return this; + }; + + Options.prototype.get = function (key) { + return this.options[key]; + }; + + Options.prototype.set = function (key, val) { + this.options[key] = val; + }; + + return Options; +}); + +S2.define('select2/core',[ + 'jquery', + './options', + './utils', + './keys' +], function ($, Options, Utils, KEYS) { + var Select2 = function ($element, options) { + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); + } + + this.$element = $element; + + this.id = this._generateId($element); + + options = options || {}; + + this.options = new Options(options, $element); + + Select2.__super__.constructor.call(this); + + // Set up the tabindex + + var tabindex = $element.attr('tabindex') || 0; + Utils.StoreData($element[0], 'old-tabindex', tabindex); + $element.attr('tabindex', '-1'); + + // Set up containers and adapters + + var DataAdapter = this.options.get('dataAdapter'); + this.dataAdapter = new DataAdapter($element, this.options); + + var $container = this.render(); + + this._placeContainer($container); + + var SelectionAdapter = this.options.get('selectionAdapter'); + this.selection = new SelectionAdapter($element, this.options); + this.$selection = this.selection.render(); + + this.selection.position(this.$selection, $container); + + var DropdownAdapter = this.options.get('dropdownAdapter'); + this.dropdown = new DropdownAdapter($element, this.options); + this.$dropdown = this.dropdown.render(); + + this.dropdown.position(this.$dropdown, $container); + + var ResultsAdapter = this.options.get('resultsAdapter'); + this.results = new ResultsAdapter($element, this.options, this.dataAdapter); + this.$results = this.results.render(); + + this.results.position(this.$results, this.$dropdown); + + // Bind events + + var self = this; + + // Bind the container to all of the adapters + this._bindAdapters(); + + // Register any DOM event handlers + this._registerDomEvents(); + + // Register any internal event handlers + this._registerDataEvents(); + this._registerSelectionEvents(); + this._registerDropdownEvents(); + this._registerResultsEvents(); + this._registerEvents(); + + // Set the initial state + this.dataAdapter.current(function (initialData) { + self.trigger('selection:update', { + data: initialData + }); + }); + + // Hide the original select + $element.addClass('select2-hidden-accessible'); + $element.attr('aria-hidden', 'true'); + + // Synchronize any monitored attributes + this._syncAttributes(); + + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). + $element.data('select2', this); + }; + + Utils.Extend(Select2, Utils.Observable); + + Select2.prototype._generateId = function ($element) { + var id = ''; + + if ($element.attr('id') != null) { + id = $element.attr('id'); + } else if ($element.attr('name') != null) { + id = $element.attr('name') + '-' + Utils.generateChars(2); + } else { + id = Utils.generateChars(4); + } + + id = id.replace(/(:|\.|\[|\]|,)/g, ''); + id = 'select2-' + id; + + return id; + }; + + Select2.prototype._placeContainer = function ($container) { + $container.insertAfter(this.$element); + + var width = this._resolveWidth(this.$element, this.options.get('width')); + + if (width != null) { + $container.css('width', width); + } + }; + + Select2.prototype._resolveWidth = function ($element, method) { + var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i; + + if (method == 'resolve') { + var styleWidth = this._resolveWidth($element, 'style'); + + if (styleWidth != null) { + return styleWidth; + } + + return this._resolveWidth($element, 'element'); + } + + if (method == 'element') { + var elementWidth = $element.outerWidth(false); + + if (elementWidth <= 0) { + return 'auto'; + } + + return elementWidth + 'px'; + } + + if (method == 'style') { + var style = $element.attr('style'); + + if (typeof(style) !== 'string') { + return null; + } + + var attrs = style.split(';'); + + for (var i = 0, l = attrs.length; i < l; i = i + 1) { + var attr = attrs[i].replace(/\s/g, ''); + var matches = attr.match(WIDTH); + + if (matches !== null && matches.length >= 1) { + return matches[1]; + } + } + + return null; + } + + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + + return method; + }; + + Select2.prototype._bindAdapters = function () { + this.dataAdapter.bind(this, this.$container); + this.selection.bind(this, this.$container); + + this.dropdown.bind(this, this.$container); + this.results.bind(this, this.$container); + }; + + Select2.prototype._registerDomEvents = function () { + var self = this; + + this.$element.on('change.select2', function () { + self.dataAdapter.current(function (data) { + self.trigger('selection:update', { + data: data + }); + }); + }); + + this.$element.on('focus.select2', function (evt) { + self.trigger('focus', evt); + }); + + this._syncA = Utils.bind(this._syncAttributes, this); + this._syncS = Utils.bind(this._syncSubtree, this); + + if (this.$element[0].attachEvent) { + this.$element[0].attachEvent('onpropertychange', this._syncA); + } + + var observer = window.MutationObserver || + window.WebKitMutationObserver || + window.MozMutationObserver + ; + + if (observer != null) { + this._observer = new observer(function (mutations) { + self._syncA(); + self._syncS(null, mutations); + }); + this._observer.observe(this.$element[0], { + attributes: true, + childList: true, + subtree: false + }); + } else if (this.$element[0].addEventListener) { + this.$element[0].addEventListener( + 'DOMAttrModified', + self._syncA, + false + ); + this.$element[0].addEventListener( + 'DOMNodeInserted', + self._syncS, + false + ); + this.$element[0].addEventListener( + 'DOMNodeRemoved', + self._syncS, + false + ); + } + }; + + Select2.prototype._registerDataEvents = function () { + var self = this; + + this.dataAdapter.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerSelectionEvents = function () { + var self = this; + var nonRelayEvents = ['toggle', 'focus']; + + this.selection.on('toggle', function () { + self.toggleDropdown(); + }); + + this.selection.on('focus', function (params) { + self.focus(params); + }); + + this.selection.on('*', function (name, params) { + if ($.inArray(name, nonRelayEvents) !== -1) { + return; + } + + self.trigger(name, params); + }); + }; + + Select2.prototype._registerDropdownEvents = function () { + var self = this; + + this.dropdown.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerResultsEvents = function () { + var self = this; + + this.results.on('*', function (name, params) { + self.trigger(name, params); + }); + }; + + Select2.prototype._registerEvents = function () { + var self = this; + + this.on('open', function () { + self.$container.addClass('select2-container--open'); + }); + + this.on('close', function () { + self.$container.removeClass('select2-container--open'); + }); + + this.on('enable', function () { + self.$container.removeClass('select2-container--disabled'); + }); + + this.on('disable', function () { + self.$container.addClass('select2-container--disabled'); + }); + + this.on('blur', function () { + self.$container.removeClass('select2-container--focus'); + }); + + this.on('query', function (params) { + if (!self.isOpen()) { + self.trigger('open', {}); + } + + this.dataAdapter.query(params, function (data) { + self.trigger('results:all', { + data: data, + query: params + }); + }); + }); + + this.on('query:append', function (params) { + this.dataAdapter.query(params, function (data) { + self.trigger('results:append', { + data: data, + query: params + }); + }); + }); + + this.on('keypress', function (evt) { + var key = evt.which; + + if (self.isOpen()) { + if (key === KEYS.ESC || key === KEYS.TAB || + (key === KEYS.UP && evt.altKey)) { + self.close(evt); + + evt.preventDefault(); + } else if (key === KEYS.ENTER) { + self.trigger('results:select', {}); + + evt.preventDefault(); + } else if ((key === KEYS.SPACE && evt.ctrlKey)) { + self.trigger('results:toggle', {}); + + evt.preventDefault(); + } else if (key === KEYS.UP) { + self.trigger('results:previous', {}); + + evt.preventDefault(); + } else if (key === KEYS.DOWN) { + self.trigger('results:next', {}); + + evt.preventDefault(); + } + } else { + if (key === KEYS.ENTER || key === KEYS.SPACE || + (key === KEYS.DOWN && evt.altKey)) { + self.open(); + + evt.preventDefault(); + } + } + }); + }; + + Select2.prototype._syncAttributes = function () { + this.options.set('disabled', this.$element.prop('disabled')); + + if (this.isDisabled()) { + if (this.isOpen()) { + this.close(); + } + + this.trigger('disable', {}); + } else { + this.trigger('enable', {}); + } + }; + + Select2.prototype._isChangeMutation = function (evt, mutations) { + var changed = false; + var self = this; + + // Ignore any mutation events raised for elements that aren't options or + // optgroups. This handles the case when the select element is destroyed + if ( + evt && evt.target && ( + evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP' + ) + ) { + return; + } + + if (!mutations) { + // If mutation events aren't supported, then we can only assume that the + // change affected the selections + changed = true; + } else if (mutations.addedNodes && mutations.addedNodes.length > 0) { + for (var n = 0; n < mutations.addedNodes.length; n++) { + var node = mutations.addedNodes[n]; + + if (node.selected) { + changed = true; + } + } + } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { + changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); + } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; + + // Only re-pull the data if we think there is a change + if (changed) { + this.dataAdapter.current(function (currentData) { + self.trigger('selection:update', { + data: currentData + }); + }); + } + }; + + /** + * Override the trigger method to automatically trigger pre-events when + * there are events that can be prevented. + */ + Select2.prototype.trigger = function (name, args) { + var actualTrigger = Select2.__super__.trigger; + var preTriggerMap = { + 'open': 'opening', + 'close': 'closing', + 'select': 'selecting', + 'unselect': 'unselecting', + 'clear': 'clearing' + }; + + if (args === undefined) { + args = {}; + } + + if (name in preTriggerMap) { + var preTriggerName = preTriggerMap[name]; + var preTriggerArgs = { + prevented: false, + name: name, + args: args + }; + + actualTrigger.call(this, preTriggerName, preTriggerArgs); + + if (preTriggerArgs.prevented) { + args.prevented = true; + + return; + } + } + + actualTrigger.call(this, name, args); + }; + + Select2.prototype.toggleDropdown = function () { + if (this.isDisabled()) { + return; + } + + if (this.isOpen()) { + this.close(); + } else { + this.open(); + } + }; + + Select2.prototype.open = function () { + if (this.isOpen()) { + return; + } + + if (this.isDisabled()) { + return; + } + + this.trigger('query', {}); + }; + + Select2.prototype.close = function (evt) { + if (!this.isOpen()) { + return; + } + + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + + Select2.prototype.isOpen = function () { + return this.$container.hasClass('select2-container--open'); + }; + + Select2.prototype.hasFocus = function () { + return this.$container.hasClass('select2-container--focus'); + }; + + Select2.prototype.focus = function (data) { + // No need to re-trigger focus events if we are already focused + if (this.hasFocus()) { + return; + } + + this.$container.addClass('select2-container--focus'); + this.trigger('focus', {}); + }; + + Select2.prototype.enable = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("enable")` method has been deprecated and will' + + ' be removed in later Select2 versions. Use $element.prop("disabled")' + + ' instead.' + ); + } + + if (args == null || args.length === 0) { + args = [true]; + } + + var disabled = !args[0]; + + this.$element.prop('disabled', disabled); + }; + + Select2.prototype.data = function () { + if (this.options.get('debug') && + arguments.length > 0 && window.console && console.warn) { + console.warn( + 'Select2: Data can no longer be set using `select2("data")`. You ' + + 'should consider setting the value instead using `$element.val()`.' + ); + } + + var data = []; + + this.dataAdapter.current(function (currentData) { + data = currentData; + }); + + return data; + }; + + Select2.prototype.val = function (args) { + if (this.options.get('debug') && window.console && console.warn) { + console.warn( + 'Select2: The `select2("val")` method has been deprecated and will be' + + ' removed in later Select2 versions. Use $element.val() instead.' + ); + } + + if (args == null || args.length === 0) { + return this.$element.val(); + } + + var newVal = args[0]; + + if ($.isArray(newVal)) { + newVal = $.map(newVal, function (obj) { + return obj.toString(); + }); + } + + this.$element.val(newVal).trigger('input').trigger('change'); + }; + + Select2.prototype.destroy = function () { + this.$container.remove(); + + if (this.$element[0].detachEvent) { + this.$element[0].detachEvent('onpropertychange', this._syncA); + } + + if (this._observer != null) { + this._observer.disconnect(); + this._observer = null; + } else if (this.$element[0].removeEventListener) { + this.$element[0] + .removeEventListener('DOMAttrModified', this._syncA, false); + this.$element[0] + .removeEventListener('DOMNodeInserted', this._syncS, false); + this.$element[0] + .removeEventListener('DOMNodeRemoved', this._syncS, false); + } + + this._syncA = null; + this._syncS = null; + + this.$element.off('.select2'); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); + + this.$element.removeClass('select2-hidden-accessible'); + this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); + this.$element.removeData('select2'); + + this.dataAdapter.destroy(); + this.selection.destroy(); + this.dropdown.destroy(); + this.results.destroy(); + + this.dataAdapter = null; + this.selection = null; + this.dropdown = null; + this.results = null; + }; + + Select2.prototype.render = function () { + var $container = $( + '' + + '' + + '' + + '' + ); + + $container.attr('dir', this.options.get('dir')); + + this.$container = $container; + + this.$container.addClass('select2-container--' + this.options.get('theme')); + + Utils.StoreData($container[0], 'element', this.$element); + + return $container; + }; + + return Select2; +}); + +S2.define('jquery-mousewheel',[ + 'jquery' +], function ($) { + // Used to shim jQuery.mousewheel for non-full builds. + return $; +}); + +S2.define('jquery.select2',[ + 'jquery', + 'jquery-mousewheel', + + './select2/core', + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { + if ($.fn.select2 == null) { + // All methods that should return the element + var thisMethods = ['open', 'close', 'destroy']; + + $.fn.select2 = function (options) { + options = options || {}; + + if (typeof options === 'object') { + this.each(function () { + var instanceOptions = $.extend(true, {}, options); + + var instance = new Select2($(this), instanceOptions); + }); + + return this; + } else if (typeof options === 'string') { + var ret; + var args = Array.prototype.slice.call(arguments, 1); + + this.each(function () { + var instance = Utils.GetData(this, 'select2'); + + if (instance == null && window.console && console.error) { + console.error( + 'The select2(\'' + options + '\') method was called on an ' + + 'element that is not using Select2.' + ); + } + + ret = instance[options].apply(instance, args); + }); + + // Check if we should be returning `this` + if ($.inArray(options, thisMethods) > -1) { + return this; + } + + return ret; + } else { + throw new Error('Invalid arguments for Select2: ' + options); + } + }; + } + + if ($.fn.select2.defaults == null) { + $.fn.select2.defaults = Defaults; + } + + return Select2; +}); + + // Return the AMD loader configuration so it can be used outside of this file + return { + define: S2.define, + require: S2.require + }; +}()); + + // Autoload the jQuery bindings + // We know that all of the modules exist above this, so we're safe + var select2 = S2.require('jquery.select2'); + + // Hold the AMD module references on the jQuery function that was just loaded + // This allows Select2 to use the internal loader outside of this file, such + // as in the language files. + jQuery.fn.select2.amd = S2; + + // Return the Select2 instance for anyone who is importing it. + return select2; +})); diff --git a/html/webpage/home.html b/html/webpage/home.html index bce5b87..bb3c291 100644 --- a/html/webpage/home.html +++ b/html/webpage/home.html @@ -4,54 +4,63 @@ - AAS_NewGen + AAS_NewGen_03Sept25 + -

        Automatic Announcement System

        +
        +
        +
        +
        +

        Automatic Announcement System

        +
        +
        +
        +
        - +
        -
        -
        -
        -
        -
        +
        +

        CPU Status : 

        -
        -

        CPU Status

        +
        +

        RAM Status : 

        -
        -

        RAM Status

        +
        +

        Disk Status : 

        -
        -

        Disk Status

        +
        +

        Network 

        -
        -

        Network Status

        -
        -
        -

        Date and Time

        -
        -
        -
        -
        -
        +
        +

        Date and Time 

        +
        + diff --git a/html/webpage/language.html b/html/webpage/language.html index 231e95a..e313dd3 100644 --- a/html/webpage/language.html +++ b/html/webpage/language.html @@ -4,24 +4,25 @@ - AAS_NewGen + AAS_NewGen_03Sept25 +
        -
        -

        Language Link

        +
        +

        Language Link

        -
        -
        -
        -
        -
        -
        +
        +
        +
        +
        +
        +
        @@ -69,22 +70,23 @@
        - \ No newline at end of file diff --git a/html/webpage/log.html b/html/webpage/log.html index 3a79fb0..4d1c641 100644 --- a/html/webpage/log.html +++ b/html/webpage/log.html @@ -4,34 +4,28 @@ - AAS_NewGen + AAS_NewGen_03Sept25 +
        -
        -

        Operational Log

        +
        +

        Operational Log

        -
        -
        -
        -

        Select Log Date

        -
        -
        -
        +
        +

        Select Log Date

        -
        -
        -
        -

        Search

        -
        -
        -
        +
        +
        +
        +

        Search

        +
        @@ -62,7 +56,6 @@
        - \ No newline at end of file diff --git a/html/webpage/login.html b/html/webpage/login.html index 34b05bf..2d5317b 100644 --- a/html/webpage/login.html +++ b/html/webpage/login.html @@ -4,9 +4,10 @@ - AAS_NewGen + AAS_NewGen_03Sept25 + @@ -14,20 +15,20 @@
        -

        Log in

        +

        Sign In

        -
        + - \ No newline at end of file diff --git a/html/webpage/messagebank.html b/html/webpage/messagebank.html index 790281c..80b7c50 100644 --- a/html/webpage/messagebank.html +++ b/html/webpage/messagebank.html @@ -4,24 +4,25 @@ - AAS_NewGen + AAS_NewGen_03Sept25 +
        -
        -

        Message Bank

        +
        +

        Message Bank

        -
        -
        -
        -
        -
        -
        +
        +
        +
        +
        +
        +
        @@ -69,23 +70,73 @@ - +
        - \ No newline at end of file diff --git a/html/webpage/overview.html b/html/webpage/overview.html new file mode 100644 index 0000000..dc1af99 --- /dev/null +++ b/html/webpage/overview.html @@ -0,0 +1,1325 @@ + + + + + + + AAS_NewGen_03Sept25 + + + + + + +
        +
        +

        Overview

        +
        +
        +
        +
        + +
        +
        +
        +
        +
        +
        +

        Channel 01

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 02

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 03

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 04

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 05

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 06

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 07

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 08

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 09

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 10

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 11

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 12

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 13

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 14

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 15

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 16

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 17

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 18

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 19

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 20

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 21

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 22

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 23

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 24

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 25

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 26

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 27

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 28

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 29

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 30

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 31

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 32

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 33

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 34

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 35

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 36

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 37

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 38

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 39

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 40

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 41

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 42

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 43

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 44

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 45

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 46

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 47

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 48

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 49

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 50

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 51

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 52

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 53

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 54

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 55

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 56

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 57

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 58

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 59

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 60

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 61

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 62

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 63

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +

        Channel 64

        +
        +
        +
        IP : 192.168.10.10
        +
        +
        +
        Free : 64KB
        +
        +
        +

        Status : Idle

        +
        +
        50%
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + +
        +
        +
        +
        + + + + + + + + +
        IndexDescription
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + +
        +
        +
        +
        + + + + + + + + +
        IndexDescription
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + + + + \ No newline at end of file diff --git a/html/webpage/setting.html b/html/webpage/setting.html index 9389aa8..6dff930 100644 --- a/html/webpage/setting.html +++ b/html/webpage/setting.html @@ -4,19 +4,19 @@ - AAS_NewGen + AAS_NewGen_03Sept25 +
        -
        -

        Setting

        +
        +

        Setting

        - \ No newline at end of file diff --git a/html/webpage/soundbank.html b/html/webpage/soundbank.html index 0a7a480..0ee3d91 100644 --- a/html/webpage/soundbank.html +++ b/html/webpage/soundbank.html @@ -4,35 +4,37 @@ - AAS_NewGen + AAS_NewGen_03Sept25 + - +
        -
        -

        Sound Bank

        +
        +

        Sound Bank

        -
        -

        Search

        +
        + -
        +
        -

        Table Length : N/A

        +

        Table Length : N/A

        -
        -
        -
        -
        -
        -
        +
        +
        +
        +
        +
        +
        @@ -71,62 +73,61 @@
        -

        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