diff --git a/keywords.txt b/keywords.txt index 6492e7a..a181bde 100644 --- a/keywords.txt +++ b/keywords.txt @@ -18,6 +18,7 @@ AutoConnectText KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### add KEYWORD2 +aux KEYWORD2 config KEYWORD2 begin KEYWORD2 del KEYWORD2 @@ -38,6 +39,8 @@ onDetect KEYWORD2 onNotFound KEYWORD2 release KEYWORD2 save KEYWORD2 +saveElement KEYWORD2 +setElementValue KEYWORD2 setTitle KEYWORD2 toHTML KEYWORD2 value KEYWORD2 diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index 6a06ca3..b1aacc9 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -280,6 +280,21 @@ WebServerClass& AutoConnect::host() { return *_webServer; } +/** + * Returns AutoConnectAux instance of specified. + * @param uri An uri string. + * @return A pointer of AutoConnectAux instance. + */ +AutoConnectAux* AutoConnect::aux(const char* uri) const { + AutoConnectAux* aux_p = _aux.get(); + while (aux_p) { + if (!strcmp(aux_p->uri(), uri)) + break; + aux_p = aux_p->_next.get(); + } + return aux_p; +} + /** * Append auxiliary pages made up with AutoConnectAux. * @param aux A reference to AutoConnectAux that made up diff --git a/src/AutoConnect.h b/src/AutoConnect.h index fca34c8..620b48a 100644 --- a/src/AutoConnect.h +++ b/src/AutoConnect.h @@ -154,6 +154,7 @@ class AutoConnect { AutoConnect(); AutoConnect(WebServerClass& webServer); ~AutoConnect(); + AutoConnectAux* aux(const char* uri) const; bool config(AutoConnectConfig& Config); bool config(const char* ap, const char* password = nullptr); void home(String uri); diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp index f35d3bb..e4a4e0d 100644 --- a/src/AutoConnectAux.cpp +++ b/src/AutoConnectAux.cpp @@ -95,7 +95,7 @@ void AutoConnectAux::add(AutoConnectElementVT addons) { */ AutoConnectElement* AutoConnectAux::getElement(const String name) { for (std::size_t n = 0; n < _addonElm.size(); n++) - if (_addonElm[n].get().name == name) + if (name.equalsIgnoreCase(_addonElm[n].get().name)) return &(_addonElm[n].get()); AC_DBG("Element<%s> not registered\n", name.c_str()); return nullptr; @@ -113,7 +113,7 @@ bool AutoConnectAux::release(const String name) { bool rc = false; for (std::size_t n = 0; n < _addonElm.size(); n++) { String elmName = _addonElm[n].get().name; - if (elmName == name) { + if (name.equalsIgnoreCase(elmName)) { AC_DBG("%s release from %s\n", elmName.c_str(), uri()); _addonElm.erase(_addonElm.begin() + n); rc = true; @@ -140,8 +140,6 @@ bool AutoConnectAux::setElementValue(const String name, const String value) { else AC_DBG("Element<%s> value type mismatch\n", name.c_str()); } - else - AC_DBG("Element<%s> not registered\n", name.c_str()); return false; } @@ -181,9 +179,6 @@ bool AutoConnectAux::setElementValue(const String name, std::vector valu } } } - else - AC_DBG("Element<%s> not registered\n", name.c_str()); - return rc; } @@ -624,8 +619,8 @@ bool AutoConnect::load(Stream& aux, size_t bufferSize) { * @return true Successfully loaded. */ bool AutoConnect::_load(JsonVariant& aux) { - bool rc = true; - if (aux.success()) { + bool rc = aux.success(); + if (rc) { if (aux.is()) { JsonArray& jb = aux.as(); for (JsonObject& auxJson : jb) { @@ -650,8 +645,10 @@ bool AutoConnect::_load(JsonVariant& aux) { } } } - else - return rc; + else { + AC_DBG("JSON parse error\n"); + } + return rc; } /** @@ -820,7 +817,7 @@ AutoConnectElement& AutoConnectAux::_loadElement(JsonObject& jb, const String na continue; } } - if (auxElm->loadElement(element)) + if (auxElm->loadMember(element)) AC_DBG("%s<%d> of %s loaded\n", auxElm->name.c_str(), (int)auxElm->typeOf(), uri()); else { // Element type mismatch @@ -833,30 +830,53 @@ AutoConnectElement& AutoConnectAux::_loadElement(JsonObject& jb, const String na } /** - * Serialize a element to JSON and write it to the stream. + * Serialize whole elements owned by an AutoConnectAux into the stream. * @param out An output stream - * @return Number of byte output + * @return Number of bytes output */ size_t AutoConnectAux::save(Stream& out) { + size_t bs = 0; size_t e = _addonElm.size(); - if (e <= 0) - return e; - DynamicJsonBuffer auxBuffer(3 + JSON_ARRAY_SIZE(e) + JSON_OBJECT_SIZE(5) * e); - JsonObject& json = auxBuffer.createObject(); + for (size_t n = 0; n < e; e++) { + AutoConnectElement& elm = _addonElm[n]; + bs += elm.getObjectSize(); + } + if (bs <= 0) + return 0; + + DynamicJsonBuffer jb(bs + JSON_OBJECT_SIZE(4)+ JSON_ARRAY_SIZE(1)); + JsonObject& json = jb.createObject(); json[F(AUTOCONNECT_JSON_KEY_TITLE)] = _title; json[F(AUTOCONNECT_JSON_KEY_URI)] = _uriStr; json[F(AUTOCONNECT_JSON_KEY_MENU)] = _menu; JsonArray& elements = json.createNestedArray(F(AUTOCONNECT_JSON_KEY_ELEMENT)); - for (size_t i = 0; i < e; i++) { + for (std::size_t n = 0; n < e; n++) { JsonObject& element = elements.createNestedObject(); - AutoConnectElement& elm = _addonElm[i]; + AutoConnectElement& elm = _addonElm[n]; elm.serialize(element); } - return static_cast(json.prettyPrintTo(out)); } +/** + * Serialize an element specified the name into the stream. + * @param name An element name to be output. + * @return Number of bytes output + */ +size_t AutoConnectAux::saveElement(const String name, Stream& out) { + for (std::size_t n = 0; n < _addonElm.size(); n++) { + AutoConnectElement& elm = _addonElm[n]; + if (elm.name == name) { + DynamicJsonBuffer jb(elm.getObjectSize()); + JsonObject& element = jb.createObject(); + elm.serialize(element); + return static_cast(element.prettyPrintTo(out)); + } + } + return 0; +} + /** * Convert element type from type as String. * @param type An element type as String diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h index 295da87..3b0800c 100644 --- a/src/AutoConnectAux.h +++ b/src/AutoConnectAux.h @@ -40,12 +40,12 @@ typedef enum { } AutoConnectExitOrder_t; /** - * A class that handles an auxiliary page with AutoConnectElement - * that placed on it by binding it to the AutoConnect menu. - * @param uri An uri string of this page. - * @param title A title string of this page. - * @param addons A set of AutoConnectElement vector. - * @param menu A switch for item displaying in AutoConnect menu. + * A class that handles an auxiliary page with AutoConnectElement + * that placed on it by binding it to the AutoConnect menu. + * @param uri An uri string of this page. + * @param title A title string of this page. + * @param addons A set of AutoConnectElement vector. + * @param menu A switch for item displaying in AutoConnect menu. */ class AutoConnectAux : public PageBuilder { public: @@ -61,6 +61,7 @@ class AutoConnectAux : public PageBuilder { void menu(const bool post) { _menu = post; } /**< Set or reset the display as menu item for this aux. */ bool release(const char* name) { return release(String(name)); } /**< Release an AutoConnectElement */ bool release(const String name); /**< Release an AutoConnectElement */ + AutoConnectElement& setElement(AutoConnectElement& element); /**< Set or replace the element */ bool setElementValue(const char* name, const String value) { return setElementValue(String(name), value); } bool setElementValue(const String name, const String value); bool setElementValue(const char* name, std::vector values) { return setElementValue(String(name), values); } @@ -76,7 +77,9 @@ class AutoConnectAux : public PageBuilder { AutoConnectElement& loadElement(const String in, const String name = "*"); /**< Load specified element */ AutoConnectElement& loadElement(const __FlashStringHelper* in, const String name = "*"); /**< Load specified element */ AutoConnectElement& loadElement(Stream& in, const String name = "*", const size_t bufferSize = AUTOCONNECT_JSON_BUFFER_SIZE); /**< Load specified element */ - size_t save(Stream& out); /**< Save specified element */ + size_t save(Stream& out); /**< Write AutoConnectAux elements to the stream */ + size_t saveElement(const char* name, Stream& out) { return saveElement(String(name), out); } /**< Write an element of AutoConnectAux to the stream */ + size_t saveElement(const String name, Stream& out); /**< Write an element of AutoConnectAux to the stream */ #endif // !AUTOCONNECT_USE_JSON protected: diff --git a/src/AutoConnectElementJson.h b/src/AutoConnectElementJson.h index b4fea4e..0f9b9c5 100644 --- a/src/AutoConnectElementJson.h +++ b/src/AutoConnectElementJson.h @@ -51,11 +51,12 @@ class AutoConnectElementJson : virtual public AutoConnectElementBasis { AutoConnectElementBasis::value = value; } ~AutoConnectElementJson() {} - virtual bool loadElement(const JsonObject& json); + virtual const size_t getObjectSize(void) const; + virtual bool loadMember(const JsonObject& json); virtual void serialize(JsonObject& json); protected: - void _setElement(const JsonObject& json); + void _setMember(const JsonObject& json); void _serialize(JsonObject& json); }; @@ -68,14 +69,15 @@ class AutoConnectElementJson : virtual public AutoConnectElementBasis { * @param action Script code to execute with the button pushed. */ class AutoConnectButtonJson : public AutoConnectElementJson, public AutoConnectButtonBasis { - public: +public: explicit AutoConnectButtonJson(const char* name = "", const char* value = "", const String action = String()) { AutoConnectButtonBasis::name = name; AutoConnectButtonBasis::value = value; AutoConnectButtonBasis::action = action; } ~AutoConnectButtonJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -97,7 +99,8 @@ class AutoConnectCheckboxJson : public AutoConnectElementJson, public AutoConnec AutoConnectCheckboxBasis::checked = checked; } ~AutoConnectCheckboxJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -119,7 +122,8 @@ class AutoConnectInputJson : public AutoConnectElementJson, public AutoConnectIn AutoConnectInputBasis::label = label; } ~AutoConnectInputJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -141,7 +145,8 @@ class AutoConnectRadioJson : public AutoConnectElementJson, public AutoConnectRa AutoConnectRadioBasis::checked = checked; } ~AutoConnectRadioJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -161,7 +166,8 @@ class AutoConnectSelectJson : public AutoConnectElementJson, public AutoConnectS AutoConnectSelectBasis::label = label; } ~AutoConnectSelectJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -182,7 +188,8 @@ class AutoConnectSubmitJson : public AutoConnectElementJson, public AutoConnectS AutoConnectSubmitBasis::uri = uri; } ~AutoConnectSubmitJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; @@ -203,7 +210,8 @@ class AutoConnectTextJson : public AutoConnectElementJson, public AutoConnectTex AutoConnectTextBasis::style = style; } ~AutoConnectTextJson() {} - bool loadElement(const JsonObject& json) override; + const size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; void serialize(JsonObject& json) override; }; diff --git a/src/AutoConnectElementJsonImpl.h b/src/AutoConnectElementJsonImpl.h index 66e2913..7824441 100644 --- a/src/AutoConnectElementJsonImpl.h +++ b/src/AutoConnectElementJsonImpl.h @@ -13,21 +13,11 @@ #include "AutoConnectElementJson.h" /** - * Set items common to any type of AutoConnectElement from JSON objects. - * @param json JSON object with the definition of AutoConnectElement. - */ -void AutoConnectElementJson::_setElement(const JsonObject& json) { - name = json.get(F(AUTOCONNECT_JSON_KEY_NAME)); - value = json.get(F(AUTOCONNECT_JSON_KEY_VALUE)); -} - -/** - * Serialize AutoConnectElement to JSON. - * This function is base for each element. - * @param json JSON object to be serialized. + * Returns JSON object size. + * @return An object size for JsonBuffer. */ -void AutoConnectElementJson::_serialize(JsonObject& json) { - json.set(F(AUTOCONNECT_JSON_KEY_NAME), name); +const size_t AutoConnectElementJson::getObjectSize() const { + return JSON_OBJECT_SIZE(3); } /** @@ -36,10 +26,10 @@ void AutoConnectElementJson::_serialize(JsonObject& json) { * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectElementJson::loadElement(const JsonObject& json) { +bool AutoConnectElementJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACELEMENT))) { - _setElement(json); + _setMember(json); return true; } return false; @@ -50,20 +40,47 @@ bool AutoConnectElementJson::loadElement(const JsonObject& json) { * @param json JSON object to be serialized. */ void AutoConnectElementJson::serialize(JsonObject& json) { + _serialize(json); json.set(F(AUTOCONNECT_JSON_KEY_TYPE), F(AUTOCONNECT_JSON_TYPE_ACELEMENT)); json.set(F(AUTOCONNECT_JSON_KEY_VALUE), value); } +/** + * Serialize AutoConnectElement to JSON. + * This function is base for each element. + * @param json JSON object to be serialized. + */ +void AutoConnectElementJson::_serialize(JsonObject& json) { + json.set(F(AUTOCONNECT_JSON_KEY_NAME), name); +} + +/** + * Set items common to any type of AutoConnectElement from JSON objects. + * @param json JSON object with the definition of AutoConnectElement. + */ +void AutoConnectElementJson::_setMember(const JsonObject& json) { + name = json.get(F(AUTOCONNECT_JSON_KEY_NAME)); + value = json.get(F(AUTOCONNECT_JSON_KEY_VALUE)); +} + +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectButtonJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(1); +} + /** * Load a button element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectButtonJson::loadElement(const JsonObject& json) { +bool AutoConnectButtonJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACBUTTON))) { - _setElement(json); + _setMember(json); action = json.get(F(AUTOCONNECT_JSON_KEY_ACTION)); return true; } @@ -81,16 +98,24 @@ void AutoConnectButtonJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_ACTION), action); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectCheckboxJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(2); +} + /** * Load a checkbox element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectCheckboxJson::loadElement(const JsonObject& json) { +bool AutoConnectCheckboxJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACCHECKBOX))) { - _setElement(json); + _setMember(json); label = json.get(F(AUTOCONNECT_JSON_KEY_LABEL)); checked = json.get(F(AUTOCONNECT_JSON_KEY_CHECKED)); return true; @@ -111,16 +136,24 @@ void AutoConnectCheckboxJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_CHECKED), checked); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectInputJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(2); +} + /** * Load a input-box element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectInputJson::loadElement(const JsonObject& json) { +bool AutoConnectInputJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACINPUT))) { - _setElement(json); + _setMember(json); placeholder = json.get(F(AUTOCONNECT_JSON_KEY_PLACEHOLDER)); label = json.get(F(AUTOCONNECT_JSON_KEY_LABEL)); return true; @@ -141,15 +174,23 @@ void AutoConnectInputJson::serialize(JsonObject& json) { } /** -* Load a radio-button element attribute member from the JSON object. -* @param json JSON object with the definition of AutoConnectElement. -* @return true AutoConnectElement loaded -* @return false Type of AutoConnectElement is mismatched. -*/ -bool AutoConnectRadioJson::loadElement(const JsonObject& json) { + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectRadioJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(3) + _values.size() * JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(1); +} + +/** + * Load a radio-button element attribute member from the JSON object. + * @param json JSON object with the definition of AutoConnectElement. + * @return true AutoConnectElement loaded + * @return false Type of AutoConnectElement is mismatched. + */ +bool AutoConnectRadioJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACRADIO))) { - _setElement(json); + _setMember(json); label = json.get(F(AUTOCONNECT_JSON_KEY_LABEL)); checked = static_cast(json.get(F(AUTOCONNECT_JSON_KEY_CHECKED))); String arrange = json.get(F(AUTOCONNECT_JSON_KEY_ARRANGE)); @@ -188,16 +229,24 @@ void AutoConnectRadioJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_CHECKED), checked); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectSelectJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(3) + _options.size() * JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(1); +} + /** * Load a select element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectSelectJson::loadElement(const JsonObject& json) { +bool AutoConnectSelectJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACSELECT))) { - _setElement(json); + _setMember(json); label = json.get(F(AUTOCONNECT_JSON_KEY_LABEL)); empty(); JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_OPTION]; @@ -221,16 +270,24 @@ void AutoConnectSelectJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_LABEL), label); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectSubmitJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(1); +} + /** * Load a submit element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectSubmitJson::loadElement(const JsonObject& json) { +bool AutoConnectSubmitJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACSUBMIT))) { - _setElement(json); + _setMember(json); uri = json.get(F(AUTOCONNECT_JSON_KEY_URI)); return true; } @@ -248,16 +305,24 @@ void AutoConnectSubmitJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_URI), uri); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +const size_t AutoConnectTextJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(1); +} + /** * Load a text element attribute member from the JSON object. * @param json JSON object with the definition of AutoConnectElement. * @return true AutoConnectElement loaded * @return false Type of AutoConnectElement is mismatched. */ -bool AutoConnectTextJson::loadElement(const JsonObject& json) { +bool AutoConnectTextJson::loadMember(const JsonObject& json) { String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACTEXT))) { - _setElement(json); + _setMember(json); style = json.get(F(AUTOCONNECT_JSON_KEY_STYLE)); return true; }