//TH-Header //***************************************************************************************** // Copyright (c) 2020 PP7 // All rights reserved. // // $FileName : PP7.SyncFusion\AppSrc\csfWebList.pkg // $ProjectName : PP7 SyncFusion // $Authors : Wil van Antwerpen // $Created : 06.04.2020 13:46 // // Contents: // This is a web framework wrapper class for the SyncFusion Grid control. // Documentation for the API is here: // https://ej2.syncfusion.com/documentation/api/grid // and tips & tricks here: // https://ej2.syncfusion.com/documentation/grid //***************************************************************************************** //TH-RevisionStart // ******************** // MODIFICATION SUMMARY // ******************** // ####### DD/MM/YYYY WHO COMMENT //TH-RevisionEnd Use csfWebList.h Use tWebRow.pkg Use csfWebBaseControl.pkg Use csfWebColumnAggregate.pkg Use csfWebColumn.pkg Use csfWebColumnHtml.pkg Use csfWebColumnCheckbox.pkg Use cJsonObject.pkg // // Perhaps later? //Class csfWebGridToolbar Is a cObject // Procedure Construct_Object // Forward Send Construct_Object // End_Procedure //End_Class // // This seems to make sense too //Class csfWebGridGroupSettings Is a cObject // Procedure Construct_Object // Forward Send Construct_Object // Property Boolean pbShowDropArea True // End_Procedure //End_Class { OverrideProperty=pGroupSettings Visibility=Private } { OverrideProperty=pColumnPrototypes Visibility=Private } { OverrideProperty=pColumnAggregates Visibility=Private } { HelpTopic=cWebList } { DesignerClass=cDTCWebGrid } { DesignerJSClass=df.WebList } { CompositeClass=csfWebColumn } Class csfWebList is a csfWebBaseControl Procedure Construct_Object Forward Send Construct_Object // Defines the mode of grid lines. The available modes are, // Both: Displays both horizontal and vertical grid lines. // None: No grid lines are displayed. // Horizontal: Displays the horizontal grid lines only. // Vertical: Displays the vertical grid lines only. // Default: Displays grid lines based on the theme. // Defaults to Default { EnumList="Both, None, Horizontal, Vertical, Default" } { WebProperty=Client } Property String psGridLines "Default" // If enableHover is set to true, the row hover is enabled in the Grid. // Defaults to true { WebProperty=Client } Property Boolean pbEnableHover True // If allowResizing is set to true, Grid columns can be resized. // Defaults to false { WebProperty=Client } Property Boolean pbAllowResizing False // If allowSorting is set to true, it allows sorting of grid records when column header is clicked. // Defaults to false { WebProperty=Client } Property Boolean pbAllowSorting False // If allowReordering is set to true, Grid columns can be reordered. Reordering can be done by // drag and drop of a particular column from one index to another index. // If Grid is rendered with stacked headers, reordering is allowed only at the same level as the // column headers. // Defaults to false { WebProperty=Client } Property Boolean pbAllowReordering False // If allowGrouping set to true, then it will allow the user to dynamically group or ungroup columns. // Grouping can be done by drag and drop columns from column header to group drop area. // Defaults to false { WebProperty=Client } Property Boolean pbAllowGrouping False // If allowPaging is set to true, the pager renders at the footer of the Grid. // It is used to handle page navigation in the Grid. // Defaults to false { WebProperty=Client } Property Boolean pbAllowPaging False // If allowPdfExport set to true, then it will allow the user to export grid to Pdf file. // Defaults to false { WebProperty=Client } Property Boolean pbAllowPdfExport False // If allowExcelExport set to true, then it will allow the user to export grid to Excel file. // Defaults to false { WebProperty=Client } Property Boolean pbAllowExcelExport False // If allowFiltering set to true the filter bar will be displayed. If set to false the filter bar // will not be displayed. Filter bar allows the user to filter grid records with required criteria. // Defaults to false { WebProperty=Client } Property Boolean pbAllowFiltering False // If enableAltRow is set to true, the grid will render with e-altrow CSS class to the // alternative tr elements. // Defaults to true { WebProperty=Client } Property Boolean pbEnableAltRow True // Enable or disable persisting component's state between page reloads. // Defaults to false { WebProperty=Client } Property Boolean pbEnablePersistence False // If enableVirtualization set to true, then the Grid will render only the rows visible within // the view-port and load subsequent rows on vertical scrolling. // This helps to load large dataset in Grid. // Defaults to false { WebProperty=Client } Property Boolean pbEnableVirtualization False // If showColumnChooser is set to true, it allows you to dynamically show or hide columns. // Defaults to false { WebProperty=Client } Property Boolean pbShowColumnChooser False // If showColumnMenu set to true, then it will enable the column menu options in each columns. // Defaults to false { WebProperty=Client } Property Boolean pbShowColumnMenu False // If showDropArea is set to true, the group drop area element will be visible at the top of the Grid. // Defaults to true { WebProperty=Client } Property Boolean pbShowGroupSettingsDropArea True // If showGroupedColumn is set to false, it hides the grouped column after grouping. // Defaults to false { WebProperty=Client } Property Boolean pbShowGroupedColumn False // If showToolbar is set to true, the toolbar element will be visible at the top of the Grid. // Defaults to true - design time only { WebProperty=Client } Property Boolean pbShowToolBar True // By SVN -- // If pbZeroSuppress is set to true, column has 'number' type and value is equal to Zero, // Cell will show nothing and '0' or '0.00' etc otherwise. Property Boolean pbZeroSuppress False // See documentation of DataFlex cWebList, contains the index of the current row { WebProperty=Client } Property Integer piCurrentRowIndex -1 // If set then it determines the width of the Grid. If equal to 0 then it uses the width as // automatically determined. { WebProperty=Client } Property Integer piWidth 0 { EnumList="rfmFindAll, rfmFindMainOnly, rfmFindMainSuper, rfmFindNone, rfmFindParentOnly" } Property Integer peRequestFindMode rfmFindAll Property Integer piOrdering -1 // initial ordering index see also Function Ordering // See documentation of DataFlex cWebList, contains the serialized RowID of the current // row. { WebProperty=Client } Property String psCurrentRowId "" // Set the language of the client, use the following codes: // https://github.com/syncfusion/ej2-locale (eg. sv = swedish) // Defaults to "" which means US { EnumList="sv, nb, fi, ru, th" } { WebProperty=Client } Property String psLocale "" { WebProperty=Client } Property Boolean pbAllowTextWrap False // Set to true if you want to be able to select multiple rows. // Defaults to False { WebProperty=Client } Property Boolean pbMultipleSelection False // Following are the enable/disable event properties // See documentation of DataFlex cWebList, enable this to be able to use the OnRowClick event. { WebProperty=Client } Property Boolean pbServerOnRowClick False { WebProperty=Client } Property Boolean pbServerOnRowDoubleClick False // Private // ChangingCurrentRow is enabled by default as that is the expected behavior. // This method will end up calling OnChangeCurrentRow { WebProperty=Client } Property Boolean pbServerChangingCurrentRow True // enable/disable onCreated event { WebProperty=Client } Property Boolean pbServerOnCreated False // Send each time a user makes a change to the grid layout. // enabled by default { WebProperty=Client } Property Boolean pbServerOnLayoutChanged True Property Boolean pbDataAware True // Set True if Grid Columns use data binding to DDO. False if there should be no DDO connection. { EnumList="gtAutomatic, gtAllData, gtManual" } Property Integer peDbGridType gtAutomatic // If set to true, data is static and load just once. Only used with pbDataAware=T. // not yet implemented (just want a better error if someone drops a normal cWebColumn object in // this grid, otherwise you would get an error about this property) Property Boolean pbColumnsEnabledStatic False { WebProperty=Client } Property Boolean pbGridDDOSyncing False // Private properties used for configuring the grid. { Visibility=Private } Property Handle[] pColumnHandles // is set on configuring and can be used during initial data load Property tsfWebListToolBarItem[] pToolBarItems Property tsfWebListToolBarItem[] private_ToolBarItems Property String[] pGroupSettings Property tsfWebColumn[] pColumnPrototypes Property tsfWebColumnAggregate[] pColumnAggregates Set psJSClass To "sf.WebList" Set Auto_Fill_State to True // Indicates that server DDO should find first record in it's dataset (important to set True for constrained child grids such as Order Details, for unconstrained lists it does not matter what the value is). Set piColumnSpan to 0 // Grids will span the whole width by default (0 does this) Set piHeight to 200 End_Procedure // Grid ordering Procedure Set Ordering Integer iOrder Set piOrdering to iOrder End_Procedure Function Ordering Returns Integer Function_Return (piOrdering(Self)) End_Function // return best index for constrained find. Return -1 which asks the runtime // to make this choice as normally there is only one choice. // This is suitable for augmentation. { Visibility=Private } Function ConstrainedIndexOrder Integer iConstrainFile Returns Integer Function_Return -1 // the runtime knows best End_Function { Visibility=Private } Function IndexOrder Returns Integer Handle hoDD Integer iOrdering iConstrainFile // if DD has an ordering we must use this Get Server to hoDD If (hoDD > 0) Begin Get Ordering of hoDD to iOrdering // get the sort index from the DDO (if this has been set) If (iOrdering<>-1) Begin Function_Return iOrdering End End Get piOrdering to iOrdering If (hoDD > 0) Begin // this is the ordering as defined by the grid Get Constrain_File of hoDD to iConstrainFile // if ordering is not specified and we have a constraining parent // we want to limit the constraint to the best choice for a constrained find If (iOrdering=-1 and iConstrainFile) Begin Get ConstrainedIndexOrder iConstrainFile to iOrdering End End Function_Return iOrdering End_Function { Visibility=Private } Procedure Attach_Deo_To_Server // Ignored if pbDataAware is False Boolean bDataAware Get pbDataAware to bDataAware If (bDataAware) Begin Forward Send Attach_Deo_To_Server End End_Procedure { Visibility=Private } Procedure RegisterColumn Handle hoColumn Integer iColumnID Boolean bIsDawColumn Handle[] ColumnHandles tsfWebColumn Column tsfWebColumn[] Columns If (hoColumn<>0) Begin Get pbIsWebColumn of hoColumn to bIsDawColumn If (bIsDawColumn=False) Begin Get LoadWebColumnProperties of hoColumn to Column Get pColumnPrototypes to Columns Move (SizeOfArray(Columns)) to iColumnID Move Column to Columns[iColumnID] Set pColumnPrototypes to Columns Set piColumnId of hoColumn to iColumnID Get pColumnHandles to ColumnHandles Move hoColumn to ColumnHandles[SizeOfArray(ColumnHandles)] Set pColumnHandles to ColumnHandles End End End_Procedure // Sent by DDO when there is a clear/find/save/delete. // // eMode - Determines the type of DDO operation which generated this refresh message. // It may be one of the following: // Mode_Clear: Used only for DEOs attached to the DDO that was the // "origin" of a Clear operation, (i.e., the DDO received // the original Clear message). All other DDOs Send their // DEOs the refresh message passing mode_find_or_clear_set. // Mode_Find_or_Clear_Set: Used for DEOs attached to DDOs which have Found and/or cleared records. // Mode_Clear_All: Used for DEOs attached to any DDO that participated in a clear_all operation. // Mode_Delete: Used for DEOs attached to any DDO that performed a successful deletion. // DDOs that were merely updated as the result of a deletion Use Mode_Find_or_Clear_Set. // Mode_Save: Used for DEOs attached to any DDO involved in a successful Save operation. { MethodType=Event } Procedure Refresh Integer eMode Integer iMainFile Integer eDDStatus Handle hoDDO Boolean bActive bAppSynching bMainFound Boolean bRowDisplay bInClearGrid bDataAware bGridDDOSyncing Integer eDBGridType String sCurrentRowID RowID riCurrentRowID riID Integer iCurrentRowIndex Get Active_State to bActive Get AppSynching to bAppSynching Get pbDataAware to bDataAware Get peDbGridType to eDBGridType WebGet pbGridDDOSyncing to bGridDDOSyncing If (bDataAware and bActive and not(bAppSynching) and not(bGridDDOSyncing)) Begin Get Server to hoDDO // hoDDO cannot be 0 otherwise we would never receive Refresh! Get Main_File of hoDDO to iMainFile Get DDRefreshTableStatus iMainFile to eDDStatus Move (eDDStatus <> ddrtsNone) to bMainFound // True = a main dd find or constrained child dd find has occurred // Get pbNotifyingExternalDD to bRowDisplay // True = we are simply responding to a change of the current row ID on the client // Get the current row's row id WebGet psCurrentRowId to sCurrentRowID Move (DeserializeRowID(sCurrentRowID)) to riCurrentRowID WebGet piCurrentRowIndex to iCurrentRowIndex // Handle the case where there is no selected row and we've done a save or delete on the main file. // We don't know what to do in this case so we will refresh the grid. This could happen if the save // is occuring from an external source (e.g., create a new record directly in the DD) If (iCurrentRowIndex=-1 and (eMode = MODE_SAVE or eMode = MODE_DELETE) and bMainFound and (not(bRowDisplay))) Begin Move MODE_FIND_OR_CLEAR_SET to eMode End // // If this is a clear on the grid's main file and it is not grid insert/append row, all we can do is clear and refresh the grid // Get pbInClearGrid to bInClearGrid // If (bInClearGrid) Begin // Move MODE_FIND_OR_CLEAR_SET to eMode // End If (eMode = MODE_CLEAR and bMainFound and sCurrentRowID <> "") Begin // HW: Added check for empty current row id which prevents recursive clearing with two grids on a single DD. // special case with clear. If this comes from some other DEO (which is unusual) // and the curent row has a record, then we need to insert a row for the // cleared row. If (not(bRowDisplay)) Begin // Send AppendNewRow End Send UpdateCurrentRowID End Else If (eMode = MODE_DELETE or eMode = MODE_SAVE or bRowDisplay or not(bMainFound)) Begin // Perform necessary actions for Save or Delete of a Grid Row If (hoDDO = OPERATION_ORIGIN) Begin // OPERATION_ORIGIN is the DDO that is the origin of the Save, Delete, find or clear // if a save notification and the save's DD is the same as the grid's // we are saving the main record and it may now be out of order If (eMode = MODE_SAVE) Begin // WebSet pbUnOrdered to True End End Send UpdateCurrentRowID End Else If (eMode = MODE_CLEAR_ALL) Begin Send UpdateCurrentRowID If (eDBGridType<>gtManual) Begin Send ClearGrid End End Else If (eMode = MODE_FIND_OR_CLEAR_SET) Begin // If we got here then refresh the entire grid Move (GetRowID(iMainFile)) to riID Send UpdateCurrentRowID If (eDBGridType<>gtManual) Begin If (hoDDO <> Main_DD(Self)) Begin Send GridRefresh End Else Begin Send UpdateList Send MoveToRowByID (SerializeRowId(riID)) // scroll to the selected row End End Send ReadByRowId of hoDDO iMainFile riID End End End_Procedure { Visibility=Private } Procedure UpdateCurrentRowID // Sets the web property psCurrentRowId for pbDataAware=True grid. Handle hoDD RowID riRowID // assert pbDataAware=True If (not(pbDataAware(Self))) Begin Error DFERR_PROGRAM "Assert: UpdateCurrentRowID called for non-data aware grid" End Get Server to hoDD If (hoDD = 0) Begin // This will probably never happen Move (NullRowID()) to riRowID End Else Begin Get CurrentRowId of hoDD to riRowID End WebSet psCurrentRowId to (SerializeRowID(riRowID)) End_Procedure // Returns the number of columns Function ColumnCount Returns Integer Handle[] ColumnHandles Get pColumnHandles to ColumnHandles Function_Return (SizeOfArray(ColumnHandles)) End_Function // Hardcoded, satisfies compatibility issue if a webcolumn object is dropped so we can // display a proper error { Visibility=Private } Function ClientSortable Returns Boolean Function_Return True End_Function Function ColumnByField String sField Returns Handle Integer iColumn String sID Handle[] ColumnHandles Get pColumnHandles to ColumnHandles For iColumn from 0 to (SizeOfArray(ColumnHandles)-1) Get psField of ColumnHandles[iColumn] to sID If (Uppercase(sField)=Uppercase(sId)) ; Function_Return ColumnHandles[iColumn] Loop Function_Return 0 // Column not found End_Function Function GetColumnObject Integer iColumnID Returns Handle Handle[] ColumnHandles Get pColumnHandles to ColumnHandles If (iColumnID < SizeOfArray(ColumnHandles)) Begin Function_Return ColumnHandles[iColumnID] End Function_Return 0 // Column not found End_Function Function ColumnAggregateValue String sField Returns Number Integer iColumn String sID Handle[] ColumnHandles Get pColumnHandles to ColumnHandles For iColumn from 0 to (SizeOfArray(ColumnHandles)-1) Get psField of ColumnHandles[iColumn] to sID If (Uppercase(sField)=Uppercase(sId)) Begin Function_Return (pnTotalValue(ColumnHandles[iColumn])) End Loop Function_Return 0 // Column not found End_Function Procedure ResetRunningTotals Integer iColumn Handle[] ColumnHandles Get pColumnHandles to ColumnHandles For iColumn from 0 to (SizeOfArray(ColumnHandles)-1) Set pnTotalValue of ColumnHandles[iColumn] to 0 Loop End_Procedure Function AggregateType String sField Returns String Integer iAggregate tsfWebColumnAggregate Aggregate tsfWebColumnAggregate[] Aggregates Get pColumnAggregates to Aggregates Move sField to Aggregate.sField Move (SearchArray(Aggregate, Aggregates)) to iAggregate If (iAggregate>=0) ; Function_Return Aggregates[iAggregate].sType Function_Return "" End_Function // Rereads the actual property values of the columns into the local // column prototype tsfWebColumn array { Visibility=Private } Procedure ReloadWebColumnProperties Boolean bIsHtml Boolean bIsDAWColumn Integer iColumn Integer iCount Handle hoColumn Handle[] ColumnHandles tsfWebColumn Column tsfWebColumn[] Columns Get pColumnHandles to ColumnHandles Move (SizeOfArray(ColumnHandles)) To iCount For iColumn From 0 To (iCount-1) Move ColumnHandles[iColumn] To hoColumn If (hoColumn) Begin Get pbIsWebColumn Of hoColumn To bIsDAWColumn If (bIsDAWColumn=false) Begin Get LoadWebColumnProperties Of hoColumn To Column Move Column To Columns[SizeOfArray(Columns)] End End Loop Set pColumnPrototypes To Columns End_Procedure Procedure ClearAggregates tsfWebColumnAggregate[] Aggregates Move (ResizeArray (Aggregates,0)) To Aggregates Set pColumnAggregates To Aggregates End_Procedure // // Creates an aggregate column without creating a DataFlex object // This makes it easier in a dynamic environment or if you want to // supply the group footer data via DataFlex // Function AddColumnAggregate tsfWebColumnAggregate aggregate Returns Integer Integer iCount tsfWebColumnAggregate[] Aggregates Get pColumnAggregates to Aggregates Move (SizeOfArray(Aggregates)) to iCount Move Aggregate to Aggregates[iCount] Set pColumnAggregates to Aggregates Function_Return iCount End_Function Procedure Set AggregateColumnFormat Integer iID String sFormat Integer iCount tsfWebColumnAggregate[] Aggregates Get pColumnAggregates To Aggregates Move (SizeOfArray(Aggregates)) To iCount If (iID0) Begin Get MemberByIndex of hoData 0 to hoRow Get IsOfJsonType Of hoRow jsonTypeObject To bOK If (bOK) Begin Move "_rid" to sMember Get HasMember of hoRow sMember to bHasMember If (bHasMember) Begin Get IsMemberOfJsonType of hoRow sMember jsonTypeString to bOk If (bOk) Begin Get MemberValue of hoRow sMember to sValue If (sValue<>"") Begin Move True to bHasRowID End End End Send Destroy of hoRow End End Else Begin Move True to bHasRowID // an array with zero rows.. has a rowid as it has no rows. End End Function_Return bHasRowID End_Function // // Method to insert a virtual rowID into the data so that we can use this to identify // rows in our logic. // Procedure JSONDataAutoNumberRowID Handle hoData Boolean bOk Integer iCount Integer iRow Handle hoRow Get IsOfJsonType of hoData jsonTypeArray to bOk If (bOk) Begin Get MemberCount Of hoData To iCount For iRow From 0 To (iCount-1) Get MemberByIndex Of hoData iRow To hoRow Get IsOfJsonType Of hoRow jsonTypeObject To bOK If (bOK) Begin Send SetMemberValue of hoRow "_rid" jsonTypeString (String(iRow+1)) Send Destroy of hoRow End Loop End End_Procedure // // Load the data as a JSON object. The hoMetaData object is entirely optional. // Procedure LoadJSONData Handle hoData Handle hoMetaData Boolean bHasRowID Handle hoJSON Handle hoMeta String[] sData Get Create (RefClass(cJsonObject)) to hoJSON Send InitializeJsonType of hoJSON jsonTypeObject If (hoData) Begin Get JSONDataHasRowID hoData to bHasRowID If (bHasRowID=False) Begin Send JSONDataAutoNumberRowID hoData End End Else Begin Error DFERR_PROGRAM "Assert: non-data aware grid is passed empty data in the LoadJSONData method." End Send SetMember Of hoJSON "data" hoData If (Num_Arguments=1) Begin Get Create (RefClass(cJsonObject)) To hoMeta Send InitializeJsonType of hoMeta jsonTypeArray End Else Begin Move hoMetaData To hoMeta Get JSONDataHasRowID hoMeta to bHasRowID If (bHasRowID=False) Begin Send JSONDataAutoNumberRowID hoMeta End End Send SetMember of hoJSON "meta" hoMeta If (Num_Arguments=1) Begin Send Destroy Of hoMeta End Get JsonDataToStringArray hoJSON To sData Send Destroy Of hoJSON Send LoadData sData End_Procedure Procedure RefreshGrid Send ClientAction "refreshGrid" End_Procedure Procedure GroupExpandAll Send ClientAction "groupExpandAll" End_Procedure Procedure GroupCollapseAll Send ClientAction "groupCollapseAll" End_Procedure // This function breaks the json data up in a string array. // This circumvents the string array size for almost all cases as each array item // can take up to 64k. // Earlier on we did this via a simple UChar array, but we had problems with utf8 to oem // encoding issues and strangely it wasn't as performant either. Function JsonDataToStringArray Handle hoJSON Returns String[] Boolean bOK Integer iRow Integer iCount Handle hoRow Handle hoData hoMeta String sRow String[] Data If (hoJSON<>0) Begin Get IsOfJsonType Of hoJson jsonTypeObject To bOK If (bOK) Begin Move '{ ' To Data[SizeOfArray(Data)] Get hasMember Of hoJSON "data" To bOK If (bOK) Begin Get Member Of hoJSON "data" To hoData End If (hoData) Begin Get IsOfJsonType of hoData jsonTypeArray to bOk If (bOk) Begin Move '"data": [ ' To Data[SizeOfArray(Data)] Get MemberCount Of hoData To iCount For iRow From 0 To (iCount-1) Get MemberByIndex Of hoData iRow To hoRow Get IsOfJsonType Of hoRow jsonTypeObject To bOK If (bOK) Begin Get Stringify Of hoRow To sRow If (iRow<(iCount-1)) Begin Move (sRow+", ") To sRow End Move sRow To Data[SizeOfArray(Data)] Send Destroy of hoRow End Loop Move " ]," To Data[SizeOfArray(Data)] End End Else Begin Send UserError "The data array object is missing from your JSON data." End Get HasMember Of hoJSON "meta" To bOK If (bOK) Begin Get Member Of hoJSON "meta" To hoMeta End If (hoMeta) Begin Get IsOfJsonType of hoMeta jsonTypeArray to bOk If (bOk) Begin Move '"meta": [ ' To Data[SizeOfArray(Data)] Get MemberCount Of hoMeta To iCount For iRow From 0 To (iCount-1) Get MemberByIndex Of hoMeta iRow To hoRow Get IsOfJsonType Of hoRow jsonTypeObject To bOK If (bOK) Begin Get Stringify Of hoRow To sRow If (iRow<(iCount-1)) Begin Move (sRow+", ") To sRow End Move sRow To Data[SizeOfArray(Data)] Send Destroy of hoRow End Loop Move " ]" To Data[SizeOfArray(Data)] End End Else Begin Send UserError "The meta array object is missing from your JSON data." End Move " }" To Data[SizeOfArray(Data)] End Else Begin Send UserError "The JSON data has to be provided with metadata." End End Function_Return Data End_Function Function DataTypeToJsonType Integer eDataType Integer iPrecision Returns Integer Integer eJsonType Case Begin Case (eDataType=typeASCII) Move jsonTypeString To eJsonType Case Break Case (eDataType=typeNumber) If (iPrecision=0) Begin Move jsonTypeInteger To eJsonType End Else Begin Move jsonTypeDouble To eJsonType End Case Break Case (eDataType=typeDate) Move jsonTypeString To eJsonType Case Break Case (eDataType=typeDateTime) Move jsonTypeString To eJsonType Case Break Case (eDataType=typeTime) Move jsonTypeString To eJsonType Case Break Case Else Move jsonTypeString To eJsonType Case End Function_Return eJsonType End_Function // // Not used anymore atm. Check if it can go away Function DBValue Integer iFile Integer iField Returns String Integer iType String sValue Get_Attribute DF_FIELD_TYPE Of iFile iField To iType Get_Field_Value iFile iField To sValue // cast value to the proper datatype If (iType=DF_BCD) Begin Function_Return (Number(sValue)) End Else If (iType=DF_DATE) Begin Function_Return (Date(sValue)) End Else If (iType=DF_DATETIME) Begin Function_Return (Cast(sValue,DateTime)) End Else Begin // else return as string Move (RTrim(sValue)) To sValue End Function_Return sValue End_Function // Adds meta data to the JSON meta data row if there is any meta data to send. // If there's none, then it won't add it either. Procedure AddCellMetaData Handle hoRow String sField tWebCell ByRef tCell Boolean ByRef bHasMeta Integer iOption iCount Handle hoCell hoOptions Move (SizeOfArray(tCell.aOptions)) To iCount If (tCell.sCssClassName<>"" or tCell.sToolTip<>"" or iCount>0) Begin Move True to bHasMeta Get Create (RefClass(cJsonObject)) To hoCell If (hoCell) Begin Send InitializeJsonType of hoCell jsonTypeObject Send SetMemberValue of hoCell "css" jsonTypeString tCell.sCssClassName Send SetMemberValue Of hoCell "tip" jsonTypeString tCell.sTooltip Get Create (RefClass(cJsonObject)) To hoOptions If (hoOptions) Begin Send InitializeJsonType Of hoOptions jsonTypeArray If (iCount>0) Begin For iOption From 0 To (iCount-1) Send AddMemberValue of hoOptions jsonTypeString tCell.aOptions[iOption] Loop End Send SetMember Of hoCell "opt" hoOptions Send Destroy Of hoOptions End Send SetMember of hoRow sField hoCell Send Destroy Of hoCell End End End_Procedure Procedure OnCustomTotals tsfWebColumnAggregate[] ByRef aggregates End_Procedure Procedure RunCustomTotals tsfWebColumnAggregate[] aggregates Get pColumnAggregates to aggregates If (SizeOfArray(aggregates)) Begin Send OnCustomTotals (&aggregates) Send UpdateAggregates aggregates End End_Procedure // This loads the data from the db into a JSON object which is then transformed // into a string array and passed on to the client side. // There's two parts, one that has the data from the database // The other part contains the (optional) meta data. The meta data contains CSS & tooltips // They are separate objects so that you don't have to extract the data before feeding it to // the grid, you just pass it a json object. Procedure SeedGridData Boolean bFound Boolean bAppSynching Boolean bIsCheckbox Boolean bHasMeta Boolean bConnected Integer iRows iMainFile Integer iColumn Integer iCount Integer iFile Integer iField Integer iIndex Integer eDataType eJsonType iPrecision Handle hoServer Handle hoData hoMetaData hoMetaRow hoRow hoJSON Handle hoColumn String sField //String sJson String sCheckedValue String sValue String sRowID RowId riRowID Handle[] Columns String[] Data tWebCell tCell tEmptyCell Get AppSynching to bAppSynching If (bAppSynching) Begin Procedure_Return End Send ResetRunningTotals Get Create (RefClass(cJsonObject)) to hoData Send InitializeJsonType of hoData jsonTypeArray Get Create (RefClass(cJsonObject)) to hoMetaData Send InitializeJsonType of hoMetaData jsonTypeArray Get pColumnHandles to Columns Move (SizeOfArray(Columns)) to iCount Move "" To tEmptyCell.sValue Get Server to hoServer Get Main_File of hoServer to iMainFile WebGet psCurrentRowID To sRowID Move (DeserializeRowID(sRowID)) to riRowID If (IsNullRowID(riRowID)) Begin // if no row id, we don't do anything. We return an empty set of rows // and indicate that we have all the records we can find Send ClearGrid Procedure_Return End Get IndexOrder to iIndex // Get ReadByRowIdEx of hoServer iMainFile riRowID to bFound // Read the current row Send Establish_Find_Direction of hoServer gt iMainFile iIndex While bFound Move False to bHasMeta Get Create (RefClass(cJsonObject)) to hoRow Send InitializeJsonType of hoRow jsonTypeObject Get Create (RefClass(cJsonObject)) to hoMetaRow Send InitializeJsonType of hoMetaRow jsonTypeObject Increment iRows // Add a hidden rowid column called _rid that we can use for selection etc.. Move (SerializeRowID(riRowID)) To sValue Send SetMemberValue of hoRow "_rid" jsonTypeString sValue Send SetMemberValue of hoMetaRow "_rid" jsonTypeString sValue // Now setup all the column objects, so we can use that when filling them up with the data For iColumn From 0 To (iCount-1) Move Columns[iColumn] to hoColumn If (hoColumn) Begin Move tEmptyCell To tCell Get Data_File Of hoColumn To iFile Get Data_Field Of hoColumn To iField Get psField Of hoColumn To sField Get peDataType Of hoColumn To eDataType Get piPrecision Of hoColumn To iPrecision Get pbDisplayAsCheckBox Of hoColumn to bIsCheckbox Get DataTypeToJsonType eDataType iPrecision To eJsonType If (bIsCheckbox) Begin Get Field_Checkbox_Value of hoServer iField True To sCheckedValue Move jsonTypeBoolean To eJsonType End Send LoadGridCell of hoColumn (&tCell) If (bIsCheckbox) Begin Move (if(tCell.sValue=sCheckedValue,True,False)) to tCell.sValue End Send SetMemberValue Of hoRow sField eJsonType tCell.sValue Send AddCellMetaData hoMetaRow sField (&tCell) (&bHasMeta) End Loop Send AddMember of hoData hoRow Send Destroy Of hoRow If (bHasMeta) Begin // only send metadata for a row if there's a field that has some Send AddMember Of hoMetaData hoMetaRow End Send Destroy of hoMetaRow Send Locate_next of hoServer Move (GetRowID(iMainFile)) To riRowID Move (Found) to bFound Loop Get Create (RefClass(cJsonObject)) to hoJSON Send InitializeJsonType of hoJSON jsonTypeObject Send SetMember of hoJSON "data" hoData Send SetMember of hoJSON "meta" hoMetaData Send Destroy of hoData Send Destroy Of hoMetaData Send RunCustomTotals Get JsonDataToStringArray hoJSON to Data Send Destroy of hoJSON Send LoadData Data End_Procedure // At this moment in time, the syncfusion grid is configured and the columns exist // Our javascript class for the webcolumns however is not yet connected to each column. // This method takes care of connecting each column. // { Visibility=Private } Procedure ConnectAllColumns Boolean bIsDAWColumn Integer iColumn Integer iCount Handle hoColumn Handle[] ColumnHandles Get pColumnHandles To ColumnHandles Move (SizeOfArray(ColumnHandles)) To iCount For iColumn From 0 To (iCount-1) Move ColumnHandles[iColumn] To hoColumn If (hoColumn) Begin Get pbIsWebColumn Of hoColumn To bIsDAWColumn If (bIsDAWColumn=false) Begin Send ConnectColumn Of hoColumn End End Loop End_Procedure // Hook that can be used to load data or to do any post configure grid // actions. Procedure onPostConfigureGrid End_Procedure Procedure InitialFind Handle hoDD Integer iMainFile String sRowID RowID riRowID Integer iIndex Get Server To hoDD Get Main_File of hoDD to iMainFile Get IndexOrder to iIndex Send Request_Read of hoDD FIRST_RECORD iMainFile iIndex If (found) Begin Move (GetRowID(iMainFile)) To riRowID Move (SerializeRowID(riRowID)) To sRowID WebSet psCurrentRowId To sRowID End End_Procedure { Visibility=Private } Procedure doPostConfigureGrid Boolean bDataAware Integer eDBGridType String sRowID Get pbDataAware To bDataAware Get peDbGridType to eDBGridType // Send ConnectAllColumns // Data is loaded manually if the data is not-data aware or if // it is data aware and manual loaded. If (not(bDataAware) or (eDBGridType=gtManual)) Begin WebGet psCurrentRowId to sRowID //Send OnManualLoadData (&atRows) (&sRowID) Send OnPostConfigureGrid WebSet psCurrentRowId to sRowID End Else Begin Send InitialFind Send OnPostConfigureGrid Send SeedGridData End End_Procedure { Visibility=Private } Procedure ConfigureDeoObjects Integer iColumn Integer iCount Integer iFile Integer iField Handle hoColumn String sField Handle[] Columns Get pColumnHandles To Columns Move (SizeOfArray(Columns)) To iCount // First setup all the column objects, so we can use that when filling them up with the data For iColumn From 0 To (iCount-1) Move Columns[iColumn] To hoColumn If (hoColumn) Begin Get Data_File Of hoColumn To iFile Get Data_Field Of hoColumn To iField If (iFile<>0 and iField<>0) Begin Send Attach_Deo_To_Server of hoColumn End End Loop Send ReloadWebColumnProperties End_Procedure Procedure doRenderGrid Send OnRender Send ClientAction "renderGrid" End_Procedure { Visibility=Private } Procedure ConfigureGrid String[] asParams String[] GroupSettings tsfWebListToolBarItem[] ToolBarItems tsfWebColumn[] columns tsfWebColumnAggregate[] aggregates tsfWebListConfig Config tWebValueTree tVT Send ConfigureDeoObjects Get pColumnPrototypes To Columns If (SizeOfArray(Columns)>0) Begin // Initialize with the toolbar items set at construct_object time. Get private_ToolBarItems To ToolBarItems Set pToolBarItems To ToolBarItems Send OnCreateToolBarItems // ToDo: Probably a good idea to test if the columns in Aggregates and GroupSettings exist! Get pColumnAggregates To Aggregates Get pGroupSettings To GroupSettings Get pToolBarItems To ToolBarItems Move Columns To Config.Columns Move Aggregates To Config.Aggregates Move GroupSettings To Config.GroupSettings Move ToolBarItems To Config.ToolBarItems ValueTreeSerializeParameter Config to tVT Send ClientAction "configureGrid" asParams tVT Send doPostConfigureGrid Send doRenderGrid End Else Begin Error DFERR_PROGRAM "Grid has no columns." End End_Procedure Procedure UpdateAggregates tsfWebColumnAggregate[] aggregates String[] asParams tWebValueTree tVT ValueTreeSerializeParameter aggregates to tVT Send ClientAction "updateAggregates" asParams tVT End_Procedure Procedure AddGroupSettingsColumn String sColumn Integer iCount String[] GroupSettings If (sColumn<>"") Begin // ToDo: Add test to make sure the column exists? Get pGroupSettings To GroupSettings Move (SizeOfArray(GroupSettings)) To iCount Move sColumn To GroupSettings[iCount] Set pGroupSettings To GroupSettings End End_Procedure // https://ej2.syncfusion.com/documentation/api/grid/#toolbar // Call this to add your toolbar items. // Built-in ToolBar items are : // Add, Edit, Update, Delete, Cancel, Search, Print, ExcelExport, PdfExport and CsvExport // You can also add your own ToolBar items by providing a string to use. // This string will be your id to use in the onToolBarButtonClick event. Procedure AddToolbarItem String sItem Integer iCount tsfWebListToolBarItem[] ToolBarItems If (sItem<>"") Begin Get pToolBarItems To ToolBarItems Move (SizeOfArray(ToolBarItems)) To iCount Move sItem To ToolBarItems[iCount].sItem Set pToolBarItems To ToolBarItems End End_Procedure // There's also a more advanced option to create a toolbar button. // An option that has a lot more configuration options. // Here custom.id becomes the id to use in the onToolBarButtonClick event. // // https://ej2.syncfusion.com/documentation/grid/tool-bar/ Procedure AddToolbarCustomItem tsfWebListToolBarCustomItem custom Integer iCount tsfWebListToolBarItem[] ToolBarItems If (custom.sId<>"") Begin Get pToolBarItems To ToolBarItems Move (SizeOfArray(ToolBarItems)) To iCount Move "Button" To custom.sType Move custom To ToolBarItems[iCount].custom Set pToolBarItems To ToolBarItems End End_Procedure Procedure EnableToolBarItem String sID Boolean bEnabled Boolean bIsCustom String[] aParams Move sID To aParams[0] Move bEnabled To aParams[1] If (Num_Arguments=2) Begin Move True To aParams[2] End Else Begin Move bIsCustom To aParams[2] End Send ClientAction "enableToolBarItem" aParams End_Procedure Procedure MoveDownRow Send ClientAction "moveDownRow" End_Procedure Procedure MoveUpRow Send ClientAction "moveUpRow" End_Procedure Procedure MoveToFirstRow Send ClientAction "moveToFirstRow" End_Procedure Procedure MoveToLastRow Send ClientAction "moveToLastRow" End_Procedure // Selects a specific row by its row index. Procedure MoveToRow Integer iRowIndex String[] aParams Move iRowIndex to aParams[0] Send ClientAction "moveToRow" aParams End_Procedure // Selects a specific row by its rowid. Procedure MoveToRowByID String sRowID String[] aParams Move sRowID to aParams[0] Send ClientAction "moveToRowByID" aParams End_Procedure // Special augmentation for weblists. If this is not a dataaware grid, we want the server // to be 0. We also want any child DEOs to have a 0 server, which they will { NoDoc=True } Function Server Returns Integer Boolean bDataAware Handle hoServer // note we use the property and not the web-property. Even though this is a web-property // it is not expected that this would ever be webset changed Get pbDataAware to bDataAware If (bDataAware) Begin Forward Get Server to hoServer End Function_Return hoServer End_Function Procedure RestoreLayout tGridLayout Layout String[] aParams tWebValueTree tVT ValueTreeSerializeParameter Layout to tVT Send ClientAction "restoreLayout" aParams tVT End_Procedure Procedure ResetLayout Send ClientAction "resetLayout" End_Procedure Procedure GetRowSelection Send ClientAction "getRowSelection" End_Procedure Procedure OnSelectedRows String[] RowIDs End_Procedure Procedure ReturnSelectedRows String[] RowIDs tWebValueTree tVT // Deserialize the sent row Get ptActionData to tVT ValueTreeDeserializeParameter tVT to RowIDs Send OnSelectedRows RowIDs End_Procedure Procedure LayoutHasChanged tWebValueTree tVT tGridLayout Layout // Retrieve and deserialize data Get ptActionData to tVT ValueTreeDeserializeParameter tVT To Layout Send OnLayoutChanged Layout End_Procedure // See DAW doc { MethodType=Event } Procedure OnRowClick String sRowID End_Procedure // See DAW doc { MethodType=Event } Procedure OnRowDoubleClick String sRowID End_Procedure // See DAW doc Procedure OnChangeCurrentRow String sFromRowID String sToRowID End_Procedure Procedure SyncDDOBuffer Handle hoDDO Integer iMainFile String sRowID RowID riRowID Get Server To hoDDO If (hoDDO) Begin WebSet pbGridDDOSyncing To True Get Main_File of hoDDO to iMainFile WebGet psCurrentRowId to sRowID Move (DeserializeRowId(sRowID)) to riRowID //Send ReadByRowId of hoDDO iMainFile riRowID Send FindByRowId of hoDDO iMainFile riRowID WebSet pbGridDDOSyncing To False End End_Procedure // Private { MethodType=Event } Procedure ChangingCurrentRow String sFromRowID String sToRowID Send SyncDDOBuffer Send OnChangeCurrentRow sFromRowID sToRowID End_Procedure // For non built-in Toolbar button's this event is executed when a user // clicks on the button. Procedure OnToolbarButtonClick String sID End_Procedure // Private { MethodType=Event } Procedure ClickingToolbarButton String sID Send SyncDDOBuffer Send OnToolbarButtonClick sID End_Procedure // // An event that you can use to fill up your toolbar button if you're using one. // Procedure OnCreateToolBarItems End_Procedure // // Send each time a user changes the layout so that you have an opportunity to save this // change in layout immediately. // For example when the user reorders a column, hides a column, changes a "group by" // etcetera... Procedure OnLayoutChanged tGridLayout Layout End_Procedure // // Executes before we ask the grid to render itself. // This is a good hook for calling your RestoreLayout logic. // Procedure OnRender End_Procedure // Triggers when the component in the browser is created. (needs to be enabled) { MethodType=Event } Procedure OnCreated End_Procedure Procedure End_Construct_Object tsfWebListToolBarItem[] ToolBarItems WebPublishProcedure ConfigureGrid WebPublishProcedure OnRowClick WebPublishProcedure OnRowDoubleClick WebPublishProcedure ChangingCurrentRow WebPublishProcedure LayoutHasChanged WebPublishProcedure OnCreated WebPublishProcedure ClickingToolbarButton WebPublishProcedure ReturnSelectedRows // Save the toolbar items set outside of onToolBarButtonClick Get pToolBarItems To ToolBarItems Set private_ToolBarItems To ToolBarItems Forward Send End_Construct_Object End_Procedure End_Class