From 43daa77f6d3c581aadf868f36617eff409bd2e71 Mon Sep 17 00:00:00 2001 From: speedie Date: Tue, 7 May 2024 21:21:58 +0200 Subject: [PATCH] Implement support for plain text elements and sections without a tag. Also, add example replica of biteme.lol. --- examples/.gitignore | 2 ++ examples/biteme.lol.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ examples/hello-world.cpp | 14 +++++--- include/docpp.hpp | 3 ++ src/docpp.cpp | 63 ++++++++++++++++++++---------------- tests/test.cpp | 11 +++++++ 6 files changed, 130 insertions(+), 32 deletions(-) create mode 100644 examples/.gitignore create mode 100644 examples/biteme.lol.cpp diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..28ca104 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,2 @@ +a.out +*.html diff --git a/examples/biteme.lol.cpp b/examples/biteme.lol.cpp new file mode 100644 index 0000000..9038dc0 --- /dev/null +++ b/examples/biteme.lol.cpp @@ -0,0 +1,69 @@ +/** + * @file biteme.lol.cpp + * @brief A simple program that replicates biteme.lol using docpp. + * @details This program creates a simple HTML document that replicates the biteme.lol website. + * @see https://biteme.lol + * @license LGPL-3.0 + * + * g++ -std=c++11 biteme.lol.cpp -o biteme.lol -ldocpp + */ +#include +#include + +int main() { + docpp::HTML::HTMLSection html(docpp::HTML::SECTION_HTML, {}); + + html.push_back({"title", {}, "Google"}); + + docpp::CSS::CSSStylesheet sheet{}; + + sheet.push_back(docpp::CSS::CSSElement( + ".center", { + {"display", "flex"}, + {"flex-wrap", "wrap"}, + {"justify-content", "center"}, + {"align-items", "center"}, + {"font-size", "10vw"}, + {"height", "10vw"}, + {"padding", "10vw"}, + } + )); + + sheet.push_back(docpp::CSS::CSSElement( + "input[type=text], select", { + {"width", "50vw"}, + } + )); + + html.push_back({"style", {}, sheet.get(docpp::CSS::FORMATTING_PRETTY)}); + + docpp::HTML::HTMLSection div{docpp::HTML::SECTION_DIV, {docpp::HTML::HTMLProperty("class", "center")}}; + + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "blue")}, "G"}); + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "red")}, "o"}); + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "yellow")}, "o"}); + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "blue")}, "g"}); + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "green")}, "l"}); + div.push_back({"font", {docpp::HTML::HTMLProperty("color", "red")}, "e"}); + + html.push_back(div); + + docpp::HTML::HTMLSection div2{docpp::HTML::SECTION_DIV, {docpp::HTML::HTMLProperty("align", "center")}}; + docpp::HTML::HTMLSection form{"form", {{docpp::HTML::HTMLProperty("action", "https://google.com/search"), docpp::HTML::HTMLProperty("method", "get")}}}; + + form.push_back({"input", docpp::HTML::HTMLElementProperties({docpp::HTML::HTMLProperty("type", "text"), docpp::HTML::HTMLProperty("name", "q")}), "", docpp::HTML::TYPE_SELF_CLOSING}); + form.push_back({"input", docpp::HTML::HTMLElementProperties({docpp::HTML::HTMLProperty("type", "submit"), docpp::HTML::HTMLProperty("value", "Search!")}), "", docpp::HTML::TYPE_SELF_CLOSING}); + + div2.push_back(form); + html.push_back(div2); + + docpp::HTML::HTMLDocument doc{html}; + + std::ofstream file("biteme.lol.html"); + + file << doc.get(docpp::HTML::FORMATTING_PRETTY); + + file.close(); + + return 0; +} diff --git a/examples/hello-world.cpp b/examples/hello-world.cpp index d4464b3..838438c 100644 --- a/examples/hello-world.cpp +++ b/examples/hello-world.cpp @@ -1,5 +1,11 @@ -// Compile with: g++ hello-world.cpp -o hello-world -ldocpp -#include +/** + * @file hello-world.cpp + * @brief A simple Hello World program, demonstrating the use of docpp. + * @details This program creates a simple HTML document with a title, a meta description, a body with a div containing a header and a paragraph, and a footer with a paragraph. It also includes a CSS stylesheet that sets the background color of the body to black and the text color to white. It then writes the document to a file called hello-world.html. + * @license LGPL-3.0 + * + * g++ -std=c++11 hello-world.cpp -o hello-world -ldocpp + */ #include #include @@ -78,7 +84,7 @@ int main() { stylesheet.push_back(bodyStyling); /* To get the stylesheet as an std::string object, call stylesheet.get(). It can then be used in an HTMLElement object. */ - const std::string& css = stylesheet.get(); // body { background-color: black; color: white; } + const std::string& css = stylesheet.get(docpp::CSS::FORMATTING_PRETTY); // body { background-color: black; color: white; } headSection.push_back(docpp::HTML::HTMLElement("style", {}, css)); // @@ -114,8 +120,6 @@ int main() { file.close(); - std::cout << doc.get() << "\n"; - /* And we're done! */ return 0; diff --git a/include/docpp.hpp b/include/docpp.hpp index 42dd3b2..ad7ef5b 100644 --- a/include/docpp.hpp +++ b/include/docpp.hpp @@ -23,6 +23,7 @@ namespace docpp { namespace HTML { enum { + SECTION_EMPTY, SECTION_HTML, SECTION_HEAD, SECTION_BODY, @@ -31,6 +32,8 @@ namespace docpp { TYPE_SELF_CLOSING, TYPE_NON_SELF_CLOSING, TYPE_NON_CLOSED, + TYPE_TEXT, + TYPE_TEXT_TAB, FORMATTING_NONE, FORMATTING_PRETTY, FORMATTING_NEWLINE, diff --git a/src/docpp.cpp b/src/docpp.cpp index 15f3eb0..583cde0 100644 --- a/src/docpp.cpp +++ b/src/docpp.cpp @@ -187,6 +187,16 @@ void docpp::HTML::HTMLElement::set(const std::string& tag, const HTMLElementProp std::string docpp::HTML::HTMLElement::get(const int formatting, const int tabc) const { std::string ret{}; + if (this->type == docpp::HTML::TYPE_TEXT) { + return this->data; + } else if (this->type == docpp::HTML::TYPE_TEXT_TAB) { + for (int i{0}; i < tabc; i++) { + ret += "\t"; + } + + return ret + this->data; + } + if (formatting == docpp::HTML::FORMATTING_PRETTY) { for (int i{0}; i < tabc; i++) { ret += "\t"; @@ -255,19 +265,7 @@ docpp::HTML::HTMLElement docpp::HTML::HTMLSection::operator[](const int& index) } docpp::HTML::HTMLSection::HTMLSection(const int tag, const HTMLElementProperties& properties) { - if (tag == docpp::HTML::SECTION_DIV) { - this->tag = "div"; - } else if (tag == docpp::HTML::SECTION_BODY) { - this->tag = "body"; - } else if (tag == docpp::HTML::SECTION_FOOTER) { - this->tag = "footer"; - } else if (tag == docpp::HTML::SECTION_HEAD) { - this->tag = "head"; - } else if (tag == docpp::HTML::SECTION_HTML) { - this->tag = "html"; - } - - this->properties = properties; + this->set(tag, properties); } void docpp::HTML::HTMLSection::set(const std::string& tag, const HTMLElementProperties& properties) { @@ -464,33 +462,44 @@ std::vector docpp::HTML::HTMLSection::getHTMLSections( std::string docpp::HTML::HTMLSection::get(const int formatting, const int tabc) const { std::string ret{}; + int tabcount{tabc}; + + if (!this->tag.compare("")) { + --tabcount; // i guess this means the section only contains elements and sections, and isn't a tag itself + + if (tabcount < -1) { + tabcount = -1; // will be incremented by 1, so it will be 0 + } + } if (formatting == docpp::HTML::FORMATTING_PRETTY) { - for (int i{0}; i < tabc; i++) { + for (int i{0}; i < tabcount; i++) { ret += "\t"; } } - ret += "<" + this->tag; + if (this->tag.compare("")) { + ret += "<" + this->tag; - for (const auto& it : this->properties.getProperties()) { - if (!it.getKey().compare("")) continue; - if (!it.getValue().compare("")) continue; + for (const auto& it : this->properties.getProperties()) { + if (!it.getKey().compare("")) continue; + if (!it.getValue().compare("")) continue; - ret += " " + it.getKey() + "=\"" + it.getValue() + "\""; - } + ret += " " + it.getKey() + "=\"" + it.getValue() + "\""; + } - ret += ">"; + ret += ">"; - if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { - ret += "\n"; + if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { + ret += "\n"; + } } for (int i{0}; i < this->index; i++) { if (this->elements.find(i) != this->elements.end()) { - ret += this->elements.at(i).get(formatting, tabc + 1); + ret += this->elements.at(i).get(formatting, tabcount + 1); } else if (this->sections.find(i) != this->sections.end()) { - ret += this->sections.at(i).get(formatting, tabc + 1); + ret += this->sections.at(i).get(formatting, tabcount + 1); if (formatting == docpp::HTML::FORMATTING_PRETTY || formatting == docpp::HTML::FORMATTING_NEWLINE) { ret += "\n"; @@ -499,12 +508,12 @@ std::string docpp::HTML::HTMLSection::get(const int formatting, const int tabc) } if (formatting == docpp::HTML::FORMATTING_PRETTY) { - for (int i{0}; i < tabc; i++) { + for (int i{0}; i < tabcount; i++) { ret += "\t"; } } - ret += "tag + ">"; + ret += this->tag.compare("") ? ("tag + ">") : ""; return std::move(ret); } diff --git a/tests/test.cpp b/tests/test.cpp index 1d87b14..6e32ffb 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -296,6 +296,16 @@ SCENARIO("Test HTML", "[HTML]") { REQUIRE(doc.get(docpp::HTML::FORMATTING_PRETTY) == "\n\n\t

Test 1

\n\t

Test 2

\n\t

Test 3

\n"); }; + auto test18 = []() { + docpp::HTML::HTMLSection section = docpp::HTML::HTMLSection(docpp::HTML::SECTION_EMPTY, {}); + + section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 1")); + section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 2")); + section.push_back(docpp::HTML::HTMLElement("p", {}, "Test 3")); + + REQUIRE(section.get() == "

Test 1

Test 2

Test 3

"); + }; + std::vector tests{ test1, test2, @@ -314,6 +324,7 @@ SCENARIO("Test HTML", "[HTML]") { test15, test16, test17, + test18, }; for (const auto& test : tests) {