diff --git a/components/wiki/lazwiki/wiki2xhtmlconvert.pas b/components/wiki/lazwiki/wiki2xhtmlconvert.pas index 02b988a087..e912f911e2 100644 --- a/components/wiki/lazwiki/wiki2xhtmlconvert.pas +++ b/components/wiki/lazwiki/wiki2xhtmlconvert.pas @@ -42,6 +42,9 @@ type protected BodyDOMNode: TDOMElement; CurDOMNode: TDOMElement; // current xhtml node + TOCNode: TDOMElement; + CurTOCNode: TDOMElement; + TOCNodeCount: integer; SectionLevel: integer; Stack: PW2XHTMLStackItem; StackPtr: integer; @@ -60,12 +63,14 @@ type TWiki2XHTMLConverter = class(TWiki2FormatConverter) private FAddLinksToTranslations: boolean; + FAddTOCIfHeaderCountMoreThan: integer; FCSSFilename: string; FLinkToBaseDocument: string; FMaxH: integer; FPageFileExt: string; - procedure DoAddLinksToTranslations(var doc: TXMLDocument; - var Page: TW2XHTMLPage); + procedure DoAddLinksToTranslations(Page: TW2XHTMLPage); + procedure DoAddLinkToBaseDocument(Page: TW2XHTMLPage); + procedure OnHeaderToken(Token: TWPToken); procedure SetCSSFilename(AValue: string); procedure SetMaxH(AValue: integer); procedure SetPageFileExt(AValue: string); @@ -73,6 +78,7 @@ type ShortFilenameToPage: TFilenameToPointerTree; // created in ConvertInit UsedImages: TFilenameToPointerTree; // image name to first page using the image procedure OnWikiToken(Token: TWPToken); virtual; + procedure RaiseNodeNotOpen(Token: TWPToken); function GetImageLink(ImgFilename: string): string; virtual; function FindImage(const ImgFilename: string): string; virtual; procedure MarkImageAsUsed(const ImgFilename: string; Page: TW2XHTMLPage); virtual; @@ -97,7 +103,9 @@ type function PageToFilename(Page: TW2XHTMLPage; Full: boolean): string; virtual; property PageFileExt: string read FPageFileExt write SetPageFileExt; property LinkToBaseDocument: string read FLinkToBaseDocument write FLinkToBaseDocument; - property AddLinksToTranslations: boolean read FAddLinksToTranslations write FAddLinksToTranslations; + property AddLinksToTranslations: boolean read FAddLinksToTranslations write FAddLinksToTranslations default true; + property AddTOCIfHeaderCountMoreThan: integer read FAddTOCIfHeaderCountMoreThan + write FAddTOCIfHeaderCountMoreThan default 2; end; implementation @@ -110,8 +118,7 @@ begin FCSSFilename:=AValue; end; -procedure TWiki2XHTMLConverter.DoAddLinksToTranslations(var doc: TXMLDocument; - var Page: TW2XHTMLPage); +procedure TWiki2XHTMLConverter.DoAddLinksToTranslations(Page: TW2XHTMLPage); var TranslationPage: TW2XHTMLPage; Lang: String; @@ -122,7 +129,9 @@ var LinkNode: TDOMElement; Captions: TStringList; i: Integer; + doc: TXMLDocument; begin + doc:=Page.XHTML; GetPageTranslations(Page.WikiDocumentName, LangToPage); //debugln(['TWiki2XHTMLConverter.DoAddLinksToTranslations ',Page.WikiDocumentName,' ',LangToPage.Count]); Captions:=TStringList.Create; @@ -166,6 +175,85 @@ begin end; end; +procedure TWiki2XHTMLConverter.DoAddLinkToBaseDocument(Page: TW2XHTMLPage); +var + Link: String; + Node: TDOMElement; + doc: TXMLDocument; +begin + // add LinkToBaseDocument
+ doc:=Page.XHTML; + Node:=doc.CreateElement('a'); + Page.BodyDOMNode.AppendChild(Node); + Link:=Page.WikiPage.BaseURL; + if (Link<>'') and (Link[length(Link)]<>'/') then + Link+='/'; + Link+=Page.WikiDocumentName; + Node.SetAttribute('href', Link); + Node.AppendChild(doc.CreateTextNode(LinkToBaseDocument)); + Node:=doc.CreateElement('br'); + Page.BodyDOMNode.AppendChild(Node); +end; + +procedure TWiki2XHTMLConverter.OnHeaderToken(Token: TWPToken); +var + LinkNode: TDOMElement; + HeaderTxt: DOMString; + Page: TW2XHTMLPage; + doc: TXMLDocument; + NodeName: String; + NodeClass: String; + Node: TDOMElement; + HRef: String; + LINode: TDOMElement; +begin + Page:=TW2XHTMLPage(Token.UserData); + doc:=Page.XHTML; + NodeClass:=''; + 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); + end else if Token.Range=wprClose then begin + // close header + if Page.CurDOMNode.TagName<>NodeName then + RaiseNodeNotOpen(Token); + HeaderTxt:=''; + if Page.CurDOMNode.FirstChild is TDOMText then + HeaderTxt:=TDOMText(Page.CurDOMNode.FirstChild).Data; + if HeaderTxt<>'' then begin + HRef:=WikiHeaderToLink(HeaderTxt); + // add anchor + LinkNode:=doc.CreateElement('a'); + LinkNode.SetAttribute('name', HRef); + Page.CurDOMNode.ParentNode.InsertBefore(LinkNode, Page.CurDOMNode); + // add TOC link + LINode:=doc.CreateElement('li'); + LINode.SetAttribute('class', 'toclevel-'+IntToStr(Page.SectionLevel)); + Page.CurTOCNode.AppendChild(LINode); + LinkNode:=doc.CreateElement('a'); + LinkNode.SetAttribute('href', '#'+HRef); + LinkNode.AppendChild(doc.CreateTextNode(HeaderTxt)); + LINode.AppendChild(LinkNode); + inc(Page.TOCNodeCount); + end; + Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement; + Page.Pop; + end; +end; + procedure TWiki2XHTMLConverter.SetMaxH(AValue: integer); begin if AValue<1 then AValue:=1; @@ -339,7 +427,6 @@ var CSSNode: TDOMElement; Node: TDOMElement; CurCSSFilename: String; - Link: String; begin Page.ClearConversion; if Page.WikiPage=nil then exit; @@ -380,29 +467,28 @@ begin // links to translations if AddLinksToTranslations then - DoAddLinksToTranslations(doc,Page); + DoAddLinksToTranslations(Page); try Page.SectionLevel:=0; + Page.TOCNode:=doc.CreateElement('ul'); + Page.TOCNodeCount:=0; + Page.CurTOCNode:=Page.TOCNode; + Page.BodyDOMNode.AppendChild(Page.TOCNode); + Page.CurDOMNode:=Page.BodyDOMNode; Page.WikiPage.Parse(@OnWikiToken,Page); - if LinkToBaseDocument<>'' then begin - // add LinkToBaseDocument
- Node:=doc.CreateElement('a'); - Page.BodyDOMNode.AppendChild(Node); - Link:=Page.WikiPage.BaseURL; - if (Link<>'') and (Link[length(Link)]<>'/') then - Link+='/'; - Link+=Page.WikiDocumentName; - Node.SetAttribute('href',Link); - Node.AppendChild(doc.CreateTextNode(LinkToBaseDocument)); - Node:=doc.CreateElement('br'); - Page.BodyDOMNode.AppendChild(Node); - end; + if LinkToBaseDocument<>'' then + DoAddLinkToBaseDocument(Page); + + if Page.TOCNodeCount<=AddTOCIfHeaderCountMoreThan then + Page.TOCNode.Free; finally Page.BodyDOMNode:=nil; Page.CurDOMNode:=nil; + Page.TOCNode:=nil; + Page.CurTOCNode:=nil; end; end; @@ -411,12 +497,6 @@ var Page: TW2XHTMLPage; W: TWikiPage; - procedure NodeNotOpen; - begin - raise Exception.Create('TWiki2XHTMLConverter.OnWikiToken can not close:' - +' Token='+dbgs(Token.Token)+' '+DbgSName(Token)+' CurNode='+Page.CurDOMNode.TagName); - end; - procedure MissingNodeName; begin raise Exception.Create('TWiki2XHTMLConverter.OnWikiToken have no node name:' @@ -432,7 +512,6 @@ var NameValueToken: TWPNameValueToken; CurName: String; CurValue: String; - HeaderTxt: DOMString; begin Page:=TW2XHTMLPage(Token.UserData); W:=Page.WikiPage; @@ -466,8 +545,7 @@ begin wptSup, wptSub, wptSmall, wptEm, wptSpan, wptString, wptVar, wptKey, wptPre, wptCenter, wptBulletList, wptNumberedList, wptDefinitionList, - wptTable, wptTableRow, wptTableCell, wptTableHeadCell, - wptSection: + wptTable, wptTableRow, wptTableCell, wptTableHeadCell: begin // simple range NodeClass:=''; @@ -500,16 +578,6 @@ begin wptTableRow: NodeName:='tr'; wptTableCell: NodeName:='td'; wptTableHeadCell: NodeName:='th'; - - wptSection: - begin - NodeName:='div'; - NodeClass:='section'; - if Token.Range=wprOpen then - inc(Page.SectionLevel) - else if Token.Range=wprClose then - dec(Page.SectionLevel); - end; end; if NodeName='' then MissingNodeName; @@ -523,48 +591,49 @@ begin exit; end else if Token.Range=wprClose then begin if Page.CurDOMNode.TagName<>NodeName then - NodeNotOpen; + RaiseNodeNotOpen(Token); Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement; exit; end; end; + wptSection: + begin + NodeName:='div'; + if Token.Range=wprOpen then begin + inc(Page.SectionLevel); + // start div + Node:=doc.CreateElement(NodeName); + Page.CurDOMNode.AppendChild(Node); + Node.SetAttribute('class','section'); + Page.CurDOMNode:=Node; + // start TOC list + Node:=doc.CreateElement('ul'); + Page.CurTOCNode.AppendChild(Node); + Page.CurTOCNode:=Node; + + Page.Push(Node,Token.Token); + exit; + end else if Token.Range=wprClose then begin + dec(Page.SectionLevel); + // end div + if Page.CurDOMNode.TagName<>NodeName then + RaiseNodeNotOpen(Token); + Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement; + // end TOC list + Node:=Page.CurTOCNode; + Page.CurTOCNode:=Node.ParentNode as TDOMElement; + if Node.FirstChild=nil then + Node.Free; + Page.Pop; + 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; + OnHeaderToken(Token); + exit; end; wptListItem: @@ -580,7 +649,7 @@ begin end else if Token.Range=wprClose then begin if (Page.CurDOMNode.TagName<>'dd') and (Page.CurDOMNode.TagName<>'li') then - NodeNotOpen; + RaiseNodeNotOpen(Token); Page.CurDOMNode:=Page.CurDOMNode.ParentNode as TDOMElement; exit; end; @@ -631,6 +700,15 @@ begin Log('TWiki2XHTMLConverter.OnWikiToken ToDo: Token='+dbgs(Token.Token)+' Range='+dbgs(Token.Range)+' Class='+Token.ClassName+' '+W.PosToStr(W.CurrentPos)); end; +procedure TWiki2XHTMLConverter.RaiseNodeNotOpen(Token: TWPToken); +var + Page: TW2XHTMLPage; +begin + Page:=TW2XHTMLPage(Token.UserData); + raise Exception.Create('TWiki2XHTMLConverter.OnWikiToken can not close:' + +' Token='+dbgs(Token.Token)+' '+DbgSName(Token)+' CurNode='+Page.CurDOMNode.TagName); +end; + function TWiki2XHTMLConverter.GetImageLink(ImgFilename: string): string; begin Result:=CreateRelativePath(ImgFilename,OutputDir); @@ -853,6 +931,7 @@ begin UsedImages:=TFilenameToPointerTree.Create(false); fLinkToBaseDocument:='Online version'; FAddLinksToTranslations:=true; + FAddTOCIfHeaderCountMoreThan:=2; end; destructor TWiki2XHTMLConverter.Destroy;