Last active
June 5, 2022 11:14
-
-
Save deton/2d11d1ff1cb5e2a8ded9fef6af6f6266 to your computer and use it in GitHub Desktop.
Lynx patch to add H1-H6 headings link list to List Page
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/GridText.c b/src/GridText.c | |
| index d9a1665..b3c41e0 100644 | |
| --- a/src/GridText.c | |
| +++ b/src/GridText.c | |
| @@ -6257,6 +6257,34 @@ HTChildAnchor *HText_childNextNumber(int number, void **prev) | |
| return a->anchor; | |
| } | |
| +#ifdef EXP_HEADINGLIST | |
| +/* returns not only HREF anchor which has number | |
| + * but also NAME or ID attribute anchor */ | |
| +HTChildAnchor *HText_childNext(void **prev) | |
| +{ | |
| + TextAnchor *a = (TextAnchor *) *prev; | |
| + | |
| + if (!HTMainText) | |
| + return (HTChildAnchor *) 0; /* Fail */ | |
| + if (!a) | |
| + a = HTMainText->first_anchor; | |
| + else | |
| + a = a->next; | |
| + | |
| + for (; a != 0; a = a->next) { | |
| + if (a->number > 0) /* HREF anchor */ | |
| + break; | |
| + if (a->anchor && a->anchor->tag) /* NAME or ID attribute anchor */ | |
| + break; | |
| + } | |
| + | |
| + if (!a) | |
| + return (HTChildAnchor *) 0; /* Fail */ | |
| + *prev = (void *) a; | |
| + return a->anchor; | |
| +} | |
| +#endif /* EXP_HEADINGLIST */ | |
| + | |
| /* | |
| * For the -unique-urls option, find the anchor-number of the first occurrence | |
| * of a given address. | |
| @@ -9573,6 +9601,49 @@ const char *HText_HiddenLinkAt(HText *text, int number) | |
| return (href); | |
| } | |
| +#ifdef EXP_HEADINGLIST | |
| +int HText_PoundCount(BOOL onlyLynxHeading) | |
| +{ | |
| + int count = 0; | |
| + TextAnchor *a; | |
| + | |
| + for (a = HTMainText->first_anchor; a != 0; a = a->next) { | |
| + if (a->anchor && non_empty(a->anchor->tag)) { | |
| + if (!onlyLynxHeading) | |
| + count++; | |
| + else if (isLYNXHEADING(a->anchor->tag)) | |
| + count++; | |
| + } | |
| + } | |
| + return (count); | |
| +} | |
| + | |
| +HTChildAnchor *HText_PoundNext(BOOL onlyLynxHeading, int *linenum, void **prev) | |
| +{ | |
| + TextAnchor *a = (TextAnchor *) *prev; | |
| + *linenum = 0; | |
| + | |
| + if (!HTMainText) | |
| + return (HTChildAnchor *) 0; /* Fail */ | |
| + if (!a) | |
| + a = HTMainText->first_anchor; | |
| + | |
| + for (; a != 0; a = a->next) | |
| + if (a->anchor && non_empty(a->anchor->tag)) { | |
| + if (!onlyLynxHeading) | |
| + break; | |
| + else if (isLYNXHEADING(a->anchor->tag)) | |
| + break; | |
| + } | |
| + | |
| + if (!a) | |
| + return (HTChildAnchor *) 0; /* Fail */ | |
| + *prev = (void *) a->next; | |
| + *linenum = a->line_num; | |
| + return a->anchor; | |
| +} | |
| +#endif /* EXP_HEADINGLIST */ | |
| + | |
| /* | |
| * Form methods | |
| * These routines are used to build forms consisting | |
| diff --git a/src/GridText.h b/src/GridText.h | |
| index 40b17b1..c53925f 100644 | |
| --- a/src/GridText.h | |
| +++ b/src/GridText.h | |
| @@ -183,6 +183,11 @@ US-ASCII control characters <32 which are not defined in Unicode standard | |
| extern void HText_setNodeAnchorBookmark(const char *bookmark); | |
| extern void HText_setTabID(HText *text, const char *name); | |
| extern void *HText_pool_calloc(HText *text, unsigned size); | |
| +#ifdef EXP_HEADINGLIST | |
| + extern HTChildAnchor *HText_childNext(void **prev); | |
| + extern int HText_PoundCount(BOOL onlyLynxHeading); | |
| + extern HTChildAnchor *HText_PoundNext(BOOL onlyLynxHeading, int *linenum, void **prev); | |
| +#endif | |
| /* "simple table" stuff */ | |
| extern BOOLEAN HText_endStblTABLE(HText *); | |
| diff --git a/src/HTML.c b/src/HTML.c | |
| index 3ab8373..04c9b8a 100644 | |
| --- a/src/HTML.c | |
| +++ b/src/HTML.c | |
| @@ -1835,6 +1839,9 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
| me->inP = FALSE; | |
| } | |
| CHECK_ID(HTML_H_ID); | |
| +#ifdef EXP_HEADINGLIST | |
| + LYAddHeadingID(me, ElementNumber); | |
| +#endif | |
| break; | |
| } | |
| @@ -1862,6 +1869,9 @@ static int HTML_start_element(HTStructured * me, int element_number, | |
| } | |
| UPDATE_STYLE; | |
| CHECK_ID(HTML_H_ID); | |
| +#ifdef EXP_HEADINGLIST | |
| + LYAddHeadingID(me, ElementNumber); | |
| +#endif | |
| if ((bold_headers == TRUE || | |
| (ElementNumber == HTML_H1 && bold_H1 == TRUE)) && | |
| @@ -7583,6 +7593,9 @@ HTStructured *HTML_new(HTParentAnchor *anchor, | |
| me->CurrentANum = 0; | |
| me->base_href = NULL; | |
| me->map_address = NULL; | |
| +#ifdef EXP_HEADINGLIST | |
| + me->nextHeadingSeqNum = 0; | |
| +#endif | |
| HTChunkInit(&me->title, 128); | |
| diff --git a/src/HTML.h b/src/HTML.h | |
| index 9f5d1d5..0fcd1c8 100644 | |
| --- a/src/HTML.h | |
| +++ b/src/HTML.h | |
| @@ -75,6 +75,9 @@ extern "C" { | |
| int CurrentANum; /* current HTML_A number */ | |
| char *base_href; /* current HTML_BASE href */ | |
| char *map_address; /* current HTML_MAP address */ | |
| +#ifdef EXP_HEADINGLIST | |
| + int nextHeadingSeqNum; /* next HTML_H# sequence number */ | |
| +#endif | |
| HTChunk title; /* Grow by 128 */ | |
| HTChunk object; /* Grow by 128 */ | |
| diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c | |
| index 03b2e81..8461ff7 100644 | |
| --- a/src/LYCharUtils.c | |
| +++ b/src/LYCharUtils.c | |
| @@ -3135,6 +3135,32 @@ void LYHandleID(HTStructured * me, const char *id) | |
| } | |
| } | |
| +#ifdef EXP_HEADINGLIST | |
| +void LYAddHeadingID(HTStructured * me, int element_number) | |
| +{ | |
| + HTChildAnchor *ID_A = NULL; | |
| + char *id = 0; | |
| + | |
| + if (!(me && me->text)) | |
| + return; | |
| + | |
| + HTSprintf0(&id, "%s%d_H%d", STR_LYNXHEADING, me->nextHeadingSeqNum, | |
| + element_number - HTML_H1 + 1); | |
| + me->nextHeadingSeqNum++; | |
| + | |
| + if ((ID_A = HTAnchor_findChildAndLink | |
| + ( | |
| + me->node_anchor, /* Parent */ | |
| + id, /* Tag */ | |
| + NULL, /* Address */ | |
| + (HTLinkType *) 0)) != NULL) { /* Type */ | |
| + HText_beginAnchor(me->text, me->inUnderline, ID_A); | |
| + HText_endAnchor(me->text, 0); | |
| + } | |
| + FREE(id); | |
| +} | |
| +#endif /* EXP_HEADINGLIST */ | |
| + | |
| /* | |
| * This function checks whether we want to override | |
| * the current default alignment for paragraphs and | |
| diff --git a/src/LYCharUtils.h b/src/LYCharUtils.h | |
| index 2b9ca88..8ffc4f8 100644 | |
| --- a/src/LYCharUtils.h | |
| +++ b/src/LYCharUtils.h | |
| @@ -92,6 +92,9 @@ extern "C" { | |
| STRING2PTR value, | |
| int attribute); | |
| extern void LYHandleID(HTStructured * me, const char *id); | |
| +#ifdef EXP_HEADINGLIST | |
| + extern void LYAddHeadingID(HTStructured * me, int element_number); | |
| +#endif | |
| extern BOOLEAN LYoverride_default_alignment(HTStructured * me); | |
| extern void LYEnsureDoubleSpace(HTStructured * me); | |
| extern void LYEnsureSingleSpace(HTStructured * me); | |
| diff --git a/src/LYList.c b/src/LYList.c | |
| index 989b6a3..dc0a1bf 100644 | |
| --- a/src/LYList.c | |
| +++ b/src/LYList.c | |
| @@ -44,6 +44,9 @@ int showlist(DocInfo *newdoc, int titles) | |
| { | |
| int cnt; | |
| int refs, hidden_links; | |
| +#ifdef EXP_HEADINGLIST | |
| + int pounds; | |
| +#endif | |
| int result; | |
| static char tempfile[LY_MAXPATH]; | |
| static BOOLEAN last_titles = TRUE; | |
| @@ -56,12 +59,23 @@ int showlist(DocInfo *newdoc, int titles) | |
| refs = HText_sourceAnchors(HTMainText); | |
| hidden_links = HText_HiddenLinkCount(HTMainText); | |
| +#ifdef EXP_HEADINGLIST | |
| + pounds = HText_PoundCount(TRUE); | |
| +#endif | |
| if (refs <= 0 && hidden_links > 0 && | |
| - LYHiddenLinks != HIDDENLINKS_SEPARATE) { | |
| + LYHiddenLinks != HIDDENLINKS_SEPARATE | |
| +#ifdef EXP_HEADINGLIST | |
| + && pounds <= 0 | |
| +#endif | |
| + ) { | |
| HTUserMsg(NO_VISIBLE_REFS_FROM_DOC); | |
| return (-1); | |
| } | |
| - if (refs <= 0 && hidden_links <= 0) { | |
| + if (refs <= 0 && hidden_links <= 0 | |
| +#ifdef EXP_HEADINGLIST | |
| + && pounds <= 0 | |
| +#endif | |
| + ) { | |
| HTUserMsg(NO_REFS_FROM_DOC); | |
| return (-1); | |
| } | |
| @@ -91,10 +105,18 @@ int showlist(DocInfo *newdoc, int titles) | |
| ? Address | |
| : gettext("this document:"))); | |
| FREE(Address); | |
| +#ifdef EXP_HEADINGLIST | |
| + if (pounds) | |
| + fprintf(fp0, "<a href='#headings'>#%s</a><p>\n", gettext("H1-H6")); | |
| +#endif | |
| if (refs > 0) { | |
| fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? | |
| "ol" : "ul")); | |
| - if (hidden_links > 0) | |
| + if (hidden_links > 0 | |
| +#ifdef EXP_HEADINGLIST | |
| + || pounds > 0 | |
| +#endif | |
| + ) | |
| fprintf(fp0, "<lh><em>%s</em>\n", gettext("Visible links:")); | |
| } | |
| if (hidden_links > 0) { | |
| @@ -103,8 +125,13 @@ int showlist(DocInfo *newdoc, int titles) | |
| } | |
| helper = NULL; /* init */ | |
| result = 1; | |
| +#ifdef EXP_HEADINGLIST | |
| + for (cnt = 0; cnt < refs; ) { | |
| + HTChildAnchor *child = HText_childNext(&helper); | |
| +#else | |
| for (cnt = 1; cnt <= refs; cnt++) { | |
| HTChildAnchor *child = HText_childNextNumber(cnt, &helper); | |
| +#endif | |
| int value = HText_findAnchorNumber(helper); | |
| HTAnchor *dest_intl = NULL; | |
| HTAnchor *dest; | |
| @@ -112,6 +139,24 @@ int showlist(DocInfo *newdoc, int titles) | |
| char *address; | |
| const char *title; | |
| +#ifdef EXP_HEADINGLIST | |
| + if (child != 0 && value == 0) { | |
| + if (isLYNXHEADING(child->tag)) { | |
| + Address = HTAnchor_address((HTAnchor *) child); | |
| + LYEntify(&Address, TRUE); | |
| + fprintf(fp0, "<%s compact>", | |
| + ((keypad_mode == NUMBERS_AS_ARROWS) ? "ol" : "ul")); | |
| + fprintf(fp0, | |
| + "<li><a href=\"%s\" TYPE=\"internal link\">#%s</a>", | |
| + Address, child->tag); | |
| + fprintf(fp0, "</%s>\n", | |
| + ((keypad_mode == NUMBERS_AS_ARROWS) ? "ol" : "ul")); | |
| + FREE(Address); | |
| + } | |
| + continue; | |
| + } | |
| + ++cnt; | |
| +#endif | |
| if (child == 0) { | |
| /* | |
| * child should not be 0 unless form field numbering is on and cnt | |
| @@ -214,6 +259,30 @@ int showlist(DocInfo *newdoc, int titles) | |
| FREE(Address); | |
| } | |
| +#ifdef EXP_HEADINGLIST | |
| + if (pounds > 0) { | |
| + if (refs > 0 || hidden_links > 0) | |
| + fprintf(fp0, "\n</%s>\n\n<p>\n", | |
| + ((keypad_mode == NUMBERS_AS_ARROWS) ? | |
| + "ol" : "ul")); | |
| + fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? | |
| + "ol continue" : "ul")); | |
| + fprintf(fp0, "<lh id=\"headings\"><em>%s</em>\n", gettext("H1-H6:")); | |
| + } | |
| + | |
| + helper = NULL; /* init */ | |
| + for (cnt = 0; cnt < pounds; cnt++) { | |
| + int linenum = 0; | |
| + HTChildAnchor *child = HText_PoundNext(TRUE, &linenum, &helper); | |
| + Address = HTAnchor_address((HTAnchor *) child); | |
| + LYEntify(&Address, TRUE); | |
| + fprintf(fp0, | |
| + "<li><a href=\"%s\" TYPE=\"internal link\">#%s</a> (line %d)\n", | |
| + Address, child->tag, linenum); | |
| + FREE(Address); | |
| + } | |
| +#endif /* EXP_HEADINGLIST */ | |
| + | |
| fprintf(fp0, "\n</%s>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ? | |
| "ol" : "ul")); | |
| EndInternalPage(fp0); | |
| diff --git a/src/LYUtils.h b/src/LYUtils.h | |
| index d15a816..8ae3749 100644 | |
| --- a/src/LYUtils.h | |
| +++ b/src/LYUtils.h | |
| @@ -532,6 +532,13 @@ extern "C" { | |
| !strncasecomp(addr, STR_LYNXPROG, LEN_LYNXPROG)) | |
| #define LYNXOPTIONS_PAGE(s) STR_LYNXOPTIONS s | |
| + | |
| +/* internal fragment identifiers after '#' */ | |
| +#ifdef EXP_HEADINGLIST | |
| +#define STR_LYNXHEADING ":~:LYNXHEADING_" | |
| +#define LEN_LYNXHEADING 15 | |
| +#define isLYNXHEADING(tag) !strncasecomp(tag, STR_LYNXHEADING, LEN_LYNXHEADING) | |
| +#endif | |
| /* | |
| * For change_sug_filename(). | |
| */ | |
| diff --git a/userdefs.h b/userdefs.h | |
| index 4fe7937..b3d2fcb 100644 | |
| --- a/userdefs.h | |
| +++ b/userdefs.h | |
| @@ -1684,6 +1684,11 @@ | |
| */ | |
| #define EXP_PPRE | |
| +/************************** | |
| + * Add H1-H6 heading links to ADDRLIST and LIST pages | |
| + */ | |
| +#define EXP_HEADINGLIST | |
| + | |
| /**************************************************************** | |
| * Section 4. Things you MUST check only if you plan to use Lynx | |
| * in an anonymous account (allow public access to Lynx). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment