1017 lines
36 KiB
Text
1017 lines
36 KiB
Text
[HTMLFormat::] HTML Formats.
|
|
|
|
To provide for weaving into HTML and into EPUB books.
|
|
|
|
@ \section{Creation.}
|
|
ePub books are basically mini-websites, so they share the same renderer.
|
|
|
|
<<*>>=
|
|
void HTMLFormat::create(void) {
|
|
<<Create HTML>>;
|
|
<<Create ePub>>;
|
|
}
|
|
|
|
<<Create HTML>>=
|
|
weave_format *wf = Formats::create_weave_format(I"HTML", I".html");
|
|
METHOD_ADD(wf, RENDER_FOR_MTID, HTMLFormat::render);
|
|
|
|
<<Create ePub>>=
|
|
weave_format *wf = Formats::create_weave_format(I"ePub", I".html");
|
|
METHOD_ADD(wf, RENDER_FOR_MTID, HTMLFormat::render_EPUB);
|
|
METHOD_ADD(wf, BEGIN_WEAVING_FOR_MTID, HTMLFormat::begin_weaving_EPUB);
|
|
METHOD_ADD(wf, END_WEAVING_FOR_MTID, HTMLFormat::end_weaving_EPUB);
|
|
|
|
@ \section{Rendering.}
|
|
To keep track of what we're writing, we store the renderer state in an
|
|
instance of this:
|
|
|
|
<<*>>=
|
|
typedef struct HTML_render_state {
|
|
struct text_stream *OUT;
|
|
struct filename *into_file;
|
|
struct weave_order *wv;
|
|
struct colour_scheme *colours;
|
|
int EPUB_flag;
|
|
int popup_counter;
|
|
int carousel_number;
|
|
int slide_number;
|
|
int slide_of;
|
|
struct asset_rule *copy_rule;
|
|
} HTML_render_state;
|
|
|
|
@ The initial state is as follows:
|
|
|
|
<<*>>=
|
|
HTML_render_state HTMLFormat::initial_state(text_stream *OUT, weave_order *wv,
|
|
int EPUB_mode, filename *into) {
|
|
HTML_render_state hrs;
|
|
hrs.OUT = OUT;
|
|
hrs.into_file = into;
|
|
hrs.wv = wv;
|
|
hrs.EPUB_flag = EPUB_mode;
|
|
hrs.popup_counter = 1;
|
|
hrs.carousel_number = 1;
|
|
hrs.slide_number = -1;
|
|
hrs.slide_of = -1;
|
|
hrs.copy_rule = Assets::new_rule(NULL, I"", I"private copy", NULL);
|
|
|
|
Swarm::ensure_plugin(wv, I"Base");
|
|
hrs.colours = Swarm::ensure_colour_scheme(wv, I"Colours", I"");
|
|
return hrs;
|
|
}
|
|
|
|
@ So, then, here are the front-end method functions for rendering to HTML and
|
|
ePub respectively:
|
|
|
|
<<*>>=
|
|
void HTMLFormat::render(weave_format *self, text_stream *OUT, heterogeneous_tree *tree) {
|
|
weave_document_node *C = RETRIEVE_POINTER_weave_document_node(tree->root->content);
|
|
HTML::declare_as_HTML(OUT, FALSE);
|
|
HTML_render_state hrs = HTMLFormat::initial_state(OUT, C->wv, FALSE, C->wv->weave_to);
|
|
Trees::traverse_from(tree->root, &HTMLFormat::render_visit, (void *) &hrs, 0);
|
|
HTML::completed(OUT);
|
|
}
|
|
void HTMLFormat::render_EPUB(weave_format *self, text_stream *OUT, heterogeneous_tree *tree) {
|
|
weave_document_node *C = RETRIEVE_POINTER_weave_document_node(tree->root->content);
|
|
HTML::declare_as_HTML(OUT, TRUE);
|
|
HTML_render_state hrs = HTMLFormat::initial_state(OUT, C->wv, TRUE, C->wv->weave_to);
|
|
Trees::traverse_from(tree->root, &HTMLFormat::render_visit, (void *) &hrs, 0);
|
|
Epub::note_page(C->wv->weave_web->as_ebook, C->wv->weave_to, C->wv->booklet_title, I"");
|
|
HTML::completed(OUT);
|
|
}
|
|
|
|
@ And in either case, we traverse the weave tree with the following visitor function.
|
|
|
|
<<*>>=
|
|
int HTMLFormat::render_visit(tree_node *N, void *state, int L) {
|
|
HTML_render_state *hrs = (HTML_render_state *) state;
|
|
text_stream *OUT = hrs->OUT;
|
|
if ((N->type == weave_document_node_type) ||
|
|
(N->type == weave_body_node_type) ||
|
|
(N->type == weave_chapter_header_node_type) ||
|
|
(N->type == weave_chapter_footer_node_type) ||
|
|
(N->type == weave_pagebreak_node_type) ||
|
|
(N->type == weave_chapter_node_type) ||
|
|
(N->type == weave_chapter_title_page_node_type) ||
|
|
(N->type == weave_grammar_index_node_type)) <<Render nothing>>
|
|
|
|
else if (N->type == weave_head_node_type) <<Render head>>
|
|
else if (N->type == weave_tail_node_type) <<Render tail>>
|
|
else if (N->type == weave_verbatim_node_type) <<Render verbatim>>
|
|
else if (N->type == weave_section_header_node_type) <<Render header>>
|
|
else if (N->type == weave_section_footer_node_type) <<Render footer>>
|
|
else if (N->type == weave_section_purpose_node_type) <<Render purpose>>
|
|
else if (N->type == weave_subheading_node_type) <<Render subheading>>
|
|
else if (N->type == weave_bar_node_type) <<Render bar>>
|
|
else if (N->type == weave_paragraph_heading_node_type) <<Render paragraph heading>>
|
|
else if (N->type == weave_endnote_node_type) <<Render endnote>>
|
|
else if (N->type == weave_figure_node_type) <<Render figure>>
|
|
else if (N->type == weave_extract_node_type) <<Render extract>>
|
|
else if (N->type == weave_audio_node_type) <<Render audio clip>>
|
|
else if (N->type == weave_video_node_type) <<Render video clip>>
|
|
else if (N->type == weave_download_node_type) <<Render download>>
|
|
else if (N->type == weave_material_node_type) <<Render material>>
|
|
else if (N->type == weave_embed_node_type) <<Render embed>>
|
|
else if (N->type == weave_pmac_node_type) <<Render pmac>>
|
|
else if (N->type == weave_vskip_node_type) <<Render vskip>>
|
|
else if (N->type == weave_section_node_type) <<Render section>>
|
|
else if (N->type == weave_code_line_node_type) <<Render code line>>
|
|
else if (N->type == weave_function_usage_node_type) <<Render function usage>>
|
|
else if (N->type == weave_commentary_node_type) <<Render commentary>>
|
|
else if (N->type == weave_carousel_slide_node_type) <<Render carousel slide>>
|
|
else if (N->type == weave_toc_node_type) <<Render toc>>
|
|
else if (N->type == weave_toc_line_node_type) <<Render toc line>>
|
|
else if (N->type == weave_defn_node_type) <<Render defn>>
|
|
else if (N->type == weave_source_code_node_type) <<Render source code>>
|
|
else if (N->type == weave_url_node_type) <<Render URL>>
|
|
else if (N->type == weave_footnote_cue_node_type) <<Render footnote cue>>
|
|
else if (N->type == weave_begin_footnote_text_node_type) <<Render footnote>>
|
|
else if (N->type == weave_display_line_node_type) <<Render display line>>
|
|
else if (N->type == weave_function_defn_node_type) <<Render function defn>>
|
|
else if (N->type == weave_item_node_type) <<Render item>>
|
|
else if (N->type == weave_inline_node_type) <<Render inline>>
|
|
else if (N->type == weave_locale_node_type) <<Render locale>>
|
|
else if (N->type == weave_maths_node_type) <<Render maths>>
|
|
else if (N->type == weave_linebreak_node_type) <<Render linebreak>>
|
|
|
|
else internal_error("unable to render unknown node");
|
|
return TRUE;
|
|
}
|
|
|
|
<<Render head>>=
|
|
weave_head_node *C = RETRIEVE_POINTER_weave_head_node(N->content);
|
|
HTML::comment(OUT, C->banner);
|
|
|
|
<<Render header>>=
|
|
if (hrs->EPUB_flag == FALSE) {
|
|
weave_section_header_node *C =
|
|
RETRIEVE_POINTER_weave_section_header_node(N->content);
|
|
Swarm::ensure_plugin(hrs->wv, I"Breadcrumbs");
|
|
HTML_OPEN_WITH("div", "class=\"breadcrumbs\"");
|
|
HTML_OPEN_WITH("ul", "class=\"crumbs\"");
|
|
Colonies::drop_initial_breadcrumbs(OUT,
|
|
hrs->wv->weave_to, hrs->wv->breadcrumbs);
|
|
text_stream *bct = Bibliographic::get_datum(hrs->wv->weave_web->md, I"Title");
|
|
if (Str::len(Bibliographic::get_datum(hrs->wv->weave_web->md, I"Short Title")) > 0)
|
|
bct = Bibliographic::get_datum(hrs->wv->weave_web->md, I"Short Title");
|
|
if (hrs->wv->self_contained == FALSE) {
|
|
Colonies::write_breadcrumb(OUT, bct, I"index.html");
|
|
if (hrs->wv->weave_web->md->chaptered) {
|
|
TEMPORARY_TEXT(chapter_link)
|
|
WRITE_TO(chapter_link, "index.html#%s%S",
|
|
(hrs->wv->weave_web->as_ebook)?"C":"",
|
|
C->sect->owning_chapter->md->ch_range);
|
|
Colonies::write_breadcrumb(OUT,
|
|
C->sect->owning_chapter->md->ch_title, chapter_link);
|
|
DISCARD_TEXT(chapter_link)
|
|
}
|
|
Colonies::write_breadcrumb(OUT, C->sect->md->sect_title, NULL);
|
|
} else {
|
|
Colonies::write_breadcrumb(OUT, bct, NULL);
|
|
}
|
|
HTML_CLOSE("ul");
|
|
HTML_CLOSE("div");
|
|
}
|
|
|
|
<<Render footer>>=
|
|
weave_section_footer_node *C =
|
|
RETRIEVE_POINTER_weave_section_footer_node(N->content);
|
|
int count = 0;
|
|
chapter *Ch;
|
|
section *next_S = NULL, *prev_S = NULL, *last = NULL;
|
|
LOOP_OVER_LINKED_LIST(Ch, chapter, hrs->wv->weave_web->chapters) {
|
|
if (Ch->md->imported == FALSE) {
|
|
section *S;
|
|
LOOP_OVER_LINKED_LIST(S, section, Ch->sections) {
|
|
count ++;
|
|
if (S == C->sect) prev_S = last;
|
|
if (last == C->sect) next_S = S;
|
|
last = S;
|
|
}
|
|
}
|
|
}
|
|
if (count >= 2) {
|
|
HTML_OPEN_WITH("nav", "role=\"progress\"");
|
|
HTML_OPEN_WITH("div", "class=\"progresscontainer\"");
|
|
HTML_OPEN_WITH("ul", "class=\"progressbar\"");
|
|
<<Insert previous arrow>>;
|
|
chapter *Ch;
|
|
LOOP_OVER_LINKED_LIST(Ch, chapter, hrs->wv->weave_web->chapters) {
|
|
if (Ch->md->imported == FALSE) {
|
|
if (Str::ne(Ch->md->ch_range, I"S")) {
|
|
if (Ch == C->sect->owning_chapter) {
|
|
HTML_OPEN_WITH("li", "class=\"progresscurrentchapter\"");
|
|
} else {
|
|
HTML_OPEN_WITH("li", "class=\"progresschapter\"");
|
|
}
|
|
section *S = FIRST_IN_LINKED_LIST(section, Ch->sections);
|
|
if (S) {
|
|
TEMPORARY_TEXT(TEMP)
|
|
Colonies::section_URL(TEMP, S->md);
|
|
if (Ch != C->sect->owning_chapter) {
|
|
HTML::begin_link(OUT, TEMP);
|
|
}
|
|
WRITE("%S", Ch->md->ch_range);
|
|
if (Ch != C->sect->owning_chapter) {
|
|
HTML::end_link(OUT);
|
|
}
|
|
DISCARD_TEXT(TEMP)
|
|
}
|
|
HTML_CLOSE("li");
|
|
}
|
|
if (Ch == C->sect->owning_chapter) {
|
|
section *S;
|
|
LOOP_OVER_LINKED_LIST(S, section, Ch->sections) {
|
|
TEMPORARY_TEXT(label)
|
|
int on = FALSE;
|
|
LOOP_THROUGH_TEXT(pos, S->md->sect_range) {
|
|
if (Str::get(pos) == '/') on = TRUE;
|
|
else if (on) PUT_TO(label, Str::get(pos));
|
|
}
|
|
if (Str::eq(Bibliographic::get_datum(hrs->wv->weave_web->md,
|
|
I"Sequential Section Ranges"), I"On"))
|
|
Str::delete_first_character(label);
|
|
if (S == C->sect) {
|
|
HTML_OPEN_WITH("li", "class=\"progresscurrent\"");
|
|
WRITE("%S", label);
|
|
HTML_CLOSE("li");
|
|
} else {
|
|
HTML_OPEN_WITH("li", "class=\"progresssection\"");
|
|
TEMPORARY_TEXT(TEMP)
|
|
Colonies::section_URL(TEMP, S->md);
|
|
HTML::begin_link(OUT, TEMP);
|
|
WRITE("%S", label);
|
|
HTML::end_link(OUT);
|
|
DISCARD_TEXT(TEMP)
|
|
HTML_CLOSE("li");
|
|
}
|
|
DISCARD_TEXT(label)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
<<Insert next arrow>>;
|
|
HTML_CLOSE("ul");
|
|
HTML_CLOSE("div");
|
|
HTML_CLOSE("nav");
|
|
}
|
|
|
|
<<Insert previous arrow>>=
|
|
if (prev_S) HTML_OPEN_WITH("li", "class=\"progressprev\"")
|
|
else HTML_OPEN_WITH("li", "class=\"progressprevoff\"");
|
|
TEMPORARY_TEXT(TEMP)
|
|
if (prev_S) Colonies::section_URL(TEMP, prev_S->md);
|
|
if (prev_S) HTML::begin_link(OUT, TEMP);
|
|
WRITE("❮");
|
|
if (prev_S) HTML::end_link(OUT);
|
|
DISCARD_TEXT(TEMP)
|
|
HTML_CLOSE("li");
|
|
|
|
<<Insert next arrow>>=
|
|
if (next_S) HTML_OPEN_WITH("li", "class=\"progressnext\"")
|
|
else HTML_OPEN_WITH("li", "class=\"progressnextoff\"");
|
|
TEMPORARY_TEXT(TEMP)
|
|
if (next_S) Colonies::section_URL(TEMP, next_S->md);
|
|
if (next_S) HTML::begin_link(OUT, TEMP);
|
|
WRITE("❯");
|
|
if (next_S) HTML::end_link(OUT);
|
|
DISCARD_TEXT(TEMP)
|
|
HTML_CLOSE("li");
|
|
|
|
<<Render tail>>=
|
|
weave_tail_node *C = RETRIEVE_POINTER_weave_tail_node(N->content);
|
|
HTML::comment(OUT, C->rennab);
|
|
|
|
<<Render purpose>>=
|
|
weave_section_purpose_node *C =
|
|
RETRIEVE_POINTER_weave_section_purpose_node(N->content);
|
|
HTML_OPEN_WITH("p", "class=\"purpose\"");
|
|
HTMLFormat::escape_text(OUT, C->purpose);
|
|
HTML_CLOSE("p"); WRITE("\n");
|
|
|
|
<<Render subheading>>=
|
|
weave_subheading_node *C = RETRIEVE_POINTER_weave_subheading_node(N->content);
|
|
HTML_OPEN("h3");
|
|
HTMLFormat::escape_text(OUT, C->text);
|
|
HTML_CLOSE("h3"); WRITE("\n");
|
|
|
|
<<Render bar>>=
|
|
HTML::hr(OUT, NULL);
|
|
|
|
<<Render paragraph heading>>=
|
|
weave_paragraph_heading_node *C =
|
|
RETRIEVE_POINTER_weave_paragraph_heading_node(N->content);
|
|
paragraph *P = C->para;
|
|
if (P == NULL) internal_error("no para");
|
|
if (N->child == NULL) {
|
|
paragraph *first_in_para = P;
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
}
|
|
|
|
<<Render endnote>>=
|
|
HTML_OPEN("li");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("li");
|
|
return FALSE;
|
|
|
|
<<Render figure>>=
|
|
weave_figure_node *C = RETRIEVE_POINTER_weave_figure_node(N->content);
|
|
filename *F = Filenames::in(
|
|
Pathnames::down(hrs->wv->weave_web->md->path_to_web, I"Figures"),
|
|
C->figname);
|
|
filename *RF = Filenames::from_text(C->figname);
|
|
HTML_OPEN_WITH("p", "class=\"center-p\"");
|
|
HTML::image_to_dimensions(OUT, RF, C->w, C->h);
|
|
Assets::include_asset(OUT, hrs->copy_rule, hrs->wv->weave_web, F, NULL,
|
|
hrs->wv->pattern, hrs->wv->weave_to);
|
|
HTML_CLOSE("p");
|
|
WRITE("\n");
|
|
|
|
<<Render extract>>=
|
|
weave_extract_node *C = RETRIEVE_POINTER_weave_extract_node(N->content);
|
|
filename *F = Filenames::in(
|
|
Pathnames::down(hrs->wv->weave_web->md->path_to_web, I"HTML"),
|
|
C->extract);
|
|
HTML_OPEN_WITH("div", "class=\"inweb-extract\"");
|
|
FILE *B = BinaryFiles::try_to_open_for_reading(F);
|
|
if (B == NULL) {
|
|
Main::error_in_web(I"Unable to find this HTML extract",
|
|
hrs->wv->current_weave_line);
|
|
} else {
|
|
while (TRUE) {
|
|
int c = getc(B);
|
|
if (c == EOF) break;
|
|
PUT((wchar_t) c);
|
|
}
|
|
BinaryFiles::close(B);
|
|
}
|
|
HTML_CLOSE("div");
|
|
WRITE("\n");
|
|
|
|
<<Render audio clip>>=
|
|
weave_audio_node *C = RETRIEVE_POINTER_weave_audio_node(N->content);
|
|
filename *F = Filenames::in(
|
|
Pathnames::down(hrs->wv->weave_web->md->path_to_web, I"Audio"),
|
|
C->audio_name);
|
|
Assets::include_asset(OUT, hrs->copy_rule, hrs->wv->weave_web, F, NULL,
|
|
hrs->wv->pattern, hrs->wv->weave_to);
|
|
HTML_OPEN_WITH("p", "class=\"center-p\"");
|
|
WRITE("<audio controls>\n");
|
|
WRITE("<source src=\"%S\" type=\"audio/mpeg\">\n", C->audio_name);
|
|
WRITE("Your browser does not support the audio element.\n");
|
|
WRITE("</audio>\n");
|
|
HTML_CLOSE("p");
|
|
WRITE("\n");
|
|
|
|
<<Render video clip>>=
|
|
weave_video_node *C = RETRIEVE_POINTER_weave_video_node(N->content);
|
|
filename *F = Filenames::in(
|
|
Pathnames::down(hrs->wv->weave_web->md->path_to_web, I"Video"),
|
|
C->video_name);
|
|
Assets::include_asset(OUT, hrs->copy_rule, hrs->wv->weave_web, F, NULL,
|
|
hrs->wv->pattern, hrs->wv->weave_to);
|
|
HTML_OPEN_WITH("p", "class=\"center-p\"");
|
|
if ((C->w > 0) && (C->h > 0))
|
|
WRITE("<video width=\"%d\" height=\"%d\" controls>", C->w, C->h);
|
|
else if (C->w > 0)
|
|
WRITE("<video width=\"%d\" controls>", C->w);
|
|
else if (C->h > 0)
|
|
WRITE("<video height=\"%d\" controls>", C->h);
|
|
else
|
|
WRITE("<video controls>");
|
|
WRITE("<source src=\"%S\" type=\"video/mp4\">\n", C->video_name);
|
|
WRITE("Your browser does not support the video tag.\n");
|
|
WRITE("</video>\n");
|
|
HTML_CLOSE("p");
|
|
WRITE("\n");
|
|
|
|
<<Render download>>=
|
|
weave_download_node *C = RETRIEVE_POINTER_weave_download_node(N->content);
|
|
pathname *P = Pathnames::down(hrs->wv->weave_web->md->path_to_web, I"Downloads");
|
|
filename *F = Filenames::in(P, C->download_name);
|
|
filename *TF = Patterns::find_file_in_subdirectory(hrs->wv->pattern, I"Embedding",
|
|
I"Download.html");
|
|
if (TF == NULL) {
|
|
Main::error_in_web(I"Downloads are not supported", hrs->wv->current_weave_line);
|
|
} else {
|
|
Swarm::ensure_plugin(hrs->wv, I"Downloads");
|
|
pathname *TOP =
|
|
Assets::include_asset(OUT, hrs->copy_rule, hrs->wv->weave_web, F, NULL,
|
|
hrs->wv->pattern, hrs->wv->weave_to);
|
|
if (TOP == NULL) TOP = Filenames::up(F);
|
|
TEMPORARY_TEXT(url)
|
|
TEMPORARY_TEXT(size)
|
|
Pathnames::relative_URL(url, Filenames::up(hrs->wv->weave_to), TOP);
|
|
WRITE_TO(url, "%S", Filenames::get_leafname(F));
|
|
int N = Filenames::size(F);
|
|
if (N > 0) <<Describe the file size>>
|
|
else Main::error_in_web(I"Download file missing or empty",
|
|
hrs->wv->current_weave_line);
|
|
filename *D = Filenames::from_text(C->download_name);
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"File Name",
|
|
Filenames::get_leafname(D));
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"File URL", url);
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"File Details", size);
|
|
Collater::for_web_and_pattern(OUT, hrs->wv->weave_web, hrs->wv->pattern,
|
|
TF, hrs->into_file);
|
|
WRITE("\n");
|
|
DISCARD_TEXT(url)
|
|
DISCARD_TEXT(size)
|
|
}
|
|
|
|
<<Describe the file size>>=
|
|
WRITE_TO(size, " (");
|
|
if (Str::len(C->filetype) > 0) WRITE_TO(size, "%S, ", C->filetype);
|
|
int x = 0, y = 0;
|
|
text_stream *unit = I" byte"; x = N; y = 0;
|
|
if (N > 1) { unit = I" bytes"; }
|
|
if (N >= 1024) { unit = I"kB"; x = 10*N/1024; y = x%10; x = x/10; }
|
|
if (N >= 1024*1024) { unit = I"MB"; x = 10*N/1024/1024; y = x%10; x = x/10; }
|
|
if (N >= 1024*1024*1024) { unit = I"GB"; x = 10*N/1024/1024/1024; y = x%10; x = x/10; }
|
|
WRITE_TO(size, "%d", x);
|
|
if (y > 0) WRITE_TO(size, ".%d", y);
|
|
WRITE_TO(size, "%S", unit);
|
|
WRITE_TO(size, ")");
|
|
|
|
<<Render material>>=
|
|
weave_material_node *C = RETRIEVE_POINTER_weave_material_node(N->content);
|
|
paragraph *first_in_para = NULL;
|
|
if ((N == N->parent->child) &&
|
|
(N->parent->type == weave_paragraph_heading_node_type)) {
|
|
weave_paragraph_heading_node *PC =
|
|
RETRIEVE_POINTER_weave_paragraph_heading_node(N->parent->content);
|
|
first_in_para = PC->para;
|
|
}
|
|
if (C->material_type == COMMENTARY_MATERIAL)
|
|
<<Deal with a commentary material node>>
|
|
else if (C->material_type == CODE_MATERIAL)
|
|
<<Deal with a code material node>>
|
|
else if (C->material_type == FOOTNOTES_MATERIAL)
|
|
<<Deal with a footnotes material node>>
|
|
else if (C->material_type == ENDNOTES_MATERIAL)
|
|
<<Deal with a endnotes material node>>
|
|
else if (C->material_type == MACRO_MATERIAL)
|
|
<<Deal with a macro material node>>
|
|
else if (C->material_type == DEFINITION_MATERIAL)
|
|
<<Deal with a definition material node>>;
|
|
return FALSE;
|
|
|
|
<<If no para number yet, render a p just to hold this>>=
|
|
if (first_in_para) {
|
|
HTML_OPEN_WITH("p", "class=\"commentary firstcommentary\"");
|
|
HTMLFormat::paragraph_number(OUT, first_in_para);
|
|
HTML_CLOSE("p"); WRITE("\n");
|
|
first_in_para = NULL;
|
|
}
|
|
|
|
<<Deal with a commentary material node>>=
|
|
int item_depth = 0;
|
|
for (tree_node *M = N->child; M; M = M->next) {
|
|
if (M->type == weave_item_node_type) {
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
weave_item_node *C = RETRIEVE_POINTER_weave_item_node(M->content);
|
|
HTMLFormat::go_to_depth(hrs, item_depth, C->depth);
|
|
item_depth = C->depth;
|
|
Trees::traverse_from(M, &HTMLFormat::render_visit, (void *) hrs, L+1);
|
|
continue;
|
|
}
|
|
if (HTMLFormat::interior_material(M)) <<Render a run of interior matter>>;
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
if (item_depth > 0) {
|
|
HTMLFormat::go_to_depth(hrs, item_depth, 0);
|
|
item_depth = 0;
|
|
}
|
|
if (M->type == weave_vskip_node_type) continue;
|
|
Trees::traverse_from(M, &HTMLFormat::render_visit, (void *) hrs, L+1);
|
|
}
|
|
if (item_depth > 0) {
|
|
HTMLFormat::go_to_depth(hrs, item_depth, 0);
|
|
item_depth = 0;
|
|
}
|
|
|
|
<<Render a run of interior matter>>=
|
|
if (first_in_para) {
|
|
HTML_OPEN_WITH("p", "class=\"commentary firstcommentary\"");
|
|
HTMLFormat::paragraph_number(OUT, first_in_para);
|
|
first_in_para = NULL;
|
|
} else {
|
|
if (item_depth == 0) HTML_OPEN_WITH("p", "class=\"commentary\"");
|
|
}
|
|
while (M) {
|
|
Trees::traverse_from(M, &HTMLFormat::render_visit, (void *) hrs, L+1);
|
|
if ((M->next == NULL) || (HTMLFormat::interior_material(M->next) == FALSE)) break;
|
|
M = M->next;
|
|
}
|
|
if (item_depth == 0) { HTML_CLOSE("p"); WRITE("\n"); }
|
|
continue;
|
|
|
|
<<Deal with a code material node>>=
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
if (C->styling) {
|
|
TEMPORARY_TEXT(csname)
|
|
WRITE_TO(csname, "%S-Colours", C->styling->language_name);
|
|
hrs->colours = Swarm::ensure_colour_scheme(hrs->wv,
|
|
csname, C->styling->language_name);
|
|
DISCARD_TEXT(csname)
|
|
}
|
|
TEMPORARY_TEXT(cl)
|
|
WRITE_TO(cl, "%S", hrs->colours->prefix);
|
|
if (C->plainly) WRITE_TO(cl, "undisplayed-code");
|
|
else WRITE_TO(cl, "displayed-code");
|
|
WRITE("<pre class=\"%S all-displayed-code code-font\">\n", cl);
|
|
DISCARD_TEXT(cl)
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("pre"); WRITE("\n");
|
|
if (Str::len(C->endnote) > 0) {
|
|
HTML_OPEN_WITH("ul", "class=\"endnotetexts\"");
|
|
HTML_OPEN("li");
|
|
HTMLFormat::escape_text(OUT, C->endnote);
|
|
HTML_CLOSE("li");
|
|
HTML_CLOSE("ul"); WRITE("\n");
|
|
}
|
|
|
|
<<Deal with a footnotes material node>>=
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
HTML_OPEN_WITH("ul", "class=\"footnotetexts\"");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("ul"); WRITE("\n");
|
|
|
|
<<Deal with a endnotes material node>>=
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
HTML_OPEN_WITH("ul", "class=\"endnotetexts\"");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("ul"); WRITE("\n");
|
|
|
|
<<Deal with a macro material node>>=
|
|
if (first_in_para) {
|
|
HTML_OPEN_WITH("p", "class=\"commentary firstcommentary\"");
|
|
HTMLFormat::paragraph_number(OUT, first_in_para);
|
|
} else {
|
|
HTML_OPEN_WITH("p", "class=\"commentary\"");
|
|
}
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("p"); WRITE("\n");
|
|
|
|
<<Deal with a definition material node>>=
|
|
<<If no para number yet, render a p just to hold this>>;
|
|
HTML_OPEN_WITH("pre", "class=\"definitions code-font\"");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("pre"); WRITE("\n");
|
|
|
|
@ This has to embed some Internet-sourced content. [[service]]
|
|
here is something like [[YouTube]] or [[Soundcloud]], and [[ID]] is whatever code
|
|
that service uses to identify the video/audio in question.
|
|
|
|
<<Render embed>>=
|
|
weave_embed_node *C = RETRIEVE_POINTER_weave_embed_node(N->content);
|
|
text_stream *CH = I"405";
|
|
text_stream *CW = I"720";
|
|
if (C->w > 0) { Str::clear(CW); WRITE_TO(CW, "%d", C->w); }
|
|
if (C->h > 0) { Str::clear(CH); WRITE_TO(CH, "%d", C->h); }
|
|
TEMPORARY_TEXT(embed_leaf)
|
|
WRITE_TO(embed_leaf, "%S.html", C->service);
|
|
filename *F = Patterns::find_file_in_subdirectory(hrs->wv->pattern, I"Embedding", embed_leaf);
|
|
DISCARD_TEXT(embed_leaf)
|
|
if (F == NULL) {
|
|
Main::error_in_web(I"This is not a supported service", hrs->wv->current_weave_line);
|
|
} else {
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"Content ID", C->ID);
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"Content Width", CW);
|
|
Bibliographic::set_datum(hrs->wv->weave_web->md, I"Content Height", CH);
|
|
HTML_OPEN_WITH("p", "class=\"center-p\"");
|
|
Collater::for_web_and_pattern(OUT, hrs->wv->weave_web, hrs->wv->pattern,
|
|
F, hrs->into_file);
|
|
HTML_CLOSE("p");
|
|
WRITE("\n");
|
|
}
|
|
|
|
<<Render pmac>>=
|
|
weave_pmac_node *C = RETRIEVE_POINTER_weave_pmac_node(N->content);
|
|
paragraph *P = C->pmac->defining_paragraph;
|
|
HTML_OPEN_WITH("span", "class=\"named-paragraph-container code-font\"");
|
|
if (C->defn == FALSE) {
|
|
TEMPORARY_TEXT(url)
|
|
Colonies::paragraph_URL(url, P, hrs->wv->weave_to);
|
|
HTML::begin_link_with_class(OUT, I"named-paragraph-link", url);
|
|
DISCARD_TEXT(url)
|
|
}
|
|
HTML_OPEN_WITH("span", "class=\"%s\"",
|
|
(C->defn)?"named-paragraph-defn":"named-paragraph");
|
|
HTMLFormat::escape_text(OUT, C->pmac->macro_name);
|
|
HTML_CLOSE("span");
|
|
HTML_OPEN_WITH("span", "class=\"named-paragraph-number\"");
|
|
HTMLFormat::escape_text(OUT, P->paragraph_number);
|
|
HTML_CLOSE("span");
|
|
if (C->defn == FALSE) HTML::end_link(OUT);
|
|
HTML_CLOSE("span");
|
|
if (C->defn) {
|
|
HTMLFormat::change_colour(OUT, COMMENT_COLOUR, hrs->colours);
|
|
WRITE(" =");
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
}
|
|
|
|
<<Render vskip>>=
|
|
WRITE("\n");
|
|
|
|
<<Render section>>=
|
|
weave_section_node *C = RETRIEVE_POINTER_weave_section_node(N->content);
|
|
LOG("It was %d\n", C->allocation_id);
|
|
|
|
<<Render code line>>=
|
|
<<Recurse the renderer through children nodes>>;
|
|
WRITE("\n");
|
|
return FALSE;
|
|
|
|
<<Render function usage>>=
|
|
weave_function_usage_node *C = RETRIEVE_POINTER_weave_function_usage_node(N->content);
|
|
HTML::begin_link_with_class(OUT, I"function-link", C->url);
|
|
HTMLFormat::change_colour(OUT, FUNCTION_COLOUR, hrs->colours);
|
|
WRITE("%S", C->fn->function_name);
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
HTML::end_link(OUT);
|
|
|
|
<<Render commentary>>=
|
|
weave_commentary_node *C = RETRIEVE_POINTER_weave_commentary_node(N->content);
|
|
if (C->in_code) HTMLFormat::change_colour(OUT, COMMENT_COLOUR, hrs->colours);
|
|
for (int i=0; i < Str::len(C->text); i++) {
|
|
if (Str::get_at(C->text, i) == '&') WRITE("&");
|
|
else if (Str::get_at(C->text, i) == '<') WRITE("<");
|
|
else if (Str::get_at(C->text, i) == '>') WRITE(">");
|
|
else if ((i == 0) && (Str::get_at(C->text, i) == '-') &&
|
|
(Str::get_at(C->text, i+1) == '-') &&
|
|
((Str::get_at(C->text, i+2) == ' ') || (Str::get_at(C->text, i+2) == 0))) {
|
|
WRITE("—"); i++;
|
|
} else if ((Str::get_at(C->text, i) == ' ') && (Str::get_at(C->text, i+1) == '-') &&
|
|
(Str::get_at(C->text, i+2) == '-') &&
|
|
((Str::get_at(C->text, i+3) == ' ') [[| (Str::get_at(C->text, i+3) == '\n') |]]
|
|
(Str::get_at(C->text, i+3) == 0))) {
|
|
WRITE(" —"); i+=2;
|
|
} else PUT(Str::get_at(C->text, i));
|
|
}
|
|
if (C->in_code) HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
|
|
<<Render carousel slide>>=
|
|
weave_carousel_slide_node *C = RETRIEVE_POINTER_weave_carousel_slide_node(N->content);
|
|
Swarm::ensure_plugin(hrs->wv, I"Carousel");
|
|
TEMPORARY_TEXT(carousel_id)
|
|
TEMPORARY_TEXT(carousel_dots_id)
|
|
text_stream *caption_class = NULL;
|
|
text_stream *slide_count_class = I"carousel-number";
|
|
switch (C->caption_command) {
|
|
case CAROUSEL_CMD: caption_class = I"carousel-caption"; break;
|
|
case CAROUSEL_ABOVE_CMD: caption_class = I"carousel-caption-above";
|
|
slide_count_class = I"carousel-number-above"; break;
|
|
case CAROUSEL_BELOW_CMD: caption_class = I"carousel-caption-below";
|
|
slide_count_class = I"carousel-number-below"; break;
|
|
}
|
|
WRITE_TO(carousel_id, "carousel-no-%d", hrs->carousel_number);
|
|
WRITE_TO(carousel_dots_id, "carousel-dots-no-%d", hrs->carousel_number);
|
|
if (hrs->slide_number == -1) {
|
|
hrs->slide_number = 1;
|
|
hrs->slide_of = 0;
|
|
for (tree_node *X = N; (X) && (X->type == N->type); X = X->next) hrs->slide_of++;
|
|
} else {
|
|
hrs->slide_number++;
|
|
if (hrs->slide_number > hrs->slide_of) internal_error("miscounted slides");
|
|
}
|
|
if (hrs->slide_number == 1) {
|
|
WRITE("<div class=\"carousel-container\" id=\"%S\">\n", carousel_id);
|
|
}
|
|
WRITE("<div class=\"carousel-slide fading-slide\"");
|
|
if (hrs->slide_number == 1) WRITE(" style=\"display: block;\"");
|
|
else WRITE(" style=\"display: none;\"");
|
|
WRITE(">\n");
|
|
if (C->caption_command == CAROUSEL_ABOVE_CMD) {
|
|
<<Place caption here>>;
|
|
WRITE("<div class=\"%S\">%d / %d</div>\n",
|
|
slide_count_class, hrs->slide_number, hrs->slide_of);
|
|
} else {
|
|
WRITE("<div class=\"%S\">%d / %d</div>\n",
|
|
slide_count_class, hrs->slide_number, hrs->slide_of);
|
|
}
|
|
WRITE("<div class=\"carousel-content\">");
|
|
<<Recurse the renderer through children nodes>>;
|
|
WRITE("</div>\n");
|
|
if (C->caption_command != CAROUSEL_ABOVE_CMD) <<Place caption here>>;
|
|
WRITE("</div>\n");
|
|
if (hrs->slide_number == hrs->slide_of) {
|
|
WRITE("<a class=\"carousel-prev-button\" ");
|
|
WRITE("onclick=\"carouselMoveSlide("%S", "%S", -1)\"",
|
|
carousel_id, carousel_dots_id);
|
|
WRITE(">❮</a>\n");
|
|
WRITE("<a class=\"carousel-next-button\" ");
|
|
WRITE("onclick=\"carouselMoveSlide("%S", "%S", 1)\"",
|
|
carousel_id, carousel_dots_id);
|
|
WRITE(">❯</a>\n");
|
|
WRITE("</div>\n");
|
|
WRITE("<div class=\"carousel-dots-container\" id=\"%S\">\n", carousel_dots_id);
|
|
for (int i=1; i<=hrs->slide_of; i++) {
|
|
if (i == 1)
|
|
WRITE("<span class=\"carousel-dot carousel-dot-active\" ");
|
|
else
|
|
WRITE("<span class=\"carousel-dot\" ");
|
|
WRITE("onclick=\"carouselSetSlide("%S", "%S", %d)\"",
|
|
carousel_id, carousel_dots_id, i-1);
|
|
WRITE("></span>\n");
|
|
}
|
|
WRITE("</div>\n");
|
|
hrs->slide_number = -1;
|
|
hrs->slide_of = -1;
|
|
hrs->carousel_number++;
|
|
}
|
|
DISCARD_TEXT(carousel_id)
|
|
DISCARD_TEXT(carousel_dots_id)
|
|
return FALSE;
|
|
|
|
<<Place caption here>>=
|
|
if (C->caption_command != CAROUSEL_UNCAPTIONED_CMD)
|
|
WRITE("<div class=\"%S\">%S</div>\n", caption_class, C->caption);
|
|
|
|
<<Render toc>>=
|
|
HTML_OPEN_WITH("ul", "class=\"toc\"");
|
|
for (tree_node *M = N->child; M; M = M->next) {
|
|
HTML_OPEN("li");
|
|
Trees::traverse_from(M, &HTMLFormat::render_visit, (void *) hrs, L+1);
|
|
HTML_CLOSE("li");
|
|
}
|
|
HTML_CLOSE("ul");
|
|
HTML::hr(OUT, "tocbar");
|
|
WRITE("\n");
|
|
return FALSE;
|
|
|
|
<<Render toc line>>=
|
|
weave_toc_line_node *C = RETRIEVE_POINTER_weave_toc_line_node(N->content);
|
|
TEMPORARY_TEXT(TEMP)
|
|
Colonies::paragraph_URL(TEMP, C->para, hrs->wv->weave_to);
|
|
HTML::begin_link(OUT, TEMP);
|
|
DISCARD_TEXT(TEMP)
|
|
WRITE("%s%S", (Str::get_first_char(C->para->ornament) == 'S')?"§":"¶",
|
|
C->para->paragraph_number);
|
|
WRITE(". %S", C->text2);
|
|
HTML::end_link(OUT);
|
|
|
|
<<Render defn>>=
|
|
weave_defn_node *C = RETRIEVE_POINTER_weave_defn_node(N->content);
|
|
HTML_OPEN_WITH("span", "class=\"definition-keyword\"");
|
|
WRITE("%S", C->keyword);
|
|
HTML_CLOSE("span");
|
|
WRITE(" ");
|
|
|
|
<<Render source code>>=
|
|
weave_source_code_node *C = RETRIEVE_POINTER_weave_source_code_node(N->content);
|
|
int starts = FALSE;
|
|
if (N == N->parent->child) starts = TRUE;
|
|
int current_colour = -1, colour_wanted = PLAIN_COLOUR;
|
|
for (int i=0; i < Str::len(C->matter); i++) {
|
|
colour_wanted = Str::get_at(C->colouring, i);
|
|
if (colour_wanted != current_colour) {
|
|
if (current_colour >= 0) HTML_CLOSE("span");
|
|
HTMLFormat::change_colour(OUT, colour_wanted, hrs->colours);
|
|
current_colour = colour_wanted;
|
|
}
|
|
if (Str::get_at(C->matter, i) == '<') WRITE("<");
|
|
else if (Str::get_at(C->matter, i) == '>') WRITE(">");
|
|
else if (Str::get_at(C->matter, i) == '&') WRITE("&");
|
|
else WRITE("%c", Str::get_at(C->matter, i));
|
|
}
|
|
if (current_colour >= 0) HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
|
|
<<Render URL>>=
|
|
weave_url_node *C = RETRIEVE_POINTER_weave_url_node(N->content);
|
|
HTML::begin_link_with_class(OUT, (C->external)?I"external":I"internal", C->url);
|
|
WRITE("%S", C->content);
|
|
HTML::end_link(OUT);
|
|
|
|
<<Render footnote cue>>=
|
|
weave_footnote_cue_node *C = RETRIEVE_POINTER_weave_footnote_cue_node(N->content);
|
|
text_stream *fn_plugin_name = hrs->wv->pattern->footnotes_plugin;
|
|
if (Str::len(fn_plugin_name) > 0)
|
|
Swarm::ensure_plugin(hrs->wv, fn_plugin_name);
|
|
if (hrs->EPUB_flag) {
|
|
if (N->parent->type != weave_begin_footnote_text_node_type)
|
|
WRITE("<a id=\"fnref%S\"></a>", C->cue_text);
|
|
WRITE("<sup><a href=\"#fn%S\" rel=\"footnote\">%S</a></sup>",
|
|
C->cue_text, C->cue_text);
|
|
} else
|
|
WRITE("<sup id=\"fnref:%S\"><a href=\"#fn:%S\" rel=\"footnote\">%S</a></sup>",
|
|
C->cue_text, C->cue_text, C->cue_text);
|
|
|
|
<<Render footnote>>=
|
|
weave_begin_footnote_text_node *C =
|
|
RETRIEVE_POINTER_weave_begin_footnote_text_node(N->content);
|
|
text_stream *fn_plugin_name = hrs->wv->pattern->footnotes_plugin;
|
|
if ((Str::len(fn_plugin_name) > 0) && (hrs->EPUB_flag == FALSE))
|
|
Swarm::ensure_plugin(hrs->wv, fn_plugin_name);
|
|
if (hrs->EPUB_flag)
|
|
WRITE("<li class=\"footnote\" id=\"fn%S\"><p class=\"inwebfootnote\">",
|
|
C->cue_text);
|
|
else
|
|
WRITE("<li class=\"footnote\" id=\"fn:%S\"><p class=\"inwebfootnote\">",
|
|
C->cue_text);
|
|
<<Recurse the renderer through children nodes>>;
|
|
if (hrs->EPUB_flag)
|
|
WRITE("<a href=\"#fnref%S\"> (return to text)</a></p></li>",
|
|
C->cue_text);
|
|
else
|
|
WRITE("<a href=\"#fnref:%S\" title=\"return to text\"> ↩</a></p></li>",
|
|
C->cue_text);
|
|
return FALSE;
|
|
|
|
<<Render display line>>=
|
|
weave_display_line_node *C =
|
|
RETRIEVE_POINTER_weave_display_line_node(N->content);
|
|
HTML_OPEN("blockquote"); WRITE("\n"); INDENT;
|
|
HTML_OPEN("p");
|
|
HTMLFormat::escape_text(OUT, C->text);
|
|
HTML_CLOSE("p");
|
|
OUTDENT; HTML_CLOSE("blockquote"); WRITE("\n");
|
|
|
|
<<Render function defn>>=
|
|
weave_function_defn_node *C =
|
|
RETRIEVE_POINTER_weave_function_defn_node(N->content);
|
|
if ((Functions::used_elsewhere(C->fn)) && (hrs->EPUB_flag == FALSE)) {
|
|
Swarm::ensure_plugin(hrs->wv, I"Popups");
|
|
HTMLFormat::change_colour(OUT, FUNCTION_COLOUR, hrs->colours);
|
|
WRITE("%S", C->fn->function_name);
|
|
WRITE("</span>");
|
|
WRITE("<button class=\"popup\" onclick=\"togglePopup('usagePopup%d')\">",
|
|
hrs->popup_counter);
|
|
HTMLFormat::change_colour(OUT, COMMENT_COLOUR, hrs->colours);
|
|
WRITE("?");
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
WRITE("<span class=\"popuptext\" id=\"usagePopup%d\">Usage of ", hrs->popup_counter);
|
|
HTML_OPEN_WITH("span", "class=\"code-font\"");
|
|
HTMLFormat::change_colour(OUT, FUNCTION_COLOUR, hrs->colours);
|
|
WRITE("%S", C->fn->function_name);
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
HTML_CLOSE("span");
|
|
WRITE(":<br/>");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
WRITE("</button>");
|
|
hrs->popup_counter++;
|
|
} else {
|
|
HTMLFormat::change_colour(OUT, FUNCTION_COLOUR, hrs->colours);
|
|
WRITE("%S", C->fn->function_name);
|
|
HTMLFormat::change_colour(OUT, -1, hrs->colours);
|
|
}
|
|
return FALSE;
|
|
|
|
<<Render item>>=
|
|
weave_item_node *C = RETRIEVE_POINTER_weave_item_node(N->content);
|
|
if (Str::eq(C->label, I"*")) WRITE("● ");
|
|
else if (Str::len(C->label) > 0) WRITE("(%S) ", C->label);
|
|
else WRITE(" ");
|
|
|
|
<<Render verbatim>>=
|
|
weave_verbatim_node *C = RETRIEVE_POINTER_weave_verbatim_node(N->content);
|
|
WRITE("%S", C->content);
|
|
|
|
<<Render inline>>=
|
|
HTML_OPEN_WITH("span", "class=\"extract\"");
|
|
<<Recurse the renderer through children nodes>>;
|
|
HTML_CLOSE("span");
|
|
return FALSE;
|
|
|
|
<<Render locale>>=
|
|
weave_locale_node *C = RETRIEVE_POINTER_weave_locale_node(N->content);
|
|
TEMPORARY_TEXT(TEMP)
|
|
Colonies::paragraph_URL(TEMP, C->par1, hrs->wv->weave_to);
|
|
HTML::begin_link(OUT, TEMP);
|
|
DISCARD_TEXT(TEMP)
|
|
WRITE("%s%S",
|
|
(Str::get_first_char(C->par1->ornament) == 'S')?"§":"¶",
|
|
C->par1->paragraph_number);
|
|
if (C->par2) WRITE("-%S", C->par2->paragraph_number);
|
|
HTML::end_link(OUT);
|
|
|
|
<<Render maths>>=
|
|
weave_maths_node *C = RETRIEVE_POINTER_weave_maths_node(N->content);
|
|
text_stream *plugin_name = hrs->wv->pattern->mathematics_plugin;
|
|
if ((Str::len(plugin_name) == 0) || (hrs->EPUB_flag)) {
|
|
TEMPORARY_TEXT(R)
|
|
TeXUtilities::remove_math_mode(R, C->content);
|
|
HTMLFormat::escape_text(OUT, R);
|
|
DISCARD_TEXT(R)
|
|
} else {
|
|
Swarm::ensure_plugin(hrs->wv, plugin_name);
|
|
if (C->displayed) WRITE("$$"); else WRITE("\\(");
|
|
HTMLFormat::escape_text(OUT, C->content);
|
|
if (C->displayed) WRITE("$$"); else WRITE("\\)");
|
|
}
|
|
|
|
<<Render linebreak>>=
|
|
WRITE("<br/>");
|
|
|
|
<<Render nothing>>=
|
|
;
|
|
|
|
<<Recurse the renderer through children nodes>>=
|
|
for (tree_node *M = N->child; M; M = M->next)
|
|
Trees::traverse_from(M, &HTMLFormat::render_visit, (void *) hrs, L+1);
|
|
|
|
@ These are the nodes falling under a commentary material node which we will
|
|
amalgamate into a single HTML paragraph:
|
|
|
|
<<*>>=
|
|
int HTMLFormat::interior_material(tree_node *N) {
|
|
if (N->type == weave_commentary_node_type) return TRUE;
|
|
if (N->type == weave_url_node_type) return TRUE;
|
|
if (N->type == weave_inline_node_type) return TRUE;
|
|
if (N->type == weave_locale_node_type) return TRUE;
|
|
if (N->type == weave_maths_node_type) return TRUE;
|
|
if (N->type == weave_footnote_cue_node_type) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
@ Depth 1 means "inside a list entry"; depth 2, "inside an entry of a list
|
|
which is itself inside a list entry"; and so on.
|
|
|
|
<<*>>=
|
|
void HTMLFormat::go_to_depth(HTML_render_state *hrs, int from_depth, int to_depth) {
|
|
text_stream *OUT = hrs->OUT;
|
|
if (from_depth == to_depth) {
|
|
HTML_CLOSE("li");
|
|
} else {
|
|
while (from_depth < to_depth) {
|
|
HTML_OPEN_WITH("ul", "class=\"items\""); from_depth++;
|
|
}
|
|
while (from_depth > to_depth) {
|
|
HTML_CLOSE("li");
|
|
HTML_CLOSE("ul");
|
|
WRITE("\n"); from_depth--;
|
|
}
|
|
}
|
|
if (to_depth > 0) HTML_OPEN("li");
|
|
}
|
|
|
|
<<*>>=
|
|
void HTMLFormat::paragraph_number(text_stream *OUT, paragraph *P) {
|
|
TEMPORARY_TEXT(TEMP)
|
|
Colonies::paragraph_anchor(TEMP, P);
|
|
HTML::anchor_with_class(OUT, TEMP, I"paragraph-anchor");
|
|
DISCARD_TEXT(TEMP)
|
|
if (P->invisible == FALSE) {
|
|
HTML_OPEN("b");
|
|
WRITE("%s%S", (Str::get_first_char(P->ornament) == 'S')?"§":"¶",
|
|
P->paragraph_number);
|
|
WRITE(". %S%s ", P->heading_text, (Str::len(P->heading_text) > 0)?".":"");
|
|
HTML_CLOSE("b");
|
|
}
|
|
}
|
|
|
|
<<*>>=
|
|
void HTMLFormat::change_colour(text_stream *OUT, int col, colour_scheme *cs) {
|
|
if (col == -1) {
|
|
HTML_CLOSE("span");
|
|
} else {
|
|
char *cl = "plain";
|
|
switch (col) {
|
|
case DEFINITION_COLOUR: cl = "definition-syntax"; break;
|
|
case FUNCTION_COLOUR: cl = "function-syntax"; break;
|
|
case IDENTIFIER_COLOUR: cl = "identifier-syntax"; break;
|
|
case ELEMENT_COLOUR: cl = "element-syntax"; break;
|
|
case RESERVED_COLOUR: cl = "reserved-syntax"; break;
|
|
case STRING_COLOUR: cl = "string-syntax"; break;
|
|
case CHARACTER_COLOUR: cl = "character-syntax"; break;
|
|
case CONSTANT_COLOUR: cl = "constant-syntax"; break;
|
|
case PLAIN_COLOUR: cl = "plain-syntax"; break;
|
|
case EXTRACT_COLOUR: cl = "extract-syntax"; break;
|
|
case COMMENT_COLOUR: cl = "comment-syntax"; break;
|
|
default: PRINT("col: %d\n", col); internal_error("bad colour"); break;
|
|
}
|
|
HTML_OPEN_WITH("span", "class=\"%S%s\"", cs->prefix, cl);
|
|
}
|
|
}
|
|
|
|
<<*>>=
|
|
void HTMLFormat::escape_text(text_stream *OUT, text_stream *id) {
|
|
for (int i=0; i < Str::len(id); i++) {
|
|
if (Str::get_at(id, i) == '&') WRITE("&");
|
|
else if (Str::get_at(id, i) == '<') WRITE("<");
|
|
else if (Str::get_at(id, i) == '>') WRITE(">");
|
|
else PUT(Str::get_at(id, i));
|
|
}
|
|
}
|
|
|
|
@ \section{EPUB-only methods.}
|
|
|
|
<<*>>=
|
|
int HTMLFormat::begin_weaving_EPUB(weave_format *wf, web *W, weave_pattern *pattern) {
|
|
TEMPORARY_TEXT(T)
|
|
WRITE_TO(T, "%S", Bibliographic::get_datum(W->md, I"Title"));
|
|
W->as_ebook = Epub::new(T, "P");
|
|
filename *CSS = Patterns::find_file_in_subdirectory(pattern, I"Base", I"Base.css");
|
|
Epub::use_CSS_throughout(W->as_ebook, CSS);
|
|
Epub::attach_metadata(W->as_ebook, L"identifier", T);
|
|
DISCARD_TEXT(T)
|
|
|
|
pathname *P = Reader::woven_folder(W);
|
|
W->redirect_weaves_to = Epub::begin_construction(W->as_ebook, P, NULL);
|
|
Shell::copy(CSS, W->redirect_weaves_to, "");
|
|
return SWARM_SECTIONS_SWM;
|
|
}
|
|
|
|
void HTMLFormat::end_weaving_EPUB(weave_format *wf, web *W, weave_pattern *pattern) {
|
|
Epub::end_construction(W->as_ebook);
|
|
}
|