123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128 |
- {
- This file is part of the Pas2JS toolchain
- Copyright (c) 2020 by Michael Van Canneyt
- This unit implements a HTML to pascal class converter.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit formgen;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, sax, sax_html, pascodegen, fpjson, jsonparser;
- Type
- TLogEvent = Procedure (Sender : TObject; Const Msg : String) of object;
- { TFormElement }
- TFormElement = Class(TCollectionItem)
- private
- FHTMLID: String;
- FName: String;
- FType: String;
- FEvents : TStrings;
- function GetEvents: TStrings;
- function getName: String;
- procedure SetEvents(AValue: TStrings);
- Public
- Destructor Destroy; override;
- Function HasEvents : Boolean;
- Procedure Assign(Source : TPersistent); override;
- Published
- Property Name : String Read getName Write FName;
- Property HTMLID : String Read FHTMLID Write FHTMLID;
- Property ElementType : String Read FType Write FType;
- Property Events : TStrings Read GetEvents Write SetEvents;
- end;
- { TFormElementList }
- TFormElementList = CLass(TCollection)
- private
- function GetEl(aIndex : Integer): TFormElement;
- Public
- Function Add(Const aName : string) : TFormElement;
- Function IndexOf(Const aName : string) : Integer;
- Function Find(Const aName : string) : TFormElement;
- Property Elements[aIndex : Integer] : TFormElement Read GetEl; default;
- end;
-
- TAttributeOperation = (aoNotPresent,aoPresent,aoEqual,aoNotEqual,aoContains);
- { TAttributeCondition }
- TAttributeCondition = Class(TCollectionItem)
- private
- FAttribute: String;
- FOperation: TAttributeOperation;
- FValue: String;
- Public
- Procedure LoadFromJSON(aName : String; aValue: TJSONData);
- function IsMatch(aValue: String): Boolean;
- Property Attribute : String Read FAttribute Write FAttribute;
- Property Operation : TAttributeOperation Read FOperation Write FOperation;
- Property Value : String Read FValue Write FValue;
- end;
-
- { TAttributeConditionList }
- TAttributeConditionList = Class(TCollection)
- private
- function GetC(aIndex : Integer): TAttributeCondition;
- Public
- Procedure LoadFromJSON(aJSON : TJSONObject);
- Function IsMatch(Attrs: TSAXAttributes): Boolean;
- Property Conditions[aIndex : Integer] : TAttributeCondition Read GetC; default;
- end;
-
- (* // Structure of accepted JSON
- [
- {
- "class" : "TWebComboBox",
- "tag" : "input",
- "attrs" : {
- name0 : null, // name0 Not present
- name1 : "value", // name1 equals value
- name2 ; "-value", // name2 does not equal value
- name3 : "~value" // name3 contains value
- }
- }
- ]
- *)
- { THTMLElementMap }
- THTMLElementMap = Class(TCollectionItem)
- private
- FConditionList : TAttributeConditionList;
- FControlClass: String;
- FTag: String;
- function GetAttrConditionList: TAttributeConditionList;
- Protected
- Function CreateConditionList : TAttributeConditionList; virtual;
- Public
- Destructor Destroy; override;
- Procedure LoadFromJSON(aJSON : TJSONObject);
- Function HasConditions : Boolean;
- Function IsMatch(aTag: SAXString; Attrs: TSAXAttributes): Boolean;
- Property Tag : String Read FTag Write FTag;
- Property ControlClass : String Read FControlClass Write FControlClass;
- Property Attributes : TAttributeConditionList Read GetAttrConditionList;
- end;
- { THTMLElementMapList }
- THTMLElementMapList = Class(TCollection)
- private
- function GetM(aIndex : Integer): THTMLElementMap;
- Public
- Procedure LoadFromFile(Const aFileName : String);
- Procedure LoadFromStream(aStream : TStream); virtual;
- Procedure LoadFromJSON(aJSON : TJSONArray); virtual;
- Function IndexOfMap(aTag: SAXString; Attrs: TSAXAttributes): Integer;
- Function FindMap(aTag: SAXString; Attrs: TSAXAttributes): THTMLElementMap;
- Property Maps[aIndex : Integer] : THTMLElementMap Read GetM; default;
- end;
-
- { THTMLToFormELements }
- THTMLToFormELements = class(TComponent)
- private
- FBelowID: String;
- FDefaultElements: Boolean;
- FExcludeIDS: TStrings;
- FFormElements: TFormElementList;
- FLevel : Integer;
- FMap: THTMLElementMapList;
- FOnLog: TLogEvent;
- function MakeValidName(aID: string): string;
- procedure SetExcludeIDS(AValue: TStrings);
- procedure SetFormElements(AValue: TFormElementList);
- protected
- Procedure DoLog(Const Msg : String);
- Procedure DoLog(Const Fmt : String; Args : Array of const);
- function CreateHTMLElementMapList: THTMLElementMapList; virtual;
- procedure GetEvents(aEl: TFormElement; Atts: TSAXAttributes); virtual;
- procedure DoEndElement(Sender: TObject; const {%H-}NamespaceURI, {%H-}LocalName,
- {%H-}QName: SAXString); virtual;
- procedure DoStartElement(Sender: TObject; const {%H-}NamespaceURI, LocalName,
- {%H-}QName: SAXString; Atts: TSAXAttributes); virtual;
- function Maptype(aTag: SAXString; Atts: TSAXAttributes): String; virtual;
- Class Function CreateElementList : TFormElementList; virtual;
- Property Level : Integer Read FLevel Write FLevel;
- Public
- Constructor Create(aOwner : TComponent); override;
- Destructor Destroy; override;
- Procedure Clear;
- Procedure LoadFromStream(aInput : TStream);
- Procedure LoadFromFile(Const aFileName : String);
- Property FormElements : TFormElementList Read FFormElements Write SetFormElements;
- Property BelowID : String Read FBelowID Write FBelowID;
- Property ExcludeIDS : TStrings Read FExcludeIDS Write SetExcludeIDS;
- Property Map : THTMLElementMapList Read FMap;
- Property DefaultElements : Boolean Read FDefaultElements Write FDefaultElements;
- Property OnLog : TLogEvent Read FOnLog Write FOnLog;
- end;
- { TFormCodeGen }
- TSpecialMethod = (smConstructor,smBindElements,smBindElementEvents);
- TSpecialMethods = Set of TSpecialMethod;
- TFormOption = (foEvents,foFormFile,foBindInConstructor);
- TFormOptions = Set of TFormOption;
- { TFormFileCodeGen }
- TFormFileCodeGen = Class(TPascalCodeGenerator)
- private
- FElementHeight: Word;
- FElementHSpacing: Word;
- FElementVSpacing: Word;
- FElementWidth: Word;
- FDoEvents: Boolean;
- FFormClassName: String;
- FFormElements: TFormElementList;
- FIDProperty: String;
- FLeft: Word;
- FMaxHeight: Word;
- FMaxWidth: Word;
- FTop: Word;
- Protected
- function GetFormName(const aClassName: string): String; virtual;
- procedure GenerateElements; virtual;
- procedure EmitElementEvents(El: TFormElement); virtual;
- procedure EmitElementProps(El: TFormElement); virtual;
- procedure NextPosition; virtual;
- Property ELeft : Word Read FLeft Write FLeft;
- Property ETop : Word Read FTop Write FTop;
- Public
- Constructor Create(aOwner : TComponent);override;
- Procedure Execute;
- Property FormElements: TFormElementList read FFormElements write FFormElements;
- Property FormClassName : String read FFormClassName write FFormClassName;
- Property DoEvents : Boolean read FDoEvents write FDoEvents;
- Property IDProperty : String Read FIDProperty Write FIDProperty;
- Property ElementHeight : Word Read FElementHeight Write FElementHeight;
- Property ElementWidth : Word Read FElementWidth Write FElementWidth;
- Property MaxWidth : Word Read FMaxWidth Write FMaxWidth;
- Property MaxHeight : Word Read FMaxHeight Write FMaxHeight;
- Property ElementHSpacing : Word Read FElementHSpacing Write FElementHSpacing;
- Property ElementVSpacing : Word Read FElementVSpacing Write FElementVSpacing;
- end;
- TFormCodeGen = Class(TPascalCodeGenerator)
- private
- FAddMethods: TSpecialMethods;
- FConstructorArgs: String;
- FEventModifiers: String;
- FEventSignature: string;
- FFormClassName: string;
- FFormElements: TFormElementList;
- fFormFileGenerator: TFormFileCodeGen;
- FFormSource: Tstrings;
- FGetElementFunction: string;
- FOptions: TFormOptions;
- FOverrideMethods: TSpecialMethods;
- FParentClassName: string;
- FVirtualMethods: TSpecialMethods;
- procedure SetFormElements(AValue: TFormElementList);
- Protected
- function BaseUnits : String; override;
- Function CreateHTMLToFormELements: THTMLToFormELements; virtual;
- Class Function CreateElementList : TFormElementList; virtual;
- procedure EmitFormFile; virtual;
- function CreateFormFileGen : TFormFileCodeGen; virtual;
- procedure EmitFormElement(aEL: TFormElement); virtual;
- procedure EmitFormEvents(aEL: TFormElement);virtual;
- procedure EmitImplementation; virtual;
- procedure EmitPublicSection; virtual;
- procedure EmitPublishedSection; virtual;
- procedure EmitFormBindElements; virtual;
- procedure EmitFormBindEvents; virtual;
- procedure EmitFormConstructor; virtual;
- function VirtualOverride(M: TSpecialMethod; const Decl: String): string; virtual;
- Public
- Constructor Create(aOwner : TComponent); override;
- Destructor Destroy; override;
- class function Pretty(const S: String): string; virtual;
- class procedure GetEventNameAndHandler(const S,aFieldName: String; out aName, aHandler: string);
- Procedure Execute;
- Property FormFileGenerator : TFormFileCodeGen Read fFormFileGenerator Write FFormFileGenerator;
- Property FormElements : TFormElementList Read FFormElements Write SetFormElements;
- Property FormClassName : string Read FFormClassName Write FFormClassName;
- Property ParentClassName : string Read FParentClassName Write FParentClassName;
- Property GetElementFunction : string Read FGetElementFunction Write FGetElementFunction;
- Property EventSignature: string Read FEventSignature Write FEventSignature;
- Property EventModifiers : String Read FEventModifiers Write FEventModifiers;
- Property ConstructorArgs : String Read FConstructorArgs Write FConstructorArgs;
- Property Options : TFormOptions Read FOptions Write FOptions;
- Property AddMethods : TSpecialMethods Read FAddMethods Write FAddMethods;
- Property OverrideMethods : TSpecialMethods Read FOverrideMethods Write FOverrideMethods;
- Property VirtualMethods : TSpecialMethods Read FVirtualMethods Write FVirtualMethods;
- Property FormSource : Tstrings Read FFormSource;
- end;
- implementation
- { TFormFileCodeGen }
- function TFormFileCodeGen.GetFormName(const aClassName: string): String;
- begin
- Result:=aClassName;
- if SameText(Copy(Result,1,1),'T') then
- Delete(Result,1,1);
- end;
- (*
- procedure TFormFileCodeGen.LoadFromStream(const AStream: TStream);
- begin
- if aStream=Nil then exit;
- end;
- *)
- constructor TFormFileCodeGen.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- IDProperty:='ElementID';
- ElementHeight:=24;
- ElementWidth:=72;
- ElementVSpacing:=8;
- ElementHSpacing:=16;
- MaxWidth:=800;
- MaxHeight:=600;
- end;
- procedure TFormFileCodeGen.NextPosition;
- begin
- ELeft:=ELeft+ElementWidth+ElementHSpacing;
- if ELeft+ElementWidth>=MaxWidth then
- begin
- ELeft:=8;
- ETop:=ETop+ElementHeight+ElementVSpacing;
- end;
- end;
- procedure TFormFileCodeGen.EmitElementProps(El : TFormElement);
- begin
- AddLn('Top = %d',[ETop]);
- AddLn('Left = %d',[ELeft]);
- Addln('Width = %d',[ElementWidth]);
- Addln('Height = %d',[ElementHeight]);
- addLn('%s = ''%s''',[IDProperty,El.Name]);
- end;
- procedure TFormFileCodeGen.EmitElementEvents(El : TFormElement);
- Var
- S,EN,EH : String;
- begin
- For S in El.Events do
- begin
- TFormCodeGen.GetEventNameAndHandler(S,El.Name,EN,EH);
- Addln('%s = %s',[EN,EH]);
- end;
- end;
- procedure TFormFileCodeGen.GenerateElements;
- Var
- I : Integer;
- El : TFormElement;
- begin
- For I:=0 to FormElements.Count-1 do
- begin
- el:=FormElements[i];
- With El do
- begin
- Addln('object %s: %s',[Name,ElementType]);
- Indent;
- EmitElementProps(EL);
- if DoEvents then
- EmitElementEvents(El);
- Undent;
- AddLn('end');
- NextPosition;
- end;
- end;
- end;
- procedure TFormFileCodeGen.Execute;
- begin
- ETop:=8;
- ELeft:=8;
- AddLn('object %s : %s',[GetFormName(FormClassName),FormClassName]);
- Indent;
- AddLn('Width = %d',[MaxWidth]);
- AddLn('Height = %d',[MaxHeight]);
- GenerateElements;
- Undent;
- AddLn('end');
- end;
- { THTMLElementMapList }
- function THTMLElementMapList.GetM(aIndex : Integer): THTMLElementMap;
- begin
- Result:=Items[aIndex] as THTMLElementMap;
- end;
- procedure THTMLElementMapList.LoadFromFile(const aFileName: String);
- Var
- F : TFileStream;
- begin
- F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(F);
- finally
- F.Free;
- end;
- end;
- procedure THTMLElementMapList.LoadFromStream(aStream: TStream);
- Var
- D : TJSONData;
- begin
- D:=GetJSON(aStream);
- try
- if D is TJSONArray then
- LoadFromJSON(D as TJSONArray);
- finally
- D.Free;
- end;
- end;
- procedure THTMLElementMapList.LoadFromJSON(aJSON: TJSONArray);
- Var
- E : TJSONEnum;
- begin
- For E in aJSON do
- if E.Value is TJSONObject then
- (Add as THTMLElementMap).LoadFromJSON(e.Value as TJSONObject);
- end;
- function THTMLElementMapList.IndexOfMap(aTag: SAXString; Attrs: TSAXAttributes
- ): Integer;
- begin
- Result:=0;
- While (Result<Count) and Not GetM(Result).IsMatch(aTag,Attrs) do
- Inc(Result);
- if Result=Count then
- Result:=-1;
- end;
- function THTMLElementMapList.FindMap(aTag: SAXString; Attrs: TSAXAttributes
- ): THTMLElementMap;
- Var
- Idx : Integer;
- begin
- Idx:=IndexOfMap(aTag,Attrs);
- If Idx=-1 then
- Result:=Nil
- else
- Result:=GetM(Idx);
- end;
- { THTMLElementMap }
- function THTMLElementMap.GetAttrConditionList: TAttributeConditionList;
- begin
- If FConditionList=Nil then
- FConditionList:=CreateConditionList;
- Result:=FConditionList
- end;
- function THTMLElementMap.CreateConditionList: TAttributeConditionList;
- begin
- Result:=TAttributeConditionList.Create(TAttributeCondition);
- end;
- destructor THTMLElementMap.Destroy;
- begin
- FreeAndNil(FConditionList);
- inherited Destroy;
- end;
- procedure THTMLElementMap.LoadFromJSON(aJSON: TJSONObject);
- Var
- A : TJSONObject;
- begin
- FTag:=aJSON.Get('tag','');
- ControlClass:=aJSON.Get('class','');
- A:=aJSON.Get('attrs',TJSONObject(Nil));
- If Assigned(A) then
- Attributes.LoadFromJSON(A);
- end;
- function THTMLElementMap.HasConditions: Boolean;
- begin
- Result:=Assigned(FConditionList) and (FConditionList.Count>0);
- end;
- function THTMLElementMap.IsMatch(aTag: SAXString; Attrs: TSAXAttributes): Boolean;
- begin
- Result:=SameText(UTF8Encode(aTag),FTag);
- if Result and HasConditions then
- Result:=Attributes.IsMatch(Attrs);
- end;
- { TAttributeConditionList }
- function TAttributeConditionList.GetC(aIndex : Integer): TAttributeCondition;
- begin
- Result:=TAttributeCondition(Items[aIndex]);
- end;
- procedure TAttributeConditionList.LoadFromJSON(aJSON: TJSONObject);
- Var
- E : TJSONEnum;
- A : TAttributeCondition;
- begin
- For E in aJSON do
- begin
- A:=Add as TAttributeCondition;
- A.LoadFromJSON(E.Key,E.Value);
- end;
- end;
- function TAttributeConditionList.IsMatch(Attrs: TSAXAttributes): Boolean;
- function GetIndex(const aName: SAXString): Integer;
- begin
- Result := Attrs.Length-1;
- while (Result>=0) and not SameText(UTF8Encode(Attrs.LocalNames[Result]),UTF8Encode(aName)) do
- Dec(Result);
- end;
- Var
- I,Idx : Integer;
- A : TAttributeCondition;
- begin
- Result:=True;
- I:=0;
- While Result and (I<Count) do
- begin
- A:=GetC(I);
- Idx:=GetIndex(UTF8Decode(A.Attribute));
- if A.Operation=aoNotPresent then
- Result:=Idx<0
- else
- Result:=A.IsMatch(UTF8Encode(Attrs.GetValue(Idx)));
- Inc(I);
- end;
- end;
- { TAttributeCondition }
- procedure TAttributeCondition.LoadFromJSON(aName: String; aValue: TJSONData);
- Var
- S : TJSONStringType;
- C : Char;
- begin
- Attribute:=aName;
- if aValue.JSONType=jtNull then
- Operation:=aoNotPresent
- else if aValue.JSONType=jtBoolean then
- begin
- if aValue.AsBoolean then
- Operation:=aoPresent
- else
- Operation:=aoNotPresent
- end
- else
- begin
- S:=aValue.AsString;
- If S<>'' then
- C:=S[1]
- else
- C:=#0;
- Case C of
- '-' : Operation:=aoNotEqual;
- '~' : Operation:=aoContains;
- else
- Operation:=aoEqual;
- Value:=S;
- end;
- if Operation in [aoNotEqual,aoContains] then
- Value:=Copy(S,2,Length(S)-1);
- end;
- end;
- function TAttributeCondition.IsMatch(aValue: String): Boolean;
- begin
- Case Operation of
- aoPresent : Result:=True;
- aoNotEqual : Result:=Not SameText(aValue,Value);
- aoEqual : Result:=SameText(aValue,Value);
- aoContains : Result:=Pos(LowerCase(Value),LowerCase(aValue))>0;
- end;
- end;
- { THTMLToFormELements }
- procedure THTMLToFormELements.SetFormElements(AValue: TFormElementList);
- begin
- if FFormElements=AValue then Exit;
- FFormElements:=AValue;
- end;
- procedure THTMLToFormELements.DoLog(const Msg: String);
- begin
- if Assigned(FOnLog) then
- FOnLog(Self,Msg);
- end;
- procedure THTMLToFormELements.DoLog(const Fmt: String; Args: array of const);
- begin
- DoLog(Format(Fmt,Args));
- end;
- function THTMLToFormELements.Maptype(aTag: SAXString; Atts: TSAXAttributes): String;
- var
- t : string;
- m : THTMLElementMap;
- begin
- Result:='';
- if Map.Count>0 then
- begin
- M:=Map.FindMap(aTag,Atts);
- if Assigned(m) then
- Exit(M.ControlClass)
- else if not DefaultElements then
- begin
- DoLog('Could not map tag %s',[aTag]);
- Exit;
- end;
- end;
- t:=lowercase(Utf8Encode(aTag));
- case t of
- 'input' : Result:='TJSHTMLInputElement';
- 'button' : Result:='TJSHTMLButtonElement';
- 'select' : Result:='TJSHTMLSelectElement';
- 'textarea' : Result:='TJSHTMLTextAreaElement';
- 'option' : Result:='';
- else
- Result:='TJSHTMLElement';
- end;
- end;
- function THTMLToFormELements.MakeValidName(aID: string): string;
- Var
- C : Char;
- begin
- Result:='';
- for C in aID do
- if C in ['_','a'..'z','A'..'Z','0'..'9'] then
- Result:=Result+C
- else
- Result:=Result+'_';
- end;
- procedure THTMLToFormELements.SetExcludeIDS(AValue: TStrings);
- begin
- if FExcludeIDS=AValue then Exit;
- FExcludeIDs.AddStrings(AValue,True);
- end;
- procedure THTMLToFormELements.DoStartElement(Sender: TObject;
- const NamespaceURI, LocalName, QName: SAXString; Atts: TSAXAttributes);
- Var
- aID,aType : String;
- El : TFormElement;
- begin
- if Not Assigned(atts) then exit;
- aID:=UTF8Encode(Atts.GetValue('','id'));
- if (aID='') or (FExcludeIDS.IndexOf(aID)>=0) then
- exit;
- if (Level=0) and (BelowID=aID) then
- Level:=1
- else if (BelowID<>'') and (Level<=0) then
- Exit;
- aType:=MapType(LocalName,Atts);
- if aType='' then
- DoLog('Ignoring tag %s with id %s',[LocalName,aID])
- else
- begin
- El:=FormElements.Add(MakeValidName(aID));
- EL.ElementType:=aType;
- EL.HTMLID:=aId;
- GetEvents(El,Atts);
- end
- end;
- procedure THTMLToFormELements.GetEvents(aEl : TFormElement; Atts : TSAXAttributes);
- Var
- I,aLen : Integer;
- aName : string;
- begin
- for I:=0 to Atts.Length-1 do
- begin
- aName:=UTF8Encode(Atts.GetLocalName(i));
- aLen:=Length(aName);
- if (aLen>3) and (Copy(aName,1,1)='_') and (Copy(aName,aLen,1)='_') then
- aEl.Events.Add(Copy(aName,2,aLen-2)+'='+UTF8Encode(Atts.GetValue(i)));
- end;
- end;
- procedure THTMLToFormELements.DoEndElement(Sender: TObject; const NamespaceURI,
- LocalName, QName: SAXString);
- begin
- if Level>0 then
- Dec(FLevel);
- end;
- class function THTMLToFormELements.CreateElementList: TFormElementList;
- begin
- Result:=TFormElementList.Create(TFormElement);
- end;
- function THTMLToFormELements.CreateHTMLElementMapList: THTMLElementMapList;
- begin
- Result:=THTMLElementMapList.Create(THTMLElementMap);
- end;
- constructor THTMLToFormELements.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- FMap:=CreateHTMLElementMapList;
- FFormElements:=CreateElementList;
- FExcludeIDS:=TStringList.Create;
- TStringList(FExcludeIDS).Sorted:=True;
- end;
- destructor THTMLToFormELements.Destroy;
- begin
- FreeAndNil(FMap);
- FreeAndNil(FExcludeIDS);
- FreeAndNil(FFormElements);
- inherited Destroy;
- end;
- procedure THTMLToFormELements.Clear;
- begin
- FFormElements.Clear;
- end;
- procedure THTMLToFormELements.LoadFromStream(aInput: TStream);
- var
- MyReader : THTMLReader;
- begin
- MyReader:=THTMLReader.Create;
- Try
- MyReader.OnStartElement:=@DoStartElement;
- MyReader.OnEndElement:=@DoEndElement;
- MyReader.ParseStream(aInput);
- finally
- FreeAndNil(MyReader);
- end;
- end;
- procedure THTMLToFormELements.LoadFromFile(const aFileName: String);
- var
- F : TFileStream;
- begin
- F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(F);
- finally
- F.Free;
- end;
- end;
- { TFormCodeGen }
- procedure TFormCodeGen.SetFormElements(AValue: TFormElementList);
- begin
- if FFormElements=AValue then Exit;
- FFormElements.Assign(AValue);
- end;
- function TFormCodeGen.BaseUnits: String;
- begin
- Result:='js, web';
- end;
- class function TFormCodeGen.CreateElementList: TFormElementList;
- begin
- Result:=TFormElementList.Create(TFormElement);
- end;
- constructor TFormCodeGen.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- // Assume class is TComponent descendant
- FConstructorArgs:='aOwner : TComponent';
- FFormElements:=CreateElementList;
- FormClassName:='TMyForm';
- ParentClassName:='TComponent';
- EventSignature:='Event : TJSEvent';
- EventModifiers:='virtual; abstract;';
- GetElementFunction:='document.getelementByID';
- AddMethods:=[smConstructor,smBindElements,smBindElementEvents];
- VirtualMethods:=[smBindElementEvents,smBindElements];
- OverrideMethods:=[smConstructor];
- Options:=[foBindInConstructor];
- fFormFileGenerator:=CreateFormFileGen;
- FFormSource:=TStringList.Create;
- end;
- destructor TFormCodeGen.Destroy;
- begin
- FreeAndNil(FFormSource);
- FreeAndNil(fFormFileGenerator) ;
- FreeAndNil(FFormElements);
- inherited Destroy;
- end;
- procedure TFormCodeGen.EmitFormElement(aEL : TFormElement);
- begin
- With aEl do
- AddLn('%s : %s;',[Name,ElementType]) ;
- end;
- procedure TFormCodeGen.EmitFormEvents(aEL : TFormElement);
- Var
- S,EN,EH : String;
- begin
- if not aEl.HasEvents then
- exit;
- For S in aEl.Events do
- begin
- GetEventNameAndHandler(S,aEl.Name,EN,EH);
- Addln('Procedure %s(%s); %s',[EH, EventSignature,EventModifiers]);
- end;
- end;
- procedure TFormCodeGen.EmitPublishedSection;
- var
- I : Integer;
- begin
- For I:=0 to FormElements.Count-1 do
- EmitFormElement(FormElements[i]);
- if foEvents in Options then
- For I:=0 to FormElements.Count-1 do
- EmitFormEvents(FormElements[i]);
- end;
- function TFormCodeGen.VirtualOverride(M: TSpecialMethod; const Decl: String): string;
- begin
- Result:=Decl;
- if M in OverrideMethods then
- Result:=Result+' override;'
- else if M in VirtualMethods then
- Result:=Result+' virtual;'
- end;
- procedure TFormCodeGen.EmitPublicSection;
- begin
- if smConstructor in AddMethods then
- Addln(VirtualOverride(smConstructor,'Constructor create('+ConstructorArgs+');'));
- if smBindElements in AddMethods then
- Addln(VirtualOverride(smBindElements, 'Procedure BindElements;'));
- if (smBindElementEvents in AddMethods) and (foEvents in Options) then
- Addln(VirtualOverride(smBindElementEvents,'Procedure BindElementEvents;'));
- end;
- procedure TFormCodeGen.Execute;
- begin
- Source.Clear;
- Addln('unit %s;',[OutputUnitName]);
- CreateHeader;
- Addln('Type');
- Indent;
- ClassHeader(FormClassName);
- AddLn('%s = class(%s) ',[FormClassName,ParentClassName]);
- Addln('Published');
- Indent;
- EmitPublishedSection;
- Undent;
- Addln('Public');
- Indent;
- EmitPublicSection;
- Undent;
- Addln('end;');
- Undent;
- Addln('');
- Addln('implementation');
- AddLn('');
- if (foFormFile in Options) then
- begin
- EmitFormFile;
- AddLn('');
- AddLn('{$R *.dfm}');
- AddLn('');
- end;
- ClassHeader(FormClassName);
- EmitImplementation;
- AddLn('');
- AddLn('end.');
- end;
- procedure TFormCodeGen.EmitFormFile;
- begin
- FormFileGenerator.FormElements:=Self.FormElements;
- FormFileGenerator.DoEvents:=foEvents in Options;
- FormFileGenerator.FormClassName:=Self.FormClassName;
- FormFileGenerator.Execute;
- FormSource.Assign(FormFileGenerator.Source);
- end;
- function TFormCodeGen.CreateFormFileGen: TFormFileCodeGen;
- begin
- Result:=TFormFileCodeGen.Create(Nil);
- end;
- function TFormCodeGen.CreateHTMLToFormELements: THTMLToFormELements;
- begin
- Result:=THTMLToFormELements.Create(Self);
- end;
- procedure TFormCodeGen.EmitFormConstructor;
- begin
- Addln('');
- Addln('Constructor %s.create(aOwner : TComponent);',[FormClassName]);
- if not (foBindInConstructor in Options) then
- SimpleMethodBody(['Inherited;'])
- else
- begin
- if foEvents in Options then
- SimpleMethodBody(['Inherited;','BindElements;','BindElementEvents;'])
- else
- SimpleMethodBody(['Inherited;','BindElements;']);
- end;
- Addln('');
- end;
- procedure TFormCodeGen.EmitImplementation;
- begin
- if smConstructor in AddMethods then
- EmitFormConstructor;
- if (smBindElements in AddMethods) then
- EmitFormBindElements;
- if (foEvents in Options) and Not (foFormFile in Options) and (smBindElementEvents in AddMethods) then
- EmitFormBindEvents;
- end;
- procedure TFormCodeGen.EmitFormBindElements;
- var
- I : integer;
- El : TFormElement;
- begin
- Addln('');
- Addln('Procedure %s.BindElements;',[FormClassName]);
- Addln('');
- AddLn('begin');
- Indent;
- if smBindElements in OverrideMethods then
- AddLn('inherited;');
- For I:=0 to FormElements.Count-1 do
- begin
- el:=FormElements[i];
- With El do
- Addln('%s:=%s(%s(''%s''));',[Name,ElementType,GetElementFunction,HTMLID]);
- end;
- Undent;
- Addln('end;');
- Addln('');
- end;
- class function TFormCodeGen.Pretty(const S: String): string;
- begin
- Result:=UpperCase(Copy(S,1,1))+LowerCase(Copy(S,2,Length(S)-1));
- end;
- class procedure TFormCodeGen.GetEventNameAndHandler(const S,
- aFieldName: String; out aName, aHandler: string);
- Var
- P : Integer;
- begin
- P:=Pos('=',S);
- if (P=0) then
- P:=Length(S)+1;
- aName:=Copy(S,1,P-1);
- aHandler:=Copy(S,P+1,Length(S)-P);
- if AHandler='' then
- aHandler:=aFieldName+Pretty(aName);
- // Writeln(aFieldName,': ',S,' -> ',aName,' & ',aHandler);
- end;
- procedure TFormCodeGen.EmitFormBindEvents;
- var
- I : integer;
- El : TFormElement;
- S,EN,EH : String;
- begin
- Addln('Procedure %s.BindElementEvents;',[FormClassName]);
- Addln('');
- AddLn('begin');
- Indent;
- if smBindElementEvents in OverrideMethods then
- AddLn('inherited;');
- For I:=0 to FormElements.Count-1 do
- begin
- el:=FormElements[i];
- With El do
- if HasEvents then
- For S in El.Events do
- begin
- GetEventNameAndHandler(S,Name,EN,EH);
- Addln('%s.AddEventListener(''%s'',@%s);',[Name,EN,EH]);
- end;
- end;
- Undent;
- Addln('end;');
- end;
- { TFormElementList }
- function TFormElementList.GetEl(aIndex : Integer): TFormElement;
- begin
- Result:=Items[aIndex] as TFormElement;
- end;
- function TFormElementList.Add(const aName: string): TFormElement;
- begin
- if IndexOf(aName)<>-1 then
- Raise Exception.CreateFmt('Duplicate name : %s' ,[aName]);
- Result:=(Inherited Add) as TFormElement;
- Result.Name:=aName;
- end;
- function TFormElementList.IndexOf(const aName: string): Integer;
- begin
- Result:=Count-1;
- While (Result>=0) and Not SameText(aName,GetEl(Result).Name) do
- Dec(Result);
- end;
- function TFormElementList.Find(const aName: string): TFormElement;
- var
- Idx : Integer;
- begin
- Idx:=IndexOf(aName);
- if Idx>=0 then
- Result:=GetEl(Idx)
- else
- Result:=Nil;
- end;
- { TFormElement }
- function TFormElement.GetEvents: TStrings;
- begin
- If (FEvents=Nil) then
- FEvents:=TStringList.Create;
- Result:=FEvents;
- end;
- function TFormElement.getName: String;
- begin
- Result:=FName;
- if Result='' then
- Result:=HTMLID;
- end;
- procedure TFormElement.SetEvents(AValue: TStrings);
- begin
- If AValue=FEVents then exit;
- Events.Assign(aValue);
- end;
- destructor TFormElement.Destroy;
- begin
- FreeAndNil(FEvents);
- inherited Destroy;
- end;
- function TFormElement.HasEvents: Boolean;
- begin
- Result:=Assigned(FEvents) and (FEvents.Count>0);
- end;
- procedure TFormElement.Assign(Source: TPersistent);
- Var
- FE : TFormElement absolute Source;
- begin
- if Source is TFormElement then
- begin
- FHTMLID:=FE.HTMLID;
- FName:=FE.FName;
- FType:=FE.FType;
- if FE.HasEvents then
- Events:=FE.Events;
- end
- else
- inherited Assign(Source);
- end;
- end.
|