/** * Implementation of AutoConnectElementBasis classes. * @file AutoConnectElementImpl.h * @author hieromon@gmail.com * @version 0.9.8 * @date 2019-03-11 * @copyright MIT license. */ #ifndef _AUTOCONNECTELEMENTBASISIMPL_H_ #define _AUTOCONNECTELEMENTBASISIMPL_H_ #include <stdlib.h> #include <stdio.h> #if defined(ARDUINO_ARCH_ESP8266) #include <regex.h> #elif defined(ARDUINO_ARCH_ESP32) #include <regex> #endif #include "AutoConnectElementBasis.h" /** * Generate an HTML <button> element. The onclick behavior depends on * the code held in factionf member. * @return An HTML string. */ const String AutoConnectButtonBasis::toHTML(void) const { return String(F("<button type=\"button\" name=\"")) + name + String(F("\" value=\"")) + value + String(F("\" onclick=\"")) + action + String("\">") + value + String(F("</button>")); } /** * Generate an HTML <input type=checkbox> element. * A "value" is associated with the input tag and sent by the form * action as the value of "name". If the label member is contained, it * is placed to the right side of the checkbox to be labeled. * f the label member is empty, only the checkbox is placed. * @return An HTML string. */ const String AutoConnectCheckboxBasis::toHTML(void) const { String html; html = String(F("<input type=\"checkbox\" name=\"")) + name + String(F("\" value=\"")) + value + String("\""); if (checked) html += String(F(" checked")); if (label.length()) html += String(F(" id=\"")) + name + String(F("\"><label for=\"")) + name + String("\">") + label + String(F("</label")); html += String(F("><br>")); return html; } /** * Generate an HTML <input type=file> 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("<label for=\"")) + name + String(F("\">")) + label + String(F("</label>")); html += String(F("<input type=\"file\" id=\"")) + name + String(F("\" name=\"")) + name + String(F("\"><br>")); return html; } /** * Instantiate the upload handler with the specified store type. * @param store An enumuration value of ACFile_t */ bool AutoConnectFileBasis::attach(const ACFile_t store) { AutoConnectUploadFS* handlerFS; AutoConnectUploadSD* handlerSD; // Release previous handler detach(); // Classify a handler type and create the corresponding handler switch (store) { case AC_File_FS: handlerFS = new AutoConnectUploadFS(SPIFFS); _upload.reset(reinterpret_cast<AutoConnectUploadHandler*>(handlerFS)); break; case AC_File_SD: handlerSD = new AutoConnectUploadSD(SD); _upload.reset(reinterpret_cast<AutoConnectUploadHandler*>(handlerSD)); break; case AC_File_Extern: break; } return _upload != false; } /** * Generate an HTML <input type=text> element. * If the value member is contained, it is reflected in the placeholder * attribute. 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 AutoConnectInputBasis::toHTML(void) const { String html = String(""); if (label.length()) html = String(F("<label for=\"")) + name + String("\">") + label + String(F("</label>")); html += String(F("<input type=\"text\" id=\"")) + name + String(F("\" name=\"")) + name + String("\""); if (pattern.length()) html += String(F(" pattern=\"")) + pattern + String("\""); if (placeholder.length()) html += String(F(" placeholder=\"")) + placeholder + String("\""); if (value.length()) html += String(F(" value=\"")) + value + String("\""); html += String(F("><br>")); return html; } /** * Evaluate the pattern as a regexp and return whether value matches. * Always return true if the pattern is undefined. * @return true The value matches a pattern. * @return false The value does not match a pattern. */ bool AutoConnectInputBasis::isValid(void) const { bool rc = true; if (pattern.length()) { #if defined(ARDUINO_ARCH_ESP8266) regex_t preg; if (regcomp(&preg, pattern.c_str(), REG_EXTENDED) != 0) { AC_DBG("%s regex compile failed\n", pattern.c_str()); rc = false; } else { regmatch_t p_match[1]; rc = regexec(&preg, value.c_str(), 1, p_match, 0) == 0 ? true : false; regfree(&preg); } #elif defined(ARDUINO_ARCH_ESP32) const std::regex re(pattern.c_str()); rc = std::regex_match(value.c_str(), re); #endif } return rc; } /** * Indicate an entry with the specified value in the value's collection. * @param value The value to indicates in the collection. */ void AutoConnectRadioBasis::check(const String& value) { for (std::size_t n = 0; n < _values.size(); n++) { if (at(n).equalsIgnoreCase(value)) { checked = n + 1; break; } } } /** * Clear value items of AutoConnectRadio and reallocate new storage. * All hold items are released. * @param reserve If 'reserve' is greater than 0, this function * allocates new holding storage with the value. */ void AutoConnectRadioBasis::empty(const size_t reserve) { _values.clear(); std::vector<String>().swap(_values); if (reserve) _values.reserve(reserve); } /** * 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(F("<br>")); } uint8_t n = 0; for (const String value : _values) { n++; String id = name + "_" + String(n); html += String(F("<input type=\"radio\" name=\"")) + name + String(F("\" id=\"")) + id + String(F("\" value=\"")) + value + String("\""); if (n == checked) html += String(F(" checked")); html += String(F("><label for=\"")) + id + String("\">") + value + String(F("</label>")); if (order == AC_Vertical) html += String(F("<br>")); } return html; } /** * Returns current selected value in the radio same group */ const String& AutoConnectRadioBasis::value(void) const { static const String _nullString = String(); return checked ? _values.at(checked - 1) : _nullString; } /** * Clear option items of AutoConnectSelect and reallocate new storage. * All hold items are released. * @param reserve If 'reserve' is greater than 0, this function * allocates new holding storage with the value. */ void AutoConnectSelectBasis::empty(const size_t reserve) { _options.clear(); std::vector<String>().swap(_options); if (reserve) _options.reserve(reserve); } /** * Indicate an entry with the specified value in the value's collection. * @param value The value to indicates in the collection. */ void AutoConnectSelectBasis::select(const String& value) { for (std::size_t n = 0; n < _options.size(); n++) { if (at(n).equalsIgnoreCase(value)) { selected = n + 1; break; } } } /** * Generate an HTML <select> element with an <option> element. * The attribute value of the <option> element is given to the * AutoConnectSelect class as a string array, which would be stored * in the 'options' member. If a label member is contained, the <label> * element would be generated the preface of <select>. * @return String an HTML string. */ const String AutoConnectSelectBasis::toHTML(void) const { String html = String(""); if (label.length()) html = String(F("<label for=\"")) + name + String("\">") + label + String(F("</label>")); html += String(F("<select name=\"")) + name + String(F("\" id=\"")) + name + String("\">"); uint8_t n = 1; for (const String option : _options) { html += String(F("<option value=\"")) + option + "\""; if (n++ == selected) html += String(F(" selected")); html += ">" + option + String(F("</option>")); } html += String(F("</select>")); return html; } /** * Returns current selected value in the radio same group */ const String& AutoConnectSelectBasis::value(void) const { static const String _nullString = String(); return selected ? _options.at(selected - 1) : _nullString; } /** * Generate an HTML <input type=button> element. This element is used * for form submission. An 'onclick' attribute calls fixed JavaScript * code as 'sa' named and it's included in the template. * @return String an HTML string. */ const String AutoConnectSubmitBasis::toHTML(void) const { return String(F("<input type=\"button\" name=\"")) + name + String(F("\" value=\"")) + value + String(F("\" onclick=\"_sa('")) + uri + String("')\">"); } /** * Generate an HTML text element from a string of the value member. If a style * exists, it gives a style attribute. * @return String an HTML string. */ const String AutoConnectTextBasis::toHTML(void) const { String html = String("<div"); String value_f = value; if (style.length()) html += String(F(" style=\"")) + style + String("\""); html += String(">"); if (format.length()) { int buflen = (value.length() + format.length() + 16 + 1) & (~0xf); char* buffer; if ((buffer = (char*)malloc(buflen))) { snprintf(buffer, buflen, format.c_str(), value.c_str()); value_f = String(buffer); free(buffer); } } html += value_f + String(F("</div>")); return html; } #endif // _AUTOCONNECTELEMENTBASISIMPL_H_