diff --git a/examples/mqttRSSI/mqttRSSI.ino b/examples/mqttRSSI/mqttRSSI.ino
index 7954e74..3205f94 100644
--- a/examples/mqttRSSI/mqttRSSI.ino
+++ b/examples/mqttRSSI/mqttRSSI.ino
@@ -44,6 +44,11 @@ static const char AUX_mqtt_setting[] PROGMEM = R"raw(
"uri": "/mqtt_setting",
"menu": true,
"element": [
+ {
+ "name": "style",
+ "type": "ACStyle",
+ "value": "label+input,label+select{position:sticky;left:120px;width:230px!important;box-sizing:border-box;}"
+ },
{
"name": "header",
"type": "ACText",
diff --git a/examples/mqttRSSI_FS/data/mqtt_setting.json b/examples/mqttRSSI_FS/data/mqtt_setting.json
index 6e5efca..36587e6 100644
--- a/examples/mqttRSSI_FS/data/mqtt_setting.json
+++ b/examples/mqttRSSI_FS/data/mqtt_setting.json
@@ -3,6 +3,11 @@
"uri": "/mqtt_setting",
"menu": true,
"element": [
+ {
+ "name": "style",
+ "type": "ACStyle",
+ "value": "label+input,label+select{position:sticky;left:120px;width:230px!important;box-sizing:border-box;}"
+ },
{
"name": "header",
"type": "ACText",
diff --git a/examples/mqttRSSI_NA/mqttRSSI_NA.ino b/examples/mqttRSSI_NA/mqttRSSI_NA.ino
index 2c0dd2c..ed30a46 100644
--- a/examples/mqttRSSI_NA/mqttRSSI_NA.ino
+++ b/examples/mqttRSSI_NA/mqttRSSI_NA.ino
@@ -46,6 +46,7 @@ typedef WebServer WiFiWebServer;
// facility.
// Declare AutoConnectElements for the page asf /mqtt_setting
+ACStyle(style, "label+input,label+select{position:sticky;left:120px;width:230px!important;box-sizing:border-box;}");
ACText(header, "
MQTT broker settings
", "text-align:center;color:#2f4f4f;padding:10px;");
ACText(caption, "Publishing the WiFi signal strength to MQTT channel. RSSI value of ESP8266 to the channel created on ThingSpeak", "font-family:serif;color:#4682b4;");
ACInput(mqttserver, "", "Server", "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$", "MQTT broker server");
@@ -60,6 +61,7 @@ ACSubmit(discard, "Discard", "/");
// Declare the custom Web page as /mqtt_setting and contains the AutoConnectElements
AutoConnectAux mqtt_setting(AUX_SETTING_URI, "MQTT Setting", true, {
+ style,
header,
caption,
mqttserver,
diff --git a/src/AutoConnectAux.cpp b/src/AutoConnectAux.cpp
index d6de164..c38e14c 100644
--- a/src/AutoConnectAux.cpp
+++ b/src/AutoConnectAux.cpp
@@ -36,6 +36,7 @@ const char AutoConnectAux::_PAGE_AUX[] PROGMEM = {
"{{CSS_INPUT_BUTTON}}"
"{{CSS_INPUT_TEXT}}"
"{{CSS_LUXBAR}}"
+ "{{AUX_CSS}}"
""
""
""
@@ -409,8 +410,14 @@ const String AutoConnectAux::_insertElement(PageArgument& args) {
}
// Generate HTML for all AutoConnectElements contained in the page.
- for (AutoConnectElement& addon : _addonElm)
- body += addon.toHTML();
+ for (AutoConnectElement& addon : _addonElm) {
+ // Since the style sheet has already drained at the time of the
+ // _insertElement function call, it skips the call to the HTML
+ // generator by each element.
+ if (addon.typeOf() != AC_Style)
+ // Invoke an HTML generator by each element
+ body += addon.toHTML();
+ }
// Call user handler after HTML generation.
if (_handler) {
@@ -422,6 +429,21 @@ const String AutoConnectAux::_insertElement(PageArgument& args) {
return body;
}
+/**
+ * Insert user defined CSS code to AutoConnectAux page.
+ * @param args A reference of PageArgument but unused.
+ * @return HTML string that should be inserted.
+ */
+const String AutoConnectAux::_insertStyle(PageArgument& args) {
+ String css = String("");
+
+ for (AutoConnectElement& elm : _addonElm) {
+ if (elm.typeOf() == AC_Style)
+ css += elm.toHTML();
+ }
+ return css;
+}
+
/**
* Generate an auxiliary page assembled with the AutoConnectElement.
* This function is the core procedure of AutoConnectAux, and uses
@@ -455,6 +477,7 @@ PageElement* AutoConnectAux::_setupPage(const String& uri) {
elm->addToken(String(FPSTR("CSS_INPUT_BUTTON")), std::bind(&AutoConnect::_token_CSS_INPUT_BUTTON, mother, std::placeholders::_1));
elm->addToken(String(FPSTR("CSS_INPUT_TEXT")), std::bind(&AutoConnect::_token_CSS_INPUT_TEXT, mother, std::placeholders::_1));
elm->addToken(String(FPSTR("CSS_LUXBAR")), std::bind(&AutoConnect::_token_CSS_LUXBAR, mother, std::placeholders::_1));
+ elm->addToken(String(FPSTR("AUX_CSS")), std::bind(&AutoConnectAux::_insertStyle, this, std::placeholders::_1));
elm->addToken(String(FPSTR("MENU_PRE")), std::bind(&AutoConnect::_token_MENU_PRE, mother, std::placeholders::_1));
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));
@@ -618,6 +641,10 @@ AutoConnectElement* AutoConnectAux::_createElement(const JsonObject& json) {
AutoConnectSelect* cert_elm = new AutoConnectSelect;
return reinterpret_cast(cert_elm);
}
+ case AC_Style: {
+ AutoConnectStyle* cert_elm = new AutoConnectStyle;
+ return reinterpret_cast(cert_elm);
+ }
case AC_Submit: {
AutoConnectSubmit* cert_elm = new AutoConnectSubmit;
return reinterpret_cast(cert_elm);
@@ -892,6 +919,7 @@ ACElement_t AutoConnectAux::_asElementType(const String& type) {
{ AUTOCONNECT_JSON_TYPE_ACINPUT, AC_Input },
{ AUTOCONNECT_JSON_TYPE_ACRADIO, AC_Radio },
{ AUTOCONNECT_JSON_TYPE_ACSELECT, AC_Select },
+ { AUTOCONNECT_JSON_TYPE_ACSTYLE, AC_Style },
{ AUTOCONNECT_JSON_TYPE_ACSUBMIT, AC_Submit },
{ AUTOCONNECT_JSON_TYPE_ACTEXT, AC_Text }
};
diff --git a/src/AutoConnectAux.h b/src/AutoConnectAux.h
index fceb7b2..e19b5b9 100644
--- a/src/AutoConnectAux.h
+++ b/src/AutoConnectAux.h
@@ -92,6 +92,7 @@ class AutoConnectAux : public PageBuilder {
void _join(AutoConnect& ac); /**< Make a link to AutoConnect */
PageElement* _setupPage(const String& uri); /**< AutoConnectAux page builder */
const String _insertElement(PageArgument& args); /**< Insert a generated HTML to the page built by PageBuilder */
+ const String _insertStyle(PageArgument& args); /**< Insert CSS style */
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 */
diff --git a/src/AutoConnectAuxImpl.h b/src/AutoConnectAuxImpl.h
index 6ee9cc3..649d302 100644
--- a/src/AutoConnectAuxImpl.h
+++ b/src/AutoConnectAuxImpl.h
@@ -133,6 +133,23 @@ AutoConnectSelectBasis& AutoConnectAux::getElement(const String& name) {
return reinterpret_cast(_nullElement());
}
+/**
+ * Get AutoConnectStyleBasis element.
+ * @param name An element name.
+ * @return A reference of AutoConnectStyle class.
+ */
+template<>
+AutoConnectStyleBasis& AutoConnectAux::getElement(const String& name) {
+ AutoConnectElement* elm = getElement(name);
+ if (elm) {
+ if (elm->typeOf() == AC_Style)
+ return *(reinterpret_cast(elm));
+ else
+ AC_DBG("Element<%s> type mismatch<%d>\n", name.c_str(), elm->typeOf());
+ }
+ return reinterpret_cast(_nullElement());
+}
+
/**
* Get AutoConnectSubmitBasis element.
* @param name An element name.
diff --git a/src/AutoConnectElement.h b/src/AutoConnectElement.h
index 4896a60..3bbcc39 100644
--- a/src/AutoConnectElement.h
+++ b/src/AutoConnectElement.h
@@ -21,6 +21,7 @@ using AutoConnectFile = AutoConnectFileJson;
using AutoConnectInput = AutoConnectInputJson;
using AutoConnectRadio = AutoConnectRadioJson;
using AutoConnectSelect = AutoConnectSelectJson;
+using AutoConnectStyle = AutoConnectStyleJson;
using AutoConnectSubmit = AutoConnectSubmitJson;
using AutoConnectText = AutoConnectTextJson;
#define AUTOCONNECT_JSON_BUFFER_SIZE 256
@@ -32,6 +33,7 @@ using AutoConnectFile = AutoConnectFileBasis;
using AutoConnectInput = AutoConnectInputBasis;
using AutoConnectRadio = AutoConnectRadioBasis;
using AutoConnectSelect = AutoConnectSelectBasis;
+using AutoConnectStyle = AutoConnectStyleBasis;
using AutoConnectSubmit = AutoConnectSubmitBasis;
using AutoConnectText = AutoConnectTextBasis;
#endif // !AUTOCONNECT_USE_JSON
@@ -49,6 +51,7 @@ using AutoConnectText = AutoConnectTextBasis;
#define ACRadio(n, ...) AutoConnectRadio n(#n, ##__VA_ARGS__)
#define ACSelect(n, ...) AutoConnectSelect n(#n, ##__VA_ARGS__)
#define ACSubmit(n, ...) AutoConnectSubmit n(#n, ##__VA_ARGS__)
+#define ACStyle(n, ...) AutoConnectStyle n(#n, ##__VA_ARGS__)
#define ACText(n, ...) AutoConnectText n(#n, ##__VA_ARGS__)
#endif // _AUTOCONNECTELEMENT_H_
diff --git a/src/AutoConnectElementBasis.h b/src/AutoConnectElementBasis.h
index 516144d..533d068 100644
--- a/src/AutoConnectElementBasis.h
+++ b/src/AutoConnectElementBasis.h
@@ -35,6 +35,7 @@ typedef enum {
AC_Input,
AC_Radio,
AC_Select,
+ AC_Style,
AC_Submit,
AC_Text,
AC_Unknown = -1
@@ -236,6 +237,19 @@ class AutoConnectSelectBasis : AC_AUTOCONNECTELEMENT_ON_VIRTUAL public AutoConne
std::vector _options; /**< List options array */
};
+/**
+ * An element class for inserting CSS in AutoConnectAux page.
+ * @param name Style name string.
+ * @param value CSS Native code.
+ */
+class AutoConnectStyleBasis : AC_AUTOCONNECTELEMENT_ON_VIRTUAL public AutoConnectElementBasis {
+ public:
+ explicit AutoConnectStyleBasis(const char* name = "", const char* value = "") : AutoConnectElementBasis(name, value, AC_Tag_None) {
+ _type = AC_Style;
+ }
+ virtual ~AutoConnectStyleBasis() {}
+};
+
/**
* Submit button arrangement class, a part of AutoConnectAux element.
* Place a submit button with a label that can be added by user sketch.
@@ -325,6 +339,13 @@ inline AutoConnectSelectBasis& AutoConnectElementBasis::as(this));
}
+template<>
+inline AutoConnectStyleBasis& AutoConnectElementBasis::as(void) {
+ if (typeOf() != AC_Style)
+ AC_DBG("%s mismatched type as <%d>\n", name.c_str(), (int)typeOf());
+ return *(reinterpret_cast(this));
+}
+
template<>
inline AutoConnectSubmitBasis& AutoConnectElementBasis::as(void) {
if (typeOf() != AC_Submit)
diff --git a/src/AutoConnectElementJson.h b/src/AutoConnectElementJson.h
index c3d8ff8..c8fb7b9 100644
--- a/src/AutoConnectElementJson.h
+++ b/src/AutoConnectElementJson.h
@@ -39,6 +39,7 @@
#define AUTOCONNECT_JSON_TYPE_ACINPUT "ACInput"
#define AUTOCONNECT_JSON_TYPE_ACRADIO "ACRadio"
#define AUTOCONNECT_JSON_TYPE_ACSELECT "ACSelect"
+#define AUTOCONNECT_JSON_TYPE_ACSTYLE "ACStyle"
#define AUTOCONNECT_JSON_TYPE_ACSUBMIT "ACSubmit"
#define AUTOCONNECT_JSON_TYPE_ACTEXT "ACText"
#define AUTOCONNECT_JSON_VALUE_BR "br"
@@ -276,6 +277,28 @@ class AutoConnectSelectJson : public AutoConnectElementJson, public AutoConnectS
void serialize(JsonObject& json) override;
};
+/**
+ * CSS style arrangement class, a part of AutoConnectAux element.
+ * This element assumes CSS that came into effect as a style code will
+ * assign. Therefore, it does not check whether the CSS error exists in
+ * the value set in AutoConnectStyle. Also, because AutoConnect inserts
+ * its style code at the end of the style block on the AutoConnectAux
+ * page, it may affect the AutoConnect web page elements.
+ * @param name A style name string.
+ * @param value CSS style code.
+ */
+class AutoConnectStyleJson : public AutoConnectElementJson, public AutoConnectStyleBasis {
+ public:
+ explicit AutoConnectStyleJson(const char* name = "", const char* value = "") {
+ AutoConnectStyleBasis::name = String(name);
+ AutoConnectStyleBasis::value = String(value);
+ AutoConnectStyleBasis::post = AC_Tag_None;
+ }
+ ~AutoConnectStyleJson() {}
+ bool loadMember(const JsonObject& json) override;
+ void serialize(JsonObject& json) override;
+};
+
/**
* Submit button arrangement class, a part of AutoConnectAux element.
* Place a submit button with a label that can be added by user sketch.
@@ -371,6 +394,13 @@ inline AutoConnectSelectJson& AutoConnectElementJson::as(
return *(reinterpret_cast(this));
}
+template<>
+inline AutoConnectStyleJson& AutoConnectElementJson::as(void) {
+ if (typeOf() != AC_Style)
+ AC_DBG("%s mismatched type as <%d>\n", name.c_str(), (int)typeOf());
+ return *(reinterpret_cast(this));
+}
+
template<>
inline AutoConnectSubmitJson& AutoConnectElementJson::as(void) {
if (typeOf() != AC_Submit)
diff --git a/src/AutoConnectElementJsonImpl.h b/src/AutoConnectElementJsonImpl.h
index 2e06cbc..f3c0647 100644
--- a/src/AutoConnectElementJsonImpl.h
+++ b/src/AutoConnectElementJsonImpl.h
@@ -404,6 +404,31 @@ void AutoConnectSelectJson::serialize(JsonObject& json) {
json[F(AUTOCONNECT_JSON_KEY_SELECTED)] = selected;
}
+/**
+ * Load an element member value from the JSON object.
+ * @param json JSON object with the definition of AutoConnectStyle.
+ * @return true AutoConnectStyle loaded
+ * @return false Type of AutoConnectStyle is mismatched.
+ */
+bool AutoConnectStyleJson::loadMember(const JsonObject& json) {
+ String type = json[F(AUTOCONNECT_JSON_KEY_TYPE)].as();
+ if (type.equalsIgnoreCase(F(AUTOCONNECT_JSON_TYPE_ACSTYLE))) {
+ _setMember(json);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Serialize AutoConnectStyle to JSON.
+ * @param json JSON object to be serialized.
+ */
+void AutoConnectStyleJson::serialize(JsonObject& json) {
+ _serialize(json);
+ json[F(AUTOCONNECT_JSON_KEY_TYPE)] = String(F(AUTOCONNECT_JSON_TYPE_ACSTYLE));
+ json[F(AUTOCONNECT_JSON_KEY_VALUE)] = value;
+}
+
/**
* Returns JSON object size.
* @return An object size for JsonBuffer.