chmsitemap.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. { Copyright (C) <2005> <Andrew Haines> chmsitemap.pas
  2. This library is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; if not, write to the Free Software Foundation,
  12. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  13. }
  14. {
  15. See the file COPYING.FPC, included in this distribution,
  16. for details about the copyright.
  17. }
  18. unit chmsitemap;
  19. {$mode Delphi}{$H+}
  20. {define preferlower}
  21. interface
  22. uses
  23. Classes, SysUtils, fasthtmlparser, contnrs, strutils, generics.collections;
  24. type
  25. TChmSiteMapItems = class; // forward
  26. TChmSiteMap = class;
  27. TChmSiteMapItem = class;
  28. { TChmSiteMapItem }
  29. TChmSiteMapItemAttrName = (siteattr_NONE,
  30. siteattr_KEYWORD, // alias for name in sitemap
  31. siteattr_NAME,
  32. siteattr_LOCAL,
  33. siteattr_URL,
  34. siteattr_TYPE,
  35. siteattr_SEEALSO,
  36. siteattr_IMAGENUMBER,
  37. siteattr_NEW,
  38. siteattr_COMMENT,
  39. siteattr_MERGE,
  40. siteattr_FRAMENAME,
  41. siteattr_WINDOWNAME,
  42. siteattr_WINDOW_STYLES,
  43. siteattr_EXWINDOW_STYLES,
  44. siteattr_FONT,
  45. siteattr_IMAGELIST,
  46. siteattr_IMAGETYPE
  47. );
  48. { TChmSiteMapSubItem }
  49. TChmSiteMapGenerationOptions = (Default,emitkeyword);
  50. TChmSiteMapSubItem = class(TPersistent)
  51. private
  52. FName,
  53. FType,
  54. FLocal,
  55. FUrl,
  56. FSeeAlso : String;
  57. FOwner : TChmSiteMapItem;
  58. public
  59. constructor Create(AOwner: TChmSiteMapItem);
  60. destructor Destroy; override;
  61. published
  62. property Name : String read FName write FName; //hhk
  63. property ItemType : String read FType write FType; //both
  64. property Local: String read FLocal write FLocal; //both
  65. property URL : String read FURL write FURL; //both
  66. property SeeAlso: String read FSeeAlso write FSeeAlso; //hhk
  67. end;
  68. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  69. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  70. TChmSiteMapItem = class(TPersistent)
  71. private
  72. FChildren: TChmSiteMapItems;
  73. FComment: String;
  74. FImageNumber: Integer;
  75. FIncreaseImageIndex: Boolean;
  76. FOwner: TChmSiteMapItems;
  77. FName : String;
  78. FMerge : String;
  79. FFrameName : String;
  80. FWindowName : String;
  81. FSubItems : TObjectList;
  82. function getlocal: string;
  83. function getseealso:string;
  84. function getsubitem( index : integer): TChmSiteMapSubItem;
  85. function getsubitemcount: integer;
  86. procedure SetChildren(const AValue: TChmSiteMapItems);
  87. public
  88. constructor Create(AOwner: TChmSiteMapItems);
  89. destructor Destroy; override;
  90. procedure AddName(const Name:string);
  91. procedure AddLocal(const Local:string);
  92. procedure AddSeeAlso(const SeeAlso:string);
  93. procedure AddURL(const URL:string);
  94. procedure AddType(const AType:string);
  95. procedure Sort(Compare: TListSortCompare);
  96. published
  97. property Children: TChmSiteMapItems read FChildren write SetChildren;
  98. property Name: String read FName write FName;
  99. property ImageNumber: Integer read FImageNumber write FImageNumber default -1;
  100. property IncreaseImageIndex: Boolean read FIncreaseImageIndex write FIncreaseImageIndex;
  101. property Comment: String read FComment write FComment;
  102. property Owner: TChmSiteMapItems read FOwner;
  103. property Keyword : string read fname; // deprecated; // Use name, sitemaps don't store the difference.
  104. property Local : string read getlocal; // deprecated; // should work on ALL pairs
  105. property Text : string read fname write fname; // deprecated; // should work on ALL pairs
  106. property SeeAlso : string read getseealso; // deprecated; // should work on ALL pairs
  107. property FrameName: String read FFrameName write FFrameName;
  108. property WindowName: String read FWindowName write FWindowName;
  109. property Merge: String read FMerge write FMerge;
  110. property SubItem[ index :integer]:TChmSiteMapSubItem read getsubitem;
  111. property SubItemcount :integer read getsubitemcount;
  112. end;
  113. { TChmSiteMapItems }
  114. TChmSiteMapItems = class(TPersistent)
  115. private
  116. FInternalData: Dword;
  117. FList: TList;
  118. FOwner: TChmSiteMap;
  119. FParentItem: TChmSiteMapItem;
  120. function GetCount: Integer;
  121. function GetItem(AIndex: Integer): TChmSiteMapItem;
  122. function getparentname: String;
  123. procedure SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
  124. public
  125. constructor Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
  126. destructor Destroy; override;
  127. procedure Delete(AIndex: Integer);
  128. function Add(AItem: TChmSiteMapItem): Integer;
  129. function NewItem: TChmSiteMapItem;
  130. function Insert(AItem: TChmSiteMapItem; AIndex: Integer): Integer;
  131. procedure Clear;
  132. procedure Sort(Compare: TListSortCompare);
  133. property Item[AIndex: Integer]: TChmSiteMapItem read GetItem write SetItem;
  134. property Count: Integer read GetCount;
  135. property ParentItem: TChmSiteMapItem read FParentItem;
  136. property Owner: TChmSiteMap read FOwner;
  137. property InternalData: Dword read FInternalData write FInternalData;
  138. property ParentName : String read getparentname;
  139. end;
  140. { TChmSiteMapTree }
  141. TSiteMapType = (stTOC, stIndex);
  142. TSiteMapTag = (smtUnknown, smtNone, smtHTML, smtHEAD, smtBODY);
  143. TSiteMapTags = set of TSiteMapTag;
  144. TSiteMapBodyTag = (smbtUnknown, smbtNone, smbtUL, smbtLI, smbtOBJECT, smbtPARAM);
  145. TSiteMapBodyTags = set of TSiteMapBodyTag;
  146. TLIObjectParamType = (ptName, ptLocal, ptKeyword);
  147. TChmSiteMap = class
  148. private
  149. FAutoGenerated: Boolean;
  150. FBackgroundColor: LongInt;
  151. FCurrentItems: TChmSiteMapItems;
  152. FExWindowStyles: LongInt;
  153. FFont: String;
  154. FForegroundColor: LongInt;
  155. FFrameName: String;
  156. FImageList: String;
  157. FImageWidth: Integer;
  158. FSiteMapTags: TSiteMapTags;
  159. FSiteMapBodyTags: TSiteMapBodyTags;
  160. FHTMLParser: THTMLParser;
  161. FItems: TChmSiteMapItems;
  162. FSiteMapType: TSiteMapType;
  163. FUseFolderImages: Boolean;
  164. FWindowName: String;
  165. FLevel: Integer;
  166. FLevelForced: Boolean;
  167. FWindowStyles: LongInt;
  168. FLoadDict : TDictionary<String,TChmSiteMapItemAttrName>;
  169. fChmSiteMapGenerationOptions:TChmSiteMapGenerationOptions;
  170. procedure SetItems(const AValue: TChmSiteMapItems);
  171. procedure CheckLookup;
  172. protected
  173. procedure FoundTag (ACaseInsensitiveTag, AActualTag: string);
  174. procedure FoundText(AText: string);
  175. public
  176. constructor Create(AType: TSiteMapType);
  177. destructor Destroy; override;
  178. Procedure Sort(Compare: TListSortCompare);
  179. procedure LoadFromFile(AFileName: String);
  180. procedure LoadFromStream(AStream: TStream);
  181. procedure SaveToFile(AFileName:String);
  182. procedure SaveToStream(AStream: TStream);
  183. property Items: TChmSiteMapItems read FItems write SetItems;
  184. property SiteMapType: TSiteMapType read FSiteMapType;
  185. // SiteMap properties. most of these are invalid for the index
  186. property FrameName: String read FFrameName write FFrameName;
  187. property WindowName: String read FWindowName write FWindowName;
  188. property ImageList: String read FImageList write FImageList;
  189. property ImageWidth: Integer read FImageWidth write FImageWidth;
  190. property BackgroundColor: LongInt read FBackgroundColor write FBackgroundColor;
  191. property ForegroundColor: LongInt read FForegroundColor write FForegroundColor;
  192. property ExWindowStyles: LongInt read FExWindowStyles write FExWindowStyles;
  193. property WindowStyles: LongInt read FWindowStyles write FWindowStyles;
  194. property UseFolderImages: Boolean read FUseFolderImages write FUseFolderImages;
  195. property Font: String read FFont write FFont;
  196. property AutoGenerated: Boolean read FAutoGenerated write FAutoGenerated;
  197. property ChmSiteMapGenerationOptions : TChmSiteMapGenerationOptions read fChmSiteMapGenerationOptions write fChmSiteMapGenerationOptions;
  198. end;
  199. function indexitemcompare(Item1, Item2: Pointer): Integer;
  200. implementation
  201. uses HTMLUtil;
  202. const sitemapkws : array[TChmSiteMapItemAttrName] of string = (
  203. '',
  204. 'KEYWORD',
  205. 'NAME',
  206. 'LOCAL',
  207. 'URL',
  208. 'TYPE',
  209. 'SEE ALSO',
  210. 'IMAGENUMBER',
  211. 'NEW',
  212. 'COMMENT',
  213. 'MERGE',
  214. 'FRAMENAME',
  215. 'WINDOWNAME',
  216. 'WINDOW STYLES',
  217. 'EXWINDOW STYLES',
  218. 'FONT',
  219. 'IMAGELIST',
  220. 'IMAGETYPE');
  221. function indexitemcompare(Item1, Item2: Pointer): Integer;
  222. begin
  223. Result := naturalComparetext(LowerCase(TChmSiteMapItem(item1).name), Lowercase(TChmSiteMapItem(item2).name));
  224. end;
  225. { TChmSiteMapSubItem }
  226. constructor TChmSiteMapSubItem.Create(AOwner: TChmSiteMapItem);
  227. begin
  228. FOwner:=AOwner;
  229. end;
  230. destructor TChmSiteMapSubItem.Destroy;
  231. begin
  232. inherited Destroy;
  233. end;
  234. { TChmSiteMapTree }
  235. procedure TChmSiteMap.SetItems(const AValue: TChmSiteMapItems);
  236. begin
  237. if FItems=AValue then exit;
  238. FItems:=AValue;
  239. end;
  240. procedure TChmSiteMap.CheckLookup;
  241. var en : TChmSiteMapItemAttrName;
  242. begin
  243. if assigned(FLoadDict) then
  244. exit;
  245. FLoadDict :=TDictionary<String,TChmSiteMapItemAttrName>.Create;
  246. for en:=succ(low(en)) to high(en) do
  247. FLoadDict.add(sitemapkws[en],en);
  248. end;
  249. procedure TChmSiteMap.FoundTag(ACaseInsensitiveTag, AActualTag: string);
  250. procedure NewSiteMapItem;
  251. begin
  252. FCurrentItems.Add(TChmSiteMapItem.Create(FCurrentItems));
  253. end;
  254. function ActiveItem: TChmSiteMapItem;
  255. begin
  256. if FCurrentItems.Count=0 then
  257. NewSiteMapItem;
  258. Result := FCurrentItems.Item[FCurrentItems.Count-1]
  259. end;
  260. procedure IncreaseULevel;
  261. begin
  262. if FCurrentItems = nil then FCurrentItems := Items
  263. else begin
  264. //WriteLn('NewLevel. Count = ', FCurrentItems.Count, ' Index = ',Items.Count-1);
  265. FCurrentItems := ActiveItem.Children;
  266. end;
  267. Inc(FLevel);
  268. end;
  269. procedure DecreaseULevel;
  270. begin
  271. if Assigned(FCurrentItems) and Assigned(FCurrentItems.ParentItem) then
  272. FCurrentItems := FCurrentItems.ParentItem.Owner
  273. else FCurrentItems := nil;
  274. Dec(FLevel);
  275. end;
  276. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  277. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  278. var
  279. TagName,
  280. TagAttributeName,
  281. TagAttributeValue: String;
  282. isParam,IsMerged : string;
  283. TagAttrName : TChmSiteMapItemAttrName;
  284. begin
  285. TagName := GetTagName(ACaseInsensitiveTag);
  286. if TagName = 'UL' then begin
  287. IncreaseULevel;
  288. end
  289. else if TagName = '/UL' then begin
  290. DecreaseULevel;
  291. end
  292. else if (TagName = 'LI') and (FLevel = 0) then
  293. FLevelForced := True
  294. else if TagName = 'OBJECT' then begin
  295. Include(FSiteMapBodyTags, smbtOBJECT);
  296. if FLevelForced then
  297. IncreaseULevel;
  298. If FLevel > 0 then // if it is zero it is the site properties
  299. NewSiteMapItem;
  300. end
  301. else if TagName = '/OBJECT' then begin
  302. Exclude(FSiteMapBodyTags, smbtOBJECT);
  303. if FLevelForced then
  304. begin
  305. DecreaseULevel;
  306. FLevelForced := False;
  307. end;
  308. end
  309. else begin // we are the properties of the object tag
  310. if (smbtOBJECT in FSiteMapBodyTags) then
  311. begin
  312. if (FLevel > 0 ) then
  313. begin
  314. if LowerCase(GetTagName(AActualTag)) = 'param' then begin
  315. TagAttributeName := GetVal(AActualTag, 'name');
  316. TagAttributeValue := GetVal(AActualTag, 'value');
  317. // a hash reduces comparisons and casing, and generics make it easy.
  318. if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
  319. TagAttrName:=siteattr_none;
  320. if TagAttrName <> siteattr_none then begin
  321. case TagAttrName of
  322. siteattr_KEYWORD,
  323. siteattr_NAME : Activeitem.AddName(TagAttributeValue);
  324. siteattr_LOCAL : ActiveItem.AddLocal(TagAttributeValue);
  325. siteattr_URL : ActiveItem.AddURL (TagAttributeValue);
  326. siteattr_TYPE : ActiveItem.AddType (TagAttributeValue);
  327. siteattr_SEEALSO : ActiveItem.AddSeeAlso(TagAttributeValue);
  328. siteattr_IMAGENUMBER : ActiveItem.ImageNumber := StrToInt(TagAttributeValue);
  329. siteattr_NEW : ActiveItem.IncreaseImageIndex := (LowerCase(TagAttributeValue) = 'yes');
  330. siteattr_COMMENT : ActiveItem.Comment := TagAttributeValue;
  331. siteattr_MERGE : ActiveItem.Merge:= TagAttributeValue;
  332. siteattr_FRAMENAME : ActiveItem.FrameName:=TagAttributeValue;
  333. siteattr_WINDOWNAME : ActiveItem.WindowName:=TagAttributeValue;
  334. end;
  335. end;
  336. end;
  337. end
  338. else
  339. begin // object and level is zero?
  340. if LowerCase(GetTagName(AActualTag)) = 'param' then begin
  341. begin
  342. TagAttributeName := uppercase(GetVal(AActualTag, 'name'));
  343. TagAttributeValue := GetVal(AActualTag, 'value');
  344. if not FLoadDict.trygetvalue(uppercase(TagAttributeName),TagAttrName) then
  345. TagAttrName:=siteattr_none;
  346. if TagAttrName <> siteattr_none then begin
  347. case TagAttrName of
  348. siteattr_FRAMENAME : FrameName:=TagAttributeValue;
  349. siteattr_WINDOWNAME : WindowName:=TagAttributeValue;
  350. siteattr_WINDOW_STYLES : WindowStyles:=StrToIntDef(TagAttributeValue,0);
  351. siteattr_EXWINDOW_STYLES : ExWindowStyles:=StrToIntDef(TagAttributeValue,0);
  352. siteattr_FONT : Font:=TagAttributeValue;
  353. siteattr_IMAGELIST : ImageList:=TagAttributeValue;
  354. siteattr_IMAGETYPE : UseFolderImages:=uppercase(TagAttributeValue)='FOLDER';
  355. end;
  356. end;
  357. // writeln('0:',flevel,' ' ,aactualtag,' ',tagname,' ' ,tagattributename, ' ' ,tagattributevalue);
  358. end;
  359. end;
  360. end;
  361. end;
  362. end;
  363. // end; {body}
  364. //end {html}
  365. end;
  366. procedure TChmSiteMap.FoundText(AText: string);
  367. begin
  368. //WriteLn('TEXT:', AText);
  369. end;
  370. constructor TChmSiteMap.Create(AType: TSiteMapType);
  371. begin
  372. Inherited Create;
  373. FSiteMapType := AType;
  374. FSiteMapTags := [smtNone];
  375. FSiteMapBodyTags := [smbtNone];
  376. FHTMLParser:=nil;
  377. FItems := TChmSiteMapItems.Create(Self, nil); ;
  378. end;
  379. destructor TChmSiteMap.Destroy;
  380. begin
  381. if Assigned(FHTMLParser) then FHTMLParser.Free;
  382. FItems.Free;
  383. FLoadDict.Free;
  384. Inherited Destroy;
  385. end;
  386. procedure TChmSiteMap.Sort(Compare: TListSortCompare);
  387. begin
  388. FItems.sort(compare);
  389. end;
  390. procedure TChmSiteMap.LoadFromFile(AFileName: String);
  391. var
  392. Buffer: String;
  393. TmpStream: TMemoryStream;
  394. begin
  395. CheckLookup;
  396. if Assigned(FHTMLParser) then FHTMLParser.Free;
  397. TmpStream := TMemoryStream.Create;
  398. try
  399. TmpStream.LoadFromFile(AFileName);
  400. SetLength(Buffer, TmpStream.Size);
  401. TmpStream.Position := 0;
  402. TmpStream.Read(Buffer[1], TmpStream.Size);
  403. finally
  404. TmpStream.Free;
  405. end;
  406. FHTMLParser := THTMLParser.Create(Buffer);
  407. try
  408. FHTMLParser.OnFoundTag := FoundTag;
  409. FHTMLParser.OnFoundText := FoundText;
  410. FHTMLParser.Exec;
  411. finally
  412. FreeAndNil(FHTMLParser);
  413. end;
  414. end;
  415. procedure TChmSiteMap.LoadFromStream(AStream: TStream);
  416. var
  417. Buffer: String;
  418. begin
  419. CheckLookup;
  420. if Assigned(FHTMLParser) then FHTMLParser.Free;
  421. SetLength(Buffer, AStream.Size-AStream.Position);
  422. if AStream.Read(Buffer[1], AStream.Size-AStream.Position) > 0 then begin;
  423. FHTMLParser := THTMLParser.Create(Buffer);
  424. FHTMLParser.OnFoundTag := FoundTag;
  425. FHTMLParser.OnFoundText := FoundText;
  426. FHTMLParser.Exec;
  427. FreeAndNil(FHTMLParser);
  428. end;
  429. end;
  430. procedure TChmSiteMap.SaveToFile(AFileName:String);
  431. var
  432. fs : TFileStream;
  433. begin
  434. fs:=TFileStream.Create(AFileName,fmcreate);
  435. try
  436. SaveToStream(fs);
  437. finally
  438. fs.free;
  439. end;
  440. end;
  441. // hhk items: Merge | ([Name] ([Name] [Type...] [Local [URL] | See Also])... [FrameName] [WindowName] [Comment])
  442. // hhc items: Merge | ([Name] ([Type...] [Local] [URL])... [FrameName] [WindowName] [Comment] [New] [ImageNumber])
  443. procedure TChmSiteMap.SaveToStream(AStream: TStream);
  444. var
  445. Indent: Integer;
  446. procedure WriteString(AString: String);
  447. var
  448. I: Integer;
  449. begin
  450. for I := 0 to Indent-1 do AStream.WriteByte(Byte(' '));
  451. AStream.Write(AString[1], Length(AString));
  452. AStream.WriteByte(10);
  453. end;
  454. procedure WriteStringNoIndent(AString: String);
  455. var
  456. I: Integer;
  457. begin
  458. AStream.Write(AString[1], Length(AString));
  459. end;
  460. procedure WriteParam(AName: String; AValue: String);
  461. begin
  462. WriteString('<param name="'+AName+'" value="'+AValue+'">');
  463. end;
  464. procedure WriteEntries(AItems: TChmSiteMapItems);
  465. var
  466. I,J : Integer;
  467. Item: TChmSiteMapItem;
  468. Sub : TChmSiteMapSubItem;
  469. lemitkeyword : boolean;
  470. begin
  471. lemitkeyword:=ChmSiteMapGenerationOptions=emitkeyword;
  472. for I := 0 to AItems.Count-1 do begin
  473. Item := AItems.Item[I];
  474. {$ifdef preferlower}
  475. WriteString('<li> <object type="text/sitemap">');
  476. {$else}
  477. WriteString('<LI> <OBJECT type="text/sitemap">');
  478. {$endif}
  479. Inc(Indent, 8);
  480. if Item.Name<>'' then
  481. begin
  482. if lemitkeyword then
  483. WriteParam('Keyword', item.Name)
  484. else
  485. WriteParam('Name', Item.Name);
  486. end;
  487. if item.FSubItems.count>0 then
  488. begin
  489. For j:=0 to item.FSubItems.count-1 do
  490. begin
  491. Sub:=TChmSiteMapSubItem(item.fsubitems[j]);
  492. if Sub.Name <> '' then WriteParam('Name', Sub.Name);
  493. if Sub.ItemType <> '' then WriteParam('Type', Sub.ItemType);
  494. if Sub.Local <> '' then WriteParam('Local', Sub.Local);
  495. if Sub.URL <> '' then WriteParam('URL', Sub.URL);
  496. if Sub.SeeAlso <> '' then WriteParam('See Also', Sub.SeeAlso);
  497. end;
  498. end;
  499. if Item.FrameName <> '' then WriteParam('FrameName', Item.FrameName);
  500. if Item.WindowName <> '' then WriteParam('WindowName', Item.WindowName);
  501. if Item.Comment <> '' then WriteParam('Comment', Item.Comment);
  502. if (SiteMapType = stTOC) and (Item.IncreaseImageIndex) then
  503. WriteParam('New', 'yes'); // is this a correct value?
  504. if (SiteMapType = stTOC) and (Item.ImageNumber <> -1) then
  505. WriteParam('ImageNumber', IntToStr(Item.ImageNumber));
  506. Dec(Indent, 3);
  507. {$ifdef preferlower}
  508. WriteString('</object>');
  509. {$else}
  510. WriteString('</OBJECT>');
  511. {$endif}
  512. Dec(Indent, 5);
  513. // Now Sub Entries
  514. if Item.Children.Count > 0 then begin
  515. {$ifdef preferlower}
  516. WriteString('<ul>');
  517. {$else}
  518. WriteString('<UL> ');
  519. {$endif}
  520. Inc(Indent, 8);
  521. WriteEntries(Item.Children);
  522. Dec(Indent, 8);
  523. {$ifdef preferlower}
  524. WriteString('</ul>');
  525. {$else}
  526. WriteString('</UL>'); //writestringnoident
  527. {$endif}
  528. end;
  529. end;
  530. end;
  531. begin
  532. Indent := 0;
  533. WriteString('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">');
  534. WriteString('<HTML>');
  535. WriteString('<HEAD>');
  536. WriteString('<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">'); // Should we change this?
  537. WriteString('<!-- Sitemap 1.0 -->');
  538. WriteString('</HEAD><BODY>');
  539. // Site Properties
  540. WriteString('<OBJECT type="text/site properties">');
  541. Inc(Indent, 8);
  542. if SiteMapType = stTOC then begin
  543. if FrameName <> '' then WriteParam('FrameName', FrameName);
  544. if WindowName <> '' then WriteParam('WindowName', WindowName);
  545. if ImageList <> '' then WriteParam('ImageList', ImageList);
  546. if ImageWidth > 0 then WriteParam('Image Width', IntToStr(ImageWidth));
  547. if BackgroundColor <> 0 then WriteParam('Background', hexStr(BackgroundColor, 4));
  548. if ForegroundColor <> 0 then WriteParam('Foreground', hexStr(ForegroundColor, 4));
  549. if ExWindowStyles <> 0 then WriteParam('ExWindow Styles', hexStr(ExWindowStyles, 4));
  550. if WindowStyles <> 0 then WriteParam('Window Styles', hexStr(WindowStyles, 4));
  551. if UseFolderImages then WriteParam('ImageType', 'Folder');
  552. end;
  553. // both TOC and Index have font
  554. if Font <> '' then
  555. WriteParam('Font', Font);
  556. Dec(Indent, 8);
  557. WriteString('</OBJECT>');
  558. // And now the items
  559. if Items.Count > 0 then begin
  560. WriteString('<UL>');
  561. Inc(Indent, 8);
  562. // WriteEntries
  563. WriteEntries(Items);
  564. Dec(Indent, 8);
  565. WriteString('</UL>');
  566. end;
  567. WriteString('</BODY></HTML>');
  568. AStream.Size := AStream.Position;
  569. end;
  570. { TChmSiteMapItem }
  571. procedure TChmSiteMapItem.SetChildren(const AValue: TChmSiteMapItems);
  572. begin
  573. if FChildren = AValue then exit;
  574. FChildren := AValue;
  575. end;
  576. function TChmSiteMapItem.getlocal: string;
  577. begin
  578. result:='';
  579. if FSubItems.count>0 then
  580. result:=TChmSiteMapSubItem(FSubItems[0]).local;
  581. end;
  582. function TChmSiteMapItem.getseealso: string;
  583. begin
  584. result:='';
  585. if FSubItems.count>0 then
  586. result:=TChmSiteMapSubItem(FSubItems[FSubItems.count-1]).SeeAlso;
  587. end;
  588. function TChmSiteMapItem.getsubitem( index : integer): TChmSiteMapSubItem;
  589. begin
  590. result:=nil;
  591. if index<FSubItems.count then
  592. result:=TChmSiteMapSubItem(FSubItems[index]);
  593. end;
  594. function TChmSiteMapItem.getsubitemcount: integer;
  595. begin
  596. result:=FSubItems.count;
  597. end;
  598. constructor TChmSiteMapItem.Create(AOwner: TChmSiteMapItems);
  599. begin
  600. Inherited Create;
  601. FOwner := AOwner;
  602. FChildren := TChmSiteMapItems.Create(Owner.Owner, Self);
  603. FSubItems := TObjectList.Create(true);
  604. imagenumber:=-1;
  605. end;
  606. destructor TChmSiteMapItem.Destroy;
  607. begin
  608. fsubitems.Free;
  609. FChildren.Free;
  610. Inherited Destroy;
  611. end;
  612. procedure TChmSiteMapItem.AddName(const Name: string);
  613. var sub :TChmSiteMapSubItem;
  614. begin
  615. if fname='' then
  616. fname:=name
  617. else
  618. begin
  619. sub :=TChmSiteMapSubItem.create(self);
  620. FSubItems.add(sub);
  621. sub.Name:=Name;
  622. end;
  623. end;
  624. procedure TChmSiteMapItem.AddLocal(const Local: string);
  625. var sub :TChmSiteMapSubItem;
  626. addnew : boolean;
  627. begin
  628. if fsubitems.count>0 then
  629. begin
  630. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  631. if sub.FLocal<>'' then
  632. begin
  633. sub.flocal:=local;
  634. exit;
  635. end;
  636. end;
  637. sub :=TChmSiteMapSubItem.create(self);
  638. FSubItems.add(sub);
  639. // sub.name:=name;
  640. sub.Local:=Local;
  641. end;
  642. procedure TChmSiteMapItem.AddSeeAlso(const SeeAlso: string);
  643. // see also is mutually exclusive with "local url", so addition procedure is same as "local"
  644. var sub :TChmSiteMapSubItem;
  645. begin
  646. if fsubitems.count>0 then
  647. begin
  648. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  649. if sub.FSeeAlso<>'' then
  650. begin
  651. sub.FSeeAlso:=SeeAlso;
  652. exit;
  653. end;
  654. end;
  655. sub :=TChmSiteMapSubItem.create(self);
  656. FSubItems.add(sub);
  657. sub.FSeeAlso:=SeeAlso;
  658. end;
  659. procedure TChmSiteMapItem.AddURL(const URL: string);
  660. var sub :TChmSiteMapSubItem;
  661. begin
  662. if fsubitems.count>0 then
  663. begin
  664. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  665. if sub.FURL<>'' then
  666. begin
  667. sub.fURL:=URL;
  668. exit;
  669. end;
  670. end
  671. { else not possible according to chmspec. An URL must always follow a "local" item}
  672. end;
  673. procedure TChmSiteMapItem.AddType(const AType: string);
  674. // in Tocs, Type can be the first is the same as local
  675. var sub :TChmSiteMapSubItem;
  676. begin
  677. if fsubitems.count>0 then
  678. begin
  679. sub:=TChmSiteMapSubItem(fsubitems[FSubItems.count-1]);
  680. if sub.ItemType<>'' then
  681. begin
  682. sub.ItemType:=AType;
  683. exit;
  684. end;
  685. end;
  686. sub :=TChmSiteMapSubItem.create(self);
  687. FSubItems.add(sub);
  688. sub.ItemType:=AType;
  689. end;
  690. procedure TChmSiteMapItem.Sort(Compare: TListSortCompare);
  691. begin
  692. FChildren.sort(compare);
  693. end;
  694. { TChmSiteMapItems }
  695. function TChmSiteMapItems.GetItem(AIndex: Integer): TChmSiteMapItem;
  696. begin
  697. Result := TChmSiteMapItem(FList.Items[AIndex]);
  698. end;
  699. function TChmSiteMapItems.getparentname: String;
  700. begin
  701. result:='Not assigned';
  702. if assigned(fparentitem) then
  703. begin
  704. result:=FParentItem.name;
  705. end;
  706. end;
  707. function TChmSiteMapItems.GetCount: Integer;
  708. begin
  709. Result := FList.Count;
  710. end;
  711. procedure TChmSiteMapItems.SetItem(AIndex: Integer; const AValue: TChmSiteMapItem);
  712. begin
  713. FList.Items[AIndex] := AValue;
  714. end;
  715. constructor TChmSiteMapItems.Create(AOwner: TChmSiteMap; AParentItem: TChmSiteMapItem);
  716. begin
  717. FList := TList.Create;
  718. FParentItem := AParentItem;
  719. FOwner := AOwner;
  720. FInternalData := maxLongint;
  721. end;
  722. destructor TChmSiteMapItems.Destroy;
  723. begin
  724. Clear;
  725. FList.Free;
  726. inherited Destroy;
  727. end;
  728. procedure TChmSiteMapItems.Delete(AIndex: Integer);
  729. begin
  730. Item[AIndex].Free;
  731. FList.Delete(AIndex);
  732. end;
  733. function TChmSiteMapItems.Add(AItem: TChmSiteMapItem): Integer;
  734. begin
  735. Result := FList.Add(AItem);
  736. end;
  737. function TChmSiteMapItems.NewItem: TChmSiteMapItem;
  738. begin
  739. Result := TChmSiteMapItem.Create(Self);
  740. Add(Result);
  741. end;
  742. function TChmSiteMapItems.Insert(AItem: TChmSiteMapItem; AIndex: Integer): Integer;
  743. begin
  744. Result := AIndex;
  745. FList.Insert(AIndex, AItem);
  746. end;
  747. procedure TChmSiteMapItems.Clear;
  748. var
  749. I: LongInt;
  750. begin
  751. for I := Count-1 downto 0 do Delete(I);
  752. end;
  753. procedure TChmSiteMapItems.Sort(Compare: TListSortCompare);
  754. var I :Integer;
  755. begin
  756. FList.Sort(Compare);
  757. for i:=0 to flist.Count-1 do
  758. TChmSiteMapItem(flist[i]).sort(Compare)
  759. end;
  760. end.