diff --git a/components/wiki/lazwiki/wiki2xhtmlconvert.pas b/components/wiki/lazwiki/wiki2xhtmlconvert.pas
index b8b8ef35f1..9905150965 100644
--- a/components/wiki/lazwiki/wiki2xhtmlconvert.pas
+++ b/components/wiki/lazwiki/wiki2xhtmlconvert.pas
@@ -29,17 +29,29 @@ uses
laz2_XMLWrite, LazUTF8, BasicCodeTools, KeywordFuncLists, CodeToolsStructs;
type
+ TW2XHTMLStackItem = record
+ Node: TDOMElement;
+ Token: TWPTokenType;
+ Txt: string;
+ end;
+ PW2XHTMLStackItem = ^TW2XHTMLStackItem;
{ TW2XHTMLPage }
TW2XHTMLPage = class(TW2FormatPage)
- private
- BodyNode: TDOMElement;
- CurNode: TDOMElement; // current xhtml node
+ protected
+ BodyDOMNode: TDOMElement;
+ CurDOMNode: TDOMElement; // current xhtml node
SectionLevel: integer;
+ Stack: PW2XHTMLStackItem;
+ StackPtr: integer;
+ StackCapacity: integer;
+ procedure Push(Node: TDOMElement; Token: TWPTokenType);
+ procedure Pop;
public
XHTML: TXMLDocument;
Filename: string;
+ constructor Create(TheConverter: TWiki2FormatConverter); override;
procedure ClearConversion; override;
end;
@@ -172,7 +184,7 @@ var
Node.SetAttribute('src', Filename);
if Caption<>'' then
Node.SetAttribute('alt', Caption);
- Page.CurNode.AppendChild(Node);
+ Page.CurDOMNode.AppendChild(Node);
exit(true);
end;
if WarnURL(LinkToken.Link) then
@@ -238,7 +250,7 @@ begin
Node.SetAttribute('href', URL);
if Caption<>'' then
Node.AppendChild(doc.CreateTextNode(Caption));
- Page.CurNode.AppendChild(Node);
+ Page.CurDOMNode.AppendChild(Node);
end else if Caption<>'' then begin
InsertText(LinkToken, Caption);
Result:=true;
@@ -286,23 +298,23 @@ begin
CSSNode.SetAttribute('rel','stylesheet');
end;
//
- Page.BodyNode:=doc.CreateElement('body');
- RootNode.AppendChild(Page.BodyNode);
+ Page.BodyDOMNode:=doc.CreateElement('body');
+ RootNode.AppendChild(Page.BodyDOMNode);
// title
Node:=doc.CreateElement('h1');
- Page.BodyNode.AppendChild(Node);
+ Page.BodyDOMNode.AppendChild(Node);
Node.SetAttribute('class','firstHeading');
Node.AppendChild(doc.CreateTextNode(Page.WikiPage.Title));
try
Page.SectionLevel:=0;
- Page.CurNode:=Page.BodyNode;
+ Page.CurDOMNode:=Page.BodyDOMNode;
Page.WikiPage.Parse(@OnWikiToken,Page);
if LinkToBaseDocument<>'' then begin
// add LinkToBaseDocument
Node:=doc.CreateElement('a');
- Page.BodyNode.AppendChild(Node);
+ Page.BodyDOMNode.AppendChild(Node);
Link:=Page.WikiPage.BaseURL;
if (Link<>'') and (Link[length(Link)]<>'/') then
Link+='/';
@@ -310,11 +322,11 @@ begin
Node.SetAttribute('href',Link);
Node.AppendChild(doc.CreateTextNode(LinkToBaseDocument));
Node:=doc.CreateElement('br');
- Page.BodyNode.AppendChild(Node);
+ Page.BodyDOMNode.AppendChild(Node);
end;
finally
- Page.BodyNode:=nil;
- Page.CurNode:=nil;
+ Page.BodyDOMNode:=nil;
+ Page.CurDOMNode:=nil;
end;
end;
@@ -326,7 +338,7 @@ var
procedure NodeNotOpen;
begin
raise Exception.Create('TWiki2XHTMLConverter.OnWikiToken can not close:'
- +' Token='+dbgs(Token.Token)+' '+DbgSName(Token)+' CurNode='+Page.CurNode.TagName);
+ +' Token='+dbgs(Token.Token)+' '+DbgSName(Token)+' CurNode='+Page.CurDOMNode.TagName);
end;
procedure MissingNodeName;
@@ -344,6 +356,7 @@ var
NameValueToken: TWPNameValueToken;
CurName: String;
CurValue: String;
+ HeaderTxt: DOMString;
begin
Page:=TW2XHTMLPage(Token.UserData);
W:=Page.WikiPage;
@@ -360,16 +373,16 @@ begin
wptLineBreak:
begin
// only append a br if there is something in front
- if Page.CurNode.FirstChild<>nil then
- Page.CurNode.AppendChild(doc.CreateElement('br'));
+ if Page.CurDOMNode.FirstChild<>nil then
+ Page.CurDOMNode.AppendChild(doc.CreateElement('br'));
exit;
end;
wptHorizontalRow:
begin
// only append a hr if there is something in front
- if Page.CurNode.FirstChild<>nil then
- Page.CurNode.AppendChild(doc.CreateElement('hr'));
+ if Page.CurDOMNode.FirstChild<>nil then
+ Page.CurDOMNode.AppendChild(doc.CreateElement('hr'));
exit;
end;
@@ -378,7 +391,7 @@ begin
wptPre, wptCenter,
wptBulletList, wptNumberedList, wptDefinitionList,
wptTable, wptTableRow, wptTableCell, wptTableHeadCell,
- wptSection, wptHeader:
+ wptSection:
begin
// simple range
NodeClass:='';
@@ -421,51 +434,78 @@ begin
else if Token.Range=wprClose then
dec(Page.SectionLevel);
end;
- wptHeader:
- begin
- if Page.SectionLevel<=1 then
- NodeName:='h1'
- else if Page.SectionLevel<=MaxH then
- NodeName:='h'+IntToStr(Page.SectionLevel)
- else if Page.SectionLevel>MaxH then begin
- NodeName:='h'+IntToStr(MaxH);
- NodeClass:='subTitle';
- end;
- end;
end;
if NodeName='' then
MissingNodeName;
if Token.Range=wprOpen then begin
Node:=doc.CreateElement(NodeName);
- Page.CurNode.AppendChild(Node);
+ Page.CurDOMNode.AppendChild(Node);
if NodeClass<>'' then
Node.SetAttribute('class',NodeClass);
- Page.CurNode:=Node;
+ Page.CurDOMNode:=Node;
exit;
end else if Token.Range=wprClose then begin
- if Page.CurNode.TagName<>NodeName then
+ if Page.CurDOMNode.TagName<>NodeName then
NodeNotOpen;
- Page.CurNode:=Page.CurNode.ParentNode as TDOMElement;
+ Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement;
+ exit;
+ end;
+ end;
+
+ wptHeader:
+ begin
+ if Page.SectionLevel<=1 then
+ NodeName:='h1'
+ else if Page.SectionLevel<=MaxH then
+ NodeName:='h'+IntToStr(Page.SectionLevel)
+ else if Page.SectionLevel>MaxH then begin
+ NodeName:='h'+IntToStr(MaxH);
+ NodeClass:='subTitle';
+ end;
+ if Token.Range=wprOpen then begin
+ // open header
+ Node:=doc.CreateElement(NodeName);
+ Page.CurDOMNode.AppendChild(Node);
+ if NodeClass<>'' then
+ Node.SetAttribute('class',NodeClass);
+ Page.CurDOMNode:=Node;
+ Page.Push(Node,wptHeader);
+ exit;
+ end else if Token.Range=wprClose then begin
+ // close header
+ if Page.CurDOMNode.TagName<>NodeName then
+ NodeNotOpen;
+ HeaderTxt:='';
+ if Page.CurDOMNode.FirstChild is TDOMText then
+ HeaderTxt:=TDOMText(Page.CurDOMNode.FirstChild).Data;
+ if HeaderTxt<>'' then begin
+ // add anchor
+ Node:=doc.CreateElement('a');
+ Node.SetAttribute('name',WikiHeaderToLink(HeaderTxt));
+ Page.CurDOMNode.ParentNode.InsertBefore(Node,Page.CurDOMNode);
+ end;
+ Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement;
+ Page.Pop;
exit;
end;
end;
wptListItem:
if Token.Range=wprOpen then begin
- if Page.CurNode.TagName='dl' then
+ if Page.CurDOMNode.TagName='dl' then
NodeName:='dd'
else
NodeName:='li';
Node:=doc.CreateElement(NodeName);
- Page.CurNode.AppendChild(Node);
- Page.CurNode:=Node;
+ Page.CurDOMNode.AppendChild(Node);
+ Page.CurDOMNode:=Node;
exit;
end else if Token.Range=wprClose then begin
- if (Page.CurNode.TagName<>'dd')
- and (Page.CurNode.TagName<>'li') then
+ if (Page.CurDOMNode.TagName<>'dd')
+ and (Page.CurDOMNode.TagName<>'li') then
NodeNotOpen;
- Page.CurNode:=Page.CurNode.ParentNode as TDOMElement;
+ Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement;
exit;
end;
@@ -474,7 +514,7 @@ begin
NameValueToken:=TWPNameValueToken(Token);
CurName:=copy(W.Src,NameValueToken.NameStartPos,NameValueToken.NameEndPos-NameValueToken.NameStartPos);
CurValue:=copy(W.Src,NameValueToken.ValueStartPos,NameValueToken.ValueEndPos-NameValueToken.ValueStartPos);
- Page.CurNode.SetAttribute(CurName,CurValue);
+ Page.CurDOMNode.SetAttribute(CurName,CurValue);
exit;
end;
@@ -486,7 +526,7 @@ begin
Node:=doc.CreateElement('span');
if CurName<>'' then
Node.SetAttribute('class',CurName);
- Page.CurNode.AppendChild(Node);
+ Page.CurDOMNode.AppendChild(Node);
if CurValue<>'' then
Node.AppendChild(doc.CreateTextNode(CurValue));
exit;
@@ -541,22 +581,23 @@ procedure TWiki2XHTMLConverter.InsertText(Token: TWPToken; Txt: string);
var
Page: TW2XHTMLPage;
doc: TXMLDocument;
+ CurNode: TDOMElement;
begin
Page:=TW2XHTMLPage(Token.UserData);
doc:=Page.XHTML;
//Log(['TWiki2XHTMLConverter.InsertText Txt="'+dbgstr(Txt)+'"']);
if Txt='' then exit;
- if Page.CurNode.TagName<>'pre' then begin
+ CurNode:=Page.CurDOMNode;
+ if CurNode.TagName<>'pre' then begin
if UTF8Trim(Txt)='' then begin
// skip empty text
exit;
end;
- if Page.CurNode.FirstChild=nil then
+ if CurNode.FirstChild=nil then
Txt:=UTF8Trim(Txt,[u8tKeepEnd]);
end;
- //Log('TWiki2XHTMLConverter.InsertText Node="'+Page.CurNode.TagName+'" Text="'+Txt+'"');
- Txt:=EncodeLesserAndGreaterThan(Txt);
- Page.CurNode.AppendChild(doc.CreateTextNode(Txt));
+ //Log('TWiki2XHTMLConverter.InsertText Node="'+Page.CurDOMNode.TagName+'" Text="'+Txt+'"');
+ CurNode.AppendChild(doc.CreateTextNode(Txt));
end;
procedure TWiki2XHTMLConverter.InsertCode(Token: TWPNameValueToken);
@@ -635,7 +676,7 @@ begin
CurName:='pascal';
if CurName<>'' then
CodeNode.SetAttribute('class',CurName);
- Page.CurNode.AppendChild(CodeNode);
+ Page.CurDOMNode.AppendChild(CodeNode);
if CurValue<>'' then begin
if (CurName='pascal') then begin
p:=PChar(CurValue);
@@ -792,11 +833,44 @@ end;
{ TW2XHTMLPage }
+procedure TW2XHTMLPage.Push(Node: TDOMElement; Token: TWPTokenType);
+var
+ s: PW2XHTMLStackItem;
+ OldCapacity: Integer;
+begin
+ inc(StackPtr);
+ if StackPtr=StackCapacity then begin
+ OldCapacity:=StackCapacity;
+ StackCapacity:=StackCapacity*2+8;
+ ReAllocMem(Stack,SizeOf(TW2XHTMLStackItem)*StackCapacity);
+ FillByte(Stack[StackPtr],SizeOf(TW2XHTMLStackItem)*(StackCapacity-OldCapacity),0);
+ end;
+ s:=@Stack[StackPtr];
+ s^.Node:=Node;
+ s^.Token:=Token;
+end;
+
+procedure TW2XHTMLPage.Pop;
+begin
+ if StackPtr<0 then
+ raise Exception.Create('bug'); // push and pop are not balanced
+ dec(StackPtr);
+end;
+
+constructor TW2XHTMLPage.Create(TheConverter: TWiki2FormatConverter);
+begin
+ inherited Create(TheConverter);
+ StackPtr:=-1;
+end;
+
procedure TW2XHTMLPage.ClearConversion;
begin
- BodyNode:=nil;
- CurNode:=nil;
+ BodyDOMNode:=nil;
+ CurDOMNode:=nil;
SectionLevel:=0;
+ ReAllocMem(Stack,0);
+ StackPtr:=-1;
+ StackCapacity:=0;
FreeAndNil(XHTML);
end;
diff --git a/components/wiki/test/wikihelpmanager.pas b/components/wiki/test/wikihelpmanager.pas
index b971adb414..fb9b7a88a5 100644
--- a/components/wiki/test/wikihelpmanager.pas
+++ b/components/wiki/test/wikihelpmanager.pas
@@ -126,8 +126,8 @@ type
TW2HelpPage = class(TW2HTMLPage)
public
- TextRoot: TWHTextNode;
- CurNode: TWHTextNode;
+ WHRoot: TWHTextNode;
+ CurWHNode: TWHTextNode;
Score: single;
destructor Destroy; override;
function GetScore(Query: TWikiHelpQuery): TWHScore;
@@ -655,7 +655,7 @@ end;
destructor TW2HelpPage.Destroy;
begin
- FreeAndNil(TextRoot);
+ FreeAndNil(WHRoot);
inherited Destroy;
end;
@@ -733,7 +733,7 @@ procedure TW2HelpPage.GetFit(Query: TWikiHelpQuery; Fit: PWHPhrasePageFit);
begin
CheckTxt(WikiPage.Title,whfcPageTitle);
- Traverse(TextRoot);
+ Traverse(WHRoot);
end;
function TW2HelpPage.GetNodeHighestScore(Query: TWikiHelpQuery): TWHTextNode;
@@ -789,7 +789,7 @@ var
begin
Result:=nil;
NodeScore:=0;
- Traverse(TextRoot,Result,NodeScore);
+ Traverse(WHRoot,Result,NodeScore);
end;
{ TWHTextNode }
@@ -992,8 +992,8 @@ var
begin
Page:=TW2HelpPage(Token.UserData);
W:=Page.WikiPage;
- CurNode:=Page.CurNode;
- if CurNode=nil then CurNode:=Page.TextRoot;
+ CurNode:=Page.CurWHNode;
+ if CurNode=nil then CurNode:=Page.WHRoot;
case Token.Token of
wptText:
if Token is TWPTextToken then begin
@@ -1015,10 +1015,10 @@ begin
NodeType:=whnHeader
else
NodeType:=whnTxt;
- Page.CurNode:=TWHTextNode.Create(NodeType,CurNode);
+ Page.CurWHNode:=TWHTextNode.Create(NodeType,CurNode);
exit;
end else if Token.Range=wprClose then begin
- Page.CurNode:=CurNode.Parent;
+ Page.CurWHNode:=CurNode.Parent;
exit;
end;
@@ -1111,14 +1111,14 @@ end;
procedure TWiki2HelpConverter.ExtractPageText(Page: TW2HelpPage);
begin
- FreeAndNil(Page.TextRoot);
- Page.TextRoot:=TWHTextNode.Create(whnTxt,nil);
+ FreeAndNil(Page.WHRoot);
+ Page.WHRoot:=TWHTextNode.Create(whnTxt,nil);
try
- Page.CurNode:=Page.TextRoot;
+ Page.CurWHNode:=Page.WHRoot;
if Page.WikiPage<>nil then
Page.WikiPage.Parse(@ExtractTextToken,Page);
finally
- Page.CurNode:=nil;
+ Page.CurWHNode:=nil;
end;
end;
@@ -1460,7 +1460,7 @@ begin
+TextToHTMLSnipped(aPage.WikiPage.Title,aQuery.LoPhrases,200)+'
'+LineEnding;
if aNode=nil then begin
// get the first node with some text
- aNode:=aPage.TextRoot;
+ aNode:=aPage.WHRoot;
while (aNode<>nil) and (UTF8Trim(aNode.Txt)='') do
aNode:=aNode.Next;
end;
diff --git a/components/wiki/test/wikisearchmain.pas b/components/wiki/test/wikisearchmain.pas
index fb37eb429b..1bd2674db9 100644
--- a/components/wiki/test/wikisearchmain.pas
+++ b/components/wiki/test/wikisearchmain.pas
@@ -132,8 +132,8 @@ type
procedure UpdateHistoryButtons;
procedure UpdateProgress;
procedure LoadWikiPage(Documentname, Anchor: string; AddToHistory: boolean);
- procedure LoadHTML(Target: TIpHtmlPanel; HTML: string); overload;
- procedure LoadHTML(Target: TIpHtmlPanel; aStream: TStream); overload;
+ procedure LoadHTML(Target: TIpHtmlPanel; HTML: string; Anchor: string = ''); overload;
+ procedure LoadHTML(Target: TIpHtmlPanel; aStream: TStream; Anchor: string = ''); overload;
procedure ViewSource(aTitle, aSource: string; aHighlighter: TSynCustomHighlighter);
procedure WikiSearchOptsWndOptionsChanged(Sender: TObject);
procedure WikiHelpScanned(Sender: TObject);
@@ -429,8 +429,8 @@ begin
DocumentName:=HRef;
p:=Pos('#',DocumentName);
if p>0 then begin
- DocumentName:=LeftStr(DocumentName,p-1);
AnchorName:=copy(DocumentName,p+1,length(DocumentName));
+ DocumentName:=LeftStr(DocumentName,p-1);
end;
LoadWikiPage(DocumentName,AnchorName,true);
end;
@@ -583,8 +583,7 @@ begin
if Src<>'' then
ms.Read(Src[1],length(Src));
ms.Position:=0;
- // ToDo: anchor
- LoadHTML(PageIpHtmlPanel,ms);
+ LoadHTML(PageIpHtmlPanel,ms,Anchor);
FPageDocumentName:=DocumentName;
FPageAnchor:=Anchor;
FPageSource:=Src;
@@ -611,7 +610,8 @@ begin
end;
end;
-procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; HTML: string);
+procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; HTML: string;
+ Anchor: string);
var
ms: TMemoryStream;
begin
@@ -622,7 +622,7 @@ begin
try
ms.Write(HTML[1],length(HTML));
ms.Position:=0;
- LoadHTML(Target,ms);
+ LoadHTML(Target,ms,Anchor);
except
on E: Exception do begin
debugln(['TWikiSearchDemoForm.LoadHTML ',E.Message]);
@@ -633,15 +633,18 @@ begin
end;
end;
-procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; aStream: TStream);
+procedure TWikiSearchDemoForm.LoadHTML(Target: TIpHtmlPanel; aStream: TStream;
+ Anchor: string);
var
NewHTML: TIpHtml;
begin
try
NewHTML:=TIpHtml.Create; // Beware: Will be freed automatically by IpHtmlPanel
- //NewHTML.OnGetImageX:=@HTMLGetImageX;
Target.SetHtml(NewHTML);
NewHTML.LoadFromStream(aStream);
+ // ToDo: fix TIpHtmlNodeA.MakeVisible
+ if Anchor<>'' then
+ Target.MakeAnchorVisible(Anchor+'/'); // ipHTML store anchor names with / at end
except
on E: Exception do begin
debugln(['TWikiSearchDemoForm.LoadHTML ',E.Message]);