MODULE HTMLTransformer;
IMPORT
WebBrowserComponents, XMLTransformer,
Strings, XML, XMLObjects, DynamicStrings, UTF8Strings, WMGraphics, KernelLog, WMEvents, WMCharCodes,
WMComponents, WMRectangles, WMTextView, TextUtilities, Texts, WMStandardComponents,
WMMessages, Streams, WMEditors, WMPopups, Messages := WMMessages;
CONST
verbose = TRUE;
defSerif = "TimesNewRoman";
defSansSerif = "Arial";
defCursive = "ComicSansMS";
defFantasy = "Arial";
defMonospace = "CourierNew";
defaultFont = "Oberon";
cText = 0;
cNewLine = 1;
cParagraph = 2;
alignLeft = 0;
alignCenter = 1;
alignRight = 2;
alignJustify = 3;
VAR
serif : ARRAY 64 OF CHAR;
sansSerif : ARRAY 64 OF CHAR;
cursive : ARRAY 64 OF CHAR;
fantasy : ARRAY 64 OF CHAR;
monospace : ARRAY 64 OF CHAR;
TYPE
String = Strings.String;
VisualComponent = WMComponents.VisualComponent;
CharsetConvProc = PROCEDURE {DELEGATE} (VAR input : ARRAY OF CHAR) : String;
TextStyle = RECORD
font : String;
size : LONGINT;
style : LONGINT;
color : LONGINT;
bgcolorPresent : BOOLEAN;
bgcolor : LONGINT;
link : String;
linktarget : String;
shift : LONGINT;
align : LONGINT;
indent : LONGINT;
enumtype : LONGINT;
preformatted : BOOLEAN;
form : Form;
END;
OLULStackItem=POINTER TO RECORD
prev : OLULStackItem;
value : LONGINT;
END;
EmbeddedObject*=POINTER TO RECORD
prev* : EmbeddedObject;
object* : VisualComponent;
END;
Transformer* = OBJECT
VAR
doc: XML.Container;
url : String;
baseAddress : String;
baseTarget : String;
sequencer : WMMessages.MsgSequencer;
initWidth : LONGINT;
loadLink* : WMEvents.EventListener;
charset : String;
frameName : String;
txtElem: XML.Element;
paragraph : XML.Element;
title-: String;
pageBgColor- : LONGINT;
bgImage- : String;
embeddedObjectsList- : EmbeddedObject;
textColor : LONGINT;
linkColor : LONGINT;
vlinkColor : LONGINT;
alinkColor : LONGINT;
crlfStr : String;
crlfDoubleStr : String;
charsetConv : CharsetConvProc;
currentText : LONGINT;
olulStackTop : OLULStackItem;
ulDepth : LONGINT;
inDL : BOOLEAN;
currentAlign : LONGINT;
currentIndent : LONGINT;
form : Form;
formButton : FormButton;
formCheckbox : FormCheckbox;
formTextInput : FormTextInput;
formRadioButton : FormRadioButton;
formMenu : FormMenu;
formHiddenControl : FormHiddenControl;
initAlignment : LONGINT;
isTableContent : BOOLEAN;
PROCEDURE &Init*(doc: XML.Container; url : String; initWidth : LONGINT; loadLink : WMEvents.EventListener; charset : String; frameName : String);
VAR
crlf : ARRAY 5 OF CHAR;
BEGIN
SELF.doc := doc;
SELF.url := url;
SELF.baseAddress := url;
SELF.initWidth := initWidth;
SELF.loadLink := loadLink;
crlf[0] := 0DX; crlf[1] := 0AX; crlf[2] := 0X;
crlfStr := Strings.NewString(crlf);
crlf[2] := 0DX; crlf[3] := 0AX; crlf[4] := 0X;
crlfDoubleStr := Strings.NewString(crlf);
IF charset # NIL THEN
charsetConv := GetCharsetConverter(charset^);
SELF.charset := charset;
ELSE
charsetConv := GetCharsetConverter("iso8859-1");
SELF.charset := Strings.NewString("iso8859-1");
END;
SELF.frameName := frameName;
textColor := 0000000H;
linkColor := 00000EEH;
vlinkColor := 0551A8BH;
alinkColor := 0EE0000H;
pageBgColor := 0FFFFFFH;
currentText := cParagraph;
ulDepth := 0;
inDL := FALSE;
initAlignment := alignLeft;
END Init;
PROCEDURE Transform*() : XML.Document;
VAR
bbtTxt: XML.Document;
xmlDecl: XML.XMLDecl;
pi: XML.ProcessingInstruction;
s: String;
style : TextStyle;
BEGIN
NEW(bbtTxt);
NEW(xmlDecl);
s := Strings.NewString("1.0");
xmlDecl.SetVersion(s^);
s := Strings.NewString("UTF-8");
xmlDecl.SetEncoding(s^);
bbtTxt.AddContent(xmlDecl);
NEW(pi);
s := Strings.NewString("bluebottle format");
pi.SetTarget(s^);
s := Strings.NewString('version="0.1"');
pi.SetInstruction(s^);
bbtTxt.AddContent(pi);
NEW(pi);
s := Strings.NewString('xml-stylesheet type="text/xsl"');
pi.SetTarget(s^);
s := Strings.NewString('href="http://bluebottle.ethz.ch/bluebottle.xsl"');
pi.SetInstruction(s^);
bbtTxt.AddContent(pi);
NEW(txtElem);
s := Strings.NewString("Text");
txtElem.SetName(s^);
bbtTxt.AddContent(txtElem);
style.font := Strings.NewString(serif);
style.size := 3;
style.style := 0;
style.color := textColor;
style.bgcolorPresent := FALSE;
style.shift := 0;
style.align := initAlignment;
style.indent := 0;
style.enumtype := 0;
style.preformatted := FALSE;
style.form := form;
currentAlign := -1;
currentIndent := -1;
SetAlignmentAndIndent(style.align, style.indent);
TransformContent(doc, style);
RETURN bbtTxt;
END Transform;
PROCEDURE TransformContent(container : XML.Container; style : TextStyle);
VAR
enum: XMLObjects.Enumerator;
p : ANY;
BEGIN
enum := container.GetContents();
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
IF p IS XML.Element THEN
TransformElement(p(XML.Element), style);
ELSIF (p IS XML.ArrayChars) & ~(p IS XML.Comment) THEN
AddText(p(XML.ArrayChars).GetStr(), style);
END;
END;
END TransformContent;
PROCEDURE GetText(container : XML.Container) : String;
VAR
enum: XMLObjects.Enumerator;
p : ANY;
text, s : String;
BEGIN
text := Strings.NewString("");
enum := container.GetContents();
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
IF (p IS XML.ArrayChars) & ~(p IS XML.Comment) THEN
s := p(XML.ArrayChars).GetStr();
text := Strings.ConcatToNew(text^, s^);
END;
END;
RETURN text;
END GetText;
PROCEDURE TransformElement(elem : XML.Element; style : TextStyle);
VAR
name, s, s2, s3 : String;
enum: XMLObjects.Enumerator;
p : ANY;
i, j, res : LONGINT;
exitLoop : BOOLEAN;
aoc : ARRAY 16 OF CHAR;
olulStackItem : OLULStackItem;
b : BOOLEAN;
oldForm : Form;
PROCEDURE ul;
BEGIN
IF olulStackTop = NIL THEN
NewParagraph(FALSE);
ELSE
NewLine(FALSE);
END;
INC(style.indent);
INC(ulDepth);
s := GetElemAttributeValue(elem, "type", TRUE);
IF s#NIL THEN
IF s^="square" THEN
style.enumtype := 1;
ELSIF s^="circle" THEN
style.enumtype := 2;
ELSE
style.enumtype := 0;
END;
ELSE
IF ulDepth = 2 THEN
style.enumtype := 2;
ELSIF ulDepth >= 3 THEN
style.enumtype := 1;
ELSE
style.enumtype := 0;
END;
END;
NEW(olulStackItem);
olulStackItem.prev := olulStackTop;
olulStackTop := olulStackItem;
olulStackItem.value := 1;
TransformContent(elem, style);
olulStackTop := olulStackTop.prev;
DEC(ulDepth);
IF olulStackTop = NIL THEN
NewParagraph(FALSE);
ELSE
NewLine(FALSE);
END;
END ul;
PROCEDURE textInput(isPassword : BOOLEAN);
BEGIN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("") END;
s3 := GetElemAttributeValue(elem, "size", FALSE);
IF s3 # NIL THEN
Strings.StrToInt(s3^, i);
ELSE
i := 20
END;
s3 := GetElemAttributeValue(elem, "maxlength", FALSE);
IF s3 # NIL THEN
Strings.StrToInt(s3^, j);
ELSE
j := 0
END;
NEW(formTextInput, s, s2, i, j, isPassword);
style.form.AddFormComponent(formTextInput);
AddVisualComponent(formTextInput.editor, style);
END textInput;
BEGIN
name := elem.GetName();
IF name^="A" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
IF s#NIL THEN
AddLabel(s);
END;
s := GetElemAttributeValue(elem, "href", FALSE);
IF s#NIL THEN
style.color := linkColor;
Strings.TrimWS(s^);
style.link := ResolveAddress(baseAddress, s);
s := GetElemAttributeValue(elem, "target", FALSE);
IF s#NIL THEN
Strings.TrimWS(s^);
style.linktarget := s;
ELSIF baseTarget # NIL THEN
style.linktarget := baseTarget;
ELSE
style.linktarget := frameName;
END;
END;
TransformContent(elem, style);
ELSIF name^="ABBR" THEN
TransformContent(elem, style);
ELSIF name^="ACRONYM" THEN
TransformContent(elem, style);
ELSIF name^="ADDRESS" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
NewLine(FALSE);
ELSIF name^="APPLET" THEN
TransformContent(elem, style);
ELSIF name^="AREA" THEN
TransformContent(elem, style);
ELSIF name^="B" THEN
IF style.style = 0 THEN
style.style := 1;
ELSIF style.style = 2 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="BASE" THEN
s := GetElemAttributeValue(elem, "href", FALSE);
IF s#NIL THEN
baseAddress := s;
END;
baseTarget := GetElemAttributeValue(elem, "target", FALSE);
ELSIF name^="BASEFONT" THEN
TransformContent(elem, style);
ELSIF name^="BDO" THEN
TransformContent(elem, style);
ELSIF name^="BIG" THEN
IF style.size < 7 THEN INC(style.size); END;
TransformContent(elem, style);
ELSIF name^="BLOCKQUOTE" THEN
NewParagraph(FALSE);
INC(style.indent);
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="BODY" THEN
s := GetElemAttributeValue(elem, "bgcolor", TRUE);
IF s#NIL THEN pageBgColor := GetColor(s); END;
s := GetElemAttributeValue(elem, "text", TRUE);
IF s#NIL THEN
textColor := GetColor(s);
style.color := textColor;
END;
s := GetElemAttributeValue(elem, "link", TRUE);
IF s#NIL THEN linkColor := GetColor(s); END;
s := GetElemAttributeValue(elem, "vlink", TRUE);
IF s#NIL THEN vlinkColor := GetColor(s); END;
s := GetElemAttributeValue(elem, "alink", TRUE);
IF s#NIL THEN alinkColor := GetColor(s); END;
s := GetElemAttributeValue(elem, "background", FALSE);
IF s#NIL THEN
bgImage := ResolveAddress(baseAddress, s);
END;
TransformContent(elem, style);
ELSIF name^="BR" THEN
NewLine(TRUE);
ELSIF name^="BUTTON" THEN
TransformContent(elem, style);
ELSIF name^="CENTER" THEN
NewLine(TRUE);
style.align := alignCenter;
TransformContent(elem, style);
NewLine(TRUE);
ELSIF name^="CITE" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="CODE" THEN
style.font := Strings.NewString(monospace);
TransformContent(elem, style);
ELSIF name^="DD" THEN
INC(style.indent);
TransformContent(elem, style);
NewLine(FALSE);
ELSIF name^="DEL" THEN
TransformContent(elem, style);
ELSIF name^="DFN" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="DIR" THEN
ul();
ELSIF name^="DIV" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewLine(TRUE);
TransformContent(elem, style);
NewLine(TRUE);
ELSIF name^="DL" THEN
IF inDL THEN
INC(style.indent);
NewLine(FALSE);
ELSE
NewParagraph(FALSE);
END;
b := inDL;
inDL := TRUE;
TransformContent(elem, style);
IF b THEN
NewLine(FALSE);
ELSE
NewParagraph(FALSE);
END;
inDL := b;
ELSIF name^="DT" THEN
TransformContent(elem, style);
NewLine(FALSE);
ELSIF name^="EM" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="FIELDSET" THEN
TransformContent(elem, style);
ELSIF name^="FONT" THEN
s := GetElemAttributeValue(elem, "size", FALSE);
IF s#NIL THEN
Strings.Copy(s^, 0, LEN(s^)-1, aoc);
Strings.TrimLeft(aoc, ' ');
Strings.StrToInt(aoc, res);
IF (aoc[0]='+') OR (aoc[0]='-') THEN
style.size := style.size + res;
ELSE
style.size := res;
END;
IF style.size < 1 THEN
style.size := 1;
ELSIF style.size > 7 THEN
style.size := 7;
END;
END;
s := GetElemAttributeValue(elem, "color", TRUE);
IF s#NIL THEN style.color := GetColor(s); END;
s := GetElemAttributeValue(elem, "face", FALSE);
IF s#NIL THEN style.font := GetExistingFontName(s); END;
TransformContent(elem, style);
ELSIF name^="FORM" THEN
oldForm := style.form;
s := GetElemAttributeValue(elem, "action", FALSE);
IF s = NIL THEN
s := baseAddress;
ELSE
s := ResolveAddress(baseAddress, s);
END;
NEW(style.form, s, loadLink);
TransformContent(elem, style);
style.form := oldForm;
ELSIF name^="H1" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 6;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="H2" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 5;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="H3" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 4;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="H4" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 3;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="H5" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 2;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="H6" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
style.size := 1;
style.style := 1;
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="HEAD" THEN
TransformContent(elem, style);
ELSIF name^="HR" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSE
style.align := alignCenter;
END;
ELSE
style.align := alignCenter;
END;
NewLine(FALSE);
AddHR(style.align);
NewLine(FALSE);
ELSIF name^="HTML" THEN
TransformContent(elem, style);
ELSIF name^="I" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="IFRAME" THEN
TransformContent(elem, style);
ELSIF name^="IMG" THEN
i := -1; j := -1;
s := GetElemAttributeValue(elem, "width", FALSE);
IF s#NIL THEN
Strings.Copy(s^, 0, LEN(s^)-1, aoc);
Strings.StrToInt(aoc, i);
END;
s := GetElemAttributeValue(elem, "height", FALSE);
IF s#NIL THEN
Strings.Copy(s^, 0, LEN(s^)-1, aoc);
Strings.StrToInt(aoc, j);
END;
s := GetElemAttributeValue(elem, "src", FALSE);
IF s#NIL THEN
s := ResolveAddress(baseAddress, s);
AddImage(s, i, j, style);
END;
ELSIF name^="INPUT" THEN
IF style.form # NIL THEN
s := GetElemAttributeValue(elem, "type", TRUE);
IF s#NIL THEN
IF s^="checkbox" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("on") END;
s3 := GetElemAttributeValue(elem, "checked", FALSE);
b := FALSE;
IF s3 # NIL THEN
b := TRUE;
Strings.TrimWS(s^);
IF s3^ = "no" THEN
b := FALSE;
END;
END;
NEW(formCheckbox, s, s2, b);
AddText(Strings.NewString(" "), style); AddText(Strings.NewString(" "), style); AddText(Strings.NewString(" "), style);
style.form.AddFormComponent(formCheckbox);
AddVisualComponent(formCheckbox.checkbox, style);
AddText(Strings.NewString(" "), style);
ELSIF s^="radio" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
IF s = NIL THEN s := Strings.NewString("radioButton") END;
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("on") END;
s3 := GetElemAttributeValue(elem, "checked", FALSE);
b := FALSE;
IF s3 # NIL THEN
b := TRUE;
Strings.TrimWS(s^);
IF s3^ = "no" THEN
b := FALSE;
END;
END;
NEW(formRadioButton, s, s2, b);
style.form.AddRadioButton(formRadioButton);
AddText(Strings.NewString(" "), style); AddText(Strings.NewString(" "), style); AddText(Strings.NewString(" "), style);
AddVisualComponent(formRadioButton.radioButton, style);
AddText(Strings.NewString(" "), style);
ELSIF s^="submit" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("Submit Query") END;
NEW(formButton, s, s2, style.form.Send);
style.form.AddFormComponent(formButton);
AddVisualComponent(formButton.button, style);
AddText(Strings.NewString(" "), style);
ELSIF s^="reset" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("Reset") END;
NEW(formButton, s, s2, style.form.Reset);
style.form.AddFormComponent(formButton);
AddVisualComponent(formButton.button, style);
AddText(Strings.NewString(" "), style);
ELSIF s^="file" THEN
ELSIF s^="hidden" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("") END;
NEW(formHiddenControl, s, s2);
style.form.AddFormComponent(formHiddenControl);
ELSIF s^="image" THEN
ELSIF s^="button" THEN
s := GetElemAttributeValue(elem, "name", FALSE);
s2 := GetElemAttributeValue(elem, "value", FALSE);
IF s2 = NIL THEN s2 := Strings.NewString("") END;
NEW(formButton, s, s2, NIL);
style.form.AddFormComponent(formButton);
AddVisualComponent(formButton.button, style);
AddText(Strings.NewString(" "), style);
ELSIF s^="password" THEN
textInput(TRUE);
ELSE
textInput(FALSE);
END;
ELSE
textInput(FALSE);
END;
END;
ELSIF name^="INS" THEN
TransformContent(elem, style);
ELSIF name^="ISINDEX" THEN
TransformContent(elem, style);
ELSIF name^="KBD" THEN
style.font := Strings.NewString(monospace);
TransformContent(elem, style);
ELSIF name^="LABEL" THEN
TransformContent(elem, style);
ELSIF name^="LEGEND" THEN
TransformContent(elem, style);
ELSIF name^="LI" THEN
NewLine(FALSE);
IF olulStackTop#NIL THEN
s := GetElemAttributeValue(elem, "value", FALSE);
IF s#NIL THEN
Strings.StrToInt(s^, olulStackTop.value);
END;
END;
i := style.enumtype;
s := GetElemAttributeValue(elem, "type", FALSE);
IF s#NIL THEN
IF s^="square" THEN
i := 1;
ELSIF s^="circle" THEN
i := 2;
ELSE
i := 0;
END;
END;
CASE i OF
| 1 : s := Strings.NewString("□ ");
| 2 : s := Strings.NewString("○ ");
| 3 : IF olulStackTop#NIL THEN
Strings.IntToStr(olulStackTop.value, aoc);
j :=Strings.Length(aoc);
IF (j+2) <= (LEN(aoc)-1) THEN
aoc[j]:='.'; aoc[j+1]:=' '; aoc[j+2]:=0X;
END;
ELSE
aoc := "0. ";
END;
s := Strings.NewString(aoc);
| 4 : IF olulStackTop#NIL THEN
s := IntToABCString(olulStackTop.value, FALSE);
ELSE
s := Strings.NewString("0. ");
END;
| 5 : IF olulStackTop#NIL THEN
s := IntToABCString(olulStackTop.value, TRUE);
ELSE
s := Strings.NewString("0. ");
END;
| 6 : IF olulStackTop#NIL THEN
s := IntToRomanString(olulStackTop.value, FALSE);
ELSE
s := Strings.NewString("0. ");
END;
| 7 : IF olulStackTop#NIL THEN
s := IntToRomanString(olulStackTop.value, TRUE);
ELSE
s := Strings.NewString("0. ");
END;
ELSE
s := Strings.NewString("● ");
END;
AddText(s, style);
IF olulStackTop#NIL THEN INC(olulStackTop.value); END;
TransformContent(elem, style);
NewLine(FALSE);
ELSIF name^="LINK" THEN
ELSIF name^="MAP" THEN
TransformContent(elem, style);
ELSIF name^="MENU" THEN
ul();
ELSIF name^="META" THEN
s := GetElemAttributeValue(elem, "content", TRUE);
IF s#NIL THEN
i := Strings.Pos("charset", s^);
IF i # -1 THEN
i := Strings.IndexOfByte('=', i+7, s^) + 1;
IF i < Strings.Length(s^) THEN
s := Strings.Substring2(i, s^);
charsetConv := GetCharsetConverter(s^);
charset := s;
END;
END;
END;
ELSIF name^="NOSCRIPT" THEN
TransformContent(elem, style);
ELSIF name^="OBJECT" THEN
TransformContent(elem, style);
ELSIF name^="OL" THEN
IF olulStackTop = NIL THEN
NewParagraph(FALSE);
ELSE
NewLine(FALSE);
END;
INC(style.indent);
s := GetElemAttributeValue(elem, "type", FALSE);
IF s#NIL THEN
IF s^="a" THEN
style.enumtype := 4;
ELSIF s^="A" THEN
style.enumtype := 5;
ELSIF s^="i" THEN
style.enumtype := 6;
ELSIF s^="I" THEN
style.enumtype := 7;
ELSE
style.enumtype := 3;
END;
ELSE
style.enumtype := 3;
END;
NEW(olulStackItem);
olulStackItem.prev := olulStackTop;
olulStackTop := olulStackItem;
s := GetElemAttributeValue(elem, "start", FALSE);
IF s#NIL THEN
Strings.StrToInt(s^, olulStackItem.value);
ELSE
olulStackItem.value := 1;
END;
TransformContent(elem, style);
olulStackTop := olulStackTop.prev;
IF olulStackTop = NIL THEN
NewParagraph(FALSE);
ELSE
NewLine(FALSE);
END;
ELSIF name^="OPTGROUP" THEN
TransformContent(elem, style);
ELSIF name^="OPTION" THEN
IF formMenu # NIL THEN
s := GetElemAttributeValue(elem, "value", FALSE);
s2 := GetElemAttributeValue(elem, "label", FALSE);
IF s2 = NIL THEN
s2 := GetText(elem);
END;
s3 := GetElemAttributeValue(elem, "selected", FALSE);
formMenu.NewItem(s, s2, s3 # NIL);
END;
ELSIF name^="P" THEN
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
style.align := alignLeft;
ELSIF s^ = "center" THEN
style.align := alignCenter;
ELSIF s^ = "right" THEN
style.align := alignRight;
ELSIF s^ = "justify" THEN
style.align := alignJustify;
END;
END;
NewParagraph(FALSE);
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="PARAM" THEN
TransformContent(elem, style);
ELSIF name^="PRE" THEN
NewParagraph(FALSE);
style.preformatted := TRUE;
style.font := Strings.NewString(monospace);
TransformContent(elem, style);
NewParagraph(FALSE);
ELSIF name^="Q" THEN
AddText(Strings.NewString('"'), style);
TransformContent(elem, style);
AddText(Strings.NewString('"'), style);
ELSIF name^="S" THEN
TransformContent(elem, style);
ELSIF name^="SAMP" THEN
style.font := Strings.NewString(monospace);
TransformContent(elem, style);
ELSIF name^="SCRIPT" THEN
ELSIF name^="SELECT" THEN
IF style.form # NIL THEN
s := GetElemAttributeValue(elem, "name", FALSE);
IF s = NIL THEN s := Strings.NewString("defaultMenu") END;
NEW(formMenu, s);
style.form.AddFormComponent(formMenu);
AddVisualComponent(formMenu.button, style);
AddText(Strings.NewString(" "), style);
TransformContent(elem, style);
formMenu := NIL;
END;
ELSIF name^="SMALL" THEN
IF style.size > 1 THEN DEC(style.size); END;
TransformContent(elem, style);
ELSIF name^="SPAN" THEN
TransformContent(elem, style);
ELSIF name^="STRIKE" THEN
TransformContent(elem, style);
ELSIF name^="STRONG" THEN
IF style.style = 0 THEN
style.style := 1;
ELSIF style.style = 2 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF name^="STYLE" THEN
ELSIF name^="SUB" THEN
IF style.shift = 0 THEN style.shift := 1; END;
IF style.size >1 THEN DEC(style.size); END;
TransformContent(elem, style);
ELSIF name^="SUP" THEN
IF style.shift = 0 THEN style.shift := -1; END;
IF style.size >1 THEN DEC(style.size); END;
TransformContent(elem, style);
ELSIF name^="SVG" THEN
AddSVG(elem, style);
ELSIF name^="TABLE" THEN
AddTable(elem, style);
ELSIF name^="TEXTAREA" THEN
TransformContent(elem, style);
ELSIF name^="TITLE" THEN
IF title = NIL THEN
exitLoop := FALSE;
enum := elem.GetContents();
WHILE enum.HasMoreElements() & ~exitLoop DO
p := enum.GetNext();
IF p IS XML.ArrayChars THEN
title := p(XML.ArrayChars).GetStr();
title := ReplaceWhiteSpaces(title);
title := charsetConv(title^);
title := TransformCharEnt(title);
exitLoop := TRUE;
END;
END;
END;
ELSIF name^="TT" THEN
style.font := Strings.NewString(monospace);
TransformContent(elem, style);
ELSIF name^="U" THEN
TransformContent(elem, style);
ELSIF name^="UL" THEN
ul();
ELSIF name^="VAR" THEN
IF style.style = 0 THEN
style.style := 2;
ELSIF style.style = 1 THEN
style.style := 3;
END;
TransformContent(elem, style);
ELSIF Strings.StartsWith2("BB:", name^) THEN
XMLTransformer.AddContentsOf(XMLTransformer.Transform(elem), txtElem);
currentAlign := -1;
currentIndent := -1;
SetAlignmentAndIndent(style.align, style.indent);
ELSE
TransformContent(elem, style);
END;
END TransformElement;
PROCEDURE SetAlignmentAndIndent(align : LONGINT; indent : LONGINT);
VAR
styleAttrPar : XML.Attribute;
s : String;
aoc : ARRAY 5 OF CHAR;
BEGIN
IF (align # currentAlign) OR (indent # currentIndent) THEN
NEW(paragraph);
paragraph.SetName("Paragraph");
NEW(styleAttrPar); s := Strings.NewString("style"); styleAttrPar.SetName(s^);
IF align = alignCenter THEN
s := Strings.NewString("AdHoc 1 ");
ELSIF align = alignRight THEN
s := Strings.NewString("AdHoc 2 ");
ELSIF align = alignJustify THEN
s := Strings.NewString("AdHoc 3 ");
ELSE
s := Strings.NewString("AdHoc 0 ");
END;
IF indent > 0 THEN
Strings.IntToStr(indent * 40, aoc);
Strings.TrimWS(aoc);
s := Strings.ConcatToNew(s^, aoc);
s := Strings.ConcatToNew(s^, " ");
Strings.IntToStr(indent * 40 + 20, aoc);
Strings.TrimWS(aoc);
s := Strings.ConcatToNew(s^, aoc);
s := Strings.ConcatToNew(s^, " 0 0 0");
ELSE
s := Strings.ConcatToNew(s^, "0 0 0 0 0");
END;
styleAttrPar.SetValue(s^);
paragraph.AddAttribute(styleAttrPar);
txtElem.AddContent(paragraph);
currentAlign := align;
currentIndent := indent;
END;
END SetAlignmentAndIndent;
PROCEDURE NewLine(allowMultiple : BOOLEAN);
VAR
span : XML.Element;
styleAttr : XML.Attribute;
cdata : XML.CDataSect;
aoc : ARRAY 39 OF CHAR;
BEGIN
IF (currentText = cNewLine) & ~allowMultiple THEN RETURN; END;
currentText := cNewLine;
NEW(span); span.SetName("Span");
aoc := "style";
NEW(styleAttr); styleAttr.SetName(aoc);
aoc := "AdHoc Oberon 12 0 0 00000000 00000000";
styleAttr.SetValue(aoc);
NEW(cdata);
cdata.SetStr(crlfStr^);
span.AddAttribute(styleAttr);
span.AddContent(cdata);
paragraph.AddContent(span);
END NewLine;
PROCEDURE NewParagraph(allowMultiple : BOOLEAN);
VAR
span : XML.Element;
styleAttr : XML.Attribute;
cdata : XML.CDataSect;
aoc : ARRAY 39 OF CHAR;
BEGIN
IF (currentText = cParagraph) & ~allowMultiple THEN RETURN; END;
NEW(cdata);
IF (currentText = cNewLine) THEN
cdata.SetStr(crlfStr^);
ELSE
cdata.SetStr(crlfDoubleStr^);
END;
currentText := cParagraph;
NEW(span); span.SetName("Span");
aoc := "style";
NEW(styleAttr); styleAttr.SetName(aoc);
aoc := "AdHoc Oberon 16 0 0 00000000 00000000";
styleAttr.SetValue(aoc);
span.AddAttribute(styleAttr);
span.AddContent(cdata);
paragraph.AddContent(span);
END NewParagraph;
PROCEDURE AddText(txt : String; style : TextStyle);
VAR
fontsize : LONGINT;
baselineshift : LONGINT;
span : XML.Element;
s : String;
aoc : ARRAY 33 OF CHAR;
styleAttr : XML.Attribute;
linkAttr : XML.Attribute;
cdata : XML.CDataSect;
dyn : DynamicStrings.DynamicString;
BEGIN
SetAlignmentAndIndent(style.align, style.indent);
IF ~style.preformatted THEN
IF StringHasNewLine(txt^) & StringIsWhiteSpace(txt^) THEN RETURN; END;
txt := ReplaceWhiteSpaces(txt);
END;
txt := charsetConv(txt^);
txt := TransformCharEnt(txt);
fontsize := MapFontSize(style.font, style.size);
baselineshift := MapBaselineShift(style.size);
NEW(span); aoc := "Span"; span.SetName(aoc);
IF style.link # NIL THEN
NEW(linkAttr); aoc := "link"; linkAttr.SetName(aoc);
span.AddAttribute(linkAttr);
s := EncodeLinkData(style.link, style.linktarget, url);
linkAttr.SetValue(s^);
END;
NEW(styleAttr); aoc := "style"; styleAttr.SetName(aoc);
NEW(dyn);
aoc := "AdHoc "; dyn.Append(aoc);
dyn.Append(style.font^);
aoc := " "; dyn.Append(aoc);
Strings.IntToStr(fontsize, aoc); dyn.Append(aoc);
aoc := " "; dyn.Append(aoc);
Strings.IntToStr(style.style, aoc); dyn.Append(aoc);
aoc := " "; dyn.Append(aoc);
IF style.shift = 1 THEN
Strings.IntToStr(baselineshift, aoc);
ELSIF style.shift = -1 THEN
Strings.IntToStr(0-baselineshift, aoc);
ELSE
aoc := "0";
END;
dyn.Append(aoc);
aoc := " "; dyn.Append(aoc);
Strings.IntToHexStr(style.color * 0100H + 0FFH, 7, aoc);
dyn.Append(aoc);
aoc := " ";
dyn.Append(aoc);
IF style.bgcolorPresent THEN
Strings.IntToHexStr(style.bgcolor * 0100H + 0FFH, 7, aoc);
ELSE
aoc := "00000000";
END;
dyn.Append(aoc);
s := dyn.ToArrOfChar();
styleAttr.SetValue(s^);
span.AddAttribute(styleAttr);
NEW(cdata);
cdata.SetStr(txt^);
span.AddContent(cdata);
paragraph.AddContent(span);
currentText := cText;
END AddText;
PROCEDURE AddImage(src : String; x : LONGINT; y : LONGINT; style : TextStyle);
VAR
object : XML.Element;
img : WebBrowserComponents.StretchImagePanel;
imgLink : WebBrowserComponents.StretchImageLinkPanel;
msg : WMTextView.LinkWrapper;
BEGIN
SetAlignmentAndIndent(style.align, style.indent);
NEW(object);
object.SetName("Object");
paragraph.AddContent(object);
IF style.link # NIL THEN
NEW(msg);
msg.link := EncodeLinkData(style.link, style.linktarget, url);
NEW(imgLink, NIL, src, x, y, loadLink, msg);
object.AddContent(imgLink);
ToEmbeddedObjectsList(imgLink);
ELSE
NEW(img, NIL, src, x, y);
object.AddContent(img);
ToEmbeddedObjectsList(img);
END;
currentText := cText;
END AddImage;
PROCEDURE AddSVG(svgRoot: XML.Element; style : TextStyle);
VAR
object : XML.Element;
svg : WebBrowserComponents.SVGPanel;
svgLink : WebBrowserComponents.SVGLinkPanel;
msg : WMTextView.LinkWrapper;
BEGIN
SetAlignmentAndIndent(style.align, style.indent);
NEW(object);
object.SetName("Object");
paragraph.AddContent(object);
IF style.link # NIL THEN
NEW(msg);
msg.link := EncodeLinkData(style.link, style.linktarget, url);
NEW(svgLink, svgRoot, loadLink, msg);
object.AddContent(svgLink);
ToEmbeddedObjectsList(svgLink);
ELSE
NEW(svg, svgRoot);
object.AddContent(svg);
ToEmbeddedObjectsList(svg);
END;
currentText := cText;
END AddSVG;
PROCEDURE ToEmbeddedObjectsList(obj : VisualComponent);
VAR
item : EmbeddedObject;
BEGIN
NEW(item);
item.object := obj;
item.prev := embeddedObjectsList;
embeddedObjectsList := item;
END ToEmbeddedObjectsList;
PROCEDURE AddHR(align : LONGINT);
VAR
object : XML.Element;
hr : WebBrowserComponents.HR;
BEGIN
SetAlignmentAndIndent(align, currentIndent);
currentText := cText;
NEW(object);
object.SetName("Object");
paragraph.AddContent(object);
NEW(hr, initWidth);
object.AddContent(hr);
ToEmbeddedObjectsList(hr);
END AddHR;
PROCEDURE AddTable(tableElem : XML.Element; style : TextStyle);
VAR
object : XML.Element;
table : Table;
BEGIN
NewLine(FALSE);
NEW(object);
object.SetName("Object");
NEW(table, tableElem, initWidth, style.align, textColor, linkColor, vlinkColor, alinkColor, url, loadLink, charset, frameName, style.form, baseAddress, baseTarget, sequencer, isTableContent);
ToEmbeddedObjectsList(table);
SetAlignmentAndIndent(style.align, style.indent);
object.AddContent(table);
paragraph.AddContent(object);
SetAlignmentAndIndent(style.align, style.indent);
NewLine(TRUE);
END AddTable;
PROCEDURE AddVisualComponent(vc : WMComponents.VisualComponent; style : TextStyle);
VAR
object : XML.Element;
BEGIN
SetAlignmentAndIndent(style.align, style.indent);
NEW(object);
object.SetName("Object");
object.AddContent(vc);
paragraph.AddContent(object);
currentText := cText;
END AddVisualComponent;
PROCEDURE AddLabel(s : String);
VAR
label : XML.Element;
nameAttr : XML.Attribute;
aoc : ARRAY 5 OF CHAR;
BEGIN
NEW(label);
label.SetName("Label");
NEW(nameAttr); aoc := "name"; nameAttr.SetName(aoc);
nameAttr.SetValue(s^);
label.AddAttribute(nameAttr);
paragraph.AddContent(label);
END AddLabel;
END Transformer;
CellSizes = POINTER TO ARRAY OF LONGINT;
StringArray = POINTER TO ARRAY OF String;
CellWrapper = POINTER TO RECORD
cell : TableCell;
END;
TableGrid = POINTER TO ARRAY OF ARRAY OF CellWrapper;
Table* = OBJECT (VisualComponent)
VAR
tableElem : XML.Element;
parentWidth : LONGINT;
align- : LONGINT;
textColor, linkColor, vlinkColor, alinkColor : LONGINT;
url : String;
loadLink : WMEvents.EventListener;
charset : String;
frameName : String;
form : Form;
baseAddress : String;
baseTarget : String;
isSubtable : BOOLEAN;
width : LONGINT;
relativeWidth : BOOLEAN;
border : LONGINT;
rules : BOOLEAN;
cellspacing : LONGINT;
relativeCellspacing : BOOLEAN;
cellpadding : LONGINT;
relativeCellpadding : BOOLEAN;
bgColor : LONGINT;
grid : TableGrid;
colsCnt : LONGINT;
rowsCnt : LONGINT;
minCellWidths, maxCellWidths : CellSizes;
minTableWidth, maxTableWidth : LONGINT;
x, y : LONGINT;
internalWidth, internalHeight : LONGINT;
PROCEDURE & New*(tableElem : XML.Element; parentWidth : LONGINT; align : LONGINT; textColor, linkColor, vlinkColor, alinkColor : LONGINT; url : String; loadLink : WMEvents.EventListener; charset : String; frameName : String; form : Form; baseAddress : String; baseTarget : String; seq : WMMessages.MsgSequencer; isSubtable : BOOLEAN);
VAR
s : String; sequencer: Messages.MsgSequencer;
BEGIN
Init;
IF seq = NIL THEN
NEW(sequencer, Handle);
SetSequencer(sequencer);
ELSE
SetSequencer(seq);
END;
SELF.tableElem := tableElem;
SELF.parentWidth := parentWidth - 20;
IF parentWidth < 1 THEN parentWidth := 1 END;
SELF.textColor := textColor;
SELF.linkColor := linkColor;
SELF.vlinkColor := vlinkColor;
SELF.alinkColor := alinkColor;
SELF.url := url;
SELF.loadLink := loadLink;
SELF.charset := charset;
SELF.frameName := frameName;
SELF.form := form;
SELF.baseAddress := baseAddress;
SELF.baseTarget := baseTarget;
SELF.isSubtable := isSubtable;
s := GetElemAttributeValue(tableElem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "left" THEN
SELF.align := alignLeft;
ELSIF s^ = "center" THEN
SELF.align := alignCenter;
ELSIF s^ = "right" THEN
SELF.align := alignRight;
ELSIF s^ = "justify" THEN
SELF.align := alignJustify;
ELSE
SELF.align := align;
END;
ELSE
SELF.align := align;
END;
s := GetElemAttributeValue(tableElem, "width", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF Strings.EndsWith("%", s^) THEN
relativeWidth := TRUE;
s := Strings.Substring(0, Strings.Length(s^)-1, s^);
END;
Strings.StrToInt(s^, width);
ELSE
width := 0;
END;
s := GetElemAttributeValue(tableElem, "border", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
Strings.StrToInt(s^, border);
ELSE
border := 0;
END;
s := GetElemAttributeValue(tableElem, "rules", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
rules := (s^ # "none");
ELSE
rules := (border > 0);
END;
s := GetElemAttributeValue(tableElem, "cellspacing", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF Strings.EndsWith("%", s^) THEN
relativeCellspacing := TRUE;
s := Strings.Substring(0, Strings.Length(s^)-1, s^);
END;
Strings.StrToInt(s^, cellspacing);
ELSE
cellspacing := 0;
END;
s := GetElemAttributeValue(tableElem, "cellpadding", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF Strings.EndsWith("%", s^) THEN
relativeCellpadding := TRUE;
s := Strings.Substring(0, Strings.Length(s^)-1, s^);
END;
Strings.StrToInt(s^, cellpadding);
ELSE
cellpadding := 0;
END;
s := GetElemAttributeValue(tableElem, "bgcolor", TRUE);
IF s # NIL THEN
fillColor.Set(GetColor(s) * 0100H + 0FFH);
END;
internalWidth := 0; internalHeight := 0;
BuildCellGrid();
CalculateMinMaxTableWidth();
IF ~isSubtable THEN AlignCells(); END;
END New;
PROCEDURE DrawBackground(canvas : WMGraphics.Canvas);
VAR
h, w, color, i : LONGINT;
BEGIN
DrawBackground^(canvas);
IF border > 0 THEN
h := bounds.GetHeight();
w := bounds.GetWidth();
color := LONGINT(0808080FFH);
FOR i := 0 TO border - 1 DO
canvas.Line(0, 0+i, w-1, 0+i, color, WMGraphics.ModeSrcOverDst);
canvas.Line(0+i, 0, 0+i, h-1, color, WMGraphics.ModeSrcOverDst);
canvas.Line(0, h-1-i, w-1, h-1-i, color, WMGraphics.ModeSrcOverDst);
canvas.Line(w-1-i, 0, w-1-i, h-1, color, WMGraphics.ModeSrcOverDst);
END;
END;
END DrawBackground;
PROCEDURE BuildCellGrid;
VAR
captionCount : LONGINT;
wantedList : StringArray;
stopList : StringArray;
wantedTDTH : StringArray;
stopAtTable : StringArray;
newRow : BOOLEAN;
enum, enum2 : XMLObjects.Enumerator;
p, p2 : ANY;
j : LONGINT;
BEGIN
NEW(wantedTDTH, 2); wantedTDTH[0] := Strings.NewString("TD"); wantedTDTH[1] := Strings.NewString("TH");
NEW(stopAtTable, 1); stopAtTable[0] := Strings.NewString("TABLE");
captionCount := 0;
NEW(wantedList, 1); wantedList[0] := Strings.NewString("CAPTION");
enum := GetElems(tableElem, wantedList, stopAtTable, FALSE);
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
AddCell(p(XML.Element), TRUE);
INC(captionCount);
END;
NEW(wantedList, 1); wantedList[0] := Strings.NewString("THEAD");
enum := GetElems(tableElem, wantedList, stopAtTable, FALSE);
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
enum2 := GetElems(p(XML.Element), wantedTDTH, stopAtTable, FALSE);
newRow := TRUE;
WHILE (enum2.HasMoreElements()) DO
p2 := enum2.GetNext();
AddCell(p2(XML.Element), newRow);
newRow := FALSE;
END;
END;
NEW(stopList, 5); stopList[0] := Strings.NewString("TABLE"); stopList[1] := Strings.NewString("THEAD"); stopList[2] := Strings.NewString("TFOOT"); stopList[3] := Strings.NewString("TR"); stopList[4] := Strings.NewString("CAPTION");
newRow := TRUE;
enum := GetElems(tableElem, wantedTDTH, stopList, FALSE);
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
AddCell(p(XML.Element), newRow);
newRow := FALSE;
END;
NEW(wantedList, 1); wantedList[0] := Strings.NewString("TR");
NEW(stopList, 4); stopList[0] := Strings.NewString("TABLE"); stopList[1] := Strings.NewString("THEAD"); stopList[2] := Strings.NewString("TFOOT"); stopList[3] := Strings.NewString("CAPTION");
enum := GetElems(tableElem, wantedList, stopList, FALSE);
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
enum2 := GetElems(p(XML.Element), wantedTDTH, stopAtTable, FALSE);
newRow := TRUE;
WHILE (enum2.HasMoreElements()) DO
p2 := enum2.GetNext();
AddCell(p2(XML.Element), newRow);
newRow := FALSE;
END;
END;
NEW(wantedList, 1); wantedList[0] := Strings.NewString("TFOOT");
newRow := TRUE;
enum := GetElems(tableElem, wantedList, stopAtTable, FALSE);
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
enum2 := GetElems(p(XML.Element), wantedTDTH, stopAtTable, FALSE);
WHILE (enum2.HasMoreElements()) DO
p2 := enum2.GetNext();
AddCell(p2(XML.Element), newRow);
newRow := FALSE;
END;
END;
FOR j := 0 TO captionCount - 1 DO
IF (grid[0, j] # NIL) & (grid[0, j].cell # NIL) THEN
grid[0, j].cell.colspan := colsCnt;
END;
END;
END BuildCellGrid;
PROCEDURE AddCell(elem : XML.Element; newRow : BOOLEAN);
VAR
tableCell : TableCell;
i, j : LONGINT;
PROCEDURE Add(x, y : LONGINT; tableCell : TableCell);
VAR
cellWrapper : CellWrapper;
BEGIN
IF y > (rowsCnt - 1) THEN
GrowY(y);
END;
WHILE (x < colsCnt) & (grid[x, y] # NIL) DO
INC(x);
END;
IF x > (colsCnt - 1) THEN
GrowX(x);
END;
NEW(cellWrapper);
cellWrapper.cell := tableCell;
grid[x, y] := cellWrapper;
END Add;
PROCEDURE GrowX(newX : LONGINT);
VAR
newInternalWidth : LONGINT;
newGrid : TableGrid;
BEGIN
IF newX > (internalWidth - 1) THEN
newInternalWidth := internalWidth;
WHILE newInternalWidth < newX + 1 DO
INC(newInternalWidth, 10);
END;
NEW(newGrid, newInternalWidth, internalHeight);
FOR i := 0 TO colsCnt - 1 DO
FOR j := 0 TO rowsCnt - 1 DO
newGrid[i, j] := grid[i, j];
END;
END;
internalWidth := newInternalWidth;
grid := newGrid;
END;
colsCnt := newX + 1;
END GrowX;
PROCEDURE GrowY(newY : LONGINT);
VAR
newInternalHeight : LONGINT;
newGrid : TableGrid;
BEGIN
IF newY > (internalHeight - 1) THEN
newInternalHeight := internalHeight;
WHILE newInternalHeight < newY + 1 DO
INC(newInternalHeight, 10);
END;
NEW(newGrid, internalWidth, newInternalHeight);
FOR i := 0 TO colsCnt - 1 DO
FOR j := 0 TO rowsCnt - 1 DO
newGrid[i, j] := grid[i, j];
END;
END;
internalHeight := newInternalHeight;
grid := newGrid;
END;
rowsCnt := newY + 1;
END GrowY;
BEGIN
IF rowsCnt = 0 THEN y := -1; newRow := TRUE END;
IF newRow THEN
x := 0;
INC(y);
ELSE
INC(x);
END;
NEW(tableCell, sequencer, SELF, elem, textColor, linkColor, vlinkColor, alinkColor, url, loadLink, charset, frameName, form, baseAddress, baseTarget);
AddContent(tableCell);
FOR i := 0 TO tableCell.colspan - 1 DO
FOR j := 0 TO tableCell.rowspan - 1 DO
IF (i = 0) & (j = 0) THEN
Add(x, y, tableCell);
ELSE
Add(x + i, y + j, NIL);
END;
END;
END;
END AddCell;
PROCEDURE CalculateMinMaxTableWidth;
VAR
i, j, k : LONGINT;
BEGIN
NEW(minCellWidths, colsCnt);
NEW(maxCellWidths, colsCnt);
FOR j := 0 TO rowsCnt - 1 DO
FOR i := 0 TO colsCnt - 1 DO
IF (grid[i, j] # NIL) & (grid[i, j].cell # NIL) THEN
k := (grid[i, j].cell.minWidth - (grid[i, j].cell.colspan - 1) * cellspacing) DIV grid[i, j].cell.colspan;
IF k > minCellWidths[i] THEN
minCellWidths[i] := k;
END;
END;
END;
END;
minTableWidth := 0;
FOR i := 0 TO colsCnt - 1 DO
INC(minTableWidth, minCellWidths[i]);
END;
INC(minTableWidth, 2 * border + (colsCnt + 1) * cellspacing);
FOR j := 0 TO rowsCnt - 1 DO
FOR i := 0 TO colsCnt - 1 DO
IF (grid[i, j] # NIL) & (grid[i, j].cell # NIL) THEN
k := (grid[i, j].cell.maxWidth - (grid[i, j].cell.colspan - 1) * cellspacing) DIV grid[i, j].cell.colspan;
IF k > maxCellWidths[i] THEN
maxCellWidths[i] := k;
END;
END;
END;
END;
maxTableWidth := 0;
FOR i := 0 TO colsCnt - 1 DO
INC(maxTableWidth, maxCellWidths[i]);
END;
INC(maxTableWidth, 2 * border + (colsCnt + 1) * cellspacing);
END CalculateMinMaxTableWidth;
PROCEDURE AlignCells;
VAR
cell : TableCell;
w, h, i, j, k : LONGINT;
W, D, d : LONGINT;
tableWidth, tableHeight : LONGINT;
targetWidth : LONGINT;
cellWidths, cellHeights : CellSizes;
fac : REAL;
leftIndent, topIndent : LONGINT;
BEGIN
NEW(cellWidths, colsCnt);
NEW(cellHeights, rowsCnt);
IF width = 0 THEN
IF maxTableWidth <= parentWidth THEN
tableWidth := maxTableWidth;
FOR i := 0 TO colsCnt - 1 DO
cellWidths[i] := maxCellWidths[i];
END;
ELSIF minTableWidth >= parentWidth THEN
tableWidth := minTableWidth;
FOR i := 0 TO colsCnt - 1 DO
cellWidths[i] := minCellWidths[i];
END;
ELSE
W := parentWidth - minTableWidth;
D := maxTableWidth - minTableWidth;
IF D < 1 THEN D := 1 END;
tableWidth := 0;
FOR i := 0 TO colsCnt - 1 DO
d := maxCellWidths[i] - minCellWidths[i];
cellWidths[i] := minCellWidths[i] + ENTIER(d * W / D);
INC(tableWidth, cellWidths[i]);
END;
INC(tableWidth, 2 * border + (colsCnt + 1) * cellspacing);
END;
ELSE
targetWidth := width;
IF relativeWidth THEN
targetWidth := ENTIER(targetWidth * parentWidth / 100);
END;
IF minTableWidth >= targetWidth THEN
tableWidth := minTableWidth;
FOR i := 0 TO colsCnt - 1 DO
cellWidths[i] := minCellWidths[i];
END;
ELSIF maxTableWidth <= targetWidth THEN
fac := targetWidth / maxTableWidth;
tableWidth := 0;
FOR i := 0 TO colsCnt - 1 DO
cellWidths[i] := ENTIER(maxCellWidths[i] * fac);
INC(tableWidth, cellWidths[i]);
END;
INC(tableWidth, 2 * border + (colsCnt + 1) * cellspacing);
ELSE
W := parentWidth - minTableWidth;
D := maxTableWidth - minTableWidth;
IF D < 1 THEN D := 1 END;
tableWidth := 0;
FOR i := 0 TO colsCnt - 1 DO
d := maxCellWidths[i] - minCellWidths[i];
cellWidths[i] := minCellWidths[i] + ENTIER(d * W / D);
INC(tableWidth, cellWidths[i]);
END;
INC(tableWidth, 2 * border + (colsCnt + 1) * cellspacing);
END;
END;
topIndent := border + cellspacing;
FOR j := 0 TO rowsCnt - 1 DO
leftIndent := border + cellspacing;
FOR i := 0 TO colsCnt - 1 DO
IF (grid[i, j] # NIL) & (grid[i, j].cell # NIL) THEN
cell := grid[i, j].cell;
IF (cell.colspan = 1) & (cell.rowspan = 1) THEN
cell.SetWidth(cellWidths[i]);
ELSE
w := 0;
FOR k := 0 TO cell.colspan - 1 DO
INC(w, cellWidths[i + k]);
END;
INC(w, (cell.colspan - 1) * cellspacing);
cell.SetWidth(w);
END;
END;
INC(leftIndent, cellWidths[i] + cellspacing);
END;
INC(topIndent, cellHeights[j] + cellspacing);
END;
FOR j := 0 TO rowsCnt - 1 DO
FOR i := 0 TO colsCnt - 1 DO
IF (grid[i, j] # NIL) & (grid[i, j].cell # NIL) THEN
cell := grid[i, j].cell;
w := 0;
FOR k := 0 TO cell.colspan - 1 DO
INC(w, cellWidths[i + k]);
END;
INC(w, (cell.colspan - 1) * cellspacing);
h := (cell.tv.GetHeight(w) + 2 * cellpadding) DIV cell.rowspan;
IF h < 1 THEN h := 1 END;
IF h < cell.height THEN h := cell.height END;
IF h > cellHeights[j] THEN
cellHeights[j] := h;
END;
END;
END;
END;
tableHeight := 0;
FOR j := 0 TO rowsCnt - 1 DO
INC(tableHeight, cellHeights[j]);
END;
INC(tableHeight, 2 * border + (rowsCnt + 1) * cellspacing);
topIndent := border + cellspacing;
FOR j := 0 TO rowsCnt - 1 DO
leftIndent := border + cellspacing;
FOR i := 0 TO colsCnt - 1 DO
IF (grid[i, j] # NIL) & (grid[i, j].cell # NIL) THEN
cell := grid[i, j].cell;
IF (cell.colspan = 1) & (cell.rowspan = 1) THEN
cell.bounds.SetHeight(cellHeights[j]);
ELSE
h := 0;
FOR k := 0 TO cell.rowspan - 1 DO
INC(h, cellHeights[j + k]);
END;
INC(h, (cell.rowspan - 1) * cellspacing);
cell.bounds.SetHeight(h);
END;
cell.bounds.SetLeft(leftIndent);
cell.bounds.SetTop(topIndent);
END;
INC(leftIndent, cellWidths[i] + cellspacing);
END;
INC(topIndent, cellHeights[j] + cellspacing);
END;
bounds.SetWidth(tableWidth);
bounds.SetHeight(tableHeight);
END AlignCells;
PROCEDURE ParentTvWidthChanged*(x : LONGINT);
BEGIN
parentWidth := x - 20;
IF parentWidth < 1 THEN parentWidth := 1 END;
AlignCells();
END ParentTvWidthChanged;
END Table;
TableCell = OBJECT (VisualComponent)
VAR
parentTable : Table;
transformer : Transformer;
tv : WMTextView.TextView;
text : Texts.Text;
minWidth, maxWidth : LONGINT;
width, height : LONGINT;
colspan, rowspan : LONGINT;
bgImage : WebBrowserComponents.TileImagePanel;
writer : Streams.Writer;
textWriter : TextUtilities.TextWriter;
PROCEDURE & New*(seq : WMMessages.MsgSequencer; parentTable : Table; elem : XML.Element; textColor, linkColor, vlinkColor, alinkColor : LONGINT; url : String; loadLink : WMEvents.EventListener; charset : String; frameName : String; form : Form; baseAddress : String; baseTarget : String);
VAR
s : String;
align : LONGINT;
xmlDoc : XML.Document;
bbtDecoder : TextUtilities.BluebottleDecoder;
rec : WMRectangles.Rectangle;
bgImageName : String;
item : EmbeddedObject;
dummy : LONGINT;
BEGIN
Init;
SetSequencer(seq);
SELF.parentTable := parentTable;
takesFocus.Set(FALSE);
s := GetElemAttributeValue(elem, "align", TRUE);
IF s # NIL THEN
Strings.TrimWS(s^);
IF s^ = "center" THEN
align := alignCenter;
ELSIF s^ = "right" THEN
align := alignRight;
ELSIF s^ = "justify" THEN
align := alignJustify;
ELSE
align := alignLeft;
END;
ELSE
align := alignLeft;
END;
s := GetElemAttributeValue(elem, "bgcolor", TRUE);
IF s = NIL THEN
s := GetElemAttributeValue(elem.GetParent(), "bgcolor", TRUE);
END;
IF s # NIL THEN
fillColor.Set(GetColor(s) * 0100H + 0FFH);
END;
s := GetElemAttributeValue(elem, "colspan", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
Strings.StrToInt(s^, colspan);
IF colspan < 1 THEN colspan := 1 END;
ELSE
colspan := 1;
END;
s := GetElemAttributeValue(elem, "rowspan", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
Strings.StrToInt(s^, rowspan);
IF rowspan < 1 THEN rowspan := 1 END;
ELSE
rowspan := 1;
END;
s := GetElemAttributeValue(elem, "width", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
Strings.StrToInt(s^, width);
END;
INC(width, 2 * colspan * parentTable.cellpadding + (colspan - 1) * parentTable.cellspacing);
s := GetElemAttributeValue(elem, "height", FALSE);
IF s # NIL THEN
Strings.TrimWS(s^);
Strings.StrToInt(s^, height);
END;
INC(height, 2 * rowspan * parentTable.cellpadding + (rowspan - 1) * parentTable.cellspacing);
s := GetElemAttributeValue(elem, "background", FALSE);
IF s#NIL THEN
bgImageName := ResolveAddress(baseAddress, s);
NEW(bgImage, NIL, bgImageName);
AddContent(bgImage);
END;
NEW(transformer, elem, url, 100, loadLink, charset, frameName);
transformer.textColor := textColor;
transformer.linkColor := linkColor;
transformer.vlinkColor := vlinkColor;
transformer.alinkColor := alinkColor;
transformer.form := form;
transformer.initAlignment := align;
transformer.baseAddress := baseAddress;
transformer.baseTarget := baseTarget;
transformer.sequencer := seq;
transformer.isTableContent := TRUE;
xmlDoc := transformer.Transform();
NEW(bbtDecoder);
bbtDecoder.OpenXML(xmlDoc);
text := bbtDecoder.GetText();
NEW(tv);
tv.onLinkClicked.Add(loadLink);
AddContent(tv);
tv.alignment.Set(WMComponents.AlignClient);
rec.l := parentTable.cellpadding; rec.t := parentTable.cellpadding; rec.r := parentTable.cellpadding; rec.b := parentTable.cellpadding;
tv.borders.Set(rec);
tv.showBorder.Set(parentTable.rules);
tv.firstLine.Set(0);
item := transformer.embeddedObjectsList;
WHILE item # NIL DO
IF item.object IS Table THEN
item.object(Table).bounds.SetWidth(item.object(Table).minTableWidth);
END;
item := item.prev;
END;
tv.SetText(text);
tv.GetMinMaxWidth(minWidth, dummy);
INC(minWidth, 2 * colspan * parentTable.cellpadding + (colspan - 1) * parentTable.cellspacing);
IF width > minWidth THEN minWidth := width END;
item := transformer.embeddedObjectsList;
WHILE item # NIL DO
IF item.object IS Table THEN
item.object(Table).bounds.SetWidth(item.object(Table).maxTableWidth);
END;
item := item.prev;
END;
tv.SetText(text);
tv.GetMinMaxWidth(dummy, maxWidth);
INC(maxWidth, 2 * colspan * parentTable.cellpadding + (colspan - 1) * parentTable.cellspacing);
END New;
PROCEDURE SetWidth(width : LONGINT);
VAR
item : EmbeddedObject;
BEGIN
bounds.SetWidth(width);
item := transformer.embeddedObjectsList;
WHILE item # NIL DO
IF item.object IS Table THEN
item.object(Table).ParentTvWidthChanged(width);
END;
item := item.prev;
END;
tv.SetText(text);
END SetWidth;
END TableCell;
Form = OBJECT
VAR
action : String;
loadLink : WMEvents.EventListener;
firstComp, lastComp : FormComponent;
firstRadioButtonGroup, lastRadioButtonGroup : RadioButtonGroup;
PROCEDURE &Init*(action : String; loadLink : WMEvents.EventListener);
BEGIN
SELF.action := action;
SELF.loadLink := loadLink;
END Init;
PROCEDURE Send(sender, par : ANY);
VAR
url, s, t : String;
curr : FormComponent;
isFirst : BOOLEAN;
msg : WMTextView.LinkWrapper;
BEGIN
url := action;
isFirst := TRUE;
curr := firstComp;
WHILE curr # NIL DO
IF curr.IsSuccessful() THEN
s := curr.GetValue();
s := Utf82UrlEncodedUtf8(s^);
s := Strings.ConcatToNew("=", s^);
t := Utf82UrlEncodedUtf8(curr.name^);
s := Strings.ConcatToNew(t^, s^);
IF isFirst THEN
s := Strings.ConcatToNew("?", s^);
isFirst := FALSE;
ELSE
s := Strings.ConcatToNew("&", s^);
END;
url := Strings.ConcatToNew(url^, s^);
END;
curr := curr.nextComp;
END;
NEW(msg);
msg.link := EncodeLinkData(url, NIL, NIL);
loadLink(SELF, msg);
END Send;
PROCEDURE Reset(sender, par : ANY);
VAR
curr : FormComponent;
BEGIN
curr := firstComp;
WHILE curr # NIL DO
curr.Reset();
curr := curr.nextComp;
END;
END Reset;
PROCEDURE AddFormComponent(comp : FormComponent);
BEGIN
IF firstComp = NIL THEN
firstComp := comp;
lastComp := comp;
ELSE
lastComp.nextComp := comp;
lastComp := comp;
END;
END AddFormComponent;
PROCEDURE AddRadioButton(radioButton : FormRadioButton);
VAR
curr : RadioButtonGroup;
BEGIN
curr := firstRadioButtonGroup;
WHILE(curr # NIL) & ~Strings.Equal(Strings.LowerCaseInNew(curr.name^), Strings.LowerCaseInNew(radioButton.name^)) DO
curr := curr.next;
END;
IF curr = NIL THEN
NEW(curr, radioButton.name);
IF firstRadioButtonGroup = NIL THEN
firstRadioButtonGroup := curr;
lastRadioButtonGroup := curr;
ELSE
lastRadioButtonGroup.next := curr;
lastRadioButtonGroup := curr;
END;
AddFormComponent(curr);
END;
curr.Add(radioButton);
radioButton.group := curr;
END AddRadioButton;
END Form;
FormComponent = OBJECT
VAR
nextComp : FormComponent;
name : String;
PROCEDURE IsSuccessful() : BOOLEAN;
END IsSuccessful;
PROCEDURE GetValue() : String;
END GetValue;
PROCEDURE Reset;
END Reset;
END FormComponent;
FormButton = OBJECT (FormComponent)
VAR
button : WMStandardComponents.Button;
value : String;
proc : WMEvents.EventListener;
active : BOOLEAN;
PROCEDURE &Init*(name : String; value : String; proc : WMEvents.EventListener);
VAR
x, y : LONGINT;
font : WMGraphics.Font;
BEGIN
SELF.name := name;
SELF.value := value;
SELF.proc := proc;
NEW(button);
value := TransformCharEnt(value);
button.caption.SetAOC(value^);
font := button.GetFont();
font.GetStringSize(value^, x, y);
button.bounds.SetExtents(x + 18, y + 8);
button.onClick.Add(Click);
END Init;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN active & (name # NIL);
END IsSuccessful;
PROCEDURE GetValue() : String;
BEGIN
IF name # NIL THEN
RETURN value;
ELSE
RETURN NIL;
END;
END GetValue;
PROCEDURE Click(sender, par : ANY);
BEGIN
active := TRUE;
IF proc # NIL THEN proc(sender, par) END;
active := FALSE;
END Click;
END FormButton;
FormCheckbox = OBJECT (FormComponent)
VAR
checkbox : WMStandardComponents.Checkbox;
value : String;
init : BOOLEAN;
PROCEDURE &Init*(name : String; value : String; checked : BOOLEAN);
BEGIN
NEW(checkbox);
checkbox.bounds.SetExtents(12, 12);
SELF.name := name;
SELF.value := value;
init := checked;
IF checked THEN
checkbox.state.Set(1);
ELSE
checkbox.state.Set(0);
END;
END Init;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN (checkbox.state.Get() = 1) & (name # NIL);
END IsSuccessful;
PROCEDURE GetValue() : String;
BEGIN
IF name # NIL THEN
RETURN value;
ELSE
RETURN NIL;
END;
END GetValue;
PROCEDURE Reset;
BEGIN
IF init THEN
checkbox.state.Set(1);
ELSE
checkbox.state.Set(0);
END;
END Reset;
END FormCheckbox;
FormTextInput = OBJECT (FormComponent)
VAR
editor : WMEditors.Editor;
init : String;
PROCEDURE &Init*(name : String; value : String; size : LONGINT; maxlength : LONGINT; isPassword : BOOLEAN);
BEGIN
NEW(editor);
editor.multiLine.Set(FALSE);
editor.fillColor.Set(0FFFFFFFFH);
editor.tv.showBorder.Set(TRUE);
editor.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
SELF.name := name;
init := value;
IF isPassword THEN editor.tv.isPassword.Set(TRUE) END;
value := TransformCharEnt(value);
editor.SetAsString(value^);
editor.bounds.SetExtents(8 * size, 22);
END Init;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN name # NIL;
END IsSuccessful;
PROCEDURE GetValue() : String;
VAR
aoc : ARRAY 1024 OF CHAR;
BEGIN
IF name # NIL THEN
editor.GetAsString(aoc);
RETURN Strings.NewString(aoc);
ELSE
RETURN NIL;
END;
END GetValue;
PROCEDURE Reset;
BEGIN
editor.SetAsString(init^);
END Reset;
END FormTextInput;
FormRadioButton = OBJECT
VAR
next : FormRadioButton;
radioButton : WMStandardComponents.Checkbox;
name : String;
value : String;
group : RadioButtonGroup;
init : BOOLEAN;
PROCEDURE &Init*(name : String; value : String; checked : BOOLEAN);
BEGIN
NEW(radioButton);
radioButton.bounds.SetExtents(12, 12);
SELF.name := name;
SELF.value := value;
init := checked;
IF checked THEN
radioButton.state.Set(1);
ELSE
radioButton.state.Set(0);
END;
radioButton.onClick.Add(Clicked);
END Init;
PROCEDURE Clicked(sender, par : ANY);
BEGIN
IF radioButton.state.Get() = 0 THEN
radioButton.state.Set(1);
END;
group.ClearOthers(SELF);
END Clicked;
END FormRadioButton;
RadioButtonGroup = OBJECT (FormComponent)
VAR
next : RadioButtonGroup;
firstB, lastB : FormRadioButton;
PROCEDURE &Init*(name : String);
BEGIN
SELF.name := name;
END Init;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN TRUE;
END IsSuccessful;
PROCEDURE GetValue() : String;
VAR
curr : FormRadioButton;
BEGIN
curr := firstB;
LOOP
IF (curr = NIL) OR (curr.radioButton.state.Get() = 1) THEN EXIT END;
curr := curr.next;
END;
IF curr = NIL THEN curr := firstB END;
RETURN curr.value;
END GetValue;
PROCEDURE Reset;
VAR
curr : FormRadioButton;
BEGIN
curr := firstB;
LOOP
IF (curr = NIL) OR curr.init THEN EXIT END;
curr := curr.next;
END;
IF curr = NIL THEN curr := firstB END;
curr.radioButton.state.Set(1);
ClearOthers(curr);
END Reset;
PROCEDURE Add(radioButton : FormRadioButton);
BEGIN
IF firstB = NIL THEN
firstB := radioButton;
lastB := radioButton;
ELSE
lastB.next := radioButton;
lastB := radioButton;
END;
END Add;
PROCEDURE ClearOthers(exclude : FormRadioButton);
VAR
curr : FormRadioButton;
BEGIN
curr := firstB;
WHILE curr # NIL DO
IF curr # exclude THEN
curr.radioButton.state.Set(0);
END;
curr := curr.next;
END;
END ClearOthers;
END RadioButtonGroup;
FormMenuItem = OBJECT
VAR
caption- : ARRAY 128 OF CHAR;
value : String;
PROCEDURE &New*(caption: ARRAY OF CHAR; value : String);
BEGIN
COPY(caption, SELF.caption);
SELF.value := value;
END New;
END FormMenuItem;
FormMenu = OBJECT (FormComponent)
VAR
button : WMStandardComponents.Button;
popup: WMPopups.Popup;
init : FormMenuItem;
current : FormMenuItem;
PROCEDURE &Init*(name : String);
BEGIN
SELF.name := name;
NEW(button);
button.caption.SetAOC("[ select ]");
button.bounds.SetExtents(120, 22);
NEW(popup);
button.SetExtPointerDownHandler(MenuHandler);
END Init;
PROCEDURE MenuHandler(x, y: LONGINT; keys: SET; VAR handled: BOOLEAN);
BEGIN
handled := TRUE;
button.ToWMCoordinates(0, button.bounds.GetHeight(), x, y);
popup.Popup(x, y);
END MenuHandler;
PROCEDURE MenuPopupHandler(sender, data: ANY);
BEGIN
IF (data # NIL) & (data IS FormMenuItem) THEN
popup.Close;
button.caption.SetAOC(data(FormMenuItem).caption);
current := data(FormMenuItem);
END
END MenuPopupHandler;
PROCEDURE NewItem(value : String; label : String; selected : BOOLEAN);
VAR
item : FormMenuItem;
s : String;
BEGIN
label := TransformCharEnt(label);
IF value = NIL THEN value := label END;
s := Strings.ConcatToNew("[ ", label^);
s := Strings.ConcatToNew(s^, " ]");
NEW(item, s^, value);
IF selected THEN
init := item;
current := item;
button.caption.SetAOC(s^);
END;
popup.AddParButton(s^, MenuPopupHandler, item);
END NewItem;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN current # NIL;
END IsSuccessful;
PROCEDURE GetValue() : String;
BEGIN
IF name # NIL THEN
RETURN current.value;
ELSE
RETURN NIL;
END;
END GetValue;
PROCEDURE Reset;
BEGIN
IF init = NIL THEN
current := NIL;
button.caption.SetAOC("[ select ]");
ELSE
current := init;
button.caption.SetAOC(init.caption);
END;
END Reset;
END FormMenu;
FormHiddenControl = OBJECT (FormComponent)
VAR
value : String;
PROCEDURE &Init*(name : String; value : String);
BEGIN
SELF.name := name;
SELF.value := value;
END Init;
PROCEDURE IsSuccessful() : BOOLEAN;
BEGIN
RETURN name # NIL;
END IsSuccessful;
PROCEDURE GetValue() : String;
BEGIN
IF name # NIL THEN
RETURN value;
ELSE
RETURN NIL;
END;
END GetValue;
END FormHiddenControl;
PROCEDURE EncodeLinkData(link, target, url : String) : String;
VAR
s : String;
inlineLink : BOOLEAN;
urlLen : LONGINT;
BEGIN
ASSERT(link # NIL);
inlineLink := FALSE;
IF (url # NIL) & Strings.StartsWith2(url^, link^) THEN
urlLen := Strings.Length(url^);
IF (Strings.Length(link^) > urlLen) & (link^[urlLen] = "#") THEN
inlineLink := TRUE;
ELSIF (Strings.Length(link^) > (urlLen+1)) & (link^[urlLen] = "/") & (link^[urlLen+1] = "#") THEN
inlineLink := TRUE;
END;
END;
IF inlineLink THEN
RETURN Strings.Substring2(Strings.LastIndexOfByte2("#", link^), link^);
ELSE
s := target; IF s = NIL THEN s := Strings.NewString("") END;
s := Strings.ConcatToNew("target=", s^);
s := Strings.ConcatToNew(s^, ";url=");
RETURN Strings.ConcatToNew(s^, link^);
END;
END EncodeLinkData;
PROCEDURE Utf82UrlEncodedUtf8(VAR in : ARRAY OF CHAR) : String;
VAR
i, cnt : LONGINT;
output : String;
aoc : ARRAY 3 OF CHAR;
BEGIN
NEW(output, 3 * Strings.Length(in) + 1);
cnt := 0;
FOR i := 0 TO Strings.Length(in)-1 DO
IF (ORD(in[i])=021H) OR (ORD(in[i])=022H) OR (ORD(in[i])=024H) OR ((ORD(in[i]) >= 027H) & (ORD(in[i]) <= 02EH)) OR
((ORD(in[i]) >= 030H) & (ORD(in[i]) <= 039H)) OR ((ORD(in[i]) >= 041H) & (ORD(in[i]) <= 05AH)) OR
(ORD(in[i])=05FH) OR ((ORD(in[i]) >= 061H) & (ORD(in[i]) <= 07AH)) THEN
output^[cnt] := in[i];
INC(cnt);
ELSIF ORD(in[i])=020H THEN
output^[cnt] := '+';
INC(cnt);
ELSE
Strings.IntToHexStr(ORD(in[i]), 1, aoc);
output^[cnt] := '%';
output^[cnt+1] := aoc[0];
output^[cnt+2] := aoc[1];
INC(cnt, 3);
END;
END;
output^[cnt] := 0X;
RETURN output;
END Utf82UrlEncodedUtf8;
PROCEDURE GetElems(root : XML.Element; wanted : StringArray; stopAt : StringArray; checkMe : BOOLEAN) : XMLObjects.Enumerator;
VAR
col : XMLObjects.ArrayCollection;
enum, enum2 : XMLObjects.Enumerator;
p, p2 : ANY;
name : String;
i : LONGINT;
BEGIN
NEW(col);
name := root.GetName();
IF checkMe THEN
FOR i := 0 TO LEN(stopAt) - 1 DO
IF stopAt[i]^ = name^ THEN RETURN col.GetEnumerator() END;
END;
FOR i := 0 TO LEN(wanted) - 1 DO
IF wanted[i]^ = name^ THEN col.Add(root); END;
END;
END;
enum := root.GetContents();
WHILE enum.HasMoreElements() DO
p := enum.GetNext();
IF p IS XML.Element THEN
enum2 := GetElems(p(XML.Element), wanted, stopAt, TRUE);
WHILE enum2.HasMoreElements() DO
p2 := enum2.GetNext();
col.Add(p2);
END;
END;
END;
RETURN col.GetEnumerator();
END GetElems;
PROCEDURE GetCharsetConverter(charset : ARRAY OF CHAR) : CharsetConvProc;
BEGIN
Strings.TrimWS(charset);
Strings.LowerCase(charset);
IF charset = "iso8859-1" THEN
RETURN Iso2Utf8;
ELSIF charset = "utf-8" THEN
RETURN Utf82Utf8;
ELSIF charset = "gb2312" THEN
RETURN Gb23122Utf8;
ELSE
RETURN Iso2Utf8;
END;
END GetCharsetConverter;
PROCEDURE Iso2Utf8(VAR input : ARRAY OF CHAR) : String;
VAR
dyn : DynamicStrings.DynamicString;
dynPos : LONGINT;
temp : ARRAY 5 OF CHAR;
i, j, len : LONGINT;
BEGIN
NEW(dyn);
dynPos := 0;
FOR i := 0 TO Strings.Length(input)-1 DO
IF ORD(input[i]) >= 128 THEN
len := 0;
IF UTF8Strings.EncodeChar(ORD(input[i]), temp, len) THEN
FOR j := 0 TO len-1 DO
dyn.Put(temp[j], dynPos);
INC(dynPos);
END;
ELSE
dyn.Put('*', dynPos);
INC(dynPos);
END;
ELSE
dyn.Put(input[i], dynPos);
INC(dynPos);
END;
END;
RETURN dyn.ToArrOfChar();
END Iso2Utf8;
PROCEDURE Utf82Utf8(VAR input : ARRAY OF CHAR) : String;
BEGIN
RETURN Strings.NewString(input);
END Utf82Utf8;
PROCEDURE Gb23122Utf8(VAR input : ARRAY OF CHAR) : String;
BEGIN
RETURN WMCharCodes.GB2312ToUTF8(Strings.NewString(input));
END Gb23122Utf8;
PROCEDURE GetColor(s : String) : LONGINT;
VAR
aoc : ARRAY 17 OF CHAR;
i, res : LONGINT;
BEGIN
IF s#NIL THEN
IF (s^[0]='#') THEN
Strings.Copy(s^, 1, Strings.Length(s^)-1, aoc);
Strings.HexStrToInt(aoc, i, res);
RETURN i;
ELSIF (s[0] >= "0") & (s[0] <="9") OR (CAP(s[0]) >= "A") & (CAP(s[0])<="F") THEN
Strings.Copy(s^, 0, Strings.Length(s^), aoc);
Strings.HexStrToInt(aoc, i, res);
RETURN i;
ELSIF s^="black" THEN RETURN 0000000H;
ELSIF s^="silver" THEN RETURN 0C0C0C0H;
ELSIF s^="gray" THEN RETURN 0808080H;
ELSIF s^="white" THEN RETURN 0FFFFFFH;
ELSIF s^="maroon" THEN RETURN 0800000H;
ELSIF s^="red" THEN RETURN 0FF0000H;
ELSIF s^="purple" THEN RETURN 0800080H;
ELSIF s^="fuchsia" THEN RETURN 0FF00FFH;
ELSIF s^="green" THEN RETURN 0008000H;
ELSIF s^="lime" THEN RETURN 000FF00H;
ELSIF s^="olive" THEN RETURN 0808000H;
ELSIF s^="yellow" THEN RETURN 0FFFF00H;
ELSIF s^="navy" THEN RETURN 0000080H;
ELSIF s^="blue" THEN RETURN 00000FFH;
ELSIF s^="teal" THEN RETURN 0008080H;
ELSIF s^="aqua" THEN RETURN 000FFFFH;
ELSE RETURN 0;
END;
END;
RETURN 0;
END GetColor;
PROCEDURE StringIsWhiteSpace(VAR txt : ARRAY OF CHAR) : BOOLEAN;
VAR
i : LONGINT;
BEGIN
FOR i := 0 TO Strings.Length(txt)-1 DO
IF ORD(txt[i]) > 32 THEN RETURN FALSE END;
END;
RETURN TRUE;
END StringIsWhiteSpace;
PROCEDURE StringHasNewLine(VAR txt : ARRAY OF CHAR) : BOOLEAN;
VAR
i : LONGINT;
BEGIN
FOR i := 0 TO Strings.Length(txt)-1 DO
IF (ORD(txt[i]) = 10) OR (ORD(txt[i]) = 13) THEN RETURN TRUE END;
END;
RETURN FALSE;
END StringHasNewLine;
PROCEDURE ReplaceWhiteSpaces(VAR txt : String) : String;
VAR
dyn : DynamicStrings.DynamicString;
dynPos : LONGINT;
i : LONGINT;
ch : CHAR;
putYet : BOOLEAN;
BEGIN
TrimLineBreak(txt^);
NEW(dyn);
dynPos := 0;
putYet := FALSE;
FOR i := 0 TO Strings.Length(txt^)-1 DO
ch := txt^[i];
IF (ch = 020X) OR (ch = 9X) OR (ch = 0DX) OR (ch = 0AX) THEN
IF ~putYet THEN
dyn.Put(' ', dynPos);
INC(dynPos);
putYet := TRUE;
END;
ELSE
dyn.Put(ch, dynPos);
INC(dynPos);
putYet := FALSE;
END;
END;
RETURN dyn.ToArrOfChar();
END ReplaceWhiteSpaces;
PROCEDURE TrimLineBreak(VAR string : ARRAY OF CHAR);
VAR i,j: LONGINT;
BEGIN
j := 0;
WHILE (ORD(string[j]) = 10) OR (ORD(string[j]) = 13) DO INC(j) END;
IF (j > 0) THEN
i := 0;
WHILE (string[j] # 0X) DO
string[i] := string[j];
INC(i); INC(j)
END;
string[i] := 0X
END;
i := Strings.Length(string)-1;
WHILE (i >= 0) & ((ORD(string[i]) = 10) OR (ORD(string[i]) = 13)) DO DEC(i) END;
string[i+1] := 0X;
END TrimLineBreak;
PROCEDURE ResolveAddress*(baseAddress : String; url : String) : String;
VAR
slashPos, colonPos, upCnt : LONGINT;
BEGIN
IF Strings.StartsWith2("http://", url^) OR Strings.StartsWith2("file://", url^) THEN
RETURN url;
END;
IF Strings.StartsWith2("#", url^) THEN
RETURN Strings.ConcatToNew(baseAddress^, url^);
END;
IF url^[0] = '/' THEN
slashPos := Strings.LastIndexOfByte2("/", baseAddress^);
IF Strings.StartsWith2("file://", baseAddress^) THEN
IF slashPos > 6 THEN
baseAddress := Strings.Substring(0, slashPos, baseAddress^);
ELSE
colonPos := Strings.IndexOfByte(":", 7, baseAddress^);
IF colonPos = -1 THEN
baseAddress := Strings.Substring(0, slashPos, baseAddress^);
ELSE
baseAddress := Strings.Substring(0, colonPos+1, baseAddress^);
url := Strings.Substring2(1, url^);
END;
END;
ELSIF Strings.StartsWith2("http://", baseAddress^) THEN
IF slashPos > 6 THEN
baseAddress := Strings.Substring(0, slashPos, baseAddress^);
END;
ELSE
KernelLog.String("unknown protocol: "); KernelLog.String(baseAddress^); KernelLog.Ln;
ASSERT(Strings.StartsWith2("file://", baseAddress^));
END;
RETURN Strings.ConcatToNew(baseAddress^, url^);
END;
IF baseAddress^[Strings.Length(baseAddress^) - 1] # '/' THEN
slashPos := Strings.LastIndexOfByte2("/", baseAddress^);
IF Strings.StartsWith2("file://", baseAddress^) THEN
baseAddress := Strings.Substring(0, slashPos+1, baseAddress^);
ELSIF Strings.StartsWith2("http://", baseAddress^) THEN
IF slashPos > 6 THEN
baseAddress := Strings.Substring(0, slashPos+1, baseAddress^);
ELSE
baseAddress := Strings.ConcatToNew(baseAddress^, "/");
END;
ELSE
KernelLog.String("unknown protocol: "); KernelLog.String(baseAddress^); KernelLog.Ln;
ASSERT(Strings.StartsWith2("file://", baseAddress^));
END;
END;
upCnt := 0;
WHILE (Strings.Pos("../", url^) = 0) & (Strings.Length(url^) > 3) DO
INC(upCnt);
url := Strings.Substring2(3, url^);
END;
WHILE (Strings.Pos("./", url^) = 0) & (Strings.Length(url^) > 2) DO
url := Strings.Substring2(2, url^);
END;
WHILE (upCnt > 0) & (Strings.LastIndexOfByte("/", Strings.Length(baseAddress^) - 1, baseAddress^) # -1) DO
baseAddress := Strings.Substring(0, Strings.LastIndexOfByte("/", Strings.Length(baseAddress^) - 2, baseAddress^) + 1, baseAddress^);
DEC(upCnt);
END;
RETURN Strings.ConcatToNew(baseAddress^, url^);
END ResolveAddress;
PROCEDURE GetElemAttributeValue*(elem : XML.Element; key : ARRAY OF CHAR; lowerCase : BOOLEAN) : String;
VAR
enum: XMLObjects.Enumerator;
p : ANY;
s : String;
BEGIN
enum := elem.GetAttributes();
WHILE (enum.HasMoreElements()) DO
p := enum.GetNext();
IF p IS XML.Attribute THEN
s := p(XML.Attribute).GetName();
s := Strings.NewString(s^);
Strings.LowerCase(s^);
IF s^ = key THEN
s := p(XML.Attribute).GetValue();
s := Strings.NewString(s^);
IF lowerCase THEN Strings.LowerCase(s^); END;
RETURN s;
END;
END;
END;
RETURN NIL;
END GetElemAttributeValue;
PROCEDURE MapFontSize(font : String; size : LONGINT) : LONGINT;
BEGIN
IF font^ = "Oberon" THEN
IF size=1 THEN RETURN 8;
ELSIF size=2 THEN RETURN 10;
ELSIF size=3 THEN RETURN 12;
ELSIF size=4 THEN RETURN 14;
ELSIF size=5 THEN RETURN 16;
ELSIF size=6 THEN RETURN 20;
ELSIF size=7 THEN RETURN 24;
ELSE RETURN 0 END;
ELSE
IF size=1 THEN RETURN 11;
ELSIF size=2 THEN RETURN 12;
ELSIF size=3 THEN RETURN 15;
ELSIF size=4 THEN RETURN 18;
ELSIF size=5 THEN RETURN 24;
ELSIF size=6 THEN RETURN 30;
ELSIF size=7 THEN RETURN 48;
ELSE RETURN 0 END;
END;
END MapFontSize;
PROCEDURE MapBaselineShift(size : LONGINT) : LONGINT;
BEGIN
IF size=1 THEN RETURN 2;
ELSIF size=2 THEN RETURN 3;
ELSIF size=3 THEN RETURN 3;
ELSIF size=4 THEN RETURN 4;
ELSIF size=5 THEN RETURN 5;
ELSIF size=6 THEN RETURN 6;
ELSIF size=7 THEN RETURN 10;
ELSE RETURN 0 END;
END MapBaselineShift;
PROCEDURE GetExistingFontName(f : String) : String;
VAR
fonts, temp : String;
pos : LONGINT;
font : ARRAY 32 OF CHAR;
PROCEDURE Get(f : ARRAY OF CHAR; alternatives : BOOLEAN) : String;
VAR
i, j, last : LONGINT;
BEGIN
Strings.Trim(f, ' ');
Strings.Trim(f, '"');
Strings.Trim(f, "'");
last := Strings.Length(f)-1;
FOR i := 0 TO last DO
IF f[i]=' ' THEN
FOR j := i TO last-1 DO
f[j] := f[j+1];
END;
DEC(last);
END;
END;
f[last+1] := 0X;
IF FontExists(f) THEN RETURN Strings.NewString(f); END;
IF f="serif" THEN RETURN Strings.NewString(serif);
ELSIF f="sans-serif" THEN RETURN Strings.NewString(sansSerif);
ELSIF f="cursive" THEN RETURN Strings.NewString(cursive);
ELSIF f="fantasy" THEN RETURN Strings.NewString(fantasy);
ELSIF f="monospace" THEN RETURN Strings.NewString(monospace);
END;
IF alternatives THEN
RETURN NIL;
ELSE
RETURN Strings.NewString(defaultFont);
END;
END Get;
BEGIN
fonts := Strings.NewString(f^);
LOOP
pos := Strings.Pos(',', fonts^);
IF pos = -1 THEN
RETURN Get(fonts^, FALSE);
ELSE
Strings.Copy(fonts^, 0, pos, font);
IF (pos+1) > (Strings.Length(fonts^)-1) THEN RETURN Get(font, FALSE); END;
temp := Get(font, TRUE);
IF temp#NIL THEN RETURN temp; END;
temp := Strings.NewString(fonts^);
Strings.Copy(temp^, pos+1, Strings.Length(fonts^)-(pos+1), fonts^);
END;
END;
END GetExistingFontName;
PROCEDURE FontExists(f : ARRAY OF CHAR) : BOOLEAN;
VAR
font : WMGraphics.Font;
BEGIN
font := WMGraphics.GetFont(f, 12, {0});
RETURN (f = font.name);
END FontExists;
PROCEDURE IntToABCString(val : LONGINT; upperCase : BOOLEAN) : String;
VAR
i, j, offset : LONGINT;
aoc : ARRAY 5 OF CHAR;
PROCEDURE GetChar(i : LONGINT) : CHAR;
BEGIN
IF i = 0 THEN
RETURN '0';
ELSE
RETURN CHR(offset+i);
END;
END GetChar;
BEGIN
IF upperCase THEN offset := 64 ELSE offset := 96; END;
val := val MOD (26*26);
i := val DIV 26;
j := val MOD 26;
IF i = 0 THEN
aoc := " . ";
aoc[0] := GetChar(j);
ELSE
aoc := " . ";
aoc[0] := GetChar(i);
aoc[1] := GetChar(j);
END;
RETURN Strings.NewString(aoc);
END IntToABCString;
PROCEDURE IntToRomanString(val : LONGINT; uppercase : BOOLEAN) : String;
VAR
dyn : DynamicStrings.DynamicString;
aoc : ARRAY 3 OF CHAR;
s : String;
BEGIN
IF val = 0 THEN RETURN Strings.NewString("0. "); END;
NEW(dyn);
WHILE val > 0 DO
IF val >= 1000 THEN
aoc := "M"; dyn.Append(aoc); val := val - 1000;
ELSIF val >= 900 THEN
aoc := "CM"; dyn.Append(aoc); val := val - 900;
ELSIF val >= 500 THEN
aoc := "D"; dyn.Append(aoc); val := val - 500;
ELSIF val >= 400 THEN
aoc := "CD"; dyn.Append(aoc); val := val - 400;
ELSIF val >= 100 THEN
aoc := "C"; dyn.Append(aoc); val := val - 100;
ELSIF val >= 90 THEN
aoc := "XC"; dyn.Append(aoc); val := val - 90;
ELSIF val >= 50 THEN
aoc := "L"; dyn.Append(aoc); val := val - 50;
ELSIF val >= 40 THEN
aoc := "XL"; dyn.Append(aoc); val := val - 40;
ELSIF val >= 10 THEN
aoc := "X"; dyn.Append(aoc); val := val - 10;
ELSIF val >= 9 THEN
aoc := "IX"; dyn.Append(aoc); val := val - 9;
ELSIF val >= 5 THEN
aoc := "V"; dyn.Append(aoc); val := val - 5;
ELSIF val >= 4 THEN
aoc := "IV"; dyn.Append(aoc); val := val - 4;
ELSIF val >= 1 THEN
aoc := "I"; dyn.Append(aoc); val := val - 1;
END;
END;
aoc := ". "; dyn.Append(aoc);
s := dyn.ToArrOfChar();
IF ~uppercase THEN Strings.LowerCase(s^); END;
RETURN s;
END IntToRomanString;
PROCEDURE TransformCharEnt*(in : String) : String;
VAR
ent : ARRAY 32 OF CHAR;
i, j : LONGINT;
rep, s1, s2 : String;
ds: DynamicStrings.DynamicString;
BEGIN
i:=0;
LOOP
IF in^[i]='&' THEN
j:=i+1;
LOOP
IF j >= LEN(in^)-1 THEN EXIT END;
IF in^[j]=';' THEN
Strings.Copy(in^, i+1, j-i-1, ent);
rep := GetCharEnt(ent);
IF rep#NIL THEN
NEW(ds);
ds.FromArrOfChar(in);
s1 := ds.Extract(0, i);
s2 := ds.Extract(j+1, LEN(in^)-j-1);
NEW(ds);
ds.Append(s1^);
ds.Append(rep^);
ds.Append(s2^);
in := ds.ToArrOfChar();
i:=i+LEN(rep^)-2;
END;
EXIT;
END;
INC(j);
END;
END;
INC(i);
IF i>LEN(in^)-3 THEN EXIT END;
END;
RETURN in;
END TransformCharEnt;
PROCEDURE GetCharEnt(VAR ent : ARRAY OF CHAR) : String;
VAR
temp : String;
aoc : ARRAY 5 OF CHAR;
res, suc, len : LONGINT;
BEGIN
res := 0;
IF ent[0] = '#' THEN
temp := Strings.Substring2(1, ent);
IF Strings.Length(temp^) > 0 THEN
IF (temp^[0] = 'x') OR (temp^[0] = 'X') THEN
temp := Strings.Substring2(1, ent);
Strings.HexStrToInt(temp^, res, suc);
IF suc # 0 THEN res := 160 END;
ELSE
Strings.StrToInt(temp^, res);
END;
ELSE
res := 160;
END;
ELSIF ent = "nbsp" THEN res := 160;
ELSIF ent = "auml" THEN res := 228;
ELSIF ent = "ouml" THEN res := 246;
ELSIF ent = "uuml" THEN res := 252;
ELSIF ent = "Auml" THEN res := 196;
ELSIF ent = "Ouml" THEN res := 214;
ELSIF ent = "Uuml" THEN res := 220;
ELSIF ent = "quot" THEN res := 34;
ELSIF ent = "copy" THEN res := 169;
ELSIF ent = "euro" THEN res := 8364;
ELSIF ent = "iexcl" THEN res := 161;
ELSIF ent = "cent" THEN res := 162;
ELSIF ent = "pound" THEN res := 163;
ELSIF ent = "curren" THEN res := 164;
ELSIF ent = "yen" THEN res := 165;
ELSIF ent = "brvbar" THEN res := 166;
ELSIF ent = "sect" THEN res := 167;
ELSIF ent = "uml" THEN res := 168;
ELSIF ent = "ordf" THEN res := 170;
ELSIF ent = "laquo" THEN res := 171;
ELSIF ent = "not" THEN res := 172;
ELSIF ent = "shy" THEN res := 173;
ELSIF ent = "reg" THEN res := 174;
ELSIF ent = "macr" THEN res := 175;
ELSIF ent = "deg" THEN res := 176;
ELSIF ent = "plusmn" THEN res := 177;
ELSIF ent = "sup2" THEN res := 178;
ELSIF ent = "sup3" THEN res := 179;
ELSIF ent = "acute" THEN res := 180;
ELSIF ent = "micro" THEN res := 181;
ELSIF ent = "para" THEN res := 182;
ELSIF ent = "middot" THEN res := 183;
ELSIF ent = "cedil" THEN res := 184;
ELSIF ent = "sup1" THEN res := 185;
ELSIF ent = "ordm" THEN res := 186;
ELSIF ent = "raquo" THEN res := 187;
ELSIF ent = "frac14" THEN res := 188;
ELSIF ent = "frac12" THEN res := 189;
ELSIF ent = "frac34" THEN res := 190;
ELSIF ent = "iquest" THEN res := 191;
ELSIF ent = "Agrave" THEN res := 192;
ELSIF ent = "Aacute" THEN res := 193;
ELSIF ent = "Acirc" THEN res := 194;
ELSIF ent = "Atilde" THEN res := 195;
ELSIF ent = "Aring" THEN res := 197;
ELSIF ent = "AElig" THEN res := 198;
ELSIF ent = "Ccedil" THEN res := 199;
ELSIF ent = "Egrave" THEN res := 200;
ELSIF ent = "Eacute" THEN res := 201;
ELSIF ent = "Ecirc" THEN res := 202;
ELSIF ent = "Euml" THEN res := 203;
ELSIF ent = "Igrave" THEN res := 204;
ELSIF ent = "Iacute" THEN res := 205;
ELSIF ent = "Icirc" THEN res := 206;
ELSIF ent = "Iuml" THEN res := 207;
ELSIF ent = "ETH" THEN res := 208;
ELSIF ent = "Ntilde" THEN res := 209;
ELSIF ent = "Ograve" THEN res := 210;
ELSIF ent = "Oacute" THEN res := 211;
ELSIF ent = "Ocirc" THEN res := 212;
ELSIF ent = "Otilde" THEN res := 213;
ELSIF ent = "times" THEN res := 215;
ELSIF ent = "Oslash" THEN res := 216;
ELSIF ent = "Ugrave" THEN res := 217;
ELSIF ent = "Uacute" THEN res := 218;
ELSIF ent = "Ucirc" THEN res := 219;
ELSIF ent = "Yacute" THEN res := 221;
ELSIF ent = "THORN" THEN res := 222;
ELSIF ent = "szlig" THEN res := 223;
ELSIF ent = "agrave" THEN res := 224;
ELSIF ent = "aacute" THEN res := 225;
ELSIF ent = "acirc" THEN res := 226;
ELSIF ent = "atilde" THEN res := 227;
ELSIF ent = "aring" THEN res := 229;
ELSIF ent = "aelig" THEN res := 230;
ELSIF ent = "ccedil" THEN res := 231;
ELSIF ent = "egrave" THEN res := 232;
ELSIF ent = "eacute" THEN res := 233;
ELSIF ent = "ecirc" THEN res := 234;
ELSIF ent = "euml" THEN res := 235;
ELSIF ent = "igrave" THEN res := 236;
ELSIF ent = "iacute" THEN res := 237;
ELSIF ent = "icirc" THEN res := 238;
ELSIF ent = "iuml" THEN res := 239;
ELSIF ent = "eth" THEN res := 240;
ELSIF ent = "ntilde" THEN res := 241;
ELSIF ent = "ograve" THEN res := 242;
ELSIF ent = "oacute" THEN res := 243;
ELSIF ent = "ocirc" THEN res := 244;
ELSIF ent = "otilde" THEN res := 245;
ELSIF ent = "divide" THEN res := 247;
ELSIF ent = "oslash" THEN res := 248;
ELSIF ent = "ugrave" THEN res := 249;
ELSIF ent = "uacute" THEN res := 250;
ELSIF ent = "ucirc" THEN res := 251;
ELSIF ent = "yacute" THEN res := 253;
ELSIF ent = "thorn" THEN res := 254;
ELSIF ent = "yuml" THEN res := 255;
ELSIF ent = "fnof" THEN res := 402;
ELSIF ent = "Alpha" THEN res := 913;
ELSIF ent = "Beta" THEN res := 914;
ELSIF ent = "Gamma" THEN res := 915;
ELSIF ent = "Delta" THEN res := 916;
ELSIF ent = "Epsilon" THEN res := 917;
ELSIF ent = "Zeta" THEN res := 918;
ELSIF ent = "Eta" THEN res := 919;
ELSIF ent = "Theta" THEN res := 920;
ELSIF ent = "Iota" THEN res := 921;
ELSIF ent = "Kappa" THEN res := 922;
ELSIF ent = "Lambda" THEN res := 923;
ELSIF ent = "Mu" THEN res := 924;
ELSIF ent = "Nu" THEN res := 925;
ELSIF ent = "Xi" THEN res := 926;
ELSIF ent = "Omicron" THEN res := 927;
ELSIF ent = "Pi" THEN res := 928;
ELSIF ent = "Rho" THEN res := 929;
ELSIF ent = "Sigma" THEN res := 931;
ELSIF ent = "Tau" THEN res := 932;
ELSIF ent = "Upsilon" THEN res := 933;
ELSIF ent = "Phi" THEN res := 934;
ELSIF ent = "Chi" THEN res := 935;
ELSIF ent = "Psi" THEN res := 936;
ELSIF ent = "Omega" THEN res := 937;
ELSIF ent = "alpha" THEN res := 945;
ELSIF ent = "beta" THEN res := 946;
ELSIF ent = "gamma" THEN res := 947;
ELSIF ent = "delta" THEN res := 948;
ELSIF ent = "epsilon" THEN res := 949;
ELSIF ent = "zeta" THEN res := 950;
ELSIF ent = "eta" THEN res := 951;
ELSIF ent = "theta" THEN res := 952;
ELSIF ent = "iota" THEN res := 953;
ELSIF ent = "kappa" THEN res := 954;
ELSIF ent = "lambda" THEN res := 955;
ELSIF ent = "mu" THEN res := 956;
ELSIF ent = "nu" THEN res := 957;
ELSIF ent = "xi" THEN res := 958;
ELSIF ent = "omicron" THEN res := 959;
ELSIF ent = "pi" THEN res := 960;
ELSIF ent = "rho" THEN res := 961;
ELSIF ent = "sigmaf" THEN res := 962;
ELSIF ent = "sigma" THEN res := 963;
ELSIF ent = "tau" THEN res := 964;
ELSIF ent = "upsilon" THEN res := 965;
ELSIF ent = "phi" THEN res := 966;
ELSIF ent = "chi" THEN res := 967;
ELSIF ent = "psi" THEN res := 968;
ELSIF ent = "omega" THEN res := 969;
ELSIF ent = "thetasym" THEN res := 977;
ELSIF ent = "upsih" THEN res := 978;
ELSIF ent = "piv" THEN res := 982;
ELSIF ent = "bull" THEN res := 8226;
ELSIF ent = "hellip" THEN res := 8230;
ELSIF ent = "prime" THEN res := 8242;
ELSIF ent = "Prime" THEN res := 8243;
ELSIF ent = "oline" THEN res := 8254;
ELSIF ent = "frasl" THEN res := 8260;
ELSIF ent = "weierp" THEN res := 8472;
ELSIF ent = "image" THEN res := 8465;
ELSIF ent = "real" THEN res := 8476;
ELSIF ent = "trade" THEN res := 8482;
ELSIF ent = "alefsym" THEN res := 8501;
ELSIF ent = "larr" THEN res := 8592;
ELSIF ent = "uarr" THEN res := 8593;
ELSIF ent = "rarr" THEN res := 8594;
ELSIF ent = "darr" THEN res := 8595;
ELSIF ent = "harr" THEN res := 8596;
ELSIF ent = "crarr" THEN res := 8629;
ELSIF ent = "lArr" THEN res := 8656;
ELSIF ent = "uArr" THEN res := 8657;
ELSIF ent = "rArr" THEN res := 8658;
ELSIF ent = "dArr" THEN res := 8659;
ELSIF ent = "hArr" THEN res := 8660;
ELSIF ent = "forall" THEN res := 8704;
ELSIF ent = "part" THEN res := 8706;
ELSIF ent = "exist" THEN res := 8707;
ELSIF ent = "empty" THEN res := 8709;
ELSIF ent = "nabla" THEN res := 8711;
ELSIF ent = "isin" THEN res := 8712;
ELSIF ent = "notin" THEN res := 8713;
ELSIF ent = "ni" THEN res := 8715;
ELSIF ent = "prod" THEN res := 8719;
ELSIF ent = "sum" THEN res := 8721;
ELSIF ent = "minus" THEN res := 8722;
ELSIF ent = "lowast" THEN res := 8727;
ELSIF ent = "radic" THEN res := 8730;
ELSIF ent = "prop" THEN res := 8733;
ELSIF ent = "infin" THEN res := 8734;
ELSIF ent = "ang" THEN res := 8736;
ELSIF ent = "and" THEN res := 8743;
ELSIF ent = "or" THEN res := 8744;
ELSIF ent = "cap" THEN res := 8745;
ELSIF ent = "cup" THEN res := 8746;
ELSIF ent = "int" THEN res := 8747;
ELSIF ent = "there4" THEN res := 8756;
ELSIF ent = "sim" THEN res := 8764;
ELSIF ent = "cong" THEN res := 8773;
ELSIF ent = "asymp" THEN res := 8776;
ELSIF ent = "ne" THEN res := 8800;
ELSIF ent = "equiv" THEN res := 8801;
ELSIF ent = "le" THEN res := 8804;
ELSIF ent = "ge" THEN res := 8805;
ELSIF ent = "sub" THEN res := 8834;
ELSIF ent = "sup" THEN res := 8835;
ELSIF ent = "nsub" THEN res := 8836;
ELSIF ent = "sube" THEN res := 8838;
ELSIF ent = "supe" THEN res := 8839;
ELSIF ent = "oplus" THEN res := 8853;
ELSIF ent = "otimes" THEN res := 8855;
ELSIF ent = "perp" THEN res := 8869;
ELSIF ent = "sdot" THEN res := 8901;
ELSIF ent = "lceil" THEN res := 8968;
ELSIF ent = "rceil" THEN res := 8969;
ELSIF ent = "lfloor" THEN res := 8970;
ELSIF ent = "rfloor" THEN res := 8971;
ELSIF ent = "lang" THEN res := 9001;
ELSIF ent = "rang" THEN res := 9002;
ELSIF ent = "loz" THEN res := 9674;
ELSIF ent = "spades" THEN res := 9824;
ELSIF ent = "clubs" THEN res := 9827;
ELSIF ent = "hearts" THEN res := 9829;
ELSIF ent = "diams" THEN res := 9830;
ELSIF ent = "amp" THEN res := 38;
ELSIF ent = "lt" THEN res := 60;
ELSIF ent = "gt" THEN res := 62;
ELSIF ent = "OElig" THEN res := 338;
ELSIF ent = "oelig" THEN res := 339;
ELSIF ent = "Scaron" THEN res := 352;
ELSIF ent = "scaron" THEN res := 353;
ELSIF ent = "Yuml" THEN res := 376;
ELSIF ent = "circ" THEN res := 710;
ELSIF ent = "tilde" THEN res := 732;
ELSIF ent = "ensp" THEN res := 8194;
ELSIF ent = "emsp" THEN res := 8195;
ELSIF ent = "thinsp" THEN res := 8201;
ELSIF ent = "zwnj" THEN res := 8204;
ELSIF ent = "zwj" THEN res := 8205;
ELSIF ent = "lrm" THEN res := 8206;
ELSIF ent = "rlm" THEN res := 8207;
ELSIF ent = "ndash" THEN res := 8211;
ELSIF ent = "mdash" THEN res := 8212;
ELSIF ent = "lsquo" THEN res := 8216;
ELSIF ent = "rsquo" THEN res := 8217;
ELSIF ent = "sbquo" THEN res := 8218;
ELSIF ent = "ldquo" THEN res := 8220;
ELSIF ent = "rdquo" THEN res := 8221;
ELSIF ent = "bdquo" THEN res := 8222;
ELSIF ent = "dagger" THEN res := 8224;
ELSIF ent = "Dagger" THEN res := 8225;
ELSIF ent = "permil" THEN res := 8240;
ELSIF ent = "lsaquo" THEN res := 8249;
ELSIF ent = "rsaquo" THEN res := 8250;
ELSE RETURN NIL;
END;
IF UTF8Strings.EncodeChar(res, aoc, len) THEN
RETURN Strings.NewString(aoc);
ELSE
RETURN Strings.NewString("*");
END;
END GetCharEnt;
BEGIN
IF FontExists(defSerif) THEN serif := defSerif; ELSE serif := defaultFont END;
IF FontExists(defSansSerif) THEN sansSerif := defSansSerif; ELSE sansSerif := defaultFont END;
IF FontExists(defCursive) THEN cursive := defCursive; ELSE cursive := defaultFont END;
IF FontExists(defFantasy) THEN fantasy := defFantasy; ELSE fantasy := defaultFont END;
IF FontExists(defMonospace) THEN monospace := defMonospace; ELSE monospace := defaultFont END;
END HTMLTransformer.