Changeset 26 for trunk/UHtmlClasses.pas


Ignore:
Timestamp:
Sep 10, 2022, 8:03:08 PM (20 months ago)
Author:
chronos
Message:
  • Removed: TemplateGenerics as required package. Used Generics.Collections instead.
Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

    • Property svn:ignore
      •  

        old new  
        77heaptrclog.trc
        88MyData.exe
         9MyData.dbg
         10
  • trunk/UHtmlClasses.pas

    r19 r26  
    11unit UHtmlClasses;
    22
    3 {$mode delphi}{$H+}
    4 
    53interface
    64
    75uses
    8   UXmlClasses, Classes, SysUtils, SpecializedList;
     6  UXmlClasses, Classes, SysUtils, Generics.Collections, UGenerics, UIpAddress;
    97
    108type
    11 
    12   { TDomainAddress }
    13 
    14   TDomainAddress = class(TPersistent)
    15   private
    16     function GetAsString: string;
    17     procedure SetAsString(const Value: string);
    18   public
    19     Levels: TListString;
    20     constructor Create;
    21     destructor Destroy; override;
    22     property AsString: string read GetAsString write SetAsString;
    23   end;
    24 
    25   TAddrClass = (acA, acB, acC, acD, acE);
    26 
    27   { TIpAddress }
    28 
    29   TIpAddress = class(TPersistent)
    30   private
    31     function GetAddrClass: TAddrClass;
    32     function GetAsCardinal: Cardinal;
    33     function GetAsString: string;
    34     function GetBroadcast: Boolean;
    35     procedure SetBroadcast(const Value: Boolean);
    36     procedure SetAsCardinal(const Value: Cardinal);
    37     procedure SetAsString(const Value: string);
    38   public
    39     Octets: array[0..3] of Byte;
    40     procedure Assign(Source: TPersistent); override;
    41     function IsAddressString(Value: string): Boolean;
    42     property AsCardinal: Cardinal read GetAsCardinal write SetAsCardinal;
    43     property AsString: string read GetAsString write SetAsString;
    44     property AddrClass: TAddrClass read GetAddrClass;
    45     property Broadcast: Boolean read GetBroadcast write SetBroadcast;
    46   end;
    47 
    48   THostAddressState = (asDomainName, asIpAddress);
    49   THostAddress = class(TPersistent)
    50   private
    51     function GetAsString: string;
    52     procedure SetAsString(const Value: string);
    53   public
    54     State: THostAddressState;
    55     DomainName: TDomainAddress;
    56     IpAddress: TIpAddress;
    57     constructor Create;
    58     destructor Destroy; override;
    59     property AsString: string read GetAsString write SetAsString;
    60   end;
     9  { TURL }
    6110
    6211  TURL = class(TPersistent)
     
    9241  end;
    9342
     43  THtmlString = class;
     44  THtmlBlock = class;
     45  THtmlList = class;
     46  THtmlInput = class;
     47
     48  { THtmlElements }
     49
     50  THtmlElements = class(TObjectList<THtmlElement>)
     51    function AddString(Text: string = ''): THtmlString;
     52    function AddBlock: THtmlBlock;
     53    function AddList: THtmlList;
     54    function AddInput: THtmlInput;
     55  end;
     56
    9457  TBlockType = (btNoTag, btBlockLevel, btInline);
    9558
     
    9760
    9861  THtmlString = class(THtmlElement)
    99   private
     62  protected
    10063    function GetAsXmlElement: TXmlElement; override;
    10164  public
     
    10770
    10871  THtmlLineBreak = class(THtmlElement)
    109   private
     72  protected
    11073    function GetAsXmlElement: TXmlElement; override;
    11174  public
     
    11881  public
    11982    BlockType: TBlockType;
    120     SubItems: TListObject; // TListObject<THtmlElement>;
     83    SubItems: THtmlElements;
     84    constructor Create;
     85    destructor Destroy; override;
     86  end;
     87
     88  TListType = (ltUnordered, ltOrdered);
     89
     90  { THtmlList }
     91
     92  THtmlList = class(THtmlElement)
     93  protected
     94    function GetAsXmlElement: TXmlElement; override;
     95  public
     96    ListType: TListType;
     97    SubItems: THtmlElements;
    12198    constructor Create;
    12299    destructor Destroy; override;
     
    124101
    125102  THtmlLink = class(THtmlElement)
    126   private
     103  protected
    127104    function GetAsXmlElement: TXmlElement; override;
    128105  public
     
    142119
    143120  THtmlImage = class(THtmlElement)
    144   private
     121  protected
    145122    function GetAsXmlElement: TXmlElement; override;
    146123  public
     
    158135
    159136  THtmlInput = class(THtmlElement)
    160   private
     137  protected
    161138    function GetAsXmlElement: TXmlElement; override;
    162139  public
     
    199176
    200177  THtmlCell = class(THtmlElement)
    201   private
     178  protected
    202179    function GetAsXmlElement: TXmlElement; override;
    203180  public
     
    209186  end;
    210187
     188  { THtmlCells }
     189
     190  THtmlCells = class(TObjectList<THtmlCell>)
     191    function AddCell: THtmlCell;
     192  end;
     193
    211194  { THtmlRow }
    212195
    213196  THtmlRow = class(THtmlElement)
    214   private
    215     function GetAsXmlElement: TXmlElement; override;
    216   public
    217     Cells: TListObject; // TListObject<THtmlCell>
    218     constructor Create;
    219     destructor Destroy; override;
     197  protected
     198    function GetAsXmlElement: TXmlElement; override;
     199  public
     200    Cells: THtmlCells;
     201    constructor Create;
     202    destructor Destroy; override;
     203  end;
     204
     205  { THtmlRows }
     206
     207  THtmlRows = class(TObjectList<THtmlRow>)
     208    function AddRow: THtmlRow;
    220209  end;
    221210
     
    226215    function GetAsXmlElement: TXmlElement; override;
    227216  public
    228     Rows: TListObject; // TListObject<THtmlRow>
     217    Rows: THtmlRows;
    229218    constructor Create;
    230219    destructor Destroy; override;
     
    242231  end;
    243232
     233
    244234implementation
    245 
    246 resourcestring
    247   SStringToIPConversionError = 'String to IP address conversion error';
    248 
    249235
    250236function LeftCutString(var Source, Output: string; Delimiter: string; Allowed: string = ''): Boolean;
     
    255241  I := 1;
    256242  Matched := True;
    257   while (I <= Length(Source)) and Matched do begin
     243  while (I < Length(Source)) and Matched do begin
    258244    Matched := False;
    259     if (Source[I] >= 'A') and (Source[I] <= 'Z') then Matched := True
    260     else if (Source[I] >= 'a') and (Source[I] <= 'z') then Matched := True
    261     else if (Source[I] >= '0') and (Source[I] <= '9') then Matched := True
    262     else for J := 1 to Length(Allowed) do
     245    if (Source[I] >= 'A') and (Source[I] <= 'Z') then Matched := True;
     246    if (Source[I] >= 'a') and (Source[I] <= 'z') then Matched := True;
     247    if (Source[I] >= '0') and (Source[I] <= '9') then Matched := True;
     248    for J := 1 to Length(Allowed) do
    263249      if Source[I] = Allowed[J] then Matched := True;
    264250    if Matched then Inc(I);
    265251  end;
    266252  if (Delimiter = Copy(Source, I, Length(Delimiter))) or (I = Length(Source)) then begin
    267     Output := Copy(Source, 1, I - 1);
     253    Output := Copy(Source, 1, I-1);
    268254    Delete(Source, 1, Length(Output) + Length(Delimiter));
    269255    Result := True;
     
    300286end;
    301287
     288{ THtmlCells }
     289
     290function THtmlCells.AddCell: THtmlCell;
     291begin
     292  Result := THtmlCell.Create;
     293  Add(Result);
     294end;
     295
     296{ THtmlRows }
     297
     298function THtmlRows.AddRow: THtmlRow;
     299begin
     300  Result := THtmlRow.Create;
     301  Add(Result);
     302end;
     303
     304{ THtmlList }
     305
     306function THtmlList.GetAsXmlElement: TXmlElement;
     307var
     308  I: Integer;
     309begin
     310  Result := TXmlTag.Create;
     311  with TXmlTag(Result) do begin
     312    case ListType of
     313      ltOrdered: Name := 'ol';
     314      ltUnordered: Name := 'ul';
     315    end;
     316    for I := 0 to SubItems.Count - 1 do begin
     317      with SubElements.AddTag('li') do
     318        SubElements.Add(SubItems[I].AsXmlElement);
     319    end;
     320  end;
     321end;
     322
     323constructor THtmlList.Create;
     324begin
     325  inherited;
     326  SubItems := THtmlElements.Create;
     327end;
     328
     329destructor THtmlList.Destroy;
     330begin
     331  FreeAndNil(SubItems);
     332  inherited;
     333end;
     334
     335{ THtmlElements }
     336
     337function THtmlElements.AddString(Text: string = ''): THtmlString;
     338begin
     339  Result := THtmlString.Create;
     340  Result.Text := Text;
     341  Add(Result);
     342end;
     343
     344function THtmlElements.AddBlock: THtmlBlock;
     345begin
     346  Result := THtmlBlock.Create;
     347  Add(Result);
     348end;
     349
     350function THtmlElements.AddList: THtmlList;
     351begin
     352  Result := THtmlList.Create;
     353  Add(Result);
     354end;
     355
     356function THtmlElements.AddInput: THtmlInput;
     357begin
     358  Result := THtmlInput.Create;
     359  Add(Result);
     360end;
     361
    302362{ THtmlCell }
    303363
     
    321381destructor THtmlCell.Destroy;
    322382begin
    323   Value.Free;
    324   inherited Destroy;
     383  FreeAndNil(Value);
     384  inherited;
    325385end;
    326386
     
    334394  TXmlTag(Result).Name := 'tr';
    335395  for Column := 0 to Cells.Count - 1 do
    336     TXmlTag(Result).SubElements.AddNew(THtmlCell(Cells[Column]).AsXmlElement);
     396    TXmlTag(Result).SubElements.Add(Cells[Column].AsXmlElement);
    337397end;
    338398
    339399constructor THtmlRow.Create;
    340400begin
    341   Cells := TListObject.Create;
     401  Cells := THtmlCells.Create;
    342402end;
    343403
    344404destructor THtmlRow.Destroy;
    345405begin
    346   Cells.Free;
    347   inherited Destroy;
     406  FreeAndNil(Cells);
     407  inherited;
    348408end;
    349409
     
    352412function THtmlTable.GetAsXmlElement: TXmlElement;
    353413var
    354   Row, Column: Integer;
     414  Row: Integer;
    355415begin
    356416  Result := inherited;
     
    358418    Name := 'table';
    359419    for Row := 0 to Rows.Count - 1 do
    360       SubElements.AddNew(THtmlRow(Rows[Row]).AsXmlElement);
     420      SubElements.Add(Rows[Row].AsXmlElement);
    361421  end;
    362422end;
     
    364424constructor THtmlTable.Create;
    365425begin
    366   Rows := TListObject.Create;
     426  Rows := THtmlRows.Create;
    367427end;
    368428
    369429destructor THtmlTable.Destroy;
    370430begin
    371   Rows.Free;
    372   inherited Destroy;
     431  FreeAndNil(Rows);
     432  inherited;
    373433end;
    374434
     
    421481constructor THtmlInput.Create;
    422482begin
    423 
    424483end;
    425484
    426485destructor THtmlInput.Destroy;
    427486begin
    428   inherited Destroy;
     487  inherited;
    429488end;
    430489
     
    451510destructor THtmlForm.Destroy;
    452511begin
    453   Action.Free;
    454   inherited Destroy;
     512  FreeAndNil(Action);
     513  inherited;
    455514end;
    456515
     
    468527destructor THtmlDocument.Destroy;
    469528begin
    470   Body.Free;
    471   Styles.Free;
    472   Scripts.Free;
     529  FreeAndNil(Body);
     530  FreeAndNil(Styles);
     531  FreeAndNil(Scripts);
    473532  inherited;
    474533end;
     
    476535function THtmlDocument.GetAsXmlDocument: TXmlDocument;
    477536var
    478   DocType: TXMLTag;
    479   HTMLTag: TXMLTag;
    480537  I: Integer;
    481538begin
    482539  Result := TXmlDocument.Create;
    483540  with Result, Content do begin
    484     DocType := TXMlTag.Create;
    485     DocType.Name := '!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"';
    486     Doctype.EndTagSymbol := '';
    487     SubElements.Add(DocType);
    488     HTMLTag := TXMLTag.Create;
    489     with HTMLTag do begin
    490       Name := 'html';
    491       with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    492         Name := 'head';
    493         with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    494           Name := 'title';
    495           with TXmlString(SubElements[SubElements.Add(TXmlString.Create)]) do begin
    496             Text := Title;
    497           end;
     541    with SubElements.AddTag('!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"') do begin
     542      EndTagSymbol := '';
     543    end;
     544    with SubElements.AddTag('html') do begin
     545      with SubElements.AddTag('head') do begin
     546        with SubElements.AddTag('title') do begin
     547          SubElements.AddString(Title);
    498548        end;
    499         with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    500           Name := 'meta';
     549        with SubElements.AddTag('meta') do begin
    501550          Attributes.Add('http-equiv', 'Content-Language');
    502551          Attributes.Add('content', ContentLanguage);
    503552        end;
    504         with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    505           Name := 'meta';
     553        with SubElements.AddTag('meta') do begin
    506554          Attributes.Add('http-equiv', 'Content-Type');
    507555          Attributes.Add('content', 'text/html; charset=' + ContentEncoding);
    508556        end;
     557        with SubElements.AddTag('meta') do begin
     558          Attributes.Add('name', 'viewport');
     559          Attributes.Add('content', 'width=device-width, initial-scale=1');
     560        end;
    509561        for I := 0 to Styles.Count - 1 do
    510         with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    511           Name := 'link';
     562        with SubElements.AddTag('link') do begin
    512563          Attributes.Add('rel', 'stylesheet');
    513564          Attributes.Add('href', Styles[I]);
     
    516567        end;
    517568        for I := 0 to Scripts.Count - 1 do
    518         with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    519           Name := 'script';
     569        with SubElements.AddTag('script') do begin
    520570          ShringEmpty := False;
    521571          Attributes.Add('type', 'text/javascript');
     
    523573        end;
    524574      end;
    525       with TXmlTag(SubElements[SubElements.Add(TXmlTag.Create)]) do begin
    526         Name := 'body';
     575      with SubElements.AddTag('body') do begin
    527576        SubElements.Add(Body.AsXmlElement);
    528577      end;
    529578    end;
    530     SubElements.Add(HTMLTag);
    531579  end;
    532580end;
     
    537585begin
    538586  inherited;
    539   SubItems := TListObject.Create;
     587  SubItems := THtmlElements.Create;
    540588end;
    541589
    542590destructor THtmlBlock.Destroy;
    543591begin
    544   SubItems.Free;
     592  FreeAndNil(SubItems);
    545593  inherited;
    546594end;
     
    558606    end;
    559607    for I := 0 to SubItems.Count - 1 do
    560       SubElements.Add(THtmlElement(SubItems[I]).AsXmlElement);
     608      SubElements.Add(SubItems[I].AsXmlElement);
    561609   end;
    562610end;
     
    583631end;
    584632
    585 { TIpAddress }
    586 
    587 procedure TIpAddress.Assign(Source: TPersistent);
    588 var
    589   I: Integer;
    590 begin
    591   if Assigned(Source) then begin
    592     if Source is TIpAddress then begin
    593       for I := 0 to High(Octets) do
    594         Octets[I] := TIpAddress(Source).Octets[I];
    595     end else inherited;
    596   end else inherited;
    597 end;
    598 
    599 function TIpAddress.IsAddressString(Value: string): Boolean;
    600 var
    601   Parts: TListString;
    602 begin
    603   Result := True;
    604   try
    605     Parts := TListString.Create;
    606     Parts.Explode(Value, '.', StrToStr);
    607     if Parts.Count = 4 then begin
    608       if (StrToInt(Parts[3]) < 0) or (StrToInt(Parts[3]) > 255) then Result := False;
    609       if (StrToInt(Parts[2]) < 0) or (StrToInt(Parts[2]) > 255) then Result := False;
    610       if (StrToInt(Parts[1]) < 0) or (StrToInt(Parts[1]) > 255) then Result := False;
    611       if (StrToInt(Parts[0]) < 0) or (StrToInt(Parts[0]) > 255) then Result := False;
    612     end else Result := False;
    613   finally
    614     Parts.Free;
    615   end;
    616 end;
    617 
    618 function TIpAddress.GetAddrClass: TAddrClass;
    619 begin
    620   if (Octets[3] and $80) = 0 then Result := acA
    621   else begin
    622     if (Octets[3] and $40) = 0 then Result := acB
    623     else begin
    624       if (Octets[3] and $20) = 0 then Result := acC
    625       else begin
    626         if (Octets[3] and $10) = 0 then Result := acD
    627         else Result := acE;
    628       end;
    629     end;
    630   end;
    631 end;
    632 
    633 function TIpAddress.GetAsCardinal: Cardinal;
    634 begin
    635   Result := Octets[0] or (Octets[1] shl 8) or (Octets[2] shl 16) or (Octets[3] shl 24);
    636 end;
    637 
    638 function TIpAddress.GetAsString: string;
    639 begin
    640   Result := IntToStr(Octets[3]) + '.' + IntToStr(Octets[2]) + '.' +
    641     IntToStr(Octets[1]) + '.' + IntToStr(Octets[0]);
    642 end;
    643 
    644 function TIpAddress.GetBroadcast: Boolean;
    645 begin
    646   Result := AsCardinal = High(Cardinal);
    647 end;
    648 
    649 procedure TIpAddress.SetAsCardinal(const Value: Cardinal);
    650 begin
    651   Octets[0] := Byte(Value);
    652   Octets[1] := Byte(Value shr 8);
    653   Octets[2] := Byte(Value shr 16);
    654   Octets[3] := Byte(Value shr 24);
    655 end;
    656 
    657 procedure TIpAddress.SetAsString(const Value: string);
    658 var
    659   Parts: TListString;
    660 begin
    661   try
    662     Parts := TListString.Create;
    663     Parts.Explode(Value, '.', StrToStr);
    664     try
    665 //    if Length(Parts) = 4 then begin
    666       Octets[0] := StrToInt(Parts[3]);
    667       Octets[1] := StrToInt(Parts[2]);
    668       Octets[2] := StrToInt(Parts[1]);
    669       Octets[3] := StrToInt(Parts[0]);
    670 //    end else raise EConvertError.Create('String to IP address conversion error');
    671     except
    672       raise EConvertError.Create(SStringToIPConversionError);
    673     end;
    674   finally
    675     Parts.Free;
    676   end;
    677 end;
    678 
    679 procedure TIpAddress.SetBroadcast(const Value: Boolean);
    680 begin
    681   AsCardinal := High(Cardinal);
    682 end;
     633{ TURL }
    683634
    684635constructor TURL.Create;
     
    689640destructor TURL.Destroy;
    690641begin
    691   Host.Free;
     642  FreeAndNil(Host);
    692643  inherited;
    693644end;
     
    724675  end else LeftCutString(Value, HostAddr, '', '.');
    725676  Host.AsString := HostAddr;
    726   LeftCutString(Value, Path, '', '/._');
    727 end;
    728 
    729 
    730 { TDomainAddress }
    731 
    732 function TDomainAddress.GetAsString: string;
    733 begin
    734   try
    735     Levels.Reverse;
    736     Result := Levels.Implode('.', StrToStr);
    737   finally
    738     Levels.Reverse;
    739   end;
    740 end;
    741 
    742 procedure TDomainAddress.SetAsString(const Value: string);
    743 begin
    744   Levels.Explode(Value, '.', StrToStr);
    745   Levels.Reverse;
    746 end;
    747 
    748 constructor TDomainAddress.Create;
    749 begin
    750   Levels := TListString.Create;
    751 end;
    752 
    753 destructor TDomainAddress.Destroy;
    754 begin
    755   Levels.Free;
    756   inherited Destroy;
     677  LeftCutString(Value, Path, '', '/.');
    757678end;
    758679
     
    766687destructor THtmlLink.Destroy;
    767688begin
    768   Target.Free;
     689  FreeAndNil(Target);
    769690  inherited;
    770691end;
     
    794715end;
    795716
    796 { THostAddress }
    797 
    798 constructor THostAddress.Create;
    799 begin
    800   DomainName := TDomainAddress.Create;
    801   IpAddress := TIpAddress.Create;
    802   State := asDomainName;
    803   DomainName.AsString := 'localhost';
    804 end;
    805 
    806 destructor THostAddress.Destroy;
    807 begin
    808   DomainName.Free;
    809   IpAddress.Free;
    810   inherited;
    811 end;
    812 
    813 function THostAddress.GetAsString: string;
    814 begin
    815   case State of
    816     asDomainName: Result := DomainName.AsString;
    817     asIpAddress: Result := IpAddress.AsString;
    818   end;
    819 end;
    820 
    821 procedure THostAddress.SetAsString(const Value: string);
    822 begin
    823   if IpAddress.IsAddressString(Value) then begin
    824     State := asIpAddress;
    825     IpAddress.AsString := Value;
    826   end else begin
    827     State := asDomainName;
    828     DomainName.AsString := Value;
    829   end;
    830 end;
    831 
    832717{ THtmlImage }
    833718
     
    839724destructor THtmlImage.Destroy;
    840725begin
    841   Source.Free;
     726  FreeAndNil(Source);
    842727  inherited;
    843728end;
     
    892777destructor TQueryString.Destroy;
    893778begin
    894   Data.Free;
    895   inherited Destroy;
     779  FreeAndNil(Data);
     780  inherited;
    896781end;
    897782
Note: See TracChangeset for help on using the changeset viewer.