docpp/examples/hello-world.cpp
Jacob 14cd8c4122 Remove/replace some "C with classes" junk. The C++ core guidelines state
that you must not use ALL_CAPS for enum members. enum class is now used
as well, to further reinforce the idea that this is a C++ library. While
neither of these changes are necessary, it leads to a better and more
intuitive API design.

More operator overloading has also been added for many of the classes,
particularly the [] index operator, which can now be used in place of
the at() method. More methods have also been added, particularly for
Section and Document.

Some methods have also been fixed, or have had their behavior altered
slightly, but this should now be covered under the new tests, which have
also been (for the most part) rewritten, both because they were
previously both primitive and rather ugly and because new functionality
was added.

Examples have also been updated to reflect the changes made in this
commit, so that they build successfully.

Of course, these changes mean that the new API is incompatible with any
applications written with the 0.0.1 version. Hopefully most of these
changes are dealt with before the 1.0 release, because I would prefer
not making API-breaking changes by that point.
2024-05-20 01:32:49 +02:00

127 lines
7.6 KiB
C++

/**
* @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 <fstream>
#include <docpp/docpp.hpp>
int main() {
/* This is your root document. It can hold *one* HTML section, and that section can hold any number of elements and/or sections.
* By default, the root document will prepend a doctype declaration. If you don't want that (e.g., if you're writing XML), you can
* use docpp::HTML::Document::set_doctype() to set the doctype to your preferred value.
*
* To get the document as an std::string object, call doc.get().
*/
docpp::HTML::Document doc{};
/* This is an HTML section. It can hold any number of elements and/or sections.
* The first argument is the type of section, and this can either be a predefined value (e.g., docpp::HTML::Tag::Html) or a
* custom value in the form of an std::string object.
*
* The second argument is an HTMLProperties object, which is a collection of Property objects. Each property is a std::pair of an
* attribute name and an attribute value. If you don't want to specify any attributes, you can pass an empty ElementAttributes object.
* If you need to change the tag and/or attributes later, you can use the set() method.
*
* Note that it is very important that you do not append a section or element to a section until you have finished its construction,
* because push_back() makes a copy of the object you pass to it. If you need to make changes later, you can use methods such as find() and swap(),
* or construct a new object. An alternative is to append using the += operator, which does the same thing as push_back().
*
* To get the section as an std::string object, call section.get().
*/
docpp::HTML::Section htmlSection(docpp::HTML::Tag::Html, {}); // <html></html>
docpp::HTML::Section headSection(docpp::HTML::Tag::Head, {}); // <head></head>
docpp::HTML::Section bodySection(docpp::HTML::Tag::Body, {}); // <body></body>
docpp::HTML::Section footerSection(docpp::HTML::Tag::Footer, {}); // <footer></footer>
/* This is an HTML element. Unlike a section, an element cannot hold any other elements or sections, rather it holds text and/or attributes.
* The first argument is the type of element, and this should simply be the tag name (e.g., "p", "h1", "a", etc.).
*
* The second argument is an HTMLProperties object, which is a collection of Property objects. Each property is a std::pair of an
* attribute name and an attribute value. If you don't want to specify any attributes, you can pass an empty ElementAttributes object.
* If you need to change the element's tag, attributes, type or text later, you can use the set() method.
*
* The third argument is the text content of the element. If you don't want to specify any text, you can pass an empty std::string object.
*
* The fourth argument is an integer representing the closing tag type. This can be one of the following:
*
* - docpp::HTML::Type::Non_Closed: No closing tag will be appended.
* Example: <img src="example.jpg">
* - docpp::HTML::TYPE_NON_SELF_CLOSING: A closing tag will be appended.
* Example: <p>Hello world</p>
* - docpp::HTML::TYPE_SELF_CLOSING: A self-closing tag will be appended.
* Example: <img src="example.jpg">
*
* To get the element as an std::string object, call element.get().
*/
docpp::HTML::Element titleElement("title", {}, "Hello world document"); // <title>Hello world document</title>
/* Add the title and meta elements to the head section. */
headSection.push_back(titleElement);
headSection.push_back(docpp::HTML::Element("meta", {{docpp::HTML::Property("name", "description"), docpp::HTML::Property("content", "Hello world document description!")}}, "", docpp::HTML::Type::Non_Closed));
/* This is a CSS document. It is essentially the CSS equivalent of an HTML section.
* It is essentially a collection of Element objects, which is a collection of Property objects.
*
* In other words, a CSS document is a collection of CSS elements, which are collections of CSS properties.
*/
docpp::CSS::Stylesheet stylesheet{};
/* This is a CSS element. It is essentially a collection of CSS properties.
* The first argument is the type of element, and this should simply be the tag name (e.g., "body", "p", "h1", etc.).
*
* The second argument is a CSSProperties object, which is a collection of Property objects. Each property is a std::pair of a
* property name and a property value. If you don't want to specify any properties, you can pass an empty CSSProperties object, but... of course, that's not very useful.
*
* To get the element as an std::string object, call element.get().
*/
docpp::CSS::Element bodyStyling("body", {{docpp::CSS::Property("background-color", "black"), docpp::CSS::Property("color", "white")}}); // body { background-color: black; color: white; }
/* Now, let's add the body style to the stylesheet. */
stylesheet.push_back(bodyStyling);
/* To get the stylesheet as an std::string object, call stylesheet.get(). It can then be used in an Element object. */
const std::string& css = stylesheet.get(docpp::CSS::Formatting::Pretty); // body { background-color: black; color: white; }
headSection.push_back(docpp::HTML::Element("style", {}, css)); // <style>body { background-color: black; color: white; }</style>
/* Add a paragraph element to the footer section. */
footerSection.push_back(docpp::HTML::Element("p", {}, "This is the footer.")); // <p>This is the footer.</p>
docpp::HTML::Section divSection(docpp::HTML::Tag::Div, {{docpp::HTML::Property("id", "main")}}); // <div id="main"></div>
/* Add a header element and a paragraph element to the div section. */
divSection.push_back(docpp::HTML::Element("h1", {}, "Hello world!")); // <h1>Hello world!</h1>
divSection.push_back(docpp::HTML::Element("p", {}, "This is a paragraph.")); // <p>This is a paragraph.</p>
/* Add the div section to the body section. */
bodySection.push_back(divSection);
/* Now, let's add the header, body and footer section to the html section.
* The order does matter, because an identifier is used internally. You can get this identifier by e.g. using find().
*/
htmlSection.push_back(headSection); // <html><head>...</head></html>
htmlSection.push_back(bodySection); // <html><head>...</head><body>...</body></html>
htmlSection.push_back(footerSection); // <html><head>...</head><body>...</body><footer>...</footer></html>
/* Now, let's add the html section to the document. */
doc.set(htmlSection);
/* Finally, let's output the document to a file and print it to standard output. */
std::ofstream file("hello-world.html");
/* Optionally, you can use the get() method with the docpp::HTML::Formatting::Pretty argument to get a *slightly* more readable document.
* The same goes for the CSS document. Or, you can use docpp::HTML::FORMATTING_NEWLINE to get a document with elements separated by newlines.
*/
file << doc.get(docpp::HTML::Formatting::Pretty);
file.close();
/* And we're done! */
return 0;
}