MODULE; IMPORT Filter, Font, HTML, HTMLVBT, Text, TextEditVBT, TextPort, TextPortButton, TextPortWithButtons, VBT; CONST FontName = "-*-fixed-bold-r-semicondensed-*-*-120-*-*-*-*-iso8859-1"; IndentAmount = 4; REVEAL T = Public BRANDED OBJECT title: TEXT; OVERRIDES init := Init; hotlink := HotLink; END; TYPE URLButton = TextPortButton.T OBJECT v: T; url: TEXT; OVERRIDES callback := URLButtonCallback; END; PROCEDURE HTMLVBTText Init (v: T; html: HTML.T): T = VAR tp := NEW(TextPortWithButtons.T).init(readOnly := FALSE); te := NEW(TextEditVBT.T); BEGIN WalkHTML(v, html, tp); tp.setFont(Font.FromName(ARRAY OF TEXT{FontName})); te.tp := tp; EVAL TextEditVBT.T.init(te); EVAL HTMLVBT.T.init(v, html); EVAL Filter.Replace(v, te); RETURN v END Init; PROCEDUREHotLink (<* UNUSED *> self: T; <* UNUSED *> url: TEXT; <* UNUSED *> READONLY cd: VBT.MouseRec) = BEGIN END HotLink; PROCEDUREURLButtonCallback (button: URLButton; READONLY cd: VBT.MouseRec) = BEGIN button.v.hotlink (button.url, cd) END URLButtonCallback; TYPE WalkInfo = RECORD v: T; insert: BOOLEAN; (* If TRUE, insert into tp, else return the text. *) indent: INTEGER; lastChar: CHAR; tp: TextPortWithButtons.T; END; PROCEDUREWalkHTML (v: T; html: HTML.T; tp: TextPort.T) = VAR info := NEW(REF WalkInfo, v := v, insert := FALSE, indent := 0, tp := tp); BEGIN info.insert := TRUE; IF html.body # NIL THEN EVAL WalkSequence(html.body, info); END; END WalkHTML; PROCEDUREConsume (info: REF WalkInfo; text: TEXT): TEXT = BEGIN IF info.insert AND NOT Text.Empty(text) THEN IF info.lastChar # '\n' OR NOT Text.Equal(text, "\n") THEN TextPort.Insert(info.tp, text); info.lastChar := Text.GetChar(text, Text.Length(text) - 1); END; RETURN ""; ELSE RETURN text; END; END Consume; PROCEDUREWalkSequence (seq: HTML.Sequence; info: REF WalkInfo): TEXT = VAR this : TEXT; returnVal := ""; BEGIN WHILE seq # NIL DO this := ""; TYPECASE seq OF | NULL => RETURN ""; | HTML.Word (word) => this := Consume(info, word.word); | HTML.Paragraph => this := Consume(info, "\n\n" & Spaces(info.indent)); | HTML.LineBreak => this := Consume(info, "\n" & Spaces(info.indent)); | HTML.HorizontalRule => this := Consume(info, "\n-----------------------------------------------------------------\n") & Spaces(info.indent); | HTML.Glossary (glossary) => this := WalkGlossary(glossary, info); | HTML.List (list) => this := WalkList(list, info); | HTML.Preformatted (pre) => this := WalkSequence(pre.content, info); | HTML.Typewriter (format) => this := WalkSequence(format.content, info); | HTML.Boldface (format) => this := WalkSequence(format.content, info); | HTML.Italic (format) => this := WalkSequence(format.content, info); | HTML.Underline (format) => this := WalkSequence(format.content, info); | HTML.Emphasis (format) => this := WalkSequence(format.content, info); | HTML.Strong (format) => this := WalkSequence(format.content, info); | HTML.Code (format) => this := WalkSequence(format.content, info); | HTML.Sample (format) => this := WalkSequence(format.content, info); | HTML.Keyboard (format) => this := WalkSequence(format.content, info); | HTML.Definition (format) => this := WalkSequence(format.content, info); | HTML.Variable (format) => this := WalkSequence(format.content, info); | HTML.Citation (format) => this := WalkSequence(format.content, info); | HTML.Anchor (anchor) => this := WalkAnchor(anchor, info); | HTML.Heading (heading) => this := WalkHeading(heading, info); | HTML.Address (addr) => this := Consume(info, "\n") & WalkSequence(addr.content, info) & Consume(info, "\n"); | HTML.BlockQuote (quote) => INC(info.indent, IndentAmount); this := Consume(info, "\n" & Spaces(info.indent)) & WalkSequence(quote.content, info) & Consume(info, "\n"); DEC(info.indent, IndentAmount); | HTML.Image (image) => VAR alt := image.alternate; BEGIN IF alt = NIL THEN alt := "<<IMAGE>>" END; this := Consume(info, alt); END; | HTML.Oblet (oblet) => this := Consume(info, "\n\nThis view cannot display oblets; sorry. [" & oblet.source & "]\n\n"); ELSE this := Consume(info, "????"); END; returnVal := returnVal & this; IF (ISTYPE(seq, HTML.Word) OR ISTYPE(seq,HTML.Image)) AND seq.next # NIL AND (ISTYPE(seq.next, HTML.Word) OR ISTYPE(seq.next, HTML.Image)) THEN returnVal := returnVal & Consume(info, " ") END; seq := seq.next; END; (* WHILE *) RETURN returnVal; END WalkSequence; PROCEDURESpaces (num: INTEGER): TEXT = CONST Indent0 = ""; Indent4 = " "; Indent8 = Indent4 & Indent4; Indent12 = Indent8 & Indent4; Indent16 = Indent12 & Indent4; VAR this := ""; BEGIN IF num = 0 THEN RETURN Indent0 ELSIF num = 4 THEN RETURN Indent4 ELSIF num = 8 THEN RETURN Indent8 ELSIF num = 12 THEN RETURN Indent12 ELSIF num = 16 THEN RETURN Indent16 END; FOR i := 1 TO num DO this := this & " "; END; RETURN this; END Spaces; PROCEDUREWalkHeading (heading: HTML.Heading; info: REF WalkInfo): TEXT = VAR nl: TEXT; BEGIN IF Text.Empty(TextPort.GetText(info.tp)) THEN nl := "" ELSE nl := "\n" END; CASE heading.level OF | 1 => RETURN Consume(info, nl & nl & "** ") & WalkSequence(heading.content, info) & Consume(info, " **\n\n"); | 2 => RETURN Consume(info, nl & nl & "* ") & WalkSequence(heading.content, info) & Consume(info, " *\n"); | 3 => RETURN Consume(info, nl & nl) & WalkSequence(heading.content, info) & Consume(info, "\n"); | 4 .. 6 => RETURN Consume(info, nl) & WalkSequence(heading.content, info) & Consume(info, "\n"); ELSE (*Error*) RETURN ""; END; END WalkHeading; PROCEDUREWalkAnchor (anchor: HTML.Anchor; info: REF WalkInfo): TEXT = VAR button := NEW(URLButton); BEGIN button.v := info.v; button.url := "Bogus default URL"; IF anchor.href = NIL THEN (* Probably a NAME anchor -- ignore it. *) RETURN WalkSequence(anchor.content, info); ELSE VAR pos := Text.FindChar(anchor.href, '#', 0); href := anchor.href; BEGIN IF pos # -1 THEN (* Pointer to a NAME anchor. *) IF pos = 0 THEN RETURN WalkSequence(anchor.content, info); (* '#' is first char. *) ELSE href := Text.Sub(href, 0, pos); (* Kill off what's after the '#'. *) END; END; info.insert := FALSE; button.label := WalkSequence(anchor.content, info); info.insert := TRUE; button.url := href; button.v := info.v; info.tp.insertButton(button); (* Add button to tp. *) RETURN ""; END; END; END WalkAnchor; PROCEDUREWalkGlossary (glossary: HTML.Glossary; info : REF WalkInfo ): TEXT = VAR this := Consume(info, "\n" & Spaces(info.indent)); gs := glossary.content; BEGIN WHILE gs # NIL DO this := this & WalkSequence(gs.term, info) & Consume(info, "\n" & Spaces(info.indent)); INC(info.indent, IndentAmount); this := this & WalkSequence(gs.definition, info); DEC(info.indent, IndentAmount); gs := gs.next; END; RETURN this; END WalkGlossary; PROCEDUREWalkList (list: HTML.List; info: REF WalkInfo): TEXT = VAR this := ""; item := list.content; BEGIN INC(info.indent, IndentAmount); WHILE item # NIL DO this := this & Consume(info, "\n" & Spaces(info.indent)) & WalkSequence(item.content, info); item := item.next; END; DEC(info.indent, IndentAmount); RETURN this; END WalkList; BEGIN END HTMLVBTText.