瀏覽代碼

* Actions column

Michaël Van Canneyt 2 年之前
父節點
當前提交
16327ebaf1
共有 1 個文件被更改,包括 220 次插入43 次删除
  1. 220 43
      packages/bootstrap/bootstraptablewidget.pp

+ 220 - 43
packages/bootstrap/bootstraptablewidget.pp

@@ -10,7 +10,7 @@ type
 
   TCustomDBBootstrapTableWidget = Class;
 
-  TColumnRenderMode = (crmText, crmNumeric, crmDateTime, crmTransformedValue, crmCheckBox, crmButton, crmCustom, crmSelect);
+  TColumnRenderMode = (crmText, crmNumeric, crmDateTime, crmTransformedValue, crmCheckBox, crmButton, crmCustom, crmSelect, crmAction);
   TColumnButtonType = (cbtInfo, cbtEdit, cbtDelete, cbtCustom);
 
   TDataTablesFieldMap = Class(TObject)
@@ -65,11 +65,55 @@ type
     Property DeleteClass : String Read FDeleteClass Write FDeleteClass;
   end;
 
+  { TBSColumnAction }
+
+Type
+  TRenderButtonData = Record
+    ButtonIconClass, tagName, classnames, sIcon: string;
+    ButtonURLTarget, ButtonURL,ExtraAttributes : String;
+    ButtonType : TColumnButtonType;
+  end;
+  TRenderButtonDataArray = Array of TRenderButtonData;
+
+
+  TBSColumnAction = class(TCollectionItem)
+  private
+    FButtonIconClass: String;
+    FButtonType: TColumnButtonType;
+    FButtonURL: string;
+    FButtonURLTarget: string;
+    FExtraAttributes: String;
+  Public
+    procedure Assign(Source: TPersistent); override;
+  Published
+    property ButtonType: TColumnButtonType read FButtonType write FButtonType;
+    // When buttontype is btCustom, use the following class (in <i class="">)
+    Property ButtonIconClass: String Read FButtonIconClass Write FButtonIconClass;
+    // URL to use when the button is clicked
+    property ButtonURL: string read FButtonURL write FButtonURL;
+    // Target of button URL
+    property ButtonURLTarget: string read FButtonURLTarget write FButtonURLTarget;
+    // Add extra attributes to the contents of the column if needed
+    property ExtraAttributes: String read FExtraAttributes write FExtraAttributes;
+  end;
+
+  { TBSColumnActionList }
+
+  TBSColumnActionList = class(TCollection)
+  private
+    function GetAction(aIndex : Integer): TBSColumnAction;
+    procedure SetAction(aIndex : Integer; AValue: TBSColumnAction);
+  Public
+    Property Actions[aIndex : Integer] : TBSColumnAction Read GetAction Write SetAction; default;
+  end;
+
+
   { TBSTableColumn }
   TBSColumnClickEvent = Procedure(Sender : TObject; Event : TJSObject; aRowData : TJSObject; aRowIndex : Integer) of Object;
 
   TBSTableColumn = class(TCollectionItem)
   private
+    FActions: TBSColumnActionList;
     FFieldName: string;
     FFormatting: string;
     FOnButtonClick: TBSColumnClickEvent;
@@ -92,7 +136,11 @@ type
     FOnGetValue: TOnCustomValueEvent;
     FExtraAttributes: String;
     FWidthUnits: String;
+    function CreateActions: TBSColumnActionList;
+    destructor Destroy;
+    function GetActionsStored: Boolean;
     function GetTitle: string;
+    procedure SetActions(AValue: TBSColumnActionList);
   protected
     function GetDisplayName: String; override;
     { private declarations }
@@ -104,6 +152,8 @@ type
     property FieldName: string read FFieldName write FFieldName;
     // Title for this column
     property Title: string read GetTitle write FTitle;
+    // Action column actions
+    Property Actions : TBSColumnActionList Read FActions Write SetActions stored GetActionsStored;
     // Render mode: text, numer, checkbox, button custom render
     property RenderMode: TColumnRenderMode read FRenderMode write FRenderMode;
     // When rendermode is rmButton, what button ?
@@ -221,6 +271,7 @@ type
     FTableCreated : Boolean;
     procedure DoDoubleClickRow(aRow: TJSOBject; El: TJSHTMLElement; aField: String);
     procedure DoCheckRow(aRow: TJSOBject; El: TJSHTMLElement);
+    function DoRenderButton(Row: TJSObject; RenderData: TRenderButtonData; aActionIndex: integer=-1): string;
     function GetData: TJSArray;
     function GetDataFromDataset: TJSArray;
     function GetDataset: TDataset;
@@ -230,6 +281,7 @@ type
     function IsSearchOptionsStored: Boolean;
     function IsSortOPtionsStored: Boolean;
     function IsViewOptionsStored: Boolean;
+    procedure PrepareButtonRender(var aButton: TRenderButtonData);
     procedure SetData(const aData: TJSArray);
     procedure SetDatasource(AValue: TDataSource);
     procedure SetStylingClasses(AValue: TStylingClasses);
@@ -256,6 +308,8 @@ type
     function CreateCol(aFieldName, aTitle: string; aWidthUnits: String=''; aWidth : Integer = 0; aVisible: Boolean= True; aClassName: String ='';
       aSearchable: Boolean = True; aSortable: Boolean = True): TBootstrapTableColumn; overload;
     // Convert column to Button column
+    function MakeActionCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
+    // Convert column to Button column
     function MakeButtonCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
     // Convert column to checkbox column
     function MakeCheckBoxCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
@@ -417,6 +471,34 @@ begin
   Result:=FWidget;
 end;
 
+{ TBSColumnAction }
+
+procedure TBSColumnAction.Assign(Source: TPersistent);
+var
+  aSource: TBSColumnAction absolute Source;
+begin
+  if Source is TBSColumnAction then
+  begin
+    ExtraAttributes:=aSource.ExtraAttributes;
+    ButtonURLTarget:=aSource.ButtonURLTarget;
+    ButtonURL:=aSource.ButtonURL;
+    ButtonType:=aSource.ButtonType;
+    ButtonIconClass:=aSource.ButtonIconClass;
+  end else
+    inherited Assign(Source);
+end;
+
+{ TBSColumnActionList }
+
+function TBSColumnActionList.GetAction(aIndex : Integer): TBSColumnAction;
+begin
+  Result:=Items[aIndex] as TBSColumnAction;
+end;
+
+procedure TBSColumnActionList.SetAction(aIndex : Integer; AValue: TBSColumnAction);
+begin
+  Items[aIndex]:=aValue;
+end;
 
   { TBSTableColumn }
 
@@ -457,8 +539,22 @@ begin
   FVisible := True;
   FSortable := True;
   FSearchable := True;
+  Factions:=CreateActions;
 end;
 
+destructor TBSTableColumn.Destroy;
+
+begin
+  Factions.Free;
+  Inherited;
+end;
+
+function TBSTableColumn.CreateActions:TBSColumnActionList;
+begin
+  Result:=TBSColumnActionList.Create(TBSColumnAction);
+end;
+
+
 function TBSTableColumn.GetDisplayName: String;
 begin
   Result:=FieldName;
@@ -475,6 +571,17 @@ begin
     Result:=FieldName;
 end;
 
+function TBSTableColumn.GetActionsStored: Boolean;
+begin
+  Result:=(RenderMode=crmAction);
+end;
+
+procedure TBSTableColumn.SetActions(AValue: TBSColumnActionList);
+begin
+  if FActions=AValue then Exit;
+  FActions.Assign(AValue);
+end;
+
 { TBSTableColumns }
 
 function TBSTableColumns.Add(const aName: string): TBSTableColumn;
@@ -530,6 +637,11 @@ Var
   v : JSValue;
 
 begin
+  if Not (Assigned(Datasource) and Assigned(Datasource.Dataset)) then
+    begin
+      Result:=TJSArray.New;
+      exit;
+    end;
   if Datasource.Dataset is TBaseJSONDataset then
     begin
     Result:=TJSArray(TRowsDataset(Datasource.Dataset).Rows).filter(function (el : jsvalue; Index : NativeInt; aArr : TJSArray) : boolean
@@ -648,6 +760,7 @@ begin
   FinishColumn(Result, aTitle, aWidthUnits, aWidth, aVisible, aClassName, aSearchable, aSortable);
 end;
 
+
 function TCustomDBBootstrapTableWidget.MakeCustomFormatCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
 
   function renderCallBack(Data: JSValue; row: TJSObject; RowIndex : Integer; Field : string): JSValue;
@@ -744,57 +857,106 @@ begin
 end;
 
 
+procedure TCustomDBBootstrapTableWidget.PrepareButtonRender(var aButton : TRenderButtonData);
+
+begin
+  aButton.classnames:= StylingClasses.ButtonClass;
+  Case aButton.ButtonType of
+    cbtInfo:
+      aButton.sIcon := StylingClasses.InfoClass;
+    cbtEdit:
+      aButton.sIcon := IfThen(DisplayReadOnly,StylingClasses.ReadonlyEditClass,StylingClasses.EditClass);
+    cbtDelete:
+      aButton.sIcon := StylingClasses.DeleteClass;
+    cbtCustom:
+      aButton.sIcon := aButton.ButtonIconClass;
+  End;
+  if (aButton.ButtonType=cbtDelete) and DisplayReadOnly then
+    begin
+    aButton.tagName:='div';
+    aButton.classnames:=aButton.classnames+' disabled';
+    end;
+  if aButton.ButtonURL<>'' then
+    aButton.tagName:='a'
+  else
+    aButton.tagName:='span';
+end;
+
+Function TCustomDBBootstrapTableWidget.DoRenderButton(Row : TJSObject; RenderData: TRenderButtonData; aActionIndex : integer = -1): string;
+
+var
+  sUrl, sExtraAttributes: string;
+
+begin
+  sUrl:='';
+  sExtraAttributes := ReplaceMoustache(row, RenderData.ExtraAttributes);
+  if aActionIndex<>-1 then
+    sExtraAttributes:=sExtraAttributes+Format(' data-action-index="%d"',[aActionIndex]);
+  if not ((RenderData.ButtonType=cbtDelete) and DisplayReadOnly) then
+    if RenderData.ButtonURL<>'' then
+      begin
+      sUrl := ReplaceMoustache(row, RenderData.ButtonURL);
+      sUrl:=Format('href="%s"',[sUrl]);
+      if RenderData.ButtonURLTarget<>'' then
+        sExtraAttributes:=sExtraAttributes+' target="'+RenderData.ButtonURLTarget+'"';
+      end;
+  if (RenderData.TagName='a') and (sURL='') then
+    sURL:='href="javascript.void()"';
+  Result:=Format('<%s class="%s" %s %s><i class="%s"></i></%s> ',
+                 [renderData.tagName, renderData.classnames, sUrl, sExtraAttributes, renderData.sIcon, renderData.tagName])
+end;
 
 function TCustomDBBootstrapTableWidget.MakeButtonCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
 
 var
-  tagName, classnames, sIcon: string;
+  RenderData : TRenderButtonData;
 
-  procedure PrepareRender;
+  function renderCallBack(Data: JSValue; row: TJSObject; RowIndex : Integer; Field : string): JSValue;
 
   begin
-    classnames:= StylingClasses.ButtonClass;
-    Case aTableCol.ButtonType of
-      cbtInfo:
-        sIcon := StylingClasses.InfoClass;
-      cbtEdit:
-        sIcon := IfThen(DisplayReadOnly,StylingClasses.ReadonlyEditClass,StylingClasses.EditClass);
-      cbtDelete:
-        sIcon := StylingClasses.DeleteClass;
-      cbtCustom:
-        sIcon := aTableCol.ButtonIconClass;
-    End;
-    if (aTableCol.ButtonType=cbtDelete) and DisplayReadOnly then
-      begin
-      tagName:='div';
-      classnames:=classnames+' disabled';
-      end;
-    if aTableCol.ButtonURL<>'' then
-      tagName:='a'
-    else
-      tagName:='span';
+    Result:=DoRenderButton(Row,RenderData);
+  end;
+
+  function doclick(e : TJSEvent; value : JSValue; row: TJSObject; index : NativeInt) : JSValue;
+  begin
+    if assigned(aTableCol.OnButtonClick) then
+      aTableCol.OnButtonClick(aTableCol,E,row,index);
   end;
 
+begin
+  Result:=aCol;
+  RenderData:=Default(TRenderButtonData);
+  RenderData.ButtonIconClass:=ATableCol.ButtonIconClass;
+  RenderData.ButtonType:=ATableCol.ButtonType;
+  RenderData.ButtonURL:=aTableCol.ButtonURL;
+  RenderData.ButtonURLTarget:=aTableCol.ButtonURLTarget;
+  RenderData.ExtraAttributes:=aTableCol.ExtraAttributes;
+
+  PrepareButtonRender(RenderData);
+  Result.Formatter := @renderCallBack;
+  if Assigned(aTableCol.OnButtonClick) then
+    begin
+    Result.events:=TJSObject.new;
+    Result.events['click '+RenderData.tagname]:=@DoClick;
+    end;
+end;
+
+
+function TCustomDBBootstrapTableWidget.MakeActionCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
+var
+  RenderData : TRenderButtonDataArray;
+
   function renderCallBack(Data: JSValue; row: TJSObject; RowIndex : Integer; Field : string): JSValue;
 
   var
-    sUrl, sExtraAttributes: string;
+    S : String;
+    I : integer;
 
   begin
-    sUrl:='';
-    sExtraAttributes := ReplaceMoustache(row, aTableCol.ExtraAttributes);
-    if not ((aTableCol.ButtonType=cbtDelete) and DisplayReadOnly) then
-      if aTableCol.ButtonURL<>'' then
-        begin
-        sUrl := ReplaceMoustache(row, aTableCol.ButtonURL);
-        sUrl:=Format('href="%s"',[sUrl]);
-        if aTableCol.ButtonURLTarget<>'' then
-          sExtraAttributes:=sExtraAttributes+' target="'+aTableCol.ButtonURLTarget+'"';
-        end;
-    if (tagName='a') and (sURL='') then
-      sURL:='href="javascript.void()"';
-    Result:=Format('<%s class="%s" %s %s><i class="%s"></i></%s> ',
-                   [tagName, classnames, sUrl, sExtraAttributes, sIcon, tagName])
+    S:='';
+    For I:=0 to Length(RenderData)-1 do
+      S:=S+DoRenderButton(Row,RenderData[i],I);
+    Result:=S;
   end;
 
   function doclick(e : TJSEvent; value : JSValue; row: TJSObject; index : NativeInt) : JSValue;
@@ -802,18 +964,33 @@ var
     if assigned(aTableCol.OnButtonClick) then
       aTableCol.OnButtonClick(aTableCol,E,row,index);
   end;
+var
+  I : integer;
+  A : TBSColumnAction;
 
 begin
   Result:=aCol;
-  PrepareRender;
-  Result.Formatter := @renderCallBack;
-  if Assigned(aTableCol.OnButtonClick) then
+  SetLength(RenderData,aTableCol.Actions.Count);
+  For I:=0 to aTableCol.Actions.Count-1 do
     begin
-    Result.events:=TJSObject.new;
-    Result.events['click '+tagname]:=@DoClick;
+    A:=aTableCol.Actions[i];
+    RenderData[i]:=Default(TRenderButtonData);
+    RenderData[i].ButtonIconClass:=A.ButtonIconClass;
+    RenderData[i].ButtonType:=A.ButtonType;
+    RenderData[i].ButtonURL:=A.ButtonURL;
+    RenderData[i].ButtonURLTarget:=A.ButtonURLTarget;
+    RenderData[i].ExtraAttributes:=A.ExtraAttributes;
+    PrepareButtonRender(RenderData[I]);
+    if Assigned(aTableCol.OnButtonClick) then
+      begin
+      Result.events:=TJSObject.new;
+      Result.events['click '+RenderData[i].tagname+'["data-action-index"]']:=@DoClick;
+      end;
     end;
+  Result.Formatter := @renderCallBack;
 end;
 
+
 function TCustomDBBootstrapTableWidget.MakeCheckBoxCol(aCol: TBootstrapTableColumn; aTableCol: TBSTableColumn): TBootstrapTableColumn;
 
   function renderCallBack(Data: JSValue; row: TJSObject; RowIndex : Integer; Field : string): JSValue;