{***************************************************************************}
{ TMS IntraWeb Component Pack Pro                                           }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2013                                               }
{            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 IWDBAsyncNavigator;

interface

{$I TMSDEFS.INC}

uses
  IWHTMLTag, DB, IWDBStdCtrls, Classes, IWTMSBase, SysUtils,
  IWDBCommon, IWRenderContext, IWXMLTag, IWControl, IWFileReference,
  IWBaseInterfaces;

type
  TTIWDBAsyncNavigator = class;

  TTIWButtonType =(btImageButton, btImage);

  TIWAsyncCustomButtonClickEvent = procedure (Sender: TObject;
    EventParams: TStringList; const Index: Integer) of object;
  TIWCustomButtonClickEvent = procedure(ASender: TObject; const Index: Integer) of object;

  TTIWTMSNavigatorDataLink = class(TDataLink)
  private
    FIWControl: TIWDBNavigator;
  protected
    procedure DataSetScrolled(Distance: Integer); override;
    procedure RecordChanged(Field: TField); override;
  public
    constructor Create(AControl: TIWDBNavigator);
  end;

  TIWDBAsyncNavActions = class(TPersistent)
  private
    FLast: Boolean;
    FPrior: Boolean;
    FRefresh: Boolean;
    FCancel: Boolean;
    FPost: Boolean;
    FFirst: Boolean;
    FDelete: Boolean;
    FEdit: Boolean;
    FNext: Boolean;
    FInsert: Boolean;
  public
    constructor Create;
  published
    property Cancel: Boolean read FCancel write FCancel default true;
    property Delete: Boolean read FDelete write FDelete default true;
    property Edit: Boolean read FEdit write FEdit default true;
    property First: Boolean read FFirst write FFirst default true;
    property Insert: Boolean read FInsert write FInsert default true;
    property Last: Boolean read FLast write FLast default true;
    property Next: Boolean read FNext write FNext default true;
    property Post: Boolean read FPost write FPost default true;
    property Prior: Boolean read FPrior write FPrior default true;
    property Refresh: Boolean read FRefresh write FRefresh default true;
  end;

  TIWDBAsyncNavHints = class(TPersistent)
  private
    FLast: string;
    FPrior: string;
    FRefresh: string;
    FCancel: string;
    FPost: string;
    FFirst: string;
    FDelete: string;
    FEdit: string;
    FNext: string;
    FInsert: string;
  public
    constructor Create;
  published
    property Cancel: string read FCancel write FCancel;
    property Delete: string read FDelete write FDelete;
    property Edit: string read FEdit write FEdit;
    property First: string read FFirst write FFirst;
    property Insert: string read FInsert write FInsert;
    property Last: string read FLast write FLast;
    property Next: string read FNext write FNext;
    property Post: string read FPost write FPost;
    property Prior: string read FPrior write FPrior;
    property Refresh: string read FRefresh write FRefresh;
  end;

  TIWDBAsyncNavCaptions = class(TPersistent)
  private
    FLast: string;
    FPrior: string;
    FRefresh: string;
    FCancel: string;
    FPost: string;
    FFirst: string;
    FDelete: string;
    FEdit: string;
    FNext: string;
    FInsert: string;
  public
    constructor Create;
  published
    property Cancel: string read FCancel write FCancel;
    property Delete: string read FDelete write FDelete;
    property Edit: string read FEdit write FEdit;
    property First: string read FFirst write FFirst;
    property Insert: string read FInsert write FInsert;
    property Last: string read FLast write FLast;
    property Next: string read FNext write FNext;
    property Post: string read FPost write FPost;
    property Prior: string read FPrior write FPrior;
    property Refresh: string read FRefresh write FRefresh;
  end;

  TIWNavCustomButton = class(TCollectionItem)
  private
    FCaption: string;
    FTag: Integer;
    FEnabled: boolean;
    FHint: string;
    FImageDisabled: TIWFileReference;
    FConfirmation: string;
    FImage: TIWFileReference;
    FVisible: boolean;
    FAsyncAction: boolean;
    function GetDBAsyncNavigator: TTIWDBAsyncNavigator;
    procedure SetAsyncAction(const Value: boolean);
    procedure SetCaption(const Value: string);
    procedure SetConfirmation(const Value: string);
    procedure SetEnabled(const Value: boolean);
    procedure SetHint(const Value: string);
    procedure SetImage(const Value: TIWFileReference);
    procedure SetImageDisabled(const Value: TIWFileReference);
    procedure SetVisible(const Value: boolean);
  protected
    function GetDisplayName: string; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    property TTIWDBAsyncNavigator: TTIWDBAsyncNavigator read GetDBAsyncNavigator;
  published
    property AsyncAction: boolean read FAsyncAction write SetAsyncAction default true;
    property Caption: string read FCaption write SetCaption;
    property Confirmation: string read FConfirmation write SetConfirmation;
    property Enabled: boolean read FEnabled write SetEnabled default true;
    property Hint: string read FHint write SetHint;
    property Image: TIWFileReference read FImage write SetImage;
    property ImageDisabled: TIWFileReference read FImageDisabled write SetImageDisabled;
    property Tag: Integer read FTag write FTag;
    property Visible: boolean read FVisible write SetVisible default true;
  end;

  TIWNavCustomButtons = class(TOwnedCollection)
  private
    FOwner: TTIWDBAsyncNavigator;
    function GetItem(Index: integer): TIWNavCustomButton;
    procedure SetItem(Index: integer; const Value: TIWNavCustomButton);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    function CreateItemClass: TCollectionItemClass; virtual;
    constructor Create(AOwner: TTIWDBAsyncNavigator);
    function Add: TIWNavCustomButton;
    function Insert(index: integer): TIWNavCustomButton;
    property Items[Index: integer]: TIWNavCustomButton read GetItem write SetItem; default;
  published
  end;

  TTIWDBAsyncNavigator = class(TIWDBNavigator, IIWInputControl)
  private
    FCustomButtonIndex: integer;
    FAction: string;
    FDataSource: TDataSource;
    FDataLink: TTIWTMSNavigatorDataLink;
    FOnAsyncFirst: TIWAsyncEvent;
    FOnAsyncLast: TIWAsyncEvent;
    FOnAsyncNext: TIWAsyncEvent;
    FOnAsyncPrior: TIWAsyncEvent;
    FOnAsyncEdit: TIWAsyncEvent;
    FOnAsyncInsert: TIWAsyncEvent;
    FOnAsyncDelete: TIWAsyncEvent;
    FOnAsyncPost: TIWAsyncEvent;
    FOnAsyncCancel: TIWAsyncEvent;
    FOnAsyncRefresh: TIWAsyncEvent;
    FAsyncActions: TIWDBAsyncNavActions;
    FButtonType: TTIWButtonType;
    FHints: TIWDBAsyncNavHints;
    FShowHint: boolean;
    FCaptions: TIWDBAsyncNavCaptions;
    FCustomButtons: TIWNavCustomButtons;
    FOnAsyncCustomButtonClick: TIWAsyncCustomButtonClickEvent;
    FOnCustomButtonClick: TIWCustomButtonClickEvent;
    FImageMargin: integer;
    procedure DoOnAsyncFirst(AParams: TStringList);
    procedure DoOnAsyncLast(AParams: TStringList);
    procedure DoOnAsyncNext(AParams: TStringList);
    procedure DoOnAsyncPrior(AParams: TStringList);
    procedure DoOnAsyncEdit(AParams: TStringList);
    procedure DoOnAsyncInsert(AParams: TStringList);
    procedure DoOnAsyncDelete(AParams: TStringList);
    procedure DoOnAsyncPost(AParams: TStringList);
    procedure DoOnAsyncCancel(AParams: TStringList);
    procedure DoOnAsyncRefresh(AParams: TStringList);
    procedure DoOnAsyncCustomButtonClick(AParams: TStringList);
    procedure SetDataSource(const Value: TDataSource);
    procedure SetButtonType(const Value: TTIWButtonType);
    procedure SetShowHint(const Value: boolean);
    procedure SetImageMargin(const Value: integer);
  protected
    procedure Submit(const AValue: string); override;
    procedure SetValue(const AValue: String); virtual;
    function GetAsyncCall(Action: string): string;
    function GetSubmitClick(Action: string): string;
    function GetButton(Action: string): string;
    function GetConfirmation(Action: string): string;
    function GetOrientation(): string;
    function GetImage(Action: string): string;
    function GetHint(Action: string): string;
    function IsCustom(Action: string): integer;
  public
    procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function RenderAsync(AContext: TIWBaseHTMLComponentContext): TIWXMLTag; override;
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
  published
    property AsyncActions: TIWDBAsyncNavActions read FAsyncActions write FAsyncActions;
    property ButtonType: TTIWButtonType read FButtonType write SetButtonType default btImageButton;
    property Captions: TIWDBAsyncNavCaptions read FCaptions write FCaptions;
    property CustomButtons: TIWNavCustomButtons read FCustomButtons write FCustomButtons;
    property DataSource: TDataSource read FDataSource write SetDataSource;
    property Hints: TIWDBAsyncNavHints read FHints write FHints;
    property ImageMargin: integer read FImageMargin write SetImageMargin default 5;
    property ShowHint: boolean read FShowHint write SetShowHint default true;
    property OnAsyncFirst: TIWAsyncEvent read FOnAsyncFirst write FOnAsyncFirst;
    property OnAsyncLast: TIWAsyncEvent read FOnAsyncLast write FOnAsyncLast;
    property OnAsyncNext: TIWAsyncEvent read FOnAsyncNext write FOnAsyncNext;
    property OnAsyncPrior: TIWAsyncEvent read FOnAsyncPrior write FOnAsyncPrior;
    property OnAsyncInsert: TIWAsyncEvent read FOnAsyncInsert write FOnAsyncInsert;
    property OnAsyncEdit: TIWAsyncEvent read FOnAsyncEdit write FOnAsyncEdit;
    property OnAsyncDelete: TIWAsyncEvent read FOnAsyncDelete write FOnAsyncDelete;
    property OnAsyncPost: TIWAsyncEvent read FOnAsyncPost write FOnAsyncPost;
    property OnAsyncCancel: TIWAsyncEvent read FOnAsyncCancel write FOnAsyncCancel;
    property OnAsyncRefresh: TIWAsyncEvent read FOnAsyncRefresh write FOnAsyncRefresh;
    property OnAsyncCustomButtonClick: TIWAsyncCustomButtonClickEvent read FOnAsyncCustomButtonClick write FOnAsyncCustomButtonClick;
    property OnCustomButtonClick : TIWCustomButtonClickEvent read FOnCustomButtonClick write FOnCustomButtonClick;
  end;

implementation

//{$R IWDB.res}

uses
  IWApplication;

{ TTIWDBAsyncNavigator }

function TTIWDBAsyncNavigator.RenderAsync(
  AContext: TIWBaseHTMLComponentContext): TIWXMLTag;
var
  js: string;
  I: integer;
begin

  Result := TIWXMLTag.CreateTag('control');
  try
    Result.AddStringParam('id', HTMLName);
    Result.AddStringParam('type', 'TTIWDBASYNCNAVIGATOR');
    RenderAsyncCommonProperties( AContext, Result );

    js := '<![CDATA['
    + GetOrientation;

    if ButtonType = btImageButton then
      js := js + HTMLName + 'Obj.buttontype = "button";'
    else
      js := js + HTMLName + 'Obj.buttontype = "image";';

    if ShowHint then
      js := js + HTMLName + 'Obj.showhint = true;'#13
    else
      js := js + HTMLName + 'Obj.showhint = false;'#13;

    js := js
    + 'el = document.getElementById("' + HTMLName + 'NAV").innerHTML = "";'#13
    + GetButton('First')
    + GetButton('Prior')
    + GetButton('Next')
    + GetButton('Last')
    + GetButton('Edit')
    + GetButton('Insert')
    + GetButton('Delete')
    + GetButton('Post')
    + GetButton('Cancel')
    + GetButton('Refresh');

    for I := 0 to CustomButtons.Count - 1 do
      js := js + GetButton('Custom' + IntToStr(I));

    js := js
      +']]>';

    GGetWebApplicationThreadVar.CallBackResponse.AddJavaScriptToExecute(js);

  except
    FreeAndNil(Result);
  end;
end;

function TTIWDBAsyncNavigator.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
var
  html: string;
  scFirst, scLast, scNext, scPrior, scEdit, scInsert, scDelete, scPost,
  scCancel, scRefresh, scCustom, acCustom: string;
  I: Integer;
begin
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncFirst', DoOnAsyncFirst);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncLast', DoOnAsyncLast);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncNext', DoOnAsyncNext);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncPrior', DoOnAsyncPrior);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncEdit', DoOnAsyncEdit);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncInsert', DoOnAsyncInsert);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncDelete', DoOnAsyncDelete);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncPost', DoOnAsyncPost);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncCancel', DoOnAsyncCancel);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncRefresh', DoOnAsyncRefresh);
  Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoOnAsyncCustomButtonClick', DoOnAsyncCustomButtonClick);

  scFirst := GetSubmitClick('First');
  if AsyncActions.First then
    scFirst := GetAsyncCall('First');

  scLast := GetSubmitClick('Last');
  if AsyncActions.Last then
    scLast := GetAsyncCall('Last');

  scNext := GetSubmitClick('Next');
  if AsyncActions.Next then
    scNext := GetAsyncCall('Next');

  scPrior := GetSubmitClick('Prior');
  if AsyncActions.Prior then
    scPrior := GetAsyncCall('Prior');

  scEdit := GetSubmitClick('Edit');
  if AsyncActions.Edit then
    scEdit := GetAsyncCall('Edit');

  scInsert := GetSubmitClick('Insert');
  if AsyncActions.Insert then
    scInsert := GetAsyncCall('Insert');

  scDelete := GetSubmitClick('Delete');
  if AsyncActions.Delete then
    scDelete := GetAsyncCall('Delete');

  scPost := GetSubmitClick('Post');
  if AsyncActions.Post then
    scPost := GetAsyncCall('Post');

  scCancel := GetSubmitClick('Cancel');
  if AsyncActions.Cancel then
    scCancel := GetAsyncCall('Cancel');

  scRefresh := GetSubmitClick('Refresh');
  if AsyncActions.Refresh then
    scRefresh := GetAsyncCall('Refresh');

  scCustom := GetSubmitClick('Custom');
  acCustom := GetAsyncCall('Custom');

  html :=
    'function '+HTMLName+'Obj(){'#13
    + 'this.orientation = "horizontal";'#13
    + 'this.margin = ' + IntToStr(ImageMargin) + ';'#13
    ;

  if ButtonType = btImageButton then
    html := html + 'this.buttontype = "button";'#13
  else
    html := html + 'this.buttontype = "image";'#13;

  if ShowHint then
    html := html + 'this.showhint = true;'#13
  else
    html := html + 'this.showhint = false;'#13;

  html := html
    + GetImage('First')
    + GetImage('Last')
    + GetImage('Next')
    + GetImage('Prior')
    + GetImage('Edit')
    + GetImage('Insert')
    + GetImage('Delete')
    + GetImage('Post')
    + GetImage('Cancel')
    + GetImage('Refresh')
    + GetHint('First')
    + GetHint('Last')
    + GetHint('Next')
    + GetHint('Prior')
    + GetHint('Edit')
    + GetHint('Insert')
    + GetHint('Delete')
    + GetHint('Post')
    + GetHint('Cancel')
    + GetHint('Refresh');

  for I := 0 to CustomButtons.Count - 1 do
  begin
    html := html + GetImage('Custom' + IntToStr(I));
    html := html + GetHint('Custom' + IntToStr(I));
  end;
  if CustomButtons.count > 0 then
  begin
     html := html + ' this.caction = new Array();'#13;
     html := html + ' this.cconf = new Array();'#13;
  end;

  html := html
    + '}'#13
    + HTMLName + 'Obj = new '+HTMLName+'Obj();'#13
    + GetOrientation();

  for I := 0 to CustomButtons.Count - 1 do
  begin
    if CustomButtons[I].AsyncAction then
      html := html + HTMLName + 'Obj.caction[' + IntToStr(I) + '] = true;'#13
    else
      html := html + HTMLName + 'Obj.caction[' + IntToStr(I) + '] = false;'#13;

    html := html + HTMLName + 'Obj.cconf[' + IntToStr(I) + '] = "' + CustomButtons[I].Confirmation + '";'#13;
  end;

  html := html
    + 'function ' + HTMLName + 'Click(obj, action) {'#13
    + ' FindElem("' + HTMLName + '_INPUT").value = action;'#13

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

    + ' if (action.indexOf("Custom") >= 0) {'#13
    + '  index = action.substr(6);'#13
    + '  doaction = true;'#13


//  if confirmation <> EmptyStr then
//  begin
//    result := 'if (confirm(''' + confirmation + ''')) { '#13
//      + result + '}'#13;
//  end;

    + '  if (obj.cconf[index] != "")'#13
    + '    doaction = confirm(obj.cconf[index]);'#13
    + '  if (doaction){'#13
    + '    if (obj.caction[index])'#13
    + acCustom
    + '    else '#13
    + scCustom
    + '  }'
    + ' }'

    + ' switch (action) {'#13
    + '  case "First":'#13
    + scFirst
    + '  break;'#13
    + '  case "Last":'#13
    + scLast
    + '  break;'#13
    + '  case "Next":'#13
    + scNext
    + '  break;'#13
    + '  case "Prior":'#13
    + scPrior
    + '  break;'#13
    + '  case "Edit":'#13
    + scEdit
    + '  break;'#13
    + '  case "Insert":'#13
    + scInsert
    + '  break;'#13
    + '  case "Delete":'#13
    + scDelete
    + '  break;'#13
    + '  case "Post":'#13
    + scPost
    + '  break;'#13
    + '  case "Cancel":'#13
    + scCancel
    + '  break;'#13
    + '  case "Refresh":'#13
    + scRefresh
    + '  break;'#13
    + ' }'#13
    + '}'#13

    + 'function ' + HTMLName + 'GetButton(obj, action, disabled, img, hint, caption) {'#13
    + ' var el = document.getElementById("' + HTMLName + 'NAV");'#13
    + ' var b = "";'#13
    + ' var c = "";'#13
    + ' var t = "";'#13
    + ' if (el) {'#13

    + '  if (obj.showhint)'#13
    + '    t = "title=''" + hint + "''";'#13

    + '  if (disabled != "disabled")'
    + '    c = "onclick=''' + HTMLName + 'Click(' + HTMLName + 'Obj, \"" + action + "\");''";'#13
    + '  else '#13
    + '    c = "";'#13

    + '  if (img == "") '#13
    + '    b += action;'#13
    + '  else {'#13
    + '    if (obj.buttontype == "button") {'#13
    + '      b += "<img class=''' + HTMLName + 'img'' src=''" + img + "''>";'#13
    + '  if (caption != "")'#13
    + '    b += "<br>" + caption;'#13
    + '   } else {'#13
    + '      b += "<img class=''' + HTMLName + 'imgb'' src=''" + img + "'' " + t + " " + c + ">";'#13
    + '  }'#13
    + '  }'#13

    + '  if (obj.buttontype == "button") {'#13
    + '    b = "<button class=''' + HTMLName + 'bt'' id=''' + HTMLName + '" + action + "'' '
    + '   " + t + " " + c + " " + disabled + ">"'#13
    + ' + b + "</button>";'#13
    + '  }'#13

    + '  if (obj.orientation == "vertical")'#13
    + '    b += "<br>";'#13

    + '  el.innerHTML += b;'#13
    + ' }'#13
    + '}'#13
    ;

  TIWComponent40Context(AContext).AddToJavaScriptOnce(html);

  html :=
    GetButton('First')
    + GetButton('Prior')
    + GetButton('Next')
    + GetButton('Last')
    + GetButton('Edit')
    + GetButton('Insert')
    + GetButton('Delete')
    + GetButton('Post')
    + GetButton('Cancel')
    + GetButton('Refresh')
    ;

  for I := 0 to CustomButtons.Count - 1 do
    html := html + GetButton('Custom' + IntToStr(I));

  TIWComponent40Context(AContext).AddToInitProc(html);

  //Result := inherited RenderHTML(AContext);
  Result := TIWHTMLTag.CreateTag('DIV');
  Result.Contents.AddText('<style>'#13
//    + '.' + HTMLName + 'bt {height:' + IntToStr(ImageHeight + 6) + 'px;}'#13
    + '.' + HTMLName + 'img, .' + HTMLName + 'imgb {width:'
    + IntToStr(ImageWidth) + 'px;height:' + IntToStr(ImageHeight) + 'px;}'#13
    + '.' + HTMLName + 'imgb {cursor:pointer;margin-right:'
    + IntToStr(ImageMargin) + 'px;margin-bottom:'
    + IntToStr(ImageMargin) + 'px;}'#13
    + '</style>'#13
    + '<span id="' + HTMLName +'NAV"></span>');
  //Result.Contents.AddText(html);

  //add hidden input
  with Result.Contents.AddTag('INPUT') do
  begin
    AddStringParam('TYPE', 'hidden');
    AddStringParam('NAME', HTMLName);
    AddStringParam('ID', HTMLName + '_INPUT');
    AddStringParam('VALUE', '-1');
  end;
end;

constructor TTIWDBAsyncNavigator.Create(AOwner: TComponent);
begin
  inherited;
  FCustomButtonIndex := -1;
  FAction := EmptyStr;
  FAsyncActions := TIWDBAsyncNavActions.Create;
  FButtonType := btImageButton;
  FCaptions := TIWDBAsyncNavCaptions.Create;
  FCustomButtons :=  TIWNavCustomButtons.Create(Self);
  FDataLink :=  TTIWTMSNavigatorDataLink.Create(self);
  FHints := TIWDBAsyncNavHints.Create;
  FImageMargin := 5;
  FShowHint := true;
  Width := 360;
end;

destructor TTIWDBAsyncNavigator.Destroy;
begin
  FAsyncActions.Free;
  FCaptions.Free;
  FCustomButtons.Free;
  FDataLink.Free;
  FHints.Free;
  inherited;
end;

procedure TTIWDBAsyncNavigator.DoOnAsyncCancel(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
    DataSource.Dataset.Cancel;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncCustomButtonClick(AParams: TStringList);
begin
  if Assigned(OnAsyncCustomButtonClick) then
    OnAsyncCustomButtonClick(Self, AParams, FCustomButtonIndex);
end;

procedure TTIWDBAsyncNavigator.DoOnAsyncDelete(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Cancel;
    DataSource.Dataset.Delete;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncEdit(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.Edit;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncFirst(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.First;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncInsert(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.Insert;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncLast(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.Last;
  end;

  if Assigned(OnAsyncLast) then
    OnAsyncNext(Self, AParams);
end;

procedure TTIWDBAsyncNavigator.DoOnAsyncNext(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.Next;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncPost(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
    DataSource.Dataset.Post;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncPrior(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Post;
    DataSource.Dataset.Prior;
  end;

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

procedure TTIWDBAsyncNavigator.DoOnAsyncRefresh(AParams: TStringList);
begin
  if CheckDataSource(DataSource) then
  begin
    if InEditMode(Datasource.Dataset) then
      Datasource.Dataset.Cancel;
    DataSource.Dataset.Refresh;
  end;

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

function TTIWDBAsyncNavigator.GetAsyncCall(Action: string): string;
var
  confirmation: string;
begin
  confirmation := GetConfirmation(Action);

  if Action = 'Custom' then
    Action := 'CustomButtonClick';

  result := 'processAjaxEvent(''on' + Action + ''', '
      + HTMLControlImplementation.IWCLName
      + ', ''' + HTMLName + '.' + 'DoOnAsync' + Action + '' + ''', '
      + 'true' + ', null, '
      + 'true' + ');'#13;

  if confirmation <> EmptyStr then
  begin
    result := 'if (confirm(''' + confirmation + ''')) { '#13
      + result + '}'#13;
  end;
end;

function TTIWDBAsyncNavigator.GetButton(Action: string): string;
var
  Visible: boolean;
  Image, Hint, Caption: string;
  i: integer;
begin
  result := '';
  Image := '';
  Hint := '';
  Caption := '';
  Visible := false;
  i := IsCustom(Action);

  if IsCustom(Action) >= 0 then
  begin
    Visible := CustomButtons[i].Visible;
    Hint := CustomButtons[i].Hint;
    Caption := CustomButtons[i].Caption;

    if not CustomButtons[i].Enabled then
      result := 'disabled ';
  end;
  if (Action = 'First') and (nbFirst in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.First;
  end;
  if (Action = 'Delete') and (nbDelete in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Delete;
  end;
  if (Action = 'Last') and (nbLast in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Last;
  end;
  if (Action = 'Next') and (nbNext in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Next;
  end;
  if (Action = 'Prior') and (nbPrior in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Prior;
  end;
  if (Action = 'Edit') and (nbEdit in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Edit;
  end;
  if (Action = 'Insert') and (nbInsert in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Insert;
  end;
  if (Action = 'Post') and (nbPost in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Post;
  end;
  if (Action = 'Cancel') and (nbCancel in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Cancel;
  end;
  if (Action = 'Refresh') and (nbRefresh in VisibleButtons) then
  begin
    Visible := true;
    Caption := Captions.Refresh;
  end;

  if Visible then
  begin
    if i >= 0 then
    begin
      Image := Action;
    end
    else
    begin
      if CheckDataSource(DataSource) then
      begin
        if (Action = 'Prior') or (Action = 'First') then
        begin
        if DataSource.DataSet.Bof then
          result := 'disabled';
        end;

        if (Action = 'Next') or (Action = 'Last') then
        begin
        if DataSource.DataSet.Eof then
          result := 'disabled';
        end;

        if (DataSource.DataSet.RecordCount = 0) and (Action = 'Delete') then
          result := 'disabled';

        if (DataSource.DataSet.State = dsEdit) or (DataSource.DataSet.State = dsInsert) then
        begin
          if (Action = 'Edit') or (Action = 'Insert')
            or (Action = 'Delete') or (Action = 'Refresh') then
              result := 'disabled';
        end
        else
        begin
          if (Action = 'Post') or (Action = 'Cancel') then
            result := 'disabled';
        end;
      end
      else
      begin
        result := 'disabled';
      end;
    end;

    Hint := HTMLName + 'Obj.h' + Action;

    Image := 'i' + Action;
    if result = 'disabled' then
      Image := Image + 'd';
    Image := HTMLName + 'Obj.' + Image;

    result := HTMLName + 'GetButton(' + HTMLName + 'Obj, "' + Action + '", "' + result + '", ' + Image + ', ' + Hint + ', "' + Caption + '");'#13
  end;
end;

function TTIWDBAsyncNavigator.GetConfirmation(Action: string): string;
var
  i: integer;
begin
  i := IsCustom(Action);
  if i >= 0 then
  begin
      result := CustomButtons[i].Confirmation;
  end
  else
  begin
    if (Action = 'First') then
      result := Confirmations.First;
    if (Action = 'Delete') then
      result := Confirmations.Delete;
    if (Action = 'Last') then
      result := Confirmations.Last;
    if (Action = 'Next') then
      result := Confirmations.Next;
    if (Action = 'Prior') then
      result := Confirmations.Prior;
    if (Action = 'Edit') then
      result := Confirmations.Edit;
    if (Action = 'Insert') then
      result := Confirmations.Insert;
    if (Action = 'Post') then
      result := Confirmations.Post;
    if (Action = 'Cancel') then
      result := Confirmations.Cancel;
    if (Action = 'Refresh') then
      result := Confirmations.Refresh;
  end;
end;

function TTIWDBAsyncNavigator.GetHint(Action: string): string;
var
  hint: string;
  i: integer;
begin

  if (Action = 'First') then
    hint := Hints.First;
  if (Action = 'Delete') then
    hint := Hints.Delete;
  if (Action = 'Last') then
    hint := Hints.Last;
  if (Action = 'Next') then
    hint := Hints.Next;
  if (Action = 'Prior') then
    hint := Hints.Prior;
  if (Action = 'Edit') then
    hint := Hints.Edit;
  if (Action = 'Insert') then
    hint := Hints.Insert;
  if (Action = 'Post') then
    hint := Hints.Post;
  if (Action = 'Cancel') then
    hint := Hints.Cancel;
  if (Action = 'Refresh') then
    hint := Hints.Refresh;

  i := IsCustom(Action);
  if i >= 0 then
    hint := CustomButtons[i].Hint;

  result :=
    'this.h' + Action + ' = "' + hint + '";'#13;
end;

function TTIWDBAsyncNavigator.GetImage(Action: string): string;
var
  url, urld: string;
  i: integer;
begin

  if (Action = 'First') then
  begin
    url := CustomImages.First_Enabled.URL;
    urld := CustomImages.First_Disabled.URL;
  end;
  if (Action = 'Delete') then
  begin
    url := CustomImages.Delete_Enabled.URL;
    urld := CustomImages.Delete_Disabled.URL;
  end;
  if (Action = 'Last') then
  begin
    url := CustomImages.Last_Enabled.URL;
    urld := CustomImages.Last_Disabled.URL;
  end;
  if (Action = 'Next') then
  begin
    url := CustomImages.Next_Enabled.URL;
    urld := CustomImages.Next_Disabled.URL;
  end;
  if (Action = 'Prior') then
  begin
    url := CustomImages.Prior_Enabled.URL;
    urld := CustomImages.Prior_Disabled.URL;
  end;
  if (Action = 'Edit') then
  begin
    url := CustomImages.Edit_Enabled.URL;
    urld := CustomImages.Edit_Disabled.URL;
  end;
  if (Action = 'Insert') then
  begin
    url := CustomImages.Insert_Enabled.URL;
    urld := CustomImages.Insert_Disabled.URL;
  end;
  if (Action = 'Post') then
  begin
    url := CustomImages.Post_Enabled.URL;
    urld := CustomImages.Post_Disabled.URL;
  end;
  if (Action = 'Cancel') then
  begin
    url := CustomImages.Cancel_Enabled.URL;
    urld := CustomImages.Cancel_Disabled.URL;
  end;
  if (Action = 'Refresh') then
  begin
    url := CustomImages.Refresh_Enabled.URL;
    urld := CustomImages.Refresh_Disabled.URL;
  end;

  i := IsCustom(Action);
  if i >= 0 then
  begin
      url := CustomButtons[i].Image.URL;
      urld := CustomButtons[i].ImageDisabled.URL;
  end
  else
  begin
{$IFDEF TMSIW11}
    if url = '' then
      url := '/$/gfx/DBNAV_' + Action + '.gif';
    if urld = '' then
      urld := '/$/gfx/DBNAV_' + Action + 'Disabled.gif';
{$ELSE}
    if url = '' then
      url := '/gfx/DBNAV_' + Action + '.gif';
    if urld = '' then
      urld := '/gfx/DBNAV_' + Action + 'Disabled.gif';
{$ENDIF}
  end;

  result :=
    'this.i' + Action + ' = "' + url + '";'#13
    + 'this.i' + Action + 'd = "' + urld + '";'#13;
end;

function TTIWDBAsyncNavigator.GetOrientation: string;
begin
  if Orientation = orHorizontal then
    result := HTMLName + 'Obj.orientation = "horizontal";'#13
  else
    result := HTMLName + 'Obj.orientation = "vertical";'#13;
end;

function TTIWDBAsyncNavigator.GetSubmitClick(Action: string): string;
begin
  if Action = 'Custom' then
    result := 'return SubmitClickConfirm(''' + HTMLName + ''', action, false, ''' + GetConfirmation(Action) + ''');'#13
  else
    result := 'return SubmitClickConfirm(''' + HTMLName + ''', ''' + Action + ''', false, ''' + GetConfirmation(Action) + ''');'#13;
end;

function TTIWDBAsyncNavigator.IsCustom(Action: string): integer;
var
  i: integer;
begin
  result := -1;
  if (Pos('Custom', Action) > 0) and (Length(Action) > 6) then
  begin
    i := StrToInt(Copy(Action,7,Length(Action)-1));
    if (i >= 0) and (i < CustomButtons.Count) then
      result := i;
  end;
end;

procedure TTIWDBAsyncNavigator.Notification(AComponent: TComponent; AOperation: TOperation);
begin
  inherited Notification(AComponent, AOperation);
  if AOperation = opRemove then begin
    if FDatasource = AComponent then begin
      FDatasource := nil;
    end;
  end;
end;

procedure TTIWDBAsyncNavigator.SetButtonType(const Value: TTIWButtonType);
begin
  FButtonType := Value;
  Invalidate;
end;

procedure TTIWDBAsyncNavigator.SetDataSource(const Value: TDataSource);
begin
  FDataSource := Value;
  FDataLink.DataSource := FDataSource;
end;

procedure TTIWDBAsyncNavigator.SetImageMargin(const Value: integer);
begin
  FImageMargin := Value;
  Invalidate;
end;

procedure TTIWDBAsyncNavigator.SetShowHint(const Value: boolean);
begin
  FShowHint := Value;
  Invalidate;
end;

procedure TTIWDBAsyncNavigator.SetValue(const AValue: String);
begin
  FCustomButtonIndex := IsCustom(AValue);
end;

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

  FCustomButtonIndex := IsCustom(AValue);
  if FCustomButtonIndex >= 0 then
  begin
    if Assigned(OnCustomButtonClick) then
      OnCustomButtonClick(Self, FCustomButtonIndex);
  end
  else
  begin
    FAction := AValue;

    if FAction = 'First' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.First;
      end;

      if Assigned(OnFirst) then
        OnFirst(Self);
    end;

    if FAction = 'Last' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.Last;
      end;

      if Assigned(OnLast) then
        OnLast(Self);
    end;

    if FAction = 'Next' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.Next;
      end;

      if Assigned(OnNext) then
        OnNext(Self);
    end;

    if FAction = 'Prior' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.Prior;
      end;

      if Assigned(OnPrior) then
        OnPrior(Self);
    end;

    if FAction = 'Edit' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.Edit;
      end;

      if Assigned(OnEdit) then
        OnEdit(Self);
    end;

    if FAction = 'Insert' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Post;
        DataSource.Dataset.Insert;
      end;

      if Assigned(OnInsert) then
        OnInsert(Self);
    end;

    if FAction = 'Cancel' then
    begin
      if CheckDataSource(DataSource) then
        DataSource.Dataset.Cancel;

      if Assigned(OnCancel) then
        OnCancel(Self);
    end;

    if FAction = 'Post' then
    begin
      if CheckDataSource(DataSource) then
        DataSource.Dataset.Post;

      if Assigned(OnPost) then
        OnPost(Self);
    end;

    if FAction = 'Refresh' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Cancel;
        DataSource.Dataset.Refresh;
      end;

      if Assigned(OnRefresh) then
        OnRefresh(Self);
    end;

    if FAction = 'Delete' then
    begin
      if CheckDataSource(DataSource) then
      begin
        if InEditMode(Datasource.Dataset) then
          Datasource.Dataset.Cancel;
        DataSource.Dataset.Delete;
      end;

      if Assigned(OnDelete) then
        OnDelete(Self);
    end;
  end;
end;

{ TTIWTMSDataLink }

constructor TTIWTMSNavigatorDataLink.Create(AControl: TIWDBNavigator);
begin
  inherited Create;
  FIWControl := AControl;
end;

procedure TTIWTMSNavigatorDataLink.DataSetScrolled(Distance: Integer);
begin
  inherited;
  if Assigned(FIWControl) then
    FIWControl.Invalidate;
end;

procedure TTIWTMSNavigatorDataLink.RecordChanged(Field: TField);
begin
  inherited;
  if Assigned(FIWControl) then
    FIWControl.Invalidate;
end;

{ TAsyncNavigatorAction }

constructor TIWDBAsyncNavActions.Create;
begin
  inherited;
  FCancel := true;
  FDelete := true;
  FEdit := true;
  FFirst := true;
  FInsert := true;
  FLast := true;
  FNext := true;
  FPost := true;
  FPrior := true;
  FRefresh := true;
end;

{ TIWDBAsyncNavHints }

constructor TIWDBAsyncNavHints.Create;
begin
  inherited;
  FCancel := 'Cancel';
  FDelete := 'Delete';
  FEdit := 'Edit';
  FFirst := 'First';
  FInsert := 'Insert';
  FLast := 'Last';
  FNext := 'Next';
  FPost := 'Post';
  FPrior := 'Prior';
  FRefresh := 'Refresh';
end;

{ TIWDBAsyncNavCaptions }

constructor TIWDBAsyncNavCaptions.Create;
begin
  inherited;
  FCancel := '';
  FDelete := '';
  FEdit := '';
  FFirst := '';
  FInsert := '';
  FLast := '';
  FNext := '';
  FPost := '';
  FPrior := '';
  FRefresh := '';
end;

{ TIWNavCustomButton }

procedure TIWNavCustomButton.Assign(Source: TPersistent);
begin
  inherited;
  AsyncAction := (Source as TIWNavCustomButton).AsyncAction;
  Caption := (Source as TIWNavCustomButton).Caption;
  Confirmation := (Source as TIWNavCustomButton).Confirmation;
  Enabled := (Source as TIWNavCustomButton).Enabled;
  Hint := (Source as TIWNavCustomButton).Hint;
  Image := (Source as TIWNavCustomButton).Image;
  ImageDisabled := (Source as TIWNavCustomButton).ImageDisabled;
  Tag := (Source as TIWNavCustomButton).Tag;
  Visible := (Source as TIWNavCustomButton).Visible;
end;

constructor TIWNavCustomButton.Create(Collection: TCollection);
begin
  inherited;
  AsyncAction := true;
  Caption := EmptyStr;
  Confirmation := EmptyStr;
  Enabled := true;
  Hint := EmptyStr;
  Image := TIWFileReference.Create;
  ImageDisabled := TIWFileReference.Create;
  Tag := 0;
  Visible := true;
end;

destructor TIWNavCustomButton.Destroy;
begin
  Image.Free;
  ImageDisabled.Free;
  inherited;
end;

function TIWNavCustomButton.GetDBAsyncNavigator: TTIWDBAsyncNavigator;
begin
  Result := TIWNavCustomButtons(Collection).FOwner;
end;

function TIWNavCustomButton.GetDisplayName: string;
begin
  if Caption <> '' then
    Result := Caption
  else
    Result := 'CustomButton' + IntToStr(Index);
end;

procedure TIWNavCustomButton.SetAsyncAction(const Value: boolean);
begin
  FAsyncAction := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetCaption(const Value: string);
begin
  FCaption := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetConfirmation(const Value: string);
begin
  FConfirmation := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetEnabled(const Value: boolean);
begin
  FEnabled := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetHint(const Value: string);
begin
  FHint := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetImage(const Value: TIWFileReference);
begin
  FImage := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetImageDisabled(const Value: TIWFileReference);
begin
  FImageDisabled := Value;
  Changed(False);
end;

procedure TIWNavCustomButton.SetVisible(const Value: boolean);
begin
  FVisible := Value;
  Changed(False);
end;

{ TIWNavCustomButtons }

function TIWNavCustomButtons.Add: TIWNavCustomButton;
begin
  Result := TIWNavCustomButton(inherited Add);
end;

constructor TIWNavCustomButtons.Create(AOwner: TTIWDBAsyncNavigator);
begin
  inherited Create(AOwner, CreateItemClass);
  FOwner := AOwner;
end;

function TIWNavCustomButtons.CreateItemClass: TCollectionItemClass;
begin
  Result := TIWNavCustomButton;
end;

function TIWNavCustomButtons.GetItem(Index: integer): TIWNavCustomButton;
begin
  Result := TIWNavCustomButton(inherited Items[Index]);
end;

function TIWNavCustomButtons.Insert(index: integer): TIWNavCustomButton;
begin
  Result := TIWNavCustomButton(inherited Insert(Index));
end;

procedure TIWNavCustomButtons.SetItem(Index: integer;
  const Value: TIWNavCustomButton);
begin
  inherited Items[Index] := Value;
end;

procedure TIWNavCustomButtons.Update(Item: TCollectionItem);
begin
  inherited;
  FOwner.Invalidate;
end;

end.
