cwUi : Initial UI creation from resource file.

This commit is contained in:
kevin.larke 2020-03-31 13:10:45 -04:00
parent 80cd776337
commit 2372f153b3
6 changed files with 725 additions and 191 deletions

View File

@ -1,6 +1,7 @@
# To Do
- implement floating point UI numbers
- UI needs a special UUID (not kInvalidId) to specify the 'root' UI element. See note in cwUi._createFromObj()
- Look at 'BUG' warnings in cwNumericConvert.h.
- cwObject must be able to parse without dynamic memory allocation into a fixed buffer
@ -33,7 +34,24 @@ This is easy to reproduce by simply decreasing the size of the buffers in the pr
- (DONE) implement kTcpFl in cwTcpSocket.cpp
# UI Control Creation Protocol
The UI elements have four identifiers:
uuId - An integer which is unique among all identifiers for a given cwUi object.
appId - A constant (enumerated) id assigned by the application. Unique among siblings.
jsId - A string id used by Javascript to identify a control. Unique among siblings.
jsUuId - An integer which is unique among all identifers for the browser representation of a given cwUi object.
The 'jsId' is selected by the application when the object is created.
The 'jsUuId' is generated by the JS client when the UI element is created.
The 'uuId' is generated by the UI server when the JS client registers the control.
The 'appId' is assigned by the UI server when the JS client regsiters the control.
Client sends 'init' message.
Server sends 'create' messages.
Client sends 'register' messages.
Server send' 'id_assign' messages.
# Development Setup

552
cwUi.cpp
View File

@ -14,27 +14,48 @@ namespace cw
{
namespace ui
{
typedef struct appIdMapRecd_str
{
struct appIdMapRecd_str* link;
unsigned parentAppId;
unsigned appId;
char* jsId;
} appIdMapRecd_t;
typedef struct ele_str
{
struct ele_str* parent; // pointer to parent ele - or nullptr if this ele is attached to the root ui ele
unsigned uuId; // UI unique id - automatically generated and unique among all elements that are part of this ui_t object.
unsigned appId; // application assigned id - application assigned id
char* jsId; // javascript id
char* jsId; // javascript id
} ele_t;
typedef struct ui_str
{
websockSrv::handle_t wssH;
unsigned eleAllocN;
unsigned eleN;
ele_t** eleA;
uiCallback_t cbFunc;
void* cbArg;
websockSrv::handle_t wssH; // websock server handle
unsigned eleAllocN; // size of eleA[]
unsigned eleN; // count of ele's in use
ele_t** eleA; // eleA[ eleAllocN ]
uiCallback_t cbFunc; // app. cb func
void* cbArg; // app. cb func arg.
appIdMapRecd_t* appIdMap; // map of application parent/child/js id's
char* buf; // buf[bufN] output message formatting buffer
unsigned bufN; //
} ui_t;
ui_t* _handleToPtr( handle_t h )
{ return handleToPtr<handle_t,ui_t>(h); }
void _print_eles( ui_t* p )
{
for(unsigned i=0; i<p->eleN; ++i)
{
ele_t* e = p->eleA[i];
printf("%15s u:%i : u:%i a:%i %s\n",e->parent==nullptr?"<null>" : e->parent->jsId,e->parent==nullptr? -1 :e->parent->uuId,e->uuId,e->appId,e->jsId);
}
}
rc_t _destroy( ui_t* p )
{
rc_t rc = kOkRC;
@ -49,19 +70,74 @@ namespace cw
mem::release(p->eleA[i]);
}
appIdMapRecd_t* m = p->appIdMap;
while( m!=nullptr )
{
appIdMapRecd_t* m0 = m->link;
mem::release(m->jsId);
mem::release(m);
m = m0;
}
mem::release(p->eleA);
mem::release(p);
return rc;
}
appIdMapRecd_t* _findAppIdMap( ui_t* p, unsigned parentAppId, const char* jsId )
{
appIdMapRecd_t* m = p->appIdMap;
for(; m != nullptr; m=m->link)
if( m->parentAppId==parentAppId && textCompare(jsId,m->jsId)==0 )
return m;
return nullptr;
}
appIdMapRecd_t* _findAppIdMap( ui_t* p, unsigned parentAppId, unsigned appId )
{
appIdMapRecd_t* m = p->appIdMap;
for(; m != nullptr; m=m->link)
if( m->parentAppId==parentAppId && m->appId==appId )
return m;
return nullptr;
}
rc_t _allocAppIdMap( ui_t* p, unsigned parentAppId, unsigned appId, const char* jsId )
{
rc_t rc = kOkRC;
// The 'jsId' must be valid (or there is no reason to create the map.
// (since it will ultimately be used to locate the appId give the parentAppId and jsId)
if( jsId == nullptr || strlen(jsId) == 0 )
return cwLogError(kInvalidIdRC,"Registered parent/child app id's must have a valid 'jsId'.");
// verify that the parent/child pair is unique
if( _findAppIdMap(p,parentAppId,appId) != nullptr )
return cwLogError(kDuplicateRC,"An attempt was made to register a duplicate parent/child appid pair. parentId:%i appId:%i jsId:'%s'.",parentAppId,appId,cwStringNullGuard(jsId));
// verify that the parent/js pair is unique
if( _findAppIdMap(p,parentAppId,jsId) != nullptr )
return cwLogError(kDuplicateRC,"An attempt was made to register a duplicate parent app id/js id pair. parentId:%i appId:%i jsId:'%s'.",parentAppId,appId,cwStringNullGuard(jsId));
// allocate and link in a new appId map record
appIdMapRecd_t* m = mem::allocZ<appIdMapRecd_t>();
m->parentAppId = parentAppId;
m->appId = appId;
m->jsId = mem::duplStr(jsId);
m->link = p->appIdMap;
p->appIdMap = m;
return rc;
}
ele_t* _createEle( ui_t* p, ele_t* parent, unsigned appId, const char* jsId )
{
ele_t* e = mem::allocZ<ele_t>();
e->parent = parent;
e->parent = parent;
e->uuId = p->eleN;
e->appId = appId;
e->jsId = mem::duplStr(jsId);
e->appId = appId;
e->jsId = mem::duplStr(jsId);
if( p->eleN == p->eleAllocN )
{
@ -75,6 +151,7 @@ namespace cw
return e;
}
// Given a uuId return a pointer to the associated element.
ele_t* _uuIdToEle( ui_t* p, unsigned uuId, bool errorFl=true )
{
if( uuId >= p->eleN )
@ -86,10 +163,26 @@ namespace cw
return p->eleA[ uuId ];
}
rc_t _websockSend( ui_t* p, const char* msg )
// Given a parent UuId and a javascript id find the associated ele
ele_t* _parentUuId_JsId_ToEle( ui_t* p, unsigned parentUuId, const char* jsId, bool errorFl=true )
{
return websock::send( websockSrv::websockHandle( p->wssH ), kUiProtocolId, msg, strlen(msg) );
for(unsigned i=0; i<p->eleN; ++i)
if( ((p->eleA[i]->parent==nullptr && parentUuId == kRootUuId) || (p->eleA[i]->parent != nullptr && parentUuId == p->eleA[i]->parent->uuId)) && (strcmp(p->eleA[i]->jsId,jsId) == 0))
return p->eleA[i];
if( errorFl )
cwLogError(kInvalidIdRC,"The element with parent uuid:%i and jsId:%s is not found.",parentUuId,jsId);
return nullptr;
}
unsigned _findElementUuId( ui_t* p, const char* jsId )
{
for(unsigned i=0; i<p->eleN; ++i)
if( strcmp(p->eleA[i]->jsId,jsId) == 0 )
return p->eleA[i]->uuId;
return kInvalidId;
}
const char* _findEleJsId( ui_t* p, unsigned uuId )
@ -101,6 +194,12 @@ namespace cw
return nullptr;
}
rc_t _websockSend( ui_t* p, unsigned wsSessId, const char* msg )
{
return websock::send( websockSrv::websockHandle( p->wssH ), kUiProtocolId, wsSessId, msg, strlen(msg) );
}
// Print the attribute data value.
template< typename T0 >
unsigned format_attribute_data( char* buf, unsigned n, T0 t0 )
@ -135,69 +234,137 @@ namespace cw
}
template< typename... ARGS>
rc_t _createOneEle( ui_t* p, unsigned& uuIdRef, const char* eleTypeStr, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, ARGS&&... args )
rc_t _createOneEle( ui_t* p, unsigned& uuIdRef, const char* eleTypeStr, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, ARGS&&... args )
{
// { op:create, parent:my_parent_id, value:{ button:{ jsId:my_jsId, appId:appId, uuId:uuId, class:clas, title:'my title' } }
rc_t rc = kOkRC;
const char* parentJsId = "";
ele_t* newEle = nullptr;
ele_t* parentEle = nullptr;
const unsigned bufN = 1024;
char buf[ bufN ];
//const unsigned bufN = 1024; // TODO: use preallocated buffer
//char buf[ bufN ];
uuIdRef = kInvalidId;
if( parentUuId == kInvalidId )
parentUuId = kRootUuId;
// get the parent element
if(( parentEle = _uuIdToEle(p, parentUuId )) == nullptr )
return cwLogError( kInvalidArgRC, "Unable to locate the parent element (id:%i).", parentUuId );
// get the parent jsId
parentJsId = parentEle->jsId;
//
if( parentUuId != kInvalidId )
{
if(( parentEle = _uuIdToEle(p, parentUuId )) == nullptr )
return cwLogError( kInvalidArgRC, "Unable to locate the parent element (id:%i).", parentUuId );
parentJsId = parentEle->jsId;
}
// create the local representation of the new element
newEle = _createEle( p, parentEle, appId, jsId );
unsigned i = snprintf( buf, bufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":{ \"%s\":{ \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i, \"class\":\"%s\", \"title\":\"%s\" ", parentJsId, eleTypeStr, jsId, appId, newEle->uuId, clas, title );
// form the create json message string
unsigned i = snprintf( p->buf, p->bufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":{ \"%s\":{ \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i, \"class\":\"%s\", \"title\":\"%s\" ", parentJsId, eleTypeStr, jsId, appId, newEle->uuId, clas, title );
i = format_attributes(buf, bufN, i, std::forward<ARGS>(args)...);
// add the UI specific attributes
i += format_attributes(p->buf+i, p->bufN-i, 0, std::forward<ARGS>(args)...);
toText(buf+i, bufN-i, "}}}");
// terminate the message
i += toText(p->buf+i, p->bufN-i, "}}}");
printf("%s\n",buf);
rc = _websockSend( p, buf );
if( i >= p->bufN )
return cwLogError(kBufTooSmallRC,"The UI message formatting buffer is too small. (size:%i bytes)", p->bufN);
printf("%s\n",p->buf);
// send the message
rc = _websockSend( p, wsSessId, p->buf );
uuIdRef = newEle->uuId;
return rc;
}
rc_t _createFromObj( ui_t* p, object_t* o, unsigned parentUuId )
rc_t _decorateObj( ui_t* p, object_t* o )
{
rc_t rc = kOkRC;
object_t* pid;
rc_t rc = kOkRC;
const object_t* oo;
ele_t* parent_ele;
const char* jsId;
// BUG BUG BUG - if kInvalidId is used both to indicate a NULL valid
// and the root object then there is no way to override the parent
// that is coded into the file with the root object. A special
// rootId needs to be created.
if((pid = o->find("parent",false)) != nullptr && parentUuId == kInvalidId )
// find the parent pair
if((oo = o->find( "parent", kNoRecurseFl | kOptionalFl)) != nullptr )
{
// get the parent JS id from the cfg object
// get the parent uuid from the JS id (verify that there is no ambiguity)
// delete the 'parent' pair
}
// form the msg string
// find the parent JsId
if((rc = oo->value(jsId)) != kOkRC )
{
}
// find the parent element
//if((parent_ele = _jsIdToEle( p, jsId )) == nullptr )
//{
//}
}
rc_t _createFromObj( ui_t* p, object_t* o, unsigned wsSessId, unsigned parentUuId )
{
rc_t rc = kOkRC;
const char* parentJsId = "";
const int kBufN = 512; // TODO: preallocate this buffer as part of ui_t.
char buf0[ kBufN ];
char buf1[ kBufN ];
// if a parentUuid was given ...
if( parentUuId != kInvalidId )
{
// ... then find the associated JS id
if((parentJsId = _findEleJsId( p, parentUuId )) == nullptr )
return cwLogError(kInvalidIdRC, "The JS id associated with the uuid '%i' could not be found for an resource object.", parentUuId );
}
else // if no parentUuid was given then look for one in the resource
{
// get the parent JS id from the cfg object
rc = o->get("parent",parentJsId,kNoRecurseFl | kOptionalFl);
switch(rc)
{
case kOkRC:
// get a pointer to the jsId from the local list (the copy in the object is about to be deleted)
parentJsId = _findEleJsId( p, _findElementUuId(p,parentJsId));
//remove the parent link
o->find("parent")->parent->free();
break;
case kLabelNotFoundRC:
parentJsId = _findEleJsId( p, kRootUuId );
break;
default:
rc = cwLogError(rc,"The resource object parent id '%s' could not be found.", parentJsId );
goto errLabel;
}
}
// form the msg string from the resource
if( o->to_string( buf0, kBufN ) >= kBufN )
return cwLogError(kBufTooSmallRC,"The resource object string buffer is too small (buf bytes:%i).",kBufN);
printf("buf0: %s\n",buf0);
if( snprintf( buf1, kBufN, "{ \"op\":\"create\", \"parent\":\"%s\", \"children\":%s }", parentJsId, buf0 ) >= kBufN )
return cwLogError(kBufTooSmallRC,"The resource object string buffer is too small (buf bytes:%i).",kBufN);
// send the msg string
printf("buf1: %s\n",buf1);
rc = _websockSend( p, wsSessId, buf1 );
errLabel:
return rc;
}
@ -221,7 +388,7 @@ namespace cw
if( s == nullptr || sscanf(msg, "value %i %c ",&eleUuId,&argType) != 2 )
{
cwLogError(kSyntaxErrorRC,"Invalid message from UI: %s.", msg );
cwLogError(kSyntaxErrorRC,"Invalid message from UI: '%s'.", msg );
goto errLabel;
}
@ -277,14 +444,123 @@ namespace cw
return ele;
}
rc_t _send_app_id_msg( ui_t* p, unsigned wsSessId, ele_t* ele )
{
rc_t rc = kOkRC;
unsigned i = snprintf(p->buf,p->bufN,"{ \"op\":\"set_app_id\", \"parentUuId\":%i, \"jsId\":\"%s\", \"appId\":%i, \"uuId\":%i }", ele->parent->uuId, ele->jsId, ele->parent->appId, ele->appId );
if( i >= p->bufN )
return cwLogError(kBufTooSmallRC,"The 'app_id' msg formatting buffer is too small (%i bytes).", p->bufN);
if((rc = _websockSend( p, wsSessId, p->buf )) != kOkRC )
return cwLogError(rc,"'app_id' msg transmission failed.");
return rc;
}
ele_t* _handle_register_msg( ui_t* p, unsigned wsSessId, const char* msg )
{
printf("%s\n",msg);
return nullptr;
}
void _websockCb( void* cbArg, unsigned protocolId, unsigned connectionId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
ele_t* _handle_register_msg0( ui_t* p, unsigned wsSessId, const char* msg )
{
rc_t rc = kOkRC;
unsigned parentUuId = kInvalidId;
ele_t* parentEle = nullptr;
ele_t* ele = nullptr;
const char* s0 = nextNonWhiteChar(msg + strlen("register"));
const char* jsId = nextNonWhiteChar(nextWhiteChar(s0));
// verifity the message tokens
if( s0 == nullptr || jsId == nullptr )
{
cwLogError(kSyntaxErrorRC, "'register' msg format error: '%s' is not a valid message.", cwStringNullGuard(msg) );
goto errLabel;
}
// verify the parentUuId parsing
if((rc = string_to_number<unsigned>(s0,parentUuId)) != kOkRC )
{
cwLogError(kSyntaxErrorRC, "'register' msg parentUuId format error: '%s' does not contain a valid parentUuId.", cwStringNullGuard(msg) );
goto errLabel;
}
// get the parent ele
if((parentEle = _uuIdToEle( p, parentUuId)) == nullptr )
{
cwLogError(kInvalidIdRC,"UI register msg parent element not found.");
goto errLabel;
}
// if the child element does not already exist
if(( ele = _parentUuId_JsId_ToEle( p, parentUuId, jsId, false )) == nullptr )
{
// look up the parent/jsId pair map
appIdMapRecd_t* m = _findAppIdMap( p, parentEle->appId, jsId );
// create the ele
ele = _createEle( p, parentEle, m==nullptr ? kInvalidId : m->appId, jsId );
printf("creating: parent uuid:%i js:%s \n", parentUuId,jsId);
// notify the app of the new ele's uuid and appId
if( m != nullptr )
_send_app_id_msg( p, wsSessId, ele );
}
else
{
printf("parent uuid:%i js:%s already exists.\n", parentUuId,jsId);
}
if( ele != nullptr )
_send_app_id_msg( p, wsSessId, ele );
return ele;
errLabel:
return nullptr;
}
opId_t _labelToOpId( const char* label )
{
typedef struct
{
opId_t id;
const char* label;
} map_t;
map_t mapA[] =
{
{ kConnectOpId, "connect" },
{ kInitOpId, "init" },
{ kValueOpId, "value" },
{ kRegisterOpId, "register" },
{ kDisconnectOpId, "disconnect" },
{ kEndAppIdUpdateOpId, "end_app_id_update" },
{ kInvalidOpId, "<invalid>" },
};
for(unsigned i=0; mapA[i].id != kInvalidOpId; ++i)
if( textCompare(label,mapA[i].label,strlen(mapA[i].label)) == 0 )
return mapA[i].id;
return kInvalidOpId;
}
void _websockCb( void* cbArg, unsigned protocolId, unsigned wsSessId, websock::msgTypeId_t msg_type, const void* msg, unsigned byteN )
{
ui_t* p = (ui_t*)cbArg;
opId_t opId = kInvalidOpId;
unsigned eleUuId = kInvalidId;
unsigned eleAppId = kInvalidId;
unsigned parentEleAppId = kInvalidId;
value_t value;
switch( msg_type )
@ -301,23 +577,54 @@ namespace cw
{
ele_t* ele;
if( textCompare((const char*)msg,"init",strlen("init")) == 0 )
opId = _labelToOpId((const char*)msg);
switch( opId )
{
opId = kInitOpId;
}
else
{
opId = kValueOpId;
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
cwLogError(kOpFailRC,"UI Value message parse failed.");
else
{
eleUuId = ele->uuId;
eleAppId = ele->appId;
parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
}
}
}
case kInitOpId:
// Pass on the 'init' msg to the app.
p->cbFunc( p->cbArg, wsSessId, opId, kInvalidId, kInvalidId, kInvalidId, nullptr );
// The UI is initialized - begin the id update process
if( _websockSend( p, wsSessId, "{ \"op\":\"begin_app_id_update\" }" ) != kOkRC )
cwLogError(kOpFailRC,"'begin_app_id_update' transmit failed.");
break;
case kValueOpId:
if((ele = _parse_value_msg(p, value, (const char*)msg )) == nullptr )
cwLogError(kOpFailRC,"UI Value message parse failed.");
else
{
unsigned parentEleAppId = ele->parent == nullptr ? kInvalidId : ele->parent->appId;
p->cbFunc( p->cbArg, wsSessId, opId, parentEleAppId, ele->uuId, ele->appId, &value );
}
break;
case kRegisterOpId:
_handle_register_msg(p, wsSessId, (const char*)msg );
break;
case kEndAppIdUpdateOpId:
_print_eles( p );
cwLogInfo("App Id Update Complete.");
break;
case kInvalidOpId:
cwLogError(kInvalidIdRC,"The UI received a NULL op. id.");
break;
default:
cwLogError(kInvalidIdRC,"The UI received an unknown op. id.");
break;
} // switch opId
} // kMessageTId
break;
default:
@ -325,8 +632,8 @@ namespace cw
return;
}
if( p->cbFunc != nullptr )
p->cbFunc( p->cbArg, connectionId, opId, parentEleAppId, eleUuId, eleAppId, &value );
}
}
}
@ -340,10 +647,12 @@ cw::rc_t cw::ui::createUi(
const char* dfltPageFn,
unsigned websockTimeOutMs,
unsigned rcvBufByteN,
unsigned xmtBufByteN )
unsigned xmtBufByteN,
unsigned fmtBufByteN)
{
rc_t rc = kOkRC;
ele_t* ele;
websock::protocol_t protocolA[] =
{
{ "http", kHttpProtocolId, 0, 0 },
@ -355,6 +664,9 @@ cw::rc_t cw::ui::createUi(
if((rc = destroyUi(h)) != kOkRC )
return rc;
if( cbFunc == nullptr )
return cwLogError(kInvalidArgRC,"The UI callback function must be a valid pointer.");
ui_t* p = mem::allocZ<ui_t>();
if((rc = websockSrv::create(p->wssH, _websockCb, p, physRootDir, dfltPageFn, port, protocolA, protocolN, websockTimeOutMs )) != kOkRC )
@ -368,6 +680,15 @@ cw::rc_t cw::ui::createUi(
p->eleN = 0;
p->cbFunc = cbFunc;
p->cbArg = cbArg;
p->buf = mem::allocZ<char>(fmtBufByteN);
p->bufN = fmtBufByteN;
// create the root element
if((ele = _createEle(p, nullptr, kRootEleAppId, "uiDivId" )) == nullptr || ele->uuId != kRootUuId )
{
cwLogError(kOpFailRC,"The UI root element creation failed.");
goto errLabel;
}
h.set(p);
@ -430,11 +751,12 @@ unsigned cw::ui::findElementAppId( handle_t h, unsigned parentUuId, const char*
unsigned cw::ui::findElementUuId( handle_t h, unsigned parentUuId, const char* jsId )
{
ui_t* p = _handleToPtr(h);
ui_t* p = _handleToPtr(h);
ele_t* ele;
if((ele = _parentUuId_JsId_ToEle(p, parentUuId, jsId )) != nullptr )
return ele->uuId;
for(unsigned i=0; i<p->eleN; ++i)
if( p->eleA[i]->parent->uuId==parentUuId && strcmp(p->eleA[i]->jsId,jsId) == 0 )
return p->eleA[i]->uuId;
return kInvalidId;
}
@ -454,8 +776,15 @@ const char* cw::ui::findElementJsId( handle_t h, unsigned uuId )
return _findEleJsId(p,uuId);
}
unsigned cw::ui::findElementUuId( handle_t h, const char* jsId )
{
ui_t* p = _handleToPtr(h);
return _findElementUuId(p,jsId);
}
cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parentUuId)
cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId)
{
ui_t* p = _handleToPtr(h);
rc_t rc = kOkRC;
@ -463,13 +792,15 @@ cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parent
if((rc = objectFromFile( fn, o )) != kOkRC )
goto errLabel;
if((rc = _createFromObj( p, o, parentUuId )) != kOkRC )
//o->print();
if((rc = _createFromObj( p, o, wsSessId, parentUuId )) != kOkRC )
goto errLabel;
errLabel:
if(rc != kOkRC )
rc = cwLogError(rc,"UI from configuration the file '%s' failed.", cwStringNullGuard(fn));
rc = cwLogError(rc,"UI instantiation from the configuration file '%s' failed.", cwStringNullGuard(fn));
if( o != nullptr )
o->free();
@ -477,7 +808,7 @@ cw::rc_t cw::ui::createFromFile( handle_t h, const char* fn, unsigned parent
return rc;
}
cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentUuId)
cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned wsSessId, unsigned parentUuId)
{
ui_t* p = _handleToPtr(h);
rc_t rc = kOkRC;
@ -486,12 +817,12 @@ cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentU
if((rc = objectFromString( text, o )) != kOkRC )
goto errLabel;
if((rc = _createFromObj( p, o, parentUuId )) != kOkRC )
if((rc = _createFromObj( p, o, wsSessId, parentUuId )) != kOkRC )
goto errLabel;
errLabel:
if(rc != kOkRC )
rc = cwLogError(rc,"UI from configuration the string '%s' failed.", cwStringNullGuard(text));
rc = cwLogError(rc,"UI instantiation failed from the configuration from string: '%s'.", cwStringNullGuard(text));
if( o != nullptr )
o->free();
@ -499,34 +830,34 @@ cw::rc_t cw::ui::createFromText( handle_t h, const char* text, unsigned parentU
return rc;
}
cw::rc_t cw::ui::createDiv( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "div", parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createDiv( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "div", wsSessId, parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createTitle( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createTitle( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", wsSessId, parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createButton( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "button", parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createButton( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "button", wsSessId, parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createCheck( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "check", parentUuId, jsId, appId, clas, title, "value", value ); }
cw::rc_t cw::ui::createCheck( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "check", wsSessId, parentUuId, jsId, appId, clas, title, "value", value ); }
cw::rc_t cw::ui::createSelect( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "select", parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createSelect( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "select", wsSessId, parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createOption( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createOption( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "option", wsSessId, parentUuId, jsId, appId, clas, title ); }
cw::rc_t cw::ui::createString( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "string", parentUuId, jsId, appId, clas, title, "value", value ); }
cw::rc_t cw::ui::createString( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "string", wsSessId, parentUuId, jsId, appId, clas, title, "value", value ); }
cw::rc_t cw::ui::createNumber( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decpl )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "number", parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue, "step", stepValue, "decpl", decpl ); }
cw::rc_t cw::ui::createNumber( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decpl )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "number", wsSessId, parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue, "step", stepValue, "decpl", decpl ); }
cw::rc_t cw::ui::createProgress( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "progress", parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue ); }
cw::rc_t cw::ui::createProgress( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue )
{ return _createOneEle( _handleToPtr(h), uuIdRef, "progress", wsSessId, parentUuId, jsId, appId, clas, title, "value", value, "min", minValue, "max", maxValue ); }
cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title )
{
rc_t rc= kOkRC;
return rc;
@ -534,4 +865,19 @@ cw::rc_t cw::ui::createText( handle_t h, unsigned& uuIdRef, unsigned parentUuI
cw::rc_t cw::ui::registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN )
{
ui_t* p = _handleToPtr(h);
rc_t rc = kOkRC;
for(unsigned i=0; i<mapN; ++i)
if((rc = _allocAppIdMap( p, map[i].parentAppId, map[i].appId, map[i].jsId )) != kOkRC )
return rc;
return rc;
}

55
cwUi.h
View File

@ -21,6 +21,8 @@ namespace cw
kConnectOpId,
kInitOpId,
kValueOpId,
kRegisterOpId,
kEndAppIdUpdateOpId,
kDisconnectOpId
} opId_t;
@ -35,6 +37,13 @@ namespace cw
kStringTId
} dtypeId_t;
enum
{
kRootUuId = 0,
kRootEleAppId,
};
typedef struct
{
dtypeId_t tid;
@ -49,7 +58,7 @@ namespace cw
} u;
} value_t;
typedef rc_t (*uiCallback_t)( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* value );
typedef rc_t (*uiCallback_t)( void* cbArg, unsigned websockSessionId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* value );
rc_t createUi( handle_t& h,
unsigned port,
@ -59,30 +68,44 @@ namespace cw
const char* dfltPageFn = "index.html",
unsigned websockTimeOutMs = 50,
unsigned rcvBufByteN = 1024,
unsigned xmtBufByteN = 1024);
unsigned xmtBufByteN = 1024,
unsigned fmtBufByteN = 4096 );
rc_t destroyUi( handle_t& h );
rc_t start( handle_t h );
rc_t stop( handle_t h );
unsigned findElementAppId( handle_t h, unsigned parentUuId, const char* jsId );
unsigned findElementAppId( handle_t h, unsigned parentUuId, const char* jsId );
unsigned findElementUuId( handle_t h, unsigned parentUuId, const char* jsId );
unsigned findElementUuId( handle_t h, unsigned parentUuId, unsigned appId );
const char* findElementJsId( handle_t h, unsigned uuId );
const char* findElementJsId( handle_t h, unsigned uuId );
// Return the uuid of the first matching 'jsId'.
unsigned findElementUuId( handle_t h, const char* jsId );
rc_t createFromFile( handle_t h, const char* fn, unsigned parentUuId=kInvalidId);
rc_t createFromText( handle_t h, const char* text, unsigned parentUuId=kInvalidId);
rc_t createDiv( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createTitle( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createButton( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createCheck( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value );
rc_t createSelect( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createOption( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createString( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value );
rc_t createNumber( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decPl );
rc_t createProgress( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue );
rc_t createText( handle_t h, unsigned& uuIdRef, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createFromFile( handle_t h, const char* fn, unsigned wsSessId, unsigned parentUuId=kInvalidId);
rc_t createFromText( handle_t h, const char* text, unsigned wsSessId, unsigned parentUuId=kInvalidId);
rc_t createDiv( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createTitle( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createButton( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createCheck( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, bool value );
rc_t createSelect( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createOption( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
rc_t createString( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, const char* value );
rc_t createNumber( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue, double stepValue, unsigned decPl );
rc_t createProgress( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title, double value, double minValue, double maxValue );
rc_t createText( handle_t h, unsigned& uuIdRef, unsigned wsSessId, unsigned parentUuId, const char* jsId, unsigned appId, const char* clas, const char* title );
typedef struct appIdMap_str
{
unsigned parentAppId;
unsigned appId;
const char* jsId;
} appIdMap_t;
// Register parent/child/js app id's
rc_t registerAppIds( handle_t h, const appIdMap_t* map, unsigned mapN );
}
}

View File

@ -12,7 +12,8 @@ namespace cw
{
typedef struct ui_test_str
{
handle_t uiH;
handle_t uiH;
const char* uiCfgFn;
} ui_test_t;
enum
@ -30,49 +31,51 @@ namespace cw
kProgressId
};
rc_t _uiTestCreateUi( ui_test_t* p, unsigned connId )
rc_t _uiTestCreateUi( ui_test_t* p, unsigned wsSessId )
{
rc_t rc = kOkRC;
unsigned uuid = kInvalidId;
unsigned selUuId = kInvalidId;
unsigned divUuId = kInvalidId;
if((rc = createDiv( p->uiH, divUuId, kInvalidId, "myDivId", kDivId, "divClass", "My Panel" )) != kOkRC )
if((rc = createDiv( p->uiH, divUuId, wsSessId, kInvalidId, "myDivId", kDivId, "divClass", "My Panel" )) != kOkRC )
goto errLabel;
if((rc = createButton( p->uiH, uuid, divUuId, "myBtnId", kBtnId, "btnClass", "Push Me" )) != kOkRC )
if((rc = createButton( p->uiH, uuid, wsSessId, divUuId, "myBtnId", kBtnId, "btnClass", "Push Me" )) != kOkRC )
goto errLabel;
if((rc = createCheck( p->uiH, uuid, divUuId, "myCheckId", kCheckId, "checkClass", "Check Me", true )) != kOkRC )
if((rc = createCheck( p->uiH, uuid, wsSessId, divUuId, "myCheckId", kCheckId, "checkClass", "Check Me", true )) != kOkRC )
goto errLabel;
if((rc = createSelect( p->uiH, selUuId, divUuId, "mySelId", kSelectId, "selClass", "Select" )) != kOkRC )
if((rc = createSelect( p->uiH, selUuId, wsSessId, divUuId, "mySelId", kSelectId, "selClass", "Select" )) != kOkRC )
goto errLabel;
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt0Id", kOption0Id, "optClass", "Option 0" )) != kOkRC )
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt0Id", kOption0Id, "optClass", "Option 0" )) != kOkRC )
goto errLabel;
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt1Id", kOption1Id, "optClass", "Option 1" )) != kOkRC )
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt1Id", kOption1Id, "optClass", "Option 1" )) != kOkRC )
goto errLabel;
if((rc = createOption( p->uiH, uuid, selUuId, "myOpt2Id", kOption2Id, "optClass", "Option 2" )) != kOkRC )
if((rc = createOption( p->uiH, uuid, wsSessId, selUuId, "myOpt2Id", kOption2Id, "optClass", "Option 2" )) != kOkRC )
goto errLabel;
if((rc = createString( p->uiH, uuid, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
if((rc = createString( p->uiH, uuid, wsSessId, divUuId, "myStringId", kStringId, "stringClass", "String", "a string value" )) != kOkRC )
goto errLabel;
if((rc = createNumber( p->uiH, uuid, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC )
if((rc = createNumber( p->uiH, uuid, wsSessId, divUuId, "myNumberId", kNumberId, "numberClass", "Number", 10, 0, 100, 1, 0 )) != kOkRC )
goto errLabel;
if((rc = createProgress( p->uiH, uuid, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
if((rc = createProgress( p->uiH, uuid, wsSessId, divUuId, "myProgressId", kProgressId, "progressClass", "Progress", 5, 0, 10 )) != kOkRC )
goto errLabel;
if((rc = createFromFile( p->uiH, p->uiCfgFn, wsSessId )) != kOkRC )
goto errLabel;
errLabel:
return rc;
}
rc_t _handleUiValueMsg( ui_test_t* p, unsigned connId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
rc_t _handleUiValueMsg( ui_test_t* p, unsigned wsSessId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
{
rc_t rc = kOkRC;
@ -103,28 +106,33 @@ namespace cw
return rc;
}
rc_t _uiTestCallback( void* cbArg, unsigned connId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
// This function is called by the websocket with messages comring from a remote UI.
rc_t _uiTestCallback( void* cbArg, unsigned wsSessId, opId_t opId, unsigned parentAppId, unsigned uuId, unsigned appId, const value_t* v )
{
ui_test_t* p = (ui_test_t*)cbArg;
switch( opId )
{
case kConnectOpId:
cwLogInfo("Connect: connId:%i.",connId);
cwLogInfo("Connect: wsSessId:%i.",wsSessId);
break;
case kDisconnectOpId:
cwLogInfo("Disconnect: connId:%i.",connId);
cwLogInfo("Disconnect: wsSessId:%i.",wsSessId);
break;
case kInitOpId:
_uiTestCreateUi(p,connId);
_uiTestCreateUi(p,wsSessId);
break;
case kRegisterOpId:
break;
case kValueOpId:
_handleUiValueMsg( p, connId, parentAppId, uuId, appId, v );
_handleUiValueMsg( p, wsSessId, parentAppId, uuId, appId, v );
break;
case kInvalidOpId:
@ -141,7 +149,7 @@ namespace cw
cw::rc_t cw::ui::test( )
{
rc_t rc = kOkRC;
const char* physRootDir = "/home/kevin/src/cw_rt/html/uiTest";
const char* physRootDir = "/home/kevin/src/cwtest/src/libcw/html/uiTest";
const char* dfltPageFn = "index.html";
int port = 5687;
unsigned rcvBufByteN = 2048;
@ -150,6 +158,8 @@ cw::rc_t cw::ui::test( )
const unsigned sbufN = 31;
char sbuf[ sbufN+1 ];
ui_test_t* ui = mem::allocZ<ui_test_t>();
ui->uiCfgFn = "/home/kevin/src/cwtest/src/libcw/html/uiTest/ui.cfg";
if((rc = createUi(ui->uiH, port, _uiTestCallback, ui, physRootDir, dfltPageFn, websockTimeOutMs, rcvBufByteN, xmtBufByteN )) != kOkRC )
return rc;

View File

@ -1,5 +1,6 @@
var _ws = null;
var _dfltParentId = "uiDivId";
var _rootJsId = "uiDivId";
var _nextEleId = 0;
function set_app_title( suffix, className )
{
@ -164,8 +165,6 @@ function uiNumberSet( r )
}
function dom_id_to_ele( id )
{ return document.getElementById(id); }
function dom_child_by_id( parentEle, child_id )
{
@ -194,11 +193,6 @@ function dom_set_option_by_text( ele_id, text )
}
}
function dom_set_checkbox( ele_id, fl )
{ dom_id_to_ele(ele_id).checked = fl }
function dom_get_checkbox( ele_id )
{ return dom_id_to_ele(ele_id).checked }
function dom_set_number( ele_id, val )
@ -206,14 +200,53 @@ function dom_set_number( ele_id, val )
dom_id_to_ele(ele_id).value = val
}
//==============================================================================
function dom_id_to_ele( id )
{ return document.getElementById(id); }
function dom_set_checkbox( ele_id, fl )
{ dom_id_to_ele(ele_id).checked = fl }
function dom_get_checkbox( ele_id )
{ return dom_id_to_ele(ele_id).checked }
function dom_create_ele( ele_type )
{
ele = document.createElement(ele_type);
ele.id = _nextEleId;
_nextEleId += 1;
}
//==============================================================================
function ui_error( msg )
{
console.log("Error: " + msg )
}
function ui_send_value( ele, typeId, value )
{
if( ele.hasOwnProperty('uuId') )
ws_send("value " + ele.uuId + " " + typeId + " : " + value)
else
ui_error("A value msg send failed because the value had no UuId.");
}
function ui_send_bool_value( ele, value ) { ui_send_value(ele,'b',value); }
function ui_send_int_value( ele, value ) { ui_send_value(ele,'i',value); }
function ui_send_string_value( ele, value ) { ui_send_value(ele,'s',value); }
function ui_send_register( ele )
{
ws_send("register " + ele.parentJsId + " " + ele.jsId + " " + ele.id + " " + ele.uuId + " " + ele.appId )
}
function ui_print_children( eleId )
{
var childrenL = document.getElementById(eleId).children
var childrenL = dom_id_to_ele(eleId).children
for(var i=0; i<childrenL.length; i++)
{
@ -224,9 +257,9 @@ function ui_print_children( eleId )
function ui_get_parent( parentId )
{
if( parentId==null || parentId.trim().length == 0 )
parentId = _dfltParentId
parentId = _rootJsId
parent_ele = document.getElementById(parentId);
parent_ele = dom_id_to_ele(parentId);
if( parent_ele == null )
{
@ -240,16 +273,26 @@ function ui_get_parent( parentId )
function ui_create_ele( parent_ele, ele_type, d )
{
// create the ctl object
var ele = document.createElement(ele_type);
var ele = dom_create_ele(ele_type);
if( ele == null )
ui_error("'%s' element create failed.", ele_type);
else
{
ele.id = d.jsId;
ele.uuId = d.uuId;
ele.appId = d.appId;
ele.jsId = d.jsId;
ele.parentJsId = d.parentJsId;
ele.uuId = d.hasOwnProperty("uuId") ? d.uuId : null
ele.appId = d.hasOwnProperty("appId") ? d.appId : null
console.log("Created: " + ele_type + " parent:" + d.parentJsId + " id:" + ele.id + " appId:" + ele.appId + " uuId:" + ele.uuId)
parent_ele.appendChild(ele);
ui_send_register( ele );
}
return ele
}
@ -257,7 +300,7 @@ function ui_create_ele( parent_ele, ele_type, d )
function ui_create_ctl( parent_ele, ele_type, label, d )
{
// create an enclosing div
var div_ele = document.createElement("div");
var div_ele = dom_create_ele("div");
div_ele.className = d.clas;
@ -268,7 +311,7 @@ function ui_create_ctl( parent_ele, ele_type, label, d )
// if label is not null then create an enclosing 'label' element
if( label != null )
{
label_ele = document.createElement("label");
label_ele = dom_create_ele("label");
label_ele.innerHTML = label;
@ -283,12 +326,11 @@ function ui_create_div( parent_ele, d )
{
var div_ele = ui_create_ele( parent_ele, "div", d );
if( div_ele != null )
{
div_ele.className = d.clas
var p_ele = document.createElement("p")
var p_ele = dom_create_ele("p")
if( d.title != null && d.title.length > 0 )
p_ele.innerHTML = d.title
@ -296,7 +338,7 @@ function ui_create_div( parent_ele, d )
div_ele.appendChild( p_ele )
}
return div_ele
return div_ele;
}
function ui_create_title( parent_ele, d )
@ -311,10 +353,10 @@ function ui_create_button( parent_ele, d )
if( ele != null )
{
ele.innerHTML = d.title;
ele.onclick = function() { _ws.send("value " + this.uuId + " i : 1"); }
ele.onclick = function() { ui_send_int_value(this,1); }
}
return ele
return ele;
}
function ui_create_check( parent_ele, d )
@ -327,15 +369,14 @@ function ui_create_check( parent_ele, d )
dom_set_checkbox(ele.id, d.value );
ele.onclick = function() { _ws.send("value" + this.uuId + " b : " + dom_get_checkbox(this.id)); }
ele.onclick = function() { ui_send_bool_value(this,dom_get_checkbox(this.id)); }
}
return ele;
}
function ui_on_select( ele )
{
var s = "value " + ele.uuId + " i : " + ele.options[ ele.selectedIndex ].appId
_ws.send( s );
ui_send_int_value(ele,ele.options[ ele.selectedIndex ].appId);
}
function ui_create_select( parent_ele, d )
@ -365,7 +406,7 @@ function ui_create_string( parent_ele, d )
if( ele != null )
{
ele.value = d.value;
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ _ws.send("value" + this.uuId + " s : " + this.value + "\0");} } );
ele.addEventListener('keyup', function(e) { if(e.keyCode===13){ ui_send_string_value(this, this.value); }} );
}
}
@ -377,7 +418,9 @@ function ui_number_keyup( e )
var ele = dom_id_to_ele(e.target.id)
console.log(ele.value)
if( ele != null )
_ws.send("value" + ele.uuId + " i : " + ele.value);
{
ui_send_int_value(ele,ele.value);
}
}
}
@ -394,7 +437,7 @@ function ui_create_number( parent_ele, d )
ele.decpl = d.decpl;
ele.addEventListener('keyup', ui_number_keyup );
}
return ele;
}
function ui_set_progress( ele_id, value )
@ -415,70 +458,130 @@ function ui_create_progress( parent_ele, d )
ele.minValue = d.min;
ui_set_progress( ele.id, d.value );
}
return ele
}
function ui_create( parentId, ele_type, d )
{
var parent_ele = ui_get_parent(parentId);
var ele = null;
if( parent_ele != null )
{
d.parentJsId = parentId
switch( ele_type )
{
case "div":
ui_create_div( parent_ele, d )
ele = ui_create_div( parent_ele, d )
break;
case "title":
ui_create_title( parent_ele, d )
ele = ui_create_title( parent_ele, d )
break;
case "button":
ui_create_button( parent_ele, d )
ele = ui_create_button( parent_ele, d )
break;
case "check":
ui_create_check( parent_ele, d )
ele = ui_create_check( parent_ele, d )
break;
case "select":
ui_create_select( parent_ele, d );
ele = ui_create_select( parent_ele, d );
break;
case "option":
ui_create_option( parent_ele, d );
ele = ui_create_option( parent_ele, d );
break;
case "string":
ui_create_string( parent_ele, d );
ele = ui_create_string( parent_ele, d );
break;
case "number":
ui_create_number( parent_ele, d );
ele = ui_create_number( parent_ele, d );
break;
case "progress":
ui_create_progress( parent_ele, d );
ele = ui_create_progress( parent_ele, d );
break;
default:
ui_error("Unknown UI element type: " + ele_type )
}
if( d.hasOwnProperty("children") )
{
for (const ele_type in d.children)
ui_create( d.jsId, ele_type, d.children[ele_type] )
}
}
}
function ws_send( d )
function ui_uuid_to_ele( uuId, ele=null )
{
if( ele == null )
ele = dom_id_to_ele( _rootJsId )
if( ele.hasOwnProperty('uuId') )
{
if( ele.uuId == uuId )
return ele
for(var i=0; i<ele.childElementCount; ++i)
ui_uuid_to_ele( uuId, ele.children[i] )
}
ui_error("The element with uuid: " + uuId + " was not found.")
return null
}
// Do breadth first search for ele's without uuId's
function ui_next_ele_to_register( parentEle )
{
for(var i=0; i<parentEle.childElementCount; ++i)
{
var ele = parentEle.children[i]
if( ele.hasOwnProperty('uuId') && ele.uuId==null)
return ele
}
for(var i=0; i<parentEle.childElementCount; ++i)
{
var ele = ui_next_ele_to_register( parentEle.children[i])
if( ele != null )
return ele
}
return null
}
//
function ui_set_app_uuId( d )
{
console.log(d)
}
function ws_send( s )
{
s = JSON.stringify(d)
//console.log(s)
_ws.send(s)
_ws.send(s+"\0")
}
function ws_on_msg( jsonMsg )
{
//console.log(jsonMsg)
console.log(jsonMsg)
d = JSON.parse(jsonMsg.data);
switch( d.op )
@ -486,12 +589,18 @@ function ws_on_msg( jsonMsg )
case 'create':
for (const ele_type in d.children)
{
ui_create( d.parent, ele_type, d.value[ele_type] )
ui_create( d.parent, ele_type, d.children[ele_type] )
//console.log(`${ele_type}: ${d.value[ele_type]}`);
}
}
break;
case 'set_app_id':
ui_set_app_uuId(d)
break;
default:
ui_error("Unknown UI operation. " + d.op )
}
}
@ -507,12 +616,35 @@ function ws_on_close()
set_app_title( "Disconnected", "title_disconnected" );
}
function ws_form_url(urlSuffix)
{
var pcol;
var u = document.URL;
pcol = "ws://";
if (u.substring(0, 4) === "http")
u = u.substr(7);
u = u.split("/");
return pcol + u[0] + "/" + urlSuffix;
}
function main()
{
_ws = new WebSocket("ws://127.0.0.1:5687/","ui_protocol")
rootEle = dom_id_to_ele(_rootJsId);
rootEle.uuId = 0;
rootEle.id = _nextEleId;
_nextEleId += 1;
console.log(ws_form_url(""))
_ws = new WebSocket(ws_form_url(""),"ui_protocol")
_ws.onmessage = ws_on_msg
_ws.onopen = ws_on_open
_ws.onclose = ws_on_close;
_ws.onclose = ws_on_close;
}

View File

@ -1,13 +1,18 @@
{
parent: "uiDivId"
div: {
title:"My panel",
jsId: "panelDivId",
class: "myPanelClass",
title: "My resource based panel",
children: {
button:{ id:myBtnId, title:"Push Me" },
check:{ id:myCheckId, title:"Check Me" },
button:{ jsId: myBtn1Id, title:"Push Me" },
check:{ jsId: myCheck1Id, title:"Check Me" },
}
}