mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-29 08:46:11 +02:00
Merge branch 'development03' into development03
This commit is contained in:
commit
6a5227bd0a
13 changed files with 82 additions and 31 deletions
|
@ -1,5 +1,11 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
|
## 0.8.111 - 2024-04-17
|
||||||
|
* fix MqTT discovery field `ALARM_MES_ID` #1591
|
||||||
|
* fix Wifi reconnect for ESP32 #1589 #1575
|
||||||
|
* open link from `index.html` in new tab #1588 #1587
|
||||||
|
* merge PR: Disable upload and import buttons when no file is selected #1586 #1519
|
||||||
|
|
||||||
## 0.8.110 - 2024-04-11
|
## 0.8.110 - 2024-04-11
|
||||||
* revert CMT2300A changes #1553
|
* revert CMT2300A changes #1553
|
||||||
* merged PR: fix closing tag #1584
|
* merged PR: fix closing tag #1584
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 8
|
#define VERSION_MINOR 8
|
||||||
#define VERSION_PATCH 110
|
#define VERSION_PATCH 111
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
|
|
|
@ -33,31 +33,31 @@
|
||||||
|
|
||||||
// prototypes
|
// prototypes
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0);
|
T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0);
|
T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcUdcCh(Inverter<> *iv, uint8_t arg0);
|
T calcUdcCh(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0);
|
T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0);
|
T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcIrradiation(Inverter<> *iv, uint8_t arg0);
|
T calcIrradiation(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0);
|
T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0);
|
T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0);
|
T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0);
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
using func_t = T (Inverter<> *, uint8_t);
|
using func_t = T (Inverter<> *, uint8_t);
|
||||||
|
@ -275,7 +275,8 @@ class Inverter {
|
||||||
if(InverterStatus::OFF != status) {
|
if(InverterStatus::OFF != status) {
|
||||||
mDevControlRequest = true;
|
mDevControlRequest = true;
|
||||||
devControlCmd = cmd;
|
devControlCmd = cmd;
|
||||||
//app->triggerTickSend(); // done in RestApi.h, because of "chicken-and-egg problem ;-)"
|
//assert(App);
|
||||||
|
//App->triggerTickSend(0);
|
||||||
}
|
}
|
||||||
return (InverterStatus::OFF != status);
|
return (InverterStatus::OFF != status);
|
||||||
}
|
}
|
||||||
|
@ -823,6 +824,7 @@ class Inverter {
|
||||||
public:
|
public:
|
||||||
static uint32_t *timestamp; // system timestamp
|
static uint32_t *timestamp; // system timestamp
|
||||||
static cfgInst_t *generalConfig; // general inverter configuration from setup
|
static cfgInst_t *generalConfig; // general inverter configuration from setup
|
||||||
|
static IApp *App;
|
||||||
|
|
||||||
uint16_t mDtuRxCnt = 0;
|
uint16_t mDtuRxCnt = 0;
|
||||||
uint16_t mDtuTxCnt = 0;
|
uint16_t mDtuTxCnt = 0;
|
||||||
|
@ -843,6 +845,8 @@ template <class REC_TYP>
|
||||||
uint32_t *Inverter<REC_TYP>::timestamp {0};
|
uint32_t *Inverter<REC_TYP>::timestamp {0};
|
||||||
template <class REC_TYP>
|
template <class REC_TYP>
|
||||||
cfgInst_t *Inverter<REC_TYP>::generalConfig {0};
|
cfgInst_t *Inverter<REC_TYP>::generalConfig {0};
|
||||||
|
template <class REC_TYP>
|
||||||
|
IApp *Inverter<REC_TYP>::App {nullptr};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -852,7 +856,7 @@ cfgInst_t *Inverter<REC_TYP>::generalConfig {0};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldTotalCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldTotalCh0"));
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -866,7 +870,7 @@ static T calcYieldTotalCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldDayCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcYieldDayCh0"));
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -880,7 +884,7 @@ static T calcYieldDayCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcUdcCh(Inverter<> *iv, uint8_t arg0) {
|
T calcUdcCh(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcUdcCh"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcUdcCh"));
|
||||||
// arg0 = channel of source
|
// arg0 = channel of source
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -894,7 +898,7 @@ static T calcUdcCh(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcPowerDcCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcPowerDcCh0"));
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -908,7 +912,7 @@ static T calcPowerDcCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcEfficiencyCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcEfficiencyCh0"));
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
|
@ -924,7 +928,7 @@ static T calcEffiencyCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcIrradiation(Inverter<> *iv, uint8_t arg0) {
|
T calcIrradiation(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcIrradiation"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcIrradiation"));
|
||||||
// arg0 = channel
|
// arg0 = channel
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
|
@ -936,7 +940,7 @@ static T calcIrradiation(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerAcCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerAcCh0"));
|
||||||
T acMaxPower = 0.0;
|
T acMaxPower = 0.0;
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
|
@ -957,7 +961,7 @@ static T calcMaxPowerAcCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0) {
|
T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxTempCh0"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxTempCh0"));
|
||||||
T maxTemp = 0.0;
|
T maxTemp = 0.0;
|
||||||
if(NULL != iv) {
|
if(NULL != iv) {
|
||||||
|
@ -979,7 +983,7 @@ static T calcMaxTempCh0(Inverter<> *iv, uint8_t arg0) {
|
||||||
|
|
||||||
|
|
||||||
template<class T=float>
|
template<class T=float>
|
||||||
static T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0) {
|
T calcMaxPowerDc(Inverter<> *iv, uint8_t arg0) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerDc"));
|
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:calcMaxPowerDc"));
|
||||||
// arg0 = channel
|
// arg0 = channel
|
||||||
T dcMaxPower = 0.0;
|
T dcMaxPower = 0.0;
|
||||||
|
|
|
@ -18,6 +18,7 @@ class HmSystem {
|
||||||
void setup(uint32_t *timestamp, cfgInst_t *config, IApp *app) {
|
void setup(uint32_t *timestamp, cfgInst_t *config, IApp *app) {
|
||||||
INVERTERTYPE::timestamp = timestamp;
|
INVERTERTYPE::timestamp = timestamp;
|
||||||
INVERTERTYPE::generalConfig = config;
|
INVERTERTYPE::generalConfig = config;
|
||||||
|
INVERTERTYPE::App = app;
|
||||||
//mInverter[0].app = app;
|
//mInverter[0].app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,8 @@ class AhoyWifi : public AhoyNetwork {
|
||||||
if(mConnected) {
|
if(mConnected) {
|
||||||
mConnected = false;
|
mConnected = false;
|
||||||
mOnNetworkCB(false);
|
mOnNetworkCB(false);
|
||||||
mAp.enable();
|
|
||||||
MDNS.end();
|
MDNS.end();
|
||||||
|
begin();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -59,7 +59,6 @@ class AhoyWifi : public AhoyNetwork {
|
||||||
mConnected = true;
|
mConnected = true;
|
||||||
ah::welcome(WiFi.localIP().toString(), F("Station"));
|
ah::welcome(WiFi.localIP().toString(), F("Station"));
|
||||||
MDNS.begin(mConfig->sys.deviceName);
|
MDNS.begin(mConfig->sys.deviceName);
|
||||||
//MDNS.addServiceTxt("http", "tcp", "path", "/");
|
|
||||||
mOnNetworkCB(true);
|
mOnNetworkCB(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -443,7 +443,8 @@ class PubMqtt {
|
||||||
snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]);
|
snprintf(topic.data(), topic.size(), "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]);
|
||||||
size_t size = measureJson(doc2) + 1;
|
size_t size = measureJson(doc2) + 1;
|
||||||
serializeJson(doc2, buf.data(), size);
|
serializeJson(doc2, buf.data(), size);
|
||||||
publish(topic.data(), buf.data(), true, false);
|
if(FLD_EVT != rec->assign[mDiscovery.sub].fieldId)
|
||||||
|
publish(topic.data(), buf.data(), true, false);
|
||||||
|
|
||||||
if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) {
|
if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) {
|
||||||
mDiscovery.sub = 0;
|
mDiscovery.sub = 0;
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Protection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Protection(Protection &other) = delete;
|
Protection(const Protection &other) = delete;
|
||||||
void operator=(const Protection &) = delete;
|
void operator=(const Protection &) = delete;
|
||||||
|
|
||||||
static Protection* getInstance(const char *pwd) {
|
static Protection* getInstance(const char *pwd) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
--nav-bg: #333;
|
--nav-bg: #333;
|
||||||
--primary: #006ec0;
|
--primary: #006ec0;
|
||||||
|
--primary-disabled: #ccc;
|
||||||
--primary-hover: #044e86;
|
--primary-hover: #044e86;
|
||||||
--secondary: #0072c8;
|
--secondary: #0072c8;
|
||||||
--nav-active: #555;
|
--nav-active: #555;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
--nav-bg: #333;
|
--nav-bg: #333;
|
||||||
--primary: #004d87;
|
--primary: #004d87;
|
||||||
|
--primary-disabled: #ccc;
|
||||||
--primary-hover: #023155;
|
--primary-hover: #023155;
|
||||||
--secondary: #0072c8;
|
--secondary: #0072c8;
|
||||||
--nav-active: #555;
|
--nav-active: #555;
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
<h3>{#SUPPORT}:</h3>
|
<h3>{#SUPPORT}:</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://github.com/lumapu/ahoy/blob/main/src/CHANGES.md" target="_blank">{#CHANGELOG}</a></li>
|
<li><a href="https://github.com/lumapu/ahoy/blob/main/src/CHANGES.md" target="_blank">{#CHANGELOG}</a></li>
|
||||||
<li>{#DISCUSS} <a href="https://discord.gg/WzhxEY62mB">Discord</a></li>
|
<li>{#DISCUSS} <a href="https://discord.gg/WzhxEY62mB" target="_blank">Discord</a></li>
|
||||||
<li>{#REPORT} <a href="https://github.com/lumapu/ahoy/issues" target="_blank">{#ISSUES}</a></li>
|
<li>{#REPORT} <a href="https://github.com/lumapu/ahoy/issues" target="_blank">{#ISSUES}</a></li>
|
||||||
<li>{#CONTRIBUTE} <a href="https://github.com/lumapu/ahoy/blob/main/User_Manual.md" target="_blank">{#DOCUMENTATION}</a></li>
|
<li>{#CONTRIBUTE} <a href="https://docs.ahoydtu.de" target="_blank">{#DOCUMENTATION}</a></li>
|
||||||
<li><a href="https://fw.ahoydtu.de/fw/dev/" target="_blank">Download</a> & Test {#DEV_FIRMWARE}, <a href="https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md" target="_blank">{#DEV_CHANGELOG}</a></li>
|
<li><a href="https://fw.ahoydtu.de/fw/dev/" target="_blank">Download</a> & Test {#DEV_FIRMWARE}, <a href="https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md" target="_blank">{#DEV_CHANGELOG}</a></li>
|
||||||
<li>{#DON_MAKE} <a href="https://paypal.me/lupusch" target="_blank">{#DONATION}</a></li>
|
<li>{#DON_MAKE} <a href="https://paypal.me/lupusch" target="_blank">{#DONATION}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -325,8 +325,8 @@
|
||||||
<div class="col-12 col-sm-9">
|
<div class="col-12 col-sm-9">
|
||||||
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
|
<form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-sm-8 my-2"><input type="file" name="upload"></div>
|
<div class="col-12 col-sm-8 my-2"><input type="file" id="importFileInput" name="upload"></div>
|
||||||
<div class="col-12 col-sm-4 my-2"><input type="button" class="btn" value="Import" onclick="hide()"></div>
|
<div class="col-12 col-sm-4 my-2"><input type="button" id="importButton" class="btn" value="Import" onclick="hide()"></div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -617,6 +617,22 @@
|
||||||
getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj));
|
getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const fileInput = document.querySelector('#importFileInput');
|
||||||
|
const button = document.querySelector('#importButton');
|
||||||
|
button.disabled = true;
|
||||||
|
button.title = "Please select a file first";
|
||||||
|
fileInput.addEventListener('change', () => {
|
||||||
|
if (fileInput.value) {
|
||||||
|
button.disabled = false;
|
||||||
|
button.title = "";
|
||||||
|
} else {
|
||||||
|
button.disabled = true;
|
||||||
|
button.title = "Please select a file first";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
document.getElementById("form").submit();
|
document.getElementById("form").submit();
|
||||||
var e = document.getElementById("content");
|
var e = document.getElementById("content");
|
||||||
|
|
|
@ -563,7 +563,13 @@ input.btn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.btn:hover {
|
input.btn:disabled {
|
||||||
|
background-color: var(--primary-disabled);
|
||||||
|
color: #888;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.btn:not(:disabled):hover {
|
||||||
background-color: #044e86;
|
background-color: #044e86;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
<legend class="des">{#SELECT_FILE} (*.bin)</legend>
|
<legend class="des">{#SELECT_FILE} (*.bin)</legend>
|
||||||
<p>{#INSTALLED_VERSION}:<br/><span id="version" style="background-color: var(--input-bg); padding: 7px; display: block; margin: 3px;"></span></p>
|
<p>{#INSTALLED_VERSION}:<br/><span id="version" style="background-color: var(--input-bg); padding: 7px; display: block; margin: 3px;"></span></p>
|
||||||
<form id="form" method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
<form id="form" method="POST" action="/update" enctype="multipart/form-data" accept-charset="utf-8">
|
||||||
<input type="file" name="update">
|
<input type="file" id="uploadFileInput" name="update">
|
||||||
<input type="button" class="btn my-4" value="{#BTN_UPDATE}" onclick="hide()">
|
<input type="button" id="uploadButton" class="btn my-4" value="{#BTN_UPDATE}" onclick="hide()">
|
||||||
</form>
|
</form>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
|
@ -23,6 +23,22 @@
|
||||||
</div>
|
</div>
|
||||||
{#HTML_FOOTER}
|
{#HTML_FOOTER}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const fileInput = document.querySelector('#uploadFileInput');
|
||||||
|
const button = document.querySelector('#uploadButton');
|
||||||
|
button.disabled = true;
|
||||||
|
button.title = "Please select a file first";
|
||||||
|
fileInput.addEventListener('change', () => {
|
||||||
|
if (fileInput.value) {
|
||||||
|
button.disabled = false;
|
||||||
|
button.title = "";
|
||||||
|
} else {
|
||||||
|
button.disabled = true;
|
||||||
|
button.title = "Please select a file first";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var env;
|
var env;
|
||||||
function parseGeneric(obj) {
|
function parseGeneric(obj) {
|
||||||
parseNav(obj)
|
parseNav(obj)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue