%
'**********************************
' Rico: GENERIC TABLE/VIEW EDITOR
' By Matt Brown
'**********************************
class TableEditTable
Public TblName,alias,arFields,arData,arColInfo(100)
end class
class TableEditClass
Public action,options,AutoInit,CurrentField,LookupField,sessions
Public SvrOnly,gridID,formVar,gridVar,bufferVar,optionsVar,DefaultSort,formView
Private Panels(20)
Private objDB,CurrentPanel,oParseMain
Private xhtmlcloser
Private ErrorFlag,ErrorMsg,MainTbl
Private Tables(30),TableCnt
Private Fields(200),FieldCnt
'*************************************************************************************
' Class Constructor
'*************************************************************************************
Private Sub Class_Initialize
dim a,resize,i
if IsObject(oDB) then set objDB=oDB ' use oDB global as database connection, if it exists
set options = CreateObject("Scripting.Dictionary")
options("TableSelectNew")="___new___"
options("TableSelectNone")=""
options("canAdd")=true
options("canEdit")=true
options("canDelete")=true
options("ConfirmDelete")=true
options("ConfirmDeleteCol")=-1
options("DebugFlag")=(trim(Request.QueryString("debug"))<>"")
options("prefetchBuffer")=true
options("PanelNamesOnTabHdr")=true
options("highlightElem")="menuRow"
set SvrOnly = CreateObject("Scripting.Dictionary")
SvrOnly("DropDownSelect")=1
SvrOnly("SelectSql")=1
SvrOnly("SelectFilter")=1
SvrOnly("TableIdx")=1
SvrOnly("AddQuotes")=1
SvrOnly("FilterFlag")=1
SvrOnly("XMLprovider")=1
xhtmlcloser=">"
FieldCnt=-1
CurrentPanel=-1
TableCnt=-1
AutoInit=true
ErrorFlag=false
ErrorMsg=""
formView=true
sessions=true
set oParseMain=new sqlParse
oParseMain.Init(-1)
end Sub
'*************************************************************************************
' Class Destructor
'*************************************************************************************
Private Sub Class_Terminate ' Setup Terminate event.
for i=0 to FieldCnt
set Fields(i)=Nothing
next
set options = Nothing
set SvrOnly = Nothing
set oParseMain = Nothing
end Sub
Public Property Let TableFilter(filter)
oParseMain.AddWhereCondition filter
End Property
' returns field number if successful, empty if error
Public Function AddEntryField(ColumnName,Heading,EntryTypeCode,DefaultValue)
if InStr("/S/N/R/H/D/DT/I/F/B/T/TA/SL/RL/CL/tinyMCE/","/" & EntryTypeCode & "/") < 1 then
TableEditError "invalid EntryTypeCode in TableEditClass"
exit Function
end if
if not IncrCurrentField then exit Function
CurrentField("ColName")=ColumnName
CurrentField("Hdg")=Heading
CurrentField("EntryType")=EntryTypeCode
CurrentField("ColData")=DefaultValue
select case EntryTypeCode
case "D": CurrentField("type")="date"
case "DT": CurrentField("type")="datetime"
case "TA","tinyMCE" : CurrentField("TxtAreaRows")=4 : CurrentField("TxtAreaCols")=80
case "R","RL": CurrentField("RadioBreak")="
0 Then s="rtrim(" & s & ")"
oParseMain.AddColumn s,"rico_col" & FieldCnt
AddEntryField=FieldCnt
end Function
' returns field number if successful, empty if error
Public Function AddEntryFieldW(ColumnName,Heading,EntryTypeCode,DefaultValue,Width)
dim retval
retval=AddEntryField(ColumnName,Heading,EntryTypeCode,DefaultValue)
if not IsEmpty(retval) then CurrentField("width")=Width
AddEntryFieldW=retval
end Function
' DescColName is optional - pass empty if not used
Public Function AddLookupField(CodeColName,DescColName,CodeHdg,DisplayHdg,EntryTypeCode,DefaultValue,sql)
dim alias,s,codeField,descField,oParseLookup
AddLookupField=AddEntryField(CodeColName,CodeHdg,EntryTypeCode,DefaultValue)
CurrentField("visible")=false
CurrentField("SelectSql")=sql
if not IsEmpty(DescColName) then
CurrentField("DescriptionField")=ExtFieldId(FieldCnt+1)
end if
set LookupField=CurrentField
set oParseLookup=new sqlParse
alias="t" & FieldCnt
oParseLookup.ParseSelect sql
if ubound(oParseLookup.arSelList)=1 then
codeField=oParseLookup.arSelList(0)
descField=oParseLookup.arSelList(1)
s="left join " & oParseLookup.FromClause & " " & alias & " on t." & CodeColName & "=" & alias & "." & replace(replace(codeField,"%alias%",""),"%aliasmain%","")
if not IsEmpty(oParseLookup.WhereClause) then s=s & " and " & replace(oParseLookup.WhereClause,"%alias%",alias & ".")
oParseMain.AddJoin s
IncrCurrentField
CurrentField("ColName")="Lookup_" & FieldCnt
CurrentField("Hdg")=DisplayHdg
If not IsEmpty(DescColName) then
descField=Tables(MainTbl).alias & "." & DescColName
CurrentField("ColName")=DescColName
CurrentField("FormView")="hidden"
CurrentField("EntryType")="T"
ElseIf IsFieldName(descField) Then
descField=alias & "." & descField
Else
descField=replace(replace(descField,"%alias%",alias & "."),"%aliasmain%","t.")
End If
oParseMain.AddColumn descField,"rico_col" & FieldCnt
else
TableEditError "Invalid lookup query (" & sql & ")"
end if
set oParseLookup = Nothing
end Function
' returns field number if successful, empty if error
Public Function AddCalculatedField(ByVal ColumnFormula, ByVal Heading)
if not IncrCurrentField then exit Function
if left(ColumnFormula,1) <> "(" then ColumnFormula="(" & ColumnFormula & ")"
CurrentField("ColName")="Calc_" & FieldCnt
CurrentField("Hdg")=Heading
oParseMain.AddColumn ColumnFormula,"rico_col" & FieldCnt
AddCalculatedField=FieldCnt
end Function
Public Sub AddPanel(ByVal PanelHeading)
if CurrentPanel >= ubound(Panels) then
TableEditError "exceeded max # of panels in TableEditClass"
exit sub
end if
CurrentPanel=CurrentPanel+1
Panels(CurrentPanel)=PanelHeading
end Sub
Public Function DefineAltTable(ByVal AltTabName, arFieldList, arFieldData)
if TableCnt >= ubound(Tables) then
TableEditError "exceeded max # of alternate tables in TableEditClass"
exit Function
end if
TableCnt=TableCnt+1
set Tables(TableCnt)=new TableEditTable
with Tables(TableCnt)
.TblName=AltTabName
.alias="a" & TableCnt
.arFields=arFieldList
.arData=arFieldData
if ubound(.arFields) <> ubound(.arData) then
TableEditError "# of fields does not match # of data entries supplied for table " & AltTabName
exit Function
end if
end with
DefineAltTable=TableCnt
end Function
' returns true if FieldCnt successfully incremented
Private Function IncrCurrentField
if FieldCnt >= ubound(Fields) then
TableEditError "exceeded max # of columns in TableEditClass"
IncrCurrentField=false
exit Function
end if
FieldCnt=FieldCnt+1
set CurrentField = CreateObject("Scripting.Dictionary")
set Fields(FieldCnt)=CurrentField
if CurrentPanel>=0 then CurrentField("panelIdx")=CurrentPanel else CurrentField("panelIdx")=0
CurrentField("AddQuotes")=true
CurrentField("ReadOnly")=false
CurrentField("TableIdx")=MainTbl
IncrCurrentField=true
end Function
Public Sub SetTableName(ByVal s)
dim actionparm
TableCnt=TableCnt+1
MainTbl=TableCnt
set Tables(TableCnt)=new TableEditTable
with Tables(TableCnt)
.TblName=s
.alias="t"
end with
oParseMain.FromClause=s & " t"
gridID=LCase(replace(replace(s,".","_")," ","_"))
formVar=gridID & "['edit']"
gridVar=gridID & "['grid']"
bufferVar=gridID & "['buffer']"
optionsVar=gridID & "['options']"
actionparm="_action_" & gridID
action=trim(Request.QueryString(actionparm))
if action="" then action=trim(Request.Form(actionparm))
if action="" then action="table" else action=lcase(action)
end Sub
Private Sub AddSort(field,direction)
if not IsEmpty(DefaultSort) then DefaultSort=DefaultSort & ","
DefaultSort=DefaultSort & field & " " & direction
end Sub
Public Sub SortCurrent(direction)
AddSort oParseMain.LastColumn,direction
options("sortCol")=FieldCnt
options("sortDir")=direction
end Sub
Public Sub SortAsc()
SortCurrent "ASC"
end Sub
Public Sub SortDesc()
SortCurrent "DESC"
end Sub
Public Sub ConfirmDeleteColumn()
options("ConfirmDeleteCol")=FieldCnt
end Sub
Public Sub genXHTML()
xhtmlcloser=" />"
end Sub
Public Sub SetDbConn(ByRef dbcls)
set objDB=dbcls
end Sub
'*************************************************************************************
' Take appropriate action
'*************************************************************************************
Public Sub DisplayPage()
if FieldCnt < 0 then exit sub
if not ErrorFlag then GetColumnInfo
if not ErrorFlag then
select case action
case "del" if options("canDelete") then TableDeleteRecord
case "ins" if options("canAdd") then TableInsertRecord
case "upd" if options("canEdit") then TableUpdateRecord
case else
if sessions then session.contents(gridID)=SqlSelectData
TableDisplay
end select
end if
if ErrorFlag then
response.write vbLf & "
ERROR ENCOUNTERED
" & objDB.LastErrorMsg
exit sub
end if
for c=0 to cnt-1
colname=trim(Columns(c).ColName)
if dicColIdx.exists(i & "." & colname) then
FieldNum=dicColIdx(i & "." & colname)
set Fields(FieldNum)("ColInfo")=Columns(c)
elseif i<>MainTbl then
for j=0 to ubound(Tables(i).arFields)
if colname=Tables(i).arFields(j) then set Tables(i).arColInfo(j)=Columns(c)
next
elseif Columns(c).IsPKey then
TableEditError "primary key field is not defined (" & Tables(i).TblName & "." & colname & ")"
set dicColIdx = Nothing
exit sub
end if
next
next
set dicColIdx = Nothing
end sub
Private sub TableUpdateDatabase(ByVal sqltext, ByVal actiontxt)
dim errmsg,cnt
if ErrorFlag then exit sub
cnt=objDB.RunActionQueryReturnMsg(sqltext,errmsg)
if IsEmpty(errmsg) and cnt=1 then
response.write "
" & sqltext & "
0 and v=options("TableSelectNone") then
addquotes=false
v="NULL"
end if
if addquotes then v=objDB.addQuotes(v)
FormatValue=v
end function
Private function FormatFormValue(idx)
dim v
if not Fields(idx).exists("EntryType") then exit function
if Fields(idx)("EntryType")="H" or Fields(idx)("FormView")="exclude" then
v=Fields(idx)("ColData")
else
v=trim(Request.Form(ExtFieldId(idx)))
end if
FormatFormValue=FormatValue(v,idx)
end function
'*************************************************************************************
' Deletes the specified record
' Assumes any AltTable columns are handled via referential integrity/cascading deletes
'*************************************************************************************
Private sub TableDeleteRecord()
TableUpdateDatabase "DELETE FROM " & Tables(MainTbl).TblName & TableKeyWhereClause(), "deleted"
end sub
Private sub UpdateRecord(sqltext)
dim errmsg
objDB.RunActionQueryReturnMsg sqltext,errmsg
if not IsEmpty(errmsg) then
errmsg="unable to update database!
SQL: " & sqltext
TableEditError errmsg
elseif options("DebugFlag") then
response.write "
" & sqltext
end if
end sub
Private sub UpdateAltTableRecords(i)
dim j,sqltext,colnames,coldata,c
if ErrorFlag then exit sub
' delete existing record
sqltext="delete from " & Tables(i).TblName
sqltext=sqltext & TableKeyWhereClause()
sqltext=sqltext & AltTableKeyWhereClause(i)
UpdateRecord(sqltext)
' insert new record
colnames=""
coldata=""
for j=0 to FieldCnt
if Fields(j).exists("ColInfo") then
if Fields(j)("TableIdx")=i or Fields(j)("ColInfo").IsPKey then
colnames=colnames & "," & Fields(j)("ColName")
coldata=coldata & "," & FormatValue(trim(Request.Form(ExtFieldId(j))),j)
end if
end if
next
for j=0 to ubound(Tables(i).arFields)
c=Tables(i).arFields(j)
colnames=colnames & "," & c
coldata=coldata & "," & Tables(i).arData(j)
next
sqltext="insert into " & Tables(i).TblName & " (" & mid(colnames,2) & ") values (" & mid(coldata,2) & ")"
UpdateRecord(sqltext)
end sub
'*************************************************************************************
' Updates an existing record in the db
'*************************************************************************************
Private sub TableUpdateRecord()
dim i,sqltext
for i=0 to TableCnt
if i<>MainTbl then UpdateAltTableRecords i
next
for i=0 to FieldCnt
if not IsCalculatedField(i) then
if Fields(i)("TableIdx")=MainTbl and Fields(i)("ColInfo").Writeable and not Fields(i).exists("InsertOnly") then
sqltext=sqltext & "," & Fields(i)("ColName") & "=" & FormatFormValue(i)
end if
end if
next
sqltext="UPDATE " & Tables(MainTbl).TblName & " SET " & mid(sqltext,2)
sqltext=sqltext & TableKeyWhereClause()
TableUpdateDatabase sqltext, "updated"
end sub
'*************************************************************************************
' Inserts a new record into the db
'*************************************************************************************
Private sub TableInsertRecord()
dim i,sqltext,sqlcol,sqlval,keyCnt,keyIdx
keyCnt=0
sqlcol=""
sqlval=""
for i=0 to FieldCnt
if not IsCalculatedField(i) and Fields(i)("TableIdx")=MainTbl and not Fields(i).exists("UpdateOnly") then
if Fields(i)("ColInfo").IsPKey then
keyCnt=keyCnt+1
keyIdx=i
end if
if Fields(i)("ColInfo").Writeable then
sqlcol=sqlcol & "," & Fields(i)("ColName")
sqlval=sqlval & "," & FormatFormValue(i)
end if
end if
next
sqltext="insert into " & Tables(MainTbl).TblName & " (" & mid(sqlcol,2) & ") values (" & mid(sqlval,2) & ")"
TableUpdateDatabase sqltext, "added"
end sub
Private Sub TableEditError(msg)
ErrorFlag=true
ErrorMsg=msg
End Sub
Private Function IsFieldName(s)
dim i,c
i=1
IsFieldName=false
while i <= len(s)
c=mid(s,i,1)
if (c >= "0" and c <= "9" and i > 1) or (c >= "A" and c <= "Z") or (c >= "a" and c <= "z") or (c = "_") then
i=i+1
else
exit function
end if
wend
IsFieldName=(i > 1)
End Function
'***********************************
' do post-processing on sql query
'***********************************
Private sub FinishQuery()
dim oParseLookup
dim i,s,codeField,descField,descQuery,alias,tabidx
set oParseLookup=new sqlParse
for i=0 to FieldCnt
if Fields(i).exists("TableIdx") then tabidx=Fields(i)("TableIdx")
if Fields(i).exists("FilterFlag") then
' add any column filters to where clause
oParseMain.AddWhereCondition Tables(tabidx).alias & "." & Fields(i)("ColName") & "='" & Fields(i)("ColData") & "'"
end if
if Fields(i).exists("EntryType") then
if InStr("CSNR",left(Fields(i)("EntryType"),1)) > 0 then
if Fields(i).exists("SelectSql") then
s=Fields(i)("SelectSql")
if Fields(i).exists("SelectFilter") then
oParseLookup.ParseSelect s
oParseLookup.AddWhereCondition Fields(i)("SelectFilter")
s=oParseLookup.UnparseSelect
end if
Fields(i)("DropDownSelect")=replace(replace(s,"%alias%",""),"%aliasmain%","")
else
s=Fields(i)("ColName")
If Fields(i).exists("ColInfo") Then
If Fields(i)("ColInfo").ColType="CHAR" and Fields(i)("ColInfo").FixedLength Then s="rtrim(" & s & ")"
End If
Fields(i)("DropDownSelect")="select distinct " & s & " from " & Tables(tabidx).TblName & " where " & Fields(i)("ColName") & " is not null"
end if
end if
end if
if tabidx<>MainTbl then
' column from alt table - no avoiding subqueries here
s="(select " & Fields(i)("ColName") & " from " & Tables(tabidx).TblName & " a" & i & _
" where " & AltTableJoinClause("t") & AltTableKeyWhereClause(tabidx) & ")"
if mid(Fields(i)("EntryType"),2)="L" and Fields(i).exists("SelectSql") then
oParseLookup.ParseSelect Fields(i)("SelectSql")
if ubound(oParseLookup.arSelList)=1 then
codeField=oParseLookup.arSelList(0)
descField=oParseLookup.arSelList(1)
descQuery="select " & descField & " from " & oParseLookup.FromClause & " where " & codeField & "=" & s
if not IsEmpty(oParseLookup.WhereClause) then descQuery=descQuery & " and " & oParseLookup.WhereClause
oParseMain.arSelList(i)="(" & objDB.concat(Array("(" & descQuery & ")","''",objDB.Convert2Char(s),"''"), false) & ")"
else
TableEditError "Invalid lookup query (" & Fields(i)("SelectSql") & ")"
exit sub
end if
else
oParseMain.arSelList(i)=s
end if
end if
next
if IsEmpty(DefaultSort) then DefaultSort=objDB.PrimaryKey(Tables(MainTbl).TblName)
oParseMain.AddSort DefaultSort
End Sub
'***********************************
' returns details of sql query as an array
'***********************************
Public Function SqlSelectData()
dim arr,i,SelectIdx,HdgIdx,a,b
FinishQuery
arr=oParseMain.ToArray()
ReDim Preserve arr(ubound(arr)+2)
HdgIdx=ubound(arr)
SelectIdx=HdgIdx-1
ReDim a(FieldCnt)
arr(SelectIdx)=a
ReDim b(FieldCnt)
arr(HdgIdx)=b
for i=0 to FieldCnt
if Fields(i).exists("DropDownSelect") then arr(SelectIdx)(i)=Fields(i)("DropDownSelect")
if Fields(i).exists("Hdg") then arr(HdgIdx)(i)=Fields(i)("Hdg")
next
SqlSelectData=arr
end Function
'***********************************
' Displays a table
'***********************************
Private sub TableDisplay()
dim i,o
response.write vbLf & "
" response.write "" response.write " " response.write "" response.write "
" response.write vbLf & "" response.write vbLf & "" end sub '******************************************************************************************************** ' Pad a number to the specified length with leading zeroes '******************************************************************************************************** Private Function PadNumber(number, length) dim strNumber if IsNull(number) or IsEmpty(number) then strNumber=String(length,"-") else strNumber = Cstr(number) do while len(strNumber) < length strNumber = "0" & strNumber loop PadNumber=strNumber End Function Private Function FormatOption(s) if IsArray(s) then FormatOption="{" & join(s,",") & "}" else select case vartype(s) case 8,129,130,200,202 ' string FormatOption="""" & replace(s,"""","\""") & """" case 11 ' boolean if s then FormatOption="true" else FormatOption="false" case 7,133,134,135: ' date/time, format as ISO8601 FormatOption="'" & year(s) & "-" & PadNumber(month(s),2) & "-" & PadNumber(day(s),2) & "T" & PadNumber(hour(s),2) & ":" & PadNumber(minute(s),2) & ":" & PadNumber(second(s),2) & "'" case 4,5,14 'single, double, decimal variants. Changing ',' to '.' FormatOption=replace(CStr(s),",",".") case else FormatOption=s end select end if End Function Public function InitScript() InitScript = vbLf & bufferVar & "=new Rico.Buffer.AjaxSQL('" & options("XMLprovider") & "', {TimeOut:" & Session.Timeout & "});" & _ vbLf & "if(typeof " & gridID & "_GridInit=='function') " & gridID & "_GridInit();" & _ vbLf & gridVar & "=new Rico.LiveGrid ('" & gridID & "'," & bufferVar & "," & optionsVar & ");" & _ vbLf & gridVar & ".menu=new Rico.GridMenu();" if formView then InitScript = InitScript & vbLf & "if(typeof " & gridID & "_FormInit=='function') " & gridID & "_FormInit();" & _ vbLf & formVar & "=new Rico.TableEdit(" & gridVar & ");" end if InitScript = InitScript & vbLf & "if(typeof " & gridID & "_InitComplete=='function') " & gridID & "_InitComplete();" end function end class %>