Initial commit: Klammertext source distribution
Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
739
sks/target/html_util.cpp
Normal file
739
sks/target/html_util.cpp
Normal file
@@ -0,0 +1,739 @@
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <regex>
|
||||
|
||||
#include "util.h"
|
||||
#include "kutil.h"
|
||||
#include "error.h"
|
||||
#include "file.h"
|
||||
#include "html_util.h"
|
||||
#include "log.h"
|
||||
#include "show.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const attr_t& a)
|
||||
{
|
||||
if (std::holds_alternative<int>(a))
|
||||
os << std::get<int>(a);
|
||||
else if (std::holds_alternative<float>(a))
|
||||
os << std::get<float>(a);
|
||||
else if (std::holds_alternative<std::string>(a))
|
||||
os << std::get<std::string>(a);
|
||||
return os;
|
||||
}
|
||||
|
||||
int _indent = 0;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const html_element_t& h)
|
||||
{
|
||||
if (std::holds_alternative<std::string>(h))
|
||||
os << std::get<std::string>(h);
|
||||
else if (std::holds_alternative<HTML>(h))
|
||||
os << std::get<HTML>(h);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const elements_t& elements)
|
||||
{
|
||||
// for (const HTML& h : elements) {
|
||||
for (const html_element_t& h : elements) {
|
||||
/*n
|
||||
if (std::holds_alternative<std::string>(h))
|
||||
os << h;
|
||||
else if (std::holds_alternative<HTML>(h))
|
||||
os << h;
|
||||
}
|
||||
*/
|
||||
os << h;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
bool attribute_with_value(attr_t attr)
|
||||
{
|
||||
return std::holds_alternative<std::string>(attr)
|
||||
&& !(std::get<std::string>(attr)).empty();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const HTML& h)
|
||||
{
|
||||
bool void_element = h.void_element(h.m_tag);
|
||||
//bool newline = !(h.void_element(h.m_tag) or h.empty_element(h.m_tag));
|
||||
//bool empty_element = h.empty_element(h.m_tag) and trim(h.m_text).size() == 0;
|
||||
|
||||
os << "<" << h.m_tag;
|
||||
for (auto [t,v] : h.m_attrs) {
|
||||
os << " " << t;
|
||||
if (attribute_with_value(v)) {
|
||||
os << "=\"" << v << "\"";
|
||||
}
|
||||
}
|
||||
os << ">";
|
||||
if (h.m_elements.size() > 0) {
|
||||
os << "\n" << h.m_elements;
|
||||
|
||||
}
|
||||
|
||||
//if (!empty_element) {
|
||||
if (trim(h.m_text).size() > 0) {
|
||||
if (h.m_text.find(' ') != std::string::npos) {
|
||||
os << "\n";
|
||||
}
|
||||
os << trim(h.m_text); // << "\n";
|
||||
}
|
||||
|
||||
/*
|
||||
//os << h.m_text;
|
||||
std::string intext = "\n" + h.m_text;
|
||||
std::string sp(_indent, ' ');
|
||||
intext = std::regex_replace(intext, std::regex("\n"), "\n" + sp);
|
||||
os << intext;
|
||||
*/
|
||||
//os << trim(h.m_text) << "\n";
|
||||
// }
|
||||
/*
|
||||
if (true or newline) {
|
||||
os << "\n";
|
||||
_indent -= 2;
|
||||
}
|
||||
*/
|
||||
|
||||
//if (!void_element and !empty_element) {
|
||||
if (!void_element) {
|
||||
if (h.m_text.find(' ') != std::string::npos) {
|
||||
os << "\n";
|
||||
}
|
||||
os << "</" << h.m_tag << ">";
|
||||
}
|
||||
os << "\n";
|
||||
|
||||
/*
|
||||
if (true or !void_element and !empty_element) {
|
||||
//std::string sp(_indent, ' ');
|
||||
//os << sp << "</" << h.m_tag << ">";
|
||||
os << "\n</" << h.m_tag << ">";
|
||||
}
|
||||
os << "\n";
|
||||
*/
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::string to_string(elements_t e)
|
||||
{
|
||||
std::stringstream ss{};
|
||||
ss << e;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool HTML::void_element(std::string tag) const
|
||||
{
|
||||
if (tag == "!DOCTYPE")
|
||||
return true;
|
||||
else
|
||||
return std::find
|
||||
(m_void_tags.begin(), m_void_tags.end(), tag) != m_void_tags.end();
|
||||
}
|
||||
|
||||
bool HTML::empty_element(std::string tag) const
|
||||
{
|
||||
if (tag == preamble_tag)
|
||||
return true;
|
||||
else
|
||||
return std::find
|
||||
(m_empty_tags.begin(), m_empty_tags.end(), tag) != m_empty_tags.end();
|
||||
}
|
||||
|
||||
//HTML& HTML::attr(std::string name, std::variant<int, float, std::string> value)
|
||||
HTML& HTML::attr(std::string name, attr_t value)
|
||||
{
|
||||
m_attrs.push_back({name, value});
|
||||
return *this;
|
||||
}
|
||||
|
||||
HTML& HTML::attrs(std::string s)
|
||||
{
|
||||
static const std::regex attr_rgx(R"((\w+)\s*=\s*\"(.*?)\")");
|
||||
auto attrs_begin = std::sregex_iterator(s.begin(), s.end(), attr_rgx);
|
||||
auto attrs_end = std::sregex_iterator();
|
||||
//std::cout << "Found " << std::distance(attrs_begin, attrs_end) << " attrs\n";
|
||||
for (std::sregex_iterator iter = attrs_begin; iter != attrs_end; ++iter) {
|
||||
std::smatch match = *iter;
|
||||
//std::cout << "attr: " << s << ": " << (*iter)[1] << " " << (*iter)[2] << "\n";
|
||||
m_attrs.push_back({(*iter)[1], (*iter)[2]});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Functions:
|
||||
|
||||
namespace html {
|
||||
|
||||
HTML elt(std::string tag)
|
||||
{
|
||||
HTML h(tag);
|
||||
return h;
|
||||
}
|
||||
|
||||
HTML elt(std::string tag, std::string text)
|
||||
{
|
||||
HTML h(tag, trim(text));
|
||||
return h;
|
||||
}
|
||||
|
||||
HTML elt(std::string tag, elements_t elements)
|
||||
{
|
||||
HTML h(tag, elements);
|
||||
return h;
|
||||
}
|
||||
|
||||
HTML elt(std::string tag, HTML e, elements_t elts)
|
||||
{
|
||||
elements_t elements = {e};
|
||||
elements.insert(elements.end(), elts.begin(), elts.end());
|
||||
HTML h(tag, elements);
|
||||
return h;
|
||||
}
|
||||
|
||||
HTML preamble()
|
||||
{
|
||||
return elt(preamble_tag);
|
||||
}
|
||||
|
||||
|
||||
// <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
// <meta http-equiv="Pragma" content="no-cache" />
|
||||
// <meta http-equiv="Expires" content="0" />
|
||||
|
||||
elements_t meta_elements()
|
||||
{
|
||||
elements_t result {
|
||||
elt("meta")
|
||||
.attr("name", "viewport")
|
||||
.attr("content", "width=device-width, initial-scale=1"),
|
||||
elt("meta")
|
||||
.attr("charset", "UTF-8"),
|
||||
// Does not conform to HTML 5:
|
||||
// elt("meta")
|
||||
// .attr("http-equiv", "Cache-Control")
|
||||
// .attr("content", "no-cache, no-store, must-revalidate"),
|
||||
// elt("meta")
|
||||
// .attr("http-equiv", "Pragma")
|
||||
// .attr("content", "no-cache"),
|
||||
// elt("meta")
|
||||
// .attr("http-equiv", "Expires")
|
||||
// .attr("content", "0")
|
||||
};
|
||||
/*
|
||||
result.push_back(
|
||||
elt("link")
|
||||
.attr("rel", "icon")
|
||||
.attr("href", "/favicon.ico")
|
||||
.attr("type", "image/x-icon"))
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
elements_t local_font_elements(strings_t fontnames)
|
||||
{
|
||||
elements_t result {};
|
||||
for (auto name : fontnames) {
|
||||
// std::cout << "Font: " << name << "\n";
|
||||
result.push_back(elt("link")
|
||||
.attr("href", "fonts/" + name + ".css")
|
||||
.attr("rel", "stylesheet"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
elements_t google_font_elements(strings_t fontnames)
|
||||
{
|
||||
elements_t result {};
|
||||
if (fontnames.size() > 0) {
|
||||
result.push_back(elt("link")
|
||||
.attr("rel", "preconnect")
|
||||
.attr("href", "https://fonts.googleapis.com"));
|
||||
result.push_back(elt("link")
|
||||
.attr("rel", "preconnect")
|
||||
.attr("href", "https://fonts.gstatic.com"));
|
||||
}
|
||||
for (auto name : fontnames)
|
||||
result.push_back(
|
||||
elt("link")
|
||||
.attr("href", "https://fonts.googleapis.com/css2?family=" + name + "&display=swap")
|
||||
.attr("rel", "stylesheet"));
|
||||
return result;
|
||||
}
|
||||
|
||||
elements_t javascript(std::string output_dir, strings_t js_filenames)
|
||||
{
|
||||
//elements_t result { jquery_elements() };
|
||||
elements_t result {};
|
||||
|
||||
std::string js_dir = output_dir + "/js/";
|
||||
fs::create_directory(js_dir);
|
||||
for (auto fname : js_filenames) {
|
||||
/*
|
||||
std::string base = file_basename(fname) + ".js";
|
||||
std::string js_page_filename = js_dir + base;
|
||||
if (file_exists(js_page_filename)) {
|
||||
fs::remove(js_page_filename);
|
||||
}
|
||||
fs::copy(fname, js_page_filename);
|
||||
*/
|
||||
result.push_back(elt("script")
|
||||
.attr("src", fname)); //"js/" + base));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
HTML head(std::string title,
|
||||
std::string css,
|
||||
strings_t css_filenames,
|
||||
strings_t local_fonts, strings_t google_fonts)
|
||||
{
|
||||
elements_t elts = meta_elements();
|
||||
// msg() << "ELTS sks: " << elts << "\n";
|
||||
for (auto e : local_font_elements(local_fonts))
|
||||
elts.push_back(e);
|
||||
for (auto e : google_font_elements(google_fonts))
|
||||
elts.push_back(e);
|
||||
//elts += google_font_prolog();
|
||||
|
||||
//std::string css_dir = output_dir + "/css/";
|
||||
// No; a single file at the top level...?
|
||||
|
||||
// std::string css_dir = output_dir + "/";
|
||||
// fs::create_directory(css_dir);
|
||||
|
||||
for (auto fname : css_filenames) {
|
||||
// msg() << "CSS: " << fname << "\n";
|
||||
/*
|
||||
std::string base = file_basename(fname) + ".css";
|
||||
std::string page_filename = css_dir + base;
|
||||
if (!file_exists(page_filename)) {
|
||||
fs::copy(fname, page_filename);
|
||||
}
|
||||
*/
|
||||
elts.push_back(elt("link")
|
||||
.attr("rel", "stylesheet")
|
||||
.attr("href", fname)); // base));
|
||||
}
|
||||
if (!css.empty()) {
|
||||
elts.push_back(elt("style", css));
|
||||
}
|
||||
|
||||
if (!title.empty()) {
|
||||
elts.push_back(elt("title", trim(title)));
|
||||
}
|
||||
HTML result = elt("head", elts);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
HTML button(std::string id, std::string name,
|
||||
std::string attrib="", std::string value="")
|
||||
{
|
||||
std::vector<std::string> hidden = {"Clear", "Back"};
|
||||
HTML result = elt("span", string_replace(name, " ", " ")).id(id).cls("navb");
|
||||
if (attrib != "") {
|
||||
result.attr(attrib, value);
|
||||
}
|
||||
if (std::find(hidden.begin(), hidden.end(), name) != hidden.end()) {
|
||||
result.attr("hidden", "");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
elements_t navtools(int maximum_depth=5)
|
||||
{
|
||||
elements_t result {};
|
||||
for (auto [name, id] : std::vector<std::pair<std::string, std::string>>
|
||||
{{ "Text only", "textshow" },
|
||||
{ "Next", "next" },
|
||||
{ "Previous", "previous" }}) {
|
||||
//{ "Fit", "fit" }}) {
|
||||
result.push_back(button(id, name));
|
||||
}
|
||||
for (int n = 1; n <= maximum_depth; n++) {
|
||||
result.push_back(
|
||||
elt("span", std::to_string(n)).cls("navb depthchoice").attr("data-depth", std::to_string(n)));
|
||||
}
|
||||
elements_t fit_elements = {
|
||||
elt("input", "")
|
||||
.id("fit_check")
|
||||
.attr("name", "fit_check")
|
||||
.attr("type", "checkbox")
|
||||
.attr("active", "false")
|
||||
.attr("autocomplete", "off"),
|
||||
//.attr("checked", ""),
|
||||
elt("label", "Fit")
|
||||
.id("fit_check_label")
|
||||
.attr("for", "fit_check")
|
||||
};
|
||||
result.push_back(elt("span", fit_elements)
|
||||
.attr("id", "fit"));
|
||||
|
||||
elements_t linkshow_elements = {
|
||||
elt("input", "")
|
||||
.id("linkshow_check")
|
||||
.attr("name", "linkshow_check")
|
||||
.attr("type", "checkbox")
|
||||
.attr("active", "false")
|
||||
.attr("autocomplete", "off"),
|
||||
//.attr("checked", ""),
|
||||
elt("label", "Links")
|
||||
.id("linkshow_check_label")
|
||||
.attr("for", "linkshow_check")
|
||||
};
|
||||
|
||||
result.push_back(elt("span", linkshow_elements)
|
||||
.attr("id", "linkshow"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
elements_t search()
|
||||
{
|
||||
elements_t result {};
|
||||
for (auto [name, id] : std::vector<std::pair<std::string, std::string>>
|
||||
{{ "Clear", "search_clear" },
|
||||
{ "Back", "search_back_label"},
|
||||
{ "Search", "search_label" }
|
||||
})
|
||||
result.push_back(button(id, name));
|
||||
elements_t search_input { elt("span", "Ⓧ").id("search_clear_input").attr("hidden", "") };
|
||||
result.push_back(
|
||||
elt("span", {
|
||||
elt("input", "").id("search_input")
|
||||
.attr("type", "text").attr("name", "search_input")
|
||||
.attr("autocomplete", "off")
|
||||
.attr("required", "required"),
|
||||
elt("span", search_input).id("search_clear_input_box")
|
||||
}).id("search_box"));
|
||||
//result.push_back(button("help", "Help"));
|
||||
/*
|
||||
elements_t search_input {};
|
||||
search_input.push_back(
|
||||
elt("span", result).id("foldersearch"));
|
||||
return search_input;
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
HTML navigation(int max_level) {
|
||||
return elt("div", {
|
||||
elt("span", navtools(max_level)).id("navtools"),
|
||||
elt("span", { elt("span", search()).id("searchtools"),
|
||||
elt("span", button("help", "Help"))})})
|
||||
.id("nav");
|
||||
}
|
||||
|
||||
elements_t middle(std::string text,
|
||||
//std::string nav,
|
||||
std::string toc)
|
||||
{
|
||||
elements_t result {};
|
||||
toc = trim(toc);
|
||||
text = trim(text);
|
||||
if (!toc.empty()) {
|
||||
result.push_back(elt("div", toc)
|
||||
.attr("id", "toc"));
|
||||
|
||||
result.push_back(elt("div")
|
||||
.attr("id", "resizer"));
|
||||
|
||||
}
|
||||
|
||||
if (!text.empty()) {
|
||||
text += "<div class=\"endspace\"></div>\n";
|
||||
elements_t content {};
|
||||
content.push_back(elt("div", text).attr("id", "text"));
|
||||
//if (!nav.empty()) {
|
||||
//content.push_back(elt("div", "<h1>SEARCH</h1>")
|
||||
// .attr("id", "search_page"));
|
||||
//content.push_back(elt("div", "<h1>HELP</h1>").attr("id", "help_page"));
|
||||
//}
|
||||
result.push_back(elt("div", content).attr("id", "content"));
|
||||
}
|
||||
else {
|
||||
throw Argument_error("The text content of the HTML page is not defined");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void install_local_fonts(strings_t font_dirs, strings_t names, std::string output_dir)
|
||||
{
|
||||
std::string output_font_dir = output_dir + "/fonts";
|
||||
//std::cout << "Font directory for website: " << output_font_dir << "\n";
|
||||
if (!file_exists(output_font_dir)) {
|
||||
fs::create_directory(output_font_dir);
|
||||
//std::cout << " Font directory created: " << output_font_dir << "\n";
|
||||
}
|
||||
|
||||
for (auto name : names) {
|
||||
//std::cout << "Font search for " << name << ": " << klammertext_dir() << "/sks/font/fonts/\n";
|
||||
std::string src_font_dir = klammertext_dir() + "/sks/font/fonts/" + name;
|
||||
if (!file_exists(src_font_dir)) {
|
||||
bool found = false;
|
||||
for (std::string font_dir : font_dirs) {
|
||||
src_font_dir = font_dir + "/" + name;
|
||||
//std::cout << "Font search for " << name << ": " << font_dir << "/\n";
|
||||
if (file_exists(src_font_dir)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw Argument_error(
|
||||
"Local font directory \"" + src_font_dir + "\" does not exist");
|
||||
}
|
||||
}
|
||||
//std::cout << "Font " << name << ": " << src_font_dir << "\n";
|
||||
|
||||
std::string src_font_css = src_font_dir + ".css";
|
||||
if (!fs::exists(src_font_css)) {
|
||||
throw Argument_error(
|
||||
"Local font CSS file \"" + src_font_css + "\" does not exist");
|
||||
}
|
||||
std::string font_copy =
|
||||
"cp -r " + src_font_css + " " + src_font_dir + " " + output_font_dir;
|
||||
|
||||
//std::string files_copy = "cp -r " + basename + " " + font_dir;
|
||||
//cout << css_copy << "\n" << files_copy << "\n";
|
||||
//std::cout << system(css_copy.c_str()) << "\n";
|
||||
//std::cout << system(files_copy.c_str()) << "\n";
|
||||
|
||||
if (system(font_copy.c_str()) != 0) {
|
||||
std::cout << "Font copy command: " << font_copy << "\n";
|
||||
throw Argument_error("Local font \"" + name + "\" not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elements_t status(std::string date, std::string version, std::string copyright)
|
||||
{
|
||||
elements_t result {};
|
||||
if (!date.empty()) {
|
||||
result.push_back(elt("span", date).cls("footeritem"));
|
||||
}
|
||||
if (!version.empty()) {
|
||||
result.push_back(elt("span", version).cls("footeritem"));
|
||||
}
|
||||
if (!copyright.empty()) {
|
||||
result.push_back(elt("span", copyright).cls("footeritem"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
elements_t page(
|
||||
std::string title,
|
||||
std::string page_title,
|
||||
std::string output_dir,
|
||||
std::string nav,
|
||||
int max_level,
|
||||
std::string toc,
|
||||
std::string text,
|
||||
std::string date,
|
||||
std::string version,
|
||||
std::string copyright,
|
||||
std::string css,
|
||||
strings_t css_filenames,
|
||||
strings_t js_filenames,
|
||||
strings_t local_fonts,
|
||||
strings_t google_fonts,
|
||||
std::string logo)
|
||||
{
|
||||
if (page_title.empty())
|
||||
page_title = title;
|
||||
elements_t body {};
|
||||
if (!title.empty()) {
|
||||
elements_t title_bar {};
|
||||
title_bar.push_back(elt("span", trim(title)).attr("id", "title_text"));
|
||||
if (!logo.empty()) {
|
||||
title_bar.push_back(elt("span", trim(logo)).attr("id", "logo"));
|
||||
}
|
||||
body.push_back(elt("div", title_bar).attr("id", "title"));
|
||||
}
|
||||
if (!nav.empty()) {
|
||||
body.push_back(navigation(max_level));
|
||||
}
|
||||
|
||||
if (!nav.empty() and !toc.empty()) {
|
||||
body.push_back(elt("div",
|
||||
elt("div",
|
||||
middle(text, toc))
|
||||
.attr("id", "middle")));
|
||||
} else {
|
||||
//std::cout << "ONLY TEXT\n" << text << "\n\n";
|
||||
body.push_back(elt("div",
|
||||
elt("div",
|
||||
text)
|
||||
.attr("id", "text"))
|
||||
.attr("id", "middle"));
|
||||
}
|
||||
|
||||
elements_t status_elements = status(date, version, copyright);
|
||||
if (!empty(status_elements)) {
|
||||
body.push_back(elt("div", status_elements).attr("id", "status"));
|
||||
}
|
||||
//if (!status.empty())
|
||||
// body.push_back(elt("div", trim(status)).attr("id", "status"));
|
||||
|
||||
if (!nav.empty() and !toc.empty())
|
||||
body.push_back(elt("div", "").attr("id", "pagecache"));
|
||||
|
||||
if (!js_filenames.empty()) {
|
||||
auto js_elements { javascript(output_dir, js_filenames) };
|
||||
body.insert(std::end(body), std::begin(js_elements), std::end(js_elements));
|
||||
}
|
||||
elements_t result { preamble() };
|
||||
if (page_title.empty())
|
||||
page_title = title;
|
||||
result.push_back(
|
||||
elt("html",
|
||||
{ head(page_title, css, css_filenames, local_fonts, google_fonts),
|
||||
elt("body", body)
|
||||
}).attr("lang", "en"));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void add_title(elements_t& body, std::string title, std::string logo)
|
||||
{
|
||||
elements_t title_bar {};
|
||||
title_bar.push_back(elt("span", trim(title)).attr("id", "title_text"));
|
||||
if (!logo.empty()) {
|
||||
title_bar.push_back(elt("span", trim(logo)).attr("id", "logo"));
|
||||
}
|
||||
body.push_back(elt("div", title_bar).attr("id", "title"));
|
||||
}
|
||||
|
||||
void add_nav(elements_t& body, int max_level)
|
||||
{
|
||||
body.push_back(navigation(max_level));
|
||||
}
|
||||
|
||||
void add_text(elements_t& body, std::string text, std::string toc, bool text_only)
|
||||
{
|
||||
if (text_only) {
|
||||
elements_t content {};
|
||||
content.push_back(elt("div", text).attr("id", "text"));
|
||||
body.push_back(
|
||||
elt("div", elt("div", content).attr("id", "content")).attr("id", "middle"));
|
||||
} else {
|
||||
body.push_back(elt("div", middle(text, toc)).attr("id", "middle"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add_bottom_spacer(elements_t& body)
|
||||
{
|
||||
body.push_back(elt("div").cls("endspace"));
|
||||
}
|
||||
|
||||
void add_status_bar(
|
||||
elements_t& body, std::string date, std::string version, std::string copyright)
|
||||
{
|
||||
elements_t status_elements = status(date, version, copyright);
|
||||
if (!empty(status_elements)) {
|
||||
body.push_back(elt("div", status_elements).attr("id", "status"));
|
||||
}
|
||||
}
|
||||
|
||||
void add_page_cache(elements_t& body)
|
||||
{
|
||||
body.push_back(elt("div", "").attr("id", "pagecache"));
|
||||
}
|
||||
|
||||
void add_js_links(elements_t& body, strings_t js_filenames, std::string output_dir)
|
||||
{
|
||||
if (!js_filenames.empty()) {
|
||||
auto js_elements { javascript(output_dir, js_filenames) };
|
||||
body.insert(std::end(body), std::begin(js_elements), std::end(js_elements));
|
||||
}
|
||||
}
|
||||
|
||||
elements_t make_page(
|
||||
elements_t body,
|
||||
std::string page_title, std::string css,
|
||||
strings_t css_filenames, strings_t local_fonts, strings_t google_fonts)
|
||||
{
|
||||
elements_t page { preamble() };
|
||||
page.push_back(
|
||||
elt("html",
|
||||
{ head(page_title, css, css_filenames, local_fonts, google_fonts),
|
||||
elt("body", body)
|
||||
}).attr("lang", "en"));
|
||||
return page;
|
||||
}
|
||||
|
||||
bool tag_is_block_element(std::string tag)
|
||||
{
|
||||
auto location = std::find(block_elements.begin(), block_elements.end(), tag);
|
||||
return location != block_elements.end();
|
||||
}
|
||||
|
||||
bool block_element(std::string par)
|
||||
{
|
||||
(void)K::log(3);
|
||||
bool result = false;
|
||||
par = trim(par);
|
||||
if (par[0] == '<') {
|
||||
static const std::regex element_rgx(R"(^\s*</?([^\s>]+).*?>)");
|
||||
std::smatch match {};
|
||||
std::regex_search(par, match, element_rgx);
|
||||
result = tag_is_block_element(match[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string make_paragraphs(std::string html_text)
|
||||
{
|
||||
(void)K::log(3);
|
||||
std::string result {};
|
||||
//html_text = std::regex_replace(html_text, std::regex(R"((<pre .*?>)\s+)"), "$1\n");
|
||||
//html_text = std::regex_replace(html_text, std::regex(R"(\s+</pre>)"), "\n</pre>");
|
||||
static const std::regex paragraph_split_rgx(R"(\n *(\n *)+)");
|
||||
for (auto par : regex_split(html_text, paragraph_split_rgx)) {
|
||||
par = trim(par);
|
||||
if (par.size() > 0) {
|
||||
if (!block_element(par)) {
|
||||
par = "<p>" + par + "</p>";
|
||||
}
|
||||
result += par + "\n\n";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string minimize_css(std::string src)
|
||||
{
|
||||
(void)K::log(3);
|
||||
std::string result = src;
|
||||
//std::smatch match {};
|
||||
std::regex line_end_space(R"(\\}[ ]+)", std::regex::awk);
|
||||
result = regex_replace(result, line_end_space, "}");
|
||||
std::regex whitespace(R"([\n ]+)", std::regex::awk);
|
||||
result = regex_replace(result, whitespace, " ");
|
||||
std::regex line_end(R"(}[ ]+)", std::regex::awk);
|
||||
result = regex_replace(result, line_end, "}\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string minimize_js(std::string src)
|
||||
{
|
||||
(void)K::log(3);
|
||||
return src;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user