Merge branch 'wellenvogel:master' into master
This commit is contained in:
commit
8a776d355b
|
@ -145,6 +145,15 @@ For details refer to the [example description](lib/exampletask/Readme.md).
|
||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
[20220124](../../releases/tag/20220124)
|
||||||
|
*********
|
||||||
|
* make the serial input and output working again
|
||||||
|
[20220114](../../releases/tag/20220114)
|
||||||
|
*********
|
||||||
|
* incorporate some changes from [Homberger](https://github.com/AK-Homberger/NMEA2000-AIS-Gateway) to improve AIS compatibility with Raymarine displays
|
||||||
|
* introduce a global switch to prevent sending out converted NMEA2000 data
|
||||||
|
* extension API improvements (hide config values, set config values)
|
||||||
|
|
||||||
[20220112](../../releases/tag/20220112)
|
[20220112](../../releases/tag/20220112)
|
||||||
*********
|
*********
|
||||||
* correctly send out seasmart if NMEA out is not configured
|
* correctly send out seasmart if NMEA out is not configured
|
||||||
|
|
|
@ -102,8 +102,8 @@ void GwChannelList::begin(bool fallbackSerial){
|
||||||
theChannels.push_back(channel);
|
theChannels.push_back(channel);
|
||||||
|
|
||||||
//serial 1
|
//serial 1
|
||||||
bool serCanRead=false;
|
bool serCanRead=true;
|
||||||
bool serCanWrite=false;
|
bool serCanWrite=true;
|
||||||
int serialrx=-1;
|
int serialrx=-1;
|
||||||
int serialtx=-1;
|
int serialtx=-1;
|
||||||
#ifdef GWSERIAL_MODE
|
#ifdef GWSERIAL_MODE
|
||||||
|
|
|
@ -114,6 +114,16 @@ int GwConfigHandler::getInt(const String name,int defaultv) const{
|
||||||
if (!i) return defaultv;
|
if (!i) return defaultv;
|
||||||
return i->asInt();
|
return i->asInt();
|
||||||
}
|
}
|
||||||
|
void GwConfigHandler::stopChanges(){
|
||||||
|
allowChanges=false;
|
||||||
|
}
|
||||||
|
bool GwConfigHandler::setValue(String name,String value){
|
||||||
|
if (! allowChanges) return false;
|
||||||
|
GwConfigInterface *i=getConfigItem(name,false);
|
||||||
|
if (!i) return false;
|
||||||
|
i->value=value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GwNmeaFilter::handleToken(String token, int index){
|
void GwNmeaFilter::handleToken(String token, int index){
|
||||||
switch(index){
|
switch(index){
|
||||||
|
|
|
@ -14,11 +14,13 @@ class GwConfigHandler: public GwConfigDefinitions{
|
||||||
GwLog *logger;
|
GwLog *logger;
|
||||||
typedef std::map<String,String> StringMap;
|
typedef std::map<String,String> StringMap;
|
||||||
StringMap changedValues;
|
StringMap changedValues;
|
||||||
|
boolean allowChanges=true;
|
||||||
public:
|
public:
|
||||||
public:
|
public:
|
||||||
GwConfigHandler(GwLog *logger);
|
GwConfigHandler(GwLog *logger);
|
||||||
bool loadConfig();
|
bool loadConfig();
|
||||||
bool saveConfig();
|
bool saveConfig();
|
||||||
|
void stopChanges();
|
||||||
bool updateValue(String name, String value);
|
bool updateValue(String name, String value);
|
||||||
bool reset(bool save);
|
bool reset(bool save);
|
||||||
String toString() const;
|
String toString() const;
|
||||||
|
@ -27,6 +29,12 @@ class GwConfigHandler: public GwConfigDefinitions{
|
||||||
bool getBool(const String name,bool defaultv=false) const ;
|
bool getBool(const String name,bool defaultv=false) const ;
|
||||||
int getInt(const String name,int defaultv=0) const;
|
int getInt(const String name,int defaultv=0) const;
|
||||||
GwConfigInterface * getConfigItem(const String name, bool dummy=false) const;
|
GwConfigInterface * getConfigItem(const String name, bool dummy=false) const;
|
||||||
|
/**
|
||||||
|
* change the value of a config item
|
||||||
|
* will become a noop after stopChanges has been called
|
||||||
|
* !use with care! no checks of the value
|
||||||
|
*/
|
||||||
|
bool setValue(String name, String value);
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
|
@ -10,6 +10,13 @@
|
||||||
*/
|
*/
|
||||||
void exampleInit(GwApi *api){
|
void exampleInit(GwApi *api){
|
||||||
api->getLogger()->logDebug(GwLog::LOG,"example init running");
|
api->getLogger()->logDebug(GwLog::LOG,"example init running");
|
||||||
|
//this example is a more or less useless example how you could set some
|
||||||
|
//config value to a fixed value
|
||||||
|
//you can only set config values within the init function
|
||||||
|
//you could also compute this value from some own configuration
|
||||||
|
//for this example it would make a lot of sense to declare a capability
|
||||||
|
//to hide this config item from the UI - see header file
|
||||||
|
api->getConfig()->setValue(api->getConfig()->minXdrInterval,"50");
|
||||||
}
|
}
|
||||||
#define INVALID_COORD -99999
|
#define INVALID_COORD -99999
|
||||||
class GetBoatDataRequest: public GwMessage{
|
class GetBoatDataRequest: public GwMessage{
|
||||||
|
@ -84,6 +91,7 @@ void exampleTask(GwApi *api){
|
||||||
bool hasPosition=false;
|
bool hasPosition=false;
|
||||||
bool hasPosition2=false;
|
bool hasPosition2=false;
|
||||||
LOG_DEBUG(GwLog::DEBUG,"example switch ist %s",exampleSwitch?"true":"false");
|
LOG_DEBUG(GwLog::DEBUG,"example switch ist %s",exampleSwitch?"true":"false");
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"minXdrInterval=%d",api->getConfig()->getInt(api->getConfig()->minXdrInterval));
|
||||||
GwApi::BoatValue *longitude=new GwApi::BoatValue(F("Longitude"));
|
GwApi::BoatValue *longitude=new GwApi::BoatValue(F("Longitude"));
|
||||||
GwApi::BoatValue *latitude=new GwApi::BoatValue(F("Latitude"));
|
GwApi::BoatValue *latitude=new GwApi::BoatValue(F("Latitude"));
|
||||||
GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName);
|
GwApi::BoatValue *testValue=new GwApi::BoatValue(boatItemName);
|
||||||
|
|
|
@ -43,4 +43,7 @@ DECLARE_INITFUNCTION(exampleInit);
|
||||||
//elements when this capability is set correctly
|
//elements when this capability is set correctly
|
||||||
DECLARE_CAPABILITY(testboard,true);
|
DECLARE_CAPABILITY(testboard,true);
|
||||||
DECLARE_CAPABILITY(testboard2,true);
|
DECLARE_CAPABILITY(testboard2,true);
|
||||||
|
//hide some config value
|
||||||
|
//just set HIDE + the name of the config item to true
|
||||||
|
DECLARE_CAPABILITY(HIDEminXdrInterval,true);
|
||||||
#endif
|
#endif
|
|
@ -83,11 +83,24 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
|
|
||||||
// PGN129038
|
// PGN129038
|
||||||
SetN2kAISClassAPosition(N2kMsg, _uMsgType, (tN2kAISRepeat)_Repeat, _uMmsi,
|
|
||||||
_iPosLat / 600000.0, _iPosLon / 600000.0,
|
N2kMsg.SetPGN(129038L);
|
||||||
_bPosAccuracy, _Raim, _timestamp,
|
N2kMsg.Priority = 4;
|
||||||
decodeCog(_iCog) , _uSog * knToms / 10.0,
|
N2kMsg.AddByte((_Repeat & 0x03) << 6 | (_uMsgType & 0x3f));
|
||||||
decodeHeading(_iHeading), decodeRot(_iRot), (tN2kAISNavStatus)_uNavstatus);
|
N2kMsg.Add4ByteUInt(_uMmsi);
|
||||||
|
N2kMsg.Add4ByteDouble(_iPosLon / 600000.0, 1e-07);
|
||||||
|
N2kMsg.Add4ByteDouble(_iPosLat / 600000.0, 1e-07);
|
||||||
|
N2kMsg.AddByte((_timestamp & 0x3f) << 2 | (_Raim & 0x01) << 1 | (_bPosAccuracy & 0x01));
|
||||||
|
N2kMsg.Add2ByteUDouble(decodeCog(_iCog), 1e-04);
|
||||||
|
N2kMsg.Add2ByteUDouble(_uSog * knToms/10.0, 0.01);
|
||||||
|
N2kMsg.AddByte(0x00); // Communication State (19 bits)
|
||||||
|
N2kMsg.AddByte(0x00);
|
||||||
|
N2kMsg.AddByte(0x00); // AIS transceiver information (5 bits)
|
||||||
|
N2kMsg.Add2ByteUDouble(decodeHeading(_iHeading), 1e-04);
|
||||||
|
N2kMsg.Add2ByteDouble(decodeRot(_iRot), 3.125E-05); // 1e-3/32.0
|
||||||
|
N2kMsg.AddByte(0xF0 | (_uNavstatus & 0x0f));
|
||||||
|
N2kMsg.AddByte(0xff); // Reserved
|
||||||
|
N2kMsg.AddByte(0xff); // SID (NA)
|
||||||
|
|
||||||
send(N2kMsg);
|
send(N2kMsg);
|
||||||
}
|
}
|
||||||
|
@ -124,16 +137,22 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
uint16_t eta_days = tNMEA0183Msg::makeTime(tm) / (24UL * 3600UL);
|
uint16_t eta_days = tNMEA0183Msg::makeTime(tm) / (24UL * 3600UL);
|
||||||
|
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
char CS[30];
|
|
||||||
char Name[30];
|
|
||||||
char Dest[30];
|
|
||||||
|
|
||||||
strncpy(CS, _strCallsign.c_str(), sizeof(CS)-1);
|
char CS[8];
|
||||||
CS[29]=0;
|
char Name[21];
|
||||||
strncpy(Name, _strName.c_str(), sizeof(Name)-1);
|
char Dest[21];
|
||||||
Name[29]=0;
|
|
||||||
strncpy(Dest, _strDestination.c_str(), sizeof(Dest)-1);
|
strncpy(CS, _strCallsign.c_str(), sizeof(CS) - 1);
|
||||||
Dest[29]=0;
|
CS[7] = 0;
|
||||||
|
for (int i = strlen(CS); i < 7; i++) CS[i] = 32;
|
||||||
|
|
||||||
|
strncpy(Name, _strName.c_str(), sizeof(Name) - 1);
|
||||||
|
Name[20] = 0;
|
||||||
|
for (int i = strlen(Name); i < 20; i++) Name[i] = 32;
|
||||||
|
|
||||||
|
strncpy(Dest, _strDestination.c_str(), sizeof(Dest) - 1);
|
||||||
|
Dest[20] = 0;
|
||||||
|
for (int i = strlen(Dest); i < 20; i++) Dest[i] = 32;
|
||||||
|
|
||||||
// PGN129794
|
// PGN129794
|
||||||
SetN2kAISClassAStatic(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi,
|
SetN2kAISClassAStatic(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi,
|
||||||
|
@ -205,9 +224,10 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
|
|
||||||
// PGN129040
|
// PGN129040
|
||||||
|
|
||||||
char Name[21] = "";
|
char Name[21];
|
||||||
strncpy(Name, _strName.c_str(), sizeof(Name)-1);
|
strncpy(Name, _strName.c_str(), sizeof(Name)-1);
|
||||||
Name[20]=0;
|
Name[20]=0;
|
||||||
|
for (int i = strlen(Name); i < 20; i++) Name[i] = 32;
|
||||||
|
|
||||||
N2kMsg.SetPGN(129040UL);
|
N2kMsg.SetPGN(129040UL);
|
||||||
N2kMsg.Priority = 4;
|
N2kMsg.Priority = 4;
|
||||||
|
@ -230,6 +250,7 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
N2kMsg.AddStr(Name, 20);
|
N2kMsg.AddStr(Name, 20);
|
||||||
N2kMsg.AddByte((_dte & 0x01) | (_assigned & 0x01) << 1) ;
|
N2kMsg.AddByte((_dte & 0x01) | (_assigned & 0x01) << 1) ;
|
||||||
N2kMsg.AddByte(0);
|
N2kMsg.AddByte(0);
|
||||||
|
N2kMsg.AddByte(0xff); // Sequence ID (Not Available)
|
||||||
|
|
||||||
send(N2kMsg);
|
send(N2kMsg);
|
||||||
}
|
}
|
||||||
|
@ -244,9 +265,11 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
//Serial.println("24A");
|
//Serial.println("24A");
|
||||||
|
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
char Name[30];
|
char Name[21];
|
||||||
strncpy(Name, _strName.c_str(), sizeof(Name)-1);
|
strncpy(Name, _strName.c_str(), sizeof(Name) - 1);
|
||||||
Name[29]=0;
|
Name[20]=0;
|
||||||
|
for (int i = strlen(Name); i < 20; i++) Name[i] = 32;
|
||||||
|
|
||||||
|
|
||||||
// PGN129809
|
// PGN129809
|
||||||
SetN2kAISClassBStaticPartA(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi, Name);
|
SetN2kAISClassBStaticPartA(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi, Name);
|
||||||
|
@ -263,13 +286,17 @@ class MyAisDecoder : public AIS::AisDecoder
|
||||||
|
|
||||||
|
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
char CS[30];
|
char CS[8];
|
||||||
char Vendor[30];
|
char Vendor[8];
|
||||||
|
|
||||||
|
strncpy(CS, _strCallsign.c_str(), sizeof(CS) - 1);
|
||||||
|
CS[7] = 0;
|
||||||
|
for (int i = strlen(CS); i < 7; i++) CS[i] = 32;
|
||||||
|
strncpy(Vendor, _strVendor.c_str(), sizeof(Vendor) - 1);
|
||||||
|
Vendor[7] = 0;
|
||||||
|
for (int i = strlen(Vendor); i < 7; i++) Vendor[i] = 32;
|
||||||
|
|
||||||
|
|
||||||
strncpy(CS, _strCallsign.c_str(), sizeof(CS)-1);
|
|
||||||
CS[29]=0;
|
|
||||||
strncpy(Vendor, _strVendor.c_str(), sizeof(Vendor)-1);
|
|
||||||
Vendor[29]=0;
|
|
||||||
|
|
||||||
// PGN129810
|
// PGN129810
|
||||||
SetN2kAISClassBStaticPartB(N2kMsg, _uMsgType, (tN2kAISRepeat)_repeat, _uMmsi,
|
SetN2kAISClassBStaticPartB(N2kMsg, _uMsgType, (tN2kAISRepeat)_repeat, _uMmsi,
|
||||||
|
|
31
src/main.cpp
31
src/main.cpp
|
@ -109,6 +109,7 @@ GwWifi gwWifi(&config,&logger,fixedApPass);
|
||||||
GwChannelList channels(&logger,&config);
|
GwChannelList channels(&logger,&config);
|
||||||
GwBoatData boatData(&logger);
|
GwBoatData boatData(&logger);
|
||||||
GwXDRMappings xdrMappings(&logger,&config);
|
GwXDRMappings xdrMappings(&logger,&config);
|
||||||
|
bool sendOutN2k=true;
|
||||||
|
|
||||||
|
|
||||||
int NodeAddress; // To store last Node Address
|
int NodeAddress; // To store last Node Address
|
||||||
|
@ -205,7 +206,7 @@ void handleN2kMessage(const tN2kMsg &n2kMsg,int sourceId, bool isConverted=false
|
||||||
if (! isConverted){
|
if (! isConverted){
|
||||||
nmea0183Converter->HandleMsg(n2kMsg,sourceId);
|
nmea0183Converter->HandleMsg(n2kMsg,sourceId);
|
||||||
}
|
}
|
||||||
if (sourceId != N2K_CHANNEL_ID){
|
if (sourceId != N2K_CHANNEL_ID && sendOutN2k){
|
||||||
countNMEA2KOut.add(n2kMsg.PGN);
|
countNMEA2KOut.add(n2kMsg.PGN);
|
||||||
NMEA2000.SendMsg(n2kMsg);
|
NMEA2000.SendMsg(n2kMsg);
|
||||||
}
|
}
|
||||||
|
@ -599,6 +600,12 @@ void setup() {
|
||||||
logger.prefix="FALLBACK:";
|
logger.prefix="FALLBACK:";
|
||||||
#endif
|
#endif
|
||||||
userCodeHandler.startInitTasks(MIN_USER_TASK);
|
userCodeHandler.startInitTasks(MIN_USER_TASK);
|
||||||
|
config.stopChanges();
|
||||||
|
//maybe the user code changed the level
|
||||||
|
level=config.getInt(config.logLevel,LOGLEVEL);
|
||||||
|
logger.setLevel(level);
|
||||||
|
sendOutN2k=config.getBool(config.sendN2k,true);
|
||||||
|
logger.logDebug(GwLog::LOG,"send N2k=%s",(sendOutN2k?"true":"false"));
|
||||||
gwWifi.setup();
|
gwWifi.setup();
|
||||||
MDNS.begin(config.getConfigItem(config.systemName)->asCString());
|
MDNS.begin(config.getConfigItem(config.systemName)->asCString());
|
||||||
channels.begin(fallbackSerial);
|
channels.begin(fallbackSerial);
|
||||||
|
@ -682,7 +689,7 @@ void setup() {
|
||||||
NMEA2000.SetProductInformation("1", // Manufacturer's Model serial code
|
NMEA2000.SetProductInformation("1", // Manufacturer's Model serial code
|
||||||
100, // Manufacturer's product code
|
100, // Manufacturer's product code
|
||||||
systemName->asCString(), // Manufacturer's Model ID
|
systemName->asCString(), // Manufacturer's Model ID
|
||||||
VERSION, // Manufacturer's Software version code
|
FIRMWARE_TYPE, // Manufacturer's Software version code
|
||||||
VERSION, // Manufacturer's Model version,
|
VERSION, // Manufacturer's Model version,
|
||||||
N2K_LOAD_LEVEL,
|
N2K_LOAD_LEVEL,
|
||||||
0xffff, //Version
|
0xffff, //Version
|
||||||
|
@ -707,17 +714,19 @@ void setup() {
|
||||||
logger.flush();
|
logger.flush();
|
||||||
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
|
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress);
|
||||||
NMEA2000.SetForwardOwnMessages(false);
|
NMEA2000.SetForwardOwnMessages(false);
|
||||||
// Set the information for other bus devices, which messages we support
|
if (sendOutN2k){
|
||||||
unsigned long *pgns=toN2KConverter->handledPgns();
|
// Set the information for other bus devices, which messages we support
|
||||||
if (logger.isActive(GwLog::DEBUG)){
|
unsigned long *pgns=toN2KConverter->handledPgns();
|
||||||
unsigned long *op=pgns;
|
if (logger.isActive(GwLog::DEBUG)){
|
||||||
while (*op != 0){
|
unsigned long *op=pgns;
|
||||||
logger.logDebug(GwLog::DEBUG,"add transmit pgn %ld",(long)(*op));
|
while (*op != 0){
|
||||||
logger.flush();
|
logger.logDebug(GwLog::DEBUG,"add transmit pgn %ld",(long)(*op));
|
||||||
op++;
|
logger.flush();
|
||||||
|
op++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
NMEA2000.ExtendTransmitMessages(pgns);
|
||||||
}
|
}
|
||||||
NMEA2000.ExtendTransmitMessages(pgns);
|
|
||||||
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
|
NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns());
|
||||||
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
|
NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){
|
||||||
handleN2kMessage(n2kMsg,N2K_CHANNEL_ID);
|
handleN2kMessage(n2kMsg,N2K_CHANNEL_ID);
|
||||||
|
|
|
@ -175,6 +175,14 @@
|
||||||
"description": "min interval in ms between 2 NMEA 2000 records with the same PGN and the same source (> 5)",
|
"description": "min interval in ms between 2 NMEA 2000 records with the same PGN and the same source (> 5)",
|
||||||
"category": "converter"
|
"category": "converter"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name":"sendN2k",
|
||||||
|
"label":"NMEA2000 out",
|
||||||
|
"type":"boolean",
|
||||||
|
"default":"true",
|
||||||
|
"description":"send out the converted data on the NMEA2000 bus\nIf set to off the converted data will still be shown at the data tab.",
|
||||||
|
"category":"converter"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "usbActisense",
|
"name": "usbActisense",
|
||||||
"label": "USB mode",
|
"label": "USB mode",
|
||||||
|
|
28
web/index.js
28
web/index.js
|
@ -320,8 +320,8 @@ let counters={
|
||||||
countTCPClientout: 'TCPclient out',
|
countTCPClientout: 'TCPclient out',
|
||||||
countUSBin: 'USB in',
|
countUSBin: 'USB in',
|
||||||
countUSBout: 'USB out',
|
countUSBout: 'USB out',
|
||||||
countSERIn: 'Serial in',
|
countSERin: 'Serial in',
|
||||||
countSEROut: 'Serial out'
|
countSERout: 'Serial out'
|
||||||
}
|
}
|
||||||
function showOverlay(text, isHtml) {
|
function showOverlay(text, isHtml) {
|
||||||
let el = document.getElementById('overlayContent');
|
let el = document.getElementById('overlayContent');
|
||||||
|
@ -953,17 +953,23 @@ function createConfigDefinitions(parent, capabilities, defs,includeXdr) {
|
||||||
category = item.category;
|
category = item.category;
|
||||||
}
|
}
|
||||||
let showItem=true;
|
let showItem=true;
|
||||||
if (item.capabilities !== undefined) {
|
let itemCapabilities=item.capabilities||{};
|
||||||
for (let capability in item.capabilities) {
|
itemCapabilities['HIDE'+item.name]=null;
|
||||||
let values = item.capabilities[capability];
|
for (let capability in itemCapabilities) {
|
||||||
let found = false;
|
let values = itemCapabilities[capability];
|
||||||
if (! (values instanceof Array)) values=[values];
|
let found = false;
|
||||||
values.forEach(function (v) {
|
if (! (values instanceof Array)) values=[values];
|
||||||
|
values.forEach(function (v) {
|
||||||
|
if ( v === null){
|
||||||
|
if (capabilities[capability] === undefined) found=true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
if (capabilities[capability] == v) found = true;
|
if (capabilities[capability] == v) found = true;
|
||||||
});
|
}
|
||||||
if (!found) showItem=false;
|
});
|
||||||
}
|
if (!found) showItem=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showItem) {
|
if (showItem) {
|
||||||
currentCategoryPopulated=true;
|
currentCategoryPopulated=true;
|
||||||
let row = addEl('div', 'row', categoryEl);
|
let row = addEl('div', 'row', categoryEl);
|
||||||
|
|
Loading…
Reference in New Issue