dbhtmlwidgets.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019-Now by Michael Van Canneyt, member of the
  4. Free Pascal development team
  5. WEB Widget Set : DB-AWare bare HTML Widgets
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit dbhtmlwidgets;
  13. {$mode objfpc}
  14. interface
  15. uses
  16. Classes, SysUtils, db, web, htmlwidgets;
  17. Type
  18. { TCustomDBTableWidget }
  19. { TDBTableColumn }
  20. TDBTableColumn = class(TCustomTableColumn)
  21. private
  22. FFieldName: String;
  23. FTemplate: String;
  24. procedure SetFieldName(AValue: String);
  25. protected
  26. Function GetCaption : String; Override;
  27. Public
  28. Procedure Assign(Source : TPersistent); override;
  29. Published
  30. Property FieldName : String Read FFieldName Write SetFieldName;
  31. Property Template : String Read FTemplate Write FTemplate;
  32. end;
  33. { TDBTableColumns }
  34. TDBTableColumns = Class(TCustomTableColumns)
  35. private
  36. function GetCol(Index : Integer): TDBTableColumn;
  37. procedure SetCol(Index : Integer; AValue: TDBTableColumn);
  38. Public
  39. Function AddField(F : TField) : TDBTableColumn;
  40. Function AddField(const AFieldName,aCaption : String) : TDBTableColumn;
  41. Property DBColumns[Index : Integer] : TDBTableColumn Read GetCol Write SetCol; default;
  42. end;
  43. { TDBTableRowEnumerator }
  44. TDBTableRowEnumerator = class(TTableRowEnumerator)
  45. FBOf: boolean;
  46. FDataset : TDataset;
  47. FColFields : Array of TField;
  48. FRowKeyField : TField;
  49. private
  50. function ReplaceTemplate(aTemplate: string; aField: TField): String;
  51. Protected
  52. Procedure SetDataset(aDataset : TDataset); virtual;
  53. Public
  54. Procedure GetCellData(aCell: TTableWidgetCellData); override;
  55. Function MoveNext: Boolean; override;
  56. Property Dataset : TDataset Read FDataset;
  57. end;
  58. TCustomDBTableWidget = Class(TCustomTableWidget)
  59. private
  60. FDatasource: TDatasource;
  61. FRowKeyField: String;
  62. function GetColumns: TDBTableColumns;
  63. procedure SetColumns(AValue: TDBTableColumns);
  64. procedure SetDatasource(AValue: TDatasource);
  65. procedure SetRowKeyField(AValue: String);
  66. Protected
  67. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  68. procedure RenderRow(aEnum : TTableRowEnumerator; aParent: TJSHTMLElement; aKind: TRowKind; aCell: TTableWidgetCellData);override;
  69. Procedure CreateDefaultColumns; override;
  70. Function CreateColumns: TCustomTableColumns; override;
  71. function GetDataset: TDataset;
  72. Function GetBodyRowEnumerator: TTableRowEnumerator; override;
  73. Property Datasource : TDatasource Read FDatasource write SetDatasource;
  74. Property RowKeyField : String Read FRowKeyField Write SetRowKeyField;
  75. Public
  76. Property Dataset : TDataset Read GetDataset;
  77. Property Columns : TDBTableColumns Read GetColumns Write SetColumns;
  78. end;
  79. TDBTableWidget = class(TCustomDBTableWidget)
  80. Public
  81. property Element;
  82. Published
  83. Property Classes;
  84. Property TableOptions;
  85. Property ParentID ;
  86. Property Datasource;
  87. Property Columns;
  88. Property OnGetCellData;
  89. Property OnCellClick;
  90. Property OnHeaderCellClick;
  91. Property OnFooterCellClick;
  92. Property OnRowClick;
  93. Property OnHeaderRowClick;
  94. Property OnFooterRowClick;
  95. Property RowKeyField;
  96. end;
  97. // Select that gets the values from a dataset.
  98. { TCustomDBSelectWidget }
  99. TCustomDBSelectWidget = class(TCustomSelectWidget)
  100. Private
  101. FDatasource : TDatasource;
  102. FItemField: String;
  103. FNullIsNotValue: Boolean;
  104. FValueField: String;
  105. function GetDataset: TDataset;
  106. function GetValue: String;
  107. procedure SetDatasource(AValue: TDatasource);
  108. procedure SetItemField(AValue: String);
  109. procedure SetNullIsNotValue(AValue: Boolean);
  110. procedure SetValueField(AValue: String);
  111. Protected
  112. Type
  113. { TStringsSelectOptionEnumerator }
  114. TDBSelectOptionEnumerator = Class(TSelectOptionEnumerator)
  115. FBof : Boolean;
  116. FDS : TDataset;
  117. FTextField : TField;
  118. FValueField : TField;
  119. FCheckValue : Boolean;
  120. constructor Create(ASelect : TCustomSelectWidget); override;
  121. Function OptionText : String; override;
  122. Function HasValue : boolean; override;
  123. Function Value : string; override;
  124. function MoveNext: Boolean; override;
  125. Property Dataset : TDataset Read FDS;
  126. end;
  127. Function CreateOptionEnumerator: TSelectOptionEnumerator; override;
  128. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  129. Protected
  130. Property Datasource : TDatasource Read FDatasource write SetDatasource;
  131. Property ItemField : String Read FItemField Write SetItemField;
  132. Property ValueField : String Read FValueField Write SetValueField;
  133. Property NullIsNotValue : Boolean Read FNullIsNotValue Write SetNullIsNotValue;
  134. Property Value : String Read GetValue;
  135. Public
  136. Property Dataset : TDataset Read GetDataset;
  137. end;
  138. { TDBSelectWidget }
  139. TDBSelectWidget = Class(TCustomDBSelectWidget)
  140. Public
  141. Property SelectionCount;
  142. Property SelectionValue;
  143. Property SelectionItem;
  144. Property Selected;
  145. Property Value;
  146. Property Options;
  147. Property SelectElement;
  148. Property ItemCount;
  149. Published
  150. Property Datasource;
  151. Property ItemField;
  152. Property ValueField;
  153. Property NullIsNotValue;
  154. property SelectedIndex;
  155. Property Multiple;
  156. end;
  157. implementation
  158. { TCustomDBSelectWidget.TDBSelectOptionEnumerator }
  159. constructor TCustomDBSelectWidget.TDBSelectOptionEnumerator.Create(ASelect: TCustomSelectWidget);
  160. Var
  161. S : TCustomDBSelectWidget;
  162. begin
  163. inherited Create(ASelect);
  164. FBOF:=True;
  165. S:=aSelect as TCustomDBSelectWidget;
  166. FDS:=S.Dataset;
  167. if FDS=Nil then
  168. exit;
  169. FTextField:=FDS.Fields.FindField(S.ItemField);
  170. if S.ValueField<>'' then
  171. FValueField:=FDS.Fields.FindField(S.ValueField);
  172. FCheckValue:=S.NullIsNotValue;
  173. end;
  174. function TCustomDBSelectWidget.TDBSelectOptionEnumerator.OptionText: String;
  175. begin
  176. Result:=FTextField.DisplayText;
  177. end;
  178. function TCustomDBSelectWidget.TDBSelectOptionEnumerator.HasValue: boolean;
  179. begin
  180. Result:=Assigned(FValueField);
  181. if Result and FCheckValue then
  182. Result:=Not FValueField.IsNull;
  183. end;
  184. function TCustomDBSelectWidget.TDBSelectOptionEnumerator.Value: string;
  185. begin
  186. Result:=FValueField.DisplayText;
  187. end;
  188. function TCustomDBSelectWidget.TDBSelectOptionEnumerator.MoveNext: Boolean;
  189. begin
  190. If not Assigned(Dataset) then
  191. exit(False);
  192. if FBOF then
  193. FBof:=False
  194. else
  195. Dataset.Next;
  196. Result:=Not Dataset.EOF;
  197. end;
  198. { TCustomDBSelectWidget }
  199. function TCustomDBSelectWidget.GetDataset: TDataset;
  200. begin
  201. if Assigned(Datasource) then
  202. Result:=Datasource.Dataset
  203. else
  204. Result:=nil;
  205. end;
  206. function TCustomDBSelectWidget.GetValue: String;
  207. begin
  208. Result:=TJSHTMLSelectElement(Element).Value;
  209. end;
  210. procedure TCustomDBSelectWidget.SetDatasource(AValue: TDatasource);
  211. begin
  212. if FDatasource=AValue then Exit;
  213. if Assigned(FDatasource) then
  214. FDatasource.RemoveFreeNotification(Self);
  215. FDatasource:=AValue;
  216. if Assigned(FDatasource) then
  217. FDatasource.FreeNotification(Self);
  218. end;
  219. procedure TCustomDBSelectWidget.SetItemField(AValue: String);
  220. begin
  221. if FItemField=AValue then Exit;
  222. FItemField:=AValue;
  223. end;
  224. procedure TCustomDBSelectWidget.SetNullIsNotValue(AValue: Boolean);
  225. begin
  226. if FNullIsNotValue=AValue then Exit;
  227. FNullIsNotValue:=AValue;
  228. end;
  229. procedure TCustomDBSelectWidget.SetValueField(AValue: String);
  230. begin
  231. if FValueField=AValue then Exit;
  232. FValueField:=AValue;
  233. end;
  234. function TCustomDBSelectWidget.CreateOptionEnumerator: TSelectOptionEnumerator;
  235. begin
  236. Result:=TDBSelectOptionEnumerator.Create(Self);
  237. end;
  238. procedure TCustomDBSelectWidget.Notification(AComponent: TComponent; Operation: TOperation);
  239. begin
  240. inherited Notification(AComponent, Operation);
  241. if (Operation=opRemove) and (AComponent=FDatasource) then
  242. FDataSource:=Nil;
  243. end;
  244. { TDBTableColumn }
  245. procedure TDBTableColumn.SetFieldName(AValue: String);
  246. begin
  247. if FFieldName=AValue then Exit;
  248. FFieldName:=AValue;
  249. end;
  250. function TDBTableColumn.GetCaption: String;
  251. begin
  252. Result:=inherited GetCaption;
  253. if Result='' then
  254. Result:=FieldName;
  255. end;
  256. procedure TDBTableColumn.Assign(Source: TPersistent);
  257. begin
  258. if Source is TDBTableColumn then
  259. FieldName:=TDBTableColumn(Source).FieldName;
  260. inherited Assign(Source);
  261. end;
  262. { TDBTableColumns }
  263. function TDBTableColumns.GetCol(Index : Integer): TDBTableColumn;
  264. begin
  265. Result:=TDBTableColumn(Items[Index])
  266. end;
  267. procedure TDBTableColumns.SetCol(Index : Integer; AValue: TDBTableColumn);
  268. begin
  269. Items[Index]:=AValue;
  270. end;
  271. function TDBTableColumns.AddField(F: TField): TDBTableColumn;
  272. begin
  273. Result:=AddField(F.FieldName,F.DisplayLabel);
  274. end;
  275. function TDBTableColumns.AddField(const AFieldName, aCaption : String): TDBTableColumn;
  276. begin
  277. Result:=(Add as TDBtableColumn);
  278. Result.FieldName:=aFieldName;
  279. Result.Caption:=aCaption;
  280. end;
  281. { TDBTableRowEnumerator }
  282. procedure TDBTableRowEnumerator.SetDataset(aDataset : TDataset);
  283. Var
  284. T : TCustomDBTableWidget;
  285. I : Integer;
  286. begin
  287. FBof:=True;
  288. FDataset:=aDataset;
  289. if Table is TCustomDBTableWidget then
  290. begin
  291. T:=Table as TCustomDBTableWidget;
  292. SetLength(FColFields,T.Columns.Count-1);
  293. For I:=0 to T.Columns.Count-1 do
  294. FColFields[I]:=Dataset.Fields.FindField(T.Columns[i].FieldName);
  295. if (T.RowKeyField<>'') then
  296. FRowKeyField:=Dataset.Fields.FindField(T.RowKeyField);
  297. end;
  298. end;
  299. Function TDBTableRowEnumerator.ReplaceTemplate(aTemplate : string; aField : TField) : String;
  300. Var
  301. I : Integer;
  302. begin
  303. Result:=aTemplate;
  304. if (aField<>Nil) then
  305. Result:=StringReplace(Result,'{{value}}',aField.AsString,[rfReplaceAll,rfIgnoreCase]);
  306. for I:=0 to Dataset.Fields.Count-1 do
  307. With Dataset.Fields[i] do
  308. Result:=StringReplace(Result,'{{'+FieldName+'}}',AsString,[rfReplaceAll,rfIgnoreCase]);
  309. end;
  310. procedure TDBTableRowEnumerator.GetCellData(aCell: TTableWidgetCellData);
  311. Var
  312. F : TField;
  313. CC : TDBTableColumn;
  314. begin
  315. if (aCell.Kind=rkBody) then
  316. begin
  317. F:=FColFields[ACell.Col];
  318. if aCell.Column is TDBTableColumn then
  319. CC:=TDBTableColumn(aCell.Column)
  320. else
  321. CC:=Nil;
  322. if Assigned(CC) and (CC.Template<>'') then
  323. begin
  324. aCell.Text:=replaceTemplate(CC.Template,F);
  325. aCell.asHTML:=True;
  326. end
  327. else if Assigned(F) then
  328. ACell.Text:=F.AsString;
  329. end
  330. else
  331. inherited GetCellData(aCell);
  332. end;
  333. function TDBTableRowEnumerator.MoveNext: Boolean;
  334. begin
  335. if FBOF then
  336. FBof:=False
  337. else
  338. Dataset.Next;
  339. Result:=Not Dataset.EOF;
  340. if Result then
  341. Result:=inherited MoveNext; // Update row number
  342. end;
  343. { TCustomDBTableWidget }
  344. procedure TCustomDBTableWidget.SetDatasource(AValue: TDatasource);
  345. begin
  346. if FDatasource=AValue then Exit;
  347. if Assigned(FDatasource) then
  348. FDatasource.RemoveFreeNotification(Self);
  349. FDatasource:=AValue;
  350. if Assigned(FDatasource) then
  351. FDatasource.FreeNotification(Self);
  352. end;
  353. procedure TCustomDBTableWidget.SetRowKeyField(AValue: String);
  354. begin
  355. if FRowKeyField=AValue then Exit;
  356. FRowKeyField:=AValue;
  357. if IsRendered then
  358. Refresh;
  359. end;
  360. procedure TCustomDBTableWidget.Notification(AComponent: TComponent; Operation: TOperation);
  361. begin
  362. inherited Notification(AComponent, Operation);
  363. if (Operation=opRemove) and (AComponent=FDatasource) then
  364. FDataSource:=Nil;
  365. end;
  366. procedure TCustomDBTableWidget.RenderRow(aEnum: TTableRowEnumerator; aParent: TJSHTMLElement; aKind: TRowKind;
  367. aCell: TTableWidgetCellData);
  368. begin
  369. With TDBTableRowEnumerator(aEnum) do
  370. begin
  371. if Assigned(FRowKeyField) then
  372. aParent.dataset['key']:=FRowKeyField.AsString;
  373. end;
  374. inherited RenderRow(aEnum, aParent, aKind, aCell);
  375. end;
  376. function TCustomDBTableWidget.GetColumns: TDBTableColumns;
  377. begin
  378. Result:=CustomColumns as TDBTableColumns;
  379. end;
  380. procedure TCustomDBTableWidget.SetColumns(AValue: TDBTableColumns);
  381. begin
  382. Customcolumns.Assign(AValue);
  383. end;
  384. procedure TCustomDBTableWidget.CreateDefaultColumns;
  385. Var
  386. I : Integer;
  387. begin
  388. With Dataset.Fields do
  389. For I:=0 to Count-1 do
  390. if Fields[i].Visible then
  391. Columns.AddField(Fields[i]);
  392. end;
  393. function TCustomDBTableWidget.CreateColumns: TCustomTableColumns;
  394. begin
  395. Result:=TDBTableColumns.Create(TDBTableColumn);
  396. end;
  397. function TCustomDBTableWidget.GetDataset: TDataset;
  398. begin
  399. Result:=Datasource.Dataset;
  400. end;
  401. function TCustomDBTableWidget.GetBodyRowEnumerator: TTableRowEnumerator;
  402. begin
  403. Result:=TDBTableRowEnumerator.Create(Self);
  404. TDBTableRowEnumerator(Result).SetDataset(Dataset);
  405. end;
  406. end.