{***************************************************************************}
{ TMS IntraWeb Component Pack Pro                                           }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2015                                               }
{            Email : info@tmssoftware.com                                   }
{            Web : http://www.tmssoftware.com                               }
{                                                                           }
{ The source code is given as is. The author is not responsible             }
{ for any possible damage done due to the use of this code.                 }
{ The component can be freely used in any application. The complete         }
{ source code remains property of the author and may not be distributed,    }
{ published, given or sold in any form as such. No parts of the source      }
{ code can be included in any other component or application without        }
{ written authorization of the author.                                      }
{***************************************************************************}

unit IWResponsiveList;

{$I TMSDEFS.INC}

interface

uses
  Windows, Graphics, Controls, Forms,
  {$IFDEF DELPHI6_LVL}
  Types,
  {$ENDIF}
  Classes,
  IWControl, IWTypes, IWRenderContext, IWHTMLTag, IWXMLTag, IWTMSBase, IWColor,
  IWFont;

type
  TTIWCustomResponsiveList = class;
  TTIWResponsiveList = class;
  TIWResponsiveLayoutItems = class;
  TIWListItems = class;
  TIWListItem = class;
  TIWItemStyles = class;

  TIWListLayout = (llFlow, llResponsive);
  TIWItemSize = (isAuto, isFixed);
  TIWItemEvent = procedure(Sender: TObject; Index: integer) of object;
  TIWItemRenderEvent = procedure(Sender: TObject; Index: integer;
    var ItemStyle: string) of object;
  TIWAsyncGetAttributesEvent = procedure(Sender: TObject;
    EventParams: TStringList; ItemIndex: integer;
    ControlIDs, AttributeNames, AttributeValues: TStringList) of object;
  TIWAsyncExecuteJSEvent = procedure(Sender: TObject; EventParams: TStringList;
    ItemIndex: integer; ReturnValue: string) of object;
  TIWAsyncItemEvent = procedure(Sender: TObject; EventParams: TStringList;
    Index: integer) of object;
  TIWAsyncControlEvent = procedure (Sender: TObject; EventParams: TStringList;
    EventType, ControlID: string; ItemIndex: integer) of object;

  TIWResponsiveLayoutItem = class(TCollectionItem)
  private
    FOwner: TIWResponsiveLayoutItems;
    FName: string;
    FTag: integer;
    FValue: string;
    FMinScreenWidth: integer;
    FColumns: integer;
    procedure SetColumns(const Value: integer);
    procedure SetMinScreenWidth(const Value: integer);
    procedure SetName(const Value: string);
    procedure SetTag(const Value: integer);
    procedure SetValue(const Value: string);
  protected
    function GetDisplayName: String; override;
    procedure Invalidate;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  published
    property Columns: integer read FColumns write SetColumns default 1;
    property MinScreenWidth: integer read FMinScreenWidth write SetMinScreenWidth default 0;
    property Name: string read FName write SetName;
    property Tag: integer read FTag write SetTag default 0;
    property Value: string read FValue write SetValue;
  end;

  TIWResponsiveLayoutItems = class(TCollection)
  private
    FOwner: TTIWCustomResponsiveList;
    function GetItem(Index: Integer): TIWResponsiveLayoutItem;
    procedure SetItem(Index: Integer; const Value: TIWResponsiveLayoutItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TTIWCustomResponsiveList);
    function Add: TIWResponsiveLayoutItem;
    function GetOwner: TPersistent; override;
    property Items[Index: Integer]: TIWResponsiveLayoutItem read GetItem write SetItem; default;
  end;

  TIWListItem = class(TCollectionItem)
  private
    FOwner: TIWListItems;
    FText: TStringList;
    FName: string;
    FTag: integer;
    FValue: string;
    FItemStyle: string;
    FIsSection: boolean;
    FSelected: boolean;
    FCss: string;
    FCssSelected: string;
    procedure SetItemStyle(const Value: string);
  protected
    function GetDisplayName: String; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  published
    property Css: string read FCss write FCss;
    property CssSelected: string read FCssSelected write FCssSelected;
    property IsSection: boolean read FIsSection write FIsSection default false;
    property ItemStyle: string read FItemStyle write SetItemStyle;
    property Name: string read FName write FName;
    property Selected: boolean read FSelected write FSelected default false;
    property Tag: integer read FTag write FTag default 0;
    property Text: TStringList read FText write FText;
    property Value: string read FValue write FValue;
  end;

  TIWListItems = class(TCollection)
  private
    FOwner: TTIWCustomResponsiveList;
    function GetItem(Index: Integer): TIWListItem;
    procedure SetItem(Index: Integer; const Value: TIWListItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TTIWCustomResponsiveList);
    function Add: TIWListItem;
    function GetOwner: TPersistent; override;
    property Items[Index: Integer]: TIWListItem read GetItem write SetItem; default;
    property List: TTIWCustomResponsiveList read FOwner;
  end;

  TIWPadding = class(TPersistent)
  private
    FOwner: TObject;
    FHorizontal: integer;
    FVertical: integer;
    procedure SetHorizontal(const Value: integer);
    procedure SetVertical(const Value: integer);
  protected
    procedure Invalidate;
  public
    constructor Create(AOwner: TObject);
    procedure Assign(Source: TPersistent); override;
    destructor Destroy; override;
  published
    property Horizontal: integer read FHorizontal write SetHorizontal default 5;
    property Vertical: integer read FVertical write SetVertical default 5;
  end;

  TIWItemStyle = class(TPersistent)
  private
    FOwner: TObject;
    FBorderColor: TIWColor;
    FFont: TIWFont;
    FSelectColor: TIWColor;
    FSelectColorTo: TIWColor;
    FColor: TIWColor;
    FColorTo: TIWColor;
    FSelectFontColor: TIWColor;
    FSelectBorderColor: TIWColor;
    FRoundedBorderRadius: integer;
    FBackgroundImage: string;
    FBorderWidth: integer;
    FSelectBackgroundImage: string;
    procedure SetBorderColor(const Value: TIWColor);
    procedure SetBorderWidth(const Value: integer);
    procedure SetSelectBorderColor(const Value: TIWColor);
    procedure SetColor(const Value: TIWColor);
    procedure SetColorTo(const Value: TIWColor);
    procedure SetFont(const Value: TIWFont);
    procedure SetBackgroundImage(const Value: string);
    procedure SetRoundedBorderRadius(const Value: integer);
    procedure SetSelectBackgroundImage(const Value: string);
    procedure SetSelectColor(const Value: TIWColor);
    procedure SetSelectColorTo(const Value: TIWColor);
    procedure SetSelectFontColor(const Value: TIWColor);
  protected
    procedure Invalidate;
    procedure FontChanged(Sender: TObject);
  public
    constructor Create(AOwner: TObject);
    procedure Assign(Source: TPersistent); override;
    destructor Destroy; override;
  published
    property BackgroundImage: string read FBackgroundImage write SetBackgroundImage;
    property BorderColor: TIWColor read FBorderColor write SetBorderColor default clWebBlack;
    property BorderWidth: integer read FBorderWidth write SetBorderWidth default 1;
    property Color: TIWColor read FColor write SetColor default clWebWhite;
    property ColorTo: TIWColor read FColorTo write SetColorTo default clNone;
    property Font: TIWFont read FFont write SetFont;
    property RoundedBorderRadius: integer read FRoundedBorderRadius write SetRoundedBorderRadius default 0;
    property SelectBackgroundImage: string read FSelectBackgroundImage write SetSelectBackgroundImage;
    property SelectBorderColor: TIWColor read FSelectBorderColor write SetSelectBorderColor default clWebBlack;
    property SelectColor: TIWColor read FSelectColor write SetSelectColor default clWebWhite;
    property SelectColorTo: TIWColor read FSelectColorTo write SetSelectColorTo default clNone;
    property SelectFontColor: TIWColor read FSelectFontColor write SetSelectFontColor default clWebBlack;
  end;

  TIWItemStylesItem = class(TCollectionItem)
  private
    FOwner: TIWItemStyles;
    FItemStyle: TIWItemStyle;
    FName: string;
    FTag: integer;
  protected
    function GetDisplayName: String; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  published
    property ItemStyle: TIWItemStyle read FItemStyle write FItemStyle;
    property Name: string read FName write FName;
    property Tag: integer read FTag write FTag default 0;
  end;

  TIWItemStyles = class(TCollection)
  private
    FOwner: TTIWCustomResponsiveList;
    function GetItem(Index: Integer): TIWItemStylesItem;
    procedure SetItem(Index: Integer; const Value: TIWItemStylesItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TTIWCustomResponsiveList);
    function Add: TIWItemStylesItem;
    function GetOwner: TPersistent; override;
    property Items[Index: Integer]: TIWItemStylesItem read GetItem write SetItem; default;
  end;

  TTIWCustomResponsiveList = class(TIWControl)
  private
    FEventType: string;
    FControlID: string;
    FControlIndex: integer;
    FGetControlID: string;
    FGetControlIDs: TStringList;
    FGetItemIndex: integer;
    FGetCallType: integer;
    FAttributeName: string;
    FAttributeNames: TStringList;
    FAttributeValue: string;
    FAttributeValues: TStringList;
    FExJSValue: string;
    FExJSItemIndex: integer;
    FItems: TIWListItems;
    FItemHeight: integer;
    FItemWidth: integer;
    FLayout: TIWListLayout;
    FPadding: TIWPadding;
    FResponsiveLayout: TIWResponsiveLayoutItems;
    FItemIndex: integer;
    FBorderColor: TIWColor;
    FBGColor: TIWColor;
    FDefaultItem: TIWItemStyle;
    FItemStyles: TIWItemStyles;
    FOnAsyncItemClick: TIWAsyncItemEvent;
    FOnItemClick: TIWItemEvent;
    FOnItemRender: TIWItemRenderEvent;
    FItemSize: TIWItemSize;
    FSectionHeight: integer;
    FTitle: string;
    FFont: TIWFont;
    FMultiSelect: Boolean;
    FScrollTop: integer;
    FScrollEnd: integer;
    FScrollMax: integer;
    FScrollTotal: integer;
    FWindowHeight: integer;
    FWindowWidth: integer;
    FItemsPerPage: integer;
    FRenderedItemIndex: integer;
    FOnAsyncScroll: TIWAsyncEvent;
    FOnAsyncControlEvent: TIWAsyncControlEvent;
    FClientScript: string;
    FOnAsyncGetAttributes: TIWAsyncGetAttributesEvent;
    FOnAsyncExecuteJS: TIWAsyncExecuteJSEvent;
    FBGImage: string;
    procedure SetItemHeight(const Value: integer);
    procedure SetItemWidth(const Value: integer);
    procedure SetLayout(const Value: TIWListLayout);
    procedure SetItemIndex(const Value: integer);
    procedure DoOnAsyncItemClick(AParams: TStringList);
    procedure DoOnAsyncControlEvent(AParams: TStringList);
    procedure DoOnAsyncExecuteJS(AParams: TStringList);
    procedure DoOnAsyncGetAttributes(AParams: TStringList);
    procedure DoOnAsyncScroll(AParams: TStringList);
    procedure DoOnAsyncResize(AParams: TStringList);
    procedure SetSectionHeight(const Value: integer);
    procedure SetDefaultItem(const Value: TIWItemStyle);
    procedure SetTitle(const Value: string);
    procedure SetBGColor(const Value: TIWColor);
    procedure SetBorderColor(const Value: TIWColor);
  protected
    procedure SetValue(const value:string); override;
    procedure Submit(const AValue: string); override;
    procedure AsyncItemAddInt(AItem: TIWListItem);
    procedure AsyncGetAttributesInt(ItemIndex: integer; ControlIDs, AttributeNames: TStringList; CallType: integer);
    procedure AddExtraItems();
    procedure DoOnItemClick(ItemIndex: integer); virtual;
    procedure DoUpdateRecord(ItemIndex: integer; FieldNames, FieldValues: TStringList; CallType: integer); virtual;
    procedure ResetScrollData();
    function GetTemplate(): string; virtual;

    property Items: TIWListItems read FItems write FItems;
  public
    procedure IWPaint; override;
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    function RenderAsync(AContext: TIWBaseHTMLComponentContext): TIWXMLTag; override;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AsyncItemAdd(AItem: TIWListItem);
    procedure AsyncItemUpdate(AItem: TIWListItem); overload;
    procedure AsyncItemUpdate(AItemIndex: integer); overload;
    procedure AsyncUpdate();
    procedure AsyncSetAttribute(ItemIndex: integer; ControlID, AttributeName, AttributeValue: string);
    procedure AsyncGetAttributes(ItemIndex: integer; ControlIDs, AttributeNames: TStringList);
    procedure AsyncRemoveAttribute(ItemIndex: integer; ControlID, AttributeName: string);
    procedure AsyncExecuteJS(FunctionName: string; Parameters: TStringList);
    property ClientScript: string read FClientScript write FClientScript;
  published
    property BGColor: TIWColor read FBGColor write SetBGColor default clNone;
    property BGImage: string read FBGImage write FBGImage;
    property BorderColor: TIWColor read FBorderColor write SetBorderColor default clNone;
    property Enabled;
    property DefaultItem: TIWItemStyle read FDefaultItem write SetDefaultItem;
    property Font: TIWFont read FFont write FFont;
    property ItemHeight: integer read FItemHeight write SetItemHeight default 50;
    property ItemIndex: integer read FItemIndex  write SetItemIndex default -1;
    property ItemSize: TIWItemSize read FItemSize write FItemSize default isAuto;
    property ItemStyles: TIWItemStyles read FItemStyles write FItemStyles;
    property ItemWidth: integer read FItemWidth write SetItemWidth default 0;
    property Layout: TIWListLayout read FLayout write SetLayout default llResponsive;
    property MultiSelect: Boolean read FMultiSelect write FMultiSelect default false;
    property Padding: TIWPadding read FPadding write FPadding;
    property ResponsiveLayout: TIWResponsiveLayoutItems read FResponsiveLayout write FResponsiveLayout;
    property SectionHeight: integer read FSectionHeight write SetSectionHeight default 50;
    property Title: string read FTitle write SetTitle;

    property OnItemClick: TIWItemEvent read FOnItemClick write FOnItemClick;
    property OnItemRender: TIWItemRenderEvent read FOnItemRender write FOnItemRender;
    property OnAsyncControlEvent: TIWAsyncControlEvent read FOnAsyncControlEvent write FOnAsyncControlEvent;
    property OnAsyncExecuteJS: TIWAsyncExecuteJSEvent read FOnAsyncExecuteJS write FOnAsyncExecuteJS;
    property OnAsyncGetAttributes: TIWAsyncGetAttributesEvent read FOnAsyncGetAttributes write FOnAsyncGetAttributes;
    property OnAsyncItemClick: TIWAsyncItemEvent read FOnAsyncItemClick write FOnAsyncItemClick;
    property OnAsyncScroll: TIWAsyncEvent read FOnAsyncScroll write FOnAsyncScroll;
  end;

  TTIWResponsiveList = class(TTIWCustomResponsiveList)
  published
    property Items;
  end;

implementation

uses
  IWApplication, SysUtils;

{ TTIWCustomResponsiveList }
function TTIWCustomResponsiveList.RenderAsync(
  AContext: TIWBaseHTMLComponentContext): TIWXMLTag;
var
  js: string;
begin
  Result := TIWXMLTag.CreateTag('control');
  try
    Result.AddStringParam('id', HTMLName);
    Result.AddStringParam('type', 'TTIWResponsiveList');
    RenderAsyncCommonProperties(AContext, Result);

    js := js + HTMLName + 'enabled = ' + BoolToStr(Enabled) + ';'#13;

    GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');

  except
    FreeAndNil(Result);
  end;
end;

procedure TTIWCustomResponsiveList.AsyncExecuteJS(FunctionName: string;
  Parameters: TStringList);
var
  js, text: string;
  I: Integer;
begin
  for I := 0 to Parameters.Count - 1 do
  begin
    if I > 0 then
      text := text + ', ';
    text := text + '"' + StringReplace(Parameters[I], '"', '\"', [rfReplaceAll]) + '"';
  end;

  js := FunctionName + '(' + text + ');'#13;
  GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

procedure TTIWCustomResponsiveList.AsyncGetAttributesInt(ItemIndex: integer;
  ControlIDs, AttributeNames: TStringList; CallType: integer);
var
  js: string;
begin
  ControlIDs.Delimiter := '^';
  AttributeNames.Delimiter := '^';
  js := 'setTimeout(function() { ' + HTMLName + 'GetAttributes('
    + IntToStr(ItemIndex) + ', "' + ControlIDs.DelimitedText + '", "' + AttributeNames.DelimitedText + '", ' + IntToStr(CallType) + ') }, 10);'#13;
  GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

procedure TTIWCustomResponsiveList.AsyncGetAttributes(ItemIndex: integer;
  ControlIDs, AttributeNames: TStringList);
begin
  AsyncGetAttributesInt(ItemIndex, ControlIDs, AttributeNames, 0);
end;

procedure TTIWCustomResponsiveList.AsyncItemAdd(AItem: TIWListItem);
begin
  //Only execute JS if all items already rendered
  if FRenderedItemIndex = Items.Count - 2 then
  begin
    AsyncItemAddInt(AItem);
  end;
end;

procedure TTIWCustomResponsiveList.AsyncItemAddInt(AItem: TIWListItem);
var
  js, VarItemStyle, text: string;
  isSelected: boolean;
begin
    FRenderedItemIndex := FRenderedItemIndex + 1;

    isSelected := (AItem.Selected) or (AItem.Index = ItemIndex);

    text := StringReplace(AItem.Text.Text, '"', '\"', [rfReplaceAll]);
    text := StringReplace(text, #13#10, '\n', [rfReplaceAll]);

    VarItemStyle := AItem.ItemStyle;

    if Assigned(OnItemRender) then
      OnItemRender(Self, AItem.Index, VarItemStyle);

    js := js
      + ' ' + HTMLName + 'RenderItem("'
      + text + '", "'
      + StringReplace(VarItemStyle, '"', '\"', [rfReplaceAll]) + '", '
      + BoolToStr(AItem.IsSection) + ', '
      + BoolToStr(isSelected) + ', "'
      + AItem.Css + '", "'
      + AItem.CssSelected + '"'
      + ');';

    GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

procedure TTIWCustomResponsiveList.AsyncItemUpdate(AItemIndex: integer);
begin
  AsyncItemUpdate(Items[AItemIndex]);
end;

procedure TTIWCustomResponsiveList.AsyncItemUpdate(AItem: TIWListItem);
var
  js: string;
  isSelected: boolean;
  iIndex: integer;
begin
  if not Assigned(AItem) then
    exit;

  iIndex := AItem.Index;

  //Only execute update JS if item is already rendered
  if iIndex <= FRenderedItemIndex then
  begin
    text := StringReplace(AItem.Text.Text, '"', '\"', [rfReplaceAll]);
    text := StringReplace(text, #13#10, '\n', [rfReplaceAll]);

    isSelected := (AItem.Selected) or (iIndex = ItemIndex);

    js := js
      + ' ' + HTMLName + 'AsyncItemUpdate(' + IntToStr(AItem.Index) + ', "'
      + text + '", "'
      + StringReplace(AItem.ItemStyle, '"', '\"', [rfReplaceAll]) + '", '
      + BoolToStr(AItem.IsSection) + ', '
      + BoolToStr(isSelected)
      + ');';

    GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
  end;
end;

procedure TTIWCustomResponsiveList.AsyncRemoveAttribute(ItemIndex: integer; ControlID,
  AttributeName: string);
var
  js: string;
begin
  js := ' el = ' + HTMLName + 'GetControl(' + IntToStr(ItemIndex) +', "' + ControlID + '");'#13
  + 'if (el){'
  + ' el.removeAttribute("' + AttributeName + '");'
  + '}'
  ;
  GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

procedure TTIWCustomResponsiveList.AsyncSetAttribute(ItemIndex: integer; ControlID,
  AttributeName, AttributeValue: string);
var
  js: string;
begin
  js := ' el = ' + HTMLName + 'GetControl(' + IntToStr(ItemIndex) +', "' + ControlID + '");'#13
  + 'if (el){'
  + ' el.setAttribute("' + AttributeName + '", "' + AttributeValue + '");'
  + '}'
  ;
  GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

procedure TTIWCustomResponsiveList.AsyncUpdate;
var
  js, VarItemStyle, text: string;
  I, ItemCount: integer;
begin
  ResetScrollData;
  js := js + ' ' + HTMLName + 'ClearItems();';
  js := js + ' ' + HTMLName + 'RenderTitle("' + StringReplace(Title, '"', '\"', [rfReplaceAll]) + '");';

  ItemCount := FItemsPerPage;
  if Items.Count < FItemsPerPage then
    ItemCount := Items.Count;

  for I := 0 to ItemCount - 1  do
  begin
    VarItemStyle := Items[I].ItemStyle;
    if Assigned(OnItemRender) then
      OnItemRender(Self, I, VarItemStyle);

    FRenderedItemIndex := FRenderedItemIndex + 1;

    text := StringReplace(Items[I].Text.Text, '"', '\"', [rfReplaceAll]);
    text := StringReplace(text, #13#10, '\n', [rfReplaceAll]);

    js := js + ' ' + HTMLName + 'Items[' + IntToStr(I) + '] = "' + text + '";';
    js := js + ' ' + HTMLName + 'Styles[' + IntToStr(I) + '] = "' + StringReplace(VarItemStyle, '"', '\"', [rfReplaceAll]) + '";';
    js := js + ' ' + HTMLName + 'Sections[' + IntToStr(I) + '] = "' + BoolToStr(Items[I].IsSection) + '";';
    js := js + ' ' + HTMLName + 'Selected[' + IntToStr(I) + '] = "' + BoolToStr(Items[I].Selected) + '";';
    js := js + ' ' + HTMLName + 'Css[' + IntToStr(I) + '] = "' + Items[I].Css + '";';
    js := js + ' ' + HTMLName + 'CssSelected[' + IntToStr(I) + '] = "' + Items[I].CssSelected + '";';
  end;

  js := js + ' ' + HTMLName + 'CreateItems();';

  GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA['+ js +']]>');
end;

constructor TTIWCustomResponsiveList.Create(AOwner: TComponent);
var
  ri: TIWResponsiveLayoutItem;
begin
  inherited;
  FGetControlIDs := TStringList.Create;
  FAttributeNames := TStringList.Create;
  FAttributeValues := TStringList.Create;

  FBGColor := clNone;
  FBGImage := EmptyStr;
  FBorderColor := clNone;
  FDefaultItem := TIWItemStyle.Create(Self);
  FDefaultItem.Color := clWebWHITE;
  FDefaultItem.ColorTo := clWebAliceBlue;
  FDefaultItem.BorderColor := clWebGRAY;
  FDefaultItem.Font.Color := clWebDimGRAY;
  FDefaultItem.SelectColor := clWebAliceBlue;
  FDefaultItem.SelectColorTo := clWebLIGHTSTEELBLUE;
  FDefaultItem.SelectBorderColor := clWebSTEELBLUE;
  FDefaultItem.SelectFontColor := clWebBLACK;
  FFont := TIWFont.Create;
  FFont.FontName := 'Arial';
  FFont.Size := 14;
  FFont.Style := [fsBold];
  FItemHeight := 50;
  FItemIndex := -1;
  FItems := TIWListItems.Create(Self);
  FItemSize := isAuto;
  FItemStyles := TIWItemStyles.Create(Self);
  FItemWidth := 0;
  FLayout := llResponsive;
  FMultiSelect := false;
  FPadding := TIWPadding.Create(Self);
  FResponsiveLayout := TIWResponsiveLayoutItems.Create(Self);
  FSectionHeight := 50;
  FTitle := EmptyStr;

  ri := FResponsiveLayout.Add;
  ri.MinScreenWidth := 769;
  ri.Columns := 3;
  ri := FResponsiveLayout.Add;
  ri.MinScreenWidth := 1025;
  ri.Columns := 4;

  ResetScrollData;

  Enabled := true;
  Height := 320;
  Width := 400;
  //Align := alClient;
  {$IFNDEF TMSIW121}
  SetRenderSize(true);
  {$ENDIF}
end;

destructor TTIWCustomResponsiveList.Destroy;
begin
  inherited;
  FGetControlIDs.Free;
  FAttributeNames.Free;
  FAttributeValues.Free;

  FItems.Free;
  FItemStyles.Free;
  FDefaultItem.Free;
  FFont.Free;
  FPadding.Free;
  FResponsiveLayout.Free;
end;

procedure TTIWCustomResponsiveList.DoOnAsyncItemClick(AParams: TStringList);
begin
  if Assigned(OnAsyncItemClick) then
    OnAsyncItemClick(Self, AParams, FItemIndex);
end;

procedure TTIWCustomResponsiveList.AddExtraItems;
var
  I: Integer;
  ColumnCount: integer;
  MaxScreenWidth: integer;
begin
  if Layout = llFlow then
    exit;

  ColumnCount := 1;
  MaxScreenWidth := 0;

  if (ItemHeight > 0) then
  begin
    FItemsPerPage := (FWindowHeight Div (ItemHeight + Padding.Vertical));
    for I := 0 to ResponsiveLayout.Count - 1 do
    begin
      if (FWindowWidth >= ResponsiveLayout.Items[I].MinScreenWidth)
          and (MaxScreenWidth < ResponsiveLayout.Items[I].MinScreenWidth)
      then
      begin
        MaxScreenWidth := ResponsiveLayout.Items[I].MinScreenWidth;
        ColumnCount := ResponsiveLayout.Items[I].Columns;
      end;
    end;
    FItemsPerPage := FItemsPerPage * ColumnCount;
  end
  else
    FItemsPerPage := Items.Count;


  if FRenderedItemindex < FItemsPerPage - 1 then
  begin
    for I := FRenderedItemindex + 1 to (FRenderedItemindex + FItemsPerPage) do
    begin
      if I < Items.Count then
        AsyncItemAddInt(Items[I]);
    end;

    //Force IW resize after adding initial items
    //to avoid vertical scrollbar
    GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA[Body_OnResize();]]>');
  end;
end;

procedure TTIWCustomResponsiveList.DoOnAsyncControlEvent(AParams: TStringList);
begin
  if Assigned(OnAsyncControlEvent) then
    OnAsyncControlEvent(Self, AParams, FEventType, FControlID, FControlIndex);
end;

procedure TTIWCustomResponsiveList.DoOnAsyncExecuteJS(AParams: TStringList);
begin
  if Assigned(OnAsyncExecuteJS) then
    OnAsyncExecuteJS(Self, AParams, FExJSItemIndex, FExJSValue);
end;

procedure TTIWCustomResponsiveList.DoOnAsyncGetAttributes(AParams: TStringList);
begin
  if FGetCallType = 0 then
  begin
    if Assigned(OnAsyncGetAttributes) then
      OnAsyncGetAttributes(Self, AParams, FGetItemIndex, FGetControlIDs, FAttributeNames, FAttributeValues);
  end;
end;

procedure TTIWCustomResponsiveList.DoOnAsyncResize(AParams: TStringList);
begin
  //If window size increased
  //add extra items
  AddExtraItems;
  FScrollTotal := FScrollEnd;
  FScrollMax := 0;
end;

procedure TTIWCustomResponsiveList.DoOnAsyncScroll(AParams: TStringList);
var
  I: Integer;
  ColumnCount: integer;
  MaxScreenWidth: integer;
  FirstRender: boolean;
begin

  if Layout = llflow then
  begin
     if FRenderedItemIndex <> Items.Count - 1 then
     begin
       FItemsPerPage := Items.Count;
       AsyncUpdate;
       GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA[Body_OnResize();]]>');
     end;
  end
  else
  begin
    ColumnCount := 1;
    MaxScreenWidth := 0;

    if (ItemHeight > 0) then
    begin
      FItemsPerPage := (FWindowHeight Div (ItemHeight + Padding.Vertical));
      for I := 0 to ResponsiveLayout.Count - 1 do
      begin
        if (FWindowWidth >= ResponsiveLayout.Items[I].MinScreenWidth)
            and (MaxScreenWidth < ResponsiveLayout.Items[I].MinScreenWidth)
        then
        begin
          MaxScreenWidth := ResponsiveLayout.Items[I].MinScreenWidth;
          ColumnCount := ResponsiveLayout.Items[I].Columns;
        end;
      end;
      FItemsPerPage := FItemsPerPage * ColumnCount;
    end
    else
      FItemsPerPage := Items.Count;

    if ((FScrollTop > (FScrollMax + 10)) and (FScrollTop >= (FScrollEnd * 0.8)))
      or (FRenderedItemindex = -1)
      then
    begin
      if FRenderedItemIndex = -1 then
        FirstRender := true
      else
        FirstRender := false;
      if FRenderedItemindex >= 0 then
      begin
        FScrollMax := FScrollTop;

        if Assigned(OnAsyncScroll) then
          OnAsyncScroll(Self, AParams);
      end;

      for I := FRenderedItemindex + 1 to (FRenderedItemindex + FItemsPerPage) do
      begin
        if I < Items.Count then
          AsyncItemAddInt(Items[I]);
      end;

      //Force IW resize after adding initial items
      //to avoid vertical scrollbar
      if FirstRender then
        GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute('<![CDATA[Body_OnResize();]]>');

    end;
  end;
end;

procedure TTIWCustomResponsiveList.DoOnItemClick(ItemIndex: integer);
begin
 //Defined in descendant DB class
end;

procedure TTIWCustomResponsiveList.DoUpdateRecord(ItemIndex: integer;
  FieldNames, FieldValues: TStringList; CallType: integer);
begin
 //Defined in descendant DB class
end;

function TTIWCustomResponsiveList.GetTemplate: string;
begin
 //Defined in descendant DB class
 Result := '';
end;


procedure TTIWCustomResponsiveList.IWPaint;
var
  r: TRect;
  ypos, xpos, defheight: integer;
  stitle, stext: string;
  ABGColor: TIWColor;
  ABorderColor: TIWColor;
  I: Integer;
  J: Integer;

  procedure DrawBox(AText: string; AWidth, AHeight: integer;
    AColor, AColorTo, AFontColor, ABorderColor: TIWColor);
  begin
    r.Left := xpos;
    r.Right := xpos + AWidth;
    r.Top := ypos;
    r.Bottom := ypos + AHeight;

    DrawGradient(Canvas, AColor, AColorTo, 64, r, false);

    Canvas.Font.Name := DefaultItem.Font.FontName;
    Canvas.Font.Size := DefaultItem.Font.Size;
    Canvas.Font.Color := AFontColor;
    Canvas.Font.Style := DefaultItem.Font.Style;
    Canvas.Pen.Color := ABorderColor;
    Canvas.Pen.Width := DefaultItem.BorderWidth;

    Canvas.Brush.Style := bsClear;

    if DefaultItem.RoundedBorderRadius = 0 then
      Canvas.Rectangle(r)
    else
      Canvas.RoundRect(r, DefaultItem.RoundedBorderRadius * 2, DefaultItem.RoundedBorderRadius * 2);

//    Canvas.TextOut(xpos + 5, ypos + 5, AText);
    r.Left := r.Left + 5;
    r.Right := r.Right - 5;
    r.Top := r.Top + 5;
    r.Bottom := r.Bottom - 5;
    DrawText(Canvas.Handle,PChar(AText),Length(AText),R,DT_LEFT);
  end;
begin
  r := ClientRect;
  defheight := 50;

  ypos := Padding.Vertical;
  xpos := Padding.Horizontal * 2;
  stitle := Name;
  if Title <> '' then
    stitle := Title;
  ABgcolor := clWebWhite;
  if BGColor <> clNone then
    ABGColor := BGColor;
  ABorderColor := clWebLightGray;
  if BorderColor <> clNone then
    ABorderColor := BorderColor;

  Canvas.Font.Name := Font.FontName;
  Canvas.Font.Size := Font.Size;
  Canvas.Font.Color := Font.Color;
  Canvas.Font.Style := Font.Style;
  Canvas.Pen.Color := ABorderColor;
  Canvas.Pen.Width := 1;
  Canvas.Brush.Color := ABGColor;
  Canvas.Rectangle(0, 0, r.Right, r.Bottom);

  Canvas.Brush.Style := bsClear;
  Canvas.TextOut(Width div 2 - Canvas.TextWidth(stitle) div 2, ypos, stitle);

  ypos := ypos + Canvas.TextHeight(stitle) + (Padding.Vertical * 2);

  stext := GetTemplate;
  if stext = '' then
    stext := 'Default Item';

  DrawBox(stext, ((Width div 2) - (Padding.Horizontal * 3)), ItemHeight,
    DefaultItem.Color, DefaultItem.ColorTo,
    DefaultItem.Font.Color, DefaultItem.BorderColor);

  xpos := xpos + r.Right;

  stext := GetTemplate;
  if stext = '' then
    stext := 'Selected Item';

  DrawBox(stext, ((Width div 2) - (Padding.Horizontal * 3)), Itemheight,
    DefaultItem.SelectColor, DefaultItem.SelectColorTo,
    DefaultItem.SelectFontColor, DefaultItem.SelectBorderColor);

  ypos := ypos + ItemHeight + (Padding.Vertical * 2);
  xpos := Padding.Horizontal * 2;

  Canvas.Font.Name := Font.FontName;
  Canvas.Font.Size := Font.Size;
  Canvas.Font.Color := Font.Color;
  Canvas.Font.Style := Font.Style;
  Canvas.Pen.Color := ABorderColor;
  Canvas.Pen.Width := 1;
  Canvas.Brush.Color := ABGColor;

  stitle := 'Responsive Layout';
  Canvas.TextOut(Width div 2 - Canvas.TextWidth(stitle) div 2, ypos, stitle);

  ypos := ypos + Canvas.TextHeight(stitle) + (Padding.Vertical * 2);

  DrawBox('Item 1 of 1 (Default)', 320, defheight,
    DefaultItem.Color, DefaultItem.ColorTo,
    DefaultItem.Font.Color, DefaultItem.BorderColor);

  if ResponsiveLayout.Count > 0 then
  begin
    for I := 0 to ResponsiveLayout.Count - 1 do
    begin
      ypos := ypos + defheight + (Padding.Vertical * 2);
      xpos := Padding.Horizontal * 2;
      for J := 0 to ResponsiveLayout.Items[I].Columns - 1 do
      begin
        DrawBox('Item ' + IntToStr(J + 1) + ' of ' + IntToStr(ResponsiveLayout.Items[I].Columns)
           + ' (' + IntToStr(ResponsiveLayout.Items[I].MinScreenWidth) + 'px)',
          (ResponsiveLayout.Items[I].MinScreenWidth div ResponsiveLayout.Items[I].Columns), defheight,
          DefaultItem.Color, DefaultItem.ColorTo,
          DefaultItem.Font.Color, DefaultItem.BorderColor);
        xpos := xpos + (ResponsiveLayout.Items[I].MinScreenWidth div ResponsiveLayout.Items[I].Columns) + Padding.Horizontal * 2;
      end;
    end;
  end;
end;

procedure TTIWCustomResponsiveList.SetBGColor(const Value: TIWColor);
begin
  if FBGColor <> Value then
  begin
    FBGColor := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetBorderColor(const Value: TIWColor);
begin
  if FBorderColor <> Value then
  begin
    FBorderColor := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetDefaultItem(const Value: TIWItemStyle);
begin
  FDefaultItem.Assign(Value);
end;

procedure TTIWCustomResponsiveList.SetItemHeight(const Value: integer);
begin
  if FItemHeight <> Value then
  begin
    if Value < 0 then
      FItemHeight := 0
    else
      FItemHeight := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetItemIndex(const Value: integer);
begin
  if FItemIndex <> Value then
  begin
    if Value < -1 then
      FItemIndex := -1
    else
      FItemIndex := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetItemWidth(const Value: integer);
begin
  if FItemWidth <> Value then
  begin
    if Value < 0 then
      FItemWidth := 0
    else
      FItemWidth := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetLayout(const Value: TIWListLayout);
begin
  if FLayout <> Value then
    FLayout := Value;
end;

procedure TTIWCustomResponsiveList.SetSectionHeight(const Value: integer);
begin
  if FSectionHeight <> Value then
  begin
    if Value < 0 then
      FSectionHeight := 0
    else
      FSectionHeight := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetTitle(const Value: string);
begin
  if FTitle <> Value then
  begin
    FTitle := Value;
    Invalidate;
  end;
end;

procedure TTIWCustomResponsiveList.SetValue (const value: string);
var
  A, B: TStringList;
  I: Integer;
begin
  inherited;

  if value <> '' then
  begin

    if Pos('[exjs]', value) > 0 then
    begin
     A := TStringList.Create;
     try
       Split('~', value, A);
       FExJSItemIndex := StrToInt(A[1]);
       FExJSValue := A[2];
     finally
      A.Free;
     end;
    end
    else if Pos('[getattrs]', value) > 0 then
    begin
     A := TStringList.Create;
     try
       Split('~', value, A);
       FGetControlID := A[1];
       FGetItemIndex := StrToInt(A[2]);
       FAttributeName := A[3];
       FAttributeValue := A[4];
       FGetCallType := StrToInt(A[5]);

       FGetControlIDs.StrictDelimiter := true;
       FGetControlIDs.Delimiter := '^';
       FGetControlIDs.DelimitedText  := A[1];

       FAttributeNames.StrictDelimiter := true;
       FAttributeNames.Delimiter := '^';
       FAttributeNames.DelimitedText := A[3];

       FAttributeValues.StrictDelimiter := true;
       FAttributeValues.Delimiter := '^';
       FAttributeValues.DelimitedText := A[4];

       DoUpdateRecord(FGetItemIndex, FGetControlIDs, FAttributeValues, FGetCallType);
     finally
      A.Free;
     end;
    end
    else if Pos('~', value) > 0 then
    begin
     A := TStringList.Create;
     try
       Split('~', value, A);
       FEventType := A[0];
       FControlID := A[1];
       FControlIndex := StrToInt(A[2]);
     finally
      A.Free;
     end;
    end
    else if Pos('^', value) > 0 then
    begin
     A := TStringList.Create;
     try
       IWTMSBase.Split('^', value, A);

       if A.Count > 0 then
       begin
        if not (A[0] = '') then
        begin
          if Pos('|', A[0]) > 0 then
          begin
            FItemIndex := StrToInt(A[1]);
            DoOnItemClick(FItemIndex);

            B := TStringList.Create;
            try
              Split('|', A[0], B);

              for I := 0 to B.Count - 1 do
              begin
                if Items.Count > I then
                begin
                  if B[I] = '-1' then
                    Items[I].Selected := true
                  else
                    Items[I].Selected := false;
                end;
              end;
            finally
              B.Free;
            end;
          end
          else
          begin
            FItemIndex := StrToInt(A[0]);
            DoOnItemClick(FItemIndex);
          end;
        end;
       end;
     finally
      A.Free;
     end;
    end
    else if Pos(':', value) > 0 then
    begin
     A := TStringList.Create;
     try
       IWTMSBase.Split(':', value, A);
       FScrollTop := StrToInt(A[0]);
       FScrollEnd := StrToInt(A[1]);
       FWindowHeight := StrToInt(A[2]);
       FWindowWidth := StrToInt(A[3]);
     finally
      A.Free;
     end;
    end
    else
      FScrollTop := StrToInt(value);
  end;
end;

procedure TTIWCustomResponsiveList.Submit(const AValue: string);
begin
  inherited;

  if Assigned(OnItemClick) then
    OnItemClick(Self, FItemIndex);
end;

function TTIWCustomResponsiveList.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
var
  htmlres, submitclick: string;
  ajaxcall, ajaxscroll, ajaxresize, ajaxcallcontrol, ajaxgetattr, ajaxjs: string;
  I: Integer;
begin
  ResetScrollData;

  //JS Init
  TIWComponent40Context(AContext).AddToInitProc(HTMLName + 'ScrollInit();');

  //------------
  //Events
  //------------
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncItemClick', DoOnAsyncItemClick);
  ajaxcall := 'processAjaxEvent(''onItemClick'', '
    + HTMLControlImplementation.IWCLName
    + ',''' + HTMLName + '.' + 'DoOnAsyncItemClick' + ''','
    + 'true' + ', null, '
    + 'true' + ');';

  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncScroll', DoOnAsyncScroll);
  ajaxscroll := 'processAjaxEvent(''onAsyncScroll'', '
    + HTMLControlImplementation.IWCLName
    + ',''' + HTMLName + '.' + 'DoOnAsyncScroll' + ''','
    + 'true' + ', null, '
    + 'true' + ');';

  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncResize', DoOnAsyncResize);
  ajaxresize := 'processAjaxEvent(''onAsyncResize'', '
    + HTMLControlImplementation.IWCLName
    + ',''' + HTMLName + '.' + 'DoOnAsyncResize' + ''','
    + 'true' + ', null, '
    + 'true' + ');';

  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncControlEvent', DoOnAsyncControlEvent);
  if Assigned(FOnAsyncControlEvent) then
  begin
    ajaxcallcontrol := 'processAjaxEvent(''onAsyncControlEvent'', '
      + HTMLControlImplementation.IWCLName
      + ',''' + HTMLName + '.' + 'DoOnAsyncControlEvent' + ''','
      + 'true' + ', null, '
      + 'true' + ');';
  end;

  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncGetAttributes', DoOnAsyncGetAttributes);
  ajaxgetattr := 'processAjaxEvent(''onAsyncGetAttributes'', '
    + HTMLControlImplementation.IWCLName
    + ',''' + HTMLName + '.' + 'DoOnAsyncGetAttributes' + ''','
    + 'true' + ', null, '
    + 'true' + ');';

  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncExecuteJS', DoOnAsyncExecuteJS);
  if Assigned(FOnAsyncExecuteJS) then
  begin
    ajaxjs := 'processAjaxEvent(''onAsyncExecuteJS'', '
      + HTMLControlImplementation.IWCLName
      + ',''' + HTMLName + '.' + 'DoOnAsyncExecuteJS' + ''','
      + 'true' + ', null, '
      + 'true' + ');';
  end;

  if Assigned(OnItemClick) then
  begin
    submitclick := '    return SubmitClick("' + HTMLName + '", "", false);'#13;
    ajaxcall := '';
  end;

  //------------
  //JavaScript
  //------------
  htmlres := '<script>'#13
    + ' var ' + HTMLName + 'enabled = ' + BoolToStr(Enabled) + ';'#13
    + ' var ' + HTMLName + 'ItemIndex = ' + IntToStr(ItemIndex) + ';'#13
    + ' var ' + HTMLName + 'MultiSelect = ' + BoolToStr(MultiSelect) + ';'#13
    + ' var ' + HTMLName + 'count = 0;'#13
    + ' var ' + HTMLName + 'Styles = new Array();'#13
    + ' var ' + HTMLName + 'Items = new Array();'#13
    + ' var ' + HTMLName + 'Sections = new Array();'#13
    + ' var ' + HTMLName + 'Selected = new Array();'#13
    + ' var ' + HTMLName + 'Css = new Array();'#13
    + ' var ' + HTMLName + 'CssSelected = new Array();'#13
    ;

  htmlres := htmlres + 'function ' + HTMLName + 'GetControl(index, id) {'
    + ' item = document.getElementById("' + HTMLName + 'item" + index);'#13
    + ' if (item) {'#13
    + '  arel = item.getElementsByTagName("*");'#13
    + '  for (ic = 0; ic < arel.length; ic++) {'#13
    + '   if (arel[ic].id == id)'#13
    + '    return arel[ic];'#13
    + '  }'#13
    + ' }'#13
    + '}'#13;

  htmlres := htmlres + 'function ' + HTMLName + 'ExecuteAsync(itemIndex, itemValue) {'
    + ' setTimeout(function ' + HTMLName + 'TriggerAsync() {'
    + ' FindElem("' + HTMLName + '").value = "[exjs]~" + itemIndex + "~" + itemValue;'
    + ajaxjs
    + '}, 10);'#13
    + '}'#13;

  htmlres := htmlres + 'function ' + HTMLName + 'GetAttributes(itemIndex, controlID, attrName, callType) {'#13
    + ' var arCtrl = controlID.split("^");'#13
    + ' var arAttr = attrName.split("^");'#13
    + ' var attrValue = "";'#13
    + ' for (i = 0; i < arCtrl.length; i++) {'#13
    + '  el = ' + HTMLName + 'GetControl(itemIndex, arCtrl[i]);'#13
    + '  if (el){'#13
    + '   if (i > 0)'#13
    + '    attrValue += "^";'#13
    + '   attrValue += el[arAttr[i]];'#13
    + '  }'#13
    + ' }'#13
    + ' if (attrValue != "") {'#13
    + ' FindElem("' + HTMLName + '").value = "[getattrs]~" + controlID + "~" + itemIndex + "~" + attrName + "~" + attrValue + "~" + callType;'#13
    + ajaxgetattr
    + ' }'#13
    + '}'#13;

  //Continuous Scroll
  htmlres := htmlres + 'function ' + HTMLName + 'GetParentScroller() {'#13
    + '  el = document.getElementById("' + HTMLName + '");'
    + '  sel = null;'#13
    + '  if (el){'#13
    + '    sel = el.parentNode;'#13
//    + '    while ((sel.tagName != "DIV") && ((sel.tagName != "BODY")))'#13
    + '    while (sel.tagName != "BODY")'#13
    + '      sel = sel.parentNode;'#13
    + '  }'#13
    + '  return sel;'#13
    + '}'#13;

  htmlres := htmlres + 'function ' + HTMLName + 'ScrollInit() {'#13
//    + '  sel = ' + HTMLName + 'GetParentScroller();'#13
//    + '  if (sel){'#13
//    + '    if (sel.tagName == "BODY") {'#13
//    + '      window.onscroll = ' + HTMLName + 'Scroll;'#13
    + '      window.addEventListener("scroll", ' + HTMLName + 'Scroll);'#13
    + '      window.addEventListener("resize", ' + HTMLName + 'Resize);'#13
//    + '    } else {'#13
//    + '      sel.onscroll = ' + HTMLName + 'Scroll;'#13
//    + '    }'#13
//    + '  }'#13
    + '  ' + HTMLName + 'Scroll();'#13
    + '}'#13;

 htmlres := htmlres + 'function ' + HTMLName + 'Resize() {'#13
    + '  scrollTop = 0;'#13
    + '  scrollMax = 0;'#13
    + '  windowHeight = 0;'#13
    + '  windowWidth = 0;'#13
    + '  sel = ' + HTMLName + 'GetParentScroller();'#13
    + '  if (sel){'#13
    + '    if (sel.tagName == "BODY"){'#13;

  if (brChrome <> GetTMSBrowser(AContext)) and (brSafari <> GetTMSBrowser(AContext)) then
    htmlres := htmlres
    + '      if (document.compatMode=="CSS1Compat") {'#13
    + '        scrollTop = document.documentElement.scrollTop;'#13
    + '        scrollMax = (document.documentElement.scrollHeight - document.documentElement.clientHeight);'#13
    + '        windowHeight = document.documentElement.clientHeight;'#13
    + '        windowWidth = document.documentElement.clientWidth;'#13
    + '      } else {'#13
    + '        scrollTop = document.body.scrollTop;'#13
    + '        scrollMax = (document.body.scrollHeight - document.body.clientHeight);'#13
    + '        windowHeight = document.body.clientHeight;'#13
    + '        windowWidth = document.body.clientHeight;'#13
    + '      }'#13
  else
    htmlres := htmlres
    + '      scrollTop = sel.scrollTop;'#13
    + '      scrollMax = (sel.scrollHeight - window.innerHeight);'#13
    + '      windowHeight = window.innerHeight;'#13
    + '      windowWidth = window.innerWidth;'#13
    ;

  htmlres := htmlres
    + '    } else {'#13
    + '      scrollTop = sel.scrollTop;'#13
    + '      scrollMax = (sel.scrollHeight - sel.offsetHeight);'#13
    + '      windowHeight = sel.offsetHeight;'#13
    + '      windowWidth = sel.offsetWidth;'#13
    + '    }'#13
    + '  }'#13
    + '  FindElem("' + HTMLName + '").value = scrollTop + ":" + scrollMax + ":" + windowHeight + ":" + windowWidth;'#13
    + ajaxresize
    + '}'#13;

  htmlres := htmlres + 'function ' + HTMLName + 'Scroll() {'#13
    + '  scrollTop = 0;'#13
    + '  scrollMax = 0;'#13
    + '  windowHeight = 0;'#13
    + '  windowWidth = 0;'#13
    + '  sel = ' + HTMLName + 'GetParentScroller();'#13
    + '  if (sel){'#13
    + '    if (sel.tagName == "BODY"){'#13;

  if (brChrome <> GetTMSBrowser(AContext)) and (brSafari <> GetTMSBrowser(AContext)) then
    htmlres := htmlres
    + '      if (document.compatMode=="CSS1Compat") {'#13
    + '        scrollTop = document.documentElement.scrollTop;'#13
    + '        scrollMax = (document.documentElement.scrollHeight - document.documentElement.clientHeight);'#13
    + '        windowHeight = document.documentElement.clientHeight;'#13
    + '        windowWidth = document.documentElement.clientWidth;'#13
    + '      } else {'#13
    + '        scrollTop = document.body.scrollTop;'#13
    + '        scrollMax = (document.body.scrollHeight - document.body.clientHeight);'#13
    + '        windowHeight = document.body.clientHeight;'#13
    + '        windowWidth = document.body.clientHeight;'#13
    + '      }'#13
  else
    htmlres := htmlres
    + '      scrollTop = sel.scrollTop;'#13
    + '      scrollMax = (sel.scrollHeight - window.innerHeight);'#13
    + '      windowHeight = window.innerHeight;'#13
    + '      windowWidth = window.innerWidth;'#13
    ;

  htmlres := htmlres
    + '    } else {'#13
    + '      scrollTop = sel.scrollTop;'#13
    + '      scrollMax = (sel.scrollHeight - sel.offsetHeight);'#13
    + '      windowHeight = sel.offsetHeight;'#13
    + '      windowWidth = sel.offsetWidth;'#13
    + '    }'#13
    + '  }'#13
    + '  FindElem("' + HTMLName + '").value = scrollTop + ":" + scrollMax + ":" + windowHeight + ":" + windowWidth;'#13
    + ajaxscroll
    + '}'#13;
  //End Continuous Scroll

  htmlres := htmlres
    + ' function ' + HTMLName + 'Changed(){'#13
    + '  if (!containsName("'+HTMLName+'")) {'#13
    + ' 	 window.ChangedControls += "'+HTMLName+',";'#13
    + '  }'#13
    + ' }'#13

    + ' function ' + HTMLName + 'GetClassName(index){'#13
    + '  if (' + HTMLName + 'Css[index] != "")'#13
    + '   css = ' + HTMLName + 'Css[index];'#13
    + '  else {'#13
    + '   css = "' + HTMLName + 'item";'#13
    + '   if (' + HTMLName + 'Styles[index] != "")'#13
    + '    css = css + " " + css + ' + HTMLName + 'Styles[index];'#13
    + '  }'#13
    + '  if ((' + HTMLName + 'Selected[index] != 0) || (' + HTMLName + 'ItemIndex == index)) {'#13
    + '   if (' + HTMLName + 'CssSelected[index] != "")'#13
    + '    css = css + " " + ' + HTMLName + 'CssSelected[index];'#13
    + '   else {'#13
    + '    css = css + " ' + HTMLName + 'itemselect";'#13
    + '    if (' + HTMLName + 'Styles[index] != "")'#13
    + '     css = css + " " + css + ' + HTMLName + 'Styles[index];'#13
    + '   }'#13
    + '  }'#13
    + '  return css;'#13
    + ' }'#13

    + ' function ' + HTMLName + 'SelectItem(index){'#13

    + HTMLName + 'Changed();'#13

    + '  var ctrl = null;'#13

    + '  if (' + HTMLName + 'MultiSelect != "0") {'#13

    + '   ctrl = document.getElementById("'+HTMLName+'item" + index);'#13
    + '   if (ctrl) {'#13
    + '    if (' + HTMLName + 'Selected[index] == 0) {'#13
    + '      ' + HTMLName + 'Selected[index] = -1;'#13
    + '    } else { '#13
    + '      ' + HTMLName + 'Selected[index] = 0;'#13
    + '    }'#13
    + '    ctrl.className = ' + HTMLName + 'GetClassName(index);'#13
    + '   }'#13

    + '  } else {'#13

    + '   prevIndex = ' + HTMLName + 'ItemIndex;'#13
    + '   ' + HTMLName + 'ItemIndex = index;'#13
    + '   ' + HTMLName + 'Selected[prevIndex] = 0;'#13
    + '   ' + HTMLName + 'Selected[index] = -1;'#13

    + '   ctrl = document.getElementById("'+HTMLName+'item" + prevIndex);'#13
    + '   if (ctrl)'#13
    + '    ctrl.className = ' + HTMLName + 'GetClassName(prevIndex);'#13

    + '   ctrl = document.getElementById("'+HTMLName+'item" + index);'#13
    + '   if (ctrl)'#13
    + '    ctrl.className = ' + HTMLName + 'GetClassName(index);'#13

    + '  }'#13
    + ' }'#13

    + ' function ' + HTMLName + 'Click(e, index){'#13

    + '  if (' + HTMLName + 'MultiSelect != "0") {'#13
    + '   if (e == null)'#13
    + '     e = window.event;'#13
    + '   var elem = e.target != null ? e.target : e.srcElement;'#13
    + '   if (elem) {'#13
    + '    if ((elem.tagName == "INPUT") || (elem.tagName == "SELECT") || (elem.tagName == "TEXTAREA"))'#13
    + '     return;'#13
    + '   }'#13
    + '  }'#13

    + '  if (' + HTMLName + 'enabled == "0")'#13
    + '   return;'#13

    + '  if (' + HTMLName + 'Sections[index] != "0")'#13
    + '   return;'#13

    + '  ' + HTMLName + 'SelectItem(index);'#13
    + '  if (' + HTMLName + 'MultiSelect != "0") {'#13
    + '   selvalues = "";'#13
    + '   for (i = 0; i < ' + HTMLName + 'Selected.length; i++)'#13
    + '    selvalues = selvalues + ' + HTMLName + 'Selected[i] + "|";'#13
    + '   FindElem("'+HTMLName+'_INPUT").value = selvalues + "^" + index;'#13
    + '  } else'#13
    + '   FindElem("'+HTMLName+'_INPUT").value = index + "^";'#13
    + '  ' + ajaxcall + #13
    + '  ' + submitclick + #13
    + '}'#13

    + 'function ' + HTMLName + 'ClearItems(){'#13
    + ' items = document.getElementById("' + HTMLName + 'container");'#13
    + ' if (items) {'#13
    + '  items.innerHTML = "";'#13
    + ' ' + HTMLName + 'count = 0;'#13
    + ' ' + HTMLName + 'Items.length = 0;'#13
    + ' ' + HTMLName + 'Styles.length = 0;'#13
    + ' ' + HTMLName + 'Selected.length = 0;'#13
    + ' ' + HTMLName + 'Sections.length = 0;'#13
    + ' ' + HTMLName + 'Css.length = 0;'#13
    + ' ' + HTMLName + 'CssSelected.length = 0;'#13
    + ' }'#13
    + '}'#13

    + ' function ' + HTMLName + 'CreateItems(){'#13
    + ' var content = "";'#13
    + ' for (i = 0; i < ' + HTMLName + 'Items.length; i++)'#13
    + ' {'#13

    + HTMLName + 'count += 1;'#13

    + ' classname = ' + HTMLName + 'GetClassName(i);'#13

    + ' if (' + HTMLName + 'Sections[i] != "0")'#13
    + '  cellclass = "' + HTMLName + 'sectioncell";'#13
    + ' else'#13
    + '  cellclass = "' + HTMLName + 'cell";'#13

    + ' content += "<div class=" + cellclass + " '
    + 'id=''' + HTMLName + 'cell" + i + "''>'
    + '<div class=''" + classname + "'' '
    + 'id=''' + HTMLName + 'item" + i + "'' '
    + 'onClick=''' + HTMLName + 'Click(event, " + i + ");''>'
    + '" + ' + HTMLName + 'Items[i] + "'
    + '</div>'
    + '</div>";'#13

    + ' }'#13
    + ' items = document.getElementById("' + HTMLName + 'container");'#13
    + ' if (items)'#13
    + '  items.innerHTML = items.innerHTML + content;'#13
    + '}'#13

    + ' function ' + HTMLName + 'AddItems(content, count){'#13
    + HTMLName + 'count += count;'#13
    + ' items = document.getElementById("' + HTMLName + 'container");'#13
    + ' if (items)'#13
    + '  items.innerHTML = items.innerHTML + content;'#13
    + '}'#13

    + ' function ' + HTMLName + 'RenderItem(content, style, section, selected, cssclass, cssselected){'#13
    + ' var index = ' + HTMLName + 'count;'#13

    + ' ' + HTMLName + 'Items[index] = content;'#13
    + ' ' + HTMLName + 'Styles[index] = style;'#13
    + ' ' + HTMLName + 'Selected[index] = selected;'#13
    + ' ' + HTMLName + 'Sections[index] = section;'#13
    + ' ' + HTMLName + 'Css[index] = cssclass;'#13
    + ' ' + HTMLName + 'CssSelected[index] = cssselected;'#13

    + ' classname = ' + HTMLName + 'GetClassName(index);'#13

    + ' if ('+ HTMLName +'Sections[index] != "0")'#13
    + '  cellclass = "' + HTMLName + 'sectioncell";'#13
    + ' else'#13
    + '  cellclass = "' + HTMLName + 'cell";'#13

    + ' newitem = "<div class=" + cellclass + " '
    + 'id=''' + HTMLName + 'cell" + index + "''>'
    + '<div class=''" + classname + "'' '
    + 'id=''' + HTMLName + 'item" + index + "'' '
    + 'onClick=''' + HTMLName + 'Click(event, " + index + ");''>'
    + '" + content + "'
    + '</div>'
    + '</div>";'#13

    + ' ' + HTMLName + 'AddItems(newitem, 1);'#13
    + '}'#13

    + 'function ' + HTMLName + 'AsyncItemUpdate(index, caption, style, section, selected){ '#13

    + ' ' + HTMLName + 'Styles[index] = style;'#13
    + ' ' + HTMLName + 'Selected[index] = selected;'#13
    + ' ' + HTMLName + 'Sections[index] = section;'#13

    //If updated item is selected and
    //MultiSelect is false then
    //deselect previously selected item
    + ' if (' + HTMLName + 'MultiSelect == "0") {'#13
    + '  if (' + HTMLName + 'Selected[index] == -1)'#13
    + '   ' + HTMLName + 'SelectItem(index);'#13
    + ' }'#13

    + ' var item = document.getElementById("' + HTMLName + 'item" + index);'#13
    + ' if (item) {'#13
    + '  item.className = ' + HTMLName + 'GetClassName(index);'#13
    + '  item.innerHTML = caption;'#13
    + ' }'#13
    + '}'#13

    + 'function ' + HTMLName + 'RenderTitle(title) {'#13
    + ' items = document.getElementById("' + HTMLName + 'container");'#13
    + ' if (items) {'#13
    + '  content = "<div id=''' + HTMLName + 'title''>" + title + "</div>";'#13
    + '  items.innerHTML = content;'#13
    + ' }'#13
    + '}'#13

    + 'function ' + HTMLName + 'ControlEventHandler(e, EventType) {'#13
    + '  if (e == null)'#13
    + '    e = window.event;'#13
    + '  e.stopPropagation();'#13
    + '  var elem = e.target != null ? e.target : e.srcElement;'#13
    + '  var elemid = elem.id;'#13
    + '  var elparent = elem.parentElement;'#13
    + '  do {'#13
    + '   if (elparent.className == "' + HTMLName + 'cell") {'#13
    + '    elIndex = elparent.id.replace("' + HTMLName + 'cell", "");'#13
    + '    break;'#13
    + '   }'#13
    + '  } while (elparent = elparent.parentElement)'#13
    + '  FindElem("' + HTMLName + '").value = EventType + "~" + elem.id + "~" + elIndex;'#13
    + ajaxcallcontrol
    + '}'#13

    + HTMLName + 'Changed();'#13

    + ClientScript

    + '</script>'#13;

  //------------
  //CSS
  //------------
  htmlres := htmlres
    + '<style>'#13

    + '	#' + HTMLName + ''#13
    + '	{'#13;

  htmlres := htmlres
    + '		box-sizing: border-box;'#13
    + '   outline: none;'#13
    + '	}'#13

    + '	.' + HTMLName + 'container'#13
    + '	{'#13;

  if not (BGImage = EmptyStr) then
    htmlres := htmlres + '  background-image: url("' + BGImage + '");'#13
  else if not (BGColor = clNone) then
    htmlres := htmlres
      + '   background-color: ' + ColorToRGBString(BGColor) + ';'#13;

  if not (BorderColor = clNone) then
    htmlres := htmlres
      + '   border: 1px solid ' + ColorToRGBString(BorderColor) + ';'#13;

  if Layout = llResponsive then
  begin
    htmlres := htmlres
      + '		display: -webkit-flex;     /* NEW - Chrome */'#13
      + '		display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */'#13

      + '		-webkit-flex-flow: row wrap;'#13
      + '		flex-flow: row wrap;'#13
  end
  else
  begin
    htmlres := htmlres
      + '		display: inline-block;'#13
  end;

  htmlres := htmlres
    + '		padding-top: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-bottom: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-left: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '		padding-right: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '	}'#13;

  htmlres := htmlres
    + '	#' + HTMLName + 'title'#13
    + '	{'#13
    + '   width: 100%;'#13
    + '   text-align:center;'#13
    +   Font.FontToStringStyle(AContext.WebApplication.Browser) + #13
    + '	}'#13;

  htmlres := htmlres
    + '	.' + HTMLName + 'sectioncell'#13
    + '	{'#13;

  htmlres := htmlres + '   width: 100%;'#13;

  htmlres := htmlres
    + '		box-sizing: border-box;'#13
    + '		padding-top: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-bottom: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-left: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '		padding-right: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '	}'#13

    + '	.' + HTMLName + 'cell'#13
    + '	{'#13;

  if Layout = llResponsive then
    htmlres := htmlres + '   width: 100%;'#13
  else
    htmlres := htmlres + '   float: left;'#13;

  htmlres := htmlres
    + '		box-sizing: border-box;'#13
    + '		padding-top: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-bottom: ' + IntToStr(Padding.Horizontal) + 'px;'#13
    + '		padding-left: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '		padding-right: ' + IntToStr(Padding.Vertical) + 'px;'#13
    + '	}'#13

    + '	.' + HTMLName + 'cell .' + HTMLName + 'item'#13
    + '	{'#13
    ;

  if ItemHeight > 0 then
  begin
    if ItemSize = isAuto then
      htmlres := htmlres
      + '   min-height: ' + IntToStr(ItemHeight) + 'px;'#13
    else
      htmlres := htmlres
      + '   height: ' + IntToStr(ItemHeight) + 'px;'#13;
  end;

  htmlres := htmlres
    + '	}'#13

    + '	.' + HTMLName + 'sectioncell .' + HTMLName + 'item'#13
    + '	{'#13
    ;

  if SectionHeight > 0 then
  begin
    if ItemSize = isAuto then
      htmlres := htmlres
      + '   min-height: ' + IntToStr(SectionHeight) + 'px;'#13
    else
      htmlres := htmlres
      + '   height: ' + IntToStr(SectionHeight) + 'px;'#13;
  end;

  htmlres := htmlres
    + '	}'#13

    + '	.' + HTMLName + 'item'#13
    + '	{'#13
    + '   cursor:default;'#13
    + '		box-sizing: border-box;'#13
    + '   padding: 10px;'#13
    + '   overflow: hidden;'#13
	  + '   -webkit-border-radius: ' + IntToStr(DefaultItem.RoundedBorderRadius) + 'px;'#13
	  + '   -moz-border-radius: ' + IntToStr(DefaultItem.RoundedBorderRadius) + 'px;'#13
    + '   border-radius: ' + IntToStr(DefaultItem.RoundedBorderRadius) + 'px;'#13
    +   DefaultItem.Font.FontToStringStyle(AContext.WebApplication.Browser) + #13
    ;

  if ItemWidth > 0 then
  begin
    if ItemSize = isAuto then
      htmlres := htmlres
        + '   min-width: ' + IntToStr(ItemWidth) + 'px;'#13
    else
      htmlres := htmlres
        + '   width: ' + IntToStr(ItemWidth) + 'px;'#13
//      + '   overflow: hidden;'#13
      ;
  end;

  if ItemHeight > 0 then
  begin
    if ItemSize = isAuto then
      htmlres := htmlres
      + '   min-height: ' + IntToStr(ItemHeight) + 'px;'#13
    else
      htmlres := htmlres
      + '   height: ' + IntToStr(ItemHeight) + 'px;'#13;
  end;

  if not (DefaultItem.Color = clNone) then
    htmlres := htmlres
     + GradientStyle(DefaultItem.Color, DefaultItem.Color, DefaultItem.ColorTo, clNone, gdVertical, AContext, true);

  if not (DefaultItem.BorderColor = clNone) then
    htmlres := htmlres
    + '   border: ' + IntToStr(DefaultItem.BorderWidth) +'px solid ' + ColorToRGBString(DefaultItem.BorderColor) + ';'#13;

  if not (DefaultItem.Font.Color = clNone) then
    htmlres := htmlres
    + '   color: ' + ColorToRGBString(DefaultItem.Font.Color) + ';'#13;

  if not (DefaultItem.BackgroundImage = '') then
  begin
    htmlres := htmlres + 'background-image: url("' + DefaultItem.BackgroundImage + '");'#13;
    htmlres := htmlres + 'background-size: 100% 100%;'#13;
  end;

  htmlres := htmlres
    + '	}'#13

    + '	.' + HTMLName + 'itemselect'#13
    + '	{'#13;

  if not (DefaultItem.SelectColor = clNone) then
    htmlres := htmlres
     + GradientStyle(DefaultItem.SelectColor, DefaultItem.SelectColor, DefaultItem.SelectColorTo, clNone, gdVertical, AContext, true);

  if not (DefaultItem.SelectBorderColor = clNone) then
    htmlres := htmlres
    + '   border: ' + IntToStr(DefaultItem.BorderWidth) + 'px solid ' + ColorToRGBString(DefaultItem.SelectBorderColor) + ';'#13;

  if not (DefaultItem.SelectFontColor = clNone) then
    htmlres := htmlres
    + '   color: ' + ColorToRGBString(DefaultItem.SelectFontColor) + ';'#13;

  if not (DefaultItem.SelectBackgroundImage = '') then
  begin
    htmlres := htmlres + 'background-image: url("' + DefaultItem.SelectBackgroundImage + '");'#13;
    htmlres := htmlres + 'background-size: 100% 100%;'#13;
  end;

  htmlres := htmlres
  + '	}'#13;

  for I := 0 to ItemStyles.Count - 1 do
  begin
    htmlres := htmlres
    + '	.' + HTMLName + 'item' + ItemStyles[I].Name + ''#13
    + '	{'#13;

    if not (ItemStyles[I].ItemStyle.Color = clNone) then
      htmlres := htmlres
       + GradientStyle(ItemStyles[I].ItemStyle.Color, ItemStyles[I].ItemStyle.Color, ItemStyles[I].ItemStyle.ColorTo, clNone, gdVertical, AContext, true);

    if not (ItemStyles[I].ItemStyle.BorderColor = clNone) then
      htmlres := htmlres
      + '   border: ' + IntToStr(ItemStyles[I].ItemStyle.BorderWidth) + 'px solid ' + ColorToRGBString(ItemStyles[I].ItemStyle.BorderColor) + ';'#13;

    htmlres := htmlres
      +   ItemStyles[I].ItemStyle.Font.FontToStringStyle(AContext.WebApplication.Browser) + #13;

    if ItemStyles[I].ItemStyle.RoundedBorderRadius <> 0 then
    begin
      htmlres := htmlres
      + '   -webkit-border-radius: ' + IntToStr(ItemStyles[I].ItemStyle.RoundedBorderRadius) + 'px;'#13
      + '   -moz-border-radius: ' + IntToStr(ItemStyles[I].ItemStyle.RoundedBorderRadius) + 'px;'#13
      + '   border-radius: ' + IntToStr(ItemStyles[I].ItemStyle.RoundedBorderRadius) + 'px;'#13
    end;

    if not (ItemStyles[I].ItemStyle.BackgroundImage = '') then
    begin
      htmlres := htmlres + 'background-image: url("' + ItemStyles[I].ItemStyle.BackgroundImage + '");'#13;
      htmlres := htmlres + 'background-repeat: no-repeat;'#13;
    end;

    htmlres := htmlres
    + '	}'#13

    + '	.' + HTMLName + 'itemselect' + ItemStyles[I].Name + ''#13
    + '	{'#13;

    if not (ItemStyles[I].ItemStyle.SelectColor = clNone) then
      htmlres := htmlres
       + GradientStyle(ItemStyles[I].ItemStyle.SelectColor, ItemStyles[I].ItemStyle.SelectColor, ItemStyles[I].ItemStyle.SelectColorTo, clNone, gdVertical, AContext, true);

    if not (ItemStyles[I].ItemStyle.SelectBorderColor = clNone) then
      htmlres := htmlres
      + '   border: 1px solid ' + ColorToRGBString(ItemStyles[I].ItemStyle.SelectBorderColor) + ';'#13;

    if not (ItemStyles[I].ItemStyle.SelectFontColor = clNone) then
      htmlres := htmlres
      + '   color: ' + ColorToRGBString(ItemStyles[I].ItemStyle.SelectFontColor) + ';'#13;

    htmlres := htmlres
    + '	}'#13;
  end;

  if Layout = llResponsive then
  begin
    for I := 0 to ResponsiveLayout.Count - 1 do
    begin
      if ResponsiveLayout[I].Columns > 0 then
      begin
        htmlres := htmlres
          + '	@media (min-width: ' + IntToStr(ResponsiveLayout[I].MinScreenWidth) + 'px)'#13
          + '	{'#13
          + '		.' + HTMLName + 'cell'#13
          + '		{'#13
          + '			width: ' + StringReplace(FloatToStr(100 / ResponsiveLayout[I].Columns), ',', '.', []) + '%;'#13
          + '		}'#13
          + '	}'#13
          ;
      end;
    end;
  end;
  htmlres := htmlres + '</style>'#13;

  //------------
  //HTML
  //------------
  htmlres := htmlres
  + '<div id="' + HTMLName + 'container" class="' + HTMLName + 'container">'#13
  + '<div id="' + HTMLName + 'title">' + Title + '</div>'#13;

  htmlres := htmlres + '</div>'#13;

  Result := TIWHTMLTag.CreateTag('DIV');
  Result.Contents.AddText(htmlres);

  with Result.Contents.AddTag('INPUT') do
  begin
    AddStringParam('TYPE','hidden');
//    AddStringParam('TYPE','text');
    AddStringParam('NAME',HTMLName+'');
    AddStringParam('ID',HTMLName+'_INPUT');
  end;
end;

procedure TTIWCustomResponsiveList.ResetScrollData;
begin
  FScrollTop := 0;
  FScrollEnd := 0;
  FScrollMax := 0;
  FScrollTotal := 0;
  //FWindowHeight := 0;
  //FWindowWidth := 0;
  //FItemsPerPage := 0;
  FRenderedItemindex := -1;
end;

{ TIWItemStyle }

procedure TIWItemStyle.Assign(Source: TPersistent);
begin
  if (Source is TIWItemStyle) then
  begin
    FBackgroundImage := (Source as TIWItemStyle).BackgroundImage;
    FBorderColor := (Source as TIWItemStyle).BorderColor;
    FBorderWidth := (Source as TIWItemStyle).BorderWidth;
    FColor := (Source as TIWItemStyle).Color;
    FColorTo := (Source as TIWItemStyle).ColorTo;
    FFont := (Source as TIWItemStyle).Font;
    FRoundedBorderRadius := (Source as TIWItemStyle).RoundedBorderRadius;
    FSelectBackgroundImage := (Source as TIWItemStyle).SelectBackgroundImage;
    FSelectBorderColor := (Source as TIWItemStyle).SelectBorderColor;
    FSelectColor := (Source as TIWItemStyle).SelectColor;
    FSelectColorTo := (Source as TIWItemStyle).SelectColorTo;
    FSelectFontColor := (Source as TIWItemStyle).SelectFontColor;
  end;
end;

constructor TIWItemStyle.Create(AOwner: TObject);
begin
  FOwner := AOwner;
  FColor := clWebWhite;
  FColorTo := clNone;
  FBackgroundImage := '';
  FBorderColor := clWebBlack;
  FBorderWidth := 1;
  FFont := TIWFont.Create;
  FFont.FontName := 'Arial';
  FFont.OnChange := FontChanged;
  FRoundedBorderRadius := 0;
  FSelectBackgroundImage := '';
  FSelectBorderColor := clWebBlack;
  FSelectColor := clWebWhite;
  FSelectColorTo := clNone;
  FSelectFontColor := clWebBlack;
end;

destructor TIWItemStyle.Destroy;
begin
  FFont.Free;
  inherited;
end;

procedure TIWItemStyle.FontChanged(Sender: TObject);
begin
  Invalidate;
end;

procedure TIWItemStyle.Invalidate;
begin
  if FOwner is TTIWCustomResponsiveList then
    (FOwner as TTIWCustomResponsiveList).Invalidate
  else if FOwner is TIWItemStylesItem then
    (FOwner as TIWItemStylesItem).FOwner.FOwner.Invalidate;
end;

procedure TIWItemStyle.SetBackgroundImage(const Value: string);
begin
  if FBackgroundImage <> Value then
  begin
    FBackgroundImage := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetBorderColor(const Value: TIWColor);
begin
  if FBorderColor <> Value then
  begin
    FBorderColor := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetBorderWidth(const Value: integer);
begin
  if FBorderWidth <> Value then
  begin
    FBorderWidth := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetColor(const Value: TIWColor);
begin
  if FColor <> Value then
  begin
    FColor := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetColorTo(const Value: TIWColor);
begin
  if FColorTo <> Value then
  begin
    FColorTo := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetFont(const Value: TIWFont);
begin
  FFont.Assign(Value);
end;

procedure TIWItemStyle.SetRoundedBorderRadius(const Value: integer);
begin
  if FRoundedBorderRadius <> Value then
  begin
    FRoundedBorderRadius := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetSelectBackgroundImage(const Value: string);
begin
  if FSelectBackgroundImage <> Value then
  begin
    FSelectBackgroundImage := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetSelectBorderColor(const Value: TIWColor);
begin
  if FSelectBorderColor <> Value then
  begin
    FSelectBorderColor := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetSelectColor(const Value: TIWColor);
begin
  if FSelectColor <> Value then
  begin
    FSelectColor := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetSelectColorTo(const Value: TIWColor);
begin
  if FSelectColorTo <> Value then
  begin
    FSelectColorTo := Value;
    Invalidate;
  end;
end;

procedure TIWItemStyle.SetSelectFontColor(const Value: TIWColor);
begin
  if FSelectFontColor <> Value then
  begin
    FSelectFontColor := Value;
    Invalidate;
  end;
end;

{ TIWPadding }

procedure TIWPadding.Assign(Source: TPersistent);
begin
  if Source is TIWPadding then
  begin
    FHorizontal := (Source as TIWPadding).Horizontal;
    FVertical := (Source as TIWPadding).Vertical;
  end;
end;

constructor TIWPadding.Create(AOwner: TObject);
begin
  FOwner := AOwner;
  FHorizontal := 5;
  FVertical := 5;
end;

destructor TIWPadding.Destroy;
begin
  inherited;
end;

procedure TIWPadding.Invalidate;
begin
  if (FOwner is TTIWCustomResponsiveList) then
    (FOwner as TTIWCustomResponsiveList).Invalidate;
end;

procedure TIWPadding.SetHorizontal(const Value: integer);
begin
  if FHorizontal <> Value then
  begin
    FHorizontal := Value;
    Invalidate;
  end;
end;

procedure TIWPadding.SetVertical(const Value: integer);
begin
  if FVertical <> Value then
  begin
    FVertical := Value;
    Invalidate;
  end;
end;

{ TIWListItem }

procedure TIWListItem.Assign(Source: TPersistent);
begin
  if Source is TIWListItem then
  begin
    FCss := (Source as TIWListItem).Css;
    FCssSelected := (Source as TIWListItem).CssSelected;
    FText := (Source as TIWListItem).Text;
    FName := (Source as TIWListItem).Name;
    FIsSection := (Source as TIWListItem).IsSection;
    FItemStyle := (Source as TIWListItem).ItemStyle;
    FSelected := (Source as TIWListItem).Selected;
    FTag := (Source as TIWListItem).Tag;
    FValue := (Source as TIWListItem).Value;
  end;
end;

constructor TIWListItem.Create(Collection: TCollection);
begin
  inherited;
  FCss := '';
  FCssSelected := '';
  FText := TStringList.Create;
  FText.Add('Item' + IntToStr(Index));
  FName := EmptyStr;
  FIsSection := False;
  FItemStyle := EmptyStr;
  FSelected := False;
  FTag := 0;
  FValue := EmptyStr;

  if Collection is TIWListItems then
  begin
    FOwner := Collection as TIWListItems;
  end;
end;

destructor TIWListItem.Destroy;
begin
  inherited;
  FText.Free;
end;

function TIWListItem.GetDisplayName: String;
begin
  Result := 'Item' + IntToStr(Index);
end;

function TIWListItem.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TIWListItem.SetItemStyle(const Value: string);
begin
  FItemStyle := Value;
end;

{ TIWEditListItems }

function TIWListItems.Add: TIWListItem;
begin
  Result := TIWListItem(inherited Add);
end;

procedure TIWListItems.Assign(Source: TPersistent);
var
  i: Integer;
  S: TIWListItems;
begin
  inherited;
  S := TIWListItems(Source);
  Clear;
  for i := 0 to S.Count-1 do
    Add.Assign(S[i]);
end;

constructor TIWListItems.Create(AOwner: TTIWCustomResponsiveList);
begin
  inherited Create(TIWListItem);
  FOwner := AOwner;
end;

destructor TIWListItems.Destroy;
begin
  inherited;
end;

function TIWListItems.GetItem(Index: Integer): TIWListItem;
begin
  Result := TIWListItem(inherited GetItem(Index));
end;

function TIWListItems.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TIWListItems.SetItem(Index: Integer;
  const Value: TIWListItem);
begin
  inherited SetItem(Index, Value);
end;

procedure TIWListItems.Update(Item: TCollectionItem);
begin
  inherited;
end;

{ TIWResponsiveLayoutItem }

procedure TIWResponsiveLayoutItem.Assign(Source: TPersistent);
begin
  if Source is TIWResponsiveLayoutItem then
  begin
    FColumns := (Source as TIWResponsiveLayoutItem).Columns;
    FMinScreenWidth := (Source as TIWResponsiveLayoutItem).MinScreenWidth;
    FName := (Source as TIWResponsiveLayoutItem).Name;
    FTag := (Source as TIWResponsiveLayoutItem).Tag;
    FValue := (Source as TIWResponsiveLayoutItem).Value;
  end;
end;

constructor TIWResponsiveLayoutItem.Create(Collection: TCollection);
begin
  inherited;
  FColumns := 1;
  FMinScreenWidth := 0;
  FName := EmptyStr;
  FTag := 0;
  FValue := EmptyStr;

  if Collection is TIWResponsiveLayoutItems then
  begin
    FOwner := Collection as TIWResponsiveLayoutItems;
  end;
  Invalidate;
end;

destructor TIWResponsiveLayoutItem.Destroy;
begin
  inherited;
  Invalidate;
end;

function TIWResponsiveLayoutItem.GetDisplayName: String;
begin
  Result := 'Item' + IntToStr(Index);
end;

function TIWResponsiveLayoutItem.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TIWResponsiveLayoutItem.Invalidate;
begin
  if Assigned(FOwner) then
    FOwner.FOwner.Invalidate;
end;

procedure TIWResponsiveLayoutItem.SetColumns(const Value: integer);
begin
  if FColumns <> Value then
  begin
    if Value < 1 then
      FColumns := 1
    else
      FColumns := Value;
    Invalidate;
  end;
end;

procedure TIWResponsiveLayoutItem.SetMinScreenWidth(const Value: integer);
begin
  if FMinScreenWidth <> Value then
  begin
    if Value < 0 then
      FMinScreenWidth := 0
    else
      FMinScreenWidth := Value;
    Invalidate;
  end;
end;

procedure TIWResponsiveLayoutItem.SetName(const Value: string);
begin
  if FName <> Value then
  begin
    FName := Value;
    Invalidate;
  end;
end;

procedure TIWResponsiveLayoutItem.SetTag(const Value: integer);
begin
  if FTag <> Value then
  begin
    FTag := Value;
    Invalidate;
  end;
end;

procedure TIWResponsiveLayoutItem.SetValue(const Value: string);
begin
  if FValue <> Value then
  begin
    FValue := Value;
    Invalidate;
  end;
end;

{ TIWResponsiveLayoutItems }

function TIWResponsiveLayoutItems.Add: TIWResponsiveLayoutItem;
begin
  Result := TIWResponsiveLayoutItem(inherited Add);
end;

procedure TIWResponsiveLayoutItems.Assign(Source: TPersistent);
var
  i: Integer;
  S: TIWResponsiveLayoutItems;
begin
  inherited;
  S := TIWResponsiveLayoutItems(Source);
  Clear;
  for i := 0 to S.Count-1 do
    Add.Assign(S[i]);
end;

constructor TIWResponsiveLayoutItems.Create(AOwner: TTIWCustomResponsiveList);
begin
  inherited Create(TIWResponsiveLayoutItem);
  FOwner := AOwner;
end;

destructor TIWResponsiveLayoutItems.Destroy;
begin
  inherited;
end;

function TIWResponsiveLayoutItems.GetItem(
  Index: Integer): TIWResponsiveLayoutItem;
begin
  Result := TIWResponsiveLayoutItem(inherited GetItem(Index));
end;

function TIWResponsiveLayoutItems.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TIWResponsiveLayoutItems.SetItem(Index: Integer;
  const Value: TIWResponsiveLayoutItem);
begin
  inherited SetItem(Index, Value);
end;

procedure TIWResponsiveLayoutItems.Update(Item: TCollectionItem);
begin
  inherited;
end;

{ TIWItemStylesItem }

procedure TIWItemStylesItem.Assign(Source: TPersistent);
begin
  if Source is TIWItemStylesItem then
  begin
    FItemStyle := (Source as TIWItemStylesItem).ItemStyle;
    FName := (Source as TIWItemStylesItem).Name;
    FTag := (Source as TIWItemStylesItem).Tag;
  end;
end;

constructor TIWItemStylesItem.Create(Collection: TCollection);
begin
  inherited;
  FName := 'Style' + IntToStr(Index);
  FItemStyle := TIWItemStyle.Create(Self);

  if Collection is TIWItemStyles then
  begin
    FOwner := Collection as TIWItemStyles;
  end;
end;

destructor TIWItemStylesItem.Destroy;
begin
  FItemStyle.Free;
  inherited;
end;

function TIWItemStylesItem.GetDisplayName: String;
begin
  if FName <> '' then
    Result := FName
  else
    Result := 'Style' + IntToStr(Index);
end;

function TIWItemStylesItem.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

{ TIWItemStyles }

function TIWItemStyles.Add: TIWItemStylesItem;
begin
  Result := TIWItemStylesItem(inherited Add);
end;

procedure TIWItemStyles.Assign(Source: TPersistent);
var
  i: Integer;
  S: TIWItemStyles;
begin
  inherited;
  S := TIWItemStyles(Source);
  Clear;
  for i := 0 to S.Count-1 do
    Add.Assign(S[i]);
end;

constructor TIWItemStyles.Create(AOwner: TTIWCustomResponsiveList);
begin
  inherited Create(TIWItemStylesItem);
  FOwner := AOwner;
end;

destructor TIWItemStyles.Destroy;
begin
  inherited;
end;

function TIWItemStyles.GetItem(Index: Integer): TIWItemStylesItem;
begin
  Result := TIWItemStylesItem(inherited GetItem(Index));
end;

function TIWItemStyles.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TIWItemStyles.SetItem(Index: Integer; const Value: TIWItemStylesItem);
begin
  inherited SetItem(Index, Value);
end;

procedure TIWItemStyles.Update(Item: TCollectionItem);
begin
  inherited;
end;

end.
