dw_basehtml.pp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  1. {
  2. FPDoc - Free Pascal Documentation Tool
  3. Copyright (C) 2021 by Michael Van Canneyt
  4. * Basic HTML output generator. No assumptions about document/documentation structure
  5. See the file COPYING, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. unit dw_basehtml;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses Classes, contnrs, DOM, DOM_HTML, dGlobals, PasTree, dWriter;
  15. type
  16. { TLinkIdentifierMap }
  17. TLinkIdentifierMap = class
  18. Flist : TFPStringHashTable;
  19. FWriter: TMultiFileDocWriter;
  20. Public
  21. constructor create(aWriter: TMultiFileDocWriter);
  22. destructor destroy; override;
  23. function GetLink(const aIdentifier : String) : String;
  24. procedure AddLink(const aName, aLink : String);
  25. procedure AddLink(const AElement : TPasElement);
  26. end;
  27. { TBaseHTMLWriter }
  28. TBaseHTMLWriter = class(TMultiFileDocWriter)
  29. Private
  30. FImageFileList: TStrings;
  31. FContentElement : THTMLELement;
  32. FInsideHeadRow: Boolean;
  33. FOutputNodeStack: TFPList;
  34. FBaseImageURL : String;
  35. FDoc: THTMLDocument;
  36. FCurOutputNode: TDOMNode;
  37. FDoPasHighlighting : Boolean;
  38. FHighlighterFlags: Byte;
  39. FContentElementStack : Array of THTMLElement;
  40. FContentElementCount : Integer;
  41. Protected
  42. Procedure SetContentElement(aElement : THTMLELement); virtual;
  43. // Description node conversion
  44. Procedure DescrEmitNotesHeader(AContext : TPasElement); override;
  45. Procedure DescrEmitNotesFooter(AContext : TPasElement); override;
  46. procedure DescrWriteText(const AText: DOMString); override;
  47. procedure DescrBeginBold; override;
  48. procedure DescrEndBold; override;
  49. procedure DescrBeginItalic; override;
  50. procedure DescrEndItalic; override;
  51. procedure DescrBeginEmph; override;
  52. procedure DescrEndEmph; override;
  53. procedure DescrBeginUnderline; override;
  54. procedure DescrEndUnderline; override;
  55. procedure DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString); override;
  56. procedure DescrWriteFileEl(const AText: DOMString); override;
  57. procedure DescrWriteKeywordEl(const AText: DOMString); override;
  58. procedure DescrWriteVarEl(const AText: DOMString); override;
  59. procedure DescrBeginLink(const AId: DOMString); override;
  60. procedure DescrEndLink; override;
  61. procedure DescrBeginURL(const AURL: DOMString); override;
  62. procedure DescrEndURL; override;
  63. procedure DescrWriteLinebreak; override;
  64. procedure DescrBeginParagraph; override;
  65. procedure DescrEndParagraph; override;
  66. procedure DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String); override;
  67. procedure DescrWriteCodeLine(const ALine: String); override;
  68. procedure DescrEndCode; override;
  69. procedure DescrBeginOrderedList; override;
  70. procedure DescrEndOrderedList; override;
  71. procedure DescrBeginUnorderedList; override;
  72. procedure DescrEndUnorderedList; override;
  73. procedure DescrBeginDefinitionList; override;
  74. procedure DescrEndDefinitionList; override;
  75. procedure DescrBeginListItem; override;
  76. procedure DescrEndListItem; override;
  77. procedure DescrBeginDefinitionTerm; override;
  78. procedure DescrEndDefinitionTerm; override;
  79. procedure DescrBeginDefinitionEntry; override;
  80. procedure DescrEndDefinitionEntry; override;
  81. procedure DescrBeginSectionTitle; override;
  82. procedure DescrBeginSectionBody; override;
  83. procedure DescrEndSection; override;
  84. procedure DescrBeginRemark; override;
  85. procedure DescrEndRemark; override;
  86. procedure DescrBeginTable(ColCount: Integer; HasBorder: Boolean); override;
  87. procedure DescrEndTable; override;
  88. procedure DescrBeginTableCaption; override;
  89. procedure DescrEndTableCaption; override;
  90. procedure DescrBeginTableHeadRow; override;
  91. procedure DescrEndTableHeadRow; override;
  92. procedure DescrBeginTableRow; override;
  93. procedure DescrEndTableRow; override;
  94. procedure DescrBeginTableCell; override;
  95. procedure DescrEndTableCell; override;
  96. // Basic HTML handling
  97. Procedure SetHTMLDocument(aDoc : THTMLDocument); virtual;
  98. procedure PushOutputNode(ANode: TDOMNode); virtual;
  99. procedure PopOutputNode; virtual;
  100. procedure AppendText(Parent: TDOMNode; const AText: AnsiString); virtual;
  101. procedure AppendText(Parent: TDOMNode; const AText: DOMString); virtual;
  102. procedure AppendNbSp(Parent: TDOMNode; ACount: Integer); virtual;
  103. procedure AppendSym(Parent: TDOMNode; const AText: DOMString); virtual;
  104. procedure AppendKw(Parent: TDOMNode; const AText: AnsiString); virtual;
  105. procedure AppendKw(Parent: TDOMNode; const AText: DOMString); virtual;
  106. function AppendPasSHFragment(Parent: TDOMNode; const AText: String; AShFlags: Byte): Byte; virtual;
  107. function AppendPasSHFragment(Parent: TDOMNode; const AText: String; AShFlags: Byte; aLinkIdentifierMap : TLinkIdentifierMap): Byte; virtual;
  108. procedure AppendFragment(aParentNode: TDOMElement; aStream: TStream); virtual;
  109. // FPDoc specifics
  110. procedure AppendSourceRef(aParent: TDOMElement; AElement: TPasElement);
  111. Procedure AppendSeeAlsoSection(AElement: TPasElement; DocNode: TDocNode); virtual;
  112. Procedure AppendSeeAlsoSection(AElement: TPasElement; aParent : TDOMElement; DocNode: TDocNode); virtual;
  113. Procedure AppendExampleSection(AElement : TPasElement;DocNode : TDocNode); virtual;
  114. Procedure AppendExampleSection(AElement : TPasElement;aParent : TDOMElement; DocNode : TDocNode); virtual;
  115. Procedure AppendShortDescr(Parent: TDOMNode; Element: TPasElement); virtual;
  116. procedure AppendShortDescr(AContext: TPasElement; Parent: TDOMNode; DocNode: TDocNode); virtual;
  117. procedure AppendShortDescrCell(Parent: TDOMNode; Element: TPasElement); virtual;
  118. procedure AppendDescr(AContext: TPasElement; Parent: TDOMNode; DescrNode: TDOMElement; AutoInsertBlock: Boolean); virtual;
  119. procedure AppendDescrSection(AContext: TPasElement; Parent: TDOMNode; DescrNode: TDOMElement; const ATitle: DOMString); virtual;
  120. procedure AppendDescrSection(AContext: TPasElement; Parent: TDOMNode; DescrNode: TDOMElement; const ATitle: AnsiString); virtual;
  121. function AppendHyperlink(Parent: TDOMNode; Element: TPasElement): TDOMElement;
  122. // Helper functions for creating DOM elements
  123. function CreateEl(Parent: TDOMNode; const AName: DOMString): THTMLElement; virtual; overload;
  124. function CreateEl(Parent: TDOMNode; const AName, aClass: DOMString): THTMLElement; virtual; overload;
  125. function CreatePara(Parent: TDOMNode): THTMLElement; virtual;
  126. function CreateH1(Parent: TDOMNode): THTMLElement; virtual;
  127. function CreateH2(Parent: TDOMNode): THTMLElement; virtual;
  128. function CreateH3(Parent: TDOMNode): THTMLElement; virtual;
  129. function CreateTable(Parent: TDOMNode; const AClass: DOMString = ''): THTMLElement;virtual;
  130. function CreateContentTable(Parent: TDOMNode): THTMLElement; virtual;
  131. function CreateTR(Parent: TDOMNode): THTMLElement; virtual;
  132. function CreateTD(Parent: TDOMNode): THTMLElement; virtual;
  133. function CreateTD_vtop(Parent: TDOMNode): THTMLElement; virtual;
  134. function CreateLink(Parent: TDOMNode; const AHRef: AnsiString): THTMLElement; virtual;
  135. function CreateLink(Parent: TDOMNode; const AHRef: DOMString): THTMLElement; virtual;
  136. function CreateAnchor(Parent: TDOMNode; const AName: DOMString): THTMLElement; virtual;
  137. function CreateCode(Parent: TDOMNode): THTMLElement; virtual;
  138. function CreateWarning(Parent: TDOMNode): THTMLElement; virtual;
  139. // Push new content element. Returns the old content element.
  140. function PushContentElement(aElement: THTMLELement) : THTMLElement;
  141. // Pop content element, returns the old content element.
  142. function PopContentElement : THTMLElement;
  143. // Some info
  144. Property ContentElement : THTMLELement Read FContentElement Write SetContentElement;
  145. Property OutputNodeStack: TFPList Read FOutputNodeStack;
  146. Property CurOutputNode : TDomNode Read FCurOutputNode;
  147. Property ImageFileList : TStrings Read FImageFileList;
  148. Property Doc: THTMLDocument Read FDoc;
  149. Property InsideHeadRow: Boolean Read FInsideHeadRow;
  150. Property DoPasHighlighting : Boolean Read FDoPasHighlighting;
  151. Property HighlighterFlags : Byte read FHighlighterFlags;
  152. Public
  153. constructor Create(APackage: TPasPackage; AEngine: TFPDocEngine); override;
  154. Destructor Destroy; override;
  155. Property BaseImageURL : String Read FBaseImageURL Write FBaseImageURL;
  156. end;
  157. Function FixHTMLpath(const S : String) : STring;
  158. implementation
  159. uses fpdocstrs, xmlread, sysutils, sh_pas ;
  160. Function FixHTMLpath(const S : String) : STring;
  161. begin
  162. Result:=StringReplace(S,'\','/',[rfReplaceAll]);
  163. end;
  164. { TLinkIdentifierMap }
  165. constructor TLinkIdentifierMap.create(aWriter: TMultiFileDocWriter);
  166. begin
  167. FList:=TFPStringHashTable.Create;
  168. FWriter:=aWriter;
  169. end;
  170. destructor TLinkIdentifierMap.destroy;
  171. begin
  172. Flist.Free;
  173. inherited destroy;
  174. end;
  175. function TLinkIdentifierMap.GetLink(const aIdentifier: String): String;
  176. begin
  177. Result:=FList.Items[Trim(LowerCase(aIdentifier))]
  178. end;
  179. procedure TLinkIdentifierMap.AddLink(const aName, aLink: String);
  180. begin
  181. if (aName='') or (aLink='') then
  182. exit;
  183. FList.Add(LowerCase(aName),aLink);
  184. end;
  185. procedure TLinkIdentifierMap.AddLink(const AElement: TPasElement);
  186. var
  187. lLink : String;
  188. begin
  189. if aElement.Name<>'' then
  190. begin
  191. lLink:=FWriter.ResolveLinkID(aElement.FullName);
  192. if lLink<>'' then
  193. AddLink(aElement.Name,lLink);
  194. end;
  195. end;
  196. constructor TBaseHTMLWriter.Create(APackage: TPasPackage; AEngine: TFPDocEngine);
  197. begin
  198. Inherited;
  199. FOutputNodeStack := TFPList.Create;
  200. FImageFileList:=TStringList.Create;
  201. end;
  202. destructor TBaseHTMLWriter.Destroy;
  203. begin
  204. FreeAndNil(FOutputNodeStack);
  205. FreeAndNil(FImageFileList);
  206. inherited Destroy;
  207. end;
  208. procedure TBaseHTMLWriter.SetContentElement(aElement: THTMLELement);
  209. begin
  210. FContentElement:=aElement;
  211. end;
  212. function TBaseHTMLWriter.CreateEl(Parent: TDOMNode;
  213. const AName: DOMString): THTMLElement;
  214. begin
  215. Result := Doc.CreateElement(AName);
  216. Parent.AppendChild(Result);
  217. end;
  218. function TBaseHTMLWriter.CreateEl(Parent: TDOMNode; const AName, aClass: DOMString): THTMLElement;
  219. begin
  220. Result:=CreateEl(Parent,aName);
  221. Result['class']:=aClass;
  222. end;
  223. function TBaseHTMLWriter.CreatePara(Parent: TDOMNode): THTMLElement;
  224. begin
  225. Result := CreateEl(Parent, 'p');
  226. end;
  227. function TBaseHTMLWriter.CreateH1(Parent: TDOMNode): THTMLElement;
  228. begin
  229. Result := CreateEl(Parent, 'h1');
  230. end;
  231. function TBaseHTMLWriter.CreateH2(Parent: TDOMNode): THTMLElement;
  232. begin
  233. Result := CreateEl(Parent, 'h2');
  234. end;
  235. function TBaseHTMLWriter.CreateH3(Parent: TDOMNode): THTMLElement;
  236. begin
  237. Result := CreateEl(Parent, 'h3');
  238. end;
  239. function TBaseHTMLWriter.CreateTable(Parent: TDOMNode; const AClass: DOMString = ''): THTMLElement;
  240. begin
  241. Result := CreateEl(Parent, 'table');
  242. Result['cellspacing'] := '0';
  243. Result['cellpadding'] := '0';
  244. if AClass <> '' then
  245. Result['class'] := AClass;
  246. end;
  247. function TBaseHTMLWriter.CreateContentTable(Parent: TDOMNode): THTMLElement;
  248. begin
  249. Result := CreateEl(Parent, 'table');
  250. end;
  251. function TBaseHTMLWriter.CreateTR(Parent: TDOMNode): THTMLElement;
  252. begin
  253. Result := CreateEl(Parent, 'tr');
  254. end;
  255. function TBaseHTMLWriter.CreateTD(Parent: TDOMNode): THTMLElement;
  256. begin
  257. Result := CreateEl(Parent, 'td');
  258. end;
  259. function TBaseHTMLWriter.CreateTD_vtop(Parent: TDOMNode): THTMLElement;
  260. begin
  261. Result := CreateEl(Parent, 'td');
  262. Result['valign'] := 'top';
  263. end;
  264. function TBaseHTMLWriter.CreateLink(Parent: TDOMNode; const AHRef: AnsiString): THTMLElement;
  265. begin
  266. Result := CreateEl(Parent, 'a');
  267. Result['href'] := UTF8Decode(FixHtmlPath(AHRef));
  268. end;
  269. function TBaseHTMLWriter.CreateLink(Parent: TDOMNode;
  270. const AHRef: DOMString): THTMLElement;
  271. begin
  272. Result:=CreateLink(Parent,UTF8Encode(aHREf));
  273. end;
  274. function TBaseHTMLWriter.CreateAnchor(Parent: TDOMNode;
  275. const AName: DOMString): THTMLElement;
  276. begin
  277. Result := CreateEl(Parent, 'a');
  278. Result['name'] := AName;
  279. end;
  280. function TBaseHTMLWriter.CreateCode(Parent: TDOMNode): THTMLElement;
  281. begin
  282. Result := CreateEl(CreateEl(Parent, 'tt'), 'span');
  283. Result['class'] := 'code';
  284. end;
  285. function TBaseHTMLWriter.CreateWarning(Parent: TDOMNode): THTMLElement;
  286. begin
  287. Result := CreateEl(Parent, 'span');
  288. Result['class'] := 'warning';
  289. end;
  290. function TBaseHTMLWriter.PushContentElement(aElement: THTMLELement): THTMLElement;
  291. begin
  292. if FContentElementCount=Length(FContentElementStack) then
  293. SetLength(FContentElementStack,FContentElementCount+10);
  294. Result:=FContentElement;
  295. FContentElementStack[FContentElementCount]:=Result;
  296. FContentElement:=aElement;
  297. Inc(FContentElementCount);
  298. end;
  299. function TBaseHTMLWriter.PopContentElement: THTMLElement;
  300. begin
  301. if FContentElementCount=0 then
  302. Raise EFPDocWriterError.Create('Cannot pop content element, at bottom of stack');
  303. Result:=FContentElement;
  304. FContentElement:=FContentElementStack[FContentElementCount-1];
  305. FContentElementStack[FContentElementCount-1]:=Nil;
  306. Dec(FContentElementCount);
  307. end;
  308. procedure TBaseHTMLWriter.DescrEmitNotesHeader(AContext: TPasElement);
  309. begin
  310. AppendText(CreateH2(ContentElement), SDocNotes);
  311. PushOutputNode(ContentElement);
  312. end;
  313. procedure TBaseHTMLWriter.DescrEmitNotesFooter(AContext: TPasElement);
  314. begin
  315. PopOutPutNode;
  316. end;
  317. procedure TBaseHTMLWriter.PushOutputNode(ANode: TDOMNode);
  318. begin
  319. OutputNodeStack.Add(CurOutputNode);
  320. FCurOutputNode := ANode;
  321. end;
  322. procedure TBaseHTMLWriter.PopOutputNode;
  323. begin
  324. FCurOutputNode := TDOMNode(OutputNodeStack[OutputNodeStack.Count - 1]);
  325. OutputNodeStack.Delete(OutputNodeStack.Count - 1);
  326. end;
  327. procedure TBaseHTMLWriter.DescrWriteText(const AText: DOMString);
  328. begin
  329. AppendText(CurOutputNode, AText);
  330. end;
  331. procedure TBaseHTMLWriter.DescrBeginBold;
  332. begin
  333. PushOutputNode(CreateEl(CurOutputNode, 'b'));
  334. end;
  335. procedure TBaseHTMLWriter.DescrEndBold;
  336. begin
  337. PopOutputNode;
  338. end;
  339. procedure TBaseHTMLWriter.DescrBeginItalic;
  340. begin
  341. PushOutputNode(CreateEl(CurOutputNode, 'i'));
  342. end;
  343. procedure TBaseHTMLWriter.DescrEndItalic;
  344. begin
  345. PopOutputNode;
  346. end;
  347. procedure TBaseHTMLWriter.DescrBeginEmph;
  348. begin
  349. PushOutputNode(CreateEl(CurOutputNode, 'em'));
  350. end;
  351. procedure TBaseHTMLWriter.DescrEndEmph;
  352. begin
  353. PopOutputNode;
  354. end;
  355. procedure TBaseHTMLWriter.DescrBeginUnderline;
  356. begin
  357. PushOutputNode(CreateEl(CurOutputNode, 'u'));
  358. end;
  359. procedure TBaseHTMLWriter.DescrEndUnderline;
  360. begin
  361. PopOutputNode;
  362. end;
  363. procedure TBaseHTMLWriter.DescrWriteImageEl(const AFileName, ACaption, ALinkName : DOMString);
  364. Var
  365. Pel,Cel: TDOMNode;
  366. El :TDomElement;
  367. D : String;
  368. L : Integer;
  369. begin
  370. // Determine parent node.
  371. If (ACaption='') then
  372. Pel:=CurOutputNode
  373. else
  374. begin
  375. Cel:=CreateTable(CurOutputNode, 'imagetable');
  376. Pel:=CreateTD(CreateTR(Cel));
  377. Cel:=CreateTD(CreateTR(Cel));
  378. El := CreateEl(Cel, 'span');
  379. El['class'] := 'imagecaption';
  380. Cel := El;
  381. If (ALinkName<>'') then
  382. Cel:=CreateAnchor(Cel,ALinkName);
  383. AppendText(Cel,ACaption);
  384. end;
  385. // Determine URL for image.
  386. If (Module=Nil) then
  387. D:=Allocator.GetRelativePathToTop(Package)
  388. else
  389. D:=Allocator.GetRelativePathToTop(Module);
  390. L:=Length(D);
  391. If (L>0) and (D[L]<>'/') then
  392. D:=D+'/';
  393. // Create image node.
  394. El:=CreateEl(Pel,'img');
  395. EL['src']:=UTF8Decode(D + BaseImageURL) + AFileName;
  396. El['alt']:=ACaption;
  397. //cache image filename, so it can be used later (CHM)
  398. ImageFileList.Add(UTF8Encode(UTF8Decode(BaseImageURL) + AFileName));
  399. end;
  400. procedure TBaseHTMLWriter.DescrWriteFileEl(const AText: DOMString);
  401. var
  402. NewEl: TDOMElement;
  403. begin
  404. NewEl := CreateEl(CurOutputNode, 'span');
  405. NewEl['class'] := 'file';
  406. AppendText(NewEl, AText);
  407. end;
  408. procedure TBaseHTMLWriter.DescrWriteKeywordEl(const AText: DOMString);
  409. var
  410. NewEl: TDOMElement;
  411. begin
  412. NewEl := CreateEl(CurOutputNode, 'span');
  413. NewEl['class'] := 'kw';
  414. AppendText(NewEl, AText);
  415. end;
  416. procedure TBaseHTMLWriter.DescrWriteVarEl(const AText: DOMString);
  417. var
  418. NewEl: TDOMElement;
  419. begin
  420. NewEl := CreateEl(CurOutputNode, 'span');
  421. NewEl['class'] := 'identifier';
  422. AppendText(NewEl, AText);
  423. end;
  424. procedure TBaseHTMLWriter.DescrBeginLink(const AId: DOMString);
  425. var
  426. a,s,n : String;
  427. begin
  428. a:=UTF8Encode(AId);
  429. s := UTF8Encode(ResolveLinkID(a));
  430. if Length(s) = 0 then
  431. begin
  432. if assigned(module) then
  433. s:=module.name
  434. else
  435. s:='?';
  436. if a='' then a:='<empty>';
  437. if Assigned(CurrentContext) then
  438. N:=CurrentContext.Name
  439. else
  440. N:='?';
  441. DoLog(SErrUnknownLinkID, [s,n,a]);
  442. LinkUnresolvedInc();
  443. PushOutputNode(CreateEl(CurOutputNode, 'b'));
  444. end else
  445. PushOutputNode(CreateLink(CurOutputNode, s));
  446. end;
  447. procedure TBaseHTMLWriter.DescrEndLink;
  448. begin
  449. PopOutputNode;
  450. end;
  451. procedure TBaseHTMLWriter.DescrBeginURL(const AURL: DOMString);
  452. begin
  453. PushOutputNode(CreateLink(CurOutputNode, AURL));
  454. end;
  455. procedure TBaseHTMLWriter.DescrEndURL;
  456. begin
  457. PopOutputNode;
  458. end;
  459. procedure TBaseHTMLWriter.DescrWriteLinebreak;
  460. begin
  461. CreateEl(CurOutputNode, 'br');
  462. end;
  463. procedure TBaseHTMLWriter.DescrBeginParagraph;
  464. begin
  465. PushOutputNode(CreatePara(CurOutputNode));
  466. end;
  467. procedure TBaseHTMLWriter.DescrEndParagraph;
  468. begin
  469. PopOutputNode;
  470. end;
  471. procedure TBaseHTMLWriter.DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String);
  472. var
  473. lNode : THTMLElement;
  474. lClass : string;
  475. begin
  476. FDoPasHighlighting := (AHighlighterName = '') or (AHighlighterName = 'Pascal');
  477. FHighlighterFlags := 0;
  478. lNode:=CreateEl(CurOutputNode, 'pre');
  479. lClass:='code code-';
  480. if AHighlighterName='' then
  481. lClass:=lClass+'pascal'
  482. else
  483. lClass:=lClass+lowercase(AHighlighterName);
  484. lNode['class']:=lClass;
  485. PushOutputNode(lNode);
  486. end;
  487. procedure TBaseHTMLWriter.DescrWriteCodeLine(const ALine: String);
  488. begin
  489. if DoPasHighlighting then
  490. begin
  491. FHighlighterFlags := AppendPasSHFragment(CurOutputNode, ALine,FHighlighterFlags);
  492. AppendText(CurOutputNode, #10);
  493. end else
  494. AppendText(CurOutputNode, ALine + #10);
  495. end;
  496. procedure TBaseHTMLWriter.DescrEndCode;
  497. begin
  498. PopOutputNode;
  499. end;
  500. procedure TBaseHTMLWriter.DescrBeginOrderedList;
  501. begin
  502. PushOutputNode(CreateEl(CurOutputNode, 'ol'));
  503. end;
  504. procedure TBaseHTMLWriter.DescrEndOrderedList;
  505. begin
  506. PopOutputNode;
  507. end;
  508. procedure TBaseHTMLWriter.DescrBeginUnorderedList;
  509. begin
  510. PushOutputNode(CreateEl(CurOutputNode, 'ul'));
  511. end;
  512. procedure TBaseHTMLWriter.DescrEndUnorderedList;
  513. begin
  514. PopOutputNode;
  515. end;
  516. procedure TBaseHTMLWriter.DescrBeginDefinitionList;
  517. begin
  518. PushOutputNode(CreateEl(CurOutputNode, 'dl'));
  519. end;
  520. procedure TBaseHTMLWriter.DescrEndDefinitionList;
  521. begin
  522. PopOutputNode;
  523. end;
  524. procedure TBaseHTMLWriter.DescrBeginListItem;
  525. begin
  526. PushOutputNode(CreateEl(CurOutputNode, 'li'));
  527. end;
  528. procedure TBaseHTMLWriter.DescrEndListItem;
  529. begin
  530. PopOutputNode;
  531. end;
  532. procedure TBaseHTMLWriter.DescrBeginDefinitionTerm;
  533. begin
  534. PushOutputNode(CreateEl(CurOutputNode, 'dt'));
  535. end;
  536. procedure TBaseHTMLWriter.DescrEndDefinitionTerm;
  537. begin
  538. PopOutputNode;
  539. end;
  540. procedure TBaseHTMLWriter.DescrBeginDefinitionEntry;
  541. begin
  542. PushOutputNode(CreateEl(CurOutputNode, 'dd'));
  543. end;
  544. procedure TBaseHTMLWriter.DescrEndDefinitionEntry;
  545. begin
  546. PopOutputNode;
  547. end;
  548. procedure TBaseHTMLWriter.DescrBeginSectionTitle;
  549. begin
  550. PushOutputNode(CreateEl(CurOutputNode, 'h3'));
  551. end;
  552. procedure TBaseHTMLWriter.DescrBeginSectionBody;
  553. begin
  554. PopOutputNode;
  555. end;
  556. procedure TBaseHTMLWriter.DescrEndSection;
  557. begin
  558. end;
  559. procedure TBaseHTMLWriter.DescrBeginRemark;
  560. var
  561. NewEl, TDEl: TDOMElement;
  562. begin
  563. NewEl := CreateEl(CurOutputNode, 'table');
  564. NewEl['width'] := '100%';
  565. NewEl['border'] := '0';
  566. NewEl['CellSpacing'] := '0';
  567. NewEl['class'] := 'remark';
  568. NewEl := CreateTR(NewEl);
  569. TDEl := CreateTD(NewEl);
  570. TDEl['valign'] := 'top';
  571. TDEl['class'] := 'pre';
  572. AppendText(CreateEl(TDEl, 'b'), SDocRemark);
  573. PushOutputNode(CreateTD(NewEl));
  574. end;
  575. procedure TBaseHTMLWriter.DescrEndRemark;
  576. begin
  577. PopOutputNode;
  578. end;
  579. procedure TBaseHTMLWriter.DescrBeginTable(ColCount: Integer; HasBorder: Boolean);
  580. var
  581. Table: TDOMElement;
  582. begin
  583. Table := CreateEl(CurOutputNode, 'table');
  584. Table['border'] := UTF8Decode(IntToStr(Ord(HasBorder)));
  585. PushOutputNode(Table);
  586. end;
  587. procedure TBaseHTMLWriter.DescrEndTable;
  588. begin
  589. PopOutputNode;
  590. end;
  591. procedure TBaseHTMLWriter.DescrBeginTableCaption;
  592. begin
  593. PushOutputNode(CreateEl(CurOutputNode, 'caption'));
  594. end;
  595. procedure TBaseHTMLWriter.DescrEndTableCaption;
  596. begin
  597. PopOutputNode;
  598. end;
  599. procedure TBaseHTMLWriter.DescrBeginTableHeadRow;
  600. begin
  601. PushOutputNode(CreateTr(CurOutputNode));
  602. FInsideHeadRow := True;
  603. end;
  604. procedure TBaseHTMLWriter.DescrEndTableHeadRow;
  605. begin
  606. FInsideHeadRow := False;
  607. PopOutputNode;
  608. end;
  609. procedure TBaseHTMLWriter.DescrBeginTableRow;
  610. begin
  611. PushOutputNode(CreateTR(CurOutputNode));
  612. end;
  613. procedure TBaseHTMLWriter.DescrEndTableRow;
  614. begin
  615. PopOutputNode;
  616. end;
  617. procedure TBaseHTMLWriter.DescrBeginTableCell;
  618. begin
  619. if InsideHeadRow then
  620. PushOutputNode(CreateEl(CurOutputNode, 'th'))
  621. else
  622. PushOutputNode(CreateTD(CurOutputNode));
  623. end;
  624. procedure TBaseHTMLWriter.DescrEndTableCell;
  625. begin
  626. PopOutputNode;
  627. end;
  628. procedure TBaseHTMLWriter.SetHTMLDocument(aDoc: THTMLDocument);
  629. begin
  630. FDoc:=aDoc;
  631. FOutputNodeStack.Clear;
  632. FCurOutputNode:=Nil;
  633. end;
  634. procedure TBaseHTMLWriter.AppendText(Parent: TDOMNode; const AText: AnsiString);
  635. begin
  636. AppendText(Parent,UTF8Decode(aText));
  637. end;
  638. procedure TBaseHTMLWriter.AppendText(Parent: TDOMNode; const AText: DOMString);
  639. begin
  640. Parent.AppendChild(Doc.CreateTextNode(AText));
  641. end;
  642. procedure TBaseHTMLWriter.AppendNbSp(Parent: TDOMNode; ACount: Integer);
  643. begin
  644. while ACount > 0 do
  645. begin
  646. Parent.AppendChild(Doc.CreateEntityReference('nbsp'));
  647. Dec(ACount);
  648. end;
  649. end;
  650. procedure TBaseHTMLWriter.AppendSym(Parent: TDOMNode; const AText: DOMString);
  651. var
  652. El: TDOMElement;
  653. begin
  654. El := CreateEl(Parent, 'span');
  655. El['class'] := 'sym';
  656. AppendText(El, AText);
  657. end;
  658. procedure TBaseHTMLWriter.AppendKw(Parent: TDOMNode; const AText: AnsiString);
  659. begin
  660. AppendKW(Parent,UTF8Decode(aText));
  661. end;
  662. procedure TBaseHTMLWriter.AppendKw(Parent: TDOMNode; const AText: DOMString);
  663. var
  664. El: TDOMElement;
  665. begin
  666. El := CreateEl(Parent, 'span');
  667. El['class'] := 'kw';
  668. AppendText(El, AText);
  669. end;
  670. function TBaseHTMLWriter.AppendPasSHFragment(Parent: TDOMNode;
  671. const AText: String; AShFlags: Byte): Byte;
  672. begin
  673. Result:=AppendPasSHFragment(Parent,aText,AShFlags,Nil);
  674. end;
  675. function TBaseHTMLWriter.AppendPasSHFragment(Parent: TDOMNode; const AText: String; AShFlags: Byte;
  676. aLinkIdentifierMap: TLinkIdentifierMap): Byte;
  677. var
  678. Line, Last, p: PChar;
  679. El: TDOMElement;
  680. Procedure MaybeOutput;
  681. Var
  682. CurParent: TDomNode;
  683. begin
  684. If (Last<>Nil) then
  685. begin
  686. If (el<>Nil) then
  687. CurParent:=El
  688. else
  689. CurParent:=Parent;
  690. AppendText(CurParent,Last);
  691. El:=Nil;
  692. Last:=Nil;
  693. end;
  694. end;
  695. Function NewEl(Const ElType,Attr,AttrVal : DOMString) : TDomElement;
  696. begin
  697. Result:=CreateEl(Parent,ElType);
  698. Result[Attr]:=AttrVal;
  699. end;
  700. Function NewSpan(Const AttrVal : DOMString) : TDomElement;
  701. begin
  702. Result:=CreateEl(Parent,'span');
  703. Result['class']:=AttrVal;
  704. end;
  705. begin
  706. GetMem(Line, Length(AText) * 3 + 4);
  707. Try
  708. DoPascalHighlighting(AShFlags, PChar(AText), Line);
  709. Result := AShFlags;
  710. Last := Nil;
  711. p := Line;
  712. el:=nil;
  713. while p[0] <> #0 do
  714. begin
  715. if p[0] = LF_ESCAPE then
  716. begin
  717. p[0] := #0;
  718. MaybeOutput;
  719. case Ord(p[1]) of
  720. shDefault: El:=Nil;
  721. shInvalid: El:=newel('font','color','red');
  722. shSymbol : El:=newspan('sym');
  723. shKeyword: El:=newspan('kw');
  724. shComment: El:=newspan('cmt');
  725. shDirective: El:=newspan('dir');
  726. shNumbers: El:=newspan('num');
  727. shCharacters: El:=newspan('chr');
  728. shStrings: El:=newspan('str');
  729. shAssembler: El:=newspan('asm');
  730. end;
  731. Inc(P);
  732. end
  733. else If (Last=Nil) then
  734. Last:=P;
  735. Inc(p);
  736. end;
  737. MaybeOutput;
  738. Finally
  739. FreeMem(Line);
  740. end;
  741. end;
  742. procedure TBaseHTMLWriter.AppendSeeAlsoSection (AElement: TPasElement; DocNode: TDocNode) ;
  743. begin
  744. AppendSeeAlsoSection(aElement,ContentElement,DocNode);
  745. end;
  746. procedure TBaseHTMLWriter.AppendSeeAlsoSection(AElement: TPasElement; aParent: TDOMElement; DocNode: TDocNode);
  747. var
  748. Node: TDOMNode;
  749. TableEl, El, TREl, ParaEl, NewEl, DescrEl: TDOMElement;
  750. l,s,n: DOMString;
  751. IsFirstSeeAlso : Boolean;
  752. begin
  753. if Not (Assigned(DocNode) and Assigned(DocNode.SeeAlso)) then
  754. Exit;
  755. IsFirstSeeAlso := True;
  756. Node:=DocNode.SeeAlso.FirstChild;
  757. While Assigned(Node) do
  758. begin
  759. if (Node.NodeType=ELEMENT_NODE) and (Node.NodeName='link') then
  760. begin
  761. if IsFirstSeeAlso then
  762. begin
  763. IsFirstSeeAlso := False;
  764. AppendText(CreateH2(aParent), SDocSeeAlso);
  765. TableEl := CreateTable(aParent);
  766. end;
  767. El:=TDOMElement(Node);
  768. TREl:=CreateTR(TableEl);
  769. ParaEl:=CreatePara(CreateTD_vtop(TREl));
  770. l:=El['id'];
  771. if Assigned(Engine) and Engine.FalbackSeeAlsoLinks then
  772. s:= ResolveLinkIDUnStrict(UTF8ENcode(l))
  773. else
  774. s:= ResolveLinkID(UTF8ENcode(l));
  775. if Length(s)=0 then
  776. begin
  777. if assigned(module) then
  778. s:=UTF8Decode(module.name)
  779. else
  780. s:='?';
  781. if l='' then l:='<empty>';
  782. if Assigned(AElement) then
  783. N:=UTF8Decode(AElement.PathName)
  784. else
  785. N:='?';
  786. DoLog(SErrUnknownLinkID, [s,N,l]);
  787. LinkUnresolvedInc();
  788. NewEl := CreateEl(ParaEl,'b')
  789. end
  790. else
  791. NewEl := CreateLink(ParaEl,s);
  792. if Not IsDescrNodeEmpty(El) then
  793. begin
  794. PushOutputNode(NewEl);
  795. Try
  796. ConvertBaseShortList(AElement, El, True)
  797. Finally
  798. PopOutputNode;
  799. end;
  800. end
  801. else
  802. AppendText(NewEl,El['id']);
  803. l:=El['id'];
  804. DescrEl := Engine.FindShortDescr(AElement.GetModule,UTF8Encode(L));
  805. if Assigned(DescrEl) then
  806. begin
  807. AppendNbSp(CreatePara(CreateTD(TREl)), 2);
  808. ParaEl := CreatePara(CreateTD(TREl));
  809. ParaEl['class'] := 'cmt';
  810. PushOutputNode(ParaEl);
  811. try
  812. ConvertShort(AElement, DescrEl);
  813. finally
  814. PopOutputNode;
  815. end;
  816. end;
  817. end; // Link node
  818. Node := Node.NextSibling;
  819. end; // While
  820. end;
  821. procedure TBaseHTMLWriter.AppendExampleSection ( AElement: TPasElement; DocNode: TDocNode ) ;
  822. begin
  823. AppendExampleSection(AElement,ContentElement,DocNode);
  824. end;
  825. Procedure TBaseHTMLWriter.AppendExampleSection(AElement : TPasElement;aParent : TDOMElement; DocNode : TDocNode);
  826. var
  827. Node: TDOMNode;
  828. fn,s: String;
  829. f: Text;
  830. begin
  831. if not (Assigned(DocNode) and Assigned(DocNode.FirstExample)) then
  832. Exit;
  833. Node := DocNode.FirstExample;
  834. while Assigned(Node) do
  835. begin
  836. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'example') then
  837. begin
  838. fn:=Engine.GetExampleFilename(TDOMElement(Node));
  839. If (fn<>'') then
  840. begin
  841. AppendText(CreateH2(aParent), SDocExample);
  842. try
  843. Assign(f, FN);
  844. Reset(f);
  845. try
  846. PushOutputNode(aParent);
  847. DescrBeginCode(False, UTF8Encode(TDOMElement(Node)['highlighter']));
  848. while not EOF(f) do
  849. begin
  850. ReadLn(f, s);
  851. DescrWriteCodeLine(s);
  852. end;
  853. DescrEndCode;
  854. PopOutputNode;
  855. finally
  856. Close(f);
  857. end;
  858. except
  859. on e: Exception do
  860. begin
  861. e.Message := '[example] ' + e.Message;
  862. raise;
  863. end;
  864. end;
  865. end;
  866. end;
  867. Node := Node.NextSibling;
  868. end;
  869. end;
  870. procedure TBaseHTMLWriter.AppendFragment(aParentNode : TDOMElement; aStream : TStream);
  871. begin
  872. if (aStream<>Nil) then
  873. begin
  874. aStream.Position:=0;
  875. ReadXMLFragment(aParentNode,aStream);
  876. end;
  877. end;
  878. procedure TBaseHTMLWriter.AppendShortDescr ( AContext: TPasElement;
  879. Parent: TDOMNode; DocNode: TDocNode ) ;
  880. Var
  881. N : TDocNode;
  882. begin
  883. if Assigned(DocNode) then
  884. begin
  885. If (DocNode.Link<>'') then
  886. begin
  887. N:=Engine.FindLinkedNode(DocNode);
  888. If (N<>Nil) then
  889. DocNode:=N;
  890. end;
  891. If Assigned(DocNode.ShortDescr) then
  892. begin
  893. PushOutputNode(Parent);
  894. try
  895. if not ConvertShort(AContext,TDomElement(DocNode.ShortDescr)) then
  896. Warning(AContext, SErrInvalidShortDescr)
  897. finally
  898. PopOutputNode;
  899. end;
  900. end;
  901. end;
  902. end;
  903. procedure TBaseHTMLWriter.AppendShortDescr(Parent: TDOMNode; Element: TPasElement);
  904. begin
  905. AppendShortDescr(Element,Parent,Engine.FindDocNode(Element));
  906. end;
  907. procedure TBaseHTMLWriter.AppendShortDescrCell(Parent: TDOMNode; Element: TPasElement);
  908. var
  909. ParaEl: TDOMElement;
  910. begin
  911. if Assigned(Engine.FindShortDescr(Element)) then
  912. begin
  913. AppendNbSp(CreatePara(CreateTD(Parent)), 2);
  914. ParaEl := CreatePara(CreateTD(Parent));
  915. ParaEl['class'] := 'cmt';
  916. AppendShortDescr(ParaEl, Element);
  917. end;
  918. end;
  919. procedure TBaseHTMLWriter.AppendDescr(AContext: TPasElement; Parent: TDOMNode;
  920. DescrNode: TDOMElement; AutoInsertBlock: Boolean);
  921. begin
  922. if Assigned(DescrNode) then
  923. begin
  924. PushOutputNode(Parent);
  925. try
  926. ConvertDescr(AContext, DescrNode, AutoInsertBlock);
  927. finally
  928. PopOutputNode;
  929. end;
  930. end;
  931. end;
  932. procedure TBaseHTMLWriter.AppendDescrSection(AContext: TPasElement; Parent: TDOMNode; DescrNode: TDOMElement; const ATitle: AnsiString);
  933. begin
  934. AppendDescrSection(aContext,Parent,DescrNode,UTF8Decode(aTitle));
  935. end;
  936. procedure TBaseHTMLWriter.AppendDescrSection(AContext: TPasElement;
  937. Parent: TDOMNode; DescrNode: TDOMElement; const ATitle: DOMString);
  938. begin
  939. if not IsDescrNodeEmpty(DescrNode) then
  940. begin
  941. If (ATitle<>'') then // Can be empty for topic.
  942. AppendText(CreateH2(Parent), ATitle);
  943. AppendDescr(AContext, Parent, DescrNode, True);
  944. end;
  945. end;
  946. function TBaseHTMLWriter.AppendHyperlink(Parent: TDOMNode; Element: TPasElement): TDOMElement;
  947. var
  948. s: DOMString;
  949. UnitList: TFPList;
  950. i: Integer;
  951. ThisPackage: TLinkNode;
  952. begin
  953. if Not Assigned(Element) then
  954. begin
  955. Result := CreateWarning(Parent);
  956. AppendText(Result, '<NIL>');
  957. exit;
  958. end
  959. else if Element.InheritsFrom(TPasUnresolvedTypeRef) then
  960. begin
  961. s := ResolveLinkID(Element.Name);
  962. if Length(s) = 0 then
  963. begin
  964. { Try all packages }
  965. ThisPackage := Engine.RootLinkNode.FirstChild;
  966. while Assigned(ThisPackage) do
  967. begin
  968. s := ResolveLinkID(ThisPackage.Name + '.' + Element.Name);
  969. if Length(s) > 0 then
  970. break;
  971. ThisPackage := ThisPackage.NextSibling;
  972. end;
  973. if (Length(s) = 0) and Assigned(Module) then
  974. begin
  975. { Okay, then we have to try all imported units of the current module }
  976. UnitList := Module.InterfaceSection.UsesList;
  977. for i := UnitList.Count - 1 downto 0 do
  978. begin
  979. { Try all packages }
  980. ThisPackage := Engine.RootLinkNode.FirstChild;
  981. while Assigned(ThisPackage) do
  982. begin
  983. s := ResolveLinkID(ThisPackage.Name + '.' +
  984. TPasType(UnitList[i]).Name + '.' + Element.Name);
  985. if Length(s) > 0 then
  986. break;
  987. ThisPackage := ThisPackage.NextSibling;
  988. end;
  989. if length(s)=0 then
  990. s := ResolveLinkID('#rtl.System.' + Element.Name);
  991. if Length(s) > 0 then
  992. break;
  993. end;
  994. end;
  995. end;
  996. end
  997. else if Element is TPasEnumValue then
  998. s := ResolveLinkID(Element.Parent.PathName)
  999. else if Element is TPasAliasType then
  1000. begin
  1001. s := ResolveLinkID(TPasAliasType(Element).DestType.PathName);
  1002. // See if we find a page for the type alias ?
  1003. if (S='') then
  1004. s := ResolveLinkID(TPasAliasType(Element).Name)
  1005. end
  1006. else
  1007. s := ResolveLinkID(Element.PathName);
  1008. if Length(s) > 0 then
  1009. begin
  1010. Result := CreateLink(Parent, s);
  1011. AppendText(Result, Element.Name);
  1012. end
  1013. else
  1014. begin
  1015. Result := CreateEl(Parent,'span');
  1016. if Element is TPasAliasType then
  1017. AppendText(Result, TPasAliasType(Element).DestType.Name)
  1018. else
  1019. AppendText(Result, Element.Name); // unresolved items
  1020. end;
  1021. end;
  1022. procedure TBaseHTMLWriter.AppendSourceRef(aParent : TDOMElement; AElement: TPasElement);
  1023. begin
  1024. AppendText(CreatePara(aParent), Format(SDocSourcePosition,
  1025. [ExtractFileName(AElement.SourceFilename), AElement.SourceLinenumber]));
  1026. end;
  1027. end.