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

{$I TMSDEFS.INC}

interface

uses
  {$IFDEF LINUX}
  QControls, QGraphics, QForms,
  {$ELSE}
  Controls, Graphics, Forms, Windows,
  {$ENDIF}
  {$IFDEF DELPHI6_LVL}
  Types,
  {$ENDIF}
  Classes,
  IWControl, IWTypes, SysUtils, IWCompButton,
  IWCompEdit, IWCompLabel, IWHTMLTag, IWTMSBase
  {$IFDEF TMSIW6}
  , IWRenderContext
  {$ENDIF}
  ;

type

  TCreditCard = (ccMasterCard, ccVISA, ccAmex, ccDinersClub, ccEnRoute, ccDiscover,ccJCB,ccUnknown);

  TCreditCards = set of TCreditCard;

  TTIWCCNumEdit = class(TIWCustomEdit)
  private
    FErrorMessage: string;
    FFlat: Boolean;
    FCreditCardTypes: TCreditCards;
    procedure SetErrorMessage(Value: String);
  protected
  public
    {$IFDEF TMSIW72}
    function get_HasTabOrder: boolean; override;
    {$ENDIF}
    constructor Create(AOwner: TComponent); override;
    procedure SetCreditCards(Value: TCreditCards);
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
  published
    property Flat: Boolean read FFlat write FFlat;
    property Text;
    property ErrorMessage: string read FErrorMessage write SetErrorMessage;
    property CreditCardTypes: TCreditCards read FCreditCardTypes write SetCreditCards;
  end;

  TTIWCCExpEdit = class(TIWControl)
  private
    FYearFrom: Integer;
    FMonth: Integer;
    FYear: Integer;
    FDesignMode: Boolean;
    FErrorMessage: string;
    procedure SetMonth(const Value: Integer);
    procedure SetYear(const Value: Integer);
    {$IFNDEF TMSIW71}
    procedure SetDesignMode(const Value: Boolean);
    {$ENDIF}
    procedure SetErrorMessage(AValue:String);
  protected
    {$IFDEF TMSIW6}
    procedure IWPaint; override;
    {$ELSE}
    procedure Paint; override;
    {$ENDIF}
  public
    {$IFDEF TMSIW72}
    function get_HasTabOrder: boolean; override;
    {$ENDIF}
    procedure Submit(const AValue: string); override;
    procedure SetValue(const AValue: string); override;
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    constructor Create(AOwner: TComponent); override;
    function GetMonthYear:string;
  published
    property Font;
    {$IFNDEF TMSIW71}
    property DesignMode: Boolean read FDesignMode write SetDesignMode default True;
    {$ENDIF}
    property Month: Integer read FMonth Write SetMonth;
    property TabOrder;
    property Year: Integer read FYear write SetYear;
    property ErrorMessage: string read FErrorMessage write SetErrorMessage;
   end;

implementation

uses
  IWApplication, IWServerControllerBase,
  SWStrings, SWSystem, IWAppForm, IWResourceStrings;


{ TTIWCCNumEdit }

constructor TTIWCCNumEdit.Create(AOwner: TComponent);
begin
  inherited;
  FErrorMessage := 'Please enter a valid CreditCard Number.';
  FCreditCardTypes := [ccMasterCard, ccVISA, ccAmex];

end;

procedure TTIWCCNumEdit.SetCreditCards(Value: TCreditCards);
begin
  FCreditCardTypes := Value;
end;

procedure TTIWCCNumEdit.SetErrorMessage(Value:String);
begin
  FErrorMessage := Value;
end;


{$IFDEF TMSIW72}
function TTIWCCNumEdit.get_HasTabOrder: boolean;
begin
  {$IFNDEF TMSIW72_NEW}
  Result := false;
  {$ELSE}
  Result := true;
  {$ENDIF}
end;
{$ENDIF}


{$IFDEF TMSIW6}
function TTIWCCNumEdit.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWCCNumEdit.RenderHTML: TIWHTMLTag;
{$ENDIF}
var

  FlatStyle:string;

  function HasCard(cc: TCreditCard): string;
  begin
    if (cc in CreditCardTypes) then
      Result := '1>0'
    else
      Result := '1<0';
  end;


  function MakeScript: string;
  begin
    Result := '<script language="JavaScript1.2">'#13

      +'function removeBlanks(s) {'#13
      +' var temp=""'#13
      +' for(var i=0;i<s.length;++i) {'#13
      +' var c=s.charAt(i)'#13
      +'  if(c!=" ") temp += c'#13
      +'  }'#13
      +' return temp'#13
      +'}'#13

      + 'function '+HTMLName+'IsValidCardType(field)'#13
      + '{'#13
      + 'strField = field.value;'#13
      + 'strField = removeBlanks(strField);'#13
      + 'if ((strField.search(/^(34|37)/) != -1) && ('+HasCard(ccAmex)+')){'#13
      + 'return (strField.length == 15);'#13
      + '}'#13
      + 'else if ((strField.search(/^(51|52|53|54|55)/) != -1) && ('+HasCard(ccMasterCard)+')){'#13
      + 'return (strField.length ==16);'#13
      + '}'#13
      + 'else if ((strField.search(/^(4)/) != -1) && ('+HasCard(ccVISA)+')){'#13
      + 'return (strField.length ==13 || strField.length ==16);'#13
      + '}'#13
      + 'else if ((strField.search(/^(300|301|302|303|304|305|36|38)/) != -1) && ('+HasCard(ccDinersClub)+')) {'#13
      + 'return(strField.length == 14);'#13
      + '}'#13
      + 'else if ((strField.search(/^(2014|2149)/) != -1) && ('+HasCard(ccEnRoute)+')) {'#13
      + 'return(strField.length == 15);'#13
      + '}'#13
      + 'else if ((strField.search(/^(6011)/) != -1)  && ('+HasCard(ccDiscover)+')) {'#13
      + 'return(strField.length == 16);'#13
      + '}'#13
      + 'else if ((strField.search(/^(3)/) != -1) && ('+HasCard(ccJCB)+')) {'#13
      + 'return(strField.length == 16);'#13
      + '}'#13
      + 'else if ((strField.search(/^(2131|1800)/) != -1)  && ('+HasCard(ccJCB)+')) {'#13
      + 'return(strField.length == 15);'#13
      + '}'#13
      + 'else if ('+HasCard(ccUnknown)+') {'#13
      + 'return true;'#13
      + '}'#13
      + 'else {'#13
      + 'return false;'#13
      + '}'#13
      + '}'#13

      + 'function ' + HTMLName + 'KeyPress(ctrl,event) {'#13
      + '  if (event.keyCode == 13){'#13
			+ '    var i;'#13
			+ '    for (i = 0; i < ctrl.form.elements.length; i++)'#13
			+ '      if (ctrl == ctrl.form.elements[i])'#13
			+ '        break;'#13
      + '    i = (i + 1) % ctrl.form.elements.length;'#13
      + '    ctrl.form.elements[i].focus();'#13
      + '    return false;'#13
      + ' }'#13
      +'  if ((event.keyCode < 48 || event.keyCode > 57) && (event.keyCode != 32))'#13
      +'    event.returnValue = false;'#13
      +'}'#13

      + 'function '+HTMLName+'ValidateCardNumber(field)'#13
      + '{'#13
      + 'try {'#13
      + 'strField = field.value;'#13
      + 'bool = ' + HTMLName+'IsValidCardType(field);'#13
      + 'if(bool!=true){'#13
      + 'throw exception;'#13
      + '}'#13
      + 'CardLength = strField.length;'#13
      + 'CheckNumbers = new Array();'#13
      + 'j=0;'#13
      + 'for(i = CardLength-2; i >= 0; i = i - 2)'#13
      + '{'#13
      + 'CheckNumbers[j] = (parseInt(strField.charAt(i))*2);'#13
      + 'j = j+1;'#13
      + '}'#13
      + 'CheckSum = 0;'#13
      + 'for(iCount = 0; iCount <=CheckNumbers.length-1; iCount++) {'#13
      + '_count = 0;'#13
      + '_numbers = parseInt(CheckNumbers[iCount]);'#13
      + 'if (_numbers > 9) { '#13
      + '_numLength = _numbers.toString().length;'#13
      + 'for(x = 0; x < _numLength; x++)'#13
      + '{'#13
      + ' _temp = parseInt(CheckNumbers[iCount]).toString();'#13
      + '_count = _count + parseInt(_temp.toString().charAt(x));'#13
      + '}'#13
      + '}'#13
      + 'else'#13
      + '{'#13
      + '_count = parseInt(CheckNumbers[iCount]);'#13
      + '}'#13
      + 'CheckSum = CheckSum + _count;'#13
      + '}'#13
      + 'OriginalSum = 0;'#13
      + 'for(y=CardLength-1; y >= 0; y=y-2) {'#13
      + 'OriginalSum = OriginalSum + parseInt(strField.charAt(y).toString());'#13
      + '}'#13
      + 'if (((OriginalSum+CheckSum)%10)!=00) {'#13
      + ' alert('#39+FErrorMessage+#39');'#13
      + '}'#13
      + 'return true;'#13
      + '}'#13
      + 'catch(exception) {'#13
      + ' alert('#39+FErrorMessage+#39')'#13
      + 'return false'#13
      + '}'#13
      + '}'#13
      + '</script>';
  end;
begin

  if SupportsInput and Required then
  begin
    {$IFDEF TMSIW6}

      {$IFDEF TMSIW9}
        TIWComponent40Context(AContext).AddValidation('getSubmitForm().'+HTMLName+'.value.length==0'
         , Format(RSValidationRequeredField, [FriendlyName]));
      {$ELSE}
        TIWComponent40Context(AContext).AddValidation('GSubmitter.' + HTMLName + '.value.length==0'
         , Format(RSValidationRequeredField, [FriendlyName]));
      {$ENDIF}

    {$ELSE}
      TIWAppForm(Form).AddValidation('GSubmitter.' + HTMLName + '.value.length==0'
       , Format(RSValidationRequeredField, [FriendlyName]));
    {$ENDIF}
  end;

  Result := TIWHTMLTag.CreateTag('DIV');
  Result.AddStringParam('id',HTMLName+'DIV');
  Result.Contents.AddText(MakeScript);

  if FFlat then
    FlatStyle := ' style="border-style:solid;border-width:1"'
  else
    FlatStyle := '';

  //changed to support "required" property

  //{$IFDEF TMSIW6}
  //with Result.Contents.AddTagAsObject(inherited RenderHTML(AContext)) do
  //{$ELSE}
  //with Result.Contents.AddTagAsObject(inherited RenderHTML) do
  //{$ENDIF}
  //begin
  //  AddStringParam('onblur', HTMLName + 'ValidateCardNumber(this)');
  //  AddStringParam('onKeyPress', HTMLName + 'KeyPress(this,event)');
  //  if FFlat then
  //    Add(FlatStyle);
  //end;

  //if css class is defined remove it from the outer div.
  //the class should only be set on the input tag
  {$IFDEF TMSIW9}
  if Css <> EmptyStr then
    Result.AddStringParam('class', ' ');
  {$ENDIF}

    Result.Contents.AddText('<input type="text" '
//    + ' id="'+HTMLName+'_INPUT" '
    + ' id="'+HTMLName+'" '
    + ' name="' + HTMLName +'" '
//    + ' name="' + HTMLName +'_INPUT" '
    + FlatStyle
    + ' onkeypress="' + HTMLName + 'KeyPress(this,event)" '
    + ' onblur="' + HTMLName + 'ValidateCardNumber(this)" '
    + 'value="' + Text + '" '
    {$IFDEF TMSIW9}
    + IIF((Css <> EmptyStr),' class="' + Css + '"','')
    {$ENDIF}
    + '>');

  //end changed

end;

{ TTIWCCExpEdit }

constructor TTIWCCExpEdit.Create(AOwner: TComponent);
var
  da,mo,ye: word;
begin
  inherited;
  DecodeDate(Now,ye,mo,da);
  FYearFrom := ye;
  FYear := ye;
  FMonth := mo;
  Width := 105;
  Height := 24;
  {$IFDEF TMSIW6}
  SetRenderSize(True);
  {$ELSE}
  FSupportsInput := True;
  FSupportsSubmit := True;
  FRenderSize := True;
  FEditable := True;  
  {$ENDIF}

  FDesignMode := True;
  FErrorMessage := 'Expiry date should be a date in the future.';
end;

function TTIWCCExpEdit.GetMonthYear: String;
begin
  Result := IntToStr(FMonth) + '/' + IntToStr(FYear);
end;

{$IFDEF TMSIW6}
procedure TTIWCCExpEdit.IWPaint;
{$ELSE}
procedure TTIWCCExpEdit.Paint;
{$ENDIF}
var
  r: TRect;
begin
  with Canvas do
  begin
    Brush.Color := clWhite;
    Pen.Color := clBlack;
    Pen.Width := 1;

    Rectangle(1,4,55,20);
    TextRect(Rect(2,5,54,19),3,5,IntToStr(Month));
    r := Rect(37,4,54,20);
    {$IFNDEF LINUX}
    DrawFrameControl(Handle,r, DFC_SCROLL,DFCS_SCROLLCOMBOBOX );
    {$ENDIF}

    Rectangle(56,4,100,20);
    TextRect(Rect(57,5,99,19),56,5,IntToStr(Year));
    r := Rect(83,4,99,20);
    {$IFNDEF LINUX}
    DrawFrameControl(Handle,r, DFC_SCROLL,DFCS_SCROLLCOMBOBOX );
    {$ENDIF}

    if FDesignMode then
    begin
      Brush.Style := bsClear;
      Pen.Style := psDot;
      Pen.Color := clBlack;
      Pen.Width := 1;
      Polygon([Point(0, 0), Point(Width - 1, 0), Point(Width - 1, Height - 1), Point(0, Height - 1)]);
      Pen.Style := psSolid;
    end;
  end;
end;

{$IFDEF TMSIW72}
function TTIWCCExpEdit.get_HasTabOrder: boolean;
begin
  {$IFNDEF TMSIW72_NEW}
  Result := false;
  {$ELSE}
  Result := true;
  {$ENDIF}
end;
{$ENDIF}


{$IFDEF TMSIW6}
function TTIWCCExpEdit.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWCCExpEdit.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  ResY,ResM: string;

  function getCurrentYear: integer;
  begin
    Result := FYearFrom;
  end;

  function getCurrentMonth: integer;
  var
    da,mo,ye:word;
  begin
    decodeDate(now,ye,mo,da);
    Result := mo;
  end;

  function MakeScript: string;
  var
    i: integer;
  begin
    {$IFDEF TMSIW6}
    TIWComponent40Context(AContext).AddToInitProc('FindElem(''' + HTMLName + ''').value="'+
      IntToStr(month)+'/'+IntToStr(year)+ '";' + EOL);
    {$ELSE}
    TIWAppForm(Form).AddToInitProc('FindElem(''' + HTMLName + ''').value="'+
      IntToStr(month)+'/'+IntToStr(year)+ '";' + EOL);
    {$ENDIF}

    ResY := '';
    for i := FYearFrom to FYearFrom+10 do
    begin
      if i = FYear then
        ResY := ResY + '<option selected value='+IntToStr(i)+'>'+IntToStr(i)+'</option>'
      else
        ResY := ResY + '<option value='+IntToStr(i)+'>'+IntToStr(i)+'</option>'
    end;

    ResM := '';

    for i := 1 to 12 do
    begin
      if i = FMonth then
        ResM := ResM + '<option selected value='+IntToStr(i)+'>'+IntToStr(i)+'</option>'
      else
        ResM := ResM + '<option value='+IntToStr(i)+'>'+IntToStr(i)+'</option>';
    end;

  Result :=
  '<SCRIPT LANGUAGE="JavaScript">'#13
    +'var '+HTMLName + 'in_validate;'#13
    +HTMLName + 'in_validate = true;'#13
    +'function ' + HTMLName+'Validate(){'#13
    +'if('+HTMLName + 'in_validate == true) {'#13
    + HTMLName + 'in_validate = false;'#13
    +'alert('#39+FErrorMessage+#39');'#13
    +'}'#13
    +'}'#13
    +'function '+HTMLName+'LookForYear(mi,yi){'#13
    +'currentDate = Date();'#13
    +'currentYear = '+ IntToStr(getCurrentYear) + ';'#13
    +'currentMonth = '+ IntToStr(getCurrentMonth) + ';'#13
    +'if(yi == currentYear) {'#13
    +'if(mi < currentMonth){'#13
    + HTMLName + 'Validate()'#13
    +'}'#13
    +'}'#13
    +'}'#13
    +'function '+HTMLName+'ValidateExpDate(field1,field2) {'#13
    + HTMLName+'LookForYear(field1.value,field2.value)'#13
    +HTMLName + 'in_validate = true;'#13
    +'ysel = document.getElementById("'+HTMLNAME+'YEAR");'#13
    +'msel = document.getElementById("'+HTMLNAME+'MONTH");'#13
    +'yi = ysel.options[ysel.selectedIndex].value'#13
    +'mi = msel.options[msel.selectedIndex].value'#13
    +'FindElem('#39+HTMLName+#39').value = mi+"/"+yi'#13
    +'}'#13
    +'</script>'#13
    +'<table border=0 cellspacing="0" cellpadding="0">'
    +'<tr>'
    +'<td align=center>'
    +'<select id="'+HTMLNAME+'MONTH" onblur="'+HTMLName+'ValidateExpDate('+HTMLNAME+'MONTH,'+HTMLNAME+'YEAR)">'
    + ResM
    +'</select>'
    +'</td>'
    +'<td>'
    +'<select id="'+HTMLNAME+'YEAR" onblur="'+HTMLName+'ValidateExpDate('+HTMLNAME+'MONTH,'+HTMLNAME+'YEAR)">'
    + ResY
    +'</select>'
    +'</td>'
    +'</tr>'
    +'</table>';
  end;

begin
  Result := TIWHTMLTag.CreateTag('DIV');
  with Result.Contents.AddTag('INPUT') do
  begin
    AddStringParam('TYPE','hidden');
    AddStringParam('NAME',HTMLName);
    AddStringParam('ID',HTMLName+'_INPUT');
  end;

  Result.Contents.AddText(MakeScript);
end;

procedure TTIWCCExpEdit.SetErrorMessage(AValue: String);
begin
  FErrorMessage := AValue;
end;

{$IFNDEF TMSIW71}
procedure TTIWCCExpEdit.SetDesignMode(const Value: Boolean);
begin
  FDesignMode := Value;
  Invalidate;
end;
{$ENDIF}

// Browser returning values to the component
procedure TTIWCCExpEdit.SetValue(const AValue: string);
var
  s:string;
  mo,ye:word;
  err: Integer;
begin
  s := AValue;
  if pos('/',s) > 0 then
  begin
    val(copy(s,1,pos('/',s)-1),mo,err);
    delete(s,1,pos('/',s));
    val(s,ye,err);
    FMonth := mo;
    FYear := ye;
  end;
end;

procedure TTIWCCExpEdit.SetYear(const Value: Integer);
begin
  FYear := Value;
  Invalidate;
end;

procedure TTIWCCExpEdit.SetMonth(const Value: Integer);
begin
  if (FMonth >= 1) and (FMonth < 13) then
    FMonth := Value
  else
    raise Exception.Create('Invalid month selected');
  Invalidate;
end;


procedure TTIWCCExpEdit.Submit(const AValue: string);
var
  s: string;
  mo,ye:word;
  err: Integer;
begin
  inherited;
  s := AValue;
  if pos('/',s) > 0 then
  begin
    val(copy(s,1,pos('/',s)-1),mo,err);
    delete(s,1,pos('/',s));
    val(s,ye,err);
    FMonth := mo;
    FYear := ye;
  end;
end;



end.
 