.eslintcache 67 KB

1
  1. [{"C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js":"1"},{"size":62870,"mtime":1641847593736,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","errorCount":1,"fatalErrorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"6","usedDeprecatedRules":"7"},"7z2b57","C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\src\\js\\custom.js",["8"],"import he from 'he';\r\nimport { Promise } from 'es6-promise';\r\n\r\nif (!String.prototype.format) {\r\n Object.assign(String.prototype, {\r\n format() {\r\n const args = arguments;\r\n return this.replace(/{(\\d+)}/g, function(match, number) {\r\n return typeof args[number] !== 'undefined' ? args[number] : match;\r\n });\r\n }, \r\n }); \r\n}\r\nif (!String.prototype.encodeHTML) {\r\n Object.assign(String.prototype, {\r\n encodeHTML() {\r\n return he.encode(this).replace(/\\n/g, '<br />')\r\n },\r\n });\r\n}\r\nObject.assign(Date.prototype, {\r\n toLocalShort() {\r\n const opt = { dateStyle: 'short', timeStyle: 'short' };\r\n return this.toLocaleString(undefined, opt);\r\n },\r\n});\r\n\r\n\r\nconst nvsTypes = {\r\n NVS_TYPE_U8: 0x01,\r\n\r\n /*! < Type uint8_t */\r\n NVS_TYPE_I8: 0x11,\r\n\r\n /*! < Type int8_t */\r\n NVS_TYPE_U16: 0x02,\r\n\r\n /*! < Type uint16_t */\r\n NVS_TYPE_I16: 0x12,\r\n\r\n /*! < Type int16_t */\r\n NVS_TYPE_U32: 0x04,\r\n\r\n /*! < Type uint32_t */\r\n NVS_TYPE_I32: 0x14,\r\n\r\n /*! < Type int32_t */\r\n NVS_TYPE_U64: 0x08,\r\n\r\n /*! < Type uint64_t */\r\n NVS_TYPE_I64: 0x18,\r\n\r\n /*! < Type int64_t */\r\n NVS_TYPE_STR: 0x21,\r\n\r\n /*! < Type string */\r\n NVS_TYPE_BLOB: 0x42,\r\n\r\n /*! < Type blob */\r\n NVS_TYPE_ANY: 0xff /*! < Must be last */,\r\n};\r\nconst btIcons = {\r\n bt_playing: 'play-circle-fill',\r\n bt_disconnected: 'bluetooth-fill',\r\n bt_neutral: '',\r\n bt_connected: 'bluetooth-connect-fill',\r\n bt_disabled: '',\r\n play_arrow: 'play-circle-fill',\r\n pause: 'pause-circle-fill',\r\n stop: 'stop-circle-fill',\r\n '': '',\r\n};\r\n\r\nconst btStateIcons = [\r\n { desc: 'Idle', sub: ['bt_neutral'] },\r\n { desc: 'Discovering', sub: ['bt_disconnected'] },\r\n { desc: 'Discovered', sub: ['bt_disconnected'] },\r\n { desc: 'Unconnected', sub: ['bt_disconnected'] },\r\n { desc: 'Connecting', sub: ['bt_disconnected'] },\r\n { \r\n desc: 'Connected',\r\n sub: ['bt_connected', 'play_arrow', 'bt_playing', 'pause', 'stop'],\r\n },\r\n { desc: 'Disconnecting', sub: ['bt_disconnected'] },\r\n];\r\n\r\nconst pillcolors = {\r\n MESSAGING_INFO: 'badge-success',\r\n MESSAGING_WARNING: 'badge-warning',\r\n MESSAGING_ERROR: 'badge-danger',\r\n};\r\nconst connectReturnCode = {\r\n UPDATE_CONNECTION_OK : 0, \r\n\tUPDATE_FAILED_ATTEMPT : 1,\r\n\tUPDATE_USER_DISCONNECT : 2,\r\n UPDATE_LOST_CONNECTION : 3,\r\n UPDATE_FAILED_ATTEMPT_AND_RESTORE : 4\r\n}\r\nconst taskStates = {\r\n 0: 'eRunning',\r\n /*! < A task is querying the state of itself, so must be running. */\r\n 1: 'eReady',\r\n /*! < The task being queried is in a read or pending ready list. */\r\n 2: 'eBlocked',\r\n /*! < The task being queried is in the Blocked state. */\r\n 3: 'eSuspended',\r\n /*! < The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */\r\n 4: 'eDeleted',\r\n};\r\nconst flash_status_codes = {\r\n NONE : 0,\r\n REBOOT_TO_RECOVERY: 2,\r\n SET_FWURL: 5,\r\n FLASHING: 6,\r\n DONE: 7,\r\n UPLOADING: 8,\r\n ERROR: 9\r\n};\r\nlet flash_state=flash_status_codes.FLASH_NONE;\r\nlet flash_ota_dsc='';\r\nlet flash_ota_pct=0;\r\nlet older_recovery=false;\r\nlet presetsloaded=false;\r\nfunction isFlashExecuting(data){\r\n return (flash_state!=flash_status_codes.UPLOADING ) && (data.ota_dsc!='' || data.ota_pct>0);\r\n}\r\nfunction post_config(data){\r\n let confPayload={\r\n timestamp: Date.now(),\r\n config : data\r\n };\r\n $.ajax({\r\n url: '/config.json',\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify(confPayload),\r\n error: handleExceptionResponse,\r\n });\r\n}\r\nfunction process_ota_event(data){\r\n if(data.ota_dsc){\r\n flash_ota_dsc=data.ota_dsc;\r\n }\r\n if( data.ota_pct != undefined){\r\n flash_ota_pct=data.ota_pct;\r\n }\r\n \r\n if(flash_state==flash_status_codes.ERROR){\r\n return;\r\n }\r\n else if(isFlashExecuting(data)){\r\n flash_state=flash_status_codes.FLASHING;\r\n } \r\n else if(flash_state==flash_status_codes.FLASHING ){\r\n if(flash_ota_pct ==100){\r\n // we were processing OTA, and we've reached 100%\r\n flash_state=flash_status_codes.DONE;\r\n $('#flashfilename').val('');\r\n } \r\n else if(flash_ota_pct<0 && older_recovery){\r\n // we were processing OTA on an older recovery and we missed the \r\n // end of flashing.\r\n console.log('End of flashing from older recovery');\r\n if(data.ota_dsc==''){\r\n flash_ota_dsc = 'OTA Process Completed';\r\n }\r\n flash_state=flash_status_codes.DONE;\r\n }\r\n }\r\n else if(flash_state ==flash_status_codes.UPLOADING){ \r\n if(flash_ota_pct ==100){\r\n // we were processing OTA, and we've reached 100%\r\n // reset the progress bar \r\n flash_ota_pct = 0;\r\n flash_state=flash_status_codes.FLASHING;\r\n } \r\n }\r\n}\r\nfunction set_ota_error(message){\r\n flash_state=flash_status_codes.ERROR;\r\n handle_flash_state({\r\n ota_pct: 0,\r\n ota_dsc: message,\r\n event: flash_events.SET_ERROR\r\n }); \r\n}\r\nfunction show_update_dialog(){\r\n $('#otadiv').modal();\r\n if (flash_ota_pct >= 0) {\r\n update_progress();\r\n }\r\n if (flash_ota_dsc !== '') {\r\n $('span#flash-status').html(flash_ota_dsc);\r\n }\r\n}\r\nconst flash_events={\r\n SET_ERROR: function(data){\r\n if(data.ota_dsc){\r\n flash_ota_dsc=data.ota_dsc;\r\n }\r\n else {\r\n flash_ota_dsc = 'Error';\r\n }\r\n flash_ota_pct=data.ota_pct??0;\r\n $('#fwProgressLabel').parent().addClass('bg-danger');\r\n update_progress();\r\n show_update_dialog();\r\n },\r\n START_OTA : function() {\r\n if (flash_state == flash_status_codes.NONE || flash_state == flash_status_codes.ERROR || flash_state == undefined) {\r\n $('#fwProgressLabel').parent().removeClass('bg-danger');\r\n flash_state=flash_status_codes.REBOOT_TO_RECOVERY;\r\n if(!recovery){\r\n flash_ota_dsc = 'Starting recovery mode...';\r\n // Reboot system to recovery mode\r\n const data = {\r\n timestamp: Date.now(),\r\n };\r\n\r\n $.ajax({\r\n url: '/recovery.json',\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify(data),\r\n error: function(xhr, _ajaxOptions, thrownError){\r\n set_ota_error(`Unexpected error while trying to restart to recovery. (status=${xhr.status??''}, error=${thrownError??''} ) `);\r\n },\r\n complete: function(response) {\r\n console.log(response.responseText);\r\n },\r\n }); \r\n }\r\n else {\r\n flash_ota_dsc='Starting Update';\r\n }\r\n show_update_dialog();\r\n \r\n }\r\n else {\r\n console.warn('Unexpected status while starting flashing');\r\n } \r\n },\r\n FOUND_RECOVERY: function(data) {\r\n console.log(JSON.stringify(data));\r\n const url=$('#fw-url-input').val();\r\n if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){\r\n const fileInput = $('#flashfilename')[0].files;\r\n if (fileInput.length > 0) {\r\n flash_ota_dsc = 'Sending file to device.';\r\n flash_state= flash_status_codes.UPLOADING;\r\n const uploadPath = '/flash.json';\r\n const xhttp = new XMLHttpRequest();\r\n // xhrObj.upload.addEventListener(\"loadstart\", loadStartFunction, false); \r\n xhttp.upload.addEventListener(\"progress\", progressFunction, false); \r\n //xhrObj.upload.addEventListener(\"load\", transferCompleteFunction, false); \r\n xhttp.onreadystatechange = function() {\r\n if (xhttp.readyState === 4) {\r\n if(xhttp.status === 0 || xhttp.status === 404) {\r\n set_ota_error(`Upload Failed. Recovery version might not support uploading. Please use web update instead.`);\r\n $('#flashfilename').val('');\r\n }\r\n }\r\n };\r\n xhttp.open('POST', uploadPath, true);\r\n xhttp.send(fileInput[0] );\r\n }\r\n else if(url==''){\r\n flash_state= flash_status_codes.NONE;\r\n }\r\n else {\r\n flash_ota_dsc = 'Saving firmware URL location.';\r\n flash_state= flash_status_codes.SET_FWURL;\r\n let confData= { fwurl: {\r\n value: $('#fw-url-input').val(),\r\n type: 33,\r\n }\r\n };\r\n post_config(confData); \r\n }\r\n show_update_dialog();\r\n }\r\n },\r\n PROCESS_OTA_UPLOAD: function(data){\r\n flash_state= flash_status_codes.UPLOADING;\r\n process_ota_event(data);\r\n show_update_dialog();\r\n },\r\n PROCESS_OTA_STATUS: function(data){\r\n if(data.ota_pct>0){\r\n older_recovery = true;\r\n }\r\n if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){\r\n data.event = flash_events.FOUND_RECOVERY;\r\n handle_flash_state(data);\r\n }\r\n else if(flash_state==flash_status_codes.DONE && !recovery){\r\n flash_state=flash_status_codes.NONE;\r\n $('#rTable tr.release').removeClass('table-success table-warning');\r\n $('#fw-url-input').val('');\r\n }\r\n\r\n else {\r\n process_ota_event(data);\r\n if(flash_state && (flash_state >flash_status_codes.NONE && flash_ota_pct>=0) ) {\r\n show_update_dialog();\r\n }\r\n } \r\n },\r\n PROCESS_OTA: function(data) {\r\n process_ota_event(data);\r\n if(flash_state && (flash_state >flash_status_codes.NONE && flash_ota_pct>=0) ) {\r\n show_update_dialog();\r\n }\r\n }\r\n};\r\nwindow.hideSurrounding = function(obj){\r\n $(obj).parent().parent().hide();\r\n}\r\nfunction update_progress(){\r\n $('.progress-bar')\r\n .css('width', flash_ota_pct + '%')\r\n .attr('aria-valuenow', flash_ota_pct)\r\n .text(flash_ota_pct+'%')\r\n $('.progress-bar').html((flash_state==flash_status_codes.DONE?100:flash_ota_pct) + '%');\r\n\r\n}\r\nfunction handle_flash_state(data) {\r\n if(data.event) {\r\n data.event(data);\r\n } \r\n else {\r\n console.error('Unexpected error while processing handle_flash_state');\r\n return;\r\n }\r\n\r\n}\r\nwindow.hFlash = function(){\r\n // reset file upload selection if any;\r\n $('#flashfilename').val('');\r\n handle_flash_state({ event: flash_events.START_OTA, url: $('#fw-url-input').val() });\r\n}\r\nwindow.handleReboot = function(link){\r\n \r\n if(link=='reboot_ota'){\r\n $('#reboot_ota_nav').removeClass('active').prop(\"disabled\",true); delayReboot(500,'', 'reboot_ota');\r\n }\r\n else {\r\n $('#reboot_nav').removeClass('active'); delayReboot(500,'',link);\r\n }\r\n}\r\nfunction progressFunction(evt){ \r\n // if (evt.lengthComputable) { \r\n // progressBar.max = evt.total; \r\n // progressBar.value = evt.loaded; \r\n // percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + \"%\"; \r\n // } \r\n handle_flash_state({\r\n ota_pct: ( Math.round(evt.loaded / evt.total * 100)),\r\n ota_dsc: ('Uploading file to device'),\r\n event: flash_events.PROCESS_OTA_UPLOAD\r\n }); \r\n} \r\nfunction handlebtstate(data) {\r\n let icon = '';\r\n let tt = '';\r\n if (data.bt_status !== undefined && data.bt_sub_status !== undefined) {\r\n const iconsvg = btStateIcons[data.bt_status].sub[data.bt_sub_status];\r\n if (iconsvg) {\r\n icon = `#${btIcons[iconsvg]}`;\r\n tt = btStateIcons[data.bt_status].desc;\r\n } else {\r\n icon = `#${btIcons.bt_connected}`;\r\n tt = 'Output status';\r\n }\r\n }\r\n $('#o_type').title = tt;\r\n $('#o_bt').attr('xlink:href',icon);\r\n\r\n \r\n}\r\nfunction handleTemplateTypeRadio(outtype) {\r\n if (outtype === 'bt') {\r\n $('#bt').prop('checked', true);\r\n $('#o_bt').attr('display', 'inline');\r\n $('#o_spdif').attr('display', 'none');\r\n $('#o_i2s').attr('display', 'none');\r\n output = 'bt';\r\n } else if (outtype === 'spdif') {\r\n $('#spdif').prop('checked', true);\r\n $('#o_bt').attr('display', 'none');\r\n $('#o_spdif').attr('display', 'inline');\r\n $('#o_i2s').attr('display', 'none');\r\n output = 'spdif';\r\n } else {\r\n $('#i2s').prop('checked', true);\r\n $('#o_bt').attr('display', 'none');\r\n $('#o_spdif').attr('display', 'none');\r\n $('#o_i2s').attr('display', 'inline');\r\n output = 'i2s';\r\n }\r\n}\r\n\r\nfunction handleExceptionResponse(xhr, _ajaxOptions, thrownError) {\r\n console.log(xhr.status);\r\n console.log(thrownError);\r\n if (thrownError !== '') {\r\n showLocalMessage(thrownError, 'MESSAGING_ERROR');\r\n }\r\n}\r\nfunction HideCmdMessage(cmdname) {\r\n $('#toast_' + cmdname).css('display', 'none');\r\n $('#toast_' + cmdname)\r\n .removeClass('table-success')\r\n .removeClass('table-warning')\r\n .removeClass('table-danger')\r\n .addClass('table-success');\r\n $('#msg_' + cmdname).html('');\r\n}\r\nfunction showCmdMessage(cmdname, msgtype, msgtext, append = false) {\r\n let color = 'table-success';\r\n if (msgtype === 'MESSAGING_WARNING') {\r\n color = 'table-warning';\r\n } else if (msgtype === 'MESSAGING_ERROR') {\r\n color = 'table-danger';\r\n }\r\n $('#toast_' + cmdname).css('display', 'block');\r\n $('#toast_' + cmdname)\r\n .removeClass('table-success')\r\n .removeClass('table-warning')\r\n .removeClass('table-danger')\r\n .addClass(color);\r\n let escapedtext = msgtext\r\n .substring(0, msgtext.length - 1)\r\n .encodeHTML()\r\n .replace(/\\n/g, '<br />');\r\n escapedtext =\r\n ($('#msg_' + cmdname).html().length > 0 && append\r\n ? $('#msg_' + cmdname).html() + '<br/>'\r\n : '') + escapedtext;\r\n $('#msg_' + cmdname).html(escapedtext);\r\n}\r\n\r\nlet releaseURL =\r\n 'https://api.github.com/repos/sle118/squeezelite-esp32/releases';\r\n \r\nlet recovery = false;\r\nconst commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W';\r\nlet blockAjax = false;\r\n//let blockFlashButton = false;\r\nlet apList = null;\r\n//let selectedSSID = '';\r\n//let checkStatusInterval = null;\r\nlet messagecount = 0;\r\nlet messageseverity = 'MESSAGING_INFO';\r\nlet StatusIntervalActive = false;\r\nlet LastRecoveryState = null;\r\nlet SystemConfig={};\r\nlet LastCommandsState = null;\r\nvar output = '';\r\nlet hostName = '';\r\nlet versionName='Squeezelite-ESP32';\r\nlet prevmessage='';\r\nlet project_name=versionName;\r\nlet platform_name=versionName;\r\nlet btSinkNamesOptSel='#cfg-audio-bt_source-sink_name';\r\nlet ConnectedToSSID={};\r\nlet ConnectingToSSID={};\r\nlet lmsBaseUrl;\r\nlet prevLMSIP='';\r\nconst ConnectingToActions = {\r\n 'CONN' : 0,'MAN' : 1,'STS' : 2,\r\n}\r\n\r\nPromise.prototype.delay = function(duration) {\r\n return this.then(\r\n function(value) {\r\n return new Promise(function(resolve) {\r\n setTimeout(function() {\r\n resolve(value);\r\n }, duration);\r\n });\r\n },\r\n function(reason) {\r\n return new Promise(function(_resolve, reject) {\r\n setTimeout(function() {\r\n reject(reason);\r\n }, duration);\r\n });\r\n }\r\n );\r\n};\r\n\r\nfunction startCheckStatusInterval() {\r\n StatusIntervalActive = true;\r\n setTimeout(checkStatus, 3000);\r\n}\r\n\r\n\r\nfunction RepeatCheckStatusInterval() {\r\n if (StatusIntervalActive) {\r\n startCheckStatusInterval();\r\n }\r\n}\r\n\r\nfunction getConfigJson(slimMode) {\r\n const config = {};\r\n $('input.nvs').each(function(_index, entry) {\r\n if (!slimMode) {\r\n const nvsType = parseInt(entry.attributes.nvs_type.value, 10);\r\n if (entry.id !== '') {\r\n config[entry.id] = {};\r\n if (\r\n nvsType === nvsTypes.NVS_TYPE_U8 ||\r\n nvsType === nvsTypes.NVS_TYPE_I8 ||\r\n nvsType === nvsTypes.NVS_TYPE_U16 ||\r\n nvsType === nvsTypes.NVS_TYPE_I16 ||\r\n nvsType === nvsTypes.NVS_TYPE_U32 ||\r\n nvsType === nvsTypes.NVS_TYPE_I32 ||\r\n nvsType === nvsTypes.NVS_TYPE_U64 ||\r\n nvsType === nvsTypes.NVS_TYPE_I64\r\n ) {\r\n config[entry.id].value = parseInt(entry.value);\r\n } else {\r\n config[entry.id].value = entry.value;\r\n }\r\n config[entry.id].type = nvsType;\r\n }\r\n } else {\r\n config[entry.id] = entry.value;\r\n }\r\n });\r\n const key = $('#nvs-new-key').val();\r\n const val = $('#nvs-new-value').val();\r\n if (key !== '') {\r\n if (!slimMode) {\r\n config[key] = {};\r\n config[key].value = val;\r\n config[key].type = 33;\r\n } else {\r\n config[key] = val;\r\n }\r\n }\r\n return config;\r\n}\r\n\r\n// eslint-disable-next-line no-unused-vars\r\nfunction onFileLoad(elementId, event) {\r\n let data = {};\r\n try {\r\n data = JSON.parse(elementId.srcElement.result);\r\n } catch (e) {\r\n alert('Parsing failed!\\r\\n ' + e);\r\n }\r\n $('input.nvs').each(function(_index, entry) {\r\n if (data[entry.id]) {\r\n if (data[entry.id] !== entry.value) {\r\n console.log(\r\n 'Changed ' + entry.id + ' ' + entry.value + '==>' + data[entry.id]\r\n );\r\n $(this).val(data[entry.id]);\r\n }\r\n }\r\n });\r\n}\r\n\r\n// eslint-disable-next-line no-unused-vars\r\nfunction onChooseFile(event, control) {\r\n if (typeof window.FileReader !== 'function') {\r\n throw \"The file API isn't supported on this browser.\";\r\n }\r\n const input = event.target;\r\n if (!input) {\r\n throw 'The browser does not properly implement the event object';\r\n }\r\n if (!input.files) {\r\n throw 'This browser does not support the `files` property of the file input.';\r\n }\r\n if (!input.files[0]) {\r\n return undefined;\r\n }\r\n \r\n const file = input.files[0];\r\n let fr = new FileReader();\r\n fr.onload = onFileLoad.bind(control)(input, event);\r\n fr.readAsText(file);\r\n input.value = '';\r\n}\r\n\r\n// pull json file from https://gist.githubusercontent.com/sle118/dae585e157b733a639c12dc70f0910c5/raw/b462691f69e2ad31ac95c547af6ec97afb0f53db/squeezelite-esp32-presets.json and\r\n// load the names into cfg-hw-preset-model_name\r\nfunction loadPresets() {\r\n if(presetsloaded) return;\r\n presetsloaded = true;\r\n $.getJSON(\r\n 'https://gist.githubusercontent.com/sle118/dae585e157b733a639c12dc70f0910c5/raw/b462691f69e2ad31ac95c547af6ec97afb0f53db/squeezelite-esp32-presets.json',\r\n function(data) {\r\n $.each(data, function(key, val) {\r\n if(key === 'name') {\r\n $('#cfg-hw-preset-model_name').append(\r\n $('<option></option>').val(val).html(val)\r\n );\r\n }\r\n });\r\n }\r\n ).fail(function(jqxhr, textStatus, error) {\r\n const err = textStatus + ', ' + error;\r\n console.log('Request Failed: ' + err);\r\n $('hw-preset-section').hide();\r\n }\r\n );\r\n}\r\n\r\n \r\n\r\n\r\nfunction delayReboot(duration, cmdname, ota = 'reboot') {\r\n const url = '/'+ota+'.json';\r\n $('tbody#tasks').empty();\r\n $('#tasks_sect').css('visibility', 'collapse');\r\n Promise.resolve({ cmdname: cmdname, url: url })\r\n .delay(duration)\r\n .then(function(data) {\r\n if (data.cmdname.length > 0) {\r\n showCmdMessage(\r\n data.cmdname,\r\n 'MESSAGING_WARNING',\r\n 'System is rebooting.\\n',\r\n true\r\n );\r\n } else {\r\n showLocalMessage('System is rebooting.\\n', 'MESSAGING_WARNING');\r\n }\r\n console.log('now triggering reboot');\r\n $(\"button[onclick*='handleReboot']\").addClass('rebooting');\r\n $.ajax({\r\n url: data.url,\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify({\r\n timestamp: Date.now(),\r\n }),\r\n error: handleExceptionResponse,\r\n complete: function() {\r\n console.log('reboot call completed');\r\n Promise.resolve(data)\r\n .delay(6000)\r\n .then(function(rdata) {\r\n if (rdata.cmdname.length > 0) {\r\n HideCmdMessage(rdata.cmdname);\r\n }\r\n getCommands();\r\n getConfig();\r\n });\r\n },\r\n });\r\n });\r\n}\r\n// eslint-disable-next-line no-unused-vars\r\nwindow.saveAutoexec1 = function(apply) {\r\n showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Saving.\\n', false);\r\n let commandLine = commandHeader + ' -n \"' + $('#player').val() + '\"';\r\n if (output === 'bt') {\r\n commandLine += ' -o \"BT\" -R -Z 192000';\r\n showCmdMessage(\r\n 'cfg-audio-tmpl',\r\n 'MESSAGING_INFO',\r\n 'Remember to configure the Bluetooth audio device name.\\n',\r\n true\r\n );\r\n } else if (output === 'spdif') {\r\n commandLine += ' -o SPDIF -Z 192000';\r\n } else {\r\n commandLine += ' -o I2S';\r\n }\r\n if ($('#optional').val() !== '') {\r\n commandLine += ' ' + $('#optional').val();\r\n }\r\n const data = {\r\n timestamp: Date.now(),\r\n };\r\n data.config = {\r\n autoexec1: { value: commandLine, type: 33 },\r\n autoexec: {\r\n value: $('#disable-squeezelite').prop('checked') ? '0' : '1',\r\n type: 33,\r\n },\r\n };\r\n\r\n $.ajax({\r\n url: '/config.json',\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify(data),\r\n error: handleExceptionResponse,\r\n complete: function(response) {\r\n if (\r\n response.responseText.result &&\r\n JSON.parse(response.responseText).result === 'OK'\r\n ) {\r\n showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Done.\\n', true);\r\n if (apply) {\r\n delayReboot(1500, 'cfg-audio-tmpl');\r\n }\r\n } else if (response.responseText.result) {\r\n showCmdMessage(\r\n 'cfg-audio-tmpl',\r\n 'MESSAGING_WARNING',\r\n JSON.parse(response.responseText).Result + '\\n',\r\n true\r\n );\r\n } else {\r\n showCmdMessage(\r\n 'cfg-audio-tmpl',\r\n 'MESSAGING_ERROR',\r\n response.statusText + '\\n'\r\n );\r\n }\r\n console.log(response.responseText);\r\n },\r\n });\r\n console.log('sent data:', JSON.stringify(data));\r\n}\r\nwindow.handleDisconnect = function(){\r\n $.ajax({\r\n url: '/connect.json',\r\n dataType: 'text',\r\n method: 'DELETE',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify({\r\n timestamp: Date.now(),\r\n }),\r\n });\r\n}\r\nfunction setPlatformFilter(val){\r\n if($('.upf').filter(function(){ return $(this).text().toUpperCase()===val.toUpperCase()}).length>0){\r\n $('#splf').val(val).trigger('input');\r\n return true;\r\n }\r\n return false;\r\n}\r\nwindow.handleConnect = function(){\r\n ConnectingToSSID.ssid = $('#manual_ssid').val();\r\n ConnectingToSSID.pwd = $('#manual_pwd').val();\r\n ConnectingToSSID.dhcpname = $('#dhcp-name2').val();\r\n $(\"*[class*='connecting']\").hide();\r\n $('#ssid-wait').text(ConnectingToSSID.ssid);\r\n $('.connecting').show();\r\n\r\n $.ajax({\r\n url: '/connect.json',\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify({\r\n timestamp: Date.now(),\r\n ssid: ConnectingToSSID.ssid,\r\n pwd: ConnectingToSSID.pwd\r\n }),\r\n error: handleExceptionResponse,\r\n });\r\n\r\n // now we can re-set the intervals regardless of result\r\n startCheckStatusInterval();\r\n\r\n}\r\n$(document).ready(function() {\r\n $('#wifiTable').on('click','tr', function() {\r\n\r\n });\r\n $('#fw-url-input').on('input', function() {\r\n if($(this).val().length>8 && ($(this).val().startsWith('http://') || $(this).val().startsWith('https://'))){\r\n $('#start-flash').show();\r\n } \r\n else {\r\n $('#start-flash').hide();\r\n }\r\n });\r\n $('.upSrch').on('input', function() {\r\n const val = this.value;\r\n $(\"#rTable tr\").removeClass(this.id+'_hide');\r\n if(val.length>0) {\r\n $(`#rTable td:nth-child(${$(this).parent().index()+1})`).filter(function(){ \r\n return !$(this).text().toUpperCase().includes(val.toUpperCase());\r\n }).parent().addClass(this.id+'_hide');\r\n }\r\n $('[class*=\"_hide\"]').hide();\r\n $('#rTable tr').not('[class*=\"_hide\"]').show()\r\n\r\n });\r\n setTimeout(refreshAP,1500);\r\n\r\n \r\n $('#otadiv').on('hidden.bs.modal', function () {\r\n // reset flash status. This should stop the state machine from\r\n // executing steps up to flashing itself.\r\n flash_state=flash_status_codes.NONE;\r\n });\r\n $('#WifiConnectDialog').on('shown.bs.modal', function () {\r\n $(\"*[class*='connecting']\").hide();\r\n if(ConnectingToSSID.Action!==ConnectingToActions.STS){\r\n $('.connecting-init').show();\r\n $('#manual_ssid').trigger('focus'); \r\n }\r\n else {\r\n handleWifiDialog();\r\n }\r\n })\r\n $('#WifiConnectDialog').on('hidden.bs.modal', function () {\r\n $('#WifiConnectDialog input').val('');\r\n })\r\n \r\n $('#uCnfrm').on('shown.bs.modal', function () {\r\n $('#selectedFWURL').text($('#fw-url-input').val());\r\n })\r\n \r\n $('input#show-commands')[0].checked = LastCommandsState === 1;\r\n $('a[href^=\"#tab-commands\"]').hide();\r\n $('#load-nvs').on('click', function() {\r\n $('#nvsfilename').trigger('click');\r\n });\r\n $('#clear-syslog').on('click', function() {\r\n messagecount = 0;\r\n messageseverity = 'MESSAGING_INFO';\r\n $('#msgcnt').text('');\r\n $('#syslogTable').html('');\r\n });\r\n \r\n $('#wifiTable').on('click','tr', function() {\r\n ConnectingToSSID.Action=ConnectingToActions.CONN;\r\n if($(this).children('td:eq(1)').text() == ConnectedToSSID.ssid){\r\n ConnectingToSSID.Action=ConnectingToActions.STS;\r\n return;\r\n }\r\n if(!$(this).is(':last-child')){\r\n ConnectingToSSID.ssid=$(this).children('td:eq(1)').text();\r\n $('#manual_ssid').val(ConnectingToSSID.ssid);\r\n } \r\n else {\r\n ConnectingToSSID.Action=ConnectingToActions.MAN;\r\n ConnectingToSSID.ssid='';\r\n $('#manual_ssid').val(ConnectingToSSID.ssid);\r\n }\r\n });\r\n\r\n\r\n $('#ok-credits').on('click', function() {\r\n $('#credits').slideUp('fast', function() {});\r\n $('#app').slideDown('fast', function() {});\r\n });\r\n\r\n $('#acredits').on('click', function(event) {\r\n event.preventDefault();\r\n $('#app').slideUp('fast', function() {});\r\n $('#credits').slideDown('fast', function() {});\r\n });\r\n\r\n $('input#show-commands').on('click', function() {\r\n this.checked = this.checked ? 1 : 0;\r\n if (this.checked) {\r\n $('a[href^=\"#tab-commands\"]').show();\r\n LastCommandsState = 1;\r\n } else {\r\n LastCommandsState = 0;\r\n $('a[href^=\"#tab-commands\"]').hide();\r\n }\r\n });\r\n\r\n $('input#show-nvs').on('click', function() {\r\n this.checked = this.checked ? 1 : 0;\r\n if (this.checked) {\r\n $('*[href*=\"-nvs\"]').show();\r\n } else {\r\n $('*[href*=\"-nvs\"]').hide();\r\n }\r\n });\r\n \r\n $('#save-as-nvs').on('click', function() {\r\n const config = getConfigJson(true);\r\n const a = document.createElement('a');\r\n a.href = URL.createObjectURL(\r\n new Blob([JSON.stringify(config, null, 2)], {\r\n type: 'text/plain',\r\n })\r\n );\r\n a.setAttribute(\r\n 'download',\r\n 'nvs_config_' + hostName + '_' + Date.now() + 'json'\r\n );\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n });\r\n\r\n $('#save-nvs').on('click', function() {\r\n post_config(getConfigJson(false));\r\n });\r\n \r\n $('#fwUpload').on('click', function() {\r\n const fileInput = document.getElementById('flashfilename').files;\r\n if (fileInput.length === 0) {\r\n alert('No file selected!');\r\n } else {\r\n handle_flash_state({ event: flash_events.START_OTA, file: fileInput[0] });\r\n }\r\n \r\n });\r\n $('[name=output-tmpl]').on('click', function() {\r\n handleTemplateTypeRadio(this.id);\r\n });\r\n\r\n $('#chkUpdates').on('click', function() {\r\n $('#rTable').html('');\r\n $.getJSON(releaseURL, function(data) {\r\n let i = 0;\r\n const branches = [];\r\n data.forEach(function(release) {\r\n const namecomponents = release.name.split('#');\r\n const branch = namecomponents[3];\r\n if (!branches.includes(branch)) {\r\n branches.push(branch);\r\n }\r\n });\r\n let fwb='';\r\n branches.forEach(function(branch) {\r\n fwb += '<option value=\"' + branch + '\">' + branch + '</option>';\r\n });\r\n $('#fwbranch').append(fwb);\r\n\r\n data.forEach(function(release) {\r\n let url = '';\r\n release.assets.forEach(function(asset) {\r\n if (asset.name.match(/\\.bin$/)) {\r\n url = asset.browser_download_url;\r\n }\r\n });\r\n const namecomponents = release.name.split('#');\r\n const ver = namecomponents[0];\r\n const cfg = namecomponents[2];\r\n const branch = namecomponents[3];\r\n var bits = ver.substr(ver.lastIndexOf('-')+1);\r\n bits = (bits =='32' || bits == '16')?bits:'';\r\n\r\n let body = release.body;\r\n body = body.replace(/'/gi, '\"');\r\n body = body.replace(\r\n /[\\s\\S]+(### Revision Log[\\s\\S]+)### ESP-IDF Version Used[\\s\\S]+/,\r\n '$1'\r\n );\r\n body = body.replace(/- \\(.+?\\) /g, '- ');\r\n $('#rTable').append(`<tr class='release ' fwurl='${url}'>\r\n <td data-toggle='tooltip' title='${body}'>${ver}</td><td>${new Date(release.created_at).toLocalShort()}\r\n </td><td class='upf'>${cfg}</td><td>${branch}</td><td>${bits}</td></tr>`\r\n );\r\n });\r\n if (i > 7) {\r\n $('#releaseTable').append(\r\n \"<tr id='showall'>\" +\r\n \"<td colspan='6'>\" +\r\n \"<input type='button' id='showallbutton' class='btn btn-info' value='Show older releases' />\" +\r\n '</td>' +\r\n '</tr>'\r\n );\r\n $('#showallbutton').on('click', function() {\r\n $('tr.hide').removeClass('hide');\r\n $('tr#showall').addClass('hide');\r\n });\r\n }\r\n $('#searchfw').css('display', 'inline');\r\n if(!setPlatformFilter(platform_name)){\r\n setPlatformFilter(project_name)\r\n }\r\n $('#rTable tr.release').on('click', function() {\r\n var url=this.attributes['fwurl'].value;\r\n if (lmsBaseUrl) {\r\n url = url.replace(/.*\\/download\\//, lmsBaseUrl + '/plugins/SqueezeESP32/firmware/');\r\n }\r\n $('#fw-url-input').val(url);\r\n $('#start-flash').show();\r\n $('#rTable tr.release').removeClass('table-success table-warning');\r\n $(this).addClass('table-success table-warning');\r\n });\r\n\r\n }).fail(function() {\r\n alert('failed to fetch release history!');\r\n }); \r\n });\r\n $('#fwcheck').on('click', function() { \r\n $('#releaseTable').html('');\r\n $('#fwbranch').empty();\r\n $.getJSON(releaseURL, function(data) {\r\n let i = 0;\r\n const branches = [];\r\n data.forEach(function(release) {\r\n const namecomponents = release.name.split('#');\r\n const branch = namecomponents[3];\r\n if (!branches.includes(branch)) {\r\n branches.push(branch);\r\n }\r\n });\r\n let fwb;\r\n branches.forEach(function(branch) {\r\n fwb += '<option value=\"' + branch + '\">' + branch + '</option>';\r\n });\r\n $('#fwbranch').append(fwb);\r\n\r\n data.forEach(function(release) {\r\n let url = '';\r\n release.assets.forEach(function(asset) {\r\n if (asset.name.match(/\\.bin$/)) {\r\n url = asset.browser_download_url;\r\n }\r\n });\r\n const namecomponents = release.name.split('#');\r\n const ver = namecomponents[0];\r\n const idf = namecomponents[1];\r\n const cfg = namecomponents[2];\r\n const branch = namecomponents[3];\r\n\r\n let body = release.body;\r\n body = body.replace(/'/gi, '\"');\r\n body = body.replace(\r\n /[\\s\\S]+(### Revision Log[\\s\\S]+)### ESP-IDF Version Used[\\s\\S]+/,\r\n '$1'\r\n );\r\n body = body.replace(/- \\(.+?\\) /g, '- ');\r\n const trclass = i++ > 6 ? ' hide' : '';\r\n $('#releaseTable').append(\r\n \"<tr class='release\" +\r\n trclass +\r\n \"'>\" +\r\n \"<td data-toggle='tooltip' title='\" +\r\n body +\r\n \"'>\" +\r\n ver +\r\n '</td>' +\r\n '<td>' +\r\n new Date(release.created_at).toLocalShort() +\r\n '</td>' +\r\n '<td>' +\r\n cfg +\r\n '</td>' +\r\n '<td>' +\r\n idf +\r\n '</td>' +\r\n '<td>' +\r\n branch +\r\n '</td>' +\r\n \"<td><input type='button' class='btn btn-success' value='Select' data-url='\" +\r\n url +\r\n \"' onclick='setURL(this);' /></td>\" +\r\n '</tr>'\r\n );\r\n });\r\n if (i > 7) {\r\n $('#releaseTable').append(\r\n \"<tr id='showall'>\" +\r\n \"<td colspan='6'>\" +\r\n \"<input type='button' id='showallbutton' class='btn btn-info' value='Show older releases' />\" +\r\n '</td>' +\r\n '</tr>'\r\n );\r\n $('#showallbutton').on('click', function() {\r\n $('tr.hide').removeClass('hide');\r\n $('tr#showall').addClass('hide');\r\n });\r\n }\r\n $('#searchfw').css('display', 'inline');\r\n }).fail(function() {\r\n alert('failed to fetch release history!');\r\n });\r\n });\r\n\r\n $('#updateAP').on('click', function() {\r\n refreshAP();\r\n console.log('refresh AP');\r\n });\r\n\r\n // first time the page loads: attempt to get the connection status and start the wifi scan\r\n getConfig();\r\n getCommands();\r\n\r\n // start timers\r\n startCheckStatusInterval();\r\n \r\n});\r\n\r\n// eslint-disable-next-line no-unused-vars\r\nwindow.setURL = function(button) {\r\n let url = button.dataset.url;\r\n\r\n $('[data-url^=\"http\"]')\r\n .addClass('btn-success')\r\n .removeClass('btn-danger');\r\n $('[data-url=\"' + url + '\"]')\r\n .addClass('btn-danger')\r\n .removeClass('btn-success');\r\n\r\n // if user can proxy download through LMS, modify the URL\r\n if (lmsBaseUrl) {\r\n url = url.replace(/.*\\/download\\//, lmsBaseUrl + '/plugins/SqueezeESP32/firmware/');\r\n }\r\n\r\n $('#fwurl').val(url);\r\n}\r\n\r\n\r\nfunction rssiToIcon(rssi) {\r\n if (rssi >= -55) {\r\n return `signal-wifi-fill`;\r\n } else if (rssi >= -60) {\r\n return `signal-wifi-3-fill`;\r\n } else if (rssi >= -65) {\r\n return `signal-wifi-2-fill`;\r\n } else if (rssi >= -70) {\r\n return `signal-wifi-1-fill`;\r\n } else { \r\n return `signal-wifi-line`;\r\n }\r\n}\r\n\r\nfunction refreshAP() {\r\n $.getJSON('/scan.json', async function() {\r\n await sleep(2000);\r\n $.getJSON('/ap.json', function(data) {\r\n if (data.length > 0) {\r\n // sort by signal strength\r\n data.sort(function(a, b) {\r\n const x = a.rssi;\r\n const y = b.rssi;\r\n // eslint-disable-next-line no-nested-ternary\r\n return x < y ? 1 : x > y ? -1 : 0;\r\n });\r\n apList = data;\r\n refreshAPHTML2(apList);\r\n\r\n }\r\n });\r\n }); \r\n}\r\nfunction formatAP(ssid, rssi, auth){\r\n return `<tr data-toggle=\"modal\" data-target=\"#WifiConnectDialog\"><td></td><td>${ssid}</td><td>\r\n \r\n \t<svg style=\"fill:white; width:1.5rem; height: 1.5rem;\">\r\n\t\t\t\t<use xlink:href=\"#${rssiToIcon(rssi)}\"></use>\r\n\t\t\t</svg>\r\n </td><td>\r\n \r\n <svg style=\"fill:white; width:1.5rem; height: 1.5rem;\">\r\n <use xlink:href=\"#lock${(auth == 0 ? '-unlock':'')}-fill\"></use>\r\n</svg>\r\n\r\n </td></tr>`;\r\n}\r\nfunction refreshAPHTML2(data) {\r\n let h = '';\r\n $('#wifiTable tr td:first-of-type').text('');\r\n $('#wifiTable tr').removeClass('table-success table-warning');\r\n if(data){\r\n data.forEach(function(e) {\r\n h+=formatAP(e.ssid, e.rssi, e.auth);\r\n });\r\n $('#wifiTable').html(h);\r\n }\r\n if($('.manual_add').length == 0){\r\n $('#wifiTable').append(formatAP('Manual add', 0,0));\r\n $('#wifiTable tr:last').addClass('table-light text-dark').addClass('manual_add');\r\n }\r\n if(ConnectedToSSID.ssid && ( ConnectedToSSID.urc === connectReturnCode.UPDATE_CONNECTION_OK || ConnectedToSSID.urc === connectReturnCode.UPDATE_FAILED_ATTEMPT_AND_RESTORE )){\r\n const wifiSelector=`#wifiTable td:contains(\"${ConnectedToSSID.ssid}\")`;\r\n if($(wifiSelector).filter(function() {return $(this).text() === ConnectedToSSID.ssid; }).length==0){\r\n $('#wifiTable').prepend(`${formatAP(ConnectedToSSID.ssid, ConnectedToSSID.rssi ?? 0, 0)}`);\r\n }\r\n $(wifiSelector).filter(function() {return $(this).text() === ConnectedToSSID.ssid; }).siblings().first().html('&check;').parent().addClass((ConnectedToSSID.urc === connectReturnCode.UPDATE_CONNECTION_OK?'table-success':'table-warning'));\r\n $('span#foot-wifi').html(`SSID: <strong>${ConnectedToSSID.ssid}</strong>, IP: <strong>${ConnectedToSSID.ip}</strong>`); \r\n $('#wifiStsIcon').attr('xlink:href',rssiToIcon(ConnectedToSSID.rssi));\r\n }\r\n else {\r\n $('span#foot-wifi').html('');\r\n }\r\n \r\n}\r\nfunction showTask(task) {\r\n console.debug(\r\n this.toLocaleString() +\r\n '\\t' +\r\n task.nme +\r\n '\\t' +\r\n task.cpu +\r\n '\\t' +\r\n taskStates[task.st] +\r\n '\\t' +\r\n task.minstk +\r\n '\\t' +\r\n task.bprio +\r\n '\\t' +\r\n task.cprio +\r\n '\\t' +\r\n task.num\r\n );\r\n $('tbody#tasks').append(\r\n '<tr class=\"table-primary\"><th scope=\"row\">' +\r\n task.num +\r\n '</th><td>' +\r\n task.nme +\r\n '</td><td>' +\r\n task.cpu +\r\n '</td><td>' +\r\n taskStates[task.st] +\r\n '</td><td>' +\r\n task.minstk +\r\n '</td><td>' +\r\n task.bprio +\r\n '</td><td>' +\r\n task.cprio +\r\n '</td></tr>'\r\n );\r\n}\r\nfunction btExists(name){\r\n return getBTSinkOpt(name).length>0;\r\n}\r\nfunction getBTSinkOpt(name){\r\n return $(`${btSinkNamesOptSel} option:contains('${name}')`);\r\n}\r\nfunction getMessages() {\r\n $.getJSON('/messages.json', async function(data) {\r\n for (const msg of data) {\r\n const msgAge = msg.current_time - msg.sent_time;\r\n var msgTime = new Date();\r\n msgTime.setTime(msgTime.getTime() - msgAge);\r\n switch (msg.class) {\r\n case 'MESSAGING_CLASS_OTA':\r\n var otaData = JSON.parse(msg.message);\r\n handle_flash_state({\r\n ota_pct: (otaData.ota_pct ?? -1),\r\n ota_dsc: (otaData.ota_dsc ??''),\r\n event: flash_events.PROCESS_OTA\r\n });\r\n break;\r\n case 'MESSAGING_CLASS_STATS':\r\n // for task states, check structure : task_state_t\r\n var statsData = JSON.parse(msg.message);\r\n console.debug(\r\n msgTime.toLocalShort() +\r\n ' - Number of running tasks: ' +\r\n statsData.ntasks\r\n );\r\n console.debug(\r\n msgTime.toLocalShort() +\r\n '\\tname' +\r\n '\\tcpu' +\r\n '\\tstate' +\r\n '\\tminstk' +\r\n '\\tbprio' +\r\n '\\tcprio' +\r\n '\\tnum'\r\n );\r\n if (statsData.tasks) {\r\n if ($('#tasks_sect').css('visibility') === 'collapse') {\r\n $('#tasks_sect').css('visibility', 'visible');\r\n }\r\n $('tbody#tasks').html('');\r\n statsData.tasks\r\n .sort(function(a, b) {\r\n return b.cpu - a.cpu;\r\n })\r\n .forEach(showTask, msgTime);\r\n } else if ($('#tasks_sect').css('visibility') === 'visible') {\r\n $('tbody#tasks').empty();\r\n $('#tasks_sect').css('visibility', 'collapse');\r\n }\r\n break;\r\n case 'MESSAGING_CLASS_SYSTEM':\r\n showMessage(msg, msgTime);\r\n break;\r\n case 'MESSAGING_CLASS_CFGCMD':\r\n var msgparts = msg.message.split(/([^\\n]*)\\n(.*)/gs);\r\n showCmdMessage(msgparts[1], msg.type, msgparts[2], true);\r\n break;\r\n case 'MESSAGING_CLASS_BT':\r\n if($(\"#cfg-audio-bt_source-sink_name\").is('input')){\r\n var attr=$(\"#cfg-audio-bt_source-sink_name\")[0].attributes;\r\n var attrs='';\r\n for (var j = 0; j < attr.length; j++) {\r\n if(attr.item(j).name!=\"type\"){\r\n attrs+=`${attr.item(j).name } = \"${attr.item(j).value}\" `;\r\n }\r\n }\r\n var curOpt=$(\"#cfg-audio-bt_source-sink_name\")[0].value;\r\n $(\"#cfg-audio-bt_source-sink_name\").replaceWith(`<select id=\"cfg-audio-bt_source-sink_name\" ${attrs}><option value=\"${curOpt}\" data-description=\"${curOpt}\">${curOpt}</option></select> `);\r\n }\r\n JSON.parse(msg.message).forEach(function(btEntry) {\r\n //<input type=\"text\" class=\"form-control bg-success\" placeholder=\"name\" hasvalue=\"true\" longopts=\"sink_name\" shortopts=\"n\" checkbox=\"false\" cmdname=\"cfg-audio-bt_source\" id=\"cfg-audio-bt_source-sink_name\" name=\"cfg-audio-bt_source-sink_name\">\r\n //<select hasvalue=\"true\" longopts=\"jack_behavior\" shortopts=\"j\" checkbox=\"false\" cmdname=\"cfg-audio-general\" id=\"cfg-audio-general-jack_behavior\" name=\"cfg-audio-general-jack_behavior\" class=\"form-control \"><option>--</option><option>Headphones</option><option>Subwoofer</option></select> \r\n if(!btExists(btEntry.name)){\r\n $(\"#cfg-audio-bt_source-sink_name\").append(`<option>${btEntry.name}</option>`);\r\n showMessage({ type:msg.type, message:`BT Audio device found: ${btEntry.name} RSSI: ${btEntry.rssi} `}, msgTime);\r\n }\r\n getBTSinkOpt(btEntry.name).attr('data-description', `${btEntry.name} (${btEntry.rssi}dB)`)\r\n .attr('rssi',btEntry.rssi)\r\n .attr('value',btEntry.name)\r\n .text(`${btEntry.name} [${btEntry.rssi}dB]`).trigger('change');\r\n \r\n });\r\n $(btSinkNamesOptSel).append($(`${btSinkNamesOptSel} option`).remove().sort(function(a, b) { \r\n console.log(`${parseInt($(a).attr('rssi'))} < ${parseInt( $(b).attr('rssi'))} ? `);\r\n return parseInt($(a).attr('rssi')) < parseInt( $(b).attr('rssi')) ? 1 : -1; \r\n }));\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n }).fail(function(xhr, ajaxOptions, thrownError){\r\n if(xhr.status==404){\r\n $('.orec').hide(); // system commands won't be available either\r\n } \r\n else {\r\n handleExceptionResponse(xhr, ajaxOptions, thrownError);\r\n }\r\n \r\n }\r\n );\r\n\r\n /*\r\n Minstk is minimum stack space left\r\nBprio is base priority\r\ncprio is current priority\r\nnme is name\r\nst is task state. I provided a \"typedef\" that you can use to convert to text\r\ncpu is cpu percent used\r\n*/\r\n}\r\nfunction handleRecoveryMode(data) {\r\n const locRecovery= data.recovery ??0;\r\n if (LastRecoveryState !== locRecovery) {\r\n LastRecoveryState = locRecovery;\r\n $('input#show-nvs')[0].checked = LastRecoveryState === 1;\r\n }\r\n if ($('input#show-nvs')[0].checked) {\r\n $('*[href*=\"-nvs\"]').show();\r\n\r\n } else {\r\n $('*[href*=\"-nvs\"]').hide();\r\n }\r\n if (locRecovery === 1) {\r\n recovery = true;\r\n $('.recovery_element').show();\r\n $('.ota_element').hide();\r\n $('#boot-button').html('Reboot');\r\n $('#boot-form').attr('action', '/reboot_ota.json');\r\n } else {\r\n recovery = false;\r\n $('.recovery_element').hide();\r\n $('.ota_element').show();\r\n $('#boot-button').html('Recovery');\r\n $('#boot-form').attr('action', '/recovery.json');\r\n }\r\n}\r\n\r\nfunction hasConnectionChanged(data){\r\n// gw: \"192.168.10.1\"\r\n// ip: \"192.168.10.225\"\r\n// netmask: \"255.255.255.0\"\r\n// ssid: \"MyTestSSID\"\r\n\r\n return (data.urc !== ConnectedToSSID.urc || \r\n data.ssid !== ConnectedToSSID.ssid || \r\n data.gw !== ConnectedToSSID.gw ||\r\n data.netmask !== ConnectedToSSID.netmask ||\r\n data.ip !== ConnectedToSSID.ip || data.rssi !== ConnectedToSSID.rssi )\r\n}\r\nfunction handleWifiDialog(data){\r\n if($('#WifiConnectDialog').is(':visible')){\r\n if(ConnectedToSSID.ip) {\r\n $('#ipAddress').text(ConnectedToSSID.ip);\r\n }\r\n if(ConnectedToSSID.ssid) {\r\n $('#connectedToSSID' ).text(ConnectedToSSID.ssid);\r\n } \r\n if(ConnectedToSSID.gw) {\r\n $('#gateway' ).text(ConnectedToSSID.gw);\r\n } \r\n if(ConnectedToSSID.netmask) {\r\n $('#netmask' ).text(ConnectedToSSID.netmask);\r\n } \r\n if(ConnectingToSSID.Action===undefined || (ConnectingToSSID.Action && ConnectingToSSID.Action == ConnectingToActions.STS)) {\r\n $(\"*[class*='connecting']\").hide();\r\n $('.connecting-status').show();\r\n }\r\n if(SystemConfig.ap_ssid){\r\n $('#apName').text(SystemConfig.ap_ssid.value);\r\n }\r\n if(SystemConfig.ap_pwd){\r\n $('#apPass').text(SystemConfig.ap_pwd.value);\r\n } \r\n if(!data)\r\n {\r\n return;\r\n }\r\n else {\r\n switch (data.urc) {\r\n case connectReturnCode.UPDATE_CONNECTION_OK:\r\n if(data.ssid && data.ssid===ConnectingToSSID.ssid){\r\n $(\"*[class*='connecting']\").hide();\r\n $('.connecting-success').show(); \r\n ConnectingToSSID.Action = ConnectingToActions.STS;\r\n }\r\n break;\r\n case connectReturnCode.UPDATE_FAILED_ATTEMPT:\r\n // \r\n if(ConnectingToSSID.Action !=ConnectingToActions.STS && ConnectingToSSID.ssid == data.ssid ){\r\n $(\"*[class*='connecting']\").hide();\r\n $('.connecting-fail').show();\r\n }\r\n break;\r\n case connectReturnCode.UPDATE_LOST_CONNECTION:\r\n \r\n break; \r\n case connectReturnCode.UPDATE_FAILED_ATTEMPT_AND_RESTORE:\r\n if(ConnectingToSSID.Action !=ConnectingToActions.STS && ConnectingToSSID.ssid != data.ssid ){\r\n $(\"*[class*='connecting']\").hide();\r\n $('.connecting-fail').show();\r\n }\r\n break;\r\n case connectReturnCode.UPDATE_USER_DISCONNECT:\r\n // that's a manual disconnect\r\n // if ($('#wifi-status').is(':visible')) {\r\n // $('#wifi-status').slideUp('fast', function() {});\r\n // $('span#foot-wifi').html('');\r\n \r\n // } \r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n }\r\n}\r\nfunction handleWifiStatus(data) {\r\n if(hasConnectionChanged(data)){\r\n ConnectedToSSID=data;\r\n refreshAPHTML2();\r\n }\r\n handleWifiDialog(data);\r\n}\r\n\r\nfunction batteryToIcon(voltage) {\r\n /* Assuming Li-ion 18650s as a power source, 3.9V per cell, or above is treated\r\n\t\t\t\tas full charge (>75% of capacity). 3.4V is empty. The gauge is loosely\r\n\t\t\t\tfollowing the graph here:\r\n\t\t\t\t\thttps://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages\r\n\t\t\t\tusing the 0.2C discharge profile for the rest of the values.\r\n\t\t\t*/\r\n if (voltage > 0) {\r\n if (inRange(voltage, 5.8, 6.8) || inRange(voltage, 8.8, 10.2)) {\r\n return `battery-low-line`;\r\n } else if (inRange(voltage, 6.8, 7.4) || inRange(voltage, 10.2, 11.1)) {\r\n return `battery-low-line`;\r\n } else if (\r\n inRange(voltage, 7.4, 7.5) ||\r\n inRange(voltage, 11.1, 11.25)\r\n ) {\r\n return `battery-low-line`;\r\n } else if (\r\n inRange(voltage, 7.5, 7.8) ||\r\n inRange(voltage, 11.25, 11.7)\r\n ) {\r\n return `battery-fill`;\r\n } else {\r\n return `battery-line`;\r\n }\r\n }\r\n}\r\nfunction checkStatus() {\r\n RepeatCheckStatusInterval();\r\n if (blockAjax) {\r\n return;\r\n }\r\n blockAjax = true;\r\n getMessages();\r\n $.getJSON('/status.json', function(data) {\r\n handleRecoveryMode(data);\r\n handleWifiStatus(data);\r\n handlebtstate(data);\r\n handle_flash_state({\r\n ota_pct: (data.ota_pct ?? -1),\r\n ota_dsc: (data.ota_dsc ??''),\r\n event: flash_events.PROCESS_OTA_STATUS\r\n });\r\n if (data.project_name && data.project_name !== '') {\r\n project_name = data.project_name;\r\n }\r\n if(data.platform_name && data.platform_name!==''){\r\n platform_name = data.platform_name;\r\n }\r\n if (data.version && data.version !== '') {\r\n versionName=data.version;\r\n $(\"#navtitle\").html(`${project_name}${recovery?'<br>[recovery]':''}`);\r\n $('span#foot-fw').html(`fw: <strong>${versionName}</strong>, mode: <strong>${recovery?\"Recovery\":project_name}</strong>`);\r\n } else {\r\n $('span#flash-status').html('');\r\n }\r\n if (data.Voltage) {\r\n $('#battery').attr('xlink:href', `#${batteryToIcon(data.Voltage)}`);\r\n $('#battery').show();\r\n } else {\r\n $('#battery').hide();\r\n }\r\n if((data.message??'')!='' && prevmessage != data.message){\r\n // supporting older recovery firmwares - messages will come from the status.json structure\r\n prevmessage = data.message;\r\n showLocalMessage(data.message, 'MESSAGING_INFO')\r\n }\r\n if(data.is_i2c_locked){\r\n $('flds-cfg-hw-preset').hide();\r\n }\r\n else {\r\n $('flds-cfg-hw-preset').show();\r\n loadPresets();\r\n }\r\n $(\"button[onclick*='handleReboot']\").removeClass('rebooting');\r\n\r\n if (typeof lmsBaseUrl == \"undefined\" || data.lms_ip != prevLMSIP && data.lms_ip && data.lms_port) {\r\n const baseUrl = 'http://' + data.lms_ip + ':' + data.lms_port;\r\n prevLMSIP=data.lms_ip;\r\n $.ajax({\r\n url: baseUrl + '/plugins/SqueezeESP32/firmware/-check.bin', \r\n type: 'HEAD',\r\n dataType: 'text',\r\n cache: false,\r\n error: function() {\r\n // define the value, so we don't check it any more.\r\n lmsBaseUrl = '';\r\n },\r\n success: function() {\r\n lmsBaseUrl = baseUrl;\r\n }\r\n });\r\n }\r\n \r\n $('#o_jack').attr('display', Number(data.Jack) ? 'inline' : 'none');\r\n blockAjax = false;\r\n }).fail(function(xhr, ajaxOptions, thrownError) {\r\n handleExceptionResponse(xhr, ajaxOptions, thrownError);\r\n blockAjax = false;\r\n });\r\n}\r\n// eslint-disable-next-line no-unused-vars\r\nwindow.runCommand = function(button, reboot) {\r\n let cmdstring = button.attributes.cmdname.value;\r\n showCmdMessage(\r\n button.attributes.cmdname.value,\r\n 'MESSAGING_INFO',\r\n 'Executing.',\r\n false\r\n );\r\n const fields = document.getElementById('flds-' + cmdstring);\r\n cmdstring += ' ';\r\n if (fields) {\r\n const allfields = fields.querySelectorAll('select,input');\r\n for (var i = 0; i < allfields.length; i++) {\r\n const attr = allfields[i].attributes;\r\n let qts = '';\r\n let opt = '';\r\n let isSelect = $(allfields[i]).is('select');\r\n const hasValue=attr.hasvalue.value === 'true';\r\n const validVal=(isSelect && allfields[i].value !== '--' ) || ( !isSelect && allfields[i].value !== '' );\r\n\r\n if ( !hasValue|| hasValue && validVal) {\r\n if (attr.longopts.value !== 'undefined') {\r\n opt += '--' + attr.longopts.value;\r\n } else if (attr.shortopts.value !== 'undefined') {\r\n opt = '-' + attr.shortopts.value;\r\n }\r\n\r\n if (attr.hasvalue.value === 'true') {\r\n if (allfields[i].value !== '') {\r\n qts = /\\s/.test(allfields[i].value) ? '\"' : '';\r\n cmdstring += opt + ' ' + qts + allfields[i].value + qts + ' ';\r\n }\r\n } else {\r\n // this is a checkbox\r\n if (allfields[i].checked) {\r\n cmdstring += opt + ' ';\r\n }\r\n }\r\n }\r\n }\r\n }\r\n console.log(cmdstring);\r\n\r\n const data = {\r\n timestamp: Date.now(),\r\n };\r\n data.command = cmdstring;\r\n\r\n $.ajax({\r\n url: '/commands.json',\r\n dataType: 'text',\r\n method: 'POST',\r\n cache: false,\r\n contentType: 'application/json; charset=utf-8',\r\n data: JSON.stringify(data),\r\n error: function(xhr, _ajaxOptions, thrownError){\r\n var cmd=JSON.parse(this.data ).command;\r\n if(xhr.status==404){\r\n showCmdMessage(\r\n cmd.substr(0,cmd.indexOf(' ')),\r\n 'MESSAGING_ERROR',\r\n `${recovery?'Limited recovery mode active. Unsupported action ':'Unexpected error while processing command'}`,\r\n true\r\n );\r\n }\r\n else {\r\n handleExceptionResponse(xhr, _ajaxOptions, thrownError);\r\n showCmdMessage(\r\n cmd.substr(0,cmd.indexOf(' ')-1),\r\n 'MESSAGING_ERROR',\r\n `Unexpected error ${(thrownError !== '')?thrownError:'with return status = '+xhr.status}`,\r\n true\r\n ); \r\n }\r\n },\r\n success: function(response) {\r\n // var returnedResponse = JSON.parse(response.responseText);\r\n $('.orec').show();\r\n console.log(response.responseText);\r\n if (\r\n response.responseText &&\r\n JSON.parse(response.responseText).Result === 'Success' &&\r\n reboot\r\n ) {\r\n delayReboot(2500, button.attributes.cmdname.value);\r\n }\r\n },\r\n });\r\n}\r\nfunction getLongOps(data, name, longopts){\r\n return data.values[name]!==undefined?data.values[name][longopts]:\"\";\r\n}\r\nfunction getCommands() {\r\n $.getJSON('/commands.json', function(data) {\r\n console.log(data);\r\n $('.orec').show();\r\n data.commands.forEach(function(command) {\r\n if ($('#flds-' + command.name).length === 0) {\r\n const cmdParts = command.name.split('-');\r\n const isConfig = cmdParts[0] === 'cfg';\r\n const targetDiv = '#tab-' + cmdParts[0] + '-' + cmdParts[1];\r\n let innerhtml = '';\r\n\r\n // innerhtml+='<tr class=\"table-light\"><td>'+(isConfig?'<h1>':'');\r\n innerhtml +=\r\n '<div class=\"card text-white mb-3\"><div class=\"card-header\">' +\r\n command.help.encodeHTML().replace(/\\n/g, '<br />') +\r\n '</div><div class=\"card-body\">';\r\n innerhtml += '<fieldset id=\"flds-' + command.name + '\">';\r\n if (command.argtable) {\r\n command.argtable.forEach(function(arg) {\r\n let placeholder = arg.datatype || '';\r\n const ctrlname = command.name + '-' + arg.longopts;\r\n const curvalue = getLongOps(data,command.name,arg.longopts);\r\n\r\n let attributes = 'hasvalue=' + arg.hasvalue + ' ';\r\n\r\n // attributes +='datatype=\"'+arg.datatype+'\" ';\r\n attributes += 'longopts=\"' + arg.longopts + '\" ';\r\n attributes += 'shortopts=\"' + arg.shortopts + '\" ';\r\n attributes += 'checkbox=' + arg.checkbox + ' ';\r\n attributes += 'cmdname=\"' + command.name + '\" ';\r\n attributes +=\r\n 'id=\"' +\r\n ctrlname +\r\n '\" name=\"' +\r\n ctrlname +\r\n '\" hasvalue=\"' +\r\n arg.hasvalue +\r\n '\" ';\r\n let extraclass = arg.mincount > 0 ? 'bg-success' : '';\r\n if (arg.glossary === 'hidden') {\r\n attributes += ' style=\"visibility: hidden;\"';\r\n }\r\n if (arg.checkbox) {\r\n innerhtml +=\r\n '<div class=\"form-check\"><label class=\"form-check-label\">';\r\n innerhtml +=\r\n '<input type=\"checkbox\" ' +\r\n attributes +\r\n ' class=\"form-check-input ' +\r\n extraclass +\r\n '\" value=\"\" >' +\r\n arg.glossary.encodeHTML() +\r\n '<small class=\"form-text text-muted\">Previous value: ' +\r\n (curvalue ? 'Checked' : 'Unchecked') +\r\n '</small></label>';\r\n } else {\r\n innerhtml +=\r\n '<div class=\"form-group\" ><label for=\"' +\r\n ctrlname +\r\n '\">' +\r\n arg.glossary.encodeHTML() +\r\n '</label>';\r\n if (placeholder.includes('|')) {\r\n extraclass = placeholder.startsWith('+') ? ' multiple ' : '';\r\n placeholder = placeholder\r\n .replace('<', '')\r\n .replace('=', '')\r\n .replace('>', '');\r\n innerhtml += `<select ${attributes} class=\"form-control ${extraclass}\" >`;\r\n placeholder = '--|' + placeholder;\r\n placeholder.split('|').forEach(function(choice) {\r\n innerhtml += '<option >' + choice + '</option>';\r\n });\r\n innerhtml += '</select>';\r\n } else {\r\n innerhtml +=\r\n '<input type=\"text\" class=\"form-control ' +\r\n extraclass +\r\n '\" placeholder=\"' +\r\n placeholder +\r\n '\" ' +\r\n attributes +\r\n '>';\r\n }\r\n innerhtml +=\r\n '<small class=\"form-text text-muted\">Previous value: ' +\r\n (curvalue || '') +\r\n '</small>';\r\n }\r\n innerhtml += '</div>';\r\n });\r\n }\r\n innerhtml += '<div style=\"margin-top: 16px;\">';\r\n innerhtml +=\r\n '<div class=\"toast show\" role=\"alert\" aria-live=\"assertive\" aria-atomic=\"true\" style=\"display: none;\" id=\"toast_' +\r\n command.name +\r\n '\">';\r\n innerhtml +=\r\n '<div class=\"toast-header\"><strong class=\"mr-auto\">Result</strong><button type=\"button\" class=\"ml-2 mb-1 close\" data-dismiss=\"toast\" aria-label=\"Close\" onclick=\"$(this).parent().parent().hide()\">';\r\n innerhtml +=\r\n '<span aria-hidden=\"true\">×</span></button></div><div class=\"toast-body\" id=\"msg_' +\r\n command.name +\r\n '\"></div></div>';\r\n if (isConfig) {\r\n innerhtml +=\r\n '<button type=\"submit\" class=\"btn btn-info\" id=\"btn-save-' +\r\n command.name +\r\n '\" cmdname=\"' +\r\n command.name +\r\n '\" onclick=\"runCommand(this,false)\">Save</button>';\r\n innerhtml +=\r\n '<button type=\"submit\" class=\"btn btn-warning\" id=\"btn-commit-' +\r\n command.name +\r\n '\" cmdname=\"' +\r\n command.name +\r\n '\" onclick=\"runCommand(this,true)\">Apply</button>';\r\n } else {\r\n innerhtml +=\r\n '<button type=\"submit\" class=\"btn btn-success\" id=\"btn-run-' +\r\n command.name +\r\n '\" cmdname=\"' +\r\n command.name +\r\n '\" onclick=\"runCommand(this,false)\">Execute</button>';\r\n }\r\n innerhtml += '</div></fieldset></div></div>';\r\n if (isConfig) {\r\n $(targetDiv).append(innerhtml);\r\n } else {\r\n $('#commands-list').append(innerhtml);\r\n }\r\n }\r\n });\r\n\r\n data.commands.forEach(function(command) {\r\n $('[cmdname=' + command.name + ']:input').val('');\r\n $('[cmdname=' + command.name + ']:checkbox').prop('checked', false);\r\n if (command.argtable) {\r\n command.argtable.forEach(function(arg) {\r\n const ctrlselector = '#' + command.name + '-' + arg.longopts;\r\n const ctrlValue = getLongOps(data,command.name,arg.longopts);\r\n if (arg.checkbox) {\r\n $(ctrlselector)[0].checked = ctrlValue;\r\n } else {\r\n if (ctrlValue !== undefined) {\r\n $(ctrlselector)\r\n .val(ctrlValue)\r\n .trigger('change');\r\n }\r\n if (\r\n $(ctrlselector)[0].value.length === 0 &&\r\n (arg.datatype || '').includes('|')\r\n ) {\r\n $(ctrlselector)[0].value = '--';\r\n }\r\n }\r\n });\r\n }\r\n });\r\n }).fail(function(xhr, ajaxOptions, thrownError) {\r\n if(xhr.status==404){\r\n $('.orec').hide();\r\n } \r\n else {\r\n handleExceptionResponse(xhr, ajaxOptions, thrownError);\r\n }\r\n \r\n $('#commands-list').empty();\r\n blockAjax = false;\r\n });\r\n}\r\n\r\nfunction getConfig() {\r\n $.getJSON('/config.json', function(entries) {\r\n $('#nvsTable tr').remove();\r\n const data = (entries.config? entries.config : entries);\r\n SystemConfig = data;\r\n Object.keys(data)\r\n .sort()\r\n .forEach(function(key) {\r\n let val = data[key].value;\r\n if (key === 'autoexec') {\r\n if (data.autoexec.value === '0') {\r\n $('#disable-squeezelite')[0].checked = true;\r\n } else {\r\n $('#disable-squeezelite')[0].checked = false;\r\n }\r\n } else if (key === 'autoexec1') {\r\n const re = /-o\\s?([\"][^\"]*[\"]|[^-]+)/g;\r\n const m = re.exec(val);\r\n if (m[1].toUpperCase().startsWith('I2S')) {\r\n handleTemplateTypeRadio('i2s');\r\n } else if (m[1].toUpperCase().startsWith('SPDIF')) {\r\n handleTemplateTypeRadio('spdif');\r\n } else if (m[1].toUpperCase().startsWith('\"BT')) {\r\n handleTemplateTypeRadio('bt');\r\n }\r\n } else if (key === 'host_name') {\r\n val = val.replaceAll('\"', '');\r\n $('input#dhcp-name1').val(val);\r\n $('input#dhcp-name2').val(val);\r\n $('#player').val(val);\r\n document.title = val;\r\n hostName = val;\r\n } else if (key === 'rel_api') {\r\n releaseURL = val;\r\n }\r\n $('tbody#nvsTable').append(\r\n '<tr>' +\r\n '<td>' +\r\n key +\r\n '</td>' +\r\n \"<td class='value'>\" +\r\n \"<input type='text' class='form-control nvs' id='\" +\r\n key +\r\n \"' nvs_type=\" +\r\n data[key].type +\r\n ' >' +\r\n '</td>' +\r\n '</tr>'\r\n );\r\n $('input#' + key).val(data[key].value);\r\n });\r\n $('tbody#nvsTable').append(\r\n \"<tr><td><input type='text' class='form-control' id='nvs-new-key' placeholder='new key'></td><td><input type='text' class='form-control' id='nvs-new-value' placeholder='new value' nvs_type=33 ></td></tr>\"\r\n );\r\n if (entries.gpio) {\r\n $('#pins').show();\r\n $('tbody#gpiotable tr').remove();\r\n entries.gpio.forEach(function(gpioEntry) {\r\n $('tbody#gpiotable').append(\r\n '<tr class=' +\r\n (gpioEntry.fixed ? 'table-secondary' : 'table-primary') +\r\n '><th scope=\"row\">' +\r\n gpioEntry.group +\r\n '</th><td>' +\r\n gpioEntry.name +\r\n '</td><td>' +\r\n gpioEntry.gpio +\r\n '</td><td>' +\r\n (gpioEntry.fixed ? 'Fixed' : 'Configuration') +\r\n '</td></tr>'\r\n );\r\n });\r\n }\r\n else {\r\n $('#pins').hide();\r\n }\r\n }).fail(function(xhr, ajaxOptions, thrownError) {\r\n handleExceptionResponse(xhr, ajaxOptions, thrownError);\r\n blockAjax = false;\r\n });\r\n}\r\nfunction showLocalMessage(message, severity) {\r\n const msg = {\r\n message: message,\r\n type: severity,\r\n };\r\n showMessage(msg, new Date());\r\n}\r\n\r\nfunction showMessage(msg, msgTime) {\r\n let color = 'table-success';\r\n\r\n if (msg.type === 'MESSAGING_WARNING') {\r\n color = 'table-warning';\r\n if (messageseverity === 'MESSAGING_INFO') {\r\n messageseverity = 'MESSAGING_WARNING';\r\n }\r\n } else if (msg.type === 'MESSAGING_ERROR') {\r\n if (\r\n messageseverity === 'MESSAGING_INFO' ||\r\n messageseverity === 'MESSAGING_WARNING'\r\n ) {\r\n messageseverity = 'MESSAGING_ERROR';\r\n }\r\n color = 'table-danger';\r\n }\r\n if (++messagecount > 0) {\r\n $('#msgcnt').removeClass('badge-success');\r\n $('#msgcnt').removeClass('badge-warning');\r\n $('#msgcnt').removeClass('badge-danger');\r\n $('#msgcnt').addClass(pillcolors[messageseverity]);\r\n $('#msgcnt').text(messagecount);\r\n }\r\n\r\n $('#syslogTable').append(\r\n \"<tr class='\" +\r\n color +\r\n \"'>\" +\r\n '<td>' +\r\n msgTime.toLocalShort() +\r\n '</td>' +\r\n '<td>' +\r\n msg.message.encodeHTML() +\r\n '</td>' +\r\n '</tr>'\r\n );\r\n}\r\n\r\nfunction inRange(x, min, max) {\r\n return (x - min) * (x - max) <= 0;\r\n}\r\n\r\nfunction sleep(ms) {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n}\r\n\r\n",[],{"ruleId":null,"fatal":true,"severity":2,"message":"9"},"Parsing error: require() of ES Module C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\node_modules\\eslint\\node_modules\\eslint-scope\\lib\\definition.js from C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\node_modules\\babel-eslint\\lib\\require-from-eslint.js not supported.\nInstead change the require of definition.js in C:\\Users\\sle11\\Documents\\VSCode\\squeezelite-esp32\\components\\wifi-manager\\webapp\\node_modules\\babel-eslint\\lib\\require-from-eslint.js to a dynamic import() which is available in all CommonJS modules."]