Supports AutoConnectAux

pull/41/head
Hieromon Ikasamo 6 years ago
parent d281bb33e7
commit 5dcbf14a77
  1. 2
      keywords.txt
  2. 4
      src/AutoConnect.cpp
  3. 114
      src/AutoConnectAux.cpp
  4. 15
      src/AutoConnectAux.h
  5. 3
      src/AutoConnectElement.h
  6. 34
      src/AutoConnectElementBasis.h
  7. 30
      src/AutoConnectElementBasisImpl.h
  8. 32
      src/AutoConnectElementJson.h
  9. 30
      src/AutoConnectElementJsonImpl.h
  10. 8
      src/AutoConnectPage.cpp

@ -9,6 +9,7 @@ AutoConnectButton KEYWORD1
AutoConnectCheckbox KEYWORD1 AutoConnectCheckbox KEYWORD1
AutoConnectElement KEYWORD1 AutoConnectElement KEYWORD1
AutoConnectInput KEYWORD1 AutoConnectInput KEYWORD1
AutoConnectRadio KEYWORD1
AutoConnectSelect KEYWORD1 AutoConnectSelect KEYWORD1
AutoConnectSubmit KEYWORD1 AutoConnectSubmit KEYWORD1
AutoConnectText KEYWORD1 AutoConnectText KEYWORD1
@ -54,6 +55,7 @@ ACButton PREPROCESSOR
ACCheckbox PREPROCESSOR ACCheckbox PREPROCESSOR
ACElement PREPROCESSOR ACElement PREPROCESSOR
ACInput PREPROCESSOR ACInput PREPROCESSOR
ACRadio PREPROCESSOR
ACSelect PREPROCESSOR ACSelect PREPROCESSOR
ACSubmit PREPROCESSOR ACSubmit PREPROCESSOR
ACText PREPROCESSOR ACText PREPROCESSOR

@ -310,6 +310,7 @@ void AutoConnect::_startWebServer() {
_webServer->onNotFound(std::bind(&AutoConnect::_handleNotFound, this)); _webServer->onNotFound(std::bind(&AutoConnect::_handleNotFound, this));
// here, Prepare PageBuilders for captive portal // here, Prepare PageBuilders for captive portal
_responsePage = new PageBuilder(); _responsePage = new PageBuilder();
_responsePage->chunked(PB_ByteStream);
_responsePage->exitCanHandle(std::bind(&AutoConnect::_classifyHandle, this, std::placeholders::_1, std::placeholders::_2)); _responsePage->exitCanHandle(std::bind(&AutoConnect::_classifyHandle, this, std::placeholders::_1, std::placeholders::_2));
_responsePage->insert(*_webServer); _responsePage->insert(*_webServer);
@ -538,10 +539,11 @@ String AutoConnect::_induceConnect(PageArgument& args) {
// Read from EEPROM // Read from EEPROM
AutoConnectCredential credential(_apConfig.boundaryOffset); AutoConnectCredential credential(_apConfig.boundaryOffset);
struct station_config entry; struct station_config entry;
AC_DBG("Load credential:%s\n", args.arg(AUTOCONNECT_PARAMID_CRED).c_str()); // AC_DBG("Load credential:%s\n", args.arg(AUTOCONNECT_PARAMID_CRED).c_str());
credential.load(args.arg(AUTOCONNECT_PARAMID_CRED).c_str(), &entry); credential.load(args.arg(AUTOCONNECT_PARAMID_CRED).c_str(), &entry);
strncpy(reinterpret_cast<char*>(_credential.ssid), reinterpret_cast<const char*>(entry.ssid), sizeof(_credential.ssid)); strncpy(reinterpret_cast<char*>(_credential.ssid), reinterpret_cast<const char*>(entry.ssid), sizeof(_credential.ssid));
strncpy(reinterpret_cast<char*>(_credential.password), reinterpret_cast<const char*>(entry.password), sizeof(_credential.password)); strncpy(reinterpret_cast<char*>(_credential.password), reinterpret_cast<const char*>(entry.password), sizeof(_credential.password));
AC_DBG("Credential loaded:%s %s\n", _credential.ssid, _credential.password);
} }
else { else {
// Credential had by the post parameter. // Credential had by the post parameter.

@ -77,7 +77,7 @@ AutoConnectAux::~AutoConnectAux() {
*/ */
void AutoConnectAux::add(AutoConnectElement& addon) { void AutoConnectAux::add(AutoConnectElement& addon) {
_addonElm.push_back(addon); _addonElm.push_back(addon);
AC_DBG("%s placed on %s\n", addon.name.length() ? addon.name.c_str() : "*nonamed*", uri()); AC_DBG("%s placed on %s\n", addon.name.length() ? addon.name.c_str() : "*noname", uri());
} }
/** /**
@ -258,6 +258,10 @@ AutoConnectElement* AutoConnectAux::_createElement(const JsonObject& json) {
AutoConnectInput* cert_elm = new AutoConnectInput; AutoConnectInput* cert_elm = new AutoConnectInput;
return reinterpret_cast<AutoConnectElement*>(cert_elm); return reinterpret_cast<AutoConnectElement*>(cert_elm);
} }
case AC_Radio: {
AutoConnectRadio* cert_elm = new AutoConnectRadio;
return reinterpret_cast<AutoConnectElement*>(cert_elm);
}
case AC_Select: { case AC_Select: {
AutoConnectSelect* cert_elm = new AutoConnectSelect; AutoConnectSelect* cert_elm = new AutoConnectSelect;
return reinterpret_cast<AutoConnectElement*>(cert_elm); return reinterpret_cast<AutoConnectElement*>(cert_elm);
@ -274,59 +278,112 @@ AutoConnectElement* AutoConnectAux::_createElement(const JsonObject& json) {
return elm; return elm;
} }
/**
* Constructs an AutoConnectAux instance by reading all the
* AutoConnectElements of the specified URI from the elements defined JSON.
* @param in AutoConnectAux element data which is described by JSON.
* @return true The element collection successfully loaded.
* @return false Invalid JSON data occurred.
*/
bool AutoConnectAux::load(const char* in) {
// DynamicJsonBuffer jsonBuffer();
const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& jb = jsonBuffer.parseObject(in);
return _load(jb);
}
bool AutoConnectAux::load(const __FlashStringHelper* in) {
// DynamicJsonBuffer jsonBuffer();
const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& jb = jsonBuffer.parseObject(in);
return _load(jb);
}
bool AutoConnectAux::load(Stream& in) {
// DynamicJsonBuffer jsonBuffer();
const size_t bufferSize = 2*JSON_ARRAY_SIZE(2) + 3*JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(9) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + 9*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + 1080;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& jb = jsonBuffer.parseObject(in);
return _load(jb);
}
bool AutoConnectAux::_load(JsonObject& jb) {
if (!jb.success())
return false;
_title = jb.get<String>(F(AUTOCONNECT_JSON_KEY_TITLE));
_uriStr = jb.get<String>(F(AUTOCONNECT_JSON_KEY_URI));
_uri = _uriStr.c_str();
_menu = jb.get<bool>(F(AUTOCONNECT_JSON_KEY_MENU));
(void)_loadElement(jb, "*");
return true;
}
/** /**
* Load element specified by the name parameter from the stream * Load element specified by the name parameter from the stream
* described by JSON. Usually, the Stream is specified a storm file of * described by JSON. Usually, the Stream is specified a storm file of
* SD or SPIFFS. The Stream must be opened before invoking the function. * SD or SPIFFS. The Stream must be opened before invoking the function.
* @param in Reference of the Stream which contains the parameter * @param in Reference of the Stream which contains the parameter
* file described by JSON. * data described by JSON.
* @param name The element name to be loaded. * @param name The element name to be loaded. '*'specifies that all
* elements are to be loaded.
* @return A reference of loaded AutoConnectElement instance. * @return A reference of loaded AutoConnectElement instance.
*/ */
AutoConnectElement& AutoConnectAux::loadElement(const char* in, const String name) {
DynamicJsonBuffer jsonBuffer;
JsonObject& jb = jsonBuffer.parseObject(in);
return _loadElement(jb, name);
}
AutoConnectElement& AutoConnectAux::loadElement(const __FlashStringHelper* in, const String name) {
DynamicJsonBuffer jsonBuffer;
JsonObject& jb = jsonBuffer.parseObject(in);
return _loadElement(jb, name);
}
AutoConnectElement& AutoConnectAux::loadElement(Stream& in, const String name) { AutoConnectElement& AutoConnectAux::loadElement(Stream& in, const String name) {
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonObject& jb = jsonBuffer.parseObject(in); JsonObject& jb = jsonBuffer.parseObject(in);
return _loadElement(jb, name);
}
if (!jb.success()) AutoConnectElement& AutoConnectAux::_loadElement(JsonObject& jb, const String name) {
return _nullElement(); AutoConnectElement* auxElm = nullptr;
bool wc = name == "*";
JsonArray& aux = jb[AUTOCONNECT_JSON_KEY_AUX]; if (!jb.success())
if (!aux.success())
return _nullElement(); return _nullElement();
for (JsonObject& page : aux) { JsonArray& elements = jb[AUTOCONNECT_JSON_KEY_ELEMENT];
if (page["uri"].as<String>() == String(uri())) { for (JsonObject& element : elements) {
JsonArray& element = page[AUTOCONNECT_JSON_KEY_ELEMENT]; String elmName = element.get<String>(F(AUTOCONNECT_JSON_KEY_NAME));
for (JsonObject& elm : element) { if (wc || name.equalsIgnoreCase(elmName)) {
if (name.equalsIgnoreCase(elm.get<String>(F(AUTOCONNECT_JSON_KEY_NAME)))) {
// The specified element is defined in the JSON stream. // The specified element is defined in the JSON stream.
// Loads from JSON object. // Loads from JSON object.
const String inType = elm[AUTOCONNECT_JSON_KEY_TYPE].as<String>(); auxElm = _getElement(elmName);
AutoConnectElement* auxElm = _getElement(name);
// The element is not created yet, create new one. // The element is not created yet, create new one.
if (!auxElm) { if (!auxElm) {
if ((auxElm = _createElement(elm))) { if ((auxElm = _createElement(element))) {
AC_DBG("%s<%d> of %s created\n", name.c_str(), (int)(auxElm->typeOf()), uri()); AC_DBG("%s<%d> of %s created\n", elmName.c_str(), (int)(auxElm->typeOf()), uri());
add(*auxElm); // Insert to AutoConnect add(*auxElm); // Insert to AutoConnect
} }
else { else {
AC_DBG("%s unknown element type\n", name.c_str()); AC_DBG("%s unknown element type\n", elmName.c_str());
return _nullElement(); continue;
}
} }
if (auxElm->loadElement(elm)) {
AC_DBG("%s<%d> of %s loaded\n", name.c_str(), (int)auxElm->typeOf(), uri());
} }
if (auxElm->loadElement(element))
AC_DBG("%s<%d> of %s loaded\n", auxElm->name.c_str(), (int)auxElm->typeOf(), uri());
else { else {
// Element type mismatch // Element type mismatch
AC_DBG("Type of %s element mismatched\n", name.c_str()); AC_DBG("Type of %s element mismatched\n", elmName.c_str());
return _nullElement(); continue;
}
} }
} }
} }
} return auxElm ? *auxElm : _nullElement();
return _nullElement();
} }
/** /**
@ -342,12 +399,12 @@ size_t AutoConnectAux::saveElement(Stream& out, const AutoConnectElement& elemen
if (!jb.success()) if (!jb.success())
return 0; return 0;
JsonArray& aux = jb[AUTOCONNECT_JSON_KEY_AUX]; JsonArray& aux = jb["aux"];
if (!aux.success()) if (!aux.success())
return 0; return 0;
for (JsonObject& page : aux) { for (JsonObject& page : aux) {
if (page["uri"].as<String>() == String(uri())) { if (page["aux"].as<String>() == String(uri())) {
JsonArray& element_j = page[AUTOCONNECT_JSON_KEY_ELEMENT]; JsonArray& element_j = page[AUTOCONNECT_JSON_KEY_ELEMENT];
for (JsonObject& elm : element_j) { for (JsonObject& elm : element_j) {
if (elm[AUTOCONNECT_JSON_KEY_NAME].as<String>() == element.name) { if (elm[AUTOCONNECT_JSON_KEY_NAME].as<String>() == element.name) {
@ -387,6 +444,7 @@ const ACElement_t AutoConnectAux::_asElementType(const String type) {
{ AUTOCONNECT_JSON_TYPE_ACCHECKBOX, AC_Checkbox }, { AUTOCONNECT_JSON_TYPE_ACCHECKBOX, AC_Checkbox },
{ AUTOCONNECT_JSON_TYPE_ACELEMENT, AC_Element }, { AUTOCONNECT_JSON_TYPE_ACELEMENT, AC_Element },
{ AUTOCONNECT_JSON_TYPE_ACINPUT, AC_Input }, { AUTOCONNECT_JSON_TYPE_ACINPUT, AC_Input },
{ AUTOCONNECT_JSON_TYPE_ACRADIO, AC_Radio },
{ AUTOCONNECT_JSON_TYPE_ACSELECT, AC_Select }, { AUTOCONNECT_JSON_TYPE_ACSELECT, AC_Select },
{ AUTOCONNECT_JSON_TYPE_ACSUBMIT, AC_Submit }, { AUTOCONNECT_JSON_TYPE_ACSUBMIT, AC_Submit },
{ AUTOCONNECT_JSON_TYPE_ACTEXT, AC_Text } { AUTOCONNECT_JSON_TYPE_ACTEXT, AC_Text }

@ -10,11 +10,14 @@
#ifndef _AUTOCONNECTAUX_H_ #ifndef _AUTOCONNECTAUX_H_
#define _AUTOCONNECTAUX_H_ #define _AUTOCONNECTAUX_H_
#include "AutoConnectDefs.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <functional> #include <functional>
#ifdef AUTOCONNECT_USE_JSON
#include <Stream.h>
#endif
#include <PageBuilder.h> #include <PageBuilder.h>
#include "AutoConnectDefs.h"
#include "AutoConnectElement.h" #include "AutoConnectElement.h"
class AutoConnect; class AutoConnect;
@ -57,7 +60,12 @@ class AutoConnectAux : public PageBuilder {
void on(const AuxHandlerFunctionT handler, const AutoConnectExitOrder_t order = AC_EXIT_AHEAD) { _handler = handler; _order = order; } /**< Set user handler */ void on(const AuxHandlerFunctionT handler, const AutoConnectExitOrder_t order = AC_EXIT_AHEAD) { _handler = handler; _order = order; } /**< Set user handler */
#ifdef AUTOCONNECT_USE_JSON #ifdef AUTOCONNECT_USE_JSON
AutoConnectElement& loadElement(Stream& in, const String name); bool load(const char* in);
bool load(const __FlashStringHelper* in);
bool load(Stream& in);
AutoConnectElement& loadElement(const char* in, const String name = "*");
AutoConnectElement& loadElement(const __FlashStringHelper* in, const String name = "*");
AutoConnectElement& loadElement(Stream& in, const String name = "*");
size_t saveElement(Stream& out, const AutoConnectElement& element); size_t saveElement(Stream& out, const AutoConnectElement& element);
#endif #endif
@ -70,6 +78,8 @@ class AutoConnectAux : public PageBuilder {
const String _injectMenu(PageArgument& args); const String _injectMenu(PageArgument& args);
#ifdef AUTOCONNECT_USE_JSON #ifdef AUTOCONNECT_USE_JSON
bool _load(JsonObject& in);
AutoConnectElement& _loadElement(JsonObject& in, const String name);
AutoConnectElement* _createElement(const JsonObject& json); AutoConnectElement* _createElement(const JsonObject& json);
AutoConnectElement* _getElement(const String name); AutoConnectElement* _getElement(const String name);
static const ACElement_t _asElementType(const String type); static const ACElement_t _asElementType(const String type);
@ -78,6 +88,7 @@ class AutoConnectAux : public PageBuilder {
String _title; /**< A title of the page */ String _title; /**< A title of the page */
bool _menu; /**< Switch for menu displaying */ bool _menu; /**< Switch for menu displaying */
String _uriStr; /**< uri as String */
AutoConnectElementVT _addonElm; /**< A vector set of AutoConnectElements placed on this auxiliary page */ AutoConnectElementVT _addonElm; /**< A vector set of AutoConnectElements placed on this auxiliary page */
std::unique_ptr<AutoConnectAux> _next; /**< Auxiliary pages chain list */ std::unique_ptr<AutoConnectAux> _next; /**< Auxiliary pages chain list */
std::unique_ptr<AutoConnect> _ac; /**< Hosted AutoConnect instance */ std::unique_ptr<AutoConnect> _ac; /**< Hosted AutoConnect instance */

@ -20,6 +20,7 @@ using AutoConnectElement = AutoConnectElementJson;
using AutoConnectButton = AutoConnectButtonJson; using AutoConnectButton = AutoConnectButtonJson;
using AutoConnectCheckbox = AutoConnectCheckboxJson; using AutoConnectCheckbox = AutoConnectCheckboxJson;
using AutoConnectInput = AutoConnectInputJson; using AutoConnectInput = AutoConnectInputJson;
using AutoConnectRadio = AutoConnectRadioJson;
using AutoConnectSelect = AutoConnectSelectJson; using AutoConnectSelect = AutoConnectSelectJson;
using AutoConnectSubmit = AutoConnectSubmitJson; using AutoConnectSubmit = AutoConnectSubmitJson;
using AutoConnectText = AutoConnectTextJson; using AutoConnectText = AutoConnectTextJson;
@ -28,6 +29,7 @@ using AutoConnectElement = AutoConnectElementBasis;
using AutoConnectButton = AutoConnectButtonBasis; using AutoConnectButton = AutoConnectButtonBasis;
using AutoConnectCheckbox = AutoConnectCheckboxBasis; using AutoConnectCheckbox = AutoConnectCheckboxBasis;
using AutoConnectInput = AutoConnectInputBasis; using AutoConnectInput = AutoConnectInputBasis;
using AutoConnectRadio = AutoConnectRadioBasis;
using AutoConnectSelect = AutoConnectSelectBasis; using AutoConnectSelect = AutoConnectSelectBasis;
using AutoConnectSubmit = AutoConnectSubmitBasis; using AutoConnectSubmit = AutoConnectSubmitBasis;
using AutoConnectText = AutoConnectTextBasis; using AutoConnectText = AutoConnectTextBasis;
@ -42,6 +44,7 @@ using AutoConnectText = AutoConnectTextBasis;
#define ACButton(n, ...) AutoConnectButton n(#n, ##__VA_ARGS__) #define ACButton(n, ...) AutoConnectButton n(#n, ##__VA_ARGS__)
#define ACCheckbox(n, ...) AutoConnectCheckbox n(#n, ##__VA_ARGS__) #define ACCheckbox(n, ...) AutoConnectCheckbox n(#n, ##__VA_ARGS__)
#define ACInput(n, ...) AutoConnectInput 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__) #define ACSelect(n, ...) AutoConnectSelect n(#n, ##__VA_ARGS__)
#define ACSubmit(n, ...) AutoConnectSubmit n(#n, ##__VA_ARGS__) #define ACSubmit(n, ...) AutoConnectSubmit n(#n, ##__VA_ARGS__)
#define ACText(n, ...) AutoConnectText n(#n, ##__VA_ARGS__) #define ACText(n, ...) AutoConnectText n(#n, ##__VA_ARGS__)

@ -18,12 +18,18 @@ typedef enum {
AC_Checkbox, AC_Checkbox,
AC_Element, AC_Element,
AC_Input, AC_Input,
AC_Radio,
AC_Select, AC_Select,
AC_Submit, AC_Submit,
AC_Text, AC_Text,
AC_Unknown AC_Unknown
} ACElement_t; /**< AutoConnectElement class type */ } ACElement_t; /**< AutoConnectElement class type */
typedef enum {
AC_Horizontal,
AC_Vertical
} ACArrange_t; /**< The element arrange order */
/** /**
* AutoConnectAux element base. * AutoConnectAux element base.
* Placed a raw text that can be added by user sketch. * Placed a raw text that can be added by user sketch.
@ -103,6 +109,32 @@ class AutoConnectInputBasis : virtual public AutoConnectElementBasis {
String label; /**< A label for a subsequent input box */ String label; /**< A label for a subsequent input box */
}; };
/**
* Radio-button arrangement class, a part of AutoConnectAux element.
* Place a group of radio-button items and selectable mark checked.
* @param name Radio-button name string.
* @param options Array of value collection.
* @param label A label string that follows radio-buttons group.
* @param checked Index of check marked item.
*/
class AutoConnectRadioBasis : virtual public AutoConnectElementBasis {
public:
explicit AutoConnectRadioBasis(const char* name = "", std::vector<String> values = {}, const char* label = "", const ACArrange_t order = AC_Vertical, const uint8_t checked = 0) : AutoConnectElementBasis(name, ""), label(label), order(order), checked(checked), _values(values) {
_type = AC_Radio;
}
virtual ~AutoConnectRadioBasis() {}
const String toHTML(void) const;
void add(const String value) { _values.push_back(value); }
void empty(void) { _values.clear(); }
String label; /**< A label for a subsequent radio buttons */
ACArrange_t order; /**< layout order */
uint8_t checked; /**< Index of check marked item */
protected:
std::vector<String> _values; /**< Items in a group */
};
/** /**
* Selection-box arrangement class, A part of AutoConnectAux element. * Selection-box arrangement class, A part of AutoConnectAux element.
* Place a optionally labeled Selection-box that can be added by user sketch. * Place a optionally labeled Selection-box that can be added by user sketch.
@ -118,7 +150,7 @@ class AutoConnectSelectBasis : virtual public AutoConnectElementBasis {
} }
virtual ~AutoConnectSelectBasis() {} virtual ~AutoConnectSelectBasis() {}
const String toHTML(void) const; const String toHTML(void) const;
void option(const String value) { _options.push_back(value); } void add(const String option) { _options.push_back(option); }
void empty(void) { _options.clear(); } void empty(void) { _options.clear(); }
String label; /**< A label for a subsequent input box */ String label; /**< A label for a subsequent input box */

@ -62,6 +62,30 @@ const String AutoConnectInputBasis::toHTML(void) const {
return html; return html;
} }
/**
* Generate an HTML <input type=radio> element with an <option> element.
* @return String an HTML string.
*/
const String AutoConnectRadioBasis::toHTML(void) const {
String html = String();
if (label.length()) {
html = label;
if (order == AC_Vertical)
html += String("<br>");
}
for (std::size_t n = 0; n < _values.size(); n++) {
String value = _values[n];
html += String(FPSTR("<input type=\"radio\" name=\"")) + name + String(FPSTR("\" id=\"")) + value + String(FPSTR("\" value=\"")) + value + String("\"");
if (n == checked - 1)
html += String(FPSTR(" checked"));
html += String(FPSTR("><label for=\"")) + value + String("\">") + value + String(FPSTR("</label>"));
if (order == AC_Vertical)
html += String("<br>");
}
return html;
}
/** /**
* Generate an HTML <select> element with an <option> element. * Generate an HTML <select> element with an <option> element.
* The attribute value of the <option> element is given to the * The attribute value of the <option> element is given to the
@ -74,14 +98,14 @@ const String AutoConnectSelectBasis::toHTML(void) const {
String html = String(); String html = String();
if (label.length()) if (label.length())
html = String(FPSTR("<label>")) + label + String(FPSTR("</label>")); html = String(FPSTR("<label for=\"")) + name + String("\">") + label + String(FPSTR("</label>"));
html += String(FPSTR("<select name=\"")) + name + String("\">"); html += String(FPSTR("<select name=\"")) + name + String("\" id=\"") + name + String("\">");
std::size_t n = _options.size(); std::size_t n = _options.size();
if (n) { if (n) {
for (std::size_t n = 0; n < _options.size(); n++) for (std::size_t n = 0; n < _options.size(); n++)
html += String(FPSTR("<option value=\"")) + _options[n] + "\">" + _options[n] + String(FPSTR("</option>")); html += String(FPSTR("<option value=\"")) + _options[n] + "\">" + _options[n] + String(FPSTR("</option>"));
} }
html += String(FPSTR("</select><br>")); html += String(FPSTR("</select>"));
return html; return html;
} }

@ -13,21 +13,26 @@
#include "AutoConnectElementBasis.h" #include "AutoConnectElementBasis.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#define AUTOCONNECT_JSON_KEY_AUX "aux"
#define AUTOCONNECT_JSON_KEY_ELEMENT "element"
#define AUTOCONNECT_JSON_KEY_ACTION "action" #define AUTOCONNECT_JSON_KEY_ACTION "action"
#define AUTOCONNECT_JSON_KEY_ARRANGE "arrange"
#define AUTOCONNECT_JSON_KEY_CHECKED "checked" #define AUTOCONNECT_JSON_KEY_CHECKED "checked"
#define AUTOCONNECT_JSON_KEY_ELEMENT "element"
#define AUTOCONNECT_JSON_KEY_HORIZONTAL "horizontal"
#define AUTOCONNECT_JSON_KEY_LABEL "label" #define AUTOCONNECT_JSON_KEY_LABEL "label"
#define AUTOCONNECT_JSON_KEY_MENU "menu"
#define AUTOCONNECT_JSON_KEY_NAME "name" #define AUTOCONNECT_JSON_KEY_NAME "name"
#define AUTOCONNECT_JSON_KEY_OPTIONS "options" #define AUTOCONNECT_JSON_KEY_OPTION "option"
#define AUTOCONNECT_JSON_KEY_STYLE "style" #define AUTOCONNECT_JSON_KEY_STYLE "style"
#define AUTOCONNECT_JSON_KEY_TITLE "title"
#define AUTOCONNECT_JSON_KEY_TYPE "type" #define AUTOCONNECT_JSON_KEY_TYPE "type"
#define AUTOCONNECT_JSON_KEY_URI "uri" #define AUTOCONNECT_JSON_KEY_URI "uri"
#define AUTOCONNECT_JSON_KEY_VALUE "value" #define AUTOCONNECT_JSON_KEY_VALUE "value"
#define AUTOCONNECT_JSON_KEY_VERTICAL "vertical"
#define AUTOCONNECT_JSON_TYPE_ACBUTTON "ACButton" #define AUTOCONNECT_JSON_TYPE_ACBUTTON "ACButton"
#define AUTOCONNECT_JSON_TYPE_ACCHECKBOX "ACCheckBox" #define AUTOCONNECT_JSON_TYPE_ACCHECKBOX "ACCheckBox"
#define AUTOCONNECT_JSON_TYPE_ACELEMENT "ACElement" #define AUTOCONNECT_JSON_TYPE_ACELEMENT "ACElement"
#define AUTOCONNECT_JSON_TYPE_ACINPUT "ACInput" #define AUTOCONNECT_JSON_TYPE_ACINPUT "ACInput"
#define AUTOCONNECT_JSON_TYPE_ACRADIO "ACRadio"
#define AUTOCONNECT_JSON_TYPE_ACSELECT "ACSelect" #define AUTOCONNECT_JSON_TYPE_ACSELECT "ACSelect"
#define AUTOCONNECT_JSON_TYPE_ACSUBMIT "ACSubmit" #define AUTOCONNECT_JSON_TYPE_ACSUBMIT "ACSubmit"
#define AUTOCONNECT_JSON_TYPE_ACTEXT "ACText" #define AUTOCONNECT_JSON_TYPE_ACTEXT "ACText"
@ -111,6 +116,27 @@ class AutoConnectInputJson : public AutoConnectElementJson, public AutoConnectIn
bool loadElement(const JsonObject& json); bool loadElement(const JsonObject& json);
}; };
/**
* Radio-button arrangement class, a part of AutoConnectAux element.
* Place a group of radio-button items and selectable mark checked.
* @param name Radio-button name string.
* @param options Array of value collection.
* @param label A label string that follows radio-buttons group.
* @param checked Index of check marked item.
*/
class AutoConnectRadioJson : public AutoConnectElementJson, public AutoConnectRadioBasis {
public:
explicit AutoConnectRadioJson(const char* name = "", std::vector<String> values = {}, const char* label = "", const ACArrange_t order = AC_Vertical, const uint8_t checked = 0) {
AutoConnectRadioBasis::name = name;
AutoConnectRadioBasis::_values = values;
AutoConnectRadioBasis::label = label;
AutoConnectRadioBasis::order = order;
AutoConnectRadioBasis::checked = checked;
}
~AutoConnectRadioJson() {}
bool loadElement(const JsonObject& json);
};
/** /**
* Selection-box arrangement class, A part of AutoConnectAux element. * Selection-box arrangement class, A part of AutoConnectAux element.
* Place a optionally labeled Selection-box that can be added by user sketch. * Place a optionally labeled Selection-box that can be added by user sketch.

@ -85,6 +85,32 @@ bool AutoConnectInputJson::loadElement(const JsonObject& json) {
return false; return false;
} }
/**
* Load a radio-button element attribute member from the JSON object.
* @param json A JSON object with the definition of AutoConnectElement.
* @return true AutoConnectElement loaded
* @return false Type of AutoConnectElement is mismatched.
*/
bool AutoConnectRadioJson::loadElement(const JsonObject& json) {
String type = json.get<String>(F(AUTOCONNECT_JSON_KEY_TYPE));
if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACRADIO))) {
_setElement(json);
label = json.get<String>(F(AUTOCONNECT_JSON_KEY_LABEL));
checked = static_cast<uint8_t>(json.get<int>(F(AUTOCONNECT_JSON_KEY_CHECKED)));
String arrange = json.get<String>(F(AUTOCONNECT_JSON_KEY_ARRANGE));
if (arrange.equalsIgnoreCase(F(AUTOCONNECT_JSON_KEY_VERTICAL)))
order = AC_Vertical;
else if (arrange.equalsIgnoreCase(F(AUTOCONNECT_JSON_KEY_HORIZONTAL)))
order = AC_Horizontal;
empty();
JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_VALUE];
for (auto value : optionArray)
add(value.as<String>());
return true;
}
return false;
}
/** /**
* Load a select element attribute member from the JSON object. * Load a select element attribute member from the JSON object.
* @param json A JSON object with the definition of AutoConnectElement. * @param json A JSON object with the definition of AutoConnectElement.
@ -97,9 +123,9 @@ bool AutoConnectSelectJson::loadElement(const JsonObject& json) {
_setElement(json); _setElement(json);
empty(); empty();
label = json.get<String>(F(AUTOCONNECT_JSON_KEY_LABEL)); label = json.get<String>(F(AUTOCONNECT_JSON_KEY_LABEL));
JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_OPTIONS]; JsonArray& optionArray = json[AUTOCONNECT_JSON_KEY_OPTION];
for (auto value : optionArray) for (auto value : optionArray)
option(value.as<String>()); add(value.as<String>());
return true; return true;
} }
return false; return false;

@ -108,6 +108,11 @@ const char AutoConnect::_CSS_UL[] PROGMEM = {
"-moz-appearance:checkbox;" "-moz-appearance:checkbox;"
"-webkit-appearance:checkbox;" "-webkit-appearance:checkbox;"
"}" "}"
"ul.noorder>input[type=\"radio\"]{"
"margin-right:0.5em;"
"-moz-appearance:radio;"
"-webkit-appearance:radio;"
"}"
}; };
/**< Image icon for inline expansion, the lock mark. */ /**< Image icon for inline expansion, the lock mark. */
@ -139,6 +144,9 @@ const char AutoConnect::_CSS_INPUT_BUTTON[] PROGMEM = {
"width:16em;" "width:16em;"
"}" "}"
".aux-page input[type=\"button\"]{" ".aux-page input[type=\"button\"]{"
"font-weight:normal;"
"padding:8px 14px;"
"margin:12px;"
"width:auto;" "width:auto;"
"}" "}"
"input#sb[type=\"submit\"]{" "input#sb[type=\"submit\"]{"

Loading…
Cancel
Save