pas2js/packages/webwidget/htmlwidgets.pp
michael 81538babe2 * Merging revisions 941,942,950,951,952,953 from trunk:
------------------------------------------------------------------------
    r941 | svenbarth | 2020-11-13 16:02:27 +0100 (Fri, 13 Nov 2020) | 1 line
    
    * TStack<>.TrimExcess should override TCustomList<>.TrimExcess
    ------------------------------------------------------------------------
    r942 | svenbarth | 2020-11-15 12:26:08 +0100 (Sun, 15 Nov 2020) | 1 line
    
    * fix compilation of Tetris demo
    ------------------------------------------------------------------------
    r950 | michael | 2020-11-24 15:59:49 +0100 (Tue, 24 Nov 2020) | 1 line
    
    * Added rendercolumn, so columns can be disabled
    ------------------------------------------------------------------------
    r951 | michael | 2020-11-25 12:15:19 +0100 (Wed, 25 Nov 2020) | 1 line
    
    * Add Focus and ReplaceClasses/AddRemoveClasses
    ------------------------------------------------------------------------
    r952 | michael | 2020-11-27 09:41:43 +0100 (Fri, 27 Nov 2020) | 1 line
    
    * Make creation of data-tags optional
    ------------------------------------------------------------------------
    r953 | michael | 2020-11-27 17:12:43 +0100 (Fri, 27 Nov 2020) | 1 line
    
    * Correct options objects
    ------------------------------------------------------------------------
2020-11-27 16:34:51 +00:00

3187 lines
80 KiB
ObjectPascal

{
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 <br> 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 <br> 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 <tr data-row> for header.
toHeaderCellDataRow, // Add rowno to <th data-row> for header. Automatic if onheadercellclick is set.
toHeaderCellDataCol, // Add colno to <th data-col> for header. Automatic if onheadercellclick is set.
toBodyRowData, // Add rowno to <tr data-row> for body.
toBodyCellDataRow, // Add rowno to <th data-row> for body. Automatic if oncellclick is set.
toBodyCellDataCol, // Add colno to <th data-col> for body. Automatic if oncellclick is set.
tofooterRowData, // Add rowno to <tr data-row> for footer
tofooterCellDataRow, // Add rowno to <th data-row> for footer. Automatic if onfootercellclick is set.
tofooterCellDataCol // Add colno to <th data-col> for footer. Automatic if onfootercellclick is set.
);
TTableOptions = Set of TTableOption;
TRowKind = (rkHeader,rkBody,rkFooter);
Type
TCustomTableWidget = Class;
// Constructed only once when rendering !
{ TTableWidgetCelldata }
TTableWidgetCellData = Class
private
FAsHTML: Boolean;
FClassNames: String;
FCol: Integer;
FColumn: TCustomTableColumn;
FContent: TJSHTMLElement;
FKind: TRowKind;
FRow: Integer;
FTable: TCustomTableWidget;
FTableID: String;
FTag: String;
FText: String;
FWidget: TWebWidget;
Protected
Procedure SetRowColKind(aRow,aCol : Integer; aKind : TRowKind); virtual;
Procedure Reset; // do not reset row,col, column
Public
Constructor Create(aTable : TCustomTableWidget;aTableID : String); virtual;
Property Table : TCustomTableWidget Read FTable;
Property Column : TCustomTableColumn Read FColumn;
Property Row : Integer Read FRow;
Property Col : Integer Read FCol;
Property Kind : TRowKind Read FKind;
Property Tag : String Read FTag Write FTag;
Property ClassNames : String Read FClassNames Write FClassNames;
Property Text : String Read FText Write FText;
Property AsHTML : Boolean Read FAsHTML Write FAsHTML;
Property Content : TJSHTMLElement Read FContent Write FContent;
Property Widget : TWebWidget Read FWidget Write FWidget;
Property TableID : String Read FTableID;
end;
TTableRowEnumerator = Class
private
FTable: TCustomTableWidget;
FCurrent : Integer;
public
constructor Create(ATable : TCustomTableWidget); reintroduce; virtual;
Procedure GetCellData(aCell : TTableWidgetCellData); virtual;
function MoveNext: Boolean; virtual;
property CurrentRow : Integer Read FCurrent;
Property Table : TCustomTableWidget Read FTable;
end;
TTableRowCountEnumerator = Class (TTableRowEnumerator)
private
FRowCount: Integer;
public
constructor Create(ATable : TCustomTableWidget;aCount : Integer); reintroduce;
function MoveNext: Boolean; override;
Property RowCount : Integer read FRowCount;
end;
TOnCellDataEvent = Procedure (Sender : TObject; Enum : TTableRowEnumerator; aCell : TTableWidgetCellData) of object;
TCustomTableWidget = Class(TCustomWebWidget)
private
FCaption: String;
FColumns: TCustomTableColumns;
FOnCellClick: THTMLNotifyEvent;
FOnFooterCellClick: THTMLNotifyEvent;
FOnFooterRowClick: THTMLNotifyEvent;
FOnHeaderCellClick: THTMLNotifyEvent;
FOnHeaderRowClick: THTMLNotifyEvent;
FOnRowClick: THTMLNotifyEvent;
FTableOptions: TTableOptions;
FOnGetCellData : TOnCellDataEvent;
FWidgets : Array of TWebWidget;
FUpdateCount : Integer;
procedure SetCaption(AValue: String);
procedure SetColumns(AValue: TCustomTableColumns);
procedure SetTableOptions(AValue: TTableOptions);
Protected
procedure AppendCaption(aCaptionElement: TJSHTMLElement); virtual;
procedure RenderData(aElement: TJSHTMLElement); virtual;
function DoCellClick(aEvent: TJSMouseEvent): boolean; virtual;
function DoHeaderCellClick(aEvent: TJSMouseEvent): boolean;virtual;
function DoFooterCellClick(aEvent: TJSMouseEvent): boolean;virtual;
function DoRowClick(aEvent: TJSMouseEvent): boolean; virtual;
function DoHeaderRowClick(aEvent: TJSMouseEvent): boolean;virtual;
function DoFooterRowClick(aEvent: TJSMouseEvent): boolean;virtual;
function CreateColumns: TCustomTableColumns; virtual;
Function DefaultTableOptions: TTableOptions; virtual;
Procedure CreateDefaultColumns; virtual;
Function GetRowEnumerator(aKind : TRowKind) : TTableRowEnumerator; virtual;
function RenderCell(aCell: TTableWidgetCellData): TJSHTMLElement; virtual;
procedure RenderRow(aEnum : TTableRowEnumerator; aParent: TJSHTMLElement; aKind: TRowKind; aCell: TTableWidgetCellData); virtual;
procedure RenderRows(aParent: TJSHTMLElement; aKind : TRowKind; aCell: TTableWidgetCellData); virtual;
Procedure ApplyWidgetSettings(aElement : TJSHTMLElement); override;
Function HTMLTag : String; override;
Function CreateCellData(const aTableID : String) : TTableWidgetCellData; virtual;
Function GetBodyRowEnumerator : TTableRowEnumerator; virtual; abstract;
Protected
// These can be made public/published
Property CustomColumns : TCustomTableColumns Read FColumns Write SetColumns;
Property TableOptions : TTableOptions read FTableOptions write SetTableOptions;
Property Caption : String Read FCaption Write SetCaption;
Property OnGetCellData : TOnCellDataEvent Read FOnGetCellData Write FOnGetCellData;
Property OnCellClick : THTMLNotifyEvent Read FOnCellClick Write FOnCellClick;
Property OnHeaderCellClick : THTMLNotifyEvent Read FOnHeaderCellClick Write FOnHeaderCellClick;
Property OnFooterCellClick : THTMLNotifyEvent Read FOnFooterCellClick Write FOnFooterCellClick;
Property OnRowClick : THTMLNotifyEvent Read FOnRowClick Write FOnRowClick;
Property OnHeaderRowClick : THTMLNotifyEvent Read FOnHeaderRowClick Write FOnHeaderRowClick;
Property OnFooterRowClick : THTMLNotifyEvent Read FOnFooterRowClick Write FOnFooterRowClick;
Public
Constructor Create(aOwner : TComponent); override;
Destructor Destroy; override;
Procedure BeginUpdate;
Procedure EndUpdate;
Procedure RefreshBody;
end;
{ TEventTableWidget }
TEventTableWidget = Class(TCustomTableWidget)
private
FRowCount: Integer;
procedure SetRowCount(AValue: Integer);
Protected
Function GetBodyRowEnumerator : TTableRowEnumerator; override;
Published
Property RowCount : Integer Read FRowCount Write SetRowCount;
Property CustomColumns;
Property TableOptions;
Property Caption;
Property OnGetCellData;
Property OnCellClick;
Property OnHeaderCellClick;
Property OnFooterCellClick;
Property OnRowClick;
Property OnHeaderRowClick;
Property OnFooterRowClick;
end;
{ TCustomStringsTableWidget }
TCustomStringsTableWidget = Class(TCustomTableWidget)
private
Type
TRow = Array of string;
private
FRows : Array of TRow;
function GetRowCount: Integer;
procedure SetRowCount(AValue: Integer);
Protected
Type
TStringRowsEnumerator = Class(TTableRowCountEnumerator)
Procedure GetCellData(aCell : TTableWidgetCellData); override;
end;
Protected
Procedure CheckIndex(aCol,aRow : Integer);
function GetCell(aCol, aRow : integer): String;
procedure SetCell(aCol, aRow : integer; AValue: String);
Function GetBodyRowEnumerator : TTableRowEnumerator; override;
Public
Property RowCount : Integer Read GetRowCount Write SetRowCount;
Property Cells[aCol,aRow : integer] : String Read GetCell Write SetCell;
Property CustomColumns;
Property TableOptions;
Property Caption;
Property OnGetCellData;
Property OnCellClick;
Property OnHeaderCellClick;
Property OnFooterCellClick;
Property OnRowClick;
Property OnHeaderRowClick;
Property OnFooterRowClick;
end;
TStringsTableWidget = Class(TCustomStringsTableWidget)
Published
Property RowCount;
Property CustomColumns;
Property TableOptions;
Property Caption;
Property OnGetCellData;
Property OnCellClick;
Property OnHeaderCellClick;
Property OnFooterCellClick;
Property OnRowClick;
Property OnHeaderRowClick;
Property OnFooterRowClick;
end;
{ TDivWidget }
THTMLElementTag = (
etUnknown, eta, etabbr, etacronym, etaddress, etapplet, etarea, etb, etbase,
etbasefont, etbdo, etbig, etblockquote, etbody, etbr, etbutton,
etcaption, etcenter, etcite, etcode, etcol, etcolgroup, etdd, etdel,
etdfn, etdir, etdiv, etdl, etdt, etem, etfieldset, etfont, etform,
etframe, etframeset, eth1, eth2, eth3, eth4, eth5, eth6, ethead, ethr,
ethtml, eti, etiframe, etimg, etinput, etins, etisindex, etkbd, etlabel,
etlegend, etli, etlink, etmap, etmenu, etmeta, etnoframes, etnoscript,
etobject, etol, etoptgroup, etoption, etp, etparam, etpre, etq, ets,
etsamp, etscript, etselect, etsmall, etspan, etstrike, etstrong,
etstyle, etsub, etsup, ettable, ettbody, ettd, ettextarea, ettfoot,
etth, etthead, ettitle, ettr, ettt, etu, etul, etvar,
etText,etAudio,etVideo,etSource
);
THTMLElementTagSet = set of THTMLElementTag;
{ TCustomTagWidget }
TCustomTagWidget = Class(TWebWidget)
private
FElementTag: THTMLElementTag;
FTextContent: String;
procedure SetElementTag(AValue: THTMLElementTag);
procedure SetTextContent(AValue: String);
Protected
Procedure ApplyWidgetSettings(aElement: TJSHTMLElement); override;
Function HTMLTag : String; override;
// Set tag you wish to use
Property elementTag : THTMLElementTag Read FElementTag Write SetElementTag;
// If set, the text will be set as InnerText of the tag
Property TextContent : String Read FTextContent Write SetTextContent;
end;
{ TTagWidget }
TTagWidget = Class(TCustomTagWidget)
Public
Constructor Create(aOwner : TComponent); override;
Published
Property elementTag;
Property TextContent;
end;
TDivWidget = Class(TCustomTagWidget)
Public
Constructor Create(aOwner : TComponent); override;
end;
{ TParagraphWidget }
TParagraphWidget = Class(TCustomTagWidget)
Public
Constructor Create(aOwner : TComponent); override;
end;
{ TMediaWidget }
TMediaWidget = Class(TCustomTagWidget)
private
Const
MaxAttrs = 20;
PropAttrs : Array[0..MaxAttrs] of string
= ('src','defaultPlaybackRate','duration','playbackRate','ended', // 0..4
'paused','seeking','sinkId','mediaGroup','currentSrc', // 5..9
'volume','controls','autoplay','crossOrigin', 'defaultMuted', // 10..14
'currentTime', 'disableRemotePlayback', 'preservesPitch','loop','muted', // 15..19
'preload' // 20
);
function GetAudioTrack: TJSHTMLAudioTrackList;
function getBool(AIndex: Integer): Boolean;
function GetError: TJSMEdiaError;
function getFloat(AIndex: Integer): Double;
function GetSrcObj: TJSHTMLMediaStream;
function getString(AIndex: Integer): String;
function GetTextTrack: TJSHTMLTextTrackList;
function GetVideoTrack: TJSHTMLVideoTrackList;
procedure SetBool(AIndex: Integer; AValue: Boolean);
procedure SetFloat(AIndex: Integer; AValue: Double);
procedure SetString(AIndex: Integer; AValue: String);
function getEl: TJSObject;
Public
Property DefaultPlayBackRate : Double Index 1 Read getFloat;
Property Duration : Double Index 2 Read getFloat;
Property PlayBackRate : Double Index 3 Read getFloat;
Property Ended : Boolean Index 4 Read getBool;
Property Paused : Boolean Index 5 Read getBool;
Property Seeking : Boolean Index 6 Read getBool;
Property SinkID : String Index 7 Read getString Write SetString;
Property MediaGroup : String Index 8 Read getString Write SetString;
Property SrcObject : TJSHTMLMediaStream Read GetSrcObj;
Property textTracks : TJSHTMLTextTrackList Read GetTextTrack;
Property videoTracks : TJSHTMLVideoTrackList Read GetVideoTrack;
Property audioTracks : TJSHTMLAudioTrackList Read GetAudioTrack;
Property Error : TJSMEdiaError Read GetError;
Property CurrentSrc : String Index 9 Read getString;
Published
Property Src : String Index 0 Read getString Write SetString;
Property Controls : Boolean Index 11 Read getBool Write SetBool;
Property AutoPlay : Boolean Index 12 Read getBool Write SetBool;
Property CrossOrigin : String index 13 Read getString Write SetString;
Property DefaultMuted : Boolean Index 14 Read getBool Write SetBool;
Property CurrentTime : Double Index 15 Read getFloat Write SetFloat;
Property DisableRemotePlayback : Boolean Index 16 Read getBool Write SetBool;
Property PreservesPitch : Boolean Index 17 Read getBool Write SetBool;
Property Loop : Boolean Index 18 Read getBool Write SetBool;
Property Muted : Boolean Index 19 Read getBool Write SetBool;
Property Preload : String Index 20 Read getString Write SetString;
Property Volume : Double Index 10 Read getFloat Write SetFloat;
end;
{ TVideoWidget }
TVideoWidget = Class(TMediaWidget)
Public
Constructor Create(aOwner : TComponent); override;
end;
{ TAudioWidget }
TAudioWidget = Class(TMediaWidget)
Public
Constructor Create(aOwner : TComponent); override;
end;
Function ViewPort : TViewPort;
Const
TextTagNames : Array[TTextTag] of string
= ('p','b','i','u','s','span','quote','blockquote','h1','h2','h3','h4','h5','h6','pre','ruby','article','address','abbr','');
RowKindNames : Array[TRowKind] of string = ('header','body','footer');
HTMLTagNames : Array[THTMLElementTag] of string = (
'?', 'a', 'abbr', 'acronym', 'address', 'applet', 'area', 'b', 'base',
'basefont', 'bdo', 'big', 'blockquote', 'body', 'br', 'button',
'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'dd', 'del',
'dfn', 'dir', 'div', 'dl', 'dt', 'em', 'fieldset', 'font', 'form',
'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr',
'html', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd', 'label',
'legend', 'li', 'link', 'map', 'menu', 'meta', 'noframes', 'noscript',
'object', 'ol', 'optgroup', 'option', 'p', 'param', 'pre', 'q', 's',
'samp', 'script', 'select', 'small', 'span', 'strike', 'strong',
'style', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot',
'th', 'thead', 'title', 'tr', 'tt', 'u', 'ul', 'var',
'Text','Audio','Video','Source'
);
implementation
uses DateUtils;
resourcestring
SErrInvalidIndex = 'Index %d not in valid range of [0..%d]';
SErrInvalidRowCount = 'Invalid row count: %d';
SRow = 'Row';
SCol = 'Column';
Function ViewPort : TViewPort;
begin
Result:=TViewPort.Instance;
end;
{ TTableRowCountEnumerator }
Const
CellTags : Array[TRowKind] of string = ('th','td','td');
{ TEventTableWidget }
procedure TEventTableWidget.SetRowCount(AValue: Integer);
begin
if FRowCount=AValue then Exit;
BeginUpdate;
FRowCount:=AValue;
EndUpdate;
end;
function TEventTableWidget.GetBodyRowEnumerator: TTableRowEnumerator;
begin
Result:=TTableRowCountEnumerator.Create(Self,RowCount);
end;
{ TCustomStringsTableWidget.TStringRowsEnumerator }
procedure TCustomStringsTableWidget.TStringRowsEnumerator.GetCellData(aCell: TTableWidgetCellData);
begin
aCell.Text:=TCustomStringsTableWidget(Table).Cells[aCell.Col,aCell.Row];
end;
{ TCustomStringsTableWidget }
function TCustomStringsTableWidget.GetCell(aCol, aRow : integer): String;
begin
CheckIndex(aCol,aRow);
Result:=FRows[aRow][aCol];
end;
function TCustomStringsTableWidget.GetRowCount: Integer;
begin
Result:=Length(FRows);
end;
procedure TCustomStringsTableWidget.SetCell(aCol, aRow : integer; AValue: String);
begin
CheckIndex(aCol,aRow);
BeginUpdate;
try
FRows[aRow][aCol]:=AValue;
Finally
EndUpdate;
end;
end;
function TCustomStringsTableWidget.GetBodyRowEnumerator: TTableRowEnumerator;
begin
Result:=TStringRowsEnumerator.Create(Self,RowCount);
end;
procedure TCustomStringsTableWidget.SetRowCount(AValue: Integer);
begin
if AValue<0 then
raise EWidgets.CreateFmt(SerrInvalidRowCount, [aValue]);
BeginUpdate;
try
SetLength(FRows,aValue);
Finally
EndUpdate;
end;
end;
procedure TCustomStringsTableWidget.CheckIndex(aCol, aRow: Integer);
begin
If (aCol<0) or (aCol>=CustomColumns.Count) then
Raise EWidgets.CreateFmt(SCol+' '+SErrInvalidIndex,[aCol,0,CustomColumns.Count-1]);
If (aRow<0) or (aRow>=RowCount) then
Raise EWidgets.CreateFmt(SRow+' '+SErrInvalidIndex,[aRow,0,RowCount-1]);
end;
{ TTagWidget }
constructor TTagWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
ElementTag:=etdiv;
end;
{ TMediaWidget }
function TMediaWidget.GetAudioTrack: TJSHTMLAudioTrackList;
begin
if Assigned(Element) then
Result:=TJSHTMLMediaElement(Element).AudioTracks
else
Result:=Nil;
end;
function TMediaWidget.getBool(AIndex: Integer): Boolean;
Var
El : TJSObject;
Att : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
Result:=Assigned(el) and isDefined(El[Att]) and (Boolean(El[Att]));
end;
function TMediaWidget.GetError: TJSMEdiaError;
begin
If Assigned(Element) then
Result:=TJSHTMLMediaElement(Element).Error
else
Result:=Nil;
end;
function TMediaWidget.getFloat(AIndex: Integer): Double;
Var
El : TJSObject;
Att : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
if Assigned(el) and isDefined(El[Att]) then
Result:=Double(El[Att])
else
Result:=0;
end;
function TMediaWidget.GetSrcObj: TJSHTMLMediaStream;
begin
If Assigned(Element) then
Result:=TJSHTMLMediaElement(Element).srcObject
else
Result:=Nil;
end;
function TMediaWidget.getString(AIndex: Integer): String;
Var
El : TJSObject;
Att : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
if Assigned(el) and isDefined(El[Att]) then
Result:=String(El[Att])
else
Result:='';
end;
function TMediaWidget.GetTextTrack: TJSHTMLTextTrackList;
begin
If Assigned(Element) then
Result:=TJSHTMLMediaElement(Element).TextTracks
else
Result:=Nil;
end;
function TMediaWidget.GetVideoTrack: TJSHTMLVideoTrackList;
begin
If Assigned(Element) then
Result:=TJSHTMLMediaElement(Element).VideoTracks
else
Result:=Nil;
end;
procedure TMediaWidget.SetBool(AIndex: Integer; AValue: Boolean);
Var
El : TJSObject;
Att : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
if Assigned(el) then
El[Att]:=aValue
else
Attrs[Att]:=IntToStr(Ord(AValue));
end;
procedure TMediaWidget.SetFloat(AIndex: Integer; AValue: Double);
Var
El : TJSObject;
Att,S : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
if Assigned(el) then
El[Att]:=aValue
else
begin
Str(aValue,S);
Attrs[Att]:=S;
end;
end;
procedure TMediaWidget.SetString(AIndex: Integer; AValue: String);
Var
El : TJSObject;
Att : String;
begin
El:=GetEl;
Att:=PropAttrs[aIndex];
if Assigned(el) then
El[Att]:=aValue
else
Attrs[Att]:=aValue;
end;
function TMediaWidget.getEl: TJSObject;
begin
Result:=Element;
if Not Assigned(Result) then
Result:=Self.StoredAttrs;
end;
{ TVideoWidget }
constructor TVideoWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
elementTag:=etVideo;
end;
{ TAudioWidget }
constructor TAudioWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
elementTag:=etAudio;
end;
{ TSelectWidget.TStringsSelectOptionEnumerator }
constructor TSelectWidget.TStringsSelectOptionEnumerator.Create(ASelect: TCustomSelectWidget);
begin
inherited Create(ASelect);
FCurrent:=-1;
end;
function TSelectWidget.TStringsSelectOptionEnumerator.OptionText: String;
begin
Result:=TSelectWidget(Select).Items[FCurrent];
end;
function TSelectWidget.TStringsSelectOptionEnumerator.HasValue: boolean;
begin
Result:=FCurrent<TSelectWidget(Select).Values.Count;
end;
function TSelectWidget.TStringsSelectOptionEnumerator.Value: string;
begin
Result:=TSelectWidget(Select).Values[FCurrent];
end;
function TSelectWidget.TStringsSelectOptionEnumerator.MoveNext: Boolean;
begin
Result:=FCurrent<TSelectWidget(Select).Items.Count-1;
if Result then
Inc(FCurrent);
end;
{ TCustomSelectWidget.TSelectOptionEnumerator }
constructor TCustomSelectWidget.TSelectOptionEnumerator.Create(ASelect: TCustomSelectWidget);
begin
FSelect:=ASelect;
end;
function TCustomSelectWidget.TSelectOptionEnumerator.HasValue: boolean;
begin
Result:=False;
end;
function TCustomSelectWidget.TSelectOptionEnumerator.Value: string;
begin
Result:='';
end;
constructor TTableRowCountEnumerator.Create(ATable: TCustomTableWidget; aCount: Integer);
begin
Inherited Create(aTable);
FRowCount:=aCount;
end;
function TTableRowCountEnumerator.MoveNext: Boolean;
begin
Result:=Inherited MoveNext and (CurrentRow<RowCount)
end;
{ TTableWidgetCellData }
procedure TTableWidgetCellData.SetRowColKind(aRow, aCol: Integer; aKind: TRowKind);
begin
if (aRow<>-1) then
FRow:=aRow;
if (aCol<>-1) then
FCol:=aCol;
FKind:=aKind;
end;
procedure TTableWidgetCellData.Reset;
begin
Ftag:='td';
FClassNames:='';
FText:='';
FContent:=Nil;
FAsHTML:=False;
FWidget:=Nil;
end;
constructor TTableWidgetCellData.Create(aTable: TCustomTableWidget; aTableID: String);
begin
FTable:=aTable;
FTableID:=aTableID;
SetRowColKind(0,0,rkBody);
end;
{ TCustomTableWidget }
procedure TCustomTableWidget.SetColumns(AValue: TCustomTableColumns);
begin
if FColumns=AValue then Exit;
FColumns.Assign(AValue);
end;
procedure TCustomTableWidget.SetCaption(AValue: String);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
if isRendered then Refresh;
end;
function TCustomTableWidget.DoCellClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnCellClick) then
FOnCellClick(Self,aEvent);
If Assigned(FOnRowClick) then
FOnRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for cell',aEvent.targetElement.innerText);
end;
function TCustomTableWidget.DoHeaderCellClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnHeaderCellClick) then
FOnHeaderCellClick(Self,aEvent);
If Assigned(FOnHeaderRowClick) then
FOnHeaderRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for header cell',aEvent.targetElement.innerText);
end;
function TCustomTableWidget.DoFooterCellClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnFooterCellClick) then
FOnFooterCellClick(Self,aEvent);
If Assigned(FOnFooterRowClick) then
FOnFooterRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for Footer cell',aEvent.targetElement.innerText);
end;
function TCustomTableWidget.DoRowClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnRowClick) then
FOnRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for Row',aEvent.targetElement.innerText);
end;
function TCustomTableWidget.DoHeaderRowClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnHeaderRowClick) then
FOnHeaderRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for Header Row',aEvent.targetElement.innerText);
end;
function TCustomTableWidget.DoFooterRowClick(aEvent: TJSMouseEvent): boolean;
begin
If Assigned(FOnFooterRowClick) then
FOnFooterRowClick(Self,aEvent);
Result:=False;
// Writeln('On click for Footer Row',aEvent.targetElement.innerText);
end;
procedure TCustomTableWidget.SetTableOptions(AValue: TTableOptions);
begin
if FTableOptions=AValue then Exit;
FTableOptions:=AValue;
if IsRendered then
Refresh;
end;
procedure TCustomTableWidget.AppendCaption(aCaptionElement: TJSHTMLElement);
begin
aCaptionElement.InnerHTML:=Caption;
end;
function TCustomTableWidget.GetRowEnumerator(aKind: TRowKind): TTableRowEnumerator;
begin
Case aKind of
rkHeader : Result:=TTableRowCountEnumerator.Create(Self,1);
rkFooter : Result:=TTableRowCountEnumerator.Create(Self,1);
rkBody : Result:=GetBodyRowEnumerator;
end;
end;
procedure TTableRowEnumerator.GetCellData(aCell: TTableWidgetCellData);
Var
K : TRowKind;
begin
K:=aCell.Kind;
Case K of
rkHeader:
begin
aCell.Tag:='th';
aCell.Text:=ACell.Column.Caption;
end;
rkFooter,
rkBody :
begin
aCell.Tag:='td';
end;
end;
end;
function TCustomTableWidget.HTMLTag: String;
begin
Result:='table';
end;
function TCustomTableWidget.RenderCell(aCell: TTableWidgetCellData): TJSHTMLElement;
Const
Aligns : Array[TAlignment] of string = ('left','right','center');
RowChecks : Array[TRowKind] of TTableOption = (toHeaderCellDataRow,toBodyCellDataRow,toFooterCellDataRow);
ColChecks : Array[TRowKind] of TTableOption = (toHeaderCellDataCol,toBodyCellDataCol,toFooterCellDataCol);
Var
C : TJSHtmlElement;
cl : THTMLNotifyEvent;
K : TRowKind;
M : THTMLClickEventHandler;
elID : string;
begin
K:=aCell.Kind;
if (toCellID in TableOptions) or Assigned(aCell.Widget) then
elID:=aCell.TableID+'-'+RowKindNames[K]+'-'+IntToStr(ACell.Row)+'-'+IntToStr(aCell.Col)
else
elID:='';
C:=CreateElement(aCell.Tag,elID);
if aCell.Widget<>Nil then
aCell.Widget.ParentID:=elID;
if aCell.Content<>Nil then
C.AppendChild(aCell.Content)
else if aCell.AsHTML then
C.innerHTML:=aCell.text
else
C.innerText:=aCell.text;
C.className:=AddClasses(aCell.Column.ClassNames,aCell.ClassNames);
if ACell.Column.Alignment<>taLeftJustify then
C.Style.setProperty('text-align',Aligns[ACell.Column.Alignment]);
Case K of
rkBody :
begin
CL:=FOnCellClick;
M:=@DoCellClick;
end;
rkHeader :
begin
CL:=FOnHeaderCellClick;
M:=@DoHeaderCellClick;
end;
rkFooter :
begin
CL:=FOnFooterCellClick;
M:=@DoFooterCellClick;
end;
else
CL:=Nil;
M:=nil;
end;
if Assigned(cl) or (RowChecks[K] in TableOptions) then
begin
C.dataset['row']:=ACell.Row;
C.Dataset['kind']:=RowKindNames[K];
end;
if Assigned(cl) or (ColChecks[K] in TableOptions) then
begin
C.dataset['col']:=ACell.Col;
C.Dataset['kind']:=RowKindNames[K];
end;
if Assigned(M) then
C.OnClick:=M;
if aCell.Widget<>Nil then
TJSArray(FWidgets).Push(aCell.Widget);
Result:=C;
end;
procedure TCustomTableWidget.RenderRow(aEnum: TTableRowEnumerator; aParent: TJSHTMLElement; aKind: TRowKind; aCell: TTableWidgetCellData);
Var
I: integer;
begin
For I:=0 to CustomColumns.Count-1 do
if CustomColumns[i].RenderColumn then
begin
aCell.Reset;
aCell.FColumn:=CustomColumns[i];
aCell.SetRowColKind(-1,I,aKind);
// Writeln(CellKinds[aKind],' cell before : ',aCell.Tag,' data : ',aCell.Text);
aEnum.GetCellData(aCell);
// Writeln(CellKinds[aKind],' cell after : ',aCell.Tag,' data : ',aCell.Text);
if aCell.Tag='' then
ACell.Tag:=CellTags[aKind];
if Assigned(FOnGetCellData) then
FOnGetCellData(Self,aEnum,aCell);
aParent.appendChild(RenderCell(aCell));
end;
end;
procedure TCustomTableWidget.RenderRows(aParent: TJSHTMLElement; aKind: TRowKind; aCell: TTableWidgetCellData);
Const
TableRowChecks : Array[TRowKind] of TTableOption = (toHeaderRowData,toBodyRowData,toFooterRowData);
Var
RowEl : TJSHTMLElement;
Enum : TTableRowEnumerator;
M : THTMLClickEventHandler;
cl : THTMLNotifyEvent;
elid : String;
begin
Enum:=GetRowEnumerator(aKind);
if Enum=Nil then
Exit;
try
While Enum.MoveNext do
begin
if toRowID in TableOptions then
elID:=aCell.TableID+'-'+RowKindNames[aKind]+'-'+IntToStr(Enum.CurrentRow)
else
elID:='';
RowEl:=CreateElement('tr',elID);
aCell.SetRowColKind(Enum.CurrentRow,-1,aKind);
Case aKind of
rkBody :
begin
CL:=FOnRowClick;
M:=@DoRowClick;
end;
rkHeader :
begin
CL:=FOnHeaderRowClick;
M:=@DoHeaderRowClick;
end;
rkFooter :
begin
CL:=FOnFooterRowClick;
M:=@DoFooterRowClick;
end;
end;
if Assigned(CL) or (TableRowChecks[Akind] in TableOptions) then
begin
RowEl.dataset['row']:=Enum.CurrentRow;
RowEl.dataset['kind']:=RowKindNames[aKind];
end;
if Assigned(M) then
RowEl.OnClick:=M;
RenderRow(Enum,RowEl,aKind,aCell);
aParent.AppendChild(RowEl);
end;
finally
Enum.Free;
end;
end;
procedure TCustomTableWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
inherited ApplyWidgetSettings(aElement);
RenderData(aElement);
end;
procedure TCustomTableWidget.RenderData(aElement: TJSHTMLElement);
Var
El : TJSHTMLElement;
aCell : TTableWidgetCellData;
W : TWebWidget;
begin
FWidgets:=[];
if (Caption<>'') then
begin
El:=CreateElement('caption',aElement.ID+'-caption');
AppendCaption(EL);
aElement.AppendChild(EL);
end;
aCell:=CreateCellData(aElement.ID);
If (CustomColumns.Count=0) then
CreateDefaultColumns;
if toHeaderRow in TableOptions then
begin
if toHeader in TableOptions then
begin
El:=CreateElement('thead',aElement.ID+'-head');
aElement.AppendChild(el);
end
else
El:=aElement;
aCell.SetRowColKind(-1,-1,rkHeader);
RenderRows(El,rkHeader,aCell);
end;
if toBody in TableOptions then
begin
El:=CreateElement('tbody',aElement.ID+'-body');
aElement.AppendChild(el);
end
else
El:=aElement;
aCell.SetRowColKind(-1,-1,rkBody);
RenderRows(El,rkBody,aCell);
if toFooterRow in TableOptions then
begin
if toFooter in TableOptions then
begin
El:=CreateElement('tFoot',aElement.ID+'-foot');
aElement.AppendChild(el);
end
else
El:=aElement;
aCell.SetRowColKind(-1,-1,rkFooter);
RenderRows(El,rkFooter,aCell);
end;
for W in FWidgets do
W.Refresh;
FWidgets:=[];
end;
function TCustomTableWidget.CreateCellData(const aTableID : String): TTableWidgetCellData;
begin
Result:=TTableWidgetCellData.Create(Self,aTableID);
end;
function TCustomTableWidget.CreateColumns: TCustomTableColumns;
begin
Result:=TCustomTableColumns.Create(TCustomTableColumn);
end;
function TCustomTableWidget.DefaultTableOptions: TTableOptions;
begin
Result:=[toHeader,toBody,toFooter,toHeaderRow]
end;
procedure TCustomTableWidget.CreateDefaultColumns;
begin
// Do nothing
end;
constructor TCustomTableWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FTableOptions:=DefaultTableOptions;
FColumns:=CreateColumns;
end;
destructor TCustomTableWidget.Destroy;
begin
FreeAndNil(FColumns);
inherited Destroy;
end;
procedure TCustomTableWidget.BeginUpdate;
begin
Inc(FUpDateCount);
end;
procedure TCustomTableWidget.EndUpdate;
begin
if (FUpdateCount>0) then
Dec(FUpDateCount);
if (FUpdateCount=0) and IsRendered then
Refresh;
end;
procedure TCustomTableWidget.RefreshBody;
begin
if Not Assigned(Element) then
Refresh
else
begin
Element.Innerhtml:='';
RenderData(Element);
end;
end;
{ TCustomTableColumn }
procedure TCustomTableColumn.SetAlignment(AValue: TAlignment);
begin
if FAlignment=AValue then Exit;
FAlignment:=AValue;
end;
function TCustomTableColumn.GetCaption: String;
begin
Result:=FCaption;
end;
procedure TCustomTableColumn.SetCaption(AValue: String);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
end;
procedure TCustomTableColumn.SetClassNames(AValue: String);
begin
if FClassNames=AValue then Exit;
FClassNames:=AValue;
end;
function TCustomTableColumn.RenderColumn: Boolean;
begin
Result:=True;
end;
function TCustomTableColumn.GetDisplayName: string;
begin
Result:=Caption;
end;
procedure TCustomTableColumn.Assign(Source: TPersistent);
Var
C : TCustomTableColumn;
begin
if Source is TCustomTableColumn then
begin
C:=Source as TCustomTableColumn;
FCaption:=C.FCaption;
FClassNames:=C.FClassNames;
FAlignment:=C.Alignment;
end
else
inherited Assign(Source);
end;
{ TCustomTableColumns }
function TCustomTableColumns.GetCustomColumn(Index : Integer): TCustomTableColumn;
begin
Result:=TCustomTableColumn(Items[Index]);
end;
procedure TCustomTableColumns.SetCustomColumn(Index : Integer; AValue: TCustomTableColumn);
begin
Items[Index]:=aValue;
end;
function TCustomTableColumns.Add(aCaption: String): TCustomTableColumn;
begin
Result:=add as TCustomTableColumn;
Result.Caption:=aCaption;
end;
{ TTableRowEnumerator }
constructor TTableRowEnumerator.Create(ATable: TCustomTableWidget);
begin
FTable:=aTable;
FCurrent:=-1;
end;
function TTableRowEnumerator.MoveNext: Boolean;
begin
Inc(FCurrent);
Result:=True;
end;
{ TCustomTextWidget }
procedure TCustomTextWidget.SetEnvelopeTag(AValue: TTextTag);
begin
// Writeln('Setting text tag : ',aValue);
if FEnvelopeTag=AValue then Exit;
FEnvelopeTag:=AValue;
if (FEnvelopeTag=ttCustom) and (FCustomTag='') then
FCustomTag:='div';
if IsRendered then
Refresh;
end;
procedure TCustomTextWidget.SetCustomTag(AValue: String);
begin
if FCustomTag=AValue then Exit;
FCustomTag:=AValue;
if (FCustomTag<>'') then
FEnvelopeTag:=ttCustom;
if IsRendered then
Refresh;
end;
procedure TCustomTextWidget.SetTextMode(AValue: TTextMode);
begin
if FTextMode=AValue then Exit;
FTextMode:=AValue;
if IsRendered then
ApplyText(Element);
end;
procedure TCustomTextWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
// Writeln('ApplyWidgetSettings: ',aElement.tagName);
inherited ApplyWidgetSettings(aElement);
ApplyText(aElement);
end;
procedure TCustomTextWidget.ApplyText(aElement: TJSHTMLElement);
begin
if FTextMode=tmText then
aElement.innerText:=GetText
else
aElement.innerHTML:=GetText;
end;
function TCustomTextWidget.HTMLTag: String;
begin
Result:=TextTagNames[FEnvelopeTag];
if Result='' then
Result:='div';
// Writeln('Getting element tag: ',Result);
end;
{ TTextLinesWidget }
procedure TTextLinesWidget.SetLines(AValue: TStrings);
begin
if FLines=AValue then Exit;
FLines.Assign(AValue);
end;
procedure TTextLinesWidget.SetForceLineBreaks(AValue: Boolean);
begin
if FForceLineBreaks=AValue then Exit;
FForceLineBreaks:=AValue;
if IsRendered then
ApplyText(Element);
end;
procedure TTextLinesWidget.DoLinesChanged(Sender: TObject);
begin
if IsRendered then
ApplyText(Element);
end;
function TTextLinesWidget.GetText: String;
Var
I : integer;
begin
if (FTextMode=tmHTML) and ForceLineBreaks then
begin
Result:='';
For I:=0 to FLines.Count-1 do
Result:=Result+flines[i]+'<br/>';
end
else
Result:=FLines.Text;
end;
procedure TTextLinesWidget.ApplyText(aElement: TJSHTMLElement);
Var
I : integer;
begin
if (TextMode=tmHTML) or (Not ForceLineBreaks) then
inherited ApplyText(aElement)
else
begin
For I:=0 to FLines.Count-1 do
begin
aElement.AppendChild(Document.createTextNode(FLines[i]));
aElement.AppendChild(CreateElement('br',''));
end;
end;
end;
constructor TTextLinesWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FLines:=TstringList.Create;
TstringList(FLines).OnChange:=@DoLinesChanged;
end;
destructor TTextLinesWidget.Destroy;
begin
FLines:=TstringList.Create;
inherited Destroy;
end;
{ TTextWidget }
procedure TTextWidget.SetText(AValue: String);
begin
if FText=AValue then Exit;
FText:=AValue;
if IsRendered then
ApplyText(Element);
end;
function TTextWidget.GetText: String;
begin
Result:=FText;
end;
{ TLabelWidget }
procedure TLabelWidget.ApplyLabelFor(aLabelElement : TJSHTMLLabelElement);
begin
if Assigned(FlabelFor) then
begin
FlabelFor.EnsureElement;
aLabelElement.for_:=FlabelFor.ElementID;
end
else
aLabelElement.for_:='';
end;
procedure TLabelWidget.SetLabelFor(AValue: TWebWidget);
begin
if (FLabelFor=AValue) then Exit;
if Assigned(FLabelFor) then
FLabelFor.RemoveFreeNotification(Self);
FLabelFor:=AValue;
if Assigned(FLabelFor) then
FLabelFor.FreeNotification(Self);
If IsRendered then
ApplyLabelFor(LabelElement);
end;
function TLabelWidget.GetText: String;
begin
if IsElementDirty then
FText:=Element.InnerText;
Result:=FText;
end;
function TLabelWidget.GetLabelEl: TJSHTMLLabelElement;
begin
Result:=TJSHTMLLabelElement(Element);
end;
procedure TLabelWidget.SetText(AValue: String);
begin
If Text=aValue then exit;
Ftext:=aValue;
If IsRendered then
Element.innerText:=aValue;
end;
procedure TLabelWidget.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation=opRemove) and (aComponent=FLabelFor) then
FLabelFor:=Nil;
end;
procedure TLabelWidget.SetName(const NewName: TComponentName);
Var
Old : String;
begin
Old:=Name;
inherited SetName(NewName);
if (csDesigning in ComponentState) then
if Old=Text then
Text:=Old;
end;
procedure TLabelWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
var
lbl : TJSHTMLLabelElement absolute aElement;
begin
inherited ApplyWidgetSettings(aElement);
lbl.InnerText:=Text;
ApplyLabelFor(Lbl);
end;
function TLabelWidget.HTMLTag: String;
begin
Result:='label';
end;
{ TSelectWidget }
function TCustomSelectWidget.GetSelectedIndex: Integer;
begin
if IsRendered then
FSelectedIndex:=SelectElement.selectedIndex;
Result:=FSelectedIndex
end;
function TCustomSelectWidget.GetMultiple: Boolean;
begin
if IsElementDirty then
FMultiple:=SelectElement.multiple;
Result:=FMultiple;
end;
function TCustomSelectWidget.GetItemCount: Integer;
begin
Result:=Length(Options);
end;
function TCustomSelectWidget.GetSelected(Index : Integer): Boolean;
begin
if (Index<0) or (Index>=Length(Foptions)) then
Raise EWidgets.CreateFmt(SErrInvalidIndex,[Index,Length(Foptions)-1]);
Result:=FOptions[Index].Selected
end;
function TCustomSelectWidget.GetSelect: TJSHTMLSelectElement;
begin
Result:=TJSHTMLSelectElement(Element);
end;
function TCustomSelectWidget.GetSelectionCount: Integer;
begin
Result:=SelectElement.selectedOptions.length;
end;
function TCustomSelectWidget.GetSelectionItem(aIndex : Integer): String;
begin
if (aIndex<0) or (aindex>=GetSelectionCount) then
Raise EWidgets.CreateFmt(SErrInvalidIndex,[aIndex,GetSelectionCount-1]);
Result:=TJSHTMLOptionElement(SelectElement.selectedOptions.item(aIndex)).innerText;
end;
function TCustomSelectWidget.GetSelectionValue(aIndex : Integer): String;
begin
if (aIndex<0) or (aindex>=GetSelectionCount) then
Raise EWidgets.CreateFmt(SErrInvalidIndex,[aIndex,GetSelectionCount-1]);
Result:=TJSHTMLOptionElement(SelectElement.selectedOptions.item(aIndex)).value;
end;
function TCustomSelectWidget.GetSize: Integer;
begin
if IsElementDirty then
FSize:=SelectElement.Size;
Result:=FSize;
end;
procedure TCustomSelectWidget.SetMultiple(AValue: Boolean);
begin
If (AValue=Multiple) then exit;
FMultiple:=aValue;
If IsRendered then
SelectElement.multiple:=FMultiple;
end;
procedure TCustomSelectWidget.SetSelected(Index : Integer; AValue: Boolean);
begin
if (Index<0) or (Index>=Length(Foptions)) then
Raise EWidgets.CreateFmt(SErrInvalidIndex,[Index,Length(Foptions)-1]);
FOptions[Index].Selected:=aValue;
end;
procedure TCustomSelectWidget.SetSelectedIndex(AValue: Integer);
begin
if (SelectedIndex=aValue) then
Exit;
FSelectedIndex:=aValue;
if IsRendered then
SelectElement.SelectedIndex:=FSelectedIndex;
if Assigned(OnChange) then
OnChange(Self,Nil);
end;
procedure TCustomSelectWidget.SetSize(AValue: Integer);
begin
If (AValue=Size) then exit;
FSize:=aValue;
If IsRendered then
SelectElement.Size:=FSize;
end;
procedure TCustomSelectWidget.BuildOptions(aSelect: TJSHTMLSelectElement);
Var
O : TJSHTMLOptionElement;
Idx : Integer;
enum : TSelectOptionEnumerator;
begin
// Clear
SetLength(FOptions,0);
aSelect.InnerHTML:='';
// Rebuild
Idx:=0;
enum:=CreateOptionEnumerator;
While enum.MoveNext do
begin
O:=TJSHTMLOptionElement(CreateElement('option',''));
O.innerText:=enum.OptionText;
if enum.HasValue then
O.value:=enum.Value;
if Idx=FSelectedIndex then
O.selected:=True;
aSelect.AppendChild(O);
Inc(Idx);
end;
SetLength(Foptions,Idx);
Dec(idx);
While Idx>=0 do
begin
FOptions[Idx]:=TJSHTMLOptionElement(aSelect.Children[Idx]);
dec(Idx);
end;
end;
constructor TCustomSelectWidget.Create(aOWner: TComponent);
begin
inherited Create(aOWner);
FSelectedIndex:=-1;
end;
procedure TCustomSelectWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
Var
el : TJSHTmlSelectElement absolute aElement;
begin
inherited ApplyWidgetSettings(aElement);
el.multiple:=Self.Multiple;
el.Size:=Self.Size;
BuildOptions(el);
// We need to force this.
if SelectedIndex=-1 then
el.selectedIndex:=-1;
end;
function TCustomSelectWidget.HTMLTag: String;
begin
Result:='select';
end;
{ TSelectWidget }
function TSelectWidget.GetItems: TStrings;
begin
Result:=FItems;
end;
function TSelectWidget.GetValues: TStrings;
begin
Result:=FValues;
end;
procedure TSelectWidget.OptionsChanged(Sender: TObject);
begin
if IsRendered then
BuildOptions(SelectElement);
end;
procedure TSelectWidget.setItems(AValue: TStrings);
begin
If (AValue=FItems) then exit;
FItems.Assign(aValue);
end;
procedure TSelectWidget.setValues(AValue: TStrings);
begin
If (AValue=FValues) then exit;
FValues.Assign(aValue);
end;
function TSelectWidget.CreateOptionEnumerator: TSelectOptionEnumerator;
begin
Result:=TStringsSelectOptionEnumerator.Create(Self);
end;
constructor TSelectWidget.Create(aOWner: TComponent);
begin
inherited Create(aOWner);
FItems:=TStringList.Create;
TStringList(FItems).OnChange:=@OptionsChanged;
FValues:=TStringList.Create;
TStringList(FValues).OnChange:=@OptionsChanged;
end;
destructor TSelectWidget.Destroy;
begin
FreeAndNil(FItems);
FreeAndNil(FValues);
inherited Destroy;
end;
{ TImageWidget }
function TImageWidget.GetHeight: Integer;
begin
if IsElementDirty then
FHeight:=ImgElement.Height;
Result:=Fheight;
end;
function TImageWidget.GetImg: TJSHTMLImageElement;
begin
Result:=TJSHTMLImageElement(Element);
end;
function TImageWidget.GetSrc: String;
begin
if IsElementDirty then
FSrc:=ImgElement.Src;
Result:=FSrc;
end;
function TImageWidget.GetWidth: Integer;
begin
if IsElementDirty then
FWidth:=ImgElement.Width;
Result:=FWidth;
end;
procedure TImageWidget.SetHeight(AValue: Integer);
begin
if AValue=Height then exit;
FHeight:=AValue;
If isrendered then
ImgElement.Height:=aValue;
end;
procedure TImageWidget.SetSrc(AValue: String);
begin
if AValue=Src then exit;
FSrc:=AValue;
If isrendered then
ImgElement.Src:=FSrc;
end;
procedure TImageWidget.SetWidth(AValue: Integer);
begin
if AValue=Width then exit;
FWidth:=AValue;
If isrendered then
ImgElement.Width:=aValue;
end;
procedure TImageWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
var
img : TJSHTMLImageElement absolute aElement;
begin
inherited ApplyWidgetSettings(aElement);
Img.Src:=FSrc;
Img.Height:=FHeight;
Img.Width:=FWidth;
end;
function TImageWidget.HTMLTag: String;
begin
Result:='img';
end;
{ TTextAreaWidget }
procedure TTextAreaWidget.SetLines(AValue: TStrings);
begin
if FLines=AValue then Exit;
FLines.Assign(AValue);
end;
procedure TTextAreaWidget.SetMaxLength(AValue: Cardinal);
begin
if FMaxLength=AValue then Exit;
FMaxLength:=AValue;
if IsRendered then
TextArea.maxLength:=aValue;
end;
procedure TTextAreaWidget.SetReadonly(AValue: Boolean);
begin
If aValue=ReadOnly then exit;
FReadOnly:=aValue;
if IsRendered then
TextArea.Readonly:=FReadOnly;
end;
procedure TTextAreaWidget.SetRequired(AValue: Boolean);
begin
If aValue=Required then exit;
FRequired:=aValue;
if IsRendered then
TextArea.Required:=FRequired;
end;
function TTextAreaWidget.GetColumns: Cardinal;
begin
if IsElementDirty then
FColumns:=TextArea.Cols;
Result:=FColumns;
end;
procedure TTextAreaWidget.DoLineChanges(Sender: TObject);
begin
if isRendered and not FIgnoreChanges then
ApplyLines(TextArea);
end;
function TTextAreaWidget.GetLines: TStrings;
begin
// We may want to change this to something more efficient. Maybe handle onchange
// Note that if yo
if IsElementDirty then
begin
FIgnoreChanges:=True;
try
LinesFromHTML(Element.InnerHTml);
finally
FIgnoreChanges:=False;
end;
end;
Result:=FLines;
end;
function TTextAreaWidget.GetReadOnly: Boolean;
begin
if IsElementDirty then
FReadonly:=TextArea.readOnly;
Result:=FReadonly;
end;
function TTextAreaWidget.GetRequired: Boolean;
begin
if IsElementDirty then
FRequired:=TextArea.Required;
Result:=FRequired;
end;
function TTextAreaWidget.GetRows: Cardinal;
begin
if IsElementDirty then
FRows:=TextArea.Rows;
Result:=FRows;
end;
function TTextAreaWidget.GetText: String;
begin
if IsElementDirty then
Result:=Element.InnerHTML
else
Result:=FLines.Text;
end;
function TTextAreaWidget.GetValueName: string;
begin
if IsElementDirty then
FValueName:=Element.Name;
Result:=FValueName;
end;
procedure TTextAreaWidget.SetColumns(AValue: Cardinal);
begin
if AValue=FColumns then exit;
FColumns:=aValue;
if isRendered then
TextArea.cols:=aValue;
end;
procedure TTextAreaWidget.SetRows(AValue: Cardinal);
begin
if AValue=FRows then exit;
FRows:=aValue;
if isRendered then
TextArea.Rows:=aValue;
end;
procedure TTextAreaWidget.SetText(AValue: String);
begin
if isRendered then
element.InnerText:=aValue
else
LinesFromHTML(aValue);
end;
procedure TTextAreaWidget.SetValueName(AValue: string);
begin
if aValue=FValueName then exit;
FValueName:=aValue;
if IsRendered then
TextArea.Name:=aValue;
end;
procedure TTextAreaWidget.SetName(const NewName: TComponentName);
var
Old : String;
begin
Old:=Name;
inherited SetName(NewName);
if csDesigning in ComponentState then
begin
if (FLines.Count=0) then
FLines.Add(Name)
else if (FLines.Count=1) and (FLines[0]=Old) then
FLines[0]:=Name;
end;
end;
procedure TTextAreaWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
var
area : TJSHTMLTextAreaElement absolute aElement;
begin
inherited ApplyWidgetSettings(aElement);
if FMaxLength>0 then
area.maxlength:=FMaxLength;
if FColumns>0 then
area.cols:=FColumns;
if FRows>0 then
area.Rows:=FRows;
if FLines.Count>0 then
ApplyLines(area);
if FValueName<>'' then
area.Name:=FValueName;
area.Readonly:=FReadOnly;
area.Required:=FRequired;
ApplyWrap(area);
end;
constructor TTextAreaWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FLines:=TStringList.Create;
TStringList(FLines).OnChange:=@DoLineChanges;
FColumns:=50;
FRows:=10;
end;
destructor TTextAreaWidget.Destroy;
begin
FreeAndNil(Flines);
inherited;
end;
class function TTextAreaWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
function TTextAreaWidget.GetTextArea: TJSHTMLTextAreaElement;
begin
Result:=TJSHTMLTextAreaElement(Element);
end;
procedure TTextAreaWidget.ApplyWrap(aElement :TJSHTMLTextAreaElement);
Const
Wraps : Array[TTextAreaWrap] of string = ('soft','hard','off');
begin
aElement.wrap:=Wraps[FWrap];
end;
procedure TTextAreaWidget.ApplyLines(aElement: TJSHTMLTextAreaElement);
begin
aElement.innerHTML:=FLines.Text;
end;
procedure TTextAreaWidget.LinesFromHTML(aHTML: String);
begin
FLines.Text:= StringReplace(aHTML,'<br>',sLineBreak,[rfIgnoreCase,rfReplaceAll]);
end;
procedure TTextAreaWidget.SetWrap(AValue: TTextAreaWrap);
begin
if FWrap=AValue then Exit;
FWrap:=AValue;
if IsRendered then
ApplyWrap(TextArea)
end;
function TTextAreaWidget.HTMLTag: String;
begin
result:='textarea';
end;
{ TCheckboxInputWidget }
function TCheckboxInputWidget.InputType: String;
begin
Result:='checkbox';
end;
{ TRadioInputWidget }
function TRadioInputWidget.InputType: String;
begin
Result:='radio';
end;
{ THiddenInputWidget }
class function THiddenInputWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
function THiddenInputWidget.InputType: String;
begin
Result:='hidden';
end;
{ TFileInputWidget }
procedure TFileInputWidget.SetMultiple(AValue: Boolean);
begin
if FMultiple=AValue then Exit;
FMultiple:=AValue;
if Isrendered then
InputElement.multiple:=FMultiple;
end;
function TFileInputWidget.GetMultiple: Boolean;
begin
if IsElementDirty then
FMultiple:=InputElement.multiple;
Result:=FMultiple;
end;
function TFileInputWidget.GetFileName(aIndex : Integer): String;
begin
Result:=InputElement.files.Files[aIndex].name;
end;
function TFileInputWidget.GetFileSize(aIndex : Integer): NativeInt;
begin
Result:=InputElement.files.Files[aIndex].Size;
end;
function TFileInputWidget.GetFileType(aIndex : Integer): String;
begin
Result:=InputElement.files.Files[aIndex]._Type;
end;
function TFileInputWidget.GetFileCount: Integer;
begin
Result:=InputElement.files.Length;
end;
function TFileInputWidget.GetFileDate(aIndex : Integer): TDateTime;
begin
Result:=JSDateToDateTime(InputElement.files.Files[aIndex].lastModifiedDate);
end;
function TFileInputWidget.GetFileInfo(aIndex : Integer): TFileInfo;
Var
f : TJSHTMLFile;
begin
F:=InputElement.files.Files[aIndex];
Result.Name:=F.name;
Result.Size:=F.size;
Result.FileType:=F._type;
Result.TimeStamp:= JSDateToDateTime(F.lastModifiedDate);
end;
procedure TFileInputWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
Var
Old : String;
begin
Old:=FValue;
FValue:='';
try
inherited ApplyWidgetSettings(aElement);
TJSHTMLInputElement(aElement).multiple:=FMultiple;
finally
FValue:=Old;
end;
end;
class function TFileInputWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
function TFileInputWidget.InputType: String;
begin
Result:='file';
end;
{ TDateInputWidget }
function TDateInputWidget.GetDate: TDateTime;
var
aDate : TDateTime;
begin
if IsElementDirty then
begin
aDate:=ScanDateTime('yyyy-mm-dd',Value);
if aDate<>0 then
FDate:=aDate;
end;
Result:=FDate;
end;
procedure TDateInputWidget.SetDate(AValue: TDateTime);
begin
FDate:=aValue;
Value:=FormatDateTime('yyyy-mm-dd',FDate);
end;
function TDateInputWidget.InputType: String;
begin
Result:='date';
end;
class function TDateInputWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
{ TCheckableInputWidget }
procedure TCheckableInputWidget.SetChecked(AValue: Boolean);
begin
// Get actual value
if Checked=AValue then Exit;
if isRendered then
InputElement.checked:=aValue;
FChecked:=AValue;
end;
procedure TCheckableInputWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
inherited ApplyWidgetSettings(aElement);
TJSHTMLInputElement(aElement).Checked:=FChecked;
end;
function TCheckableInputWidget.GetChecked: Boolean;
begin
if IsElementDirty then
FChecked:=InputElement.Checked;
Result:=FChecked;
end;
{ TButtonInputWidget }
procedure TButtonInputWidget.SetButtonType(AValue: TInputButtonType);
begin
if FButtonType=AValue then Exit;
FButtonType:=AValue;
if IsRendered then
Refresh;
end;
procedure TButtonInputWidget.SetSrc(AValue: String);
begin
if FSrc=AValue then Exit;
FSrc:=AValue;
if IsRendered and (ButtonType=ibtImage) then
Element.setAttribute('src',FSrc);
end;
procedure TButtonInputWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
inherited ApplyWidgetSettings(aElement);
if ButtonType=ibtImage then
aElement.setAttribute('src',FSrc);
end;
function TButtonInputWidget.InputType: String;
Const
Types : Array[TInputButtonType] of string = ('submit','reset','image');
begin
Result:=Types[FButtonType]
end;
class function TButtonInputWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
{ TTextInputWidget }
function TTextInputWidget.GetAsNumber: NativeInt;
begin
Result:=StrToIntDef(Value,0);
end;
function TTextInputWidget.GetMaxLength: NativeInt;
begin
if IsElementDirty then
FMaxLength:=InputElement.maxLength;
Result:=FMaxLength;
end;
function TTextInputWidget.GetMinLength: NativeInt;
begin
if IsElementDirty then
FMinLength:=InputElement.minLength;
Result:=FMinLength;
end;
function TTextInputWidget.GetTextType: TInputTextType;
begin
Result:=FTextType;
end;
procedure TTextInputWidget.SetAsNumber(AValue: NativeInt);
begin
Value:=IntToStr(aValue);
end;
procedure TTextInputWidget.SetMaxLength(AValue: NativeInt);
begin
if (aValue=FMaxLength) then exit;
FMaxLength:=aValue;
if IsRendered then
InputElement.maxLength:=FMaxLength;
end;
procedure TTextInputWidget.SetMinLength(AValue: NativeInt);
begin
if (aValue=FMinLength) then exit;
FMinLength:=aValue;
if IsRendered then
InputElement.minLength:=FMinLength;
end;
procedure TTextInputWidget.SetTextType(AValue: TInputTextType);
begin
if aValue=FTextType then exit;
FTextType:=aValue;
if IsRendered then
Refresh;
end;
procedure TTextInputWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
var
inp : TJSHTMLInputElement absolute aElement;
begin
inherited ApplyWidgetSettings(aElement);
if FMaxLength<>0 then
inp.maxLength:=FMaxLength;
if FMinLength<>0 then
inp.minLength:=FMinLength;
end;
class function TTextInputWidget.AllowChildren: Boolean;
begin
Result:=False;
end;
function TTextInputWidget.InputType: String;
Const
Types : Array[TInputTextType] of string =
('text','password','number','email','search','tel','url','color');
begin
Result:=Types[FTextType];
end;
{ TWebPage }
constructor TWebPage.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Classes:='WebPage';
end;
class function TWebPage.DefaultParentElement: TJSHTMLElement;
begin
Result:=TViewport.Instance.Element;
end;
class function TWebPage.DefaultParent: TCustomWebWidget;
begin
Result:=TViewport.Instance;
end;
procedure TWebPage.DoUnRender(aParent: TJSHTMLElement);
begin
inherited DoUnRender(aParent);
end;
function TWebPage.HTMLTag: String;
begin
Result:='div';
end;
{ TViewPort }
function TViewPort.HTMLTag: String;
begin
Result:='body';
end;
class function TViewPort.FixedParent: TJSHTMLElement;
begin
Result:=TJSHTMLElement(Document.documentElement);
end;
class function TViewPort.FixedElement: TJSHTMLElement;
begin
Result:=TJSHTMLElement(Document.Body);
end;
function TViewPort.DoRenderHTML(aParent, aElement: TJSHTMLElement): TJSHTMLElement;
begin
Result:=FixedElement;
end;
constructor TViewPort.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
EnsureElement;
end;
class function TViewPort.Instance: TViewPort;
begin
if Finstance=Nil then
FInstance:=TViewPort.Create(Nil);
Result:=FInstance;
end;
{ TButtonWidget }
{ TButtonWidget }
procedure TButtonWidget.SetText(AValue: String);
begin
if FText=AValue then Exit;
FText:=AValue;
if IsRendered then
ApplyText(Element);
end;
procedure TButtonWidget.SetTextMode(AValue: TTextMode);
begin
if FTextMode=AValue then Exit;
FTextMode:=AValue;
if IsRendered then
ApplyText(Element)
end;
procedure TButtonWidget.SetName(const NewName: TComponentName);
Var
Old : String;
begin
Old:=Name;
inherited SetName(NewName);
if (FText=Old) and (csDesigning in ComponentState) then
FText:=NewName;
end;
function TButtonWidget.HTMLTag: String;
begin
Result:='button';
end;
procedure TButtonWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
Inherited;
ApplyText(aElement);
end;
Procedure TButtonWidget.ApplyText(aElement : TJSHTMLElement);
begin
if FTextMode=tmText then
aElement.InnerText:=FText
else
aElement.InnerHTML:=FText;
end;
procedure TButtonWidget.Click;
begin
DispatchEvent('click');
end;
{ TCustomInputWidget }
function TCustomInputWidget.GetValue: String;
Var
Inp : TJSHTMLInputElement;
begin
Inp:=InputElement;
If Assigned(Inp) then
Result:=Inp.value
else
Result:=FValue
end;
function TCustomInputWidget.GetText: String;
Var
Inp : TJSHTMLElement;
begin
Inp:=Element;
If Assigned(Inp) then
Result:=Inp.InnerText
else
Result:=FText;
// Writeln('Getting text: ',Result,' inner : ',FText);
end;
function TCustomInputWidget.GetReadOnly: Boolean;
begin
if IsElementDirty then
FReadonly:=InputElement.readOnly;
Result:=FReadonly;
end;
function TCustomInputWidget.GetRequired: Boolean;
begin
if IsElementDirty then
FRequired:=InputElement.Required;
Result:=FRequired;
end;
function TCustomInputWidget.GetValueName: String;
Var
Inp : TJSHTMLInputElement;
begin
Inp:=InputElement;
If Assigned(Inp) then
Result:=Inp.Name
else
begin
Result:=FValueName;
if Result='' then
Result:=Name;
end;
end;
procedure TCustomInputWidget.SetReadonly(AValue: Boolean);
begin
If aValue=ReadOnly then exit;
FReadOnly:=aValue;
if IsRendered then
InputElement.Readonly:=FReadOnly;
end;
procedure TCustomInputWidget.SetRequired(AValue: Boolean);
begin
If aValue=Required then exit;
FRequired:=aValue;
if IsRendered then
InputElement.Required:=FRequired;
end;
procedure TCustomInputWidget.SetText(AValue: String);
Var
Inp : TJSHTMLElement;
begin
Writeln('Setting text: ',AValue,' previous : ',Text);
if aValue=Text then exit;
FText:=aValue;
Inp:=Element;
If Assigned(Inp) then
Inp.innerText:=aValue;
end;
procedure TCustomInputWidget.SetValue(AValue: String);
Var
Inp : TJSHTMLInputElement;
begin
if aValue=Value then exit;
FValue:=aValue;
Inp:=InputElement;
If Assigned(Inp) then
Inp.value:=aValue;
end;
procedure TCustomInputWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
var
Inp : TJSHTMLInputElement absolute aElement;
begin
Inherited;
if (ExternalElement) and (FValue='') then
FValue:=TJSHTMLInputElement(aElement).value
else
begin
Inp._type:=InputType;
Inp.name:=FValueName;
Inp.value:=FValue;
Inp.Required:=FRequired;
Inp.ReadOnly:=FReadOnly;
Writeln('Setting inner text to "',FText,'"');
Inp.innerHtml:=FText;
Writeln('Setting inner text is now "',Inp.innerText,'"');
end;
end;
function TCustomInputWidget.HTMLTag: String;
begin
Result:='input';
end;
function TCustomInputWidget.GetInputElement: TJSHTMLInputElement;
begin
Result:=TJSHTMLInputElement(Element);
end;
procedure TCustomInputWidget.SetValueName(AValue: String);
Var
Inp : TJSHTMLInputElement;
begin
if aValue=ValueName then exit;
FValueName:=aValue;
Inp:=InputElement;
If Assigned(Inp) then
Inp.name:=aValue;
end;
procedure TCustomInputWidget.SetName(const NewName: TComponentName);
Var
Old : String;
begin
Old:=Name;
inherited SetName(NewName);
if (Value=Old) then
Value:=NewName;
end;
{ TCustomTagWidget }
procedure TCustomTagWidget.SetElementTag(AValue: THTMLElementTag);
begin
if FElementTag=AValue then Exit;
FElementTag:=AValue;
if IsRendered then
Refresh;
end;
procedure TCustomTagWidget.SetTextContent(AValue: String);
begin
if FTextContent=AValue then Exit;
FTextContent:=AValue;
if IsRendered then
Refresh;
end;
procedure TCustomTagWidget.ApplyWidgetSettings(aElement: TJSHTMLElement);
begin
inherited ApplyWidgetSettings(aElement);
if FTextContent<>'' then
aElement.InnerText:=TextContent;
end;
function TCustomTagWidget.HTMLTag: String;
begin
Result:=HTMLTagNames[ElementTag];
end;
{ TDivWidget }
constructor TDivWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
ElementTag:=etDiv;
end;
constructor TParagraphWidget.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
ElementTag:=etP;
end;
end.