diff --git a/modules/web/SCsub b/modules/web/SCsub new file mode 100644 index 000000000..ac9d52bfb --- /dev/null +++ b/modules/web/SCsub @@ -0,0 +1,25 @@ +import os + +Import('env') + +module_env = env.Clone() + +sources = [ + + "register_types.cpp", + + "html/html_builder_bind.cpp", +] + +if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': + # Shared lib compilation + module_env.Append(CCFLAGS=['-fPIC']) + module_env['LIBS'] = [] + shared_lib = module_env.SharedLibrary(target='#bin/web', source=sources) + shared_lib_shim = shared_lib[0].name.rsplit('.', 1)[0] + env.Append(LIBS=[shared_lib_shim]) + env.Append(LIBPATH=['#bin']) +else: + # Static compilation + module_env.add_source_files(env.modules_sources, sources) + diff --git a/modules/web/config.py b/modules/web/config.py new file mode 100644 index 000000000..7d9e15b51 --- /dev/null +++ b/modules/web/config.py @@ -0,0 +1,22 @@ + + +def can_build(env, platform): + #return True + return False + + +def configure(env): + pass + + +def get_doc_classes(): + return [ + #"WorldArea", + + #"HTMLBuilder", + #"HTMLTag", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/web/file_cache.cpp b/modules/web/file_cache.cpp new file mode 100644 index 000000000..cef0c1fa3 --- /dev/null +++ b/modules/web/file_cache.cpp @@ -0,0 +1,135 @@ +#include "file_cache.h" + +#include "core/os/directory.h" + +#include + +void FileCache::wwwroot_register_file(const String &file_path) { + registered_files.insert(file_path); +} + +void FileCache::wwwroot_deregister_file(const String &file_path) { + registered_files.erase(file_path); +} + +bool FileCache::wwwroot_has_file(const String &file_path) { + return registered_files.find(file_path) != registered_files.end(); +} + +void FileCache::wwwroot_refresh_cache() { + _lock.write_lock(); + + registered_files.clear(); + + wwwroot.path_clean_end_slash(); + + wwwroot_evaluate_dir(wwwroot.c_str()); + + _lock.write_unlock(); +} + +void FileCache::wwwroot_evaluate_dir(const char *path, const bool should_exist) { + Ref dir; + dir.instance(); + + ERR_FAIL_COND_MSG(dir->open_dir(path) != OK, "Error opening wwwroot! folder: " + String(path)); + + while (dir->next()) { + if (dir->current_is_file()) { + String np = dir->current_get_path_cstr(); + + np = np.substr(wwwroot.size(), np.size() - wwwroot.size()); + + registered_files.insert(np); + } else { + wwwroot_evaluate_dir(dir->current_get_path_cstr()); + } + } + + dir->close_dir(); +} + +bool FileCache::get_cached_body(const String &path, String *body) { + //TODO ERROR MACRO body == null + + _lock.read_lock(); + CacheEntry *e = cache_map[path]; + _lock.read_unlock(); + + if (!e) { + return false; + } + + int64_t current_timestamp = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + int64_t diff = current_timestamp - e->timestamp; + + if (diff > cache_invalidation_time) { + return false; + } + + body->append_str(e->body); + + return true; +} + +void FileCache::set_cached_body(const String &path, const String &body) { + _lock.write_lock(); + + CacheEntry *e = cache_map[path]; + + if (!e) { + e = new CacheEntry(); + cache_map[path] = e; + } + + int64_t current_timestamp = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + e->timestamp = current_timestamp; + e->body = body; + + _lock.write_unlock(); +} + +void FileCache::clear() { + _lock.write_lock(); + + registered_files.clear(); + + for (std::map::iterator E = cache_map.begin(); E != cache_map.end(); E++) { + CacheEntry * ce = E->second; + + if (ce) { + delete ce; + } + } + + cache_map.clear(); + + _lock.write_unlock(); +} + +FileCache::FileCache(bool singleton) { + if (singleton) { + if (_instance) { + printf("FileCache: Filecache instance is set as singleton, but an another FileCache instance is already set up as singleton! Ignoring setting!\n"); + } else { + _instance = this; + } + } + + cache_invalidation_time = 1; +} + +FileCache::~FileCache() { + registered_files.clear(); + + if (_instance == this) + _instance = nullptr; +} + +FileCache *FileCache::get_singleton() { + return _instance; +} + +FileCache *FileCache::_instance = nullptr; diff --git a/modules/web/file_cache.h b/modules/web/file_cache.h new file mode 100644 index 000000000..7009e3c67 --- /dev/null +++ b/modules/web/file_cache.h @@ -0,0 +1,59 @@ +#ifndef FILE_CACHE_H +#define FILE_CACHE_H + +#include "core/string.h" + +#include +#include +#include +#include "core/threading/rw_lock.h" + +#include "core/object.h" + + +class FileCache : public Object { + RCPP_OBJECT(FileCache, Object); + +public: + String wwwroot; + int cache_invalidation_time; + + //Note: file path should be the url you want to access the file with, inculding lead slash + //e.g. http://127.0.0.1/a/b/d.jpg -> /a/b/d.jpg + void wwwroot_register_file(const String &file_path); + void wwwroot_deregister_file(const String &file_path); + bool wwwroot_has_file(const String &file_path); + void wwwroot_refresh_cache(); + void wwwroot_evaluate_dir(const char *path, const bool should_exist = true); + + bool get_cached_body(const String &path, String *body); + void set_cached_body(const String &path, const String &body); + + void clear(); + + FileCache(bool singleton = false); + virtual ~FileCache(); + + static FileCache *get_singleton(); + + std::set registered_files; + +protected: + + struct CacheEntry { + int64_t timestamp; + String body; + + CacheEntry() { + timestamp = 0; + } + }; + + RWLock _lock; + std::map cache_map; + +private: + static FileCache *_instance; +}; + +#endif \ No newline at end of file diff --git a/modules/web/html/bbcode_parser.cpp b/modules/web/html/bbcode_parser.cpp new file mode 100644 index 000000000..befff90e9 --- /dev/null +++ b/modules/web/html/bbcode_parser.cpp @@ -0,0 +1,540 @@ +#include "bbcode_parser.h" +#include "core/error_macros.h" + +bool BBCodeParserAttribute::match_attrib(const String &attrib) { + return attribute == attrib; +} +bool BBCodeParserAttribute::match_data(const String &d) { + return data == d; +} +bool BBCodeParserAttribute::match_data(const Vector &d) { + // todo + return false; +} +bool BBCodeParserAttribute::contains_data(const String &d) { + return data.find(d) != -1; +} + +String BBCodeParserAttribute::to_string() { + if (single) { + return attribute; + } + + if (data.find('"' == -1)) { + return attribute + "=\"" + data + "\""; + } else { + return attribute + "=\'" + data + "\'"; + } +} + +void BBCodeParserAttribute::print() { + to_string().print(); +} + +BBCodeParserAttribute::BBCodeParserAttribute() { + single = false; +} + +BBCodeParserAttribute::~BBCodeParserAttribute() { +} + +BBCodeParserTag *BBCodeParserTag::get_first(const String &t) { + if (tag == t) { + return this; + } + + for (int i = 0; i < tags.size(); ++i) { + BBCodeParserTag *ht = tags[i]->get_first(t); + + if (ht) { + return ht; + } + } + + return nullptr; +} + +BBCodeParserTag *BBCodeParserTag::get_first(const String &t, const String &attrib, const String &val) { + if (tag == t) { + if (has_attribute(attrib, val)) { + return this; + } + } + + for (int i = 0; i < tags.size(); ++i) { + BBCodeParserTag *ht = tags[i]->get_first(t, attrib, val); + + if (ht) { + return ht; + } + } + + return nullptr; +} + +String BBCodeParserTag::get_attribute_value(const String &attrib) { + BBCodeParserAttribute *a = get_attribute(attrib); + + if (a) { + return a->data; + } + + return ""; +} + +BBCodeParserAttribute *BBCodeParserTag::get_attribute(const String &attrib) { + for (int i = 0; i < attributes.size(); ++i) { + BBCodeParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib)) { + return a; + } + } + + return nullptr; +} + +bool BBCodeParserTag::has_attribute(const String &attrib) { + for (int i = 0; i < attributes.size(); ++i) { + BBCodeParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib)) { + return true; + } + } + + return false; +} + +BBCodeParserAttribute *BBCodeParserTag::get_attribute(const String &attrib, const String &contains_val) { + for (int i = 0; i < attributes.size(); ++i) { + BBCodeParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib) && a->contains_data(contains_val)) { + return a; + } + } + + return nullptr; +} + +bool BBCodeParserTag::has_attribute(const String &attrib, const String &contains_val) { + for (int i = 0; i < attributes.size(); ++i) { + BBCodeParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib) && a->contains_data(contains_val)) { + return true; + } + } + + return false; +} + +void BBCodeParserTag::process() { + if (type != BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_NONE) { + return; + } + + if (data.size() < 2) { + return; + } + + ERR_FAIL_COND(data[0] != '['); + ERR_FAIL_COND(data[data.size() - 1] != ']'); + + int start_index = 1; + if (data[1] == '/') { + ++start_index; + + type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_CLOSING_TAG; + } else { + String tag_text; + + if (data[data.size() - 2] == '/') { + // will catch all that looks like
+ // tags that look like
will be caught later in a post process, in a way + // which also tries to catch erroneously not closed tags that supposed to be closed + type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_SELF_CLOSING_TAG; + + tag_text = data.substr(1, data.size() - 3); + } else { + type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_OPENING_TAG; + + tag_text = data.substr(1, data.size() - 2); + } + + int fspc_index = tag_text.find(' '); + + if (fspc_index == -1) { + // no args + + int feq_ind = tag_text.find('='); + if (feq_ind == -1) { + tag = tag_text; + return; + } + + //Tag is like: [color=white] + //tag will be like color + tag = tag_text.substr(0, feq_ind); + + //Add color=white as argument + parse_args(tag_text); + + return; + } + + // grab the tag itself + tag = tag_text.substr(0, fspc_index); + + if (fspc_index + 1 == tag_text.size()) { + // no args, but had a space like
+ return; + } + + String args = tag_text.substr(fspc_index + 1, tag_text.size() - fspc_index - 1); + parse_args(args); + } + + int tag_end_index = data.find(' ', start_index); + + if (tag_end_index == -1) { + // simple tag + tag = data.substr(start_index, data.size() - start_index - 1); + return; + } +} + +void BBCodeParserTag::parse_args(const String &args) { + attributes.clear(); + + int i = 0; + while (i < args.size()) { + if (args[i] == ' ') { + //"trim" + ++i; + continue; + } + + int equals_index = args.find('=', i); + + BBCodeParserAttribute *a = new BBCodeParserAttribute(); + + if (equals_index == -1) { + a->attribute = args.substr(i, args.size() - i); + a->single = true; + attributes.push_back(a); + + return; + } + + a->attribute = args.substr(i, equals_index - i); + + // todo + // a.trim(); + + int next_char_index = equals_index + 1; + + if (next_char_index >= args.size()) { + // an attribute looks like this "... attrib=" + attributes.push_back(a); + return; + } + + // skip spaces + while (args[next_char_index] == ' ') { + ++next_char_index; + + if (next_char_index >= args.size()) { + // an attribute looks like this "... attrib= " + attributes.push_back(a); + return; + } + } + + char c = args[next_char_index]; + char find_char = ' '; + + if (c == '"' || c == '\'') { + ++next_char_index; + find_char = c; + } + + int end_index = args.find(find_char, next_char_index); + + if (end_index == -1) { + // missing closing ' or " if c is ' or " + // else missing parameter + + a->data = args.substr(next_char_index, args.size() - next_char_index); + attributes.push_back(a); + return; + } + + a->data = args.substr(next_char_index, end_index - next_char_index); + attributes.push_back(a); + + i = end_index + 1; + } +} + +String BBCodeParserTag::to_string(const int level) { + String s; + + s.append_repeat(" ", level); + + if (type == BBCODE_PARSER_TAG_TYPE_CONTENT) { + s += data + "\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!CONTENT TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == BBCODE_PARSER_TAG_TYPE_OPENING_TAG) { + int ln = level + 1; + + s += "[" + tag; + + for (int i = 0; i < attributes.size(); ++i) { + s += " " + attributes[i]->to_string(); + } + + s += "]\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(ln); + } + + s.append_repeat(" ", level); + + s += "[/" + tag + "]\n"; + } else if (type == BBCODE_PARSER_TAG_TYPE_CLOSING_TAG) { + // BBCodeParserTag should handle this automatically + // it's here for debugging purposes though + s += "[/" + tag + "(!)]"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!CLOSING TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == BBCODE_PARSER_TAG_TYPE_SELF_CLOSING_TAG) { + s += "[" + tag; + + for (int i = 0; i < attributes.size(); ++i) { + s += " " + attributes[i]->to_string(); + } + + s += "/]\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == BBCODE_PARSER_TAG_TYPE_NONE) { + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level) + "\n"; + s.append_repeat(" ", level); + } + } + + return s; +} +void BBCodeParserTag::print() { + to_string().print(); +} + +BBCodeParserTag::BBCodeParserTag() { + type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_NONE; +} + +BBCodeParserTag::~BBCodeParserTag() { + for (int i = 0; i < tags.size(); ++i) { + delete tags[i]; + } + + for (int i = 0; i < attributes.size(); ++i) { + delete attributes[i]; + } +} + +void BBCodeParser::parse(const String &data) { + Vector tags; + + // split into tags + for (int i = 0; i < data.size(); ++i) { + if (data[i] == '[') { + // tag + for (int j = i + 1; j < data.size(); ++j) { + if (data[j] == ']') { + BBCodeParserTag *t = new BBCodeParserTag(); + + t->data = data.substr(i, j - i + 1); + t->process(); + + tags.push_back(t); + + i = j; + break; + } + } + } else { + // content + + for (int j = i + 1; j < data.size(); ++j) { + if (data[j] == '[') { + BBCodeParserTag *t = new BBCodeParserTag(); + + t->data = data.substr(i, j - i); + t->type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_CONTENT; + + tags.push_back(t); + + i = j - 1; + break; + } + } + } + } + + if (root) { + delete root; + } + + root = new BBCodeParserTag(); + + // process tags into hierarchical order + Vector tag_stack; + for (int i = 0; i < tags.size(); ++i) { + BBCodeParserTag *t = tags[i]; + + if (t == nullptr) { + RLOG_ERR("BBCodeParser::parse: t == nullptr!"); + continue; + } + + if (t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_NONE) { + RLOG_ERR("BBCodeParser::parse: t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_NONE!"); + delete t; + tags[i] = nullptr; + continue; + } else if (t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_OPENING_TAG) { + tag_stack.push_back(t); + + tags[i] = nullptr; + continue; + } else if (t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_SELF_CLOSING_TAG) { + if (tag_stack.size() == 0) { + root->tags.push_back(t); + } else { + tag_stack[tag_stack.size() - 1]->tags.push_back(t); + } + + tags[i] = nullptr; + continue; + } else if (t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_CONTENT) { + if (tag_stack.size() == 0) { + root->tags.push_back(t); + } else { + tag_stack[tag_stack.size() - 1]->tags.push_back(t); + } + + tags[i] = nullptr; + continue; + } else if (t->type == BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_CLOSING_TAG) { + if (tag_stack.size() == 0) { + delete t; + tags[i] = nullptr; + + // ill-formed html + continue; + } + + // find it's pair + int tag_index = 0; + for (int j = tag_stack.size() - 1; j > 0; --j) { + BBCodeParserTag *ts = tag_stack[j]; + + // we sould only have opening tags on the stack + if (ts->tag == t->tag) { + // found + tag_index = j; + break; + } + } + + BBCodeParserTag *opening_tag = tag_stack[tag_index]; + + // mark everything else that we found before finding the opening tag as self closing, and add them to out opening tag + // If the html is ill formed, it just grabs everything from the tag stack + for (int j = tag_index + 1; j < tag_stack.size(); ++j) { + BBCodeParserTag *ts = tag_stack[j]; + + ts->type = BBCodeParserTag::BBCODE_PARSER_TAG_TYPE_SELF_CLOSING_TAG; + opening_tag->tags.push_back(ts); + } + + tag_stack.resize(tag_index); + + if (tag_stack.size() == 0) { + root->tags.push_back(opening_tag); + } else { + tag_stack[tag_stack.size() - 1]->tags.push_back(opening_tag); + } + + delete t; + tags[i] = nullptr; + + continue; + } + } + + // add everything remaining on the stack to root + for (int i = 0; i < tag_stack.size(); ++i) { + root->tags.push_back(tag_stack[i]); + } + + for (int i = 0; i < tags.size(); ++i) { + BBCodeParserTag *t = tags[i]; + + if (t != nullptr) { + RLOG_ERR("BBCodeParser::parse(const String &data): tag was not processed!\n"); + t->print(); + + delete t; + } + } +} + +String BBCodeParser::to_string() { + if (!root) { + return ""; + } + + return root->to_string(); +} +void BBCodeParser::print() { + if (root) { + root->print(); + } +} + +BBCodeParser::BBCodeParser() { + root = nullptr; +} + +BBCodeParser::~BBCodeParser() { + if (root) { + delete root; + } +} diff --git a/modules/web/html/bbcode_parser.h b/modules/web/html/bbcode_parser.h new file mode 100644 index 000000000..a0a0005d4 --- /dev/null +++ b/modules/web/html/bbcode_parser.h @@ -0,0 +1,78 @@ +#ifndef BBCODE_PARSER_H +#define BBCODE_PARSER_H + +#include "core/containers/vector.h" +#include "core/string.h" + +class BBCodeParserAttribute { +public: + String attribute; + String data; + bool single; + + bool match_attrib(const String &attrib); + bool match_data(const String &d); + bool match_data(const Vector &d); + bool contains_data(const String &d); + + String to_string(); + void print(); + + BBCodeParserAttribute(); + virtual ~BBCodeParserAttribute(); +}; + +class BBCodeParserTag { +public: + enum BBCodeParserTagType { + BBCODE_PARSER_TAG_TYPE_NONE = 0, + BBCODE_PARSER_TAG_TYPE_OPENING_TAG, + BBCODE_PARSER_TAG_TYPE_CLOSING_TAG, + BBCODE_PARSER_TAG_TYPE_SELF_CLOSING_TAG, + BBCODE_PARSER_TAG_TYPE_CONTENT + }; + + int type; + + String tag; + String data; + + Vector tags; + Vector attributes; + + BBCodeParserTag *get_first(const String &t); + BBCodeParserTag *get_first(const String &t, const String &attrib, const String &val); + + String get_attribute_value(const String &attrib); + + BBCodeParserAttribute *get_attribute(const String &attrib); + bool has_attribute(const String &attrib); + + BBCodeParserAttribute *get_attribute(const String &attrib, const String &contains_val); + bool has_attribute(const String &attrib, const String &contains_val); + + void process(); + void parse_args(const String &args); + + String to_string(const int level = 0); + void print(); + + BBCodeParserTag(); + virtual ~BBCodeParserTag(); +}; + +class BBCodeParser { +public: + BBCodeParserTag *root; + + void parse(const String &data); + //void parse_tag(const String &data, const int index); + + String to_string(); + void print(); + + BBCodeParser(); + virtual ~BBCodeParser(); +}; + +#endif \ No newline at end of file diff --git a/modules/web/html/form_validator.cpp b/modules/web/html/form_validator.cpp new file mode 100644 index 000000000..ce4dd7751 --- /dev/null +++ b/modules/web/html/form_validator.cpp @@ -0,0 +1,535 @@ +#include "form_validator.h" + +#include "web/http/request.h" + +//FormFieldEntry + +bool FormFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + return true; +} + +FormFieldEntry::FormFieldEntry() { +} + +FormFieldEntry::~FormFieldEntry() { +} + +//FormExistsFieldEntry + +bool FormExistsFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data == "") { + if (errors) { + errors->push_back(field->human_name + not_exists_error); + } + + return false; + } + + return true; +} + +FormExistsFieldEntry::FormExistsFieldEntry() { + not_exists_error = " field need to exists!"; +} +FormExistsFieldEntry::~FormExistsFieldEntry() { +} + +//FormIntFieldEntry + +bool FormIntFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + //https://stackoverflow.com/questions/2844817/how-do-i-check-if-a-c-string-is-an-int + + if (data.empty()) { + return true; + } + + if (((!isdigit(data[0])) && (data[0] != '-') && (data[0] != '+'))) { + if (errors) { + errors->push_back(field->human_name + not_int_error); + } + + return false; + } + + char *p; + strtol(data.c_str(), &p, 10); + + bool is_int = (*p == 0); + + if (!is_int) { + if (errors) { + errors->push_back(field->human_name + not_int_error); + } + } + + return is_int; +} + +FormIntFieldEntry::FormIntFieldEntry() { + not_int_error = " needs to be an integer."; +} + +FormIntFieldEntry::~FormIntFieldEntry() { +} + +//FormFloatFieldEntry + +bool FormFloatFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data.empty()) { + return true; + } + + //from https://stackoverflow.com/questions/447206/c-isfloat-function + char *ptr; + strtof(data.c_str(), &ptr); + bool is_float = (*ptr) == '\0'; + + if (!is_float) { + if (errors) { + errors->push_back(field->human_name + not_float_error); + } + } + + return is_float; +} + +FormFloatFieldEntry::FormFloatFieldEntry() { + not_float_error = " needs to be an floating point number."; +} +FormFloatFieldEntry::~FormFloatFieldEntry() { +} + +//FormAlphaFieldEntry + +bool FormAlphaFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + for (int i = 0; i < data.size(); ++i) { + if (!isalpha(data[i])) { + if (errors) { + errors->push_back(field->human_name + not_alpha_error); + } + + return false; + } + } + + return true; +} + +FormAlphaFieldEntry::FormAlphaFieldEntry() { + not_alpha_error = " needs to only contain caharcters."; +} +FormAlphaFieldEntry::~FormAlphaFieldEntry() { +} + +//FormAlphaNumericFieldEntry + +bool FormAlphaNumericFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + for (int i = 0; i < data.size(); ++i) { + if (!isalnum(data[i])) { + if (errors) { + errors->push_back(field->human_name + not_alpha_numeric_error); + } + + return false; + } + } + + return true; +} + +FormAlphaNumericFieldEntry::FormAlphaNumericFieldEntry() { + not_alpha_numeric_error = " needs to only contain caharcters of numbers."; +} +FormAlphaNumericFieldEntry::~FormAlphaNumericFieldEntry() { +} + +//FormNeedsLowercaseCharacterFieldEntry + +bool FormNeedsLowercaseCharacterFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + for (int i = 0; i < data.size(); ++i) { + if (islower(data[i])) { + + return true; + } + } + + if (errors) { + errors->push_back(field->human_name + does_not_have_lowercase_error); + } + + return false; +} + +FormNeedsLowercaseCharacterFieldEntry::FormNeedsLowercaseCharacterFieldEntry() { + does_not_have_lowercase_error = " needs at least one lowercase character!"; +} +FormNeedsLowercaseCharacterFieldEntry::~FormNeedsLowercaseCharacterFieldEntry() { +} + +//FormNeedsUppercaseCharacterFieldEntry + +bool FormNeedsUppercaseCharacterFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + for (int i = 0; i < data.size(); ++i) { + if (isupper(data[i])) { + return true; + } + } + + if (errors) { + errors->push_back(field->human_name + does_not_have_uppercase_error); + } + + return false; +} + +FormNeedsUppercaseCharacterFieldEntry::FormNeedsUppercaseCharacterFieldEntry() { + does_not_have_uppercase_error = " needs at least one uppercase character!"; +} +FormNeedsUppercaseCharacterFieldEntry::~FormNeedsUppercaseCharacterFieldEntry() { +} + +//FormNeedsOtherCharacterFieldEntry + +bool FormNeedsOtherCharacterFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + for (int i = 0; i < data.size(); ++i) { + if (!isalnum(data[i])) { + return true; + } + } + + if (errors) { + errors->push_back(field->human_name + does_not_have_other_error); + } + + return false; +} + +FormNeedsOtherCharacterFieldEntry::FormNeedsOtherCharacterFieldEntry() { + does_not_have_other_error = " needs at least one other character!"; +} +FormNeedsOtherCharacterFieldEntry::~FormNeedsOtherCharacterFieldEntry() { +} + +//FormMinimumLengthFieldEntry + +bool FormMinimumLengthFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data.size() < min_length) { + if (errors) { + errors->push_back(field->human_name + does_not_have_min_length_errorf + min_length + does_not_have_min_length_errors); + } + + return false; + } + + return true; +} + +FormMinimumLengthFieldEntry::FormMinimumLengthFieldEntry() { + does_not_have_min_length_errorf = " needs at least "; + does_not_have_min_length_errors = " characters!"; + + min_length = 5; +} +FormMinimumLengthFieldEntry::~FormMinimumLengthFieldEntry() { +} + +//FormMaximumLengthFieldEntry + +bool FormMaximumLengthFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data.size() > max_length) { + if (errors) { + errors->push_back(field->human_name + does_not_have_max_length_errorf + max_length + does_not_have_max_length_errors); + } + + return false; + } + + return true; +} + +FormMaximumLengthFieldEntry::FormMaximumLengthFieldEntry() { + does_not_have_max_length_errorf = " needs at most "; + does_not_have_max_length_errors = " characters!"; + + max_length = 10; +} +FormMaximumLengthFieldEntry::~FormMaximumLengthFieldEntry() { +} + +//FormEmailFieldEntry + +bool FormEmailFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data.size() == 0) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + if (!isalpha(data[0])) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + int dot_pos = -1; + int at_pos = -1; + + for (int i = 0; i < data.size(); ++i) { + if (data[i] == '.') { + if (dot_pos != -1) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + dot_pos = i; + + return true; + } + } + + if (dot_pos == -1) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + for (int i = 0; i < data.size(); ++i) { + if (data[i] == '@') { + if (at_pos != -1) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + at_pos = i; + + return true; + } + } + + if (at_pos == -1) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + + for (int i = 0; i < data.size(); ++i) { + if (i == at_pos || i == dot_pos) { + continue; + } + + if (!isalnum(data[i])) { + if (errors) { + errors->push_back(field->human_name + email_format_error); + } + + return false; + } + } + + return true; +} + +FormEmailFieldEntry::FormEmailFieldEntry() { + email_format_error = " is invalid!"; +} +FormEmailFieldEntry::~FormEmailFieldEntry() { +} + +//FormNeedToMatchOtherFieldEntry + +bool FormNeedToMatchOtherFieldEntry::validate(Request *request, const FormField *field, const String &data, Vector *errors) { + if (data != request->get_parameter(other_field)) { + if (errors) { + errors->push_back(field->human_name + does_not_match_error + field->name + "."); + } + + return false; + } + + return true; +} + +FormNeedToMatchOtherFieldEntry::FormNeedToMatchOtherFieldEntry() { + does_not_match_error = " does not match "; +} +FormNeedToMatchOtherFieldEntry::~FormNeedToMatchOtherFieldEntry() { +} + +//FormField + +FormField *FormField::need_to_exist() { + add_entry(new FormExistsFieldEntry()); + + return this; +} +FormField *FormField::need_to_be_int() { + add_entry(new FormIntFieldEntry()); + + return this; +} +FormField *FormField::need_to_be_float() { + add_entry(new FormFloatFieldEntry()); + + return this; +} +FormField *FormField::need_to_be_alpha() { + add_entry(new FormAlphaFieldEntry()); + + return this; +} +FormField *FormField::need_to_be_alpha_numeric() { + add_entry(new FormAlphaNumericFieldEntry()); + + return this; +} +FormField *FormField::need_to_have_lowercase_character() { + add_entry(new FormNeedsLowercaseCharacterFieldEntry()); + + return this; +} +FormField *FormField::need_to_have_uppercase_character() { + add_entry(new FormNeedsUppercaseCharacterFieldEntry()); + + return this; +} +FormField *FormField::need_to_have_other_character() { + add_entry(new FormNeedsOtherCharacterFieldEntry()); + + return this; +} +FormField *FormField::need_minimum_length(const int min_length) { + FormMinimumLengthFieldEntry *f = new FormMinimumLengthFieldEntry(); + f->min_length = min_length; + add_entry(f); + + return this; +} +FormField *FormField::need_maximum_length(const int max_length) { + FormMaximumLengthFieldEntry *f = new FormMaximumLengthFieldEntry(); + f->max_length = max_length; + add_entry(f); + + return this; +} +FormField *FormField::need_to_be_email() { + add_entry(new FormEmailFieldEntry()); + + return this; +} + +FormField *FormField::need_to_match(const String &other) { + FormNeedToMatchOtherFieldEntry *f = new FormNeedToMatchOtherFieldEntry(); + f->other_field = other; + add_entry(f); + + return this; +} + +FormField *FormField::ignore_if_not_exists() { + _ignore_if_not_exists = true; + + return this; +} + +FormField *FormField::ignore_if_other_field_not_exists(const String &other) { + _ignore_if_other_field_not_exists = true; + _ignore_if_other_field_not_exist_field = other; + + return this; +} + +void FormField::add_entry(FormFieldEntry *field) { + fields.push_back(field); +} + +bool FormField::validate(Request *request, Vector *errors) { + String param = request->get_parameter(name); + + if (_ignore_if_not_exists && param == "") { + return true; + } + + if (_ignore_if_other_field_not_exists) { + String op = request->get_parameter(_ignore_if_other_field_not_exist_field); + + if (op == "") { + return true; + } + } + + bool valid = true; + + for (int i = 0; i < fields.size(); ++i) { + if (!fields[i]->validate(request, this, param, errors)) { + valid = false; + } + } + + return valid; +} + +FormField::FormField() { + _ignore_if_not_exists = false; + _ignore_if_other_field_not_exists = false; +} +FormField::~FormField() { + for (int i = 0; i < fields.size(); ++i) { + delete fields[i]; + } + + fields.clear(); +} + +//FormValidator + +bool FormValidator::validate(Request *request, Vector *errors) { + bool valid = true; + + for (int i = 0; i < fields.size(); ++i) { + + if (!fields[i]->validate(request, errors)) { + valid = false; + } + } + + return valid; +} + +void FormValidator::add_field(FormField *field) { + fields.push_back(field); +} + +FormField *FormValidator::new_field(const String &name, const String &human_name) { + FormField *f = new FormField(); + f->name = name; + f->human_name = human_name; + + fields.push_back(f); + + return f; +} + +FormValidator::FormValidator() { +} + +FormValidator::~FormValidator() { + for (int i = 0; i < fields.size(); ++i) { + delete fields[i]; + } + + fields.clear(); +} diff --git a/modules/web/html/form_validator.h b/modules/web/html/form_validator.h new file mode 100644 index 000000000..616807837 --- /dev/null +++ b/modules/web/html/form_validator.h @@ -0,0 +1,200 @@ +#ifndef FORM_H +#define FORM_H + +#include "core/string.h" +#include "core/containers/vector.h" + +#include + +class Request; +class FormField; + +class FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormFieldEntry(); + virtual ~FormFieldEntry(); +}; + +class FormExistsFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormExistsFieldEntry(); + ~FormExistsFieldEntry(); + + String not_exists_error; +}; + +class FormIntFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormIntFieldEntry(); + ~FormIntFieldEntry(); + + String not_int_error; +}; + +class FormFloatFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormFloatFieldEntry(); + ~FormFloatFieldEntry(); + + String not_float_error; +}; + +class FormAlphaFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormAlphaFieldEntry(); + ~FormAlphaFieldEntry(); + + String not_alpha_error; +}; + +class FormAlphaNumericFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormAlphaNumericFieldEntry(); + ~FormAlphaNumericFieldEntry(); + + String not_alpha_numeric_error; +}; + +class FormNeedsLowercaseCharacterFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormNeedsLowercaseCharacterFieldEntry(); + ~FormNeedsLowercaseCharacterFieldEntry(); + + String does_not_have_lowercase_error; +}; + +class FormNeedsUppercaseCharacterFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormNeedsUppercaseCharacterFieldEntry(); + ~FormNeedsUppercaseCharacterFieldEntry(); + + String does_not_have_uppercase_error; +}; + +class FormNeedsOtherCharacterFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormNeedsOtherCharacterFieldEntry(); + ~FormNeedsOtherCharacterFieldEntry(); + + String does_not_have_other_error; +}; + +class FormMinimumLengthFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormMinimumLengthFieldEntry(); + ~FormMinimumLengthFieldEntry(); + + int min_length; + + String does_not_have_min_length_errorf; + String does_not_have_min_length_errors; +}; + +class FormMaximumLengthFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormMaximumLengthFieldEntry(); + ~FormMaximumLengthFieldEntry(); + + int max_length; + + String does_not_have_max_length_errorf; + String does_not_have_max_length_errors; +}; + +class FormEmailFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormEmailFieldEntry(); + ~FormEmailFieldEntry(); + + String email_format_error; +}; + +class FormNeedToMatchOtherFieldEntry : public FormFieldEntry { +public: + virtual bool validate(Request *request, const FormField* field, const String &data, Vector *errors); + + FormNeedToMatchOtherFieldEntry(); + ~FormNeedToMatchOtherFieldEntry(); + + String other_field; + + String does_not_match_error; +}; + +//FormField + +class FormField { +public: + String name; + String human_name; + + bool _ignore_if_not_exists; + + bool _ignore_if_other_field_not_exists; + String _ignore_if_other_field_not_exist_field; + + FormField *need_to_exist(); + FormField *need_to_be_int(); + FormField *need_to_be_float(); + FormField *need_to_be_alpha(); + FormField *need_to_be_alpha_numeric(); + FormField *need_to_have_lowercase_character(); + FormField *need_to_have_uppercase_character(); + FormField *need_to_have_other_character(); + FormField *need_minimum_length(const int min_length); + FormField *need_maximum_length(const int max_length); + FormField *need_to_be_email(); + FormField *need_to_match(const String &other); + FormField *ignore_if_not_exists(); + FormField *ignore_if_other_field_not_exists(const String &other); + + void add_entry(FormFieldEntry *field); + + bool validate(Request *request, Vector *errors); + + FormField(); + virtual ~FormField(); + + Vector fields; +}; + +//FormValidator + +class FormValidator { +public: + bool validate(Request *request, Vector *errors = nullptr); + + void add_field(FormField *field); + FormField *new_field(const String &name, const String &human_name); + + FormValidator(); + virtual ~FormValidator(); + + Vector fields; +}; + +#endif \ No newline at end of file diff --git a/modules/web/html/html_builder.cpp b/modules/web/html/html_builder.cpp new file mode 100644 index 000000000..7af0c8ffd --- /dev/null +++ b/modules/web/html/html_builder.cpp @@ -0,0 +1,3422 @@ +#include "html_builder.h" +#include "core/string.h" + +#include "web/http/request.h" + +HTMLTag *HTMLTag::str(const String &str) { + result += " " + str; + + return this; +} + +HTMLTag *HTMLTag::style(const String &val) { + attrib("style", val); + + return this; +} + +HTMLTag *HTMLTag::href(const String &val) { + attrib("href", val); + + return this; +} + +HTMLTag *HTMLTag::cls(const String &val) { + attrib("class", val); + + return this; +} + +HTMLTag *HTMLTag::clsse(const String &val) { + if (val == "") { + return this; + } + + attrib("class", val); + + return this; +} + +HTMLTag *HTMLTag::id(const String &val) { + attrib("id", val); + + return this; +} + +HTMLTag *HTMLTag::name(const String &val) { + attrib("name", val); + + return this; +} + +HTMLTag *HTMLTag::content(const String &val) { + attrib("content", val); + + return this; +} + +HTMLTag *HTMLTag::value(const String &val) { + attrib("value", val); + + return this; +} + +HTMLTag *HTMLTag::accept(const String &val) { + attrib("accept", val); + + return this; +} + +HTMLTag *HTMLTag::src(const String &val) { + attrib("src", val); + + return this; +} + +HTMLTag *HTMLTag::alt(const String &val) { + attrib("alt", val); + + return this; +} + +HTMLTag *HTMLTag::autocomplete(const String &val) { + attrib("autocomplete", val); + + return this; +} + +HTMLTag *HTMLTag::autocomplete_off() { + attrib("autocomplete", "off"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_on() { + attrib("autocomplete", "on"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name() { + attrib("autocomplete", "name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_honorific_prefix() { + attrib("autocomplete", "honorific-prefix"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_given_name() { + attrib("autocomplete", "given-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_additional_name() { + attrib("autocomplete", "additional-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_family_name() { + attrib("autocomplete", "family-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_honorific_suffix() { + attrib("autocomplete", "honorific-suffix"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_name_nickname() { + attrib("autocomplete", "nickname"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_email() { + attrib("autocomplete", "email"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_username() { + attrib("autocomplete", "username"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_new_password() { + attrib("autocomplete", "new-password"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_current_password() { + attrib("autocomplete", "current-password"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_one_time_code() { + attrib("autocomplete", "one-time-code"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_organization_title() { + attrib("autocomplete", "organization-title"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_organization() { + attrib("autocomplete", "organization"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_street_address() { + attrib("autocomplete", "street-address"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_line1() { + attrib("autocomplete", "address-line1"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_line2() { + attrib("autocomplete", "address-line2"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_line3() { + attrib("autocomplete", "address-line3"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_level_1() { + attrib("autocomplete", "address-level1"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_level_2() { + attrib("autocomplete", "address-level2"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_level_3() { + attrib("autocomplete", "address-level3"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_address_level_4() { + attrib("autocomplete", "address-level4"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_country() { + attrib("autocomplete", "country"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_country_name() { + attrib("autocomplete", "country-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_postal_code() { + attrib("autocomplete", "postal-code"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_name() { + attrib("autocomplete", "cc-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_given_name() { + attrib("autocomplete", "cc-given-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_additional_name() { + attrib("autocomplete", "cc-additional-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_family_name() { + attrib("autocomplete", "cc-family-name"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_number() { + attrib("autocomplete", "cc-number"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_exp() { + attrib("autocomplete", "cc-exp"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_exp_month() { + attrib("autocomplete", "cc-exp-month"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_exp_year() { + attrib("autocomplete", "cc-exp-year"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_csc() { + attrib("autocomplete", "cc-csc"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_cc_type() { + attrib("autocomplete", "cc-type"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_transaction_currency() { + attrib("autocomplete", "transaction-currency"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_transaction_amount() { + attrib("autocomplete", "transaction-amount"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_language() { + attrib("autocomplete", "language"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_bday() { + attrib("autocomplete", "bday"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_bday_day() { + attrib("autocomplete", "bday-day"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_bday_month() { + attrib("autocomplete", "bday-month"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_bday_year() { + attrib("autocomplete", "bday-year"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_sex() { + attrib("autocomplete", "sex"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel() { + attrib("autocomplete", "tel"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel_country_code() { + attrib("autocomplete", "tel-country-code"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel_national() { + attrib("autocomplete", "tel-national"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel_area_code() { + attrib("autocomplete", "tel-area-code"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel_local() { + attrib("autocomplete", "tel-local"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_tel_extension() { + attrib("autocomplete", "tel-extension"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_impp() { + attrib("autocomplete", "impp"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_url() { + attrib("autocomplete", "url"); + + return this; +} +HTMLTag *HTMLTag::autocomplete_photo() { + attrib("autocomplete", "photo"); + + return this; +} + +HTMLTag *HTMLTag::onclick(const String &val) { + attrib("onclick", val); + + return this; +} + +HTMLTag *HTMLTag::inputmode(const String &val) { + attrib("inputmode", val); + + return this; +} + +HTMLTag *HTMLTag::list(const String &val) { + attrib("list", val); + + return this; +} + +HTMLTag *HTMLTag::checked(const bool val) { + if (val) { + result += " checked"; + } + + return this; +} + +HTMLTag *HTMLTag::selected(const bool val) { + if (val) { + result += " selected"; + } + + return this; +} + +HTMLTag *HTMLTag::autofocus(const bool val) { + if (val) { + result += " autofocus"; + } + + return this; +} + +HTMLTag *HTMLTag::disabled(const bool val) { + if (val) { + result += " disabled"; + } + + return this; +} + +HTMLTag *HTMLTag::multiple(const bool val) { + if (val) { + result += " multiple"; + } + + return this; +} + +HTMLTag *HTMLTag::required(const bool val) { + if (val) { + result += " required"; + } + + return this; +} + +HTMLTag *HTMLTag::spellcheck(const bool val) { + if (val) { + attrib("spellcheck", "true"); + } else { + attrib("spellcheck", "false"); + } + + return this; +} + +HTMLTag *HTMLTag::max(const String &val) { + attrib("max", val); + + return this; +} + +HTMLTag *HTMLTag::min(const String &val) { + attrib("min", val); + + return this; +} + +HTMLTag *HTMLTag::step(const String &val) { + attrib("step", val); + + return this; +} +HTMLTag *HTMLTag::step_any() { + attrib("step", "any"); + + return this; +} + +HTMLTag *HTMLTag::minlength(const int val) { + attrib("minlength", String::num(val)); + + return this; +} +HTMLTag *HTMLTag::minlength(const String &val) { + attrib("minlength", val); + + return this; +} +HTMLTag *HTMLTag::maxlength(const int val) { + attrib("maxlength", String::num(val)); + + return this; +} +HTMLTag *HTMLTag::maxlength(const String &val) { + attrib("maxlength", val); + + return this; +} +HTMLTag *HTMLTag::size(const int val) { + attrib("size", String::num(val)); + + return this; +} +HTMLTag *HTMLTag::size(const String &val) { + attrib("size", val); + + return this; +} + +HTMLTag *HTMLTag::width(const int val) { + attrib("width", String::num(val)); + + return this; +} + +HTMLTag *HTMLTag::width(const String &val) { + attrib("width", val); + + return this; +} + +HTMLTag *HTMLTag::height(const int val) { + attrib("height", String::num(val)); + + return this; +} + +HTMLTag *HTMLTag::height(const String &val) { + attrib("height", val); + + return this; +} + +HTMLTag *HTMLTag::pattern(const String &val) { + attrib("pattern", val); + + return this; +} + +HTMLTag *HTMLTag::method(const String &val) { + attrib("method", val); + + return this; +} + +HTMLTag *HTMLTag::method_get() { + attrib("method", "get"); + + return this; +} +HTMLTag *HTMLTag::method_post() { + attrib("method", "post"); + + return this; +} + +HTMLTag *HTMLTag::action(const String &val) { + attrib("action", val); + + return this; +} + +HTMLTag *HTMLTag::type(const String &val) { + attrib("type", val); + + return this; +} + +HTMLTag *HTMLTag::placeholder(const String &val) { + attrib("placeholder", val); + + return this; +} + +HTMLTag *HTMLTag::fora(const String &val) { + attrib("for", val); + + return this; +} + +HTMLTag *HTMLTag::rel(const String &val) { + attrib("rel", val); + + return this; +} + +HTMLTag *HTMLTag::rel_stylesheet() { + attrib("rel", "stylesheet"); + + return this; +} + +HTMLTag *HTMLTag::rel_alternate() { + attrib("rel", "alternate"); + + return this; +} + +HTMLTag *HTMLTag::rel_author() { + attrib("rel", "author"); + + return this; +} + +HTMLTag *HTMLTag::rel_bookmark() { + attrib("rel", "bookmark"); + + return this; +} + +HTMLTag *HTMLTag::rel_external() { + attrib("rel", "external"); + + return this; +} + +HTMLTag *HTMLTag::rel_help() { + attrib("rel", "help"); + + return this; +} + +HTMLTag *HTMLTag::rel_next() { + attrib("rel", "next"); + + return this; +} + +HTMLTag *HTMLTag::rel_nofollow() { + attrib("rel", "nofollow"); + + return this; +} + +HTMLTag *HTMLTag::rel_noopener() { + attrib("rel", "noopener"); + + return this; +} + +HTMLTag *HTMLTag::rel_noreferrer() { + attrib("rel", "noreferrer"); + + return this; +} + +HTMLTag *HTMLTag::rel_prev() { + attrib("rel", "prev"); + + return this; +} + +HTMLTag *HTMLTag::rel_search() { + attrib("rel", "search"); + + return this; +} + +HTMLTag *HTMLTag::rel_tag() { + attrib("rel", "tag"); + + return this; +} + +HTMLTag *HTMLTag::charset(const String &val) { + attrib("charset", val); + + return this; +} + +HTMLTag *HTMLTag::charset_utf_8() { + attrib("charset", "utf-8"); + + return this; +} + +HTMLTag *HTMLTag::itbutton() { + attrib("type", "button"); + + return this; +} +HTMLTag *HTMLTag::itcheckbox() { + attrib("type", "checkbox"); + + return this; +} +HTMLTag *HTMLTag::itcolor() { + attrib("type", "color"); + + return this; +} +HTMLTag *HTMLTag::itdate() { + attrib("type", "date"); + + return this; +} +HTMLTag *HTMLTag::itdatetime_local() { + attrib("type", "datetime_local"); + + return this; +} +HTMLTag *HTMLTag::itemail() { + attrib("type", "email"); + + return this; +} +HTMLTag *HTMLTag::itfile() { + attrib("type", "file"); + + return this; +} +HTMLTag *HTMLTag::ithidden() { + attrib("type", "hidden"); + + return this; +} +HTMLTag *HTMLTag::itimage() { + attrib("type", "image"); + + return this; +} +HTMLTag *HTMLTag::itmonth() { + attrib("type", "month"); + + return this; +} +HTMLTag *HTMLTag::itnumber() { + attrib("type", "number"); + + return this; +} +HTMLTag *HTMLTag::itpassword() { + attrib("type", "password"); + + return this; +} +HTMLTag *HTMLTag::itradio() { + attrib("type", "radio"); + + return this; +} +HTMLTag *HTMLTag::itrange() { + attrib("type", "range"); + + return this; +} +HTMLTag *HTMLTag::itreset() { + attrib("type", "reset"); + + return this; +} +HTMLTag *HTMLTag::itsearch() { + attrib("type", "search"); + + return this; +} +HTMLTag *HTMLTag::itsubmit() { + attrib("type", "submit"); + + return this; +} +HTMLTag *HTMLTag::ittel() { + attrib("type", "tel"); + + return this; +} +HTMLTag *HTMLTag::ittext() { + attrib("type", "text"); + + return this; +} +HTMLTag *HTMLTag::ittime() { + attrib("type", "time"); + + return this; +} +HTMLTag *HTMLTag::iturl() { + attrib("type", "url"); + + return this; +} +HTMLTag *HTMLTag::itweek() { + attrib("type", "week"); + + return this; +} + +HTMLTag *HTMLTag::inputmode_none() { + attrib("inputmode", "none"); + + return this; +} +HTMLTag *HTMLTag::inputmode_text() { + attrib("inputmode", "text"); + + return this; +} +HTMLTag *HTMLTag::inputmode_decimal() { + attrib("inputmode", "decimal"); + + return this; +} +HTMLTag *HTMLTag::inputmode_numeric() { + attrib("inputmode", "numeric"); + + return this; +} +HTMLTag *HTMLTag::inputmode_tel() { + attrib("inputmode", "tel"); + + return this; +} +HTMLTag *HTMLTag::inputmode_search() { + attrib("inputmode", "search"); + + return this; +} +HTMLTag *HTMLTag::inputmode_email() { + attrib("inputmode", "email"); + + return this; +} +HTMLTag *HTMLTag::inputmode_url() { + attrib("inputmode", "url"); + + return this; +} + +HTMLTag *HTMLTag::attrib(const String &attr, const String &val) { + result += " " + attr + "=\"" + val + "\""; + + return this; +} + +HTMLTag *HTMLTag::start(const String &p_tag, const bool p_simple) { + simple = p_simple; + + result = "<" + p_tag; + + return this; +} + +HTMLTag *HTMLTag::reset() { + result.clear(); + + return this; +} + +HTMLTag *HTMLTag::close() { + if (simple) + result += "/>"; + else + result += ">"; + + return this; +} + +HTMLBuilder *HTMLTag::f() { + return owner; +} + +bool HTMLTag::has_data() { + return result.size() > 0; +} + +HTMLTag::HTMLTag() { + simple = true; + owner = nullptr; +} + +HTMLBuilder *HTMLBuilder::comment(const String &val) { + write_tag(); + + result += ""; + + return this; +} + +HTMLTag *HTMLBuilder::doctype() { + write_tag(); + + return tag.start("!DOCTYPE"); +} + +HTMLBuilder *HTMLBuilder::doctype(const String &val) { + write_tag(); + + result += ""; + + return this; +} + +HTMLTag *HTMLBuilder::a() { + write_tag(); + + return tag.start("a"); +} +HTMLTag *HTMLBuilder::abbr() { + write_tag(); + + return tag.start("abbr"); +} + +HTMLTag *HTMLBuilder::acronym() { // Not supported in HTML5. Use instead. Defines an acronym + write_tag(); + + return tag.start("acronym"); +} + +HTMLTag *HTMLBuilder::address() { + write_tag(); + + return tag.start("address"); +} + +HTMLTag *HTMLBuilder::applet() { // Not supported in HTML5. Use or instead. Defines an embedded applet + write_tag(); + + return tag.start("applet"); +} + +HTMLTag *HTMLBuilder::area() { + write_tag(); + + return tag.start("area"); +} + +HTMLTag *HTMLBuilder::article() { + write_tag(); + + return tag.start("article"); +} + +HTMLTag *HTMLBuilder::aside() { + write_tag(); + + return tag.start("aside"); +} + +HTMLTag *HTMLBuilder::audio() { + write_tag(); + + return tag.start("audio"); +} + +HTMLTag *HTMLBuilder::b() { + write_tag(); + + return tag.start("b"); +} + +HTMLTag *HTMLBuilder::basefont() { // Not supported in HTML5. Use CSS instead. Specifies a default color, size, and font for all text in a document + write_tag(); + + return tag.start("basefont"); +} + +HTMLTag *HTMLBuilder::bdi() { + write_tag(); + + return tag.start("bdi"); +} + +HTMLTag *HTMLBuilder::bdo() { + write_tag(); + + return tag.start("bdo"); +} + +HTMLTag *HTMLBuilder::big() { // Not supported in HTML5. Use CSS instead. Defines big text + write_tag(); + + return tag.start("big"); +} + +HTMLTag *HTMLBuilder::blockquote() { + write_tag(); + + return tag.start("blockquote"); +} + +HTMLTag *HTMLBuilder::body() { + write_tag(); + + return tag.start("body"); +} + +HTMLTag *HTMLBuilder::br() { + write_tag(); + + return tag.start("br", true); +} + +HTMLTag *HTMLBuilder::button() { + write_tag(); + + return tag.start("button"); +} + +HTMLTag *HTMLBuilder::canvas() { + write_tag(); + + return tag.start("canvas"); +} + +HTMLTag *HTMLBuilder::caption() { + write_tag(); + + return tag.start("caption"); +} + +HTMLTag *HTMLBuilder::center() { // Not supported in HTML5. Use CSS instead. Defines centered text + write_tag(); + + return tag.start("center"); +} + +HTMLTag *HTMLBuilder::cite() { + write_tag(); + + return tag.start("cite"); +} + +HTMLTag *HTMLBuilder::code() { + write_tag(); + + return tag.start("code"); +} + +HTMLTag *HTMLBuilder::col() { + write_tag(); + + return tag.start("col"); +} + +HTMLTag *HTMLBuilder::colgroup() { + write_tag(); + + return tag.start("colgroup"); +} + +HTMLTag *HTMLBuilder::data() { + write_tag(); + + return tag.start("cite"); +} + +HTMLTag *HTMLBuilder::datalist() { + write_tag(); + + return tag.start("datalist"); +} + +HTMLTag *HTMLBuilder::dd() { + write_tag(); + + return tag.start("dd"); +} + +HTMLTag *HTMLBuilder::del() { + write_tag(); + + return tag.start("del"); +} + +HTMLTag *HTMLBuilder::details() { + write_tag(); + + return tag.start("details"); +} + +HTMLTag *HTMLBuilder::dfn() { + write_tag(); + + return tag.start("dfn"); +} + +HTMLTag *HTMLBuilder::dialog() { + write_tag(); + + return tag.start("dialog"); +} + +HTMLTag *HTMLBuilder::dir() { // Not supported in HTML5. Use
    instead. + write_tag(); + + return tag.start("dir"); +} + +HTMLTag *HTMLBuilder::div() { + write_tag(); + + return tag.start("div"); +} + +HTMLTag *HTMLBuilder::dl() { + write_tag(); + + return tag.start("dl"); +} + +HTMLTag *HTMLBuilder::dt() { + write_tag(); + + return tag.start("dt"); +} + +HTMLTag *HTMLBuilder::em() { + write_tag(); + + return tag.start("em"); +} + +HTMLTag *HTMLBuilder::embed() { + write_tag(); + + return tag.start("embed"); +} + +HTMLTag *HTMLBuilder::fieldset() { + write_tag(); + + return tag.start("fieldset"); +} +HTMLTag *HTMLBuilder::figcaption() { + write_tag(); + + return tag.start("figcaption"); +} + +HTMLTag *HTMLBuilder::figure() { + write_tag(); + + return tag.start("figure"); +} + +HTMLTag *HTMLBuilder::font() { // Not supported in HTML5. + write_tag(); + + return tag.start("font"); +} + +HTMLTag *HTMLBuilder::footer() { + write_tag(); + + return tag.start("footer"); +} + +HTMLTag *HTMLBuilder::form() { + write_tag(); + + return tag.start("form"); +} + +HTMLTag *HTMLBuilder::frame() { // Not supported in HTML5. + write_tag(); + + return tag.start("frame"); +} + +HTMLTag *HTMLBuilder::frameset() { // Not supported in HTML5. + write_tag(); + + return tag.start("frameset"); +} + +HTMLTag *HTMLBuilder::h1() { + write_tag(); + + return tag.start("h1"); +} + +HTMLTag *HTMLBuilder::h2() { + write_tag(); + + return tag.start("h2"); +} + +HTMLTag *HTMLBuilder::h3() { + write_tag(); + + return tag.start("h3"); +} + +HTMLTag *HTMLBuilder::h4() { + write_tag(); + + return tag.start("h4"); +} + +HTMLTag *HTMLBuilder::h5() { + write_tag(); + + return tag.start("h5"); +} + +HTMLTag *HTMLBuilder::h6() { + write_tag(); + + return tag.start("h6"); +} + +HTMLTag *HTMLBuilder::head() { + write_tag(); + + return tag.start("head"); +} + +HTMLTag *HTMLBuilder::header() { + write_tag(); + + return tag.start("header"); +} + +HTMLTag *HTMLBuilder::hr() { + write_tag(); + + return tag.start("hr"); +} + +HTMLTag *HTMLBuilder::html() { + write_tag(); + + return tag.start("html"); +} + +HTMLTag *HTMLBuilder::i() { + write_tag(); + + return tag.start("i"); +} + +HTMLTag *HTMLBuilder::iframe() { + write_tag(); + + return tag.start("iframe"); +} + +HTMLTag *HTMLBuilder::img() { + write_tag(); + + return tag.start("img"); +} + +HTMLTag *HTMLBuilder::input() { + write_tag(); + + return tag.start("input"); +} + +HTMLTag *HTMLBuilder::ins() { + write_tag(); + + return tag.start("ins"); +} + +HTMLTag *HTMLBuilder::kbd() { + write_tag(); + + return tag.start("kbd"); +} + +HTMLTag *HTMLBuilder::label() { + write_tag(); + + return tag.start("label"); +} + +HTMLTag *HTMLBuilder::legend() { + write_tag(); + + return tag.start("legend"); +} + +HTMLTag *HTMLBuilder::li() { + write_tag(); + + return tag.start("li"); +} + +HTMLTag *HTMLBuilder::link() { + write_tag(); + + return tag.start("link"); +} + +HTMLTag *HTMLBuilder::main() { + write_tag(); + + return tag.start("main"); +} + +HTMLTag *HTMLBuilder::map() { + write_tag(); + + return tag.start("map"); +} +HTMLTag *HTMLBuilder::mark() { + write_tag(); + + return tag.start("mark"); +} + +HTMLTag *HTMLBuilder::meta() { + write_tag(); + + return tag.start("meta"); +} + +HTMLTag *HTMLBuilder::meter() { + write_tag(); + + return tag.start("meter"); +} + +HTMLTag *HTMLBuilder::nav() { + write_tag(); + + return tag.start("nav"); +} + +HTMLTag *HTMLBuilder::noframes() { // Not supported in HTML5. + write_tag(); + + return tag.start("noframes"); +} + +HTMLTag *HTMLBuilder::noscript() { + write_tag(); + + return tag.start("noscript"); +} + +HTMLTag *HTMLBuilder::object() { + write_tag(); + + return tag.start("object"); +} + +HTMLTag *HTMLBuilder::ol() { + write_tag(); + + return tag.start("ol"); +} + +HTMLTag *HTMLBuilder::optgroup() { + write_tag(); + + return tag.start("optgroup"); +} + +HTMLTag *HTMLBuilder::option() { + write_tag(); + + return tag.start("option"); +} + +HTMLTag *HTMLBuilder::output() { + write_tag(); + + return tag.start("output"); +} + +HTMLTag *HTMLBuilder::p() { + write_tag(); + + return tag.start("p"); +} + +HTMLTag *HTMLBuilder::param() { + write_tag(); + + return tag.start("param"); +} + +HTMLTag *HTMLBuilder::picture() { + write_tag(); + + return tag.start("picture"); +} + +HTMLTag *HTMLBuilder::pre() { + write_tag(); + + return tag.start("pre"); +} + +HTMLTag *HTMLBuilder::progress() { + write_tag(); + + return tag.start("progress"); +} + +HTMLTag *HTMLBuilder::q() { + write_tag(); + + return tag.start("q"); +} + +HTMLTag *HTMLBuilder::rp() { + write_tag(); + + return tag.start("rp"); +} + +HTMLTag *HTMLBuilder::rt() { + write_tag(); + + return tag.start("rt"); +} + +HTMLTag *HTMLBuilder::ruby() { + write_tag(); + + return tag.start("ruby"); +} + +HTMLTag *HTMLBuilder::s() { + write_tag(); + + return tag.start("s"); +} + +HTMLTag *HTMLBuilder::samp() { + write_tag(); + + return tag.start("samp"); +} + +HTMLTag *HTMLBuilder::script() { + write_tag(); + + return tag.start("script"); +} + +HTMLTag *HTMLBuilder::section() { + write_tag(); + + return tag.start("section"); +} + +HTMLTag *HTMLBuilder::select() { + write_tag(); + + return tag.start("select"); +} + +HTMLTag *HTMLBuilder::small() { + write_tag(); + + return tag.start("small"); +} + +HTMLTag *HTMLBuilder::source() { + write_tag(); + + return tag.start("source"); +} + +HTMLTag *HTMLBuilder::span() { + write_tag(); + + return tag.start("span"); +} + +HTMLTag *HTMLBuilder::strike() { // Not supported in HTML5 + write_tag(); + + return tag.start("strike"); +} + +HTMLTag *HTMLBuilder::strong() { + write_tag(); + + return tag.start("strong"); +} + +HTMLTag *HTMLBuilder::style() { + write_tag(); + + return tag.start("style"); +} + +HTMLTag *HTMLBuilder::sub() { + write_tag(); + + return tag.start("sub"); +} + +HTMLTag *HTMLBuilder::summary() { + write_tag(); + + return tag.start("summary"); +} + +HTMLTag *HTMLBuilder::sup() { + write_tag(); + + return tag.start("sup"); +} + +HTMLTag *HTMLBuilder::svg() { + write_tag(); + + return tag.start("svg"); +} + +HTMLTag *HTMLBuilder::table() { + write_tag(); + + return tag.start("table"); +} + +HTMLTag *HTMLBuilder::tbody() { + write_tag(); + + return tag.start("tbody"); +} + +HTMLTag *HTMLBuilder::td() { + write_tag(); + + return tag.start("td"); +} + +HTMLTag *HTMLBuilder::templateh() { + write_tag(); + + return tag.start("template"); +} + +HTMLTag *HTMLBuilder::textarea() { + write_tag(); + + return tag.start("textarea"); +} + +HTMLTag *HTMLBuilder::tfoot() { + write_tag(); + + return tag.start("tfoot"); +} + +HTMLTag *HTMLBuilder::th() { + write_tag(); + + return tag.start("th"); +} + +HTMLTag *HTMLBuilder::thead() { + write_tag(); + + return tag.start("thead"); +} + +HTMLTag *HTMLBuilder::time() { + write_tag(); + + return tag.start("time"); +} + +HTMLTag *HTMLBuilder::title() { + write_tag(); + + return tag.start("title"); +} + +HTMLTag *HTMLBuilder::tr() { + write_tag(); + + return tag.start("tr"); +} + +HTMLTag *HTMLBuilder::track() { + write_tag(); + + return tag.start("track"); +} + +HTMLTag *HTMLBuilder::tt() { // Not supported in HTML5. + write_tag(); + + return tag.start("tt"); +} + +HTMLTag *HTMLBuilder::u() { + write_tag(); + + return tag.start("u"); +} + +HTMLTag *HTMLBuilder::ul() { + write_tag(); + + return tag.start("ul"); +} + +HTMLTag *HTMLBuilder::var() { + write_tag(); + + return tag.start("var"); +} + +HTMLTag *HTMLBuilder::video() { + write_tag(); + + return tag.start("video"); +} + +HTMLTag *HTMLBuilder::wbr() { + write_tag(); + + return tag.start("wbr"); +} + +HTMLBuilder *HTMLBuilder::a(const String &href, const String &cls, const String &id) { + HTMLTag *t = a(); + + t->href(href); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::fa(const String &href, const String &body, const String &cls, const String &id) { + a(href, cls, id); + w(body); + ca(); + + return this; +} + +HTMLBuilder *HTMLBuilder::div(const String &cls, const String &id) { + HTMLTag *t = div(); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::fdiv(const String &body, const String &cls, const String &id) { + div(cls, id); + w(body); + cdiv(); + + return this; +} + +HTMLBuilder *HTMLBuilder::textarea(const String &name, const String &cls, const String &id) { + HTMLTag *t = textarea(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} +HTMLBuilder *HTMLBuilder::ftextarea(const String &name, const String &body, const String &cls, const String &id) { + textarea(name, cls, id); + w(body); + ctextarea(); + + return this; +} + +HTMLBuilder *HTMLBuilder::select(const String &name, const String &cls, const String &id) { + HTMLTag *t = select(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLTag *HTMLBuilder::option(const String &value) { + HTMLTag *t = option(); + + t->value(value); + + return t; +} +HTMLBuilder *HTMLBuilder::foption(const String &value, const String &body, const bool selected) { + option(value)->selected(selected); + w(body); + coption(); + + return this; +} + +// Closing tags + +HTMLBuilder *HTMLBuilder::ca() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cabbr() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cacronym() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::caddress() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::capplet() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::carea() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::carticle() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::caside() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::caudio() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cb() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbasefont() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbdi() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbdo() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbig() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cblockquote() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbody() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cbutton() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccanvas() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccaption() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccenter() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccite() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccode() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccol() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ccolgroup() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdata() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdatalist() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdd() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdel() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdetails() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdfn() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdialog() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdir() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdiv() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdl() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cdt() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cem() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cembed() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cfieldset() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cfigcaption() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cfigure() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cfont() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cfooter() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cform() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cframe() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cframeset() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch1() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch2() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch3() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch4() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch5() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ch6() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::chead() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cheader() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::chr() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::chtml() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ci() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ciframe() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cimg() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cinput() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cins() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ckbd() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::clabel() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::clegend() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cli() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::clink() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cmain() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cmap() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cmark() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cmeta() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cmeter() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cnav() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cnoframes() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cnoscript() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cobject() { + write_tag(); + result += "
"; + + return this; +} + +HTMLBuilder *HTMLBuilder::c_ol() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::coptgroup() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::coption() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::coutput() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cp() { + write_tag(); + result += "

"; + + return this; +} + +HTMLBuilder *HTMLBuilder::cparam() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cpicture() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cpre() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cprogress() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cq() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::crp() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::crt() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cruby() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cs() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csamp() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cscript() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csection() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cselect() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csmall() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csource() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cspan() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cstrike() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cstrong() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cstyle() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csub() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csummary() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csup() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::csvg() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctable() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctbody() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctd() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctemplateh() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctextarea() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctfoot() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cth() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cthead() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctime() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctitle() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctr() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctrack() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::ctt() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cu() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cul() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cvar() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cvideo() { + write_tag(); + result += ""; + + return this; +} + +HTMLBuilder *HTMLBuilder::cwbr() { + write_tag(); + result += ""; + + return this; +} + +HTMLTag *HTMLBuilder::form_get() { + write_tag(); + + return tag.start("form")->method_get(); +} +HTMLTag *HTMLBuilder::form_post() { + write_tag(); + + return tag.start("form")->method_post(); +} +HTMLBuilder *HTMLBuilder::form_get(const String &action, const String &cls, const String &id) { + HTMLTag *t = form_get(); + + t->fora(action); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} +HTMLBuilder *HTMLBuilder::form_post(const String &action, const String &cls, const String &id) { + HTMLTag *t = form_post(); + + t->action(action); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::form_post(const String &action, Request *request, const String &cls, const String &id) { + form_post(action, cls, id); + csrf_token(request); + + return this; +} + +HTMLTag *HTMLBuilder::input_button() { + write_tag(); + + return tag.start("input")->itbutton(); +} + +HTMLTag *HTMLBuilder::input_checkbox() { + write_tag(); + + return tag.start("input")->itcheckbox(); +} + +HTMLTag *HTMLBuilder::input_color() { + write_tag(); + + return tag.start("input")->itcolor(); +} + +HTMLTag *HTMLBuilder::input_date() { + write_tag(); + + return tag.start("input")->itdate(); +} + +HTMLTag *HTMLBuilder::input_datetime_local() { + write_tag(); + + return tag.start("input")->itdatetime_local(); +} + +HTMLTag *HTMLBuilder::input_email() { + write_tag(); + + return tag.start("input")->itemail(); +} + +HTMLTag *HTMLBuilder::input_file() { + write_tag(); + + return tag.start("input")->itfile(); +} + +HTMLTag *HTMLBuilder::input_hidden() { + write_tag(); + + return tag.start("input")->ithidden(); +} + +HTMLTag *HTMLBuilder::input_image() { + write_tag(); + + return tag.start("input")->itimage(); +} + +HTMLTag *HTMLBuilder::input_month() { + write_tag(); + + return tag.start("input")->itmonth(); +} + +HTMLTag *HTMLBuilder::input_number() { + write_tag(); + + return tag.start("input")->itnumber(); +} + +HTMLTag *HTMLBuilder::input_password() { + write_tag(); + + return tag.start("input")->itpassword(); +} + +HTMLTag *HTMLBuilder::input_radio() { + write_tag(); + + return tag.start("input")->itradio(); +} + +HTMLTag *HTMLBuilder::input_range() { + write_tag(); + + return tag.start("input")->itrange(); +} + +HTMLTag *HTMLBuilder::input_reset() { + write_tag(); + + return tag.start("input")->itreset(); +} + +HTMLTag *HTMLBuilder::input_search() { + write_tag(); + + return tag.start("input")->itsearch(); +} + +HTMLTag *HTMLBuilder::input_submit() { + write_tag(); + + return tag.start("input")->itsubmit(); +} + +HTMLTag *HTMLBuilder::input_tel() { + write_tag(); + + return tag.start("input")->ittel(); +} + +HTMLTag *HTMLBuilder::input_text() { + write_tag(); + + return tag.start("input")->ittext(); +} + +HTMLTag *HTMLBuilder::input_time() { + write_tag(); + + return tag.start("input")->ittime(); +} + +HTMLTag *HTMLBuilder::input_url() { + write_tag(); + + return tag.start("input")->iturl(); +} + +HTMLTag *HTMLBuilder::input_week() { + write_tag(); + + return tag.start("input")->itweek(); +} + +HTMLBuilder *HTMLBuilder::label(const String &pfor, const String &plabel, const String &cls, const String &id) { + HTMLTag *t = label(); + + t->fora(pfor); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + w(plabel); + + clabel(); + + return this; +} + +HTMLBuilder *HTMLBuilder::input_button(const String &name, const String &value, const String &cls, const String &id) { + HTMLTag *t = input_button(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_checkbox(const String &name, const String &value, const bool checked, const String &cls, const String &id) { + HTMLTag *t = input_checkbox(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + t->checked(checked); + + return this; +} + +HTMLBuilder *HTMLBuilder::input_color(const String &name, const String &value, const String &cls, const String &id) { + HTMLTag *t = input_color(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_date(const String &name, const String &value, const String &cls, const String &id, const String &date_min, const String &date_max, const String &date_step) { + HTMLTag *t = input_date(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (date_min != "") { + t->min(date_min); + } + + if (date_max != "") { + t->max(date_max); + } + + if (date_step != "") { + t->step(date_step); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_datetime_local(const String &name, const String &value, const String &cls, const String &id, const String &date_min, const String &date_max, const String &date_step) { + HTMLTag *t = input_datetime_local(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (date_min != "") { + t->min(date_min); + } + + if (date_max != "") { + t->max(date_max); + } + + if (date_step != "") { + t->step(date_step); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_email(const String &name, const String &value, const String &placeholder, const String &cls, const String &id) { + HTMLTag *t = input_email(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_file(const String &name, const String &accept, const String &cls, const String &id) { + HTMLTag *t = input_file(); + + t->name(name); + + if (accept != "") { + t->accept(accept); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_image(const String &name, const String &src, const String &alt, const String &cls, const String &id, const int width, const int height) { + HTMLTag *t = input_image(); + + t->name(name); + + if (src != "") { + t->src(src); + } + + if (alt != "") { + t->alt(alt); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (width != 0) { + t->width(width); + } + + if (height != 0) { + t->height(height); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_month(const String &name, const String &cls, const String &id) { + HTMLTag *t = input_month(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_number(const String &name, const String &vmin, const String &vmax, const String &cls, const String &id) { + HTMLTag *t = input_number(); + + t->name(name); + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_password(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + HTMLTag *t = input_password(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_radio(const String &name, const String &value, const String &cls, const String &id) { + HTMLTag *t = input_password(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_range(const String &name, const String &value, const String &vmin, const String &vmax, const String &vstep, const String &cls, const String &id) { + HTMLTag *t = input_range(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (vstep != "") { + t->step(vstep); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_reset(const String &name, const String &value, const String &cls, const String &id) { + HTMLTag *t = input_reset(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_search(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size, const String &pattern) { + HTMLTag *t = input_search(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + if (pattern != "") { + t->pattern(pattern); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_submit(const String &value, const String &cls, const String &id) { + HTMLTag *t = input_submit(); + + t->value(value); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_tel(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size, const String &pattern) { + HTMLTag *t = input_tel(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + if (pattern != "") { + t->pattern(pattern); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_text(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + HTMLTag *t = input_text(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_time(const String &name, const String &cls, const String &id, const String &vmin, const String &vmax, const String &vstep) { + HTMLTag *t = input_time(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (vstep != "") { + t->step(vstep); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_url(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + HTMLTag *t = input_url(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_week(const String &name, const String &cls, const String &id, const String &vmin, const String &vmax) { + HTMLTag *t = input_week(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::input_hidden(const String &name, const String &value) { + HTMLTag *t = input_hidden(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + return this; +} + +HTMLBuilder *HTMLBuilder::csrf_token(const String &token) { + if (token == "") { + // don't waste html characters if it's an empty string anyway + return this; + } + + input_hidden("csrf_token", token); + + return this; +} +HTMLBuilder *HTMLBuilder::csrf_token(Request *request) { + return csrf_token(request->get_csrf_token()); +} + +void HTMLBuilder::f() { + write_tag(); +} + +HTMLBuilder *HTMLBuilder::w(const String &val) { + write_tag(); + + result += val; + + return this; +} + +HTMLBuilder *HTMLBuilder::wn(const double val, int p_decimals) { + write_tag(); + + result += String::num(val, p_decimals); + + return this; +} +HTMLBuilder *HTMLBuilder::wns(const double val) { + write_tag(); + + result += String::num_scientific(val); + + return this; +} +HTMLBuilder *HTMLBuilder::wr(const double val, const bool p_trailing) { + write_tag(); + + result += String::num_real(val, p_trailing); + + return this; +} +HTMLBuilder *HTMLBuilder::wi(const int64_t val, const int base, const bool capitalize_hex) { + write_tag(); + + result += String::num_int64(val, base, capitalize_hex); + + return this; +} +HTMLBuilder *HTMLBuilder::wui(const uint64_t val, const int base, const bool capitalize_hex) { + write_tag(); + + result += String::num_uint64(val, base, capitalize_hex); + + return this; +} + +HTMLBuilder *HTMLBuilder::wbn(const bool val) { + write_tag(); + + result += String::bool_num(val); + + return this; +} +HTMLBuilder *HTMLBuilder::wbs(const bool val) { + write_tag(); + + result += String::bool_str(val); + + return this; +} + +// TODO! +HTMLBuilder *HTMLBuilder::we(const String &val) { + printf("HTMLBuilder::write_excaped NYI!"); + + write_tag(); + + result += val; + + return this; +} + +HTMLBuilder *HTMLBuilder::write_tag() { + if (tag.has_data()) { + tag.close(); + result += tag.result; + tag.reset(); + } + + return this; +} + +HTMLBuilder::HTMLBuilder() { + tag.owner = this; +} + +HTMLBuilder::~HTMLBuilder() { +} \ No newline at end of file diff --git a/modules/web/html/html_builder.h b/modules/web/html/html_builder.h new file mode 100644 index 000000000..32fb855bb --- /dev/null +++ b/modules/web/html/html_builder.h @@ -0,0 +1,551 @@ +#ifndef HTML_BUILDER_H +#define HTML_BUILDER_H + +#include "core/string.h" + +class Request; +class HTMLBuilder; + +class HTMLTag { +public: + bool simple; + String result; + + HTMLTag *str(const String &str); + HTMLTag *style(const String &val); + HTMLTag *href(const String &val); + HTMLTag *cls(const String &val); + HTMLTag *clsse(const String &val); //se -> skip empty + HTMLTag *id(const String &val); + HTMLTag *name(const String &val); + HTMLTag *content(const String &val); + HTMLTag *value(const String &val); + HTMLTag *accept(const String &val); + HTMLTag *src(const String &val); + HTMLTag *alt(const String &val); + HTMLTag *inputmode(const String &val); + HTMLTag *list(const String &val); + + HTMLTag *autocomplete(const String &val); + + HTMLTag *autocomplete_off(); + HTMLTag *autocomplete_on(); + HTMLTag *autocomplete_name(); + HTMLTag *autocomplete_name_honorific_prefix(); + HTMLTag *autocomplete_name_given_name(); + HTMLTag *autocomplete_name_additional_name(); + HTMLTag *autocomplete_name_family_name(); + HTMLTag *autocomplete_name_honorific_suffix(); + HTMLTag *autocomplete_name_nickname(); + HTMLTag *autocomplete_email(); + HTMLTag *autocomplete_username(); + HTMLTag *autocomplete_new_password(); + HTMLTag *autocomplete_current_password(); + HTMLTag *autocomplete_one_time_code(); + HTMLTag *autocomplete_organization_title(); + HTMLTag *autocomplete_organization(); + HTMLTag *autocomplete_street_address(); + HTMLTag *autocomplete_address_line1(); + HTMLTag *autocomplete_address_line2(); + HTMLTag *autocomplete_address_line3(); + HTMLTag *autocomplete_address_level_1(); + HTMLTag *autocomplete_address_level_2(); + HTMLTag *autocomplete_address_level_3(); + HTMLTag *autocomplete_address_level_4(); + HTMLTag *autocomplete_country(); + HTMLTag *autocomplete_country_name(); + HTMLTag *autocomplete_postal_code(); + HTMLTag *autocomplete_cc_name(); + HTMLTag *autocomplete_cc_given_name(); + HTMLTag *autocomplete_cc_additional_name(); + HTMLTag *autocomplete_cc_family_name(); + HTMLTag *autocomplete_cc_number(); + HTMLTag *autocomplete_cc_exp(); + HTMLTag *autocomplete_cc_exp_month(); + HTMLTag *autocomplete_cc_exp_year(); + HTMLTag *autocomplete_cc_csc(); + HTMLTag *autocomplete_cc_type(); + HTMLTag *autocomplete_transaction_currency(); + HTMLTag *autocomplete_transaction_amount(); + HTMLTag *autocomplete_language(); + HTMLTag *autocomplete_bday(); + HTMLTag *autocomplete_bday_day(); + HTMLTag *autocomplete_bday_month(); + HTMLTag *autocomplete_bday_year(); + HTMLTag *autocomplete_sex(); + HTMLTag *autocomplete_tel(); + HTMLTag *autocomplete_tel_country_code(); + HTMLTag *autocomplete_tel_national(); + HTMLTag *autocomplete_tel_area_code(); + HTMLTag *autocomplete_tel_local(); + HTMLTag *autocomplete_tel_extension(); + HTMLTag *autocomplete_impp(); + HTMLTag *autocomplete_url(); + HTMLTag *autocomplete_photo(); + + HTMLTag *onclick(const String &val); + + HTMLTag *checked(const bool val = true); + HTMLTag *selected(const bool val = true); + HTMLTag *autofocus(const bool val = true); + HTMLTag *disabled(const bool val = true); + HTMLTag *multiple(const bool val = true); + HTMLTag *required(const bool val = true); + HTMLTag *spellcheck(const bool val); + + HTMLTag *max(const String &val); + HTMLTag *min(const String &val); + HTMLTag *step(const String &val); + HTMLTag *step_any(); + + HTMLTag *minlength(const int val); + HTMLTag *minlength(const String &val); + HTMLTag *maxlength(const int val); + HTMLTag *maxlength(const String &val); + HTMLTag *size(const int val); + HTMLTag *size(const String &val); + + HTMLTag *width(const int val); + HTMLTag *width(const String &val); + HTMLTag *height(const int val); + HTMLTag *height(const String &val); + + HTMLTag *pattern(const String &val); + + HTMLTag *method(const String &val); + HTMLTag *method_get(); + HTMLTag *method_post(); + + HTMLTag *action(const String &val); + HTMLTag *type(const String &val); + HTMLTag *placeholder(const String &val); + HTMLTag *fora(const String &val); // for attrib -> for is reserved keyword + + HTMLTag *rel(const String &val); + HTMLTag *rel_stylesheet(); + HTMLTag *rel_alternate(); + HTMLTag *rel_author(); + HTMLTag *rel_bookmark(); + HTMLTag *rel_external(); + HTMLTag *rel_help(); + HTMLTag *rel_license(); + HTMLTag *rel_next(); + HTMLTag *rel_nofollow(); + HTMLTag *rel_noopener(); + HTMLTag *rel_noreferrer(); + HTMLTag *rel_prev(); + HTMLTag *rel_search(); + HTMLTag *rel_tag(); + + HTMLTag *charset(const String &val); + HTMLTag *charset_utf_8(); + + HTMLTag *itbutton(); + HTMLTag *itcheckbox(); + HTMLTag *itcolor(); + HTMLTag *itdate(); + HTMLTag *itdatetime_local(); + HTMLTag *itemail(); + HTMLTag *itfile(); + HTMLTag *ithidden(); + HTMLTag *itimage(); + HTMLTag *itmonth(); + HTMLTag *itnumber(); + HTMLTag *itpassword(); + HTMLTag *itradio(); + HTMLTag *itrange(); + HTMLTag *itreset(); + HTMLTag *itsearch(); + HTMLTag *itsubmit(); + HTMLTag *ittel(); + HTMLTag *ittext(); + HTMLTag *ittime(); + HTMLTag *iturl(); + HTMLTag *itweek(); + + HTMLTag *inputmode_none(); + HTMLTag *inputmode_text(); + HTMLTag *inputmode_decimal(); + HTMLTag *inputmode_numeric(); + HTMLTag *inputmode_tel(); + HTMLTag *inputmode_search(); + HTMLTag *inputmode_email(); + HTMLTag *inputmode_url(); + + HTMLTag *attrib(const String &attr, const String &val); + + HTMLTag *start(const String &p_new_tag, const bool p_simple = false); + HTMLTag *reset(); + HTMLTag *close(); + + HTMLBuilder *f(); + + bool has_data(); + + HTMLTag(); + + HTMLBuilder *owner; +}; + +class HTMLBuilder { +public: + String result; + + HTMLBuilder *comment(const String &val); + HTMLTag *doctype(); + HTMLBuilder *doctype(const String &val); + + HTMLTag *a(); + HTMLTag *abbr(); + HTMLTag *acronym(); // Not supported in HTML5. + HTMLTag *address(); + HTMLTag *applet(); // Not supported in HTML5. + HTMLTag *area(); + HTMLTag *article(); + HTMLTag *aside(); + HTMLTag *audio(); + HTMLTag *b(); + HTMLTag *basefont(); // Not supported in HTML5. + HTMLTag *bdi(); + HTMLTag *bdo(); + HTMLTag *big(); // Not supported in HTML5. + HTMLTag *blockquote(); + HTMLTag *body(); + HTMLTag *br(); + HTMLTag *button(); + HTMLTag *canvas(); + HTMLTag *caption(); + HTMLTag *center(); // Not supported in HTML5. + HTMLTag *cite(); + HTMLTag *code(); + HTMLTag *col(); + HTMLTag *colgroup(); + HTMLTag *data(); + HTMLTag *datalist(); + HTMLTag *dd(); + HTMLTag *del(); + HTMLTag *details(); + HTMLTag *dfn(); + HTMLTag *dialog(); + HTMLTag *dir(); // Not supported in HTML5. + HTMLTag *div(); + HTMLTag *dl(); + HTMLTag *dt(); + HTMLTag *em(); + HTMLTag *embed(); + HTMLTag *fieldset(); + HTMLTag *figcaption(); + HTMLTag *figure(); + HTMLTag *font(); // Not supported in HTML5. + HTMLTag *footer(); + HTMLTag *form(); + HTMLTag *frame(); // Not supported in HTML5. + HTMLTag *frameset(); // Not supported in HTML5. + HTMLTag *h1(); + HTMLTag *h2(); + HTMLTag *h3(); + HTMLTag *h4(); + HTMLTag *h5(); + HTMLTag *h6(); + HTMLTag *head(); + HTMLTag *header(); + HTMLTag *hr(); + HTMLTag *html(); + + HTMLTag *i(); + HTMLTag *iframe(); + HTMLTag *img(); + HTMLTag *input(); + HTMLTag *ins(); + HTMLTag *kbd(); + HTMLTag *label(); + HTMLTag *legend(); + HTMLTag *li(); + HTMLTag *link(); + HTMLTag *main(); + HTMLTag *map(); + HTMLTag *mark(); + HTMLTag *meta(); + HTMLTag *meter(); + + HTMLTag *nav(); + HTMLTag *noframes(); // Not supported in HTML5. + HTMLTag *noscript(); + HTMLTag *object(); + HTMLTag *ol(); + HTMLTag *optgroup(); + HTMLTag *option(); + HTMLTag *output(); + HTMLTag *p(); + HTMLTag *param(); + HTMLTag *picture(); + HTMLTag *pre(); + HTMLTag *progress(); + HTMLTag *q(); + HTMLTag *rp(); + + HTMLTag *rt(); + HTMLTag *ruby(); + HTMLTag *s(); + HTMLTag *samp(); + HTMLTag *script(); + HTMLTag *section(); + HTMLTag *select(); + HTMLTag *small(); + HTMLTag *source(); + HTMLTag *span(); + HTMLTag *strike(); // Not supported in HTML5 + HTMLTag *strong(); + HTMLTag *style(); + HTMLTag *sub(); + HTMLTag *summary(); + HTMLTag *sup(); + + HTMLTag *svg(); + HTMLTag *table(); + HTMLTag *tbody(); + HTMLTag *td(); + HTMLTag *templateh(); + HTMLTag *textarea(); + HTMLTag *tfoot(); + HTMLTag *th(); + HTMLTag *thead(); + HTMLTag *time(); + HTMLTag *title(); + HTMLTag *tr(); + HTMLTag *track(); + HTMLTag *tt(); // Not supported in HTML5. + HTMLTag *u(); + HTMLTag *ul(); + HTMLTag *var(); + HTMLTag *video(); + HTMLTag *wbr(); + + HTMLBuilder *a(const String &href, const String &cls = "", const String &id = ""); + HTMLBuilder *fa(const String &href, const String &body, const String &cls = "", const String &id = ""); + + HTMLBuilder *div(const String &cls, const String &id = ""); + HTMLBuilder *fdiv(const String &body, const String &cls = "", const String &id = ""); + + HTMLBuilder *textarea(const String &name, const String &cls = "", const String &id = ""); + HTMLBuilder *ftextarea(const String &name, const String &body, const String &cls = "", const String &id = ""); + + HTMLBuilder *select(const String &name, const String &cls = "", const String &id = ""); + + HTMLTag *option(const String &value); + HTMLBuilder *foption(const String &value, const String &body, const bool selected = false); + + // closing tags c prefix means close + // Note simple tags should not have these like
+ // Note that I might have a few that shouldn't be here, those will be removed as I find them + HTMLBuilder *ca(); + HTMLBuilder *cabbr(); + HTMLBuilder *cacronym(); + HTMLBuilder *caddress(); + HTMLBuilder *capplet(); + HTMLBuilder *carea(); + HTMLBuilder *carticle(); + HTMLBuilder *caside(); + HTMLBuilder *caudio(); + HTMLBuilder *cb(); + HTMLBuilder *cbasefont(); + HTMLBuilder *cbdi(); + HTMLBuilder *cbdo(); + HTMLBuilder *cbig(); + HTMLBuilder *cblockquote(); + HTMLBuilder *cbody(); + HTMLBuilder *cbutton(); + HTMLBuilder *ccanvas(); + + HTMLBuilder *ccaption(); + HTMLBuilder *ccenter(); + HTMLBuilder *ccite(); + HTMLBuilder *ccode(); + HTMLBuilder *ccol(); + HTMLBuilder *ccolgroup(); + HTMLBuilder *cdata(); + HTMLBuilder *cdatalist(); + HTMLBuilder *cdd(); + HTMLBuilder *cdel(); + HTMLBuilder *cdetails(); + HTMLBuilder *cdfn(); + HTMLBuilder *cdialog(); + HTMLBuilder *cdir(); + HTMLBuilder *cdiv(); + HTMLBuilder *cdl(); + HTMLBuilder *cdt(); + + HTMLBuilder *cem(); + HTMLBuilder *cembed(); + HTMLBuilder *cfieldset(); + HTMLBuilder *cfigcaption(); + HTMLBuilder *cfigure(); + HTMLBuilder *cfont(); + HTMLBuilder *cfooter(); + HTMLBuilder *cform(); + HTMLBuilder *cframe(); + HTMLBuilder *cframeset(); + HTMLBuilder *ch1(); + HTMLBuilder *ch2(); + HTMLBuilder *ch3(); + HTMLBuilder *ch4(); + HTMLBuilder *ch5(); + HTMLBuilder *ch6(); + HTMLBuilder *chead(); + HTMLBuilder *cheader(); + HTMLBuilder *chr(); + HTMLBuilder *chtml(); + + HTMLBuilder *ci(); + HTMLBuilder *ciframe(); + HTMLBuilder *cimg(); + HTMLBuilder *cinput(); + HTMLBuilder *cins(); + HTMLBuilder *ckbd(); + HTMLBuilder *clabel(); + HTMLBuilder *clegend(); + HTMLBuilder *cli(); + HTMLBuilder *clink(); + HTMLBuilder *cmain(); + HTMLBuilder *cmap(); + HTMLBuilder *cmark(); + HTMLBuilder *cmeta(); + HTMLBuilder *cmeter(); + + HTMLBuilder *cnav(); + HTMLBuilder *cnoframes(); + HTMLBuilder *cnoscript(); + HTMLBuilder *cobject(); + HTMLBuilder *c_ol(); + HTMLBuilder *coptgroup(); + HTMLBuilder *coption(); + HTMLBuilder *coutput(); + HTMLBuilder *cp(); + HTMLBuilder *cparam(); + HTMLBuilder *cpicture(); + HTMLBuilder *cpre(); + HTMLBuilder *cprogress(); + HTMLBuilder *cq(); + HTMLBuilder *crp(); + + HTMLBuilder *crt(); + HTMLBuilder *cruby(); + HTMLBuilder *cs(); + HTMLBuilder *csamp(); + HTMLBuilder *cscript(); + HTMLBuilder *csection(); + HTMLBuilder *cselect(); + HTMLBuilder *csmall(); + HTMLBuilder *csource(); + HTMLBuilder *cspan(); + HTMLBuilder *cstrike(); + HTMLBuilder *cstrong(); + HTMLBuilder *cstyle(); + HTMLBuilder *csub(); + HTMLBuilder *csummary(); + HTMLBuilder *csup(); + + HTMLBuilder *csvg(); + HTMLBuilder *ctable(); + HTMLBuilder *ctbody(); + HTMLBuilder *ctd(); + HTMLBuilder *ctemplateh(); + HTMLBuilder *ctextarea(); + HTMLBuilder *ctfoot(); + HTMLBuilder *cth(); + HTMLBuilder *cthead(); + HTMLBuilder *ctime(); + HTMLBuilder *ctitle(); + HTMLBuilder *ctr(); + HTMLBuilder *ctrack(); + HTMLBuilder *ctt(); + HTMLBuilder *cu(); + HTMLBuilder *cul(); + HTMLBuilder *cvar(); + HTMLBuilder *cvideo(); + HTMLBuilder *cwbr(); + + HTMLTag *form_get(); + HTMLTag *form_post(); + HTMLBuilder *form_get(const String &action, const String &cls = "", const String &id = ""); + HTMLBuilder *form_post(const String &action, const String &cls = "", const String &id = ""); + // will add a csrf token from request + HTMLBuilder *form_post(const String &action, Request *request, const String &cls = "", const String &id = ""); + + HTMLTag *input_button(); + HTMLTag *input_checkbox(); + HTMLTag *input_color(); + HTMLTag *input_date(); + HTMLTag *input_datetime_local(); + HTMLTag *input_email(); + HTMLTag *input_file(); + HTMLTag *input_hidden(); + HTMLTag *input_image(); + HTMLTag *input_month(); + HTMLTag *input_number(); + HTMLTag *input_password(); + HTMLTag *input_radio(); + HTMLTag *input_range(); + HTMLTag *input_reset(); + HTMLTag *input_search(); + HTMLTag *input_submit(); + HTMLTag *input_tel(); + HTMLTag *input_text(); + HTMLTag *input_time(); + HTMLTag *input_url(); + HTMLTag *input_week(); + + HTMLBuilder *label(const String &pfor, const String &plabel, const String &cls = "", const String &id = ""); + + HTMLBuilder *input_button(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_checkbox(const String &name, const String &value = "", const bool checked = false, const String &cls = "", const String &id = ""); + HTMLBuilder *input_color(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_date(const String &name, const String &value = "", const String &cls = "", const String &id = "", const String &date_min = "", const String &date_max = "", const String &date_step = ""); + HTMLBuilder *input_datetime_local(const String &name, const String &value = "", const String &cls = "", const String &id = "", const String &date_min = "", const String &date_max = "", const String &date_step = ""); + HTMLBuilder *input_email(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_file(const String &name, const String &accept = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_image(const String &name, const String &src = "", const String &alt = "", const String &cls = "", const String &id = "", const int width = 0, const int height = 0); + HTMLBuilder *input_month(const String &name, const String &cls = "", const String &id = ""); + HTMLBuilder *input_number(const String &name, const String & = "", const String & = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_password(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + HTMLBuilder *input_radio(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_range(const String &name, const String &value = "", const String &vmin = "", const String &vmax = "", const String &vstep = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_reset(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + HTMLBuilder *input_search(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = "", const String &pattern = ""); + HTMLBuilder *input_submit(const String &value, const String &cls = "", const String &id = ""); + HTMLBuilder *input_tel(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = "", const String &pattern = ""); + HTMLBuilder *input_text(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + HTMLBuilder *input_time(const String &name, const String &cls = "", const String &id = "", const String &vmin = "", const String &vmax = "", const String &vstep = ""); + HTMLBuilder *input_url(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + HTMLBuilder *input_week(const String &name, const String &cls = "", const String &id = "", const String &vmin = "", const String &vmax = ""); + HTMLBuilder *input_hidden(const String &name, const String &value); + + HTMLBuilder *csrf_token(const String &token); + HTMLBuilder *csrf_token(Request *request); + + void f(); + + // write + HTMLBuilder *w(const String &val); + + HTMLBuilder *wn(const double val, int p_decimals = -1); + HTMLBuilder *wns(const double val); + HTMLBuilder *wr(const double val, const bool p_trailing = true); + HTMLBuilder *wi(const int64_t val, const int base = 10, const bool capitalize_hex = false); + HTMLBuilder *wui(const uint64_t val, const int base = 10, const bool capitalize_hex = false); + HTMLBuilder *wbn(const bool val); + HTMLBuilder *wbs(const bool val); + + // write_escaped + HTMLBuilder *we(const String &val); + + HTMLBuilder *write_tag(); + + HTMLBuilder(); + virtual ~HTMLBuilder(); + +protected: + HTMLTag tag; +}; + +#endif \ No newline at end of file diff --git a/modules/web/html/html_builder_bind.cpp b/modules/web/html/html_builder_bind.cpp new file mode 100644 index 000000000..6645e174e --- /dev/null +++ b/modules/web/html/html_builder_bind.cpp @@ -0,0 +1,3440 @@ +#include "html_builder_bind.h" +#include "core/print_string.h" +#include "core/ustring.h" + +//#include "web/http/request.h" + +_HTMLTag *_HTMLTag::str(const String &str) { + result += " " + str; + + return this; +} + +_HTMLTag *_HTMLTag::style(const String &val) { + attrib("style", val); + + return this; +} + +_HTMLTag *_HTMLTag::href(const String &val) { + attrib("href", val); + + return this; +} + +_HTMLTag *_HTMLTag::cls(const String &val) { + attrib("class", val); + + return this; +} + +_HTMLTag *_HTMLTag::clsse(const String &val) { + if (val == "") { + return this; + } + + attrib("class", val); + + return this; +} + +_HTMLTag *_HTMLTag::id(const String &val) { + attrib("id", val); + + return this; +} + +_HTMLTag *_HTMLTag::name(const String &val) { + attrib("name", val); + + return this; +} + +_HTMLTag *_HTMLTag::content(const String &val) { + attrib("content", val); + + return this; +} + +_HTMLTag *_HTMLTag::value(const String &val) { + attrib("value", val); + + return this; +} + +_HTMLTag *_HTMLTag::accept(const String &val) { + attrib("accept", val); + + return this; +} + +_HTMLTag *_HTMLTag::src(const String &val) { + attrib("src", val); + + return this; +} + +_HTMLTag *_HTMLTag::alt(const String &val) { + attrib("alt", val); + + return this; +} + +_HTMLTag *_HTMLTag::autocomplete(const String &val) { + attrib("autocomplete", val); + + return this; +} + +_HTMLTag *_HTMLTag::autocomplete_off() { + attrib("autocomplete", "off"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_on() { + attrib("autocomplete", "on"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name() { + attrib("autocomplete", "name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_honorific_prefix() { + attrib("autocomplete", "honorific-prefix"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_given_name() { + attrib("autocomplete", "given-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_additional_name() { + attrib("autocomplete", "additional-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_family_name() { + attrib("autocomplete", "family-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_honorific_suffix() { + attrib("autocomplete", "honorific-suffix"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_name_nickname() { + attrib("autocomplete", "nickname"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_email() { + attrib("autocomplete", "email"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_username() { + attrib("autocomplete", "username"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_new_password() { + attrib("autocomplete", "new-password"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_current_password() { + attrib("autocomplete", "current-password"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_one_time_code() { + attrib("autocomplete", "one-time-code"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_organization_title() { + attrib("autocomplete", "organization-title"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_organization() { + attrib("autocomplete", "organization"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_street_address() { + attrib("autocomplete", "street-address"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_line1() { + attrib("autocomplete", "address-line1"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_line2() { + attrib("autocomplete", "address-line2"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_line3() { + attrib("autocomplete", "address-line3"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_level_1() { + attrib("autocomplete", "address-level1"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_level_2() { + attrib("autocomplete", "address-level2"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_level_3() { + attrib("autocomplete", "address-level3"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_address_level_4() { + attrib("autocomplete", "address-level4"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_country() { + attrib("autocomplete", "country"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_country_name() { + attrib("autocomplete", "country-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_postal_code() { + attrib("autocomplete", "postal-code"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_name() { + attrib("autocomplete", "cc-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_given_name() { + attrib("autocomplete", "cc-given-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_additional_name() { + attrib("autocomplete", "cc-additional-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_family_name() { + attrib("autocomplete", "cc-family-name"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_number() { + attrib("autocomplete", "cc-number"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_exp() { + attrib("autocomplete", "cc-exp"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_exp_month() { + attrib("autocomplete", "cc-exp-month"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_exp_year() { + attrib("autocomplete", "cc-exp-year"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_csc() { + attrib("autocomplete", "cc-csc"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_cc_type() { + attrib("autocomplete", "cc-type"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_transaction_currency() { + attrib("autocomplete", "transaction-currency"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_transaction_amount() { + attrib("autocomplete", "transaction-amount"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_language() { + attrib("autocomplete", "language"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_bday() { + attrib("autocomplete", "bday"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_bday_day() { + attrib("autocomplete", "bday-day"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_bday_month() { + attrib("autocomplete", "bday-month"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_bday_year() { + attrib("autocomplete", "bday-year"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_sex() { + attrib("autocomplete", "sex"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel() { + attrib("autocomplete", "tel"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel_country_code() { + attrib("autocomplete", "tel-country-code"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel_national() { + attrib("autocomplete", "tel-national"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel_area_code() { + attrib("autocomplete", "tel-area-code"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel_local() { + attrib("autocomplete", "tel-local"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_tel_extension() { + attrib("autocomplete", "tel-extension"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_impp() { + attrib("autocomplete", "impp"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_url() { + attrib("autocomplete", "url"); + + return this; +} +_HTMLTag *_HTMLTag::autocomplete_photo() { + attrib("autocomplete", "photo"); + + return this; +} + +_HTMLTag *_HTMLTag::onclick(const String &val) { + attrib("onclick", val); + + return this; +} + +_HTMLTag *_HTMLTag::inputmode(const String &val) { + attrib("inputmode", val); + + return this; +} + +_HTMLTag *_HTMLTag::list(const String &val) { + attrib("list", val); + + return this; +} + +_HTMLTag *_HTMLTag::checked(const bool val) { + if (val) { + result += " checked"; + } + + return this; +} + +_HTMLTag *_HTMLTag::selected(const bool val) { + if (val) { + result += " selected"; + } + + return this; +} + +_HTMLTag *_HTMLTag::autofocus(const bool val) { + if (val) { + result += " autofocus"; + } + + return this; +} + +_HTMLTag *_HTMLTag::disabled(const bool val) { + if (val) { + result += " disabled"; + } + + return this; +} + +_HTMLTag *_HTMLTag::multiple(const bool val) { + if (val) { + result += " multiple"; + } + + return this; +} + +_HTMLTag *_HTMLTag::required(const bool val) { + if (val) { + result += " required"; + } + + return this; +} + +_HTMLTag *_HTMLTag::spellcheck(const bool val) { + if (val) { + attrib("spellcheck", "true"); + } else { + attrib("spellcheck", "false"); + } + + return this; +} + +_HTMLTag *_HTMLTag::max(const String &val) { + attrib("max", val); + + return this; +} + +_HTMLTag *_HTMLTag::min(const String &val) { + attrib("min", val); + + return this; +} + +_HTMLTag *_HTMLTag::step(const String &val) { + attrib("step", val); + + return this; +} +_HTMLTag *_HTMLTag::step_any() { + attrib("step", "any"); + + return this; +} + +_HTMLTag *_HTMLTag::minlength(const int val) { + attrib("minlength", String::num(val)); + + return this; +} +_HTMLTag *_HTMLTag::minlength(const String &val) { + attrib("minlength", val); + + return this; +} +_HTMLTag *_HTMLTag::maxlength(const int val) { + attrib("maxlength", String::num(val)); + + return this; +} +_HTMLTag *_HTMLTag::maxlength(const String &val) { + attrib("maxlength", val); + + return this; +} +_HTMLTag *_HTMLTag::size(const int val) { + attrib("size", String::num(val)); + + return this; +} +_HTMLTag *_HTMLTag::size(const String &val) { + attrib("size", val); + + return this; +} + +_HTMLTag *_HTMLTag::width(const int val) { + attrib("width", String::num(val)); + + return this; +} + +_HTMLTag *_HTMLTag::width(const String &val) { + attrib("width", val); + + return this; +} + +_HTMLTag *_HTMLTag::height(const int val) { + attrib("height", String::num(val)); + + return this; +} + +_HTMLTag *_HTMLTag::height(const String &val) { + attrib("height", val); + + return this; +} + +_HTMLTag *_HTMLTag::pattern(const String &val) { + attrib("pattern", val); + + return this; +} + +_HTMLTag *_HTMLTag::method(const String &val) { + attrib("method", val); + + return this; +} + +_HTMLTag *_HTMLTag::method_get() { + attrib("method", "get"); + + return this; +} +_HTMLTag *_HTMLTag::method_post() { + attrib("method", "post"); + + return this; +} + +_HTMLTag *_HTMLTag::action(const String &val) { + attrib("action", val); + + return this; +} + +_HTMLTag *_HTMLTag::type(const String &val) { + attrib("type", val); + + return this; +} + +_HTMLTag *_HTMLTag::placeholder(const String &val) { + attrib("placeholder", val); + + return this; +} + +_HTMLTag *_HTMLTag::fora(const String &val) { + attrib("for", val); + + return this; +} + +_HTMLTag *_HTMLTag::rel(const String &val) { + attrib("rel", val); + + return this; +} + +_HTMLTag *_HTMLTag::rel_stylesheet() { + attrib("rel", "stylesheet"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_alternate() { + attrib("rel", "alternate"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_author() { + attrib("rel", "author"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_bookmark() { + attrib("rel", "bookmark"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_external() { + attrib("rel", "external"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_help() { + attrib("rel", "help"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_next() { + attrib("rel", "next"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_nofollow() { + attrib("rel", "nofollow"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_noopener() { + attrib("rel", "noopener"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_noreferrer() { + attrib("rel", "noreferrer"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_prev() { + attrib("rel", "prev"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_search() { + attrib("rel", "search"); + + return this; +} + +_HTMLTag *_HTMLTag::rel_tag() { + attrib("rel", "tag"); + + return this; +} + +_HTMLTag *_HTMLTag::charset(const String &val) { + attrib("charset", val); + + return this; +} + +_HTMLTag *_HTMLTag::charset_utf_8() { + attrib("charset", "utf-8"); + + return this; +} + +_HTMLTag *_HTMLTag::itbutton() { + attrib("type", "button"); + + return this; +} +_HTMLTag *_HTMLTag::itcheckbox() { + attrib("type", "checkbox"); + + return this; +} +_HTMLTag *_HTMLTag::itcolor() { + attrib("type", "color"); + + return this; +} +_HTMLTag *_HTMLTag::itdate() { + attrib("type", "date"); + + return this; +} +_HTMLTag *_HTMLTag::itdatetime_local() { + attrib("type", "datetime_local"); + + return this; +} +_HTMLTag *_HTMLTag::itemail() { + attrib("type", "email"); + + return this; +} +_HTMLTag *_HTMLTag::itfile() { + attrib("type", "file"); + + return this; +} +_HTMLTag *_HTMLTag::ithidden() { + attrib("type", "hidden"); + + return this; +} +_HTMLTag *_HTMLTag::itimage() { + attrib("type", "image"); + + return this; +} +_HTMLTag *_HTMLTag::itmonth() { + attrib("type", "month"); + + return this; +} +_HTMLTag *_HTMLTag::itnumber() { + attrib("type", "number"); + + return this; +} +_HTMLTag *_HTMLTag::itpassword() { + attrib("type", "password"); + + return this; +} +_HTMLTag *_HTMLTag::itradio() { + attrib("type", "radio"); + + return this; +} +_HTMLTag *_HTMLTag::itrange() { + attrib("type", "range"); + + return this; +} +_HTMLTag *_HTMLTag::itreset() { + attrib("type", "reset"); + + return this; +} +_HTMLTag *_HTMLTag::itsearch() { + attrib("type", "search"); + + return this; +} +_HTMLTag *_HTMLTag::itsubmit() { + attrib("type", "submit"); + + return this; +} +_HTMLTag *_HTMLTag::ittel() { + attrib("type", "tel"); + + return this; +} +_HTMLTag *_HTMLTag::ittext() { + attrib("type", "text"); + + return this; +} +_HTMLTag *_HTMLTag::ittime() { + attrib("type", "time"); + + return this; +} +_HTMLTag *_HTMLTag::iturl() { + attrib("type", "url"); + + return this; +} +_HTMLTag *_HTMLTag::itweek() { + attrib("type", "week"); + + return this; +} + +_HTMLTag *_HTMLTag::inputmode_none() { + attrib("inputmode", "none"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_text() { + attrib("inputmode", "text"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_decimal() { + attrib("inputmode", "decimal"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_numeric() { + attrib("inputmode", "numeric"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_tel() { + attrib("inputmode", "tel"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_search() { + attrib("inputmode", "search"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_email() { + attrib("inputmode", "email"); + + return this; +} +_HTMLTag *_HTMLTag::inputmode_url() { + attrib("inputmode", "url"); + + return this; +} + +_HTMLTag *_HTMLTag::attrib(const String &attr, const String &val) { + result += " " + attr + "=\"" + val + "\""; + + return this; +} + +_HTMLTag *_HTMLTag::start(const String &p_tag, const bool p_simple) { + simple = p_simple; + + result = "<" + p_tag; + + return this; +} + +_HTMLTag *_HTMLTag::reset() { + result.clear(); + + return this; +} + +_HTMLTag *_HTMLTag::close() { + if (simple) + result += "/>"; + else + result += ">"; + + return this; +} + +_HTMLBuilder *_HTMLTag::f() { + return owner; +} + +bool _HTMLTag::has_data() { + return result.size() > 0; +} + +_HTMLTag::_HTMLTag() { + simple = true; + owner = nullptr; +} + +void _HTMLTag::_bind_methods() { + ClassDB::bind_method(D_METHOD("style", "val"), &_HTMLTag::style); +} + +_HTMLBuilder *_HTMLBuilder::comment(const String &val) { + write_tag(); + + result += ""; + + return this; +} + +_HTMLTag *_HTMLBuilder::doctype() { + write_tag(); + + return tag.start("!DOCTYPE"); +} + +_HTMLBuilder *_HTMLBuilder::doctype(const String &val) { + write_tag(); + + result += ""; + + return this; +} + +_HTMLTag *_HTMLBuilder::a() { + write_tag(); + + return tag.start("a"); +} +_HTMLTag *_HTMLBuilder::abbr() { + write_tag(); + + return tag.start("abbr"); +} + +_HTMLTag *_HTMLBuilder::acronym() { // Not supported in HTML5. Use instead. Defines an acronym + write_tag(); + + return tag.start("acronym"); +} + +_HTMLTag *_HTMLBuilder::address() { + write_tag(); + + return tag.start("address"); +} + +_HTMLTag *_HTMLBuilder::applet() { // Not supported in HTML5. Use or instead. Defines an embedded applet + write_tag(); + + return tag.start("applet"); +} + +_HTMLTag *_HTMLBuilder::area() { + write_tag(); + + return tag.start("area"); +} + +_HTMLTag *_HTMLBuilder::article() { + write_tag(); + + return tag.start("article"); +} + +_HTMLTag *_HTMLBuilder::aside() { + write_tag(); + + return tag.start("aside"); +} + +_HTMLTag *_HTMLBuilder::audio() { + write_tag(); + + return tag.start("audio"); +} + +_HTMLTag *_HTMLBuilder::b() { + write_tag(); + + return tag.start("b"); +} + +_HTMLTag *_HTMLBuilder::basefont() { // Not supported in HTML5. Use CSS instead. Specifies a default color, size, and font for all text in a document + write_tag(); + + return tag.start("basefont"); +} + +_HTMLTag *_HTMLBuilder::bdi() { + write_tag(); + + return tag.start("bdi"); +} + +_HTMLTag *_HTMLBuilder::bdo() { + write_tag(); + + return tag.start("bdo"); +} + +_HTMLTag *_HTMLBuilder::big() { // Not supported in HTML5. Use CSS instead. Defines big text + write_tag(); + + return tag.start("big"); +} + +_HTMLTag *_HTMLBuilder::blockquote() { + write_tag(); + + return tag.start("blockquote"); +} + +_HTMLTag *_HTMLBuilder::body() { + write_tag(); + + return tag.start("body"); +} + +_HTMLTag *_HTMLBuilder::br() { + write_tag(); + + return tag.start("br", true); +} + +_HTMLTag *_HTMLBuilder::button() { + write_tag(); + + return tag.start("button"); +} + +_HTMLTag *_HTMLBuilder::canvas() { + write_tag(); + + return tag.start("canvas"); +} + +_HTMLTag *_HTMLBuilder::caption() { + write_tag(); + + return tag.start("caption"); +} + +_HTMLTag *_HTMLBuilder::center() { // Not supported in HTML5. Use CSS instead. Defines centered text + write_tag(); + + return tag.start("center"); +} + +_HTMLTag *_HTMLBuilder::cite() { + write_tag(); + + return tag.start("cite"); +} + +_HTMLTag *_HTMLBuilder::code() { + write_tag(); + + return tag.start("code"); +} + +_HTMLTag *_HTMLBuilder::col() { + write_tag(); + + return tag.start("col"); +} + +_HTMLTag *_HTMLBuilder::colgroup() { + write_tag(); + + return tag.start("colgroup"); +} + +_HTMLTag *_HTMLBuilder::data() { + write_tag(); + + return tag.start("cite"); +} + +_HTMLTag *_HTMLBuilder::datalist() { + write_tag(); + + return tag.start("datalist"); +} + +_HTMLTag *_HTMLBuilder::dd() { + write_tag(); + + return tag.start("dd"); +} + +_HTMLTag *_HTMLBuilder::del() { + write_tag(); + + return tag.start("del"); +} + +_HTMLTag *_HTMLBuilder::details() { + write_tag(); + + return tag.start("details"); +} + +_HTMLTag *_HTMLBuilder::dfn() { + write_tag(); + + return tag.start("dfn"); +} + +_HTMLTag *_HTMLBuilder::dialog() { + write_tag(); + + return tag.start("dialog"); +} + +_HTMLTag *_HTMLBuilder::dir() { // Not supported in HTML5. Use
    instead. + write_tag(); + + return tag.start("dir"); +} + +_HTMLTag *_HTMLBuilder::div() { + write_tag(); + + return tag.start("div"); +} + +_HTMLTag *_HTMLBuilder::dl() { + write_tag(); + + return tag.start("dl"); +} + +_HTMLTag *_HTMLBuilder::dt() { + write_tag(); + + return tag.start("dt"); +} + +_HTMLTag *_HTMLBuilder::em() { + write_tag(); + + return tag.start("em"); +} + +_HTMLTag *_HTMLBuilder::embed() { + write_tag(); + + return tag.start("embed"); +} + +_HTMLTag *_HTMLBuilder::fieldset() { + write_tag(); + + return tag.start("fieldset"); +} +_HTMLTag *_HTMLBuilder::figcaption() { + write_tag(); + + return tag.start("figcaption"); +} + +_HTMLTag *_HTMLBuilder::figure() { + write_tag(); + + return tag.start("figure"); +} + +_HTMLTag *_HTMLBuilder::font() { // Not supported in HTML5. + write_tag(); + + return tag.start("font"); +} + +_HTMLTag *_HTMLBuilder::footer() { + write_tag(); + + return tag.start("footer"); +} + +_HTMLTag *_HTMLBuilder::form() { + write_tag(); + + return tag.start("form"); +} + +_HTMLTag *_HTMLBuilder::frame() { // Not supported in HTML5. + write_tag(); + + return tag.start("frame"); +} + +_HTMLTag *_HTMLBuilder::frameset() { // Not supported in HTML5. + write_tag(); + + return tag.start("frameset"); +} + +_HTMLTag *_HTMLBuilder::h1() { + write_tag(); + + return tag.start("h1"); +} + +_HTMLTag *_HTMLBuilder::h2() { + write_tag(); + + return tag.start("h2"); +} + +_HTMLTag *_HTMLBuilder::h3() { + write_tag(); + + return tag.start("h3"); +} + +_HTMLTag *_HTMLBuilder::h4() { + write_tag(); + + return tag.start("h4"); +} + +_HTMLTag *_HTMLBuilder::h5() { + write_tag(); + + return tag.start("h5"); +} + +_HTMLTag *_HTMLBuilder::h6() { + write_tag(); + + return tag.start("h6"); +} + +_HTMLTag *_HTMLBuilder::head() { + write_tag(); + + return tag.start("head"); +} + +_HTMLTag *_HTMLBuilder::header() { + write_tag(); + + return tag.start("header"); +} + +_HTMLTag *_HTMLBuilder::hr() { + write_tag(); + + return tag.start("hr"); +} + +_HTMLTag *_HTMLBuilder::html() { + write_tag(); + + return tag.start("html"); +} + +_HTMLTag *_HTMLBuilder::i() { + write_tag(); + + return tag.start("i"); +} + +_HTMLTag *_HTMLBuilder::iframe() { + write_tag(); + + return tag.start("iframe"); +} + +_HTMLTag *_HTMLBuilder::img() { + write_tag(); + + return tag.start("img"); +} + +_HTMLTag *_HTMLBuilder::input() { + write_tag(); + + return tag.start("input"); +} + +_HTMLTag *_HTMLBuilder::ins() { + write_tag(); + + return tag.start("ins"); +} + +_HTMLTag *_HTMLBuilder::kbd() { + write_tag(); + + return tag.start("kbd"); +} + +_HTMLTag *_HTMLBuilder::label() { + write_tag(); + + return tag.start("label"); +} + +_HTMLTag *_HTMLBuilder::legend() { + write_tag(); + + return tag.start("legend"); +} + +_HTMLTag *_HTMLBuilder::li() { + write_tag(); + + return tag.start("li"); +} + +_HTMLTag *_HTMLBuilder::link() { + write_tag(); + + return tag.start("link"); +} + +_HTMLTag *_HTMLBuilder::main() { + write_tag(); + + return tag.start("main"); +} + +_HTMLTag *_HTMLBuilder::map() { + write_tag(); + + return tag.start("map"); +} +_HTMLTag *_HTMLBuilder::mark() { + write_tag(); + + return tag.start("mark"); +} + +_HTMLTag *_HTMLBuilder::meta() { + write_tag(); + + return tag.start("meta"); +} + +_HTMLTag *_HTMLBuilder::meter() { + write_tag(); + + return tag.start("meter"); +} + +_HTMLTag *_HTMLBuilder::nav() { + write_tag(); + + return tag.start("nav"); +} + +_HTMLTag *_HTMLBuilder::noframes() { // Not supported in HTML5. + write_tag(); + + return tag.start("noframes"); +} + +_HTMLTag *_HTMLBuilder::noscript() { + write_tag(); + + return tag.start("noscript"); +} + +_HTMLTag *_HTMLBuilder::object() { + write_tag(); + + return tag.start("object"); +} + +_HTMLTag *_HTMLBuilder::ol() { + write_tag(); + + return tag.start("ol"); +} + +_HTMLTag *_HTMLBuilder::optgroup() { + write_tag(); + + return tag.start("optgroup"); +} + +_HTMLTag *_HTMLBuilder::option() { + write_tag(); + + return tag.start("option"); +} + +_HTMLTag *_HTMLBuilder::output() { + write_tag(); + + return tag.start("output"); +} + +_HTMLTag *_HTMLBuilder::p() { + write_tag(); + + return tag.start("p"); +} + +_HTMLTag *_HTMLBuilder::param() { + write_tag(); + + return tag.start("param"); +} + +_HTMLTag *_HTMLBuilder::picture() { + write_tag(); + + return tag.start("picture"); +} + +_HTMLTag *_HTMLBuilder::pre() { + write_tag(); + + return tag.start("pre"); +} + +_HTMLTag *_HTMLBuilder::progress() { + write_tag(); + + return tag.start("progress"); +} + +_HTMLTag *_HTMLBuilder::q() { + write_tag(); + + return tag.start("q"); +} + +_HTMLTag *_HTMLBuilder::rp() { + write_tag(); + + return tag.start("rp"); +} + +_HTMLTag *_HTMLBuilder::rt() { + write_tag(); + + return tag.start("rt"); +} + +_HTMLTag *_HTMLBuilder::ruby() { + write_tag(); + + return tag.start("ruby"); +} + +_HTMLTag *_HTMLBuilder::s() { + write_tag(); + + return tag.start("s"); +} + +_HTMLTag *_HTMLBuilder::samp() { + write_tag(); + + return tag.start("samp"); +} + +_HTMLTag *_HTMLBuilder::script() { + write_tag(); + + return tag.start("script"); +} + +_HTMLTag *_HTMLBuilder::section() { + write_tag(); + + return tag.start("section"); +} + +_HTMLTag *_HTMLBuilder::select() { + write_tag(); + + return tag.start("select"); +} + +_HTMLTag *_HTMLBuilder::small() { + write_tag(); + + return tag.start("small"); +} + +_HTMLTag *_HTMLBuilder::source() { + write_tag(); + + return tag.start("source"); +} + +_HTMLTag *_HTMLBuilder::span() { + write_tag(); + + return tag.start("span"); +} + +_HTMLTag *_HTMLBuilder::strike() { // Not supported in HTML5 + write_tag(); + + return tag.start("strike"); +} + +_HTMLTag *_HTMLBuilder::strong() { + write_tag(); + + return tag.start("strong"); +} + +_HTMLTag *_HTMLBuilder::style() { + write_tag(); + + return tag.start("style"); +} + +_HTMLTag *_HTMLBuilder::sub() { + write_tag(); + + return tag.start("sub"); +} + +_HTMLTag *_HTMLBuilder::summary() { + write_tag(); + + return tag.start("summary"); +} + +_HTMLTag *_HTMLBuilder::sup() { + write_tag(); + + return tag.start("sup"); +} + +_HTMLTag *_HTMLBuilder::svg() { + write_tag(); + + return tag.start("svg"); +} + +_HTMLTag *_HTMLBuilder::table() { + write_tag(); + + return tag.start("table"); +} + +_HTMLTag *_HTMLBuilder::tbody() { + write_tag(); + + return tag.start("tbody"); +} + +_HTMLTag *_HTMLBuilder::td() { + write_tag(); + + return tag.start("td"); +} + +_HTMLTag *_HTMLBuilder::templateh() { + write_tag(); + + return tag.start("template"); +} + +_HTMLTag *_HTMLBuilder::textarea() { + write_tag(); + + return tag.start("textarea"); +} + +_HTMLTag *_HTMLBuilder::tfoot() { + write_tag(); + + return tag.start("tfoot"); +} + +_HTMLTag *_HTMLBuilder::th() { + write_tag(); + + return tag.start("th"); +} + +_HTMLTag *_HTMLBuilder::thead() { + write_tag(); + + return tag.start("thead"); +} + +_HTMLTag *_HTMLBuilder::time() { + write_tag(); + + return tag.start("time"); +} + +_HTMLTag *_HTMLBuilder::title() { + write_tag(); + + return tag.start("title"); +} + +_HTMLTag *_HTMLBuilder::tr() { + write_tag(); + + return tag.start("tr"); +} + +_HTMLTag *_HTMLBuilder::track() { + write_tag(); + + return tag.start("track"); +} + +_HTMLTag *_HTMLBuilder::tt() { // Not supported in HTML5. + write_tag(); + + return tag.start("tt"); +} + +_HTMLTag *_HTMLBuilder::u() { + write_tag(); + + return tag.start("u"); +} + +_HTMLTag *_HTMLBuilder::ul() { + write_tag(); + + return tag.start("ul"); +} + +_HTMLTag *_HTMLBuilder::var() { + write_tag(); + + return tag.start("var"); +} + +_HTMLTag *_HTMLBuilder::video() { + write_tag(); + + return tag.start("video"); +} + +_HTMLTag *_HTMLBuilder::wbr() { + write_tag(); + + return tag.start("wbr"); +} + +//_HTMLBuilder *_HTMLBuilder::a(const String &href, const String &cls, const String &id) { +/* + _HTMLTag *t = a(); + + t->href(href); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } +*/ +// return this; +//} + +_HTMLBuilder *_HTMLBuilder::fa(const String &href, const String &body, const String &cls, const String &id) { + //a(href, cls, id); + w(body); + ca(); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::div(const String &cls, const String &id) { + _HTMLTag *t = div(); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::fdiv(const String &body, const String &cls, const String &id) { + div(cls, id); + w(body); + cdiv(); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::textarea(const String &name, const String &cls, const String &id) { + _HTMLTag *t = textarea(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} +_HTMLBuilder *_HTMLBuilder::ftextarea(const String &name, const String &body, const String &cls, const String &id) { + textarea(name, cls, id); + w(body); + ctextarea(); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::select(const String &name, const String &cls, const String &id) { + _HTMLTag *t = select(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLTag *_HTMLBuilder::option(const String &value) { + _HTMLTag *t = option(); + + t->value(value); + + return t; +} +_HTMLBuilder *_HTMLBuilder::foption(const String &value, const String &body, const bool selected) { + option(value)->selected(selected); + w(body); + coption(); + + return this; +} + +// Closing tags + +_HTMLBuilder *_HTMLBuilder::ca() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cabbr() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cacronym() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::caddress() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::capplet() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::carea() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::carticle() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::caside() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::caudio() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cb() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbasefont() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbdi() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbdo() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbig() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cblockquote() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbody() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cbutton() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccanvas() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccaption() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccenter() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccite() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccode() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccol() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ccolgroup() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdata() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdatalist() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdd() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdel() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdetails() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdfn() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdialog() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdir() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdiv() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdl() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cdt() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cem() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cembed() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cfieldset() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cfigcaption() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cfigure() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cfont() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cfooter() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cform() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cframe() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cframeset() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch1() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch2() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch3() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch4() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch5() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ch6() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::chead() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cheader() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::chr() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::chtml() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ci() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ciframe() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cimg() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cinput() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cins() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ckbd() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::clabel() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::clegend() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cli() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::clink() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cmain() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cmap() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cmark() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cmeta() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cmeter() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cnav() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cnoframes() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cnoscript() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cobject() { + write_tag(); + result += "
"; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::c_ol() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::coptgroup() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::coption() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::coutput() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cp() { + write_tag(); + result += "

"; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cparam() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cpicture() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cpre() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cprogress() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cq() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::crp() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::crt() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cruby() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cs() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csamp() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cscript() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csection() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cselect() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csmall() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csource() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cspan() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cstrike() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cstrong() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cstyle() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csub() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csummary() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csup() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csvg() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctable() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctbody() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctd() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctemplateh() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctextarea() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctfoot() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cth() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cthead() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctime() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctitle() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctr() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctrack() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::ctt() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cu() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cul() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cvar() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cvideo() { + write_tag(); + result += ""; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::cwbr() { + write_tag(); + result += ""; + + return this; +} + +_HTMLTag *_HTMLBuilder::form_get() { + write_tag(); + + return tag.start("form")->method_get(); +} +_HTMLTag *_HTMLBuilder::form_post() { + write_tag(); + + return tag.start("form")->method_post(); +} +_HTMLBuilder *_HTMLBuilder::form_get(const String &action, const String &cls, const String &id) { + _HTMLTag *t = form_get(); + + t->fora(action); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} +_HTMLBuilder *_HTMLBuilder::form_post(const String &action, const String &cls, const String &id) { + _HTMLTag *t = form_post(); + + t->action(action); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +/* +_HTMLBuilder *_HTMLBuilder::form_post(const String &action, Request *request, const String &cls, const String &id) { + form_post(action, cls, id); + csrf_token(request); + + return this; +} +*/ + +_HTMLTag *_HTMLBuilder::input_button() { + write_tag(); + + return tag.start("input")->itbutton(); +} + +_HTMLTag *_HTMLBuilder::input_checkbox() { + write_tag(); + + return tag.start("input")->itcheckbox(); +} + +_HTMLTag *_HTMLBuilder::input_color() { + write_tag(); + + return tag.start("input")->itcolor(); +} + +_HTMLTag *_HTMLBuilder::input_date() { + write_tag(); + + return tag.start("input")->itdate(); +} + +_HTMLTag *_HTMLBuilder::input_datetime_local() { + write_tag(); + + return tag.start("input")->itdatetime_local(); +} + +_HTMLTag *_HTMLBuilder::input_email() { + write_tag(); + + return tag.start("input")->itemail(); +} + +_HTMLTag *_HTMLBuilder::input_file() { + write_tag(); + + return tag.start("input")->itfile(); +} + +_HTMLTag *_HTMLBuilder::input_hidden() { + write_tag(); + + return tag.start("input")->ithidden(); +} + +_HTMLTag *_HTMLBuilder::input_image() { + write_tag(); + + return tag.start("input")->itimage(); +} + +_HTMLTag *_HTMLBuilder::input_month() { + write_tag(); + + return tag.start("input")->itmonth(); +} + +_HTMLTag *_HTMLBuilder::input_number() { + write_tag(); + + return tag.start("input")->itnumber(); +} + +_HTMLTag *_HTMLBuilder::input_password() { + write_tag(); + + return tag.start("input")->itpassword(); +} + +_HTMLTag *_HTMLBuilder::input_radio() { + write_tag(); + + return tag.start("input")->itradio(); +} + +_HTMLTag *_HTMLBuilder::input_range() { + write_tag(); + + return tag.start("input")->itrange(); +} + +_HTMLTag *_HTMLBuilder::input_reset() { + write_tag(); + + return tag.start("input")->itreset(); +} + +_HTMLTag *_HTMLBuilder::input_search() { + write_tag(); + + return tag.start("input")->itsearch(); +} + +_HTMLTag *_HTMLBuilder::input_submit() { + write_tag(); + + return tag.start("input")->itsubmit(); +} + +_HTMLTag *_HTMLBuilder::input_tel() { + write_tag(); + + return tag.start("input")->ittel(); +} + +_HTMLTag *_HTMLBuilder::input_text() { + write_tag(); + + return tag.start("input")->ittext(); +} + +_HTMLTag *_HTMLBuilder::input_time() { + write_tag(); + + return tag.start("input")->ittime(); +} + +_HTMLTag *_HTMLBuilder::input_url() { + write_tag(); + + return tag.start("input")->iturl(); +} + +_HTMLTag *_HTMLBuilder::input_week() { + write_tag(); + + return tag.start("input")->itweek(); +} + +_HTMLBuilder *_HTMLBuilder::label(const String &pfor, const String &plabel, const String &cls, const String &id) { + _HTMLTag *t = label(); + + t->fora(pfor); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + w(plabel); + + clabel(); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_button(const String &name, const String &value, const String &cls, const String &id) { + _HTMLTag *t = input_button(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_checkbox(const String &name, const String &value, const bool checked, const String &cls, const String &id) { + _HTMLTag *t = input_checkbox(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + t->checked(checked); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_color(const String &name, const String &value, const String &cls, const String &id) { + _HTMLTag *t = input_color(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_date(const String &name, const String &value, const String &cls, const String &id, const String &date_min, const String &date_max, const String &date_step) { + _HTMLTag *t = input_date(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (date_min != "") { + t->min(date_min); + } + + if (date_max != "") { + t->max(date_max); + } + + if (date_step != "") { + t->step(date_step); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_datetime_local(const String &name, const String &value, const String &cls, const String &id, const String &date_min, const String &date_max, const String &date_step) { + _HTMLTag *t = input_datetime_local(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (date_min != "") { + t->min(date_min); + } + + if (date_max != "") { + t->max(date_max); + } + + if (date_step != "") { + t->step(date_step); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_email(const String &name, const String &value, const String &placeholder, const String &cls, const String &id) { + _HTMLTag *t = input_email(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_file(const String &name, const String &accept, const String &cls, const String &id) { + _HTMLTag *t = input_file(); + + t->name(name); + + if (accept != "") { + t->accept(accept); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_image(const String &name, const String &src, const String &alt, const String &cls, const String &id, const int width, const int height) { + _HTMLTag *t = input_image(); + + t->name(name); + + if (src != "") { + t->src(src); + } + + if (alt != "") { + t->alt(alt); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (width != 0) { + t->width(width); + } + + if (height != 0) { + t->height(height); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_month(const String &name, const String &cls, const String &id) { + _HTMLTag *t = input_month(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_number(const String &name, const String &vmin, const String &vmax, const String &cls, const String &id) { + _HTMLTag *t = input_number(); + + t->name(name); + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_password(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + _HTMLTag *t = input_password(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_radio(const String &name, const String &value, const String &cls, const String &id) { + _HTMLTag *t = input_password(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_range(const String &name, const String &value, const String &vmin, const String &vmax, const String &vstep, const String &cls, const String &id) { + _HTMLTag *t = input_range(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (vstep != "") { + t->step(vstep); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_reset(const String &name, const String &value, const String &cls, const String &id) { + _HTMLTag *t = input_reset(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_search(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size, const String &pattern) { + _HTMLTag *t = input_search(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + if (pattern != "") { + t->pattern(pattern); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_submit(const String &value, const String &cls, const String &id) { + _HTMLTag *t = input_submit(); + + t->value(value); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_tel(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size, const String &pattern) { + _HTMLTag *t = input_tel(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + if (pattern != "") { + t->pattern(pattern); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_text(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + _HTMLTag *t = input_text(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_time(const String &name, const String &cls, const String &id, const String &vmin, const String &vmax, const String &vstep) { + _HTMLTag *t = input_time(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + if (vstep != "") { + t->step(vstep); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_url(const String &name, const String &value, const String &placeholder, const String &cls, const String &id, const String &minlength, const String &maxlength, const String &size) { + _HTMLTag *t = input_url(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + if (placeholder != "") { + t->placeholder(placeholder); + } + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (minlength != "") { + t->minlength(minlength); + } + + if (maxlength != "") { + t->maxlength(maxlength); + } + + if (size != "") { + t->size(size); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_week(const String &name, const String &cls, const String &id, const String &vmin, const String &vmax) { + _HTMLTag *t = input_week(); + + t->name(name); + + if (cls != "") { + t->cls(cls); + } + + if (id != "") { + t->id(id); + } + + if (vmin != "") { + t->min(vmin); + } + + if (vmax != "") { + t->max(vmax); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::input_hidden(const String &name, const String &value) { + _HTMLTag *t = input_hidden(); + + t->name(name); + + if (value != "") { + t->value(value); + } + + return this; +} + +_HTMLBuilder *_HTMLBuilder::csrf_token(const String &token) { + if (token == "") { + // don't waste html characters if it's an empty string anyway + return this; + } + + input_hidden("csrf_token", token); + + return this; +} +/* +_HTMLBuilder *_HTMLBuilder::csrf_token(Request *request) { + return csrf_token(request->get_csrf_token()); +} +*/ + +void _HTMLBuilder::f() { + write_tag(); +} + +_HTMLBuilder *_HTMLBuilder::w(const String &val) { + write_tag(); + + result += val; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::wn(const double val, int p_decimals) { + write_tag(); + + result += String::num(val, p_decimals); + + return this; +} +_HTMLBuilder *_HTMLBuilder::wns(const double val) { + write_tag(); + + result += String::num_scientific(val); + + return this; +} +_HTMLBuilder *_HTMLBuilder::wr(const double val, const bool p_trailing) { + write_tag(); + + //TODO + //result += String::num_real(val, p_trailing); + + return this; +} +_HTMLBuilder *_HTMLBuilder::wi(const int64_t val, const int base, const bool capitalize_hex) { + write_tag(); + + result += String::num_int64(val, base, capitalize_hex); + + return this; +} +_HTMLBuilder *_HTMLBuilder::wui(const uint64_t val, const int base, const bool capitalize_hex) { + write_tag(); + + result += String::num_uint64(val, base, capitalize_hex); + + return this; +} + +_HTMLBuilder *_HTMLBuilder::wbn(const bool val) { + write_tag(); + + //TODO + //result += String::bool_num(val); + + return this; +} +_HTMLBuilder *_HTMLBuilder::wbs(const bool val) { + write_tag(); + + //TODO + //result += String::bool_str(val); + + return this; +} + +// TODO! +_HTMLBuilder *_HTMLBuilder::we(const String &val) { + //print_error("_HTMLBuilder::write_excaped NYI!"); + + write_tag(); + + result += val; + + return this; +} + +_HTMLBuilder *_HTMLBuilder::write_tag() { + if (tag.has_data()) { + tag.close(); + result += tag.result; + tag.reset(); + } + + return this; +} + +_HTMLBuilder::_HTMLBuilder() { + tag.owner = this; +} + +_HTMLBuilder::~_HTMLBuilder() { +} + +void _HTMLBuilder::_bind_methods() { + ClassDB::bind_method(D_METHOD("a"), &_HTMLBuilder::a); + //_HTMLTag *a(); +} diff --git a/modules/web/html/html_builder_bind.h b/modules/web/html/html_builder_bind.h new file mode 100644 index 000000000..c9ce52c11 --- /dev/null +++ b/modules/web/html/html_builder_bind.h @@ -0,0 +1,562 @@ +#ifndef HTML_BUILDER_BIND_H +#define HTML_BUILDER_BIND_H + +#include "core/object.h" +#include "core/ustring.h" + +#include "core/reference.h" + +class _HTMLBuilder; + +class _HTMLTag : public Reference { + GDCLASS(_HTMLTag, Reference) + +public: + bool simple; + String result; + + _HTMLTag *str(const String &str); + _HTMLTag *style(const String &val); + _HTMLTag *href(const String &val); + _HTMLTag *cls(const String &val); + _HTMLTag *clsse(const String &val); //se -> skip empty + _HTMLTag *id(const String &val); + _HTMLTag *name(const String &val); + _HTMLTag *content(const String &val); + _HTMLTag *value(const String &val); + _HTMLTag *accept(const String &val); + _HTMLTag *src(const String &val); + _HTMLTag *alt(const String &val); + _HTMLTag *inputmode(const String &val); + _HTMLTag *list(const String &val); + + _HTMLTag *autocomplete(const String &val); + + _HTMLTag *autocomplete_off(); + _HTMLTag *autocomplete_on(); + _HTMLTag *autocomplete_name(); + _HTMLTag *autocomplete_name_honorific_prefix(); + _HTMLTag *autocomplete_name_given_name(); + _HTMLTag *autocomplete_name_additional_name(); + _HTMLTag *autocomplete_name_family_name(); + _HTMLTag *autocomplete_name_honorific_suffix(); + _HTMLTag *autocomplete_name_nickname(); + _HTMLTag *autocomplete_email(); + _HTMLTag *autocomplete_username(); + _HTMLTag *autocomplete_new_password(); + _HTMLTag *autocomplete_current_password(); + _HTMLTag *autocomplete_one_time_code(); + _HTMLTag *autocomplete_organization_title(); + _HTMLTag *autocomplete_organization(); + _HTMLTag *autocomplete_street_address(); + _HTMLTag *autocomplete_address_line1(); + _HTMLTag *autocomplete_address_line2(); + _HTMLTag *autocomplete_address_line3(); + _HTMLTag *autocomplete_address_level_1(); + _HTMLTag *autocomplete_address_level_2(); + _HTMLTag *autocomplete_address_level_3(); + _HTMLTag *autocomplete_address_level_4(); + _HTMLTag *autocomplete_country(); + _HTMLTag *autocomplete_country_name(); + _HTMLTag *autocomplete_postal_code(); + _HTMLTag *autocomplete_cc_name(); + _HTMLTag *autocomplete_cc_given_name(); + _HTMLTag *autocomplete_cc_additional_name(); + _HTMLTag *autocomplete_cc_family_name(); + _HTMLTag *autocomplete_cc_number(); + _HTMLTag *autocomplete_cc_exp(); + _HTMLTag *autocomplete_cc_exp_month(); + _HTMLTag *autocomplete_cc_exp_year(); + _HTMLTag *autocomplete_cc_csc(); + _HTMLTag *autocomplete_cc_type(); + _HTMLTag *autocomplete_transaction_currency(); + _HTMLTag *autocomplete_transaction_amount(); + _HTMLTag *autocomplete_language(); + _HTMLTag *autocomplete_bday(); + _HTMLTag *autocomplete_bday_day(); + _HTMLTag *autocomplete_bday_month(); + _HTMLTag *autocomplete_bday_year(); + _HTMLTag *autocomplete_sex(); + _HTMLTag *autocomplete_tel(); + _HTMLTag *autocomplete_tel_country_code(); + _HTMLTag *autocomplete_tel_national(); + _HTMLTag *autocomplete_tel_area_code(); + _HTMLTag *autocomplete_tel_local(); + _HTMLTag *autocomplete_tel_extension(); + _HTMLTag *autocomplete_impp(); + _HTMLTag *autocomplete_url(); + _HTMLTag *autocomplete_photo(); + + _HTMLTag *onclick(const String &val); + + _HTMLTag *checked(const bool val = true); + _HTMLTag *selected(const bool val = true); + _HTMLTag *autofocus(const bool val = true); + _HTMLTag *disabled(const bool val = true); + _HTMLTag *multiple(const bool val = true); + _HTMLTag *required(const bool val = true); + _HTMLTag *spellcheck(const bool val); + + _HTMLTag *max(const String &val); + _HTMLTag *min(const String &val); + _HTMLTag *step(const String &val); + _HTMLTag *step_any(); + + _HTMLTag *minlength(const int val); + _HTMLTag *minlength(const String &val); + _HTMLTag *maxlength(const int val); + _HTMLTag *maxlength(const String &val); + _HTMLTag *size(const int val); + _HTMLTag *size(const String &val); + + _HTMLTag *width(const int val); + _HTMLTag *width(const String &val); + _HTMLTag *height(const int val); + _HTMLTag *height(const String &val); + + _HTMLTag *pattern(const String &val); + + _HTMLTag *method(const String &val); + _HTMLTag *method_get(); + _HTMLTag *method_post(); + + _HTMLTag *action(const String &val); + _HTMLTag *type(const String &val); + _HTMLTag *placeholder(const String &val); + _HTMLTag *fora(const String &val); // for attrib -> for is reserved keyword + + _HTMLTag *rel(const String &val); + _HTMLTag *rel_stylesheet(); + _HTMLTag *rel_alternate(); + _HTMLTag *rel_author(); + _HTMLTag *rel_bookmark(); + _HTMLTag *rel_external(); + _HTMLTag *rel_help(); + _HTMLTag *rel_license(); + _HTMLTag *rel_next(); + _HTMLTag *rel_nofollow(); + _HTMLTag *rel_noopener(); + _HTMLTag *rel_noreferrer(); + _HTMLTag *rel_prev(); + _HTMLTag *rel_search(); + _HTMLTag *rel_tag(); + + _HTMLTag *charset(const String &val); + _HTMLTag *charset_utf_8(); + + _HTMLTag *itbutton(); + _HTMLTag *itcheckbox(); + _HTMLTag *itcolor(); + _HTMLTag *itdate(); + _HTMLTag *itdatetime_local(); + _HTMLTag *itemail(); + _HTMLTag *itfile(); + _HTMLTag *ithidden(); + _HTMLTag *itimage(); + _HTMLTag *itmonth(); + _HTMLTag *itnumber(); + _HTMLTag *itpassword(); + _HTMLTag *itradio(); + _HTMLTag *itrange(); + _HTMLTag *itreset(); + _HTMLTag *itsearch(); + _HTMLTag *itsubmit(); + _HTMLTag *ittel(); + _HTMLTag *ittext(); + _HTMLTag *ittime(); + _HTMLTag *iturl(); + _HTMLTag *itweek(); + + _HTMLTag *inputmode_none(); + _HTMLTag *inputmode_text(); + _HTMLTag *inputmode_decimal(); + _HTMLTag *inputmode_numeric(); + _HTMLTag *inputmode_tel(); + _HTMLTag *inputmode_search(); + _HTMLTag *inputmode_email(); + _HTMLTag *inputmode_url(); + + _HTMLTag *attrib(const String &attr, const String &val); + + _HTMLTag *start(const String &p_new_tag, const bool p_simple = false); + _HTMLTag *reset(); + _HTMLTag *close(); + + _HTMLBuilder *f(); + + bool has_data(); + + _HTMLTag(); + + _HTMLBuilder *owner; + +protected: + static void _bind_methods(); +}; + +class _HTMLBuilder : public Reference { + GDCLASS(_HTMLBuilder, Reference) + +public: + String result; + + _HTMLBuilder *comment(const String &val); + _HTMLTag *doctype(); + _HTMLBuilder *doctype(const String &val); + + _HTMLTag *a(); + _HTMLTag *abbr(); + _HTMLTag *acronym(); // Not supported in HTML5. + _HTMLTag *address(); + _HTMLTag *applet(); // Not supported in HTML5. + _HTMLTag *area(); + _HTMLTag *article(); + _HTMLTag *aside(); + _HTMLTag *audio(); + _HTMLTag *b(); + _HTMLTag *basefont(); // Not supported in HTML5. + _HTMLTag *bdi(); + _HTMLTag *bdo(); + _HTMLTag *big(); // Not supported in HTML5. + _HTMLTag *blockquote(); + _HTMLTag *body(); + _HTMLTag *br(); + _HTMLTag *button(); + _HTMLTag *canvas(); + _HTMLTag *caption(); + _HTMLTag *center(); // Not supported in HTML5. + _HTMLTag *cite(); + _HTMLTag *code(); + _HTMLTag *col(); + _HTMLTag *colgroup(); + _HTMLTag *data(); + _HTMLTag *datalist(); + _HTMLTag *dd(); + _HTMLTag *del(); + _HTMLTag *details(); + _HTMLTag *dfn(); + _HTMLTag *dialog(); + _HTMLTag *dir(); // Not supported in HTML5. + _HTMLTag *div(); + _HTMLTag *dl(); + _HTMLTag *dt(); + _HTMLTag *em(); + _HTMLTag *embed(); + _HTMLTag *fieldset(); + _HTMLTag *figcaption(); + _HTMLTag *figure(); + _HTMLTag *font(); // Not supported in HTML5. + _HTMLTag *footer(); + _HTMLTag *form(); + _HTMLTag *frame(); // Not supported in HTML5. + _HTMLTag *frameset(); // Not supported in HTML5. + _HTMLTag *h1(); + _HTMLTag *h2(); + _HTMLTag *h3(); + _HTMLTag *h4(); + _HTMLTag *h5(); + _HTMLTag *h6(); + _HTMLTag *head(); + _HTMLTag *header(); + _HTMLTag *hr(); + _HTMLTag *html(); + + _HTMLTag *i(); + _HTMLTag *iframe(); + _HTMLTag *img(); + _HTMLTag *input(); + _HTMLTag *ins(); + _HTMLTag *kbd(); + _HTMLTag *label(); + _HTMLTag *legend(); + _HTMLTag *li(); + _HTMLTag *link(); + _HTMLTag *main(); + _HTMLTag *map(); + _HTMLTag *mark(); + _HTMLTag *meta(); + _HTMLTag *meter(); + + _HTMLTag *nav(); + _HTMLTag *noframes(); // Not supported in HTML5. + _HTMLTag *noscript(); + _HTMLTag *object(); + _HTMLTag *ol(); + _HTMLTag *optgroup(); + _HTMLTag *option(); + _HTMLTag *output(); + _HTMLTag *p(); + _HTMLTag *param(); + _HTMLTag *picture(); + _HTMLTag *pre(); + _HTMLTag *progress(); + _HTMLTag *q(); + _HTMLTag *rp(); + + _HTMLTag *rt(); + _HTMLTag *ruby(); + _HTMLTag *s(); + _HTMLTag *samp(); + _HTMLTag *script(); + _HTMLTag *section(); + _HTMLTag *select(); + _HTMLTag *small(); + _HTMLTag *source(); + _HTMLTag *span(); + _HTMLTag *strike(); // Not supported in HTML5 + _HTMLTag *strong(); + _HTMLTag *style(); + _HTMLTag *sub(); + _HTMLTag *summary(); + _HTMLTag *sup(); + + _HTMLTag *svg(); + _HTMLTag *table(); + _HTMLTag *tbody(); + _HTMLTag *td(); + _HTMLTag *templateh(); + _HTMLTag *textarea(); + _HTMLTag *tfoot(); + _HTMLTag *th(); + _HTMLTag *thead(); + _HTMLTag *time(); + _HTMLTag *title(); + _HTMLTag *tr(); + _HTMLTag *track(); + _HTMLTag *tt(); // Not supported in HTML5. + _HTMLTag *u(); + _HTMLTag *ul(); + _HTMLTag *var(); + _HTMLTag *video(); + _HTMLTag *wbr(); + + //_HTMLBuilder *a(const String &href, const String &cls = "", const String &id = ""); + _HTMLBuilder *fa(const String &href, const String &body, const String &cls = "", const String &id = ""); + + _HTMLBuilder *div(const String &cls, const String &id = ""); + _HTMLBuilder *fdiv(const String &body, const String &cls = "", const String &id = ""); + + _HTMLBuilder *textarea(const String &name, const String &cls = "", const String &id = ""); + _HTMLBuilder *ftextarea(const String &name, const String &body, const String &cls = "", const String &id = ""); + + _HTMLBuilder *select(const String &name, const String &cls = "", const String &id = ""); + + _HTMLTag *option(const String &value); + _HTMLBuilder *foption(const String &value, const String &body, const bool selected = false); + + // closing tags c prefix means close + // Note simple tags should not have these like
+ // Note that I might have a few that shouldn't be here, those will be removed as I find them + _HTMLBuilder *ca(); + _HTMLBuilder *cabbr(); + _HTMLBuilder *cacronym(); + _HTMLBuilder *caddress(); + _HTMLBuilder *capplet(); + _HTMLBuilder *carea(); + _HTMLBuilder *carticle(); + _HTMLBuilder *caside(); + _HTMLBuilder *caudio(); + _HTMLBuilder *cb(); + _HTMLBuilder *cbasefont(); + _HTMLBuilder *cbdi(); + _HTMLBuilder *cbdo(); + _HTMLBuilder *cbig(); + _HTMLBuilder *cblockquote(); + _HTMLBuilder *cbody(); + _HTMLBuilder *cbutton(); + _HTMLBuilder *ccanvas(); + + _HTMLBuilder *ccaption(); + _HTMLBuilder *ccenter(); + _HTMLBuilder *ccite(); + _HTMLBuilder *ccode(); + _HTMLBuilder *ccol(); + _HTMLBuilder *ccolgroup(); + _HTMLBuilder *cdata(); + _HTMLBuilder *cdatalist(); + _HTMLBuilder *cdd(); + _HTMLBuilder *cdel(); + _HTMLBuilder *cdetails(); + _HTMLBuilder *cdfn(); + _HTMLBuilder *cdialog(); + _HTMLBuilder *cdir(); + _HTMLBuilder *cdiv(); + _HTMLBuilder *cdl(); + _HTMLBuilder *cdt(); + + _HTMLBuilder *cem(); + _HTMLBuilder *cembed(); + _HTMLBuilder *cfieldset(); + _HTMLBuilder *cfigcaption(); + _HTMLBuilder *cfigure(); + _HTMLBuilder *cfont(); + _HTMLBuilder *cfooter(); + _HTMLBuilder *cform(); + _HTMLBuilder *cframe(); + _HTMLBuilder *cframeset(); + _HTMLBuilder *ch1(); + _HTMLBuilder *ch2(); + _HTMLBuilder *ch3(); + _HTMLBuilder *ch4(); + _HTMLBuilder *ch5(); + _HTMLBuilder *ch6(); + _HTMLBuilder *chead(); + _HTMLBuilder *cheader(); + _HTMLBuilder *chr(); + _HTMLBuilder *chtml(); + + _HTMLBuilder *ci(); + _HTMLBuilder *ciframe(); + _HTMLBuilder *cimg(); + _HTMLBuilder *cinput(); + _HTMLBuilder *cins(); + _HTMLBuilder *ckbd(); + _HTMLBuilder *clabel(); + _HTMLBuilder *clegend(); + _HTMLBuilder *cli(); + _HTMLBuilder *clink(); + _HTMLBuilder *cmain(); + _HTMLBuilder *cmap(); + _HTMLBuilder *cmark(); + _HTMLBuilder *cmeta(); + _HTMLBuilder *cmeter(); + + _HTMLBuilder *cnav(); + _HTMLBuilder *cnoframes(); + _HTMLBuilder *cnoscript(); + _HTMLBuilder *cobject(); + _HTMLBuilder *c_ol(); + _HTMLBuilder *coptgroup(); + _HTMLBuilder *coption(); + _HTMLBuilder *coutput(); + _HTMLBuilder *cp(); + _HTMLBuilder *cparam(); + _HTMLBuilder *cpicture(); + _HTMLBuilder *cpre(); + _HTMLBuilder *cprogress(); + _HTMLBuilder *cq(); + _HTMLBuilder *crp(); + + _HTMLBuilder *crt(); + _HTMLBuilder *cruby(); + _HTMLBuilder *cs(); + _HTMLBuilder *csamp(); + _HTMLBuilder *cscript(); + _HTMLBuilder *csection(); + _HTMLBuilder *cselect(); + _HTMLBuilder *csmall(); + _HTMLBuilder *csource(); + _HTMLBuilder *cspan(); + _HTMLBuilder *cstrike(); + _HTMLBuilder *cstrong(); + _HTMLBuilder *cstyle(); + _HTMLBuilder *csub(); + _HTMLBuilder *csummary(); + _HTMLBuilder *csup(); + + _HTMLBuilder *csvg(); + _HTMLBuilder *ctable(); + _HTMLBuilder *ctbody(); + _HTMLBuilder *ctd(); + _HTMLBuilder *ctemplateh(); + _HTMLBuilder *ctextarea(); + _HTMLBuilder *ctfoot(); + _HTMLBuilder *cth(); + _HTMLBuilder *cthead(); + _HTMLBuilder *ctime(); + _HTMLBuilder *ctitle(); + _HTMLBuilder *ctr(); + _HTMLBuilder *ctrack(); + _HTMLBuilder *ctt(); + _HTMLBuilder *cu(); + _HTMLBuilder *cul(); + _HTMLBuilder *cvar(); + _HTMLBuilder *cvideo(); + _HTMLBuilder *cwbr(); + + _HTMLTag *form_get(); + _HTMLTag *form_post(); + _HTMLBuilder *form_get(const String &action, const String &cls = "", const String &id = ""); + _HTMLBuilder *form_post(const String &action, const String &cls = "", const String &id = ""); + // will add a csrf token from request + //_HTMLBuilder *form_post(const String &action, Request *request, const String &cls = "", const String &id = ""); + + _HTMLTag *input_button(); + _HTMLTag *input_checkbox(); + _HTMLTag *input_color(); + _HTMLTag *input_date(); + _HTMLTag *input_datetime_local(); + _HTMLTag *input_email(); + _HTMLTag *input_file(); + _HTMLTag *input_hidden(); + _HTMLTag *input_image(); + _HTMLTag *input_month(); + _HTMLTag *input_number(); + _HTMLTag *input_password(); + _HTMLTag *input_radio(); + _HTMLTag *input_range(); + _HTMLTag *input_reset(); + _HTMLTag *input_search(); + _HTMLTag *input_submit(); + _HTMLTag *input_tel(); + _HTMLTag *input_text(); + _HTMLTag *input_time(); + _HTMLTag *input_url(); + _HTMLTag *input_week(); + + _HTMLBuilder *label(const String &pfor, const String &plabel, const String &cls = "", const String &id = ""); + + _HTMLBuilder *input_button(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_checkbox(const String &name, const String &value = "", const bool checked = false, const String &cls = "", const String &id = ""); + _HTMLBuilder *input_color(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_date(const String &name, const String &value = "", const String &cls = "", const String &id = "", const String &date_min = "", const String &date_max = "", const String &date_step = ""); + _HTMLBuilder *input_datetime_local(const String &name, const String &value = "", const String &cls = "", const String &id = "", const String &date_min = "", const String &date_max = "", const String &date_step = ""); + _HTMLBuilder *input_email(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_file(const String &name, const String &accept = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_image(const String &name, const String &src = "", const String &alt = "", const String &cls = "", const String &id = "", const int width = 0, const int height = 0); + _HTMLBuilder *input_month(const String &name, const String &cls = "", const String &id = ""); + _HTMLBuilder *input_number(const String &name, const String & = "", const String & = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_password(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + _HTMLBuilder *input_radio(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_range(const String &name, const String &value = "", const String &vmin = "", const String &vmax = "", const String &vstep = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_reset(const String &name, const String &value = "", const String &cls = "", const String &id = ""); + _HTMLBuilder *input_search(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = "", const String &pattern = ""); + _HTMLBuilder *input_submit(const String &value, const String &cls = "", const String &id = ""); + _HTMLBuilder *input_tel(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = "", const String &pattern = ""); + _HTMLBuilder *input_text(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + _HTMLBuilder *input_time(const String &name, const String &cls = "", const String &id = "", const String &vmin = "", const String &vmax = "", const String &vstep = ""); + _HTMLBuilder *input_url(const String &name, const String &value = "", const String &placeholder = "", const String &cls = "", const String &id = "", const String &minlength = "", const String &maxlength = "", const String &size = ""); + _HTMLBuilder *input_week(const String &name, const String &cls = "", const String &id = "", const String &vmin = "", const String &vmax = ""); + _HTMLBuilder *input_hidden(const String &name, const String &value); + + _HTMLBuilder *csrf_token(const String &token); + //_HTMLBuilder *csrf_token(Request *request); + + void f(); + + // write + _HTMLBuilder *w(const String &val); + + _HTMLBuilder *wn(const double val, int p_decimals = -1); + _HTMLBuilder *wns(const double val); + _HTMLBuilder *wr(const double val, const bool p_trailing = true); + _HTMLBuilder *wi(const int64_t val, const int base = 10, const bool capitalize_hex = false); + _HTMLBuilder *wui(const uint64_t val, const int base = 10, const bool capitalize_hex = false); + _HTMLBuilder *wbn(const bool val); + _HTMLBuilder *wbs(const bool val); + + // write_escaped + _HTMLBuilder *we(const String &val); + + _HTMLBuilder *write_tag(); + + _HTMLBuilder(); + virtual ~_HTMLBuilder(); + +protected: + static void _bind_methods(); + + _HTMLTag tag; +}; + +#endif diff --git a/modules/web/html/html_parser.cpp b/modules/web/html/html_parser.cpp new file mode 100644 index 000000000..23fa52a6a --- /dev/null +++ b/modules/web/html/html_parser.cpp @@ -0,0 +1,676 @@ +#include "html_parser.h" +#include "core/error_macros.h" + +bool HTMLParserAttribute::match_attrib(const String &attrib) { + return attribute == attrib; +} +bool HTMLParserAttribute::match_data(const String &d) { + return data == d; +} +bool HTMLParserAttribute::match_data(const Vector &d) { + // todo + return false; +} +bool HTMLParserAttribute::contains_data(const String &d) { + return data.find(d) != -1; +} + +String HTMLParserAttribute::to_string() { + if (single) { + return attribute; + } + + if (data.find('"' == -1)) { + return attribute + "=\"" + data + "\""; + } else { + return attribute + "=\'" + data + "\'"; + } +} + +void HTMLParserAttribute::print() { + to_string().print(); +} + +HTMLParserAttribute::HTMLParserAttribute() { + single = false; +} + +HTMLParserAttribute::~HTMLParserAttribute() { +} + +HTMLParserTag *HTMLParserTag::get_first(const String &t) { + if (tag == t) { + return this; + } + + for (int i = 0; i < tags.size(); ++i) { + HTMLParserTag *ht = tags[i]->get_first(t); + + if (ht) { + return ht; + } + } + + return nullptr; +} + +HTMLParserTag *HTMLParserTag::get_first(const String &t, const String &attrib, const String &val) { + if (tag == t) { + if (has_attribute(attrib, val)) { + return this; + } + } + + for (int i = 0; i < tags.size(); ++i) { + HTMLParserTag *ht = tags[i]->get_first(t, attrib, val); + + if (ht) { + return ht; + } + } + + return nullptr; +} + +String HTMLParserTag::get_attribute_value(const String &attrib) { + HTMLParserAttribute *a = get_attribute(attrib); + + if (a) { + return a->data; + } + + return ""; +} + +HTMLParserAttribute *HTMLParserTag::get_attribute(const String &attrib) { + for (int i = 0; i < attributes.size(); ++i) { + HTMLParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib)) { + return a; + } + } + + return nullptr; +} + +bool HTMLParserTag::has_attribute(const String &attrib) { + for (int i = 0; i < attributes.size(); ++i) { + HTMLParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib)) { + return true; + } + } + + return false; +} + +HTMLParserAttribute *HTMLParserTag::get_attribute(const String &attrib, const String &contains_val) { + for (int i = 0; i < attributes.size(); ++i) { + HTMLParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib) && a->contains_data(contains_val)) { + return a; + } + } + + return nullptr; +} + +bool HTMLParserTag::has_attribute(const String &attrib, const String &contains_val) { + for (int i = 0; i < attributes.size(); ++i) { + HTMLParserAttribute *a = attributes[i]; + + if (a->match_attrib(attrib) && a->contains_data(contains_val)) { + return true; + } + } + + return false; +} + +void HTMLParserTag::process() { + if (type != HTMLParserTag::HTML_PARSER_TAG_TYPE_NONE) { + return; + } + + if (data.size() < 2) { + return; + } + + ERR_FAIL_COND(data[0] != '<'); + ERR_FAIL_COND(data[data.size() - 1] != '>'); + + int start_index = 1; + if (data[1] == '/') { + ++start_index; + + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_CLOSING_TAG; + } else if (data[1] == '!') { + if (data.size() < 8) { + return; + } + + // test for comment. + ++start_index; + if (data[2] == '-' && data[3] == '-') { + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_COMMENT; + + int comment_start_index = data.find(' ', 3); + + if (comment_start_index == -1) { + comment_start_index = 4; + } + + tag = data.substr(comment_start_index, data.size() - comment_start_index - 3); + } + + if (data.size() < 11) { + return; + } + + // test for doctype. + int doctype_start_index = data.find("doctype ", 2); + + if (doctype_start_index == -1) { + return; + } + + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_DOCTYPE; + + tag = data.substr(doctype_start_index + 8, data.size() - doctype_start_index - 8 - 1); + } else { + String tag_text; + + if (data[data.size() - 2] == '/') { + // will catch all that looks like
+ // tags that look like
will be caught later in a post process, in a way + // which also tries to catch erroneously not closed tags that supposed to be closed + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_SELF_CLOSING_TAG; + + tag_text = data.substr(1, data.size() - 3); + } else { + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_OPENING_TAG; + + tag_text = data.substr(1, data.size() - 2); + } + + int fspc_index = tag_text.find(' '); + + if (fspc_index == -1) { + // no args + tag = tag_text; + return; + } + + // grab the tag itself + tag = tag_text.substr(0, fspc_index); + + if (fspc_index + 1 == tag_text.size()) { + // no args, but had a space like
+ return; + } + + String args = tag_text.substr(fspc_index + 1, tag_text.size() - fspc_index - 1); + parse_args(args); + } + + int tag_end_index = data.find(' ', start_index); + + if (tag_end_index == -1) { + // simple tag + tag = data.substr(start_index, data.size() - start_index - 1); + return; + } +} + +void HTMLParserTag::parse_args(const String &args) { + attributes.clear(); + + int i = 0; + while (i < args.size()) { + if (args[i] == ' ') { + //"trim" + ++i; + continue; + } + + int equals_index = args.find('=', i); + + HTMLParserAttribute *a = new HTMLParserAttribute(); + + if (equals_index == -1) { + a->attribute = args.substr(i, args.size() - i); + a->single = true; + attributes.push_back(a); + + return; + } + + a->attribute = args.substr(i, equals_index - i); + + // todo + // a.trim(); + + int next_char_index = equals_index + 1; + + if (next_char_index >= args.size()) { + // an attribute looks like this "... attrib=" + attributes.push_back(a); + return; + } + + // skip spaces + while (args[next_char_index] == ' ') { + ++next_char_index; + + if (next_char_index >= args.size()) { + // an attribute looks like this "... attrib= " + attributes.push_back(a); + return; + } + } + + char c = args[next_char_index]; + char find_char = ' '; + + if (c == '"' || c == '\'') { + ++next_char_index; + find_char = c; + } + + int end_index = args.find(find_char, next_char_index); + + if (end_index == -1) { + // missing closing ' or " if c is ' or " + // else missing parameter + + a->data = args.substr(next_char_index, args.size() - next_char_index - 1); + attributes.push_back(a); + return; + } + + a->data = args.substr(next_char_index, end_index - next_char_index); + attributes.push_back(a); + + i = end_index + 1; + } +} + +String HTMLParserTag::to_string(const int level) { + String s; + + s.append_repeat(" ", level); + + if (type == HTML_PARSER_TAG_TYPE_CONTENT) { + s += data + "\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!CONTENT TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == HTML_PARSER_TAG_TYPE_OPENING_TAG) { + int ln = level + 1; + + s += "<" + tag; + + for (int i = 0; i < attributes.size(); ++i) { + s += " " + attributes[i]->to_string(); + } + + s += ">\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(ln); + } + + s.append_repeat(" ", level); + + s += "\n"; + } else if (type == HTML_PARSER_TAG_TYPE_CLOSING_TAG) { + // HTMLParserTag should handle this automatically + // it's here for debugging purposes though + s += ""; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!CLOSING TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == HTML_PARSER_TAG_TYPE_SELF_CLOSING_TAG) { + s += "<" + tag; + + for (int i = 0; i < attributes.size(); ++i) { + s += " " + attributes[i]->to_string(); + } + + s += "/>\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!SELF CLOSING TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == HTML_PARSER_TAG_TYPE_COMMENT) { + s += "\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!COMMENT TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == HTML_PARSER_TAG_TYPE_DOCTYPE) { + s += data + "\n"; + + if (tags.size() != 0) { + s.append_repeat(" ", level); + s += "(!DOCTYPE TAG HAS TAGS!)\n"; + + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level + 1) + "\n"; + } + } + } else if (type == HTML_PARSER_TAG_TYPE_NONE) { + for (int i = 0; i < tags.size(); ++i) { + s += tags[i]->to_string(level) + "\n"; + s.append_repeat(" ", level); + } + } + + return s; +} +void HTMLParserTag::print() { + to_string().print(); +} + +HTMLParserTag::HTMLParserTag() { + type = HTMLParserTag::HTML_PARSER_TAG_TYPE_NONE; +} + +HTMLParserTag::~HTMLParserTag() { + for (int i = 0; i < tags.size(); ++i) { + delete tags[i]; + } + + for (int i = 0; i < attributes.size(); ++i) { + delete attributes[i]; + } +} + +void HTMLParser::parse(const String &data) { + Vector tags; + + //