{
This file is part of the Free Pascal run time library.
Copyright (c) 2019-Now by Michael Van Canneyt, member of the
Free Pascal development team
WEB Widget Set : Basic bare HTML Widgets
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 htmlwidgets;
{$mode objfpc}
interface
uses
Classes, SysUtils, webwidget, js, web;
Type
TTextMode = (tmText,tmHTML);
{ TButtonWidget }
TButtonWidget = Class(TWebWidget)
private
FText: String;
FTextMode: TTextMode;
procedure SetText(AValue: String);
procedure SetTextMode(AValue: TTextMode);
Protected
procedure ApplyText(aElement: TJSHTMLElement);
Procedure SetName(const NewName: TComponentName); override;
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Public
Procedure Click;
Function HTMLTag : String; override;
Published
Property Text : String Read FText Write SetText;
Property TextMode : TTextMode Read FTextMode Write SetTextMode;
end;
{ TViewPort }
TViewPort = Class(TCustomWebWidget)
Private
Class var FInstance : TViewPort;
Protected
Class Function FixedParent : TJSHTMLElement; override;
Class Function FixedElement : TJSHTMLElement; override;
Function DoRenderHTML(aParent,aElement : TJSHTMLElement) :TJSHTMLElement; override;
Public
Constructor Create (aOwner: TComponent); override;
Function HTMLTag : String; override;
Class Function Instance : TViewPort;
Property Element;
end;
{ TWebPage }
TWebPage = Class(TCustomWebWidget)
private
Protected
Class Function DefaultParentElement: TJSHTMLElement; override;
Class Function DefaultParent : TCustomWebWidget; override;
Procedure DoUnRender(aParent : TJSHTMLElement) ; override;
Public
Constructor Create(AOwner : TComponent); override;
Function HTMLTag : String; override;
// Later on, allow IFrame;
Published
Property ParentID;
Property ElementID;
Property Classes;
Property Styles;
Property StyleRefresh;
Property Visible;
// Events
Property BeforeRenderHTML;
Property AfterRenderHTML;
Property OnAbort;
Property OnAnimationCancel;
Property OnAnimationEnd;
Property OnAnimationIteration;
Property OnAnimationStart;
Property OnAuxClick;
Property OnBlur;
Property OnCancel;
Property OnCanPlay;
Property OnCanPlayThrough;
Property OnChange;
Property OnClick;
Property OnCompositionEnd;
Property OnCompositionStart;
Property OnCompositionUpdate;
Property OnContextMenu;
Property OnCopy;
Property OnCut;
Property OnCueChange;
Property OnDblClick;
Property OnDurationChange;
Property OnEnded ;
Property OnError ;
Property OnFocus;
Property OnFocusIn ;
Property OnFocusOut ;
Property OnGotPointerCapture;
Property OnInput;
Property OnInvalid;
Property OnKeyDown;
Property OnKeyPress;
Property OnKeyUp;
Property OnLoad;
Property OnLoadedData;
Property OnLoadedMetaData;
Property OnLoadend;
Property OnLoadStart;
Property OnLostPointerCapture;
Property OnMouseDown;
Property OnMouseEnter;
Property OnMouseLeave;
Property OnMouseMove;
Property OnMouseOut;
Property OnMouseUp;
Property OnOverFlow;
Property OnPaste;
Property OnPause;
Property OnPlay;
Property OnPointerCancel;
Property OnPointerDown;
Property OnPointerEnter;
Property OnPointerLeave;
Property OnPointerMove;
Property OnPointerOut;
Property OnPointerOver;
Property OnPointerUp;
Property OnReset;
Property OnResize;
Property OnScroll;
Property OnSelect;
Property OnSubmit;
Property OnTouchStart;
Property OnTransitionCancel;
Property OnTransitionEnd;
Property OnTransitionRun;
Property OnTransitionStart;
Property OnWheel;
end;
{ TCustomInputWidget }
TCustomInputWidget = Class(TWebWidget)
private
FValue : String;
FValueName : String;
FText : String;
FReadOnly : Boolean;
FRequired : Boolean;
function GetReadOnly: Boolean;
function GetRequired: Boolean;
function GetText: String;
function GetValue: String;
function GetValueName: String;
procedure SetReadonly(AValue: Boolean);
procedure SetRequired(AValue: Boolean);
procedure SetText(AValue: String);
procedure SetValue(AValue: String);
function GetInputElement: TJSHTMLInputElement;
procedure SetValueName(AValue: String);
Protected
Procedure SetName(const NewName: TComponentName); override;
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Property InputElement : TJSHTMLInputElement Read GetInputElement;
// Text to show (checkbox etc). Enable in descendents as needed
Property Text : String Read GetText Write SetText;
Public
function InputType : String; virtual; abstract;
Function HTMLTag : String; override;
// Value as string
Property Value : String Read GetValue Write SetValue;
// Value Name to use when submitting using form.
Property ValueName : String Read GetValueName Write SetValueName;
Property ReadOnly : Boolean Read GetReadOnly Write SetReadonly;
Property Required : Boolean Read GetRequired Write SetRequired;
end;
{ TTextInputWidget }
TInputTextType = (ittText,ittPassword,ittNumber,ittEmail,ittSearch,ittTelephone,ittURL,ittColor);
TTextInputWidget = class(TCustomInputWidget)
private
FMaxLength : Integer;
FMinLength : Integer;
FTextType : TInputTextType;
function GetAsNumber: NativeInt;
function GetMaxLength: NativeInt;
function GetMinLength: NativeInt;
function GetTextType: TInputTextType;
procedure SetAsNumber(AValue: NativeInt);
procedure SetMaxLength(AValue: NativeInt);
procedure SetMinLength(AValue: NativeInt);
procedure SetTextType(AValue: TInputTextType);
Protected
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Public
Class Function AllowChildren : Boolean; override;
function InputType : String; override;
Published
Property Value;
Property ValueName;
Property Required;
Property TextType : TInputTextType Read GetTextType Write SetTextType;
property AsNumber : NativeInt Read GetAsNumber Write SetAsNumber;
Property MaxLength : NativeInt Read GetMaxLength Write SetMaxLength;
Property MinLength : NativeInt Read GetMinLength Write SetMinLength;
// Todo: List support
end;
{ TButtonInputWidget }
TInputButtonType = (ibtSubmit,ibtReset,ibtImage);
TInputButtonTypes = set of TInputButtonType;
TButtonInputWidget = class(TCustomInputWidget)
private
FButtonType: TInputButtonType;
FSrc: String;
procedure SetButtonType(AValue: TInputButtonType);
procedure SetSrc(AValue: String);
Public
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
function InputType : String; override;
Class Function AllowChildren : Boolean; override;
Published
Property ButtonType : TInputButtonType Read FButtonType Write SetButtonType;
Property Value;
Property ValueName;
Property Src : String Read FSrc Write SetSrc;
end;
{ TCheckableInputWidget }
TCheckableInputWidget = class(TCustomInputWidget)
private
FChecked: Boolean;
function GetChecked: Boolean;
procedure SetChecked(AValue: Boolean);
Protected
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Public
Property Value;
Property ValueName;
Property Checked : Boolean Read GetChecked Write SetChecked;
Property Text;
end;
{ TRadioInputWidget }
TRadioInputWidget = class(TCheckableInputWidget)
private
Public
function InputType : String; override;
Published
Property Value;
Property ValueName;
Property Checked;
Property Text;
end;
{ TCheckboxInputWidget }
TCheckboxInputWidget = class(TCheckableInputWidget)
private
Public
function InputType : String; override;
Published
Property Value;
Property ValueName;
Property Checked;
Property Text;
end;
{ TDateInputWidget }
TDateInputWidget = class(TCustomInputWidget)
private
FDate: TDateTime;
function GetDate: TDateTime;
procedure SetDate(AValue: TDateTime);
Public
function InputType : String; override;
Class Function AllowChildren : Boolean; override;
Published
Property Required;
Property ValueName;
Property Date : TDateTime Read GetDate Write SetDate;
end;
{ TFileInputWidget }
TFileInfo = record
Name : String;
TimeStamp : TDateTime;
FileType : String;
Size : NativeInt;
end;
TFileInputWidget = class(TCustomInputWidget)
private
FMultiple: Boolean;
function GetFileCount: Integer;
function GetFileDate(aIndex : Integer): TDateTime;
function GetFileInfo(aIndex : Integer): TFileInfo;
function GetFileName(aIndex : Integer): String;
function GetFileSize(aIndex : Integer): NativeInt;
function GetFileType(aIndex : Integer): String;
function GetMultiple: Boolean;
procedure SetMultiple(AValue: Boolean);
Protected
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Public
Class Function AllowChildren : Boolean; override;
function InputType : String; override;
Property FileCount : Integer read GetFileCount;
Property Files[aIndex : Integer] : String Read GetFileName;
Property FileSizes[aIndex : Integer] : NativeInt Read GetFileSize;
Property FileTypes[aIndex : Integer] : String Read GetFileType;
Property FileDates[aIndex : Integer] : TDateTime Read GetFileDate;
Property FileInfos[aIndex : Integer] : TFileInfo Read GetFileInfo;
Published
Property ValueName;
Property Required;
Property Multiple : Boolean Read GetMultiple Write SetMultiple;
end;
{ THiddenInputWidget }
THiddenInputWidget = class(TCustomInputWidget)
Public
Class Function AllowChildren : Boolean; override;
function InputType : String; override;
Published
Property ValueName;
Property Value;
Property Required;
end;
{ TTextAreaWidget }
TTextAreaWrap = (tawSoft,tawHard,tawOff);
TTextAreaWidget = Class(TWebWidget)
private
FLines: TStrings;
FIgnoreChanges : Boolean;
FMaxLength: Cardinal;
FValueName : String;
FRows,
FColumns : Cardinal;
FWrap: TTextAreaWrap;
FRequired,
FReadOnly : Boolean;
procedure ApplyWrap(aElement: TJSHTMLTextAreaElement);
procedure DoLineChanges(Sender: TObject);
function GetColumns: Cardinal;
function GetLines: TStrings;
function GetReadOnly: Boolean;
function GetRequired: Boolean;
function GetRows: Cardinal;
function GetText: String;
function GetValueName: string;
procedure SetColumns(AValue: Cardinal);
procedure SetLines(AValue: TStrings);
procedure SetMaxLength(AValue: Cardinal);
procedure SetReadonly(AValue: Boolean);
procedure SetRequired(AValue: Boolean);
procedure SetRows(AValue: Cardinal);
procedure SetText(AValue: String);
procedure SetValueName(AValue: string);
Function GetTextArea : TJSHTMLTextAreaElement;
procedure SetWrap(AValue: TTextAreaWrap);
Protected
procedure ApplyLines(aElement: TJSHTMLTextAreaElement);
procedure LinesFromHTML(aHTML : String);
Procedure SetName(const NewName: TComponentName); override;
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Property TextArea :TJSHTMLTextAreaElement Read GetTextArea;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
Class Function AllowChildren : Boolean; override;
Function HTMLTag : String; override;
Property InnerHTML : String Read GetText Write SetText;
Published
Property ValueName : string Read GetValueName Write SetValueName;
Property Rows : Cardinal Read GetRows Write SetRows;
Property Columns : Cardinal Read GetColumns Write SetColumns;
Property Lines : TStrings Read GetLines Write SetLines;
Property MaxLength : Cardinal Read FMaxLength Write SetMaxLength;
Property Wrap : TTextAreaWrap Read FWrap Write SetWrap;
Property ReadOnly : Boolean Read GetReadOnly Write SetReadonly;
Property Required : Boolean Read GetRequired Write SetRequired;
end;
{ TImageWidget }
TImageWidget = class(TWebWidget)
private
FHeight: Integer;
FWidth: Integer;
FSrc : String;
function GetHeight: Integer;
function GetImg: TJSHTMLImageElement;
function GetSrc: String;
function GetWidth: Integer;
procedure SetHeight(AValue: Integer);
procedure SetSrc(AValue: String);
procedure SetWidth(AValue: Integer);
Protected
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Property ImgElement : TJSHTMLImageElement Read GetImg;
Public
Function HTMLTag : String; override;
Published
Property Src : String Read GetSrc Write SetSrc;
Property Width : Integer Read GetWidth Write SetWidth;
Property Height : Integer Read GetHeight Write SetHeight;
end;
{ TSelectWidget }
TJSHTMLOptionElementArray = Array of TJSHTMLOptionElement;
TCustomSelectWidget = Class;
{ TCustomSelectWidget }
TCustomSelectWidget = class(TWebWidget)
Private
FSize,
FSelectedIndex : Integer;
FOptions : TJSHTMLOptionElementArray;
FMultiple : Boolean;
function GetMultiple: Boolean;
function GetSelected(Index : Integer): Boolean;
function GetSelectedIndex: Integer;
function GetSelect: TJSHTMLSelectElement;
function GetSelectionCount: Integer;
function GetSelectionItem(aIndex : Integer): String;
function GetSelectionValue(aIndex : Integer): String;
function GetSize: Integer;
procedure SetMultiple(AValue: Boolean);
procedure SetSelected(Index : Integer; AValue: Boolean);
procedure SetSelectedIndex(AValue: Integer);
procedure SetSize(AValue: Integer);
Protected
Type
{ TSelectOptionEnumerator }
TSelectOptionEnumerator = Class
private
FSelect: TCustomSelectWidget;
public
constructor Create(ASelect : TCustomSelectWidget); reintroduce; virtual;
Function OptionText : String; virtual; abstract;
Function HasValue : boolean; virtual;
Function Value : string; virtual;
function MoveNext: Boolean; virtual; abstract;
Property Select: TCustomSelectWidget Read FSelect;
end;
Protected
function GetItemCount: Integer; virtual;
Function CreateOptionEnumerator : TSelectOptionEnumerator; virtual; abstract;
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Procedure BuildOptions(aSelect : TJSHTMLSelectElement); virtual;
Property Options : TJSHTMLOptionElementArray Read Foptions;
Property SelectElement : TJSHTMLSelectElement Read GetSelect;
Protected
// Can be made public/published
// Items that are selected
Property ItemCount : Integer Read GetItemCount;
Property Selected[Index : Integer] : Boolean Read GetSelected Write SetSelected;
Property SelectionCount : Integer Read GetSelectionCount;
Property SelectionValue[aIndex : Integer] : String Read GetSelectionValue;
Property SelectionItem[aIndex : Integer] : String Read GetSelectionItem;
property SelectedIndex : Integer Read GetSelectedIndex Write SetSelectedindex;
Property Multiple : Boolean Read GetMultiple Write SetMultiple;
Property Size : Integer Read GetSize Write SetSize;
Public
Constructor Create(aOWner : TComponent); override;
Function HTMLTag : String; override;
end;
TSelectWidget = class(TCustomSelectWidget)
private
FItems : TStrings;
FValues : TStrings;
function GetItems: TStrings;
function GetValues: TStrings;
procedure OptionsChanged(Sender: TObject);
procedure setItems(AValue: TStrings);
procedure setValues(AValue: TStrings);
Protected
Type
{ TStringsSelectOptionEnumerator }
TStringsSelectOptionEnumerator = Class(TSelectOptionEnumerator)
FCurrent : Integer;
constructor Create(ASelect : TCustomSelectWidget); override;
Function OptionText : String; override;
Function HasValue : boolean; override;
Function Value : string; override;
function MoveNext: Boolean; override;
end;
Function CreateOptionEnumerator: TSelectOptionEnumerator; override;
Public
Constructor Create(aOWner : TComponent); override;
Destructor Destroy; override;
Property SelectionCount;
Property SelectionValue;
Property SelectionItem;
Property Selected;
Property Options;
Property SelectElement;
Property ItemCount;
Published
Property Items : TStrings Read GetItems Write setItems;
Property Values : TStrings Read GetValues Write setValues;
property SelectedIndex;
Property Multiple;
property size;
property Classes;
end;
{ TLabelWidget }
TLabelWidget = Class(TWebWidget)
private
FLabelFor: TWebWidget;
FText: String;
function GetLabelEl: TJSHTMLLabelElement;
function GetText: String;
procedure SetLabelFor(AValue: TWebWidget);
procedure SetText(AValue: String);
Protected
procedure ApplyLabelFor(aLabelElement: TJSHTMLLabelElement);
Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
Procedure SetName(const NewName: TComponentName); override;
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Property LabelElement : TJSHTMLLabelElement Read GetLabelEl;
Public
Function HTMLTag : String; override;
Property Text : String Read GetText Write SetText;
Property LabelFor : TWebWidget Read FLabelFor Write SetLabelFor;
end;
TTextTag = (ttParagraph,ttBold,ttItalic,ttUnderline,ttStrikeThrough,ttSpan,ttQuote,ttBlockQuote,ttH1,ttH2,ttH3,ttH4,ttH5,ttH6,ttPre,ttRuby,ttArticle,ttAddress,ttAbbr,ttCustom);
{ TTextWidget }
{ TCustomTextWidget }
TCustomTextWidget = Class(TCustomWebWidget)
private
FCustomTag: String;
FEnvelopeTag: TTextTag;
FTextMode: TTextMode;
procedure SetCustomTag(AValue: String);
procedure SetEnvelopeTag(AValue: TTextTag);
procedure SetTextMode(AValue: TTextMode);
Protected
procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
procedure ApplyText(aElement : TJSHTMLElement); virtual;
Function GetText : String; virtual; abstract;
Public
Function HTMLTag : String; override;
Published
Property CustomTag : String Read FCustomTag Write SetCustomTag;
Property EnvelopeTag : TTextTag Read FEnvelopeTag Write SetEnvelopeTag;
Property TextMode : TTextMode Read FTextMode Write SetTextMode;
end;
TTextWidget = Class(TCustomTextWidget)
private
FText : String;
procedure SetText(AValue: String);
Protected
Function GetText : String; override;
published
Property Text : String Read FText Write SetText;
end;
{ TTextLinesWidget }
TTextLinesWidget = Class(TCustomTextWidget)
private
FLines : TStrings;
FForceLineBreaks: Boolean;
procedure DoLinesChanged(Sender: TObject);
procedure SetLines(AValue: TStrings);
procedure SetForceLineBreaks(AValue: Boolean);
Protected
Function GetText : String; override;
procedure ApplyText(aElement : TJSHTMLElement); override;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
published
Property Lines : TStrings Read FLines Write SetLines;
// When forcelinebreaks is true a
will be appended to every line.
// Note that for TextMode=tmText this means the lines will be rendered as-is, but there will still be a
between the lines
Property ForceLineBreaks : Boolean Read FForceLineBreaks Write SetForceLineBreaks;
end;
{ TCustomTableColumn }
TColumnOption = (coHeader,coCaptionHeader);
TColumnOptions = set of TColumnOption;
TCustomTableColumn = Class(TCollectionItem)
private
FAlignment: TAlignment;
FCaption: String;
FClassNames: String;
procedure SetAlignment(AValue: TAlignment);
procedure SetCaption(AValue: String);
procedure SetClassNames(AValue: String);
Protected
Function RenderColumn : Boolean; virtual;
Function GetDisplayName: string; override;
function GetCaption: String; virtual;
Public
Procedure Assign(Source : TPersistent); override;
Property Alignment : TAlignment Read FAlignment Write SetAlignment;
Property Caption : String Read GetCaption Write SetCaption;
Property ClassNames : String Read FClassNames Write SetClassNames;
end;
{ TCustomTableColumns }
TCustomTableColumns = Class(TCollection)
private
function GetCustomColumn(Index : Integer): TCustomTableColumn;
procedure SetCustomColumn(Index : Integer; AValue: TCustomTableColumn);
Protected
Property CustomColumns [Index : Integer] : TCustomTableColumn Read GetCustomColumn Write SetCustomColumn; default;
Public
Function Add(aCaption : String): TCustomTableColumn; overload;
end;
{ TCustomTableWidget }
TTableOption = (toHeader, // use THead tag
toHeaderRow, // Create header row
toBody, // use TBody tag
toFooter, // use TFoot tag
toFooterRow, // create footer row
toRowID, // add ID to tr: -kind-row
toCellID, // add ID to cell td: -kind-row-col
toHeaderRowData, // Add rowno to