|
@@ -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;
|