diff options
Diffstat (limited to 'src/html.c')
-rw-r--r-- | src/html.c | 703 |
1 files changed, 0 insertions, 703 deletions
diff --git a/src/html.c b/src/html.c deleted file mode 100644 index 47b2d7a..0000000 --- a/src/html.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - * HTML document generation - * - * Copyright (C) 2017 Patrick McDermott - * - * This file is part of Marquee. - * - * Marquee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Marquee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Marquee. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "html.h" - -#include <stdarg.h> -#include <string.h> - -#include <glib.h> -#include <gtk/gtk.h> - -static const gchar *styles = - /* - * General styles - */ - "* {\n" - "margin: 6px;\n" - "padding: 0;\n" - "background: none;\n" - "border: 0 none;\n" - "}\n" - "html {\n" - "margin: 0;\n" - "}\n" - "body {\n" - "margin: 18px;\n" - "background-color: #AFAFAF;\n" - "font-family: sans-serif;\n" - "}\n" - "h1, h2, h3, h4, h5, h6, p {\n" - "text-align: center;\n" - "}\n" - /* - * Horizontal notebook - */ - "div.notebook-h {\n" - "clear: left;\n" - "position: relative;\n" - "padding: 0;\n" - "}\n" - "div.notebook-h > input {\n" - "display: none;\n" - "}\n" - "div.notebook-h > label {\n" - "display: block;\n" - "background-color: #9F9F9F;\n" - "color: #5F5F5F;\n" - "float: left;\n" - "margin: 6px 3px 0 0;\n" - "border-width: 1px 1px 0 1px;\n" - "border-style: solid;\n" - "border-color: #8F8F8F;\n" - "border-radius: 3px 3px 0 0;\n" - "padding: 6px;\n" - "font-weight: bold;\n" - "position: relative;\n" - "top: 3px;\n" - "}\n" - "div.notebook-h > input:checked + label {\n" - "background-color: #CFCFCF;\n" - "color: #000000;\n" - "padding: 6px 6px 7px 6px;\n" - "border-color: #9F9F9F;\n" - "position: relative;\n" - "top: 0;\n" - "z-index: 1;\n" - "}\n" - "div.notebook-h > div {\n" - "display: none;\n" - "background-color: #CFCFCF;\n" - "clear: left;\n" - "border: 1px solid #9F9F9F;\n" - "border-radius: 0 0 3px 3px;\n" - "position: relative;\n" - "top: -1px;\n" - "margin: 0;\n" - "}\n" - /* - * Vertical notebook - */ - "div.notebook-v {\n" - "position: relative;\n" - /* Why are these weird margin and padding numbers necessary? */ - "margin: 6px 5px 6px 0;\n" - "padding: 6px 0 0 0;\n" - "}\n" - "div.notebook-v > input {\n" - "display: none;\n" - "}\n" - "div.notebook-v > label {\n" - "display: block;\n" - "background-color: #9F9F9F;\n" - "color: #5F5F5F;\n" - "float: left;\n" - "clear: left;\n" - "margin: 0 0 3px 6px;\n" - "border-width: 1px 0 1px 1px;\n" - "border-style: solid;\n" - "border-color: #8F8F8F;\n" - "border-radius: 3px 0 0 3px;\n" - "padding: 6px;\n" - "font-weight: bold;\n" - "position: relative;\n" - "left: 3px;\n" - "}\n" - "div.notebook-v > input:checked + label {\n" - "background-color: #CFCFCF;\n" - "color: #000000;\n" - "padding: 6px 7px 6px 6px;\n" - "border-color: #9F9F9F;\n" - "position: relative;\n" - "left: 0;\n" - "z-index: 1;\n" - "}\n" - "div.notebook-v > div {\n" - "display: none;\n" - "background-color: #CFCFCF;\n" - "border: 1px solid #9F9F9F;\n" - "border-radius: 0 3px 3px 0;\n" - "position: relative;\n" - "left: -1px;\n" - "margin: 0;\n" - "overflow: hidden;\n" - "}\n" - /* - * Form elements - */ - "form {\n" - "margin: 0;\n" - "}\n" - "form input, form select {\n" - "border: 1px solid #9F9F9F;\n" - "border-radius: 3px;\n" - "background-color: #EFEFEF;\n" - "padding: 6px;\n" - "color: #000000;\n" - "transition: all 250ms ease-in-out 0s;\n" - "-moz-transition: all 250ms ease-in-out 0s;\n" - "-wekbit-transition: all 250ms ease-in-out 0s;\n" - "-o-transition: all 250ms ease-in-out 0s;\n" - "}\n" - "div.dialog-buttonbox {\n" - "margin: 0;\n" - "float: right;\n" - "}\n" - "form label {\n" - "display: block;\n" - "}\n" - "form label span {\n" - "display: inline-block;\n" - "width: calc(50% - 6px);\n" - "text-align: right;\n" - "}\n" - "form input[type=submit], form input[type=reset] {\n" - "background-color: #DFDFDF;\n" - "}\n" - "form input:hover, form select:hover,\n" - "form input:focus, form select:focus {\n" - "border: 1px solid #4F8FCF;\n" - "outline: 0;\n" - "}\n" - "form input[type=submit]:hover, form input[type=reset]:hover,\n" - "form input[type=submit]:focus, form input[type=reset]:focus {\n" - "background-color: #EFEFEF;\n" - "}\n" - "iframe {\n" - "width: calc(100% - 12px);\n" - "height: 400px;\n" - "}\n" - ; - -gchar * -mq_html_document(const gchar *title, ...) -{ - gsize len; - va_list ap; - gchar *child; - gchar *document; - gchar *ptr; - - /* Calculate length. */ - len = strlen("<!doctype html>\n<html dir=\""); - len += 3; /* "ltr" or "rtl" */ - len += strlen("\">\n<head>\n<meta charset=\"utf-8\">\n<title>"); - len += strlen(title); - len += strlen("</title>\n<style>\n"); - len += strlen(styles); - len += strlen("</style>\n</head>\n<body>\n"); - va_start(ap, title); - while ((child = va_arg(ap, gchar *))) { - len += strlen(child); - } - va_end(ap); - len += strlen("</body>\n</html>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - document = g_new(gchar, len); - ptr = g_stpcpy(document, "<!doctype html>\n<html dir=\""); - ptr = g_stpcpy(ptr, gtk_widget_get_default_direction() == - GTK_TEXT_DIR_RTL ? "rtl" : "ltr"); - ptr = g_stpcpy(ptr, "\">\n<head>\n<meta charset=\"utf-8\">\n<title>"); - ptr = g_stpcpy(ptr, title); - ptr = g_stpcpy(ptr, "</title>\n<style>\n"); - ptr = g_stpcpy(ptr, styles); - ptr = g_stpcpy(ptr, "</style>\n</head>\n<body>\n"); - va_start(ap, title); - while ((child = va_arg(ap, gchar *))) { - ptr = g_stpcpy(ptr, child); - g_free(child); - } - va_end(ap); - ptr = g_stpcpy(ptr, "</body>\n</html>\n"); /* g_stpcpy() adds NUL. */ - - return document; -} - -#define TEXT_ELEMENT(ELEM) \ - gchar * \ - mq_html_##ELEM(const gchar *text) \ - { \ - return g_strconcat("<" #ELEM ">", text, "</" #ELEM ">\n", \ - NULL); \ - } \ - gchar * \ - mq_html_##ELEM##_free(gchar *text) \ - { \ - gchar *e; \ - e = g_strconcat("<" #ELEM ">", text, "</" #ELEM ">\n", NULL); \ - g_free(text); \ - return e; \ - } -TEXT_ELEMENT(h1) -TEXT_ELEMENT(h2) -TEXT_ELEMENT(h3) -TEXT_ELEMENT(h4) -TEXT_ELEMENT(h5) -TEXT_ELEMENT(h6) -TEXT_ELEMENT(p) -#undef TEXT_ELEMENT - -gchar * -mq_html_list(const gchar *type, GDestroyNotify destroy, ...) -{ - gsize len; - va_list ap; - gchar *child; - gchar *list; - gchar *ptr; - - /* TODO: Doesn't support specification of <ol> list types. */ - - /* Calculate length. */ - len = strlen("<ul>\n"); - va_start(ap, destroy); - while ((child = va_arg(ap, gchar *))) { - len += strlen("<li>\n"); - len += strlen(child); - len += strlen("</li>\n"); - } - va_end(ap); - len += strlen("</ul>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - list = g_new(gchar, len); - if (type && type[0]) { - ptr = g_stpcpy(list, "<ol>\n"); - } else { - ptr = g_stpcpy(list, "<ul>\n"); - } - va_start(ap, destroy); - while ((child = va_arg(ap, gchar *))) { - ptr = g_stpcpy(ptr, "<li>\n"); - ptr = g_stpcpy(ptr, child); - if (destroy) { - destroy(child); - } - ptr = g_stpcpy(ptr, "</li>\n"); - } - va_end(ap); - ptr = g_stpcpy(ptr, "</ul>\n"); /* g_stpcpy() adds the NUL. */ - - return list; -} - -gchar * -mq_html_list_v(const gchar *type, gchar **children) -{ - gsize len; - gsize i; - gchar *list; - gchar *ptr; - - /* TODO: Doesn't support specification of <ol> list types. */ - - /* Calculate length. */ - len = strlen("<ul>\n"); - for (i = 0; children && children[i]; ++i) { - len += strlen("<li>\n"); - len += strlen(children[i]); - len += strlen("</li>\n"); - } - len += strlen("</ul>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - list = g_new(gchar, len); - if (type && type[0]) { - ptr = g_stpcpy(list, "<ol>\n"); - } else { - ptr = g_stpcpy(list, "<ul>\n"); - } - for (i = 0; children && children[i]; ++i) { - ptr = g_stpcpy(ptr, "<li>\n"); - ptr = g_stpcpy(ptr, children[i]); - ptr = g_stpcpy(ptr, "</li>\n"); - } - ptr = g_stpcpy(ptr, "</ul>\n"); /* g_stpcpy() adds the NUL. */ - - return list; -} - -gchar * -mq_html_container(const gchar *element, ...) -{ - gsize len; - va_list ap; - gchar *child; - gchar *container; - gchar *ptr; - - /* Calculate length. */ - len = strlen("<"); - len += strlen(element); - len += strlen(">\n"); - va_start(ap, element); - while ((child = va_arg(ap, gchar *))) { - len += strlen(child); - } - va_end(ap); - len += strlen("</"); - len += strlen(element); - len += strlen(">\n"); - ++len; /* NUL byte */ - - /* Build string. */ - container = g_new(gchar, len); - ptr = g_stpcpy(container, "<"); - ptr = g_stpcpy(ptr, element); - ptr = g_stpcpy(ptr, ">\n"); - va_start(ap, element); - while ((child = va_arg(ap, gchar *))) { - ptr = g_stpcpy(ptr, child); - g_free(child); - } - va_end(ap); - ptr = g_stpcpy(ptr, "</"); - ptr = g_stpcpy(ptr, element); - ptr = g_stpcpy(ptr, ">\n"); /* g_stpcpy() adds the NUL. */ - - return container; -} - -gchar * -mq_html_notebook(gboolean vertical, const gchar *name, guint current_page, ...) -{ - gsize name_len; - gsize len; - va_list ap; - gsize i; - gchar *child; - gchar *tab_label; - gchar *i_str; - gchar *notebook; - gchar *ptr; - - /* Calculate length. */ - name_len = strlen(name); - len = strlen("<div class=\"notebook-") + 1 + strlen("\">\n"); - va_start(ap, current_page); - i = 0; - while ((child = va_arg(ap, gchar *)) && - (tab_label = va_arg(ap, gchar *))) { - i_str = g_strdup_printf("%zu", i); - len += strlen("<input id=\"_tab_"); - len += name_len; - len += strlen("_"); - len += strlen(i_str); - /* len += (gsize) log10(i) + 1; */ - len += strlen("\" type=\"radio\""); - if (i == current_page) { - len += strlen(" checked=\"checked\""); - } - len += strlen(" name=\"_tabs\"></input>\n"); - len += strlen("<label for=\"_tab_"); - len += name_len; - len += strlen("_"); - len += strlen(i_str); - /* len += (gsize) log10(i) + 1; */ - len += strlen("\">"); - len += strlen(tab_label); - len += strlen("</label>\n"); - ++i; - } - va_end(ap); - va_start(ap, current_page); - while ((child = va_arg(ap, gchar *)) && - (tab_label = va_arg(ap, gchar *))) { - i_str = g_strdup_printf("%zu", i); - len += strlen("<div id=\"_tab-page_"); - len += name_len; - len += strlen("_"); - len += strlen(i_str); - len += strlen("\">\n"); - len += strlen(child); - len += strlen("</div>\n<style>\ndiv.notebook-") + 1; - len += strlen(" > input#_tab_"); - len += name_len; - len += strlen("_"); - len += strlen(i_str); - len += strlen(":checked ~ div#_tab-page_"); - len += name_len; - len += strlen("_"); - len += strlen(i_str); - len += strlen(" {\ndisplay: block;\n}\n</style>\n"); - } - va_end(ap); - len += strlen("</div>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - notebook = g_new(gchar, len); - ptr = g_stpcpy(notebook, "<div class=\"notebook-"); - ptr = g_stpcpy(ptr, vertical ? "v" : "h"); - ptr = g_stpcpy(ptr, "\">\n"); - va_start(ap, current_page); - i = 0; - while ((child = va_arg(ap, gchar *)) && - (tab_label = va_arg(ap, gchar *))) { - i_str = g_strdup_printf("%zu", i); - ptr = g_stpcpy(ptr, "<input id=\"_tab_"); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "_"); - ptr = g_stpcpy(ptr, i_str); - ptr = g_stpcpy(ptr, "\" type=\"radio\""); - if (i == current_page) { - ptr = g_stpcpy(ptr, " checked=\"checked\""); - } - ptr = g_stpcpy(ptr, " name=\"_tabs\"></input>\n"); - ptr = g_stpcpy(ptr, "<label for=\"_tab_"); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "_"); - ptr = g_stpcpy(ptr, i_str); - ptr = g_stpcpy(ptr, "\">"); - ptr = g_stpcpy(ptr, tab_label); - ptr = g_stpcpy(ptr, "</label>\n"); - g_free(i_str); - ++i; - } - va_end(ap); - va_start(ap, current_page); - i = 0; - while ((child = va_arg(ap, gchar *)) && - (tab_label = va_arg(ap, gchar *))) { - i_str = g_strdup_printf("%zu", i); - ptr = g_stpcpy(ptr, "<div id=\"_tab-page_"); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "_"); - ptr = g_stpcpy(ptr, i_str); - ptr = g_stpcpy(ptr, "\">\n"); - ptr = g_stpcpy(ptr, child); - g_free(child); - ptr = g_stpcpy(ptr, "</div>\n<style>\ndiv.notebook-"); - ptr = g_stpcpy(ptr, vertical ? "v" : "h"); - ptr = g_stpcpy(ptr, " > input#_tab_"); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "_"); - ptr = g_stpcpy(ptr, i_str); - ptr = g_stpcpy(ptr, ":checked ~ div#_tab-page_"); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "_"); - ptr = g_stpcpy(ptr, i_str); - ptr = g_stpcpy(ptr, " {\ndisplay: block;\n}\n</style>\n"); - ++i; - } - va_end(ap); - ptr = g_stpcpy(ptr, "</div>\n"); /* g_stpcpy() adds the NUL. */ - - return notebook; -} - -gchar * -mq_html_form(const gchar *submit_label, const gchar *reset_label, ...) -{ - gsize len; - va_list ap; - gchar *child; - gchar *form; - gchar *ptr; - - /* Calculate length. */ - len = strlen("<form>\n"); - va_start(ap, reset_label); - while ((child = va_arg(ap, gchar *))) { - len += strlen(child); - } - va_end(ap); - len += strlen("<div class=\"dialog-buttonbox\">\n") + - strlen("<input type=\"reset\" value=\"") + strlen(reset_label) + - strlen("\">\n<input type=\"submit\" value=\"") + - strlen(submit_label) + strlen("\">\n</div>\n") + - strlen("</form>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - form = g_new(gchar, len); - ptr = g_stpcpy(form, "<form>\n"); - va_start(ap, reset_label); - while ((child = va_arg(ap, gchar *))) { - ptr = g_stpcpy(ptr, child); - g_free(child); - } - va_end(ap); - ptr = g_stpcpy(ptr, "<div class=\"dialog-buttonbox\">\n"); - ptr = g_stpcpy(ptr, "<input type=\"reset\" value=\""); - ptr = g_stpcpy(ptr, reset_label); - ptr = g_stpcpy(ptr, "\">\n<input type=\"submit\" value=\""); - ptr = g_stpcpy(ptr, submit_label); - ptr = g_stpcpy(ptr, "\">\n</div>\n"); - ptr = g_stpcpy(ptr, "</form>\n"); /* g_stpcpy() adds the NUL. */ - - return form; -} - -gchar * -mq_html_input_text(const gchar *name, const gchar *label, const gchar *value) -{ - return g_strdup_printf("<label for=\"%s\">\n<span>%s:</span>\n" - "<input type=\"text\" name=\"%s\" id=\"%s\" value=\"%s\">\n" - "</label>\n", - name, label, name, name, value ? value : ""); -} - -gchar * -mq_html_input_number_i(const gchar *name, const gchar *label, - gint min, gint step, gint max, gint value) -{ - return g_strdup_printf("<label for=\"%s\">\n<span>%s:</span>\n" - "<input type=\"number\" name=\"%s\" id=\"%s\"" - " min=\"%d\" step=\"%d\" max=\"%d\" value=\"%d\">\n" - "</label>\n", - name, label, name, name, min, step, max, value); -} - -gchar * -mq_html_input_number_d(const gchar *name, const gchar *label, - gdouble min, gdouble step, gdouble max, gdouble value) -{ - return g_strdup_printf("<label for=\"%s\">\n<span>%s:</span>\n" - "<input type=\"number\" name=\"%s\" id=\"%s\"" - " min=\"%f\" step=\"%f\" max=\"%f\" value=\"%f\">\n" - "</label>\n", - name, label, name, name, min, step, max, value); -} - -gchar * -mq_html_input_radio(const gchar *name, const gchar *label, gboolean checked) -{ - return g_strdup_printf("<label for=\"%s\">\n<span>%s:</span>\n" - "<input type=\"radio\" name=\"%s\" id=\"%s\"%s>\n</label>\n", - name, label, name, name, checked ? " checked=\"checked\"" : ""); -} - -gchar * -mq_html_input_checkbox(const gchar *name, const gchar *label, gboolean checked) -{ - /* - * Values of "checkbox"-type <input>s that are not checked are not sent - * in queries with form submissions. The "about:preferences" - * query-handling code doesn't handle any preferences that aren't - * submitted in the query, so values need to be submitted for unchecked - * "checkbox"-type <input>s in order for unchecking to have any effect. - * - * This function returns two <input>s: one of type "hidden" with a value - * of "off" and one of type "checkbox". If the "checkbox"-type <input> - * is checked, both <input> values will be submitted in the query, with - * the value of the "checkbox"-type <input> last. Otherwise, only the - * "off" value of the "hidden"-type <input> will be submitted. - * - * The query-parsing code for "about"-scheme resources iterates through - * each "key=value" pair in order, inserting each pair into a - * GHashTable. When keys collide, g_hash_table_insert() replaces the - * previous value with the new value. Thus, the value of the - * "checkbox"-type <input> will override that of the "hidden"-type - * <input> when the former <input> is checked. - */ - - return g_strdup_printf("<label for=\"%s\">\n<span>%s:</span>\n" - "<input type=\"hidden\" name=\"%s\" value=\"off\">\n" - "<input type=\"checkbox\" name=\"%s\" id=\"%s\"%s>\n</label>\n", - name, label, name, name, name, - checked ? " checked=\"checked\"" : ""); -} - -gchar * -mq_html_input_select(const gchar *name, const gchar *label, - const gchar *selected, - GDestroyNotify destroy_value, GDestroyNotify destroy_label, ...) -{ - gsize len; - va_list ap; - gchar *option_value; - gchar *option_label; - gchar *select; - gchar *ptr; - - g_assert(selected && selected[0]); /* Would cause buffer overflow */ - - /* Calculate length. */ - len = strlen("<label for=\""); - len += strlen(name); - len += strlen("\">\n<span>"); - len += strlen(label); - len += strlen(":</span>\n<select name=\""); - len += strlen(name); - len += strlen("\" id=\""); - len += strlen(name); - len += strlen("\">\n"); - va_start(ap, destroy_label); - while ((option_value = va_arg(ap, gchar *)) && (option_label = - va_arg(ap, gchar *))) { - len += strlen("<option value=\""); - len += strlen(option_value); - len += strlen("\""); - len += strlen(">"); - len += strlen(option_label); - len += strlen("</option>\n"); - } - va_end(ap); - len += strlen(" selected=\"selected\""); - len += strlen("</select>\n</label>\n"); - ++len; /* NUL byte */ - - /* Build string. */ - select = g_new(gchar, len); - ptr = g_stpcpy(select, "<label for=\""); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "\">\n<span>"); - ptr = g_stpcpy(ptr, label); - ptr = g_stpcpy(ptr, ":</span>\n<select name=\""); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "\" id=\""); - ptr = g_stpcpy(ptr, name); - ptr = g_stpcpy(ptr, "\">\n"); - va_start(ap, destroy_label); - while ((option_value = va_arg(ap, gchar *)) && (option_label = - va_arg(ap, gchar *))) { - ptr = g_stpcpy(ptr, "<option value=\""); - ptr = g_stpcpy(ptr, option_value); - ptr = g_stpcpy(ptr, "\""); - if (g_strcmp0(option_value, selected) == 0) { - ptr = g_stpcpy(ptr, " selected=\"selected\""); - } - ptr = g_stpcpy(ptr, ">"); - ptr = g_stpcpy(ptr, option_label); - if (destroy_value) { - destroy_value(option_value); - } - if (destroy_label) { - destroy_label(option_label); - } - ptr = g_stpcpy(ptr, "</option>\n"); - } - va_end(ap); - ptr = g_stpcpy(ptr, "</select>\n</label>\n"); /* g_stpcpy() adds NUL */ - - return select; -} - -gchar * -mq_html_input_iframe(const gchar *src) -{ - return g_strdup_printf("<iframe src=\"%s\"></iframe>", src); -} |