formgen.pas 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406
  1. unit formgen;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, sax, sax_html, fpjson, pascodegen;
  6. Type
  7. TSpecialMethod = (smConstructor,smBindElements,smBindElementEvents);
  8. TSpecialMethods = Set of TSpecialMethod;
  9. TFormOption = (foEvents,foFormFile,foBindInConstructor);
  10. TFormOptions = Set of TFormOption;
  11. { THTML2ClassOptions }
  12. THTML2ClassOptions = Class (TPersistent)
  13. Private
  14. FExcludeElements: TStrings;
  15. FFormOptions: TFormOptions;
  16. FMethods : Array[1..3] of TSpecialMethods;
  17. FBools : Array[1..2] of Boolean;
  18. FStrings : Array[1..10] of String;
  19. function GetB(AIndex: Integer): Boolean;
  20. function GetMethods(AIndex: Integer): TSpecialMethods;
  21. function GetS(AIndex: Integer): String;
  22. procedure SetB(AIndex: Integer; AValue: Boolean);
  23. procedure SetExcludeElements(AValue: TStrings);
  24. procedure SetMethods(AIndex: Integer; AValue: TSpecialMethods);
  25. procedure SetS(AIndex: Integer; AValue: String);
  26. Public
  27. Constructor Create;
  28. Destructor Destroy; override;
  29. Procedure Reset; virtual;
  30. Procedure toJSON(aObject : TJSONObject);
  31. Procedure FromJSON(aObject : TJSONObject);
  32. Function asJSON(Formatted : Boolean) : String;
  33. Property OverrideMethods : TSpecialMethods index 1 Read GetMethods Write SetMethods;
  34. Property AddMethods : TSpecialMethods index 2 Read GetMethods Write SetMethods;
  35. Property VirtualMethods : TSpecialMethods index 3 Read GetMethods Write SetMethods;
  36. Property FormOptions : TFormOptions Read FFormOptions Write FFormOptions;
  37. Property ParentClassName : String Index 1 Read GetS Write SetS;
  38. Property GetElementFunction : String Index 2 Read GetS Write SetS;
  39. Property EventSignature : String Index 3 Read GetS Write SetS;
  40. Property EventModifiers : String Index 4 Read GetS Write SetS;
  41. Property ConstructorArgs : String Index 5 Read GetS Write SetS;
  42. Property BelowID : String Index 6 Read GetS Write SetS;
  43. Property HTMLFileName : String Index 7 Read GetS Write SetS;
  44. Property TagMapFileName : String Index 8 Read GetS Write SetS;
  45. Property FormClassname : String Index 9 Read GetS Write SetS;
  46. Property ExtraUnits: String index 10 Read GetS Write SetS;
  47. Property UseDefaultElements : Boolean Index 1 Read GetB Write SetB;
  48. Property AddHTMLToProject : Boolean Index 2 Read GetB Write SetB;
  49. Property ExcludeElements : TStrings Read FExcludeElements Write SetExcludeElements;
  50. end;
  51. Type
  52. TLogEvent = Procedure (Sender : TObject; Const Msg : String) of object;
  53. { TFormElement }
  54. TFormElement = Class(TCollectionItem)
  55. private
  56. FHTMLID: String;
  57. FName: String;
  58. FType: String;
  59. FEvents : TStrings;
  60. function GetEvents: TStrings;
  61. function getName: String;
  62. procedure SetEvents(AValue: TStrings);
  63. Public
  64. Destructor Destroy; override;
  65. Function HasEvents : Boolean;
  66. Procedure Assign(Source : TPersistent); override;
  67. Published
  68. Property Name : String Read getName Write FName;
  69. Property HTMLID : String Read FHTMLID Write FHTMLID;
  70. Property ElementType : String Read FType Write FType;
  71. Property Events : TStrings Read GetEvents Write SetEvents;
  72. end;
  73. { TFormElementList }
  74. TFormElementList = CLass(TCollection)
  75. private
  76. function GetEl(aIndex : Integer): TFormElement;
  77. Public
  78. Function Add(Const aName : string) : TFormElement;
  79. Function IndexOf(Const aName : string) : Integer;
  80. Function Find(Const aName : string) : TFormElement;
  81. Property Elements[aIndex : Integer] : TFormElement Read GetEl; default;
  82. end;
  83. TAttributeOperation = (aoNotPresent,aoPresent,aoEqual,aoNotEqual,aoContains);
  84. { TAttributeCondition }
  85. TAttributeCondition = Class(TCollectionItem)
  86. private
  87. FAttribute: String;
  88. FOperation: TAttributeOperation;
  89. FValue: String;
  90. Public
  91. Procedure LoadFromJSON(aName : String; aValue: TJSONData);
  92. function IsMatch(aValue: String): Boolean;
  93. Property Attribute : String Read FAttribute Write FAttribute;
  94. Property Operation : TAttributeOperation Read FOperation Write FOperation;
  95. Property Value : String Read FValue Write FValue;
  96. end;
  97. { TAttributeConditionList }
  98. TAttributeConditionList = Class(TCollection)
  99. private
  100. function GetC(aIndex : Integer): TAttributeCondition;
  101. Public
  102. Procedure LoadFromJSON(aJSON : TJSONObject);
  103. Function IsMatch(Attrs: TSAXAttributes): Boolean;
  104. Property Conditions[aIndex : Integer] : TAttributeCondition Read GetC; default;
  105. end;
  106. (* // Structure of accepted JSON
  107. [
  108. {
  109. "class" : "TWebComboBox",
  110. "tag" : "input",
  111. "attrs" : {
  112. name0 : null, // name0 Not present
  113. name1 : "value", // name1 equals value
  114. name2 ; "-value", // name2 does not equal value
  115. name3 : "~value" // name3 contains value
  116. }
  117. }
  118. ]
  119. *)
  120. { THTMLElementMap }
  121. THTMLElementMap = Class(TCollectionItem)
  122. private
  123. FConditionList : TAttributeConditionList;
  124. FControlClass: String;
  125. FTag: String;
  126. function GetAttrConditionList: TAttributeConditionList;
  127. Protected
  128. Function CreateConditionList : TAttributeConditionList; virtual;
  129. Public
  130. Destructor Destroy; override;
  131. Procedure LoadFromJSON(aJSON : TJSONObject);
  132. Function HasConditions : Boolean;
  133. Function IsMatch(aTag: SAXString; Attrs: TSAXAttributes): Boolean;
  134. Property Tag : String Read FTag Write FTag;
  135. Property ControlClass : String Read FControlClass Write FControlClass;
  136. Property Attributes : TAttributeConditionList Read GetAttrConditionList;
  137. end;
  138. { THTMLElementMapList }
  139. THTMLElementMapList = Class(TCollection)
  140. private
  141. function GetM(aIndex : Integer): THTMLElementMap;
  142. Public
  143. Procedure LoadFromFile(Const aFileName : String);
  144. Procedure LoadFromStream(aStream : TStream); virtual;
  145. Procedure LoadFromJSON(aJSON : TJSONArray); virtual;
  146. Function IndexOfMap(aTag: SAXString; Attrs: TSAXAttributes): Integer;
  147. Function FindMap(aTag: SAXString; Attrs: TSAXAttributes): THTMLElementMap;
  148. Property Maps[aIndex : Integer] : THTMLElementMap Read GetM; default;
  149. end;
  150. { THTMLToFormELements }
  151. THTMLToFormELements = class(TComponent)
  152. private
  153. FBelowID: String;
  154. FDefaultElements: Boolean;
  155. FExcludeIDS: TStrings;
  156. FFormElements: TFormElementList;
  157. FLevel : Integer;
  158. FMap: THTMLElementMapList;
  159. FOnLog: TLogEvent;
  160. function MakeValidName(aID: string): string;
  161. procedure SetExcludeIDS(AValue: TStrings);
  162. procedure SetFormElements(AValue: TFormElementList);
  163. protected
  164. Procedure DoLog(Const Msg : String);
  165. Procedure DoLog(Const Fmt : String; Args : Array of const);
  166. function CreateHTMLElementMapList: THTMLElementMapList; virtual;
  167. procedure GetEvents(aEl: TFormElement; Atts: TSAXAttributes); virtual;
  168. procedure DoEndElement(Sender: TObject; const {%H-}NamespaceURI, {%H-}LocalName,
  169. {%H-}QName: SAXString); virtual;
  170. procedure DoStartElement(Sender: TObject; const {%H-}NamespaceURI, LocalName,
  171. {%H-}QName: SAXString; Atts: TSAXAttributes); virtual;
  172. function Maptype(aTag: SAXString; Atts: TSAXAttributes): String; virtual;
  173. Class Function CreateElementList : TFormElementList; virtual;
  174. Property Level : Integer Read FLevel Write FLevel;
  175. Public
  176. Constructor Create(aOwner : TComponent); override;
  177. Destructor Destroy; override;
  178. Procedure Clear;
  179. Procedure LoadFromStream(aInput : TStream);
  180. Procedure LoadFromFile(Const aFileName : String);
  181. Procedure LoadOptions(aOptions : THTML2ClassOptions);
  182. Property FormElements : TFormElementList Read FFormElements Write SetFormElements;
  183. Property BelowID : String Read FBelowID Write FBelowID;
  184. Property ExcludeIDS : TStrings Read FExcludeIDS Write SetExcludeIDS;
  185. Property Map : THTMLElementMapList Read FMap;
  186. Property DefaultElements : Boolean Read FDefaultElements Write FDefaultElements;
  187. Property OnLog : TLogEvent Read FOnLog Write FOnLog;
  188. end;
  189. { TFormCodeGen }
  190. { TFormFileCodeGen }
  191. TFormFileCodeGen = Class(TPascalCodeGenerator)
  192. private
  193. FElementHeight: Word;
  194. FElementHSpacing: Word;
  195. FElementVSpacing: Word;
  196. FElementWidth: Word;
  197. FDoEvents: Boolean;
  198. FFormClassName: String;
  199. FFormElements: TFormElementList;
  200. FIDProperty: String;
  201. FLeft: Word;
  202. FMaxHeight: Word;
  203. FMaxWidth: Word;
  204. FTop: Word;
  205. Protected
  206. function GetFormName(const aClassName: string): String; virtual;
  207. procedure GenerateElements; virtual;
  208. procedure EmitElementEvents(El: TFormElement); virtual;
  209. procedure EmitElementProps(El: TFormElement); virtual;
  210. procedure NextPosition; virtual;
  211. Property ELeft : Word Read FLeft Write FLeft;
  212. Property ETop : Word Read FTop Write FTop;
  213. Public
  214. Constructor Create(aOwner : TComponent);override;
  215. Procedure Execute;
  216. Property FormElements: TFormElementList read FFormElements write FFormElements;
  217. Property FormClassName : String read FFormClassName write FFormClassName;
  218. Property DoEvents : Boolean read FDoEvents write FDoEvents;
  219. Property IDProperty : String Read FIDProperty Write FIDProperty;
  220. Property ElementHeight : Word Read FElementHeight Write FElementHeight;
  221. Property ElementWidth : Word Read FElementWidth Write FElementWidth;
  222. Property MaxWidth : Word Read FMaxWidth Write FMaxWidth;
  223. Property MaxHeight : Word Read FMaxHeight Write FMaxHeight;
  224. Property ElementHSpacing : Word Read FElementHSpacing Write FElementHSpacing;
  225. Property ElementVSpacing : Word Read FElementVSpacing Write FElementVSpacing;
  226. end;
  227. TFormCodeGen = Class(TPascalCodeGenerator)
  228. private
  229. FAddMethods: TSpecialMethods;
  230. FConstructorArgs: String;
  231. FEventModifiers: String;
  232. FEventSignature: string;
  233. FFormClassName: string;
  234. FFormElements: TFormElementList;
  235. FFormFileGenerator: TFormFileCodeGen;
  236. FFormSource: Tstrings;
  237. FGetElementFunction: string;
  238. FOptions: TFormOptions;
  239. FOverrideMethods: TSpecialMethods;
  240. FParentClassName: string;
  241. FVirtualMethods: TSpecialMethods;
  242. procedure SetFormElements(AValue: TFormElementList);
  243. Protected
  244. function BaseUnits : String; override;
  245. Function CreateHTMLToFormELements: THTMLToFormELements; virtual;
  246. Class Function CreateElementList : TFormElementList; virtual;
  247. procedure EmitFormFile; virtual;
  248. function CreateFormFileGen : TFormFileCodeGen; virtual;
  249. procedure EmitFormElement(aEL: TFormElement); virtual;
  250. procedure EmitFormEvents(aEL: TFormElement);virtual;
  251. procedure EmitImplementation; virtual;
  252. procedure EmitPublicSection; virtual;
  253. procedure EmitPublishedSection; virtual;
  254. procedure EmitFormBindElements; virtual;
  255. procedure EmitFormBindEvents; virtual;
  256. procedure EmitFormConstructor; virtual;
  257. function VirtualOverride(M: TSpecialMethod; const Decl: String): string; virtual;
  258. Public
  259. Constructor Create(aOwner : TComponent); override;
  260. Destructor Destroy; override;
  261. class function Pretty(const S: String): string; virtual;
  262. class procedure GetEventNameAndHandler(const S,aFieldName: String; out aName, aHandler: string);
  263. Procedure Execute;
  264. Procedure LoadOptions(aOptions : THTML2ClassOptions);
  265. Property FormFileGenerator : TFormFileCodeGen Read fFormFileGenerator Write FFormFileGenerator;
  266. Property FormElements : TFormElementList Read FFormElements Write SetFormElements;
  267. Property FormClassName : string Read FFormClassName Write FFormClassName;
  268. Property ParentClassName : string Read FParentClassName Write FParentClassName;
  269. Property GetElementFunction : string Read FGetElementFunction Write FGetElementFunction;
  270. Property EventSignature: string Read FEventSignature Write FEventSignature;
  271. Property EventModifiers : String Read FEventModifiers Write FEventModifiers;
  272. Property ConstructorArgs : String Read FConstructorArgs Write FConstructorArgs;
  273. Property Options : TFormOptions Read FOptions Write FOptions;
  274. Property AddMethods : TSpecialMethods Read FAddMethods Write FAddMethods;
  275. Property OverrideMethods : TSpecialMethods Read FOverrideMethods Write FOverrideMethods;
  276. Property VirtualMethods : TSpecialMethods Read FVirtualMethods Write FVirtualMethods;
  277. Property FormSource : Tstrings Read FFormSource;
  278. end;
  279. implementation
  280. uses TypInfo;
  281. { ----------------------------------------------------------------------
  282. ----------------------------------------------------------------------}
  283. { THTML2ClassOptions }
  284. function THTML2ClassOptions.GetB(AIndex: Integer): Boolean;
  285. begin
  286. Result:=FBools[aindex];
  287. end;
  288. function THTML2ClassOptions.GetMethods(AIndex: Integer): TSpecialMethods;
  289. begin
  290. Result:=FMethods[aindex];
  291. end;
  292. function THTML2ClassOptions.GetS(AIndex: Integer): String;
  293. begin
  294. Result:=FStrings[aindex];
  295. end;
  296. procedure THTML2ClassOptions.SetB(AIndex: Integer; AValue: Boolean);
  297. begin
  298. FBools[aIndex]:=aValue;
  299. end;
  300. procedure THTML2ClassOptions.SetExcludeElements(AValue: TStrings);
  301. begin
  302. if FExcludeElements=AValue then Exit;
  303. FExcludeElements.Assign(AValue);
  304. end;
  305. procedure THTML2ClassOptions.SetMethods(AIndex: Integer; AValue: TSpecialMethods);
  306. begin
  307. FMethods[aIndex]:=aValue;
  308. end;
  309. procedure THTML2ClassOptions.SetS(AIndex: Integer; AValue: String);
  310. begin
  311. FStrings[aIndex]:=aValue;
  312. end;
  313. constructor THTML2ClassOptions.Create;
  314. begin
  315. FExcludeElements:=TStringList.Create;
  316. Reset;
  317. end;
  318. destructor THTML2ClassOptions.Destroy;
  319. begin
  320. FreeAndNil(FExcludeElements);
  321. inherited Destroy;
  322. end;
  323. procedure THTML2ClassOptions.Reset;
  324. begin
  325. // Assume class is TComponent descendant
  326. ConstructorArgs:='aOwner : TComponent';
  327. FormClassName:='TMyForm';
  328. ParentClassName:='TComponent';
  329. EventSignature:='Event : TJSEvent';
  330. EventModifiers:='virtual; abstract;';
  331. GetElementFunction:='document.getelementByID';
  332. AddMethods:=[smConstructor,smBindElements,smBindElementEvents];
  333. VirtualMethods:=[smBindElementEvents,smBindElements];
  334. OverrideMethods:=[smConstructor];
  335. FormOptions:=[foBindInConstructor];
  336. FExcludeElements.Clear;
  337. ExtraUnits:='Classes'
  338. end;
  339. procedure THTML2ClassOptions.toJSON(aObject: TJSONObject);
  340. Function GenToArray(aMethods : TSpecialMethods) : TJSONArray;
  341. Var
  342. M : TSpecialMethod;
  343. begin
  344. Result:=TJSONArray.Create;
  345. For M in TSpecialMethods do
  346. If M in aMethods then
  347. Result.Add(GetEnumName(TypeInfo(TSpecialMethod),Ord(M)));
  348. end;
  349. Function OptionsToArray(aOptions : TFormOptions) : TJSONArray;
  350. Var
  351. F : TFormOption;
  352. begin
  353. Result:=TJSONArray.Create;
  354. For F in TFormOptions do
  355. If F in aOptions then
  356. Result.Add(GetEnumName(TypeInfo(TFormOptions),Ord(F)));
  357. end;
  358. Var
  359. arr : TJSONArray;
  360. S : String;
  361. begin
  362. With aObject do
  363. begin
  364. Add('OverrideMethods',GenToArray(OverrideMethods));
  365. Add('AddMethods',GenToArray(AddMethods));
  366. Add('VirtualMethods',GenToArray(VirtualMethods));
  367. Add('FormOptions',OptionsToArray(FormOptions));
  368. Add('GetElementFunction',GetElementFunction);
  369. Add('EventSignature',EventSignature);
  370. Add('EventModifiers',EventModifiers);
  371. Add('ConstructorArgs',ConstructorArgs);
  372. Add('BelowID',BelowID);
  373. Add('HTMLFileName',HTMLFileName);
  374. Add('FormClassname',FormClassname);
  375. Add('FormClassname',FormClassname);
  376. Add('UseDefaultElements',UseDefaultElements);
  377. Add('AddHTMLToProject',AddHTMLToProject);
  378. arr:=TJSONArray.Create;
  379. Add('ExcludeElements',Arr);
  380. For S in ExcludeElements do
  381. arr.Add(S);
  382. end;
  383. end;
  384. procedure THTML2ClassOptions.FromJSON(aObject: TJSONObject);
  385. Function GenFromArray(Arr : TJSONArray) : TSpecialMethods;
  386. Var
  387. I,Idx : integer;
  388. begin
  389. Result:=[];
  390. if Assigned(Arr) then
  391. For I:=0 to Arr.Count-1 do
  392. if (Arr.types[I]=jtString) then
  393. begin
  394. Idx:=GetEnumValue(TypeInfo(TSpecialMethod),Arr.Strings[I]);
  395. If Idx<>-1 then
  396. include(Result,TSpecialMethod(Idx));
  397. end;
  398. end;
  399. Function OptionsFromArray(arr : TJSONArray) : TFormOptions;
  400. Var
  401. I,Idx : integer;
  402. begin
  403. Result:=[];
  404. if Assigned(Arr) then
  405. For I:=0 to Arr.Count-1 do
  406. if (Arr.types[I]=jtString) then
  407. begin
  408. Idx:=GetEnumValue(TypeInfo(TFormOption),Arr.Strings[I]);
  409. If Idx<>-1 then
  410. include(Result,TFormOption(Idx));
  411. end;
  412. end;
  413. Var
  414. arr : TJSONArray;
  415. I : integer;
  416. begin
  417. With aObject do
  418. begin
  419. OverrideMethods:=GenFromArray(Get('OverrideMethods',TJSONArray(Nil)));
  420. AddMethods:=GenFromArray(Get('AddMethods',TJSONArray(Nil)));
  421. VirtualMethods:=GenFromArray(Get('VirtualMethods',TJSONArray(Nil)));
  422. FormOptions:=OptionsFromArray(Get('FormOptions',TJSONArray(Nil)));
  423. GetElementFunction:=Get('GetElementFunction','');
  424. EventSignature:=Get('EventSignature','');
  425. EventModifiers:=Get('EventModifiers','');
  426. ConstructorArgs:=Get('ConstructorArgs','');
  427. BelowID:=Get('BelowID','');
  428. HTMLFileName:=Get('HTMLFileName','');
  429. FormClassname:=Get('FormClassname','');
  430. UseDefaultElements:=Get('UseDefaultElements',False);
  431. AddHTMLToProject:=Get('AddHTMLToProject',False);
  432. ExcludeElements.Clear;
  433. Arr:=Get('ExcludeElements',TJSONArray(Nil));
  434. if Assigned(Arr) then
  435. For I:=0 to Arr.Count-1 do
  436. if (Arr.types[I]=jtString) then
  437. ExcludeElements.Add(Arr.Strings[I]);
  438. end;
  439. end;
  440. function THTML2ClassOptions.asJSON(Formatted: Boolean): String;
  441. Var
  442. J : TJSONObject;
  443. begin
  444. J:=TJSONObject.Create;
  445. try
  446. ToJSON(J);
  447. if Formatted then
  448. Result:=J.FormatJSON()
  449. else
  450. Result:=J.asJSON;
  451. finally
  452. J.Free;
  453. end;
  454. end;
  455. { TFormFileCodeGen }
  456. function TFormFileCodeGen.GetFormName(const aClassName: string): String;
  457. begin
  458. Result:=aClassName;
  459. if SameText(Copy(Result,1,1),'T') then
  460. Delete(Result,1,1);
  461. end;
  462. (*
  463. procedure TFormFileCodeGen.LoadFromStream(const AStream: TStream);
  464. begin
  465. if aStream=Nil then exit;
  466. end;
  467. *)
  468. constructor TFormFileCodeGen.Create(aOwner: TComponent);
  469. begin
  470. inherited Create(aOwner);
  471. IDProperty:='ElementID';
  472. ElementHeight:=24;
  473. ElementWidth:=72;
  474. ElementVSpacing:=8;
  475. ElementHSpacing:=16;
  476. MaxWidth:=800;
  477. MaxHeight:=600;
  478. end;
  479. procedure TFormFileCodeGen.NextPosition;
  480. begin
  481. ELeft:=ELeft+ElementWidth+ElementHSpacing;
  482. if ELeft+ElementWidth>=MaxWidth then
  483. begin
  484. ELeft:=8;
  485. ETop:=ETop+ElementHeight+ElementVSpacing;
  486. end;
  487. end;
  488. procedure TFormFileCodeGen.EmitElementProps(El : TFormElement);
  489. begin
  490. AddLn('Top = %d',[ETop]);
  491. AddLn('Left = %d',[ELeft]);
  492. Addln('Width = %d',[ElementWidth]);
  493. Addln('Height = %d',[ElementHeight]);
  494. addLn('%s = ''%s''',[IDProperty,El.Name]);
  495. end;
  496. procedure TFormFileCodeGen.EmitElementEvents(El : TFormElement);
  497. Var
  498. S,EN,EH : String;
  499. begin
  500. For S in El.Events do
  501. begin
  502. TFormCodeGen.GetEventNameAndHandler(S,El.Name,EN,EH);
  503. Addln('%s = %s',[EN,EH]);
  504. end;
  505. end;
  506. procedure TFormFileCodeGen.GenerateElements;
  507. Var
  508. I : Integer;
  509. El : TFormElement;
  510. begin
  511. For I:=0 to FormElements.Count-1 do
  512. begin
  513. el:=FormElements[i];
  514. With El do
  515. begin
  516. Addln('object %s: %s',[Name,ElementType]);
  517. Indent;
  518. EmitElementProps(EL);
  519. if DoEvents then
  520. EmitElementEvents(El);
  521. Undent;
  522. AddLn('end');
  523. NextPosition;
  524. end;
  525. end;
  526. end;
  527. procedure TFormFileCodeGen.Execute;
  528. begin
  529. ETop:=8;
  530. ELeft:=8;
  531. AddLn('object %s : %s',[GetFormName(FormClassName),FormClassName]);
  532. Indent;
  533. AddLn('Width = %d',[MaxWidth]);
  534. AddLn('Height = %d',[MaxHeight]);
  535. GenerateElements;
  536. Undent;
  537. AddLn('end');
  538. end;
  539. { THTMLElementMapList }
  540. function THTMLElementMapList.GetM(aIndex : Integer): THTMLElementMap;
  541. begin
  542. Result:=Items[aIndex] as THTMLElementMap;
  543. end;
  544. procedure THTMLElementMapList.LoadFromFile(const aFileName: String);
  545. Var
  546. F : TFileStream;
  547. begin
  548. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  549. try
  550. LoadFromStream(F);
  551. finally
  552. F.Free;
  553. end;
  554. end;
  555. procedure THTMLElementMapList.LoadFromStream(aStream: TStream);
  556. Var
  557. D : TJSONData;
  558. begin
  559. D:=GetJSON(aStream);
  560. try
  561. if D is TJSONArray then
  562. LoadFromJSON(D as TJSONArray);
  563. finally
  564. D.Free;
  565. end;
  566. end;
  567. procedure THTMLElementMapList.LoadFromJSON(aJSON: TJSONArray);
  568. Var
  569. E : TJSONEnum;
  570. begin
  571. For E in aJSON do
  572. if E.Value is TJSONObject then
  573. (Add as THTMLElementMap).LoadFromJSON(e.Value as TJSONObject);
  574. end;
  575. function THTMLElementMapList.IndexOfMap(aTag: SAXString; Attrs: TSAXAttributes
  576. ): Integer;
  577. begin
  578. Result:=0;
  579. While (Result<Count) and Not GetM(Result).IsMatch(aTag,Attrs) do
  580. Inc(Result);
  581. if Result=Count then
  582. Result:=-1;
  583. end;
  584. function THTMLElementMapList.FindMap(aTag: SAXString; Attrs: TSAXAttributes
  585. ): THTMLElementMap;
  586. Var
  587. Idx : Integer;
  588. begin
  589. Idx:=IndexOfMap(aTag,Attrs);
  590. If Idx=-1 then
  591. Result:=Nil
  592. else
  593. Result:=GetM(Idx);
  594. end;
  595. { THTMLElementMap }
  596. function THTMLElementMap.GetAttrConditionList: TAttributeConditionList;
  597. begin
  598. If FConditionList=Nil then
  599. FConditionList:=CreateConditionList;
  600. Result:=FConditionList
  601. end;
  602. function THTMLElementMap.CreateConditionList: TAttributeConditionList;
  603. begin
  604. Result:=TAttributeConditionList.Create(TAttributeCondition);
  605. end;
  606. destructor THTMLElementMap.Destroy;
  607. begin
  608. FreeAndNil(FConditionList);
  609. inherited Destroy;
  610. end;
  611. procedure THTMLElementMap.LoadFromJSON(aJSON: TJSONObject);
  612. Var
  613. A : TJSONObject;
  614. begin
  615. FTag:=aJSON.Get('tag','');
  616. ControlClass:=aJSON.Get('class','');
  617. A:=aJSON.Get('attrs',TJSONObject(Nil));
  618. If Assigned(A) then
  619. Attributes.LoadFromJSON(A);
  620. end;
  621. function THTMLElementMap.HasConditions: Boolean;
  622. begin
  623. Result:=Assigned(FConditionList) and (FConditionList.Count>0);
  624. end;
  625. function THTMLElementMap.IsMatch(aTag: SAXString; Attrs: TSAXAttributes): Boolean;
  626. begin
  627. Result:=SameText(UTF8Encode(aTag),FTag);
  628. if Result and HasConditions then
  629. Result:=Attributes.IsMatch(Attrs);
  630. end;
  631. { TAttributeConditionList }
  632. function TAttributeConditionList.GetC(aIndex : Integer): TAttributeCondition;
  633. begin
  634. Result:=TAttributeCondition(Items[aIndex]);
  635. end;
  636. procedure TAttributeConditionList.LoadFromJSON(aJSON: TJSONObject);
  637. Var
  638. E : TJSONEnum;
  639. A : TAttributeCondition;
  640. begin
  641. For E in aJSON do
  642. begin
  643. A:=Add as TAttributeCondition;
  644. A.LoadFromJSON(E.Key,E.Value);
  645. end;
  646. end;
  647. function TAttributeConditionList.IsMatch(Attrs: TSAXAttributes): Boolean;
  648. function GetIndex(const aName: SAXString): Integer;
  649. begin
  650. Result := Attrs.Length-1;
  651. while (Result>=0) and not SameText(UTF8Encode(Attrs.LocalNames[Result]),UTF8Encode(aName)) do
  652. Dec(Result);
  653. end;
  654. Var
  655. I,Idx : Integer;
  656. A : TAttributeCondition;
  657. begin
  658. Result:=True;
  659. I:=0;
  660. While Result and (I<Count) do
  661. begin
  662. A:=GetC(I);
  663. Idx:=GetIndex(UTF8Decode(A.Attribute));
  664. if A.Operation=aoNotPresent then
  665. Result:=Idx<0
  666. else
  667. Result:=A.IsMatch(UTF8Encode(Attrs.GetValue(Idx)));
  668. Inc(I);
  669. end;
  670. end;
  671. { TAttributeCondition }
  672. procedure TAttributeCondition.LoadFromJSON(aName: String; aValue: TJSONData);
  673. Var
  674. S : TJSONStringType;
  675. C : Char;
  676. begin
  677. Attribute:=aName;
  678. if aValue.JSONType=jtNull then
  679. Operation:=aoNotPresent
  680. else if aValue.JSONType=jtBoolean then
  681. begin
  682. if aValue.AsBoolean then
  683. Operation:=aoPresent
  684. else
  685. Operation:=aoNotPresent
  686. end
  687. else
  688. begin
  689. S:=aValue.AsString;
  690. If S<>'' then
  691. C:=S[1]
  692. else
  693. C:=#0;
  694. Case C of
  695. '-' : Operation:=aoNotEqual;
  696. '~' : Operation:=aoContains;
  697. else
  698. Operation:=aoEqual;
  699. Value:=S;
  700. end;
  701. if Operation in [aoNotEqual,aoContains] then
  702. Value:=Copy(S,2,Length(S)-1);
  703. end;
  704. end;
  705. function TAttributeCondition.IsMatch(aValue: String): Boolean;
  706. begin
  707. Case Operation of
  708. aoPresent : Result:=True;
  709. aoNotEqual : Result:=Not SameText(aValue,Value);
  710. aoEqual : Result:=SameText(aValue,Value);
  711. aoContains : Result:=Pos(LowerCase(Value),LowerCase(aValue))>0;
  712. end;
  713. end;
  714. { THTMLToFormELements }
  715. procedure THTMLToFormELements.SetFormElements(AValue: TFormElementList);
  716. begin
  717. if FFormElements=AValue then Exit;
  718. FFormElements:=AValue;
  719. end;
  720. procedure THTMLToFormELements.DoLog(const Msg: String);
  721. begin
  722. if Assigned(FOnLog) then
  723. FOnLog(Self,Msg);
  724. end;
  725. procedure THTMLToFormELements.DoLog(const Fmt: String; Args: array of const);
  726. begin
  727. DoLog(Format(Fmt,Args));
  728. end;
  729. function THTMLToFormELements.Maptype(aTag: SAXString; Atts: TSAXAttributes): String;
  730. var
  731. t : string;
  732. m : THTMLElementMap;
  733. begin
  734. Result:='';
  735. if Map.Count>0 then
  736. begin
  737. M:=Map.FindMap(aTag,Atts);
  738. if Assigned(m) then
  739. Exit(M.ControlClass)
  740. else if not DefaultElements then
  741. begin
  742. DoLog('Could not map tag %s',[aTag]);
  743. Exit;
  744. end;
  745. end;
  746. t:=lowercase(Utf8Encode(aTag));
  747. case t of
  748. 'input' : Result:='TJSHTMLInputElement';
  749. 'button' : Result:='TJSHTMLButtonElement';
  750. 'select' : Result:='TJSHTMLSelectElement';
  751. 'textarea' : Result:='TJSHTMLTextAreaElement';
  752. 'option' : Result:='';
  753. else
  754. Result:='TJSHTMLElement';
  755. end;
  756. end;
  757. function THTMLToFormELements.MakeValidName(aID: string): string;
  758. Var
  759. C : Char;
  760. begin
  761. Result:='';
  762. for C in aID do
  763. if C in ['_','a'..'z','A'..'Z','0'..'9'] then
  764. Result:=Result+C
  765. else
  766. Result:=Result+'_';
  767. end;
  768. procedure THTMLToFormELements.SetExcludeIDS(AValue: TStrings);
  769. begin
  770. if FExcludeIDS=AValue then Exit;
  771. FExcludeIDs.AddStrings(AValue,True);
  772. end;
  773. procedure THTMLToFormELements.DoStartElement(Sender: TObject;
  774. const NamespaceURI, LocalName, QName: SAXString; Atts: TSAXAttributes);
  775. Var
  776. aID,aType : String;
  777. El : TFormElement;
  778. begin
  779. if Not Assigned(atts) then exit;
  780. aID:=UTF8Encode(Atts.GetValue('','id'));
  781. if (aID='') or (FExcludeIDS.IndexOf(aID)>=0) then
  782. exit;
  783. if (Level=0) and (BelowID=aID) then
  784. Level:=1
  785. else if (BelowID<>'') and (Level<=0) then
  786. Exit;
  787. aType:=MapType(LocalName,Atts);
  788. if aType='' then
  789. DoLog('Ignoring tag %s with id %s',[LocalName,aID])
  790. else
  791. begin
  792. El:=FormElements.Add(MakeValidName(aID));
  793. EL.ElementType:=aType;
  794. EL.HTMLID:=aId;
  795. GetEvents(El,Atts);
  796. end
  797. end;
  798. procedure THTMLToFormELements.GetEvents(aEl : TFormElement; Atts : TSAXAttributes);
  799. Var
  800. I,aLen : Integer;
  801. aName : string;
  802. begin
  803. for I:=0 to Atts.Length-1 do
  804. begin
  805. aName:=UTF8Encode(Atts.GetLocalName(i));
  806. aLen:=Length(aName);
  807. if (aLen>3) and (Copy(aName,1,1)='_') and (Copy(aName,aLen,1)='_') then
  808. aEl.Events.Add(Copy(aName,2,aLen-2)+'='+UTF8Encode(Atts.GetValue(i)));
  809. end;
  810. end;
  811. procedure THTMLToFormELements.DoEndElement(Sender: TObject; const NamespaceURI,
  812. LocalName, QName: SAXString);
  813. begin
  814. if Level>0 then
  815. Dec(FLevel);
  816. end;
  817. class function THTMLToFormELements.CreateElementList: TFormElementList;
  818. begin
  819. Result:=TFormElementList.Create(TFormElement);
  820. end;
  821. function THTMLToFormELements.CreateHTMLElementMapList: THTMLElementMapList;
  822. begin
  823. Result:=THTMLElementMapList.Create(THTMLElementMap);
  824. end;
  825. constructor THTMLToFormELements.Create(aOwner: TComponent);
  826. begin
  827. inherited Create(aOwner);
  828. FMap:=CreateHTMLElementMapList;
  829. FFormElements:=CreateElementList;
  830. FExcludeIDS:=TStringList.Create;
  831. TStringList(FExcludeIDS).Sorted:=True;
  832. end;
  833. destructor THTMLToFormELements.Destroy;
  834. begin
  835. FreeAndNil(FMap);
  836. FreeAndNil(FExcludeIDS);
  837. FreeAndNil(FFormElements);
  838. inherited Destroy;
  839. end;
  840. procedure THTMLToFormELements.Clear;
  841. begin
  842. FFormElements.Clear;
  843. end;
  844. procedure THTMLToFormELements.LoadFromStream(aInput: TStream);
  845. var
  846. MyReader : THTMLReader;
  847. begin
  848. MyReader:=THTMLReader.Create;
  849. Try
  850. MyReader.OnStartElement:=@DoStartElement;
  851. MyReader.OnEndElement:=@DoEndElement;
  852. MyReader.ParseStream(aInput);
  853. finally
  854. FreeAndNil(MyReader);
  855. end;
  856. end;
  857. procedure THTMLToFormELements.LoadFromFile(const aFileName: String);
  858. var
  859. F : TFileStream;
  860. begin
  861. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  862. try
  863. LoadFromStream(F);
  864. finally
  865. F.Free;
  866. end;
  867. end;
  868. procedure THTMLToFormELements.LoadOptions(aOptions: THTML2ClassOptions);
  869. begin
  870. BelowID:=aoptions.BelowID;
  871. ExcludeIDS:=aOptions.ExcludeElements;
  872. DefaultElements:=aOptions.UseDefaultElements;
  873. if (aOptions.TagMapFileName<>'') and FileExists(aOptions.TagMapFileName) then
  874. Map.LoadFromFile(aOptions.TagMapFileName);
  875. end;
  876. { TFormCodeGen }
  877. procedure TFormCodeGen.SetFormElements(AValue: TFormElementList);
  878. begin
  879. if FFormElements=AValue then Exit;
  880. FFormElements.Assign(AValue);
  881. end;
  882. function TFormCodeGen.BaseUnits: String;
  883. begin
  884. Result:='js, web';
  885. end;
  886. class function TFormCodeGen.CreateElementList: TFormElementList;
  887. begin
  888. Result:=TFormElementList.Create(TFormElement);
  889. end;
  890. constructor TFormCodeGen.Create(aOwner: TComponent);
  891. Var
  892. Defs : THTML2ClassOptions;
  893. begin
  894. inherited Create(aOwner);
  895. FFormElements:=CreateElementList;
  896. FFormFileGenerator:=CreateFormFileGen;
  897. FFormSource:=TStringList.Create;
  898. // Defaults must be set in
  899. Defs:=THTML2ClassOptions.Create;
  900. try
  901. Defs.Reset;
  902. Loadoptions(Defs);
  903. finally
  904. Defs.Free;
  905. end;
  906. end;
  907. destructor TFormCodeGen.Destroy;
  908. begin
  909. FreeAndNil(FFormSource);
  910. FreeAndNil(fFormFileGenerator) ;
  911. FreeAndNil(FFormElements);
  912. inherited Destroy;
  913. end;
  914. procedure TFormCodeGen.EmitFormElement(aEL : TFormElement);
  915. begin
  916. With aEl do
  917. AddLn('%s : %s;',[Name,ElementType]) ;
  918. end;
  919. procedure TFormCodeGen.EmitFormEvents(aEL : TFormElement);
  920. Var
  921. S,EN,EH : String;
  922. begin
  923. if not aEl.HasEvents then
  924. exit;
  925. For S in aEl.Events do
  926. begin
  927. GetEventNameAndHandler(S,aEl.Name,EN,EH);
  928. Addln('Procedure %s(%s); %s',[EH, EventSignature,EventModifiers]);
  929. end;
  930. end;
  931. procedure TFormCodeGen.EmitPublishedSection;
  932. var
  933. I : Integer;
  934. begin
  935. For I:=0 to FormElements.Count-1 do
  936. EmitFormElement(FormElements[i]);
  937. if foEvents in Options then
  938. For I:=0 to FormElements.Count-1 do
  939. EmitFormEvents(FormElements[i]);
  940. end;
  941. function TFormCodeGen.VirtualOverride(M: TSpecialMethod; const Decl: String): string;
  942. begin
  943. Result:=Decl;
  944. if M in OverrideMethods then
  945. Result:=Result+' override;'
  946. else if M in VirtualMethods then
  947. Result:=Result+' virtual;'
  948. end;
  949. procedure TFormCodeGen.EmitPublicSection;
  950. begin
  951. if smConstructor in AddMethods then
  952. Addln(VirtualOverride(smConstructor,'Constructor create('+ConstructorArgs+');'));
  953. if smBindElements in AddMethods then
  954. Addln(VirtualOverride(smBindElements, 'Procedure BindElements;'));
  955. if (smBindElementEvents in AddMethods) and (foEvents in Options) then
  956. Addln(VirtualOverride(smBindElementEvents,'Procedure BindElementEvents;'));
  957. end;
  958. procedure TFormCodeGen.Execute;
  959. begin
  960. Source.Clear;
  961. Addln('unit %s;',[OutputUnitName]);
  962. CreateHeader;
  963. Addln('Type');
  964. Indent;
  965. ClassHeader(FormClassName);
  966. AddLn('%s = class(%s) ',[FormClassName,ParentClassName]);
  967. Addln('Published');
  968. Indent;
  969. EmitPublishedSection;
  970. Undent;
  971. Addln('Public');
  972. Indent;
  973. EmitPublicSection;
  974. Undent;
  975. Addln('end;');
  976. Undent;
  977. Addln('');
  978. Addln('implementation');
  979. AddLn('');
  980. if (foFormFile in Options) then
  981. begin
  982. EmitFormFile;
  983. AddLn('');
  984. AddLn('{$R *.dfm}');
  985. AddLn('');
  986. end;
  987. ClassHeader(FormClassName);
  988. EmitImplementation;
  989. AddLn('');
  990. AddLn('end.');
  991. end;
  992. procedure TFormCodeGen.LoadOptions(aOptions: THTML2ClassOptions);
  993. begin
  994. ExtraUnits:=aOptions.ExtraUnits;
  995. FormClassName:=aOptions.FormClassname;
  996. ParentClassName:=aOptions.ParentClassName;
  997. GetElementFunction:=aOptions.GetElementFunction;
  998. EventSignature:=aOptions.EventSignature;
  999. EventModifiers:=aOptions.EventModifiers;
  1000. ConstructorArgs:=aOptions.ConstructorArgs;
  1001. Options:=aOptions.FormOptions;
  1002. AddMethods:=aOptions.AddMethods;
  1003. OverrideMethods:=aOptions.OverrideMethods;
  1004. VirtualMethods:=aOptions.VirtualMethods;
  1005. end;
  1006. procedure TFormCodeGen.EmitFormFile;
  1007. begin
  1008. FormFileGenerator.FormElements:=Self.FormElements;
  1009. FormFileGenerator.DoEvents:=foEvents in Options;
  1010. FormFileGenerator.FormClassName:=Self.FormClassName;
  1011. FormFileGenerator.Execute;
  1012. FormSource.Assign(FormFileGenerator.Source);
  1013. end;
  1014. function TFormCodeGen.CreateFormFileGen: TFormFileCodeGen;
  1015. begin
  1016. Result:=TFormFileCodeGen.Create(Nil);
  1017. end;
  1018. function TFormCodeGen.CreateHTMLToFormELements: THTMLToFormELements;
  1019. begin
  1020. Result:=THTMLToFormELements.Create(Self);
  1021. end;
  1022. procedure TFormCodeGen.EmitFormConstructor;
  1023. begin
  1024. Addln('');
  1025. Addln('Constructor %s.create(%s);',[FormClassName,ConstructorArgs]);
  1026. if not (foBindInConstructor in Options) then
  1027. SimpleMethodBody(['Inherited;'])
  1028. else
  1029. begin
  1030. if foEvents in Options then
  1031. SimpleMethodBody(['Inherited;','BindElements;','BindElementEvents;'])
  1032. else
  1033. SimpleMethodBody(['Inherited;','BindElements;']);
  1034. end;
  1035. Addln('');
  1036. end;
  1037. procedure TFormCodeGen.EmitImplementation;
  1038. begin
  1039. if smConstructor in AddMethods then
  1040. EmitFormConstructor;
  1041. if (smBindElements in AddMethods) then
  1042. EmitFormBindElements;
  1043. if (foEvents in Options) and Not (foFormFile in Options) and (smBindElementEvents in AddMethods) then
  1044. EmitFormBindEvents;
  1045. end;
  1046. procedure TFormCodeGen.EmitFormBindElements;
  1047. var
  1048. I : integer;
  1049. El : TFormElement;
  1050. begin
  1051. Addln('');
  1052. Addln('Procedure %s.BindElements;',[FormClassName]);
  1053. Addln('');
  1054. AddLn('begin');
  1055. Indent;
  1056. if smBindElements in OverrideMethods then
  1057. AddLn('inherited;');
  1058. For I:=0 to FormElements.Count-1 do
  1059. begin
  1060. el:=FormElements[i];
  1061. With El do
  1062. Addln('%s:=%s(%s(''%s''));',[Name,ElementType,GetElementFunction,HTMLID]);
  1063. end;
  1064. Undent;
  1065. Addln('end;');
  1066. Addln('');
  1067. end;
  1068. class function TFormCodeGen.Pretty(const S: String): string;
  1069. begin
  1070. Result:=UpperCase(Copy(S,1,1))+LowerCase(Copy(S,2,Length(S)-1));
  1071. end;
  1072. class procedure TFormCodeGen.GetEventNameAndHandler(const S,
  1073. aFieldName: String; out aName, aHandler: string);
  1074. Var
  1075. P : Integer;
  1076. begin
  1077. P:=Pos('=',S);
  1078. if (P=0) then
  1079. P:=Length(S)+1;
  1080. aName:=Copy(S,1,P-1);
  1081. aHandler:=Copy(S,P+1,Length(S)-P);
  1082. if AHandler='' then
  1083. aHandler:=aFieldName+Pretty(aName);
  1084. // Writeln(aFieldName,': ',S,' -> ',aName,' & ',aHandler);
  1085. end;
  1086. procedure TFormCodeGen.EmitFormBindEvents;
  1087. var
  1088. I : integer;
  1089. El : TFormElement;
  1090. S,EN,EH : String;
  1091. begin
  1092. Addln('Procedure %s.BindElementEvents;',[FormClassName]);
  1093. Addln('');
  1094. AddLn('begin');
  1095. Indent;
  1096. if smBindElementEvents in OverrideMethods then
  1097. AddLn('inherited;');
  1098. For I:=0 to FormElements.Count-1 do
  1099. begin
  1100. el:=FormElements[i];
  1101. With El do
  1102. if HasEvents then
  1103. For S in El.Events do
  1104. begin
  1105. GetEventNameAndHandler(S,Name,EN,EH);
  1106. Addln('%s.AddEventListener(''%s'',@%s);',[Name,EN,EH]);
  1107. end;
  1108. end;
  1109. Undent;
  1110. Addln('end;');
  1111. end;
  1112. { TFormElementList }
  1113. function TFormElementList.GetEl(aIndex : Integer): TFormElement;
  1114. begin
  1115. Result:=Items[aIndex] as TFormElement;
  1116. end;
  1117. function TFormElementList.Add(const aName: string): TFormElement;
  1118. begin
  1119. if IndexOf(aName)<>-1 then
  1120. Raise Exception.CreateFmt('Duplicate name : %s' ,[aName]);
  1121. Result:=(Inherited Add) as TFormElement;
  1122. Result.Name:=aName;
  1123. end;
  1124. function TFormElementList.IndexOf(const aName: string): Integer;
  1125. begin
  1126. Result:=Count-1;
  1127. While (Result>=0) and Not SameText(aName,GetEl(Result).Name) do
  1128. Dec(Result);
  1129. end;
  1130. function TFormElementList.Find(const aName: string): TFormElement;
  1131. var
  1132. Idx : Integer;
  1133. begin
  1134. Idx:=IndexOf(aName);
  1135. if Idx>=0 then
  1136. Result:=GetEl(Idx)
  1137. else
  1138. Result:=Nil;
  1139. end;
  1140. { TFormElement }
  1141. function TFormElement.GetEvents: TStrings;
  1142. begin
  1143. If (FEvents=Nil) then
  1144. FEvents:=TStringList.Create;
  1145. Result:=FEvents;
  1146. end;
  1147. function TFormElement.getName: String;
  1148. begin
  1149. Result:=FName;
  1150. if Result='' then
  1151. Result:=HTMLID;
  1152. end;
  1153. procedure TFormElement.SetEvents(AValue: TStrings);
  1154. begin
  1155. If AValue=FEVents then exit;
  1156. Events.Assign(aValue);
  1157. end;
  1158. destructor TFormElement.Destroy;
  1159. begin
  1160. FreeAndNil(FEvents);
  1161. inherited Destroy;
  1162. end;
  1163. function TFormElement.HasEvents: Boolean;
  1164. begin
  1165. Result:=Assigned(FEvents) and (FEvents.Count>0);
  1166. end;
  1167. procedure TFormElement.Assign(Source: TPersistent);
  1168. Var
  1169. FE : TFormElement absolute Source;
  1170. begin
  1171. if Source is TFormElement then
  1172. begin
  1173. FHTMLID:=FE.HTMLID;
  1174. FName:=FE.FName;
  1175. FType:=FE.FType;
  1176. if FE.HasEvents then
  1177. Events:=FE.Events;
  1178. end
  1179. else
  1180. inherited Assign(Source);
  1181. end;
  1182. end.