From 062779b5e8ba988f7bb6d2992e329263842383f7 Mon Sep 17 00:00:00 2001 From: Hieromon Ikasamo Date: Tue, 12 Mar 2019 23:21:43 +0900 Subject: [PATCH] Add AutoConnectFile --- src/AutoConnectAux.cpp | 91 ++++++++++++++++++++++++++++++- src/AutoConnectAux.h | 1 + src/AutoConnectElement.h | 7 ++- src/AutoConnectElementBasis.h | 26 ++++++++- src/AutoConnectElementBasisImpl.h | 27 ++++++++- src/AutoConnectElementJson.h | 22 ++++++++ src/AutoConnectElementJsonImpl.h | 40 +++++++++++++- 7 files changed, 201 insertions(+), 13 deletions(-) diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp index e3fde92..33f37c9 100644 --- a/src/AutoConnectAux.cpp +++ b/src/AutoConnectAux.cpp @@ -2,8 +2,8 @@ * Implementation of AutoConnectAux class. * @file AutoConnectAuxBasisImpl.h * @author hieromon@gmail.com - * @version 0.9.7 - * @date 2018-11-17 + * @version 0.9.8 + * @date 2019-03-11 * @copyright MIT license. */ #include @@ -43,7 +43,7 @@ const char AutoConnectAux::_PAGE_AUX[] PROGMEM = { "{{MENU_AUX}}" "{{MENU_POST}}" "
" - "
" + "" "
    " "{{AUX_ELEMENT}}" "
" @@ -263,6 +263,23 @@ const String AutoConnectAux::_indicateUri(PageArgument& args) { return lastUri; } +/** + * Modifying the form of attribute depending on the type of `input` tag + * contained. If the custom web page contains `input type=file` then + * allows multipart as ENCTYPE attribute. + * @param args A reference of PageArgument but unused. + * @return HTML string that should be inserted. + */ +const String AutoConnectAux::_indicateEncType(PageArgument& args) { + AC_UNUSED(args); + String encType = String(""); + for (AutoConnectElement& elm : _addonElm) + if (elm.typeOf() == AC_File) { + return String(F("enctype='multipart/form-data'")); + } + return AutoConnect::_emptyString; +} + /** * Insert the token handler of PageBuilder. This handler inserts HTML * elements generated by the whole AutoConnectElements to the auxiliary page. @@ -328,6 +345,7 @@ PageElement* AutoConnectAux::_setupPage(const String& uri) { elm->addToken(String(FPSTR("MENU_AUX")), std::bind(&AutoConnect::_token_MENU_AUX, mother, std::placeholders::_1)); elm->addToken(String(FPSTR("MENU_POST")), std::bind(&AutoConnect::_token_MENU_POST, mother, std::placeholders::_1)); elm->addToken(String(FPSTR("AUX_URI")), std::bind(&AutoConnectAux::_indicateUri, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("ENC_TYPE")), std::bind(&AutoConnectAux::_indicateEncType, this, std::placeholders::_1)); elm->addToken(String(FPSTR("AUX_ELEMENT")), std::bind(&AutoConnectAux::_insertElement, this, std::placeholders::_1)); } } @@ -363,6 +381,20 @@ void AutoConnectAux::_storeElements(WebServerClass* webServer) { #ifndef AUTOCONNECT_USE_JSON +/** + * Get AutoConnectElementBasis element. + * @param name an element name. + * @return A reference of AutoConnectElement class. + */ +template<> +AutoConnectElementBasis& AutoConnectAux::getElement(const String& name) { + AutoConnectElement* elm = getElement(name); + if (elm) { + return *(reinterpret_cast(elm)); + } + return reinterpret_cast(_nullElement()); +} + /** * Get AutoConnectButtonBasis element. * @param name An element name. @@ -397,6 +429,23 @@ AutoConnectCheckboxBasis& AutoConnectAux::getElement(const String& name) { return reinterpret_cast(_nullElement()); } +/** + * Get AutoConnectFileBasis element. + * @param name An element name. + * @return A reference of AutoConnectFile class. + */ +template<> +AutoConnectFileBasis& AutoConnectAux::getElement(const String& name) { + AutoConnectElement* elm = getElement(name); + if (elm) { + if (elm->typeOf() == AC_Input) + return *(reinterpret_cast(elm)); + else + AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); + } + return reinterpret_cast(_nullElement()); +} + /** * Get AutoConnectInputBasis element. * @param name An element name. @@ -484,6 +533,20 @@ AutoConnectTextBasis& AutoConnectAux::getElement(const String& name) { #else +/** + * Get AutoConnectElementJson element. + * @param name an element name. + * @return A reference of AutoConnectElement class. + */ +template<> +AutoConnectElementJson& AutoConnectAux::getElement(const String& name) { + AutoConnectElement* elm = getElement(name); + if (elm) { + return *(reinterpret_cast(elm)); + } + return reinterpret_cast(_nullElement()); +} + /** * Get AutoConnectButtonJson element. * @param name An element name. @@ -518,6 +581,23 @@ AutoConnectCheckboxJson& AutoConnectAux::getElement(const String& name) { return reinterpret_cast(_nullElement()); } +/** + * Get AutoConnectFile element. + * @param name An element name. + * @return A reference of AutoConnectFile class. + */ +template<> +AutoConnectFileJson& AutoConnectAux::getElement(const String& name) { + AutoConnectElement* elm = getElement(name); + if (elm) { + if (elm->typeOf() == AC_File) + return *(reinterpret_cast(elm)); + else + AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf()); + } + return reinterpret_cast(_nullElement()); +} + /** * Get AutoConnectInputJson element. * @param name An element name. @@ -702,6 +782,10 @@ AutoConnectElement* AutoConnectAux::_createElement(const JsonObject& json) { AutoConnectCheckbox* cert_elm = new AutoConnectCheckbox; return reinterpret_cast(cert_elm); } + case AC_File: { + AutoConnectFile* cert_elm = new AutoConnectFile; + return reinterpret_cast(cert_elm); + } case AC_Input: { AutoConnectInput* cert_elm = new AutoConnectInput; return reinterpret_cast(cert_elm); @@ -949,6 +1033,7 @@ ACElement_t AutoConnectAux::_asElementType(const String& type) { { AUTOCONNECT_JSON_TYPE_ACBUTTON, AC_Button }, { AUTOCONNECT_JSON_TYPE_ACCHECKBOX, AC_Checkbox }, { AUTOCONNECT_JSON_TYPE_ACELEMENT, AC_Element }, + { AUTOCONNECT_JSON_TYPE_ACFILE, AC_File }, { AUTOCONNECT_JSON_TYPE_ACINPUT, AC_Input }, { AUTOCONNECT_JSON_TYPE_ACRADIO, AC_Radio }, { AUTOCONNECT_JSON_TYPE_ACSELECT, AC_Select }, diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h index 46e172b..19b9f5e 100644 --- a/src/AutoConnectAux.h +++ b/src/AutoConnectAux.h @@ -80,6 +80,7 @@ class AutoConnectAux : public PageBuilder { const String _injectTitle(PageArgument& args) const { (void)(args); return _title; } /**< Returns title of this page to PageBuilder */ const String _injectMenu(PageArgument& args); /**< Inject menu title of this page to PageBuilder */ const String _indicateUri(PageArgument& args); /**< Inject the uri that caused the request */ + const String _indicateEncType(PageArgument& args); /**< Inject the ENCTYPE attribute */ void _storeElements(WebServerClass* webServer); /**< Store element values from contained in request arguments */ static AutoConnectElement& _nullElement(void); /**< A static returning value as invalid */ diff --git a/src/AutoConnectElement.h b/src/AutoConnectElement.h index afb2633..4896a60 100644 --- a/src/AutoConnectElement.h +++ b/src/AutoConnectElement.h @@ -2,8 +2,8 @@ * Alias declarations for an accessible the AutoConnectElement class. * @file AutoConnectAux.h * @author hieromon@gmail.com - * @version 0.9.7 - * @date 2018-11-17 + * @version 0.9.8 + * @date 2018-03-11 * @copyright MIT license. */ @@ -17,6 +17,7 @@ using AutoConnectElement = AutoConnectElementJson; using AutoConnectButton = AutoConnectButtonJson; using AutoConnectCheckbox = AutoConnectCheckboxJson; +using AutoConnectFile = AutoConnectFileJson; using AutoConnectInput = AutoConnectInputJson; using AutoConnectRadio = AutoConnectRadioJson; using AutoConnectSelect = AutoConnectSelectJson; @@ -27,6 +28,7 @@ using AutoConnectText = AutoConnectTextJson; using AutoConnectElement = AutoConnectElementBasis; using AutoConnectButton = AutoConnectButtonBasis; using AutoConnectCheckbox = AutoConnectCheckboxBasis; +using AutoConnectFile = AutoConnectFileBasis; using AutoConnectInput = AutoConnectInputBasis; using AutoConnectRadio = AutoConnectRadioBasis; using AutoConnectSelect = AutoConnectSelectBasis; @@ -42,6 +44,7 @@ using AutoConnectText = AutoConnectTextBasis; #define ACElement(n, v) AutoConnectElement n(#n, v) #define ACButton(n, ...) AutoConnectButton n(#n, ##__VA_ARGS__) #define ACCheckbox(n, ...) AutoConnectCheckbox n(#n, ##__VA_ARGS__) +#define ACFile(n, ...) AutoConnectFile n(#n, ##__VA_ARGS__) #define ACInput(n, ...) AutoConnectInput n(#n, ##__VA_ARGS__) #define ACRadio(n, ...) AutoConnectRadio n(#n, ##__VA_ARGS__) #define ACSelect(n, ...) AutoConnectSelect n(#n, ##__VA_ARGS__) diff --git a/src/AutoConnectElementBasis.h b/src/AutoConnectElementBasis.h index 589960f..6c18cba 100644 --- a/src/AutoConnectElementBasis.h +++ b/src/AutoConnectElementBasis.h @@ -2,8 +2,8 @@ * Declaration of AutoConnectElement basic class. * @file AutoConnectElementBasis.h * @author hieromon@gmail.com - * @version 0.9.7 - * @date 2018-12-29 + * @version 0.9.8 + * @date 2019-03-11 * @copyright MIT license. */ @@ -17,12 +17,13 @@ typedef enum { AC_Button, AC_Checkbox, AC_Element, + AC_File, AC_Input, AC_Radio, AC_Select, AC_Submit, AC_Text, - AC_Unknown + AC_Unknown = -1 } ACElement_t; /**< AutoConnectElement class type */ typedef enum { @@ -90,6 +91,25 @@ class AutoConnectCheckboxBasis : virtual public AutoConnectElementBasis { bool checked; /**< The element should be pre-selected */ }; +/** + * File-select input arrangement class, a part of AutoConnectAux element. + * Place a optionally labeled file-select input box that can be added by user sketch. + * @param name File-select input box name string. + * @param value A string value entered by the selected file name. + * @param label A label string that follows file-select box, optionally. + * The label is placed in front of file-select box. + */ +class AutoConnectFileBasis : virtual public AutoConnectElementBasis { + public: + explicit AutoConnectFileBasis(const char* name = "", const char* value= "", const char* label = "") : AutoConnectElementBasis(name, value), label(String(label)) { + _type = AC_File; + } + virtual ~AutoConnectFileBasis() {} + const String toHTML(void) const override; + + String label; /**< A label for a subsequent input box */ +}; + /** * Input-box arrangement class, a part of AutoConnectAux element. * Place a optionally labeled input-box that can be added by user sketch. diff --git a/src/AutoConnectElementBasisImpl.h b/src/AutoConnectElementBasisImpl.h index 1a69d78..5baf08e 100644 --- a/src/AutoConnectElementBasisImpl.h +++ b/src/AutoConnectElementBasisImpl.h @@ -2,8 +2,8 @@ * Implementation of AutoConnectElementBasis classes. * @file AutoConnectElementImpl.h * @author hieromon@gmail.com - * @version 0.9.7 - * @date 2018-12-29 + * @version 0.9.8 + * @date 2019-03-11 * @copyright MIT license. */ @@ -46,6 +46,22 @@ const String AutoConnectCheckboxBasis::toHTML(void) const { return html; } +/** + * Generate an HTML element. + * The entered value can be obtained using the user callback function + * registered by AutoConnectAux::on after the form is sent in + * combination with AutoConnectSubmit. + * @return String an HTML string. + */ +const String AutoConnectFileBasis::toHTML(void) const { + String html = String(""); + + if (label.length()) + html = String(F("")); + html += String(F("
")); + return html; +} + /** * Generate an HTML element. * If the value member is contained, it is reflected in the placeholder @@ -208,7 +224,12 @@ const String AutoConnectSubmitBasis::toHTML(void) const { * @return String an HTML string. */ const String AutoConnectTextBasis::toHTML(void) const { - return String(F("
") + value + String(F("
")); + String html = String("") + value + String(F("
")); + return html; } #endif // _AUTOCONNECTELEMENTBASISIMPL_H_ diff --git a/src/AutoConnectElementJson.h b/src/AutoConnectElementJson.h index 3260b03..d9e4a63 100644 --- a/src/AutoConnectElementJson.h +++ b/src/AutoConnectElementJson.h @@ -33,6 +33,7 @@ #define AUTOCONNECT_JSON_TYPE_ACBUTTON "ACButton" #define AUTOCONNECT_JSON_TYPE_ACCHECKBOX "ACCheckBox" #define AUTOCONNECT_JSON_TYPE_ACELEMENT "ACElement" +#define AUTOCONNECT_JSON_TYPE_ACFILE "ACFile" #define AUTOCONNECT_JSON_TYPE_ACINPUT "ACInput" #define AUTOCONNECT_JSON_TYPE_ACRADIO "ACRadio" #define AUTOCONNECT_JSON_TYPE_ACSELECT "ACSelect" @@ -105,6 +106,27 @@ class AutoConnectCheckboxJson : public AutoConnectElementJson, public AutoConnec void serialize(JsonObject& json) override; }; +/** + * File-select input arrangement class, a part of AutoConnectAux element. + * Place a optionally labeled file-select input box that can be added by user sketch. + * @param name File-select input box name string. + * @param value A string value entered by the selected file name. + * @param label A label string that follows file-select box, optionally. + * The label is placed in front of file-select box. + */ +class AutoConnectFileJson : public AutoConnectElementJson, public AutoConnectFileBasis { + public: + explicit AutoConnectFileJson(const char* name = "", const char* value= "", const char* label = "") { + AutoConnectFileBasis::name = String(name); + AutoConnectFileBasis::value = String(value); + AutoConnectFileBasis::label = String(label); + } + ~AutoConnectFileJson() {} + size_t getObjectSize(void) const override; + bool loadMember(const JsonObject& json) override; + void serialize(JsonObject& json) override; +}; + /** * Input-box arrangement class, a part of AutoConnectAux element with * handling JSON object. diff --git a/src/AutoConnectElementJsonImpl.h b/src/AutoConnectElementJsonImpl.h index c30dd27..cef5ada 100644 --- a/src/AutoConnectElementJsonImpl.h +++ b/src/AutoConnectElementJsonImpl.h @@ -2,8 +2,8 @@ * Implementation of AutoConnectElementJson classes. * @file AutoConnectElementImpl.h * @author hieromon@gmail.com - * @version 0.9.7 - * @date 2018-11-17 + * @version 0.9.8 + * @date 2019-03-11 * @copyright MIT license. */ @@ -140,6 +140,42 @@ void AutoConnectCheckboxJson::serialize(JsonObject& json) { json.set(F(AUTOCONNECT_JSON_KEY_CHECKED), checked); } +/** + * Returns JSON object size. + * @return An object size for JsonBuffer. + */ +size_t AutoConnectFileJson::getObjectSize() const { + return AutoConnectElementJson::getObjectSize() + JSON_OBJECT_SIZE(1); +} + +/** + * Load a file-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 AutoConnectFileJson::loadMember(const JsonObject& json) { + String type = json.get(F(AUTOCONNECT_JSON_KEY_TYPE)); + if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACFILE))) { + _setMember(json); + if (json.containsKey(F(AUTOCONNECT_JSON_KEY_LABEL))) + label = json.get(F(AUTOCONNECT_JSON_KEY_LABEL)); + return true; + } + return false; +} + +/** + * Serialize AutoConnectFile to JSON. + * @param json JSON object to be serialized. + */ +void AutoConnectFileJson::serialize(JsonObject& json) { + _serialize(json); + json.set(F(AUTOCONNECT_JSON_KEY_TYPE), F(AUTOCONNECT_JSON_TYPE_ACFILE)); + json.set(F(AUTOCONNECT_JSON_KEY_VALUE), value); + json.set(F(AUTOCONNECT_JSON_KEY_LABEL), label); +} + /** * Returns JSON object size. * @return An object size for JsonBuffer.