====== O4W Sample Stored Procedures ======
=== O4W_EXAMPLE0 ===
Subroutine O4W_EXAMPLE0(CtlEntId, Event, Request)
* Example #0: A simple entry/collection form
*
* Always include our equates
$Insert O4WEquates
*
* Determine how we were called, and what to do
*
Begin Case
Case event _eqc "CREATE"
* Creation event - called the first time through for each application
* Specify that this will generate a full web page
O4WForm()
* Put up the 'header' describing the page
O4WHeader("Revelation Software POS (Pizza Ordering System)", 4)
* "Space down" a few blank lines
O4WBreak()
O4WBreak()
* Use a table to align everything neatly
O4WTableStart("mainTable")
* Display a prompt in the first 'cell' of the table
O4WSetCell(1,1)
O4WText("Delivery Address: ")
* And put up a 'textbox' for the response in the next 'cell'
O4WSetCell(1,2)
O4WTextbox('','' ,'' , 'ADD1')
* Repeat for the other desired information
* Notice the shortcut: only specifying the 'row number' to O4WSetCell automatically puts you in the first column of that row
O4WSetCell(2)
O4WText("Address 2:")
* Notice the shortcut: if neither the row nor column is specified in O4WSetCell, it automatically puts you in the next column of the current row
O4WSetCell()
O4WTextbox('','','','ADD2')
O4WSetCell(3)
O4WText("City:")
O4WSetCell()
O4WTextBox('','','','CITY')
O4WSetCell(4)
O4WText("State:")
O4WSetCell()
O4WTextBox('','','','STATE')
O4WSetCell(5)
O4WText("Zip:")
O4WSetCell()
O4WTextBox('','','','ZIP')
O4WSetCell(6)
O4WText("Pizza Size:")
O4WSetCell()
* Display a list of choices as radio buttons (allowing only a single choice)
O4WRadioButton("Small", "S", "SIZE")
O4WRadioButton("Medium", "M", "SIZE")
O4WRadioButton("Large", "L", "SIZE")
O4WSetCell(7)
O4WText("Toppings:")
O4WSetCell()
* Display a list of toppings as checkboxes (allowing multiple choices)
O4WCheckBox("Pepperoni", "P", "TOPPINGS")
O4WBreak()
O4WCheckBox("Sausage", "S", "TOPPINGS")
O4WBreak()
O4WCheckBox("Extra Cheese", "C", "TOPPINGS")
O4WBreak()
O4WCheckBox("Mushrooms", "M", "TOPPINGS")
* End the table
O4WTableEnd("mainTable")
O4WBreak()
* Display a button for them to submit the order
O4WButton("Order!", "BTNORDER")
* Tell O4W you wish to be notified when the user clicks on this button
O4WQualifyEvent("BTNORDER", "CLICK")
Case event _eqc "CLICK"
* Click event - called when the button is pressed
* Read in all the values
ADD1 = O4WGetValue("ADD1")
ADD2 = O4WGetValue("ADD2")
CITY = O4WGetValue("CITY")
STATE = O4WGetValue("STATE")
ZIP = O4WGetValue("ZIP")
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* Calculate the price from the toppings and size selected
cost = 0
Begin Case
Case SIZE = "S"
cost = 700
Case SIZE = "M"
cost = 1000
Case SIZE = "L"
cost = 1300
Case 1
* Not a valid size - return an error
O4WError("We're sorry, but the size '":size:"' doesn't appear to be valid!")
Return
End Case
* Now find each of the toppings
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Begin Case
Case THIS.TOPPING = "P"
cost += 100
Case THIS.TOPPING = "S"
cost += 100
Case THIS.TOPPING = "C"
cost += 50
Case THIS.TOPPING = "M"
cost += 100
Case 1
* Not a valid topping? Report an error
O4WError("We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!")
Return
End Case
Next each.topping
* In a 'real' application, you'd now write all the information we collected into a database somewhere
orderNum = DATE():"*":TIME()
*
* Notify the customer that his order has been received, and give him/her the total
O4WError('Thank you for your order! Your order number is ':orderNum:'. Your total is ':OCONV(cost,'MD2,$'):'.', 'Thank You')
End Case
*
Return 0
{{image688.jpg?625x267}}
{{image690.jpg?622x288}}
=== O4W_EXAMPLE1 ===
Subroutine O4W_EXAMPLE1(CtlEntId, Event, Request)
* Example #1: A simple entry/collection form
*
* example 1: establish some constants we'll use in the example
Equ SizeList$ To "Small,Medium,Large"
Equ SizeCode$ To "S,M,L"
Equ SizeCost$ To "700,1000,1300"
*
Equ ToppingList$ To "Pepperoni,Sausage,Extra Cheese,Mushrooms"
Equ ToppingCode$ To "P,S,C,M"
Equ ToppingCost$ To "100,100,50,100"
*
* Always include our equates
$Insert O4WEquates
*
* Determine how we were called, and what to do
*
Begin Case
Case event _eqc "CREATE"
* Creation event - called the first time through for each application
* Specify that this will generate a full web page
O4WForm()
* example 1: Define the section that the form will go in
O4WSectionStart('mainSection')
* Put up the 'header' describing the page
O4WHeader("Revelation Software POS (Pizza Ordering System)", 4)
* "Space down" a few blank lines
O4WBreak()
O4WBreak()
* Use a table to align everything neatly
O4WTableStart("mainTable")
* Display a prompt in the first 'cell' of the table
O4WSetCell(1,1)
O4WText("Delivery Address: ")
* And put up a 'textbox' for the response in the next 'cell'
O4WSetCell(1,2)
O4WTextbox('','' ,'' , 'ADD1')
* Repeat for the other desired information
* Notice the shortcut: only specifying the 'row number' to O4WSetCell automatically puts you in the first column of that row
O4WSetCell(2)
O4WText("Address 2:")
* Notice the shortcut: if neither the row nor column is specified in O4WSetCell, it automatically puts you in the next column of the current row
O4WSetCell()
O4WTextbox('','','','ADD2')
O4WSetCell(3)
O4WText("City:")
O4WSetCell()
O4WTextBox('','','','CITY')
O4WSetCell(4)
O4WText("State:")
O4WSetCell()
O4WTextBox('','','','STATE')
O4WSetCell(5)
O4WText("Zip:")
O4WSetCell()
O4WTextBox('','','','ZIP')
O4WSetCell(6)
O4WText("Pizza Size:")
O4WSetCell()
* Display a list of choices as radio buttons (allowing only a single choice)
* example 1: Instead of hard-coding the choices...
/*
O4WRadioButton("Small", "S", "SIZE")
O4WRadioButton("Medium", "M", "SIZE")
O4WRadioButton("Large", "L", "SIZE")
*/
*...it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.SIZES = DCount(SizeList$, ",")
For each.size = 1 To num.sizes
this.size = Field(SizeList$, ",", each.size)
this.code = Field(SizeCode$, ",", each.size)
O4WRadioButton(this.size, this.code, "SIZE")
Next each.size
O4WSetCell(7)
O4WText("Toppings:")
O4WSetCell()
* Display a list of toppings as checkboxes (allowing multiple choices)
* example 1: instead of hard-coding the choices...
/*
O4WCheckBox("Pepperoni", "P", "TOPPINGS")
O4WBreak()
O4WCheckBox("Sausage", "S", "TOPPINGS")
O4WBreak()
O4WCheckBox("Extra Cheese", "C", "TOPPINGS")
O4WBreak()
O4WCheckBox("Mushrooms", "M", "TOPPINGS")
*/
*...it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.TOPPINGS = DCount(ToppingList$, ",")
For each.topping = 1 To num.toppings
this.topping = Field(ToppingList$, ",", each.topping)
this.code = Field(ToppingCode$, ",", each.topping)
O4WCheckBox(this.topping, this.code, "TOPPINGS")
O4WBreak()
Next each.topping
* End the table
O4WTableEnd("mainTable")
O4WBreak()
* Display a button for them to submit the order
O4WButton("Order!", "BTNORDER")
* Tell O4W you wish to be notified when the user clicks on this button
O4WQualifyEvent("BTNORDER", "CLICK")
* example 1: finish up the main section we defined
O4WSectionEnd('mainSection')
* example 1: create a special area for us to use when displaying some response to the user
* nothing goes in it now, but we may fill it in later
O4WSectionStart('responseArea')
O4WSectionEnd('responseArea')
Case event _eqc "CLICK"
* Click event - called when the button is pressed
* example 1: Tell O4W we'll be generating a response updating the current form (as opposed to making a whole new form)
O4WResponse()
* Read in all the values
ADD1 = O4WGetValue("ADD1")
ADD2 = O4WGetValue("ADD2")
CITY = O4WGetValue("CITY")
STATE = O4WGetValue("STATE")
ZIP = O4WGetValue("ZIP")
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* example 1: calculate the price from the toppings and size selected, using the equated list
locate size In SizeCode$ Using "," Setting pos Then
cost = Field(SizeCost$,",",pos)
End Else
* Couldn't find the size in the list? Report an error to the customer
O4WError("We're sorry, but the size '":size:"' doesn't appear to be valid!")
Return
End
* example 1: Now find each of the toppings in the equated list
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Locate this.topping In ToppingCode$ Using "," Setting pos Then
cost += Field(ToppingCost$, ",", pos)
End Else
* Couldn't find the topping in the list? Report an error
O4WError("We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!")
End
Next each.topping
* In a 'real' application, you'd now write all the information we collected into a database somewhere
orderNum = DATE():"*":TIME()
*
* Notify the customer that his order has been received, and give him/her the total
* example 1: We'll put this information into our 'responseArea'
* Note that we use a special style so that O4W knows we're updating the previously-defined area (and not asking to create a new one)
O4WSectionStart('responseArea', O4WResponseStyle())
O4WHeader('Your order number is ':orderNum, 4)
O4WBreak()
O4WText('Thank you for your order! Your order total is ':OCONV(cost,'MD2,$'):'.')
O4WBreak()
O4WText('Please press ')
* Build a 'link' to return to the home page
O4WLink('here', O4W_LINKTYPE_NORMAL$, 'www.revelation.com')
O4WText(' to return to the home page')
O4WSectionEnd('responseArea')
* Display this area as a 'dialog box' to the user
O4WDialog('responseArea', 'Thank You')
End Case
*
Return 0
{{image692.jpg?625x269}}
{{image694.jpg?625x288}}
=== O4W_EXAMPLE2 ===
Subroutine O4W_EXAMPLE2(CtlEntId, Event, Request)
* Example #2: A simple entry/collection form with some dynamic updates
*
* Establish some constants we'll use in the example
Equ SizeList$ To "Small,Medium,Large"
Equ SizeCode$ To "S,M,L"
Equ SizeCost$ To "700,1000,1300"
*
Equ ToppingList$ To "Pepperoni,Sausage,Extra Cheese,Mushrooms"
Equ ToppingCode$ To "P,S,C,M"
Equ ToppingCost$ To "100,100,50,100"
*
* Always include our equates
$Insert O4WEquates
*
* Determine how we were called, and what to do
*
Begin Case
Case event _eqc "CREATE"
* Creation event - called the first time through for each application
* Specify that this will generate a full web page
O4WForm()
* Define the section that the form will go in
O4WSectionStart('mainSection')
* Put up the 'header' describing the page
O4WHeader("Revelation Software POS (Pizza Ordering System)", 4)
* "Space down" a few blank lines
O4WBreak()
O4WBreak()
* Use a table to align everything neatly
O4WTableStart("mainTable")
* Display a prompt in the first 'cell' of the table
O4WSetCell(1,1)
O4WText("Delivery Address: ")
* And put up a 'textbox' for the response in the next 'cell'
O4WSetCell(1,2)
O4WTextbox('','' ,'' , 'ADD1')
* Repeat for the other desired information
* Notice the shortcut: only specifying the 'row number' to O4WSetCell automatically puts you in the first column of that row
O4WSetCell(2)
O4WText("Address 2:")
* Notice the shortcut: if neither the row nor column is specified in O4WSetCell, it automatically puts you in the next column of the current row
O4WSetCell()
O4WTextbox('','','','ADD2')
O4WSetCell(3)
O4WText("City:")
O4WSetCell()
O4WTextBox('','','','CITY')
O4WSetCell(4)
O4WText("State:")
O4WSetCell()
* O4WTextBox('','','','STATE')
* example 2: Use a combo box for the state
* O4W provides a standard 'states' code record in the standard "configuration" file
stateInfo = Xlate("O4WCODES", "CODES_STATES", "", "X")
num.states = dcount(stateInfo<1>, @VM)
* Define a 'default' value to prompt the user
O4WListBox("Select...", "", "STATE")
For each.state = 1 To num.states
state.name = stateInfo<1,each.state>
state.code = stateInfo<2,each.state>
O4WListBox(state.name, state.code, "STATE")
Next each.state
O4WSetCell(5)
O4WText("Zip:")
O4WSetCell()
O4WTextBox('','','','ZIP')
O4WSetCell(6)
O4WText("Pizza Size:")
O4WSetCell()
* Display a list of choices as radio buttons (allowing only a single choice)
* If we wanted to 'hard code' the choices, we could do this:
/*
O4WRadioButton("Small", "S", "SIZE")
O4WRadioButton("Medium", "M", "SIZE")
O4WRadioButton("Large", "L", "SIZE")
*/
* But it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.SIZES = DCount(SizeList$, ",")
For each.size = 1 To num.sizes
this.size = Field(SizeList$, ",", each.size)
this.code = Field(SizeCode$, ",", each.size)
*O4WRadioButton(this.size, this.code, "SIZE")
* example 2: identify each radio button with a unique name
O4WRadioButton(this.size, this.code, "SIZE", "SIZE_":this.code)
Next each.size
O4WSetCell(7)
O4WText("Toppings:")
O4WSetCell()
* Display a list of toppings as checkboxes (allowing multiple choices)
* If we wanted to 'hard code' the choices, we could do this:
/*
O4WCheckBox("Pepperoni", "Pepperoni", "TOPPINGS")
O4WBreak()
O4WCheckBox("Sausage", "Sausage", "TOPPINGS")
O4WBreak()
O4WCheckBox("Extra Cheese", "ExtraCheese", "TOPPINGS")
O4WBreak()
O4WCheckBox("Mushrooms", "Mushrooms", "TOPPINGS")
*/
* But it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.TOPPINGS = DCount(ToppingList$, ",")
For each.topping = 1 To num.toppings
this.topping = Field(ToppingList$, ",", each.topping)
this.code = Field(ToppingCode$, ",", each.topping)
*O4WCheckBox(this.topping, this.code, "TOPPINGS")
* example 2: identify each checkbox with a unique name
O4WCheckBox(this.topping, this.code, "TOPPINGS", "TOPPINGS_":this.code)
O4WBreak()
Next each.topping
* End the table
O4WTableEnd("mainTable")
O4WBreak()
* example 2: define an area where the 'running total' can go
O4WSectionStart('runningTotal')
O4WSectionEnd('runningTotal')
* Display a button for them to submit the order
O4WButton("Order!", "BTNORDER")
* Tell O4W you wish to be notified when the user clicks on this button
O4WQualifyEvent("BTNORDER", "CLICK")
* example 2: Tell O4W we want to be notified when the size or toppings change
O4WQualifyEvent("TOPPINGS", "CHANGE", "CHECKBOX")
O4WQualifyEvent("SIZE", "CHANGE", "RADIOBUTTON")
* finish up the main section we defined
O4WSectionEnd('mainSection')
* create a special area for us to use when displaying some response to the user
* nothing goes in it now, but we may fill it in later
O4WSectionStart('responseArea')
O4WSectionEnd('responseArea')
Case event _eqc "CLICK"
* Click event - called when the button is pressed
* Tell O4W we'll be generating a response updating the current form (as opposed to making a whole new form)
O4WResponse()
* Read in all the values
ADD1 = O4WGetValue("ADD1")
ADD2 = O4WGetValue("ADD2")
CITY = O4WGetValue("CITY")
STATE = O4WGetValue("STATE")
ZIP = O4WGetValue("ZIP")
* example 2: Make sure these values have something in them
If TRIM(ADD1) = "" Or TRIM(CITY) = "" Or TRIM(STATE) = "" Or TRIM(ZIP)="" Then
O4WError("Please be sure to enter complete address information before proceeding")
Return
End
* example 2: move the extraction of the size and topping values, and the calculation of the cost, to a subroutine so we can call it from the 'change' event too
/*
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* Calculate the price from the toppings and size selected
locate size In SizeCode$ Using "," Setting pos Then
cost = Field(SizeCost$,",",pos)
End Else
* Couldn't find the size in the list? Report an error to the customer
O4WError("We're sorry, but the size '":size:"' doesn't appear to be valid!")
Return
End
* Now find each of the toppings
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Locate this.topping In ToppingCode$ Using "," Setting pos Then
cost += Field(ToppingCost$, ",", pos)
End Else
* Couldn't find the topping in the list? Report an error
O4WError("We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!")
End
Next each.topping
*/
Gosub calcTotal
If error <> "" Then
O4WError(error)
Return
end
* In a 'real' application, you'd now write all the information we collected into a database somewhere
orderNum = DATE():"*":TIME()
*
* Notify the customer that his order has been received, and give him/her the total
* We'll put this information into our 'responseArea'
* Note that we use a special style so that O4W knows we're updating the previously-defined area (and not asking to create a new one)
O4WSectionStart('responseArea', O4WResponseStyle())
O4WHeader('Your order number is ':orderNum, 4)
O4WBreak()
O4WText('Thank you for your order! Your order total is ':OCONV(cost,'MD2,$'):'.')
O4WBreak()
O4WText('Please press ')
* Build a 'link' to return to the home page
O4WLink('here', 0, 'www.revelation.com')
O4WText(' to return to the home page')
O4WSectionEnd('responseArea')
* Display this area as a 'dialog box' to the user
O4WDialog('responseArea', 'Thank You')
Case event _eqc "CHANGE"
* example 2: the 'CHANGE' event is triggered when our toppings or size is changed
* Update our total cost
cost = 0
* Because of how we organized our form, all the values are passed to us when we get the CHANGE event
Gosub calcTotal
If error <> "" Then
* display any error message instead of our total
O4WError(error)
Return
end
* No error - display the total cost
* Tell O4W we're generating an update to the current form and not an entire new form
O4WResponse()
* We'll put this information into our 'runningTotal'
* Note that we use a special style so that O4W knows we're updating the previously-defined area (and not asking to create a new one)
O4WSectionStart('runningTotal', O4WResponseStyle())
O4WText("Current Order Total: ":Oconv(cost, "MD2,$"))
O4WSectionEnd('runningTotal')
End Case
*
Return 0
*
*
* example 2: calcTotal subroutine will pull in the size and toppings info and calculate the cost
* if any errors occur, the variable "error" will be returned with the error text
calcTotal:
error = ""
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* Calculate the price from the toppings and size selected
locate size In SizeCode$ Using "," Setting pos Then
cost = Field(SizeCost$,",",pos)
End Else
* Couldn't find the size in the list? Report an error to the customer
error = "We're sorry, but the size '":size:"' doesn't appear to be valid!"
Return
End
* Now find each of the toppings
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Locate this.topping In ToppingCode$ Using "," Setting pos Then
cost += Field(ToppingCost$, ",", pos)
End Else
* Couldn't find the topping in the list? Report an error
error = "We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!"
return
End
Next each.topping
Return
{{image696.jpg?625x263}}
{{image698.jpg?625x285}}
=== O4W_EXAMPLE3 ===
Subroutine O4W_EXAMPLE3(CtlEntId, Event, Request)
* Example #3: A simple entry/collection form with some dynamic updates, validation, and images
*
* Establish some constants we'll use in the example
Equ SizeList$ To "Small,Medium,Large"
Equ SizeCode$ To "S,M,L"
Equ SizeCost$ To "700,1000,1300"
*
Equ ToppingList$ To "Pepperoni,Sausage,Extra Cheese,Mushrooms"
Equ ToppingCode$ To "P,S,C,M"
Equ ToppingCost$ To "100,100,50,100"
*
* example 3: include some images
Equ imagePath To "../examples/images/pizza"
* Always include our equates
$Insert O4WEquates
* example 3: define a 'validation' style that we can use
requiredStyle = O4WValidateStyle('','required')
*
* Determine how we were called, and what to do
*
Begin Case
Case event _eqc "CREATE"
* Creation event - called the first time through for each application
* Specify that this will generate a full web page
O4WForm()
* Define the section that the form will go in
O4WSectionStart('mainSection')
* Put up the 'header' describing the page
O4WHeader("Revelation Software POS (Pizza Ordering System)", 4)
* "Space down" a few blank lines
O4WBreak()
O4WBreak()
* Use a table to align everything neatly
O4WTableStart("mainTable")
* Display a prompt in the first 'cell' of the table
O4WSetCell(1,1)
O4WText("Delivery Address: ")
* And put up a 'textbox' for the response in the next 'cell'
O4WSetCell(1,2)
* example 3: add in some validation (note that we now provide an "ID" for the textbox, in addition to the "Name")
O4WTextbox('','' ,'' , 'ADD1', "ADD1", requiredStyle)
* Repeat for the other desired information
* Notice the shortcut: only specifying the 'row number' to O4WSetCell automatically puts you in the first column of that row
O4WSetCell(2)
O4WText("Address 2:")
* Notice the shortcut: if neither the row nor column is specified in O4WSetCell, it automatically puts you in the next column of the current row
O4WSetCell()
O4WTextbox('','','','ADD2')
O4WSetCell(3)
O4WText("City:")
O4WSetCell()
* example 3: add in some validation
O4WTextBox('','','','CITY', 'CITY', requiredStyle)
O4WSetCell(4)
O4WText("State:")
O4WSetCell()
* O4WTextBox('','','','STATE')
* Use a combo box for the state
* O4W provides a standard 'states' code record in the standard "configuration" file
stateInfo = Xlate("O4WCODES", "CODES_STATES", "", "X")
num.states = dcount(stateInfo<1>, @VM)
* Define a 'default' value to prompt the user
O4WListBox("Select...", "", "STATE")
For each.state = 1 To num.states
state.name = stateInfo<1,each.state>
state.code = stateInfo<2,each.state>
O4WListBox(state.name, state.code, "STATE")
Next each.state
O4WSetCell(5)
O4WText("Zip:")
O4WSetCell()
* example 3: add in another specific validation for zip codes
O4WTextBox('','','','ZIP', 'ZIP', O4WValidateStyle('','zip','1'))
O4WSetCell(6)
O4WText("Pizza Size:")
O4WSetCell()
* Display a list of choices as radio buttons (allowing only a single choice)
* If we wanted to 'hard code' the choices, we could do this:
/*
O4WRadioButton("Small", "S", "SIZE")
O4WRadioButton("Medium", "M", "SIZE")
O4WRadioButton("Large", "L", "SIZE")
*/
* But it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.SIZES = DCount(SizeList$, ",")
For each.size = 1 To num.sizes
this.size = Field(SizeList$, ",", each.size)
this.code = Field(SizeCode$, ",", each.size)
*O4WRadioButton(this.size, this.code, "SIZE")
* identify each radio button with a unique name
O4WRadioButton(this.size, this.code, "SIZE", "SIZE_":this.code)
Next each.size
* example 3: add another cell to contain the image of the pizza
O4WSetCell()
* example 3: for now, put up the generic cheese image
O4WImage("Mmmm...pizza!", imagePath:"L_.jpg",'','','','imagePizza')
O4WSetCell(7)
O4WText("Toppings:")
O4WSetCell()
* Display a list of toppings as checkboxes (allowing multiple choices)
* If we wanted to 'hard code' the choices, we could do this:
/*
O4WCheckBox("Pepperoni", "Pepperoni", "TOPPINGS")
O4WBreak()
O4WCheckBox("Sausage", "Sausage", "TOPPINGS")
O4WBreak()
O4WCheckBox("Extra Cheese", "ExtraCheese", "TOPPINGS")
O4WBreak()
O4WCheckBox("Mushrooms", "Mushrooms", "TOPPINGS")
*/
* But it's better to drive this from the constants we declared at the top (so we can change them without changing the program logic)
NUM.TOPPINGS = DCount(ToppingList$, ",")
For each.topping = 1 To num.toppings
this.topping = Field(ToppingList$, ",", each.topping)
this.code = Field(ToppingCode$, ",", each.topping)
*O4WCheckBox(this.topping, this.code, "TOPPINGS")
* identify each checkbox with a unique name
O4WCheckBox(this.topping, this.code, "TOPPINGS", "TOPPINGS_":this.code)
O4WBreak()
Next each.topping
* End the table
O4WTableEnd("mainTable")
O4WBreak()
* define an area where the 'running total' can go
O4WSectionStart('runningTotal')
O4WSectionEnd('runningTotal')
* Display a button for them to submit the order
O4WButton("Order!", "BTNORDER")
* Tell O4W you wish to be notified when the user clicks on this button
* example 3: we don't just want to click the button - we want to validate our validations too
*O4WQualifyEvent("BTNORDER", "CLICK")
O4WQualifyEvent("BTNORDER", "VALIDATE")
* Tell O4W we want to be notified when the size or toppings change
O4WQualifyEvent("TOPPINGS", "CHANGE", "CHECKBOX")
O4WQualifyEvent("SIZE", "CHANGE", "RADIOBUTTON")
* finish up the main section we defined
O4WSectionEnd('mainSection')
* create a special area for us to use when displaying some response to the user
* nothing goes in it now, but we may fill it in later
O4WSectionStart('responseArea')
O4WSectionEnd('responseArea')
Case event _eqc "CLICK"
* Click event - called when the button is pressed
* Tell O4W we'll be generating a response updating the current form (as opposed to making a whole new form)
O4WResponse()
* Read in all the values
ADD1 = O4WGetValue("ADD1")
ADD2 = O4WGetValue("ADD2")
CITY = O4WGetValue("CITY")
STATE = O4WGetValue("STATE")
ZIP = O4WGetValue("ZIP")
* Make sure these values have something in them
If TRIM(ADD1) = "" Or TRIM(CITY) = "" Or TRIM(STATE) = "" Or TRIM(ZIP)="" Then
O4WError("Please be sure to enter complete address information before proceeding")
Return
End
* move the extraction of the size and topping values, and the calculation of the cost, to a subroutine so we can call it from the 'change' event too
/*
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* Calculate the price from the toppings and size selected
locate size In SizeCode$ Using "," Setting pos Then
cost = Field(SizeCost$,",",pos)
End Else
* Couldn't find the size in the list? Report an error to the customer
O4WError("We're sorry, but the size '":size:"' doesn't appear to be valid!")
Return
End
* Now find each of the toppings
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Locate this.topping In ToppingCode$ Using "," Setting pos Then
cost += Field(ToppingCost$, ",", pos)
End Else
* Couldn't find the topping in the list? Report an error
O4WError("We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!")
End
Next each.topping
*/
Gosub calcTotal
If error <> "" Then
O4WError(error)
Return
end
* In a 'real' application, you'd now write all the information we collected into a database somewhere
orderNum = DATE():"*":TIME()
*
* Notify the customer that his order has been received, and give him/her the total
* We'll put this information into our 'responseArea'
* Note that we use a special style so that O4W knows we're updating the previously-defined area (and not asking to create a new one)
O4WSectionStart('responseArea', O4WResponseStyle())
O4WHeader('Your order number is ':orderNum, 4)
O4WBreak()
O4WText('Thank you for your order! Your order total is ':OCONV(cost,'MD2,$'):'.')
O4WBreak()
O4WText('Please press ')
* Build a 'link' to return to the home page
O4WLink('here', 0, 'www.revelation.com')
O4WText(' to return to the home page')
O4WSectionEnd('responseArea')
* Display this area as a 'dialog box' to the user
O4WDialog('responseArea', 'Thank You')
Case event _eqc "CHANGE"
* the 'CHANGE' event is triggered when our toppings or size is changed
* Update our total cost
cost = 0
* Because of how we organized our form, all the values are passed to us when we get the CHANGE event
Gosub calcTotal
If error <> "" Then
* display any error message instead of our total
O4WError(error)
Return
end
* No error - display the total cost
* Tell O4W we're generating an update to the current form and not an entire new form
O4WResponse()
* example 3: update the image with our current selections
O4WImage("Mmmm...pizza!", imagePath:imageType:".jpg",'','','','imagePizza', O4WResponseStyle('','','1'))
* We'll put this information into our 'runningTotal'
* Note that we use a special style so that O4W knows we're updating the previously-defined area (and not asking to create a new one)
O4WSectionStart('runningTotal', O4WResponseStyle())
O4WText("Current Order Total: ":Oconv(cost, "MD2,$"))
O4WSectionEnd('runningTotal')
End Case
*
Return 0
*
*
* calcTotal subroutine will pull in the size and toppings info and calculate the cost
* if any errors occur, the variable "error" will be returned with the error text
* example 3: also create imageType (with details about which picture to display)
calcTotal:
error = ""
* 'SIZE' will return the S/M/L code from the SIZE radio buttons
SIZE = O4WGetValue("SIZE")
* example 3: make sure a size is selected
If size = "" Then
error = "We're sorry, but you must select a size to continue"
Return
End
* 'TOPPINGS' will return an @VM-delimited list of the selected toppings
TOPPING = O4WGetValue("TOPPINGS")
* Calculate the price from the toppings and size selected
locate size In SizeCode$ Using "," Setting pos Then
cost = Field(SizeCost$,",",pos)
End Else
* Couldn't find the size in the list? Report an error to the customer
error = "We're sorry, but the size '":size:"' doesn't appear to be valid!"
Return
End
* Now find each of the toppings
num.toppings = dcount(topping, @VM)
For each.topping = 1 To num.toppings
this.topping = topping<1,each.topping>
Locate this.topping In ToppingCode$ Using "," Setting pos Then
cost += Field(ToppingCost$, ",", pos)
End Else
* Couldn't find the topping in the list? Report an error
error = "We're sorry, but the topping '":this.topping:"' doesn't appear to be valid!"
return
End
Next each.topping
* example 3
* always show 'large' pizza
* imageType = size:"_"
imageType = "L_"
* don't show anything special for 'extra cheese'
* If Index(topping, "C", 1) Then imageType := "C"
If Index(topping, "M", 1) Then imageType := "M"
If Index(topping, "P", 1) Then imageType := "P"
If Index(topping, "S", 1) Then imageType := "S"
Return
{{image700.jpg?625x321}}
{{image702.jpg?625x318}}\\
=== O4W_REVSHOW ===
Subroutine O4W_REVSHOW(CTLENTID, EVENT, REQUEST)
*
* Build an O4W Stored Procedure to make Penn & Teller reservations
*
* Demonstrated at Revelation Software User Conference 04/2010
* NOTE: for this to work you will need (in addition to the standard O4W files):
* 1. The "template" named tickets.html, and
* 2. The "youtubin" plugin
*
*
* Insert our required equates
*
$Insert O4WCOMMON
$Insert O4WEQUATES
*
* Respond to the various events that our O4W form generates
*
Begin Case
* Every form is called with the "create" event when it starts up
Case EVENT _EQC "CREATE"
* Specify the location of the "template" we want to use for this form
O4WForm("C:\TEMP\tickets.html")
* Add in the "js" (javascript) and "css" (style sheets) for any of our plugins
O4WScript("../plugins/Zebra_DatePicker/zebra_datepicker.js")
O4WStyleSheet("../plugins/Zebra_DatePicker/metallic.css")
O4WScript("../plugins/youtube/jquery.youtubin-1.js")
* What do we want to show at the top of our browser page?
O4WTitle("Penn & Teller Reservations")
* Convert our sections into tabs
O4WTabs("orderTabs", "showing":@VM:"reserve", "Select A Show":@VM:"Reservation Details")
O4WSectionStart("showing", O4WMarkedStyle('','0'))
* Put up a button to hide or show our on-line help
O4WButton("Show/Hide Instructions...", "BTN_HELP")
* Build the on-line help into a special section
O4WSectionStart("helpSection")
O4WText("You should put some help text here. It would make everyone's life much easier!")
O4WSectionEnd("helpSection")
* When the form starts up, make sure the help section is hidden
O4WQualifyEvent("", "hide", "helpSection")
* Enable the pure client-side "toggling" of the help section when the help button is clicked
O4WQualifyEvent("BTN_HELP", "toggle", "helpSection", "1")
* Output a newline so things look nice
O4WBreak()
* Lay out our show information as a table so it looks nice as well
O4WTableStart("showInfo")
O4WSetCell(1,1)
O4WText("Show date:")
O4WSetCell(1,2)
* Build a textbox with the current date as the default value
* The textbox will be 10 characters wide, it will be named "DATE", and
* it will have a unique ID of "txtDATE"
O4WTextbox(Oconv(DATE(), "D4/"), 10, "", "DATE", "txtDATE")
O4WSetCell(2,1)
O4WText("Number of tickets:")
O4WSetCell(2,2)
* Build a textbox with "0" as the default value
* The textbox will be 5 characters wide, and will accept no more than 5 characters
* It will be named "NUMTICKETS" and have the unique ID of "txtNUMBER"
* When the form is submitted, or validated, the textbox will be checked to make sure only numeric data
* is present - and that something is, indeed, present
O4WTextbox("0", "5", "5", "NUMTICKETS", "txtNUMBER", O4WValidateStyle('', O4W_VALIDATE_NUM$, "1"))
O4WSetCell(3,1)
O4WText("Total Cost":@VM:"($49.99/seat):")
O4WSetCell(3,2)
O4WText("$0.00", "lblCost")
O4WSetCell(3,3)
* We'll put up a button labeled "Update"...
O4WButton("Update", "BTN_UPDATE")
* ...that will generate a "click" event when pressed
O4WQualifyEvent("BTN_UPDATE", "CLICK")
O4WTableEnd("showInfo")
O4WSectionEnd("showing")
* In the next section let's collect the "demographic" data for the buyer
O4WSectionStart("reserve", O4WMarkedStyle('','0'))
O4WTableStart("demoInfo")
O4WSetCell(1,1)
O4WText("Name:")
O4WSetCell(1,2)
O4wTextbox("", "", "", "NAME")
O4WSetCell(2,1)
O4WText("Address 1:")
O4WSetCell(2,2)
O4WTextbox("", "", "", "ADD1")
O4WSetCell(3,1)
O4WText("Address 2:")
O4WSetCell(3,2)
O4WTextbox("", "", "", "ADD2")
O4WSetCell(4,1)
O4WText("City:")
O4WSetCell(4,2)
O4WTextbox("", "", "", "CITY")
O4WSetCell(4,3)
O4WText("State:")
O4WSetCell(4,4)
* Build a listbox with the state information: first, read the state names and codes...
states = Xlate("O4WCODES", "CODES_STATES", "", "X")
* ...and then pass them into a listbox named "ST"
O4WListbox(states<1>, states<2>, "ST")
O4WSetCell(5,3)
O4WText("ZIP:")
O4WSetCell(5,4)
O4WTextbox("", "", "", "ZIP")
O4WTableEnd("demoInfo")
O4WSectionEnd("reserve")
O4WSectionEnd("orderTabs")
O4WBreak()
* Outside of the tabs, display a "Make Your Reservation" button and a link to YouTube
o4wTableStart("displayTable", O4WMarkedStyle('','0'))
O4WButton("Make Your Reservation!", "BTN_RESERVE")
O4WSetCell(1,2)
url = "http://www.youtube.com/watch?v=_qQX-jayixQ&NR=1"
O4WLink("Watch a clip!", O4W_LINKTYPE_NORMAL$, url, "", "lnkPT")
O4WTableEnd("displayTable")
* When the "BTN_RESERVE" is clicked, it will generate a "SUBMIT" event
* (which is like a CLICK event, but it also performs any validation)
O4WQualifyEvent("BTN_RESERVE", "SUBMIT")
* Turn our textbox (with the ID "txtDATE") into a "date picker" field by using
* the "Zebra DatePicker" plugin
O4WPlugin("testDATE","Zebra_DatePicker", "{format: 'M d, Y'}")
* Turn our Penn & Teller link (with the ID "lnkPT") into an embedded video by
* using the "youtubin" plugin
O4WPlugin("lnkPT", "youtubin")
* The CLICK event was generated by the BTN_UPDATE
Case EVENT _EQC "CLICK"
* Let O4W know we're building a response (and not a full page)
O4WResponse()
* Pull in the value of the NUMTICKETS field
numTickets = O4WGetValue("NUMTICKETS")
If Num(numTickets) And numTickets <> "" then
* Had a valid number; calculate the cost and update the lblCost control
* Note the use of the O4WResponseStyle to tell the control we're only
* updating its text portion
O4WUpdate("lblCost", Oconv(numTickets * 4999, "MD2,$"), O4WResponseStyle('','1'))
End Else
* Didn't have a valid number - show an error message
O4WError("You must enter a valid number to continue")
End
* The SUBMIT event was generated by the BTN_RESERVE
Case EVENT _EQC "SUBMIT"
* After a SUBMIT, we do have to build a new page - so we'll call O4WForm with
* our template again
O4WForm("C:\TEMP\tickets.html")
* Load in the data from the form
numTickets = O4WGetValue("NUMTICKETS")
NAME = O4WGetValue("NAME")
amt = Oconv(numTickets * 4999, "MD2,$")
* Imagine that we get all the rest of the info from the form too...
* ...and write it out somewhere in the database
* Now generate a thank you message
O4WText("Thanks, ":NAME:"! Please be sure to complete your purchase using PayPal and your tickets will be waiting for you at the 'All Call' box")
* And call the PayPal site (with the O4WPayPal api) to do a "buy it now" transaction
O4WPaypal("BUY", "", "xxx@revelation.com", "Penn and Teller tickets", "pttickets", NUMTICKETS, "$49.99", "$0.00", "$0.00")
End Case
*
Return 0
{{image704.jpg?623x384}}
{{image706.jpg?623x384}}
{{image708.jpg?623x384}}
=== Login Screen ===
Below is code for a sample login screen for use with an O4W application. This code will prompt for username and password, validate the user and launch an O4W menu.
Subroutine O4W_CUSTLOGIN(CtlEntId, Event, Request)
*
* O4W Example code: login screen
*
$Insert O4WCommon
$Insert O4WEquates
*
*
Begin Case
Case EVENT _EQC "CREATE"
O4WForm()
* Have we already logged in?
loginCookie = O4WCookie("tempCookie")
If loginCookie <> "" Then
* we've already had our cookie set; we must have logged in already
* get the information stored in our temp file (referenced by the cookie)
Read userInfo From O4WTempFile%, loginCookie Then
* found the information from the successful login; go ahead and display the menu
userName = userInfo<1>
userPrivileges = userInfo<2>
* display the menu
O4WMenu("SAMPLE_MENU")
* and some welcome text
O4WHeader("Welcome, ":userName, 4)
O4WBreak()
O4WBreak()
O4WText("Please select an option from the menu to continue")
Return 0
End
* Couldn't read our user information record from the temp file?
* Must have been a false alarm; fall through to the login page
end
O4WHeader("O4W Customer Login":@VM:"Login Please", 4)
O4WTableStart("loginTable", O4WTableStyle("", "", "", "1"))
O4WText("User name: ")
O4WSetCell(1,2)
O4WTextBox("",'' ,'' ,'' , "uname")
O4WSetCell(2,1)
O4WText("Password: ")
O4WSetCell(2,2)
O4WPwdBox("",'' ,'' ,'' , "pwd")
O4WSetCell(3,2)
O4WButton("Login", "BTNLOGIN", O4WInputStyle('','','','',1))
O4WTableEnd("loginTable")
O4WQualifyEvent("BTNLOGIN", "CLICK")
* Define an empty section for any messages we might have to issue
O4WSectionStart("msgArea", O4WMarkedStyle('','0'))
O4WSectionEnd("msgArea")
Case EVENT _EQC "CLICK"
Begin Case
Case CtlEntId _eqc "BTNLOGIN"
O4WResponse()
* evaluate what the user entered
userName = O4WGetValue("uname")
passwd = O4WGetValue("pwd")
bIsBad = 1
userPrivileges = ""
* given the username and password, validate this user
* normally done by looking in a table and verifying that the passwords match
onfileInfo = Xlate("MYUSERTABLE", userName, "", "X")
If onFileInfo <> "" Then
If passwd = onFileInfo<1> And passwd <> "" Then
* this user is ok to proceed
bIsBad = 0
* record what "permissions level" they have as well (in case we need to allow different "levels" of users)
userPrivileges = onFileInfo<2>
End
end
If bIsBad then
* Bad - display error in the "msgArea"
O4WSectionStart("msgArea", O4WResponseStyle():O4WMarkedStyle('','0'))
O4WText("Invalid logon - please retry",'' , O4WColors("","","red"))
O4WSectionEnd("msgArea")
RETURN
End
* Success! Record login status in our temp file so we can find this information later
* first, build a unique ID that we can use as our key to the temp table
tempKey = O4WGenerateID("LOGIN")
* and save it into our cookie
O4WCookie("tempCookie", tempKey)
* now save the user information into the temp table with this key
cfgInfo = ""
CFGINFO<1> = username
CFGINFO<2> = userPrivileges
Write CFGINFO On O4WTempFile%, tempKey
* force redisplay of this page to properly display the menu
O4WRedirect("O4W_CUSTLOGIN")
End case
End CASE
*
Return 0
This sample login routine must be registered and its required permissions must be set to “none”.
The routine also assumes that you have created an O4W menu (in the sample code above it is called SAMPLE_MENU). The permissions for this O4W menu must be set to “none”.
This routine also assumes you have a table that contains user names, passwords and “permission levels” which can be customized as needed.
For anything that needs to determine what user you are logged in as, and what permissions you have, you can use the following code snippet:
tempKey = O4WCookie(“tempCookie”)
userName = “”
userPerms = “”
if tempKey <> “” then
Read userInfo from O4WTempFile%, tempkey then
userName – userInfo<1>
userPerms = userInfo<2>
End
End
For this login screen to be truly “integrated”, you must also change your O4W configuration so that you have a custom “O4W Permissions Authorization procedure”; this custom procedure will check the required permissions for any O4W Form, Report, Dashboard, or Procedure against the “permissions level” assigned to the logged-in user, and determine whether the user should be allowed to execute the Form, Report, Dashboard, or Procedure. A sample Permissions Authorization procedure might look like the following:
Function O4WCUSTOMPERMISSIONS(ReqdPerms, SessionInfo)
$Insert O4WCommon
$Insert O4WEquates
tempKey = O4WCookie(“tempCookie”)
userName = “”
userPerms = “”
if tempKey <> “” then
Read userInfo from O4WTempFile%, tempkey then
userName = userInfo<1>
userPerms = userInfo<2>
End
End
** For this simple example, assume being logged in is all that is required to proceed (so we do not compare “userPerms” with “ReqdPerms”)
If userName <> “” then
Rslt = 1
End Else
Rslt = -1; * not logged in – do not let them run this
End
Return Rslt
=== Invoice Form ===
Subroutine O4W_INVOICE_REPORT(CTLENTID, EVENT, REQUEST)
*
* Demonstration routine
*
$Insert O4WCOMMON
$Insert O4WEQUATES
Declare Function ucase
* Open our tables (otherwise we can't generate any report)
Open 'INVOICES' To INV.FL Else
O4WError("Unable to open INVOICES table - cannot proceed!")
Return 0
End
Open 'DICT','INVOICES' To @DICT Else
O4WError("Unable to open DICT.INVOICES table - cannot proceed!")
Return 0
End
* Define some style variables that we'll use repeatedly
* This creates some "temporary" unnamed styles that we can reuse
rightAlignStyle = O4WTextOptions("", "","1"):O4WAlignStyle("", O4W_ALIGN_RIGHT$)
greenbarStyle = o4wcolorstyle("", "lightgreen")
* Alternatively, this creates a named style ("overallSection") that we can reuse
O4WTableStyle("overallSection", "", "", O4W_ALIGN_CENTER$)
O4WSizeStyle("overallSection", "90%")
* This creates some named styles ("invoiceSection", "headingOverride") with some explicit CSS commands
* These could also go directly into our stylesheet
O4WRawStyle("invoiceSection", "margin-left":@fm:"margin-right":@fm:"text-align", "0px":@FM:"0px":@FM:"left")
O4WRawStyle("headingOverride", "padding", "8px 0px")
Begin Case
Case EVENT _EQC "CREATE"
* Create event should always use O4WForm call (optionally specifying the template to use)
O4WFORM()
* Load in the stylesheet that will "dress up" our output
* CSS derived from editable invoice example at http://www.css-tricks.com (lots of good information there!)
O4WStyleSheet("../stylesheet/invoicereport.css")
O4WHeader("Invoice Report", 3)
O4WBreak()
O4WBreak()
*
* In the CREATE event, we will define a section for our prompt
* In the later pages, this section will be replaced with the invoice report output
*
* Only take up 90% of the page, and center this section
O4WSectionStart("invOutput", O4WMarkedOptions('1'):"overallSection")
* Allow for override in URL for the number of invoices per page
nppg = O4WGetValue("PPG")
If nppg = "" Or Not(Num(nppg)) Then nppg = 10
* Store this away so our later pages know how many should be shown
O4WStore(nppg, "inv_per_page", "inv_per_page")
O4WStore("1", "pageno", "pageno")
* Build a table to display the prompts
O4WTableStart("paramTable")
O4WText("Enter starting date: ")
O4WSetCell()
* As a further enhancement, this could be a 'datepicker' control
O4WTextbox(Oconv(DATE(), "D4/"), "", "", "STDATE")
O4WSetCell(2)
O4WText("Enter ending date: ")
O4WSetCell()
O4WTEXTBOX(Oconv(DATE(), "D4/"), "", "", "EDDATE")
O4WSetCell(3, 2)
* Display the button...
O4WButton("Go...", "BTN_GO")
* ... and associate it with the "CLICK" action
O4WQualifyEvent("BTN_GO", "CLICK")
O4WTableend("paramTable")
O4WSectionEnd("invOutput")
*
* CLICK event handler
* This may be invoked either when navigating back and forth, or when first submitting the report parameters
*
Case event _eqc "CLICK"
Begin Case
Case ctlentid _eqc "BTN_GO"
* Called after submitting the report parameters
* When responding to an event, we will almost always need the O4WResponse() call (comparable to the O4WForm() call on the CREATE event)
o4wresponse()
* determine which invoices fall in our date (if any)
STDATE = O4WGETVALUE("STDATE")
EDDATE = O4WGETVALUE("EDDATE")
* As an enhancement, we chould check that these are valid, and if not, return an error...
* "normal" OpenInsight programming is used here
stmt = 'SELECT INVOICES BY INVOICE_DATE BY CUST_NAME'
DELIM = ""
If stdate <> "" Then
stmt := ' WITH INVOICE_DATE >= "':STDATE:'"'
DELIM = ' AND'
End
If eddate <> "" Then
stmt := DELIM:' WITH INVOICE_DATE <= "':EDDATE:'"'
End
* Get the unique ID that O4W has already generated for this page
* Use this as the key to store the selected IDs
UniqueID = ucase(o4wgetvalue("O4WUniqueID"))
LISTID = UniqueID:"*LIST"
Call Rlist(STMT, 4, LISTID,'' ,'' )
* did we select anything?
* note: this only works if we don't span multiple records; in newer versions of OpenInsight, use RTI_LIST instead to read in the entire list
listinfo = Xlate("SYSLISTS", LISTID, "", "X")
If listinfo = "" Then
* Return an error
o4wError("No invoices selected; please retry")
End Else
* Preserve the list of IDs in the O4WTEMP table
listinfo = Delete(listinfo, 1, 0, 0) ;* First, remove the "list header" from field 1
Write listinfo On O4WTempFile%, LISTID
* Some browsers may have available the parameters from the URL even on our AJAX events
* O4W will make multiple occurences of the same parameter available as @VM delimited values
* Make sure, then, that if we have more than one hanging around, we operate on only one
invperpage = o4wgetvalue("inv_per_page")<1,1>
If invperpage = "" Or Not(Num(invperpage)) Then
invperpage = 10
End
pageno = o4wgetvalue("pageno")<1,1>
If pageno = "" Or Not(Num(pageno)) Then
pageno = 1
End
* The "buildInvoices" subroutine will generate the invoices for the current page
Gosub buildInvoices
End
Case ctlentid _eqc "BTN_NEXT"
* Called by the NEXT button
o4wresponse()
invperpage = o4wgetvalue("inv_per_page")<1,1> ;* make sure, if we have more than one hanging around, we only get one
If invperpage = "" Or Not(Num(invperpage)) Then
invperpage = 10
End
pageno = o4wgetvalue("pageno")<1,1>
If pageno = "" Or Not(Num(pageno)) Then
pageno = 1
End
* Increment the page number that we were on
pageno += 1
* Build the invoices for this page
Gosub buildInvoices
Case ctlentid _eqc "BTN_PREV"
* Called by the PREV button
o4wresponse()
invperpage = o4wgetvalue("inv_per_page")<1,1> ;* make sure, if we have more than one hanging around, we only get one
If invperpage = "" Or Not(Num(invperpage)) Then
invperpage = 10
End
pageno = o4wgetvalue("pageno")<1,1>
If pageno = "" Or Not(Num(pageno)) Then
pageno = 1
End
* Decrement the page number that we were on
pageno -= 1
* Sanity check of the results
If pageno < 1 Then pageno = 1
* Build the invoices for this page
Gosub buildInvoices
End case
End Case
Return 0
buildInvoices:
* Tell O4W that we want to replace the "invOutput" section of the displayed browser page
O4WSectionStart("invOutput", O4WResponseOptions():O4WMarkedOptions('1'):"overallSection")
* Preserve the values we want to pass in on the "Next" or "Prev" button presses
O4WStore(invperpage, "inv_per_page", "inv_per_page")
O4WStore(pageno, "pageno", "pageno")
* Retrieve the unique ID that O4W has generated for this form
UniqueID = ucase(o4wgetvalue("O4WUniqueID"))
LISTID = UniqueID:"*LIST"
* Try to retrieve the list of selected invoices we generated previously
Read listInfo From O4WTempFile%, ListID Else listInfo = ""
* Is that list missing or empty? => Error
If listInfo = "" Then
O4WError("Error: No items selected, or list item lost")
Return
End
* Calculate how many invoices are in the list, and which ones in the list we should process for this page
num.items = dcount(listInfo, @FM)
stno = (pageno-1)*invperpage + 1
edno = stno + invperpage - 1
* Sanity check - are we beyond the end of the list?
If stno > num.items Then
O4WError("Error: Invalid page number")
Return
End
* If the last page has fewer than our maximum to display, adjust ourselves accordingly
If edno > num.items Then edno = num.items
cntr = 0
*
* For each ID in our list, we will read the invoice record, pull out its information (and associated information from the CUSTOMERS table), and display it in appropriate sections
*
For each.invoice = stno To edno
@ID = listInfo
Read @record From INV.FL, @ID Else
@RECORD = "Record ":@ID:" not found"
End
cntr += 1
* get all the details
INV_DATE = {INVOICE_DATE}
CUST_NO = {CUST_NO}
CUST_NAME = {CUST_NAME}
ORD_DATE = {ORDER_DATE}
ORD_NUM = {ORDER_NUMBER}
DUE_DATE = {DUE_DATE}
PAID_DATE = {PAID_DATE}
QTYS = {QTYS}
DESCS = {DESCS}
ITEMS = {ITEMS}
PRICES = {PRICES}
EXTENDED = {EXT_COSTS}
AMOUNT = {AMOUNT}
* get address information
CUSTINFO = Xlate("CUSTOMERS", CUST_NO, "", "X")
ADD1 = CUSTINFO<3>
ADD2 = CUSTINFO<4>
CITY = CUSTINFO<5>
ST = CUSTINFO<6>
ZIP = CUSTINFO<7>
COUNTRY = CUSTINFO<8>
* Display this invoice in its own section
* "Green bar" the output for easier identification
invcolor = ""
If cntr/2 = int(cntr/2) Then
* change the background color of this section
invcolor = greenbarStyle
End
* Insert a few blank lines
O4WBreak()
O4WBreak()
O4WBreak()
*
* Each invoice will go into its own section
* Note the use of the CNTR variable - this makes sure that each element has a unique ID (as required)
*
o4wsectionstart("invoice_":cntr, "invoiceSection":@SVM:invcolor)
* Display the word "INVOICE", and assign it to the "hdr" style
* We also assign it to the "headerOverride" style (dynamically created at the top of this report) to override the padding setting in our template's css
o4wtext("INVOICE", "", "headingOverride":@SVM:O4WTextOptions("","","1"):"hdr")
O4WBreak()
O4WBreak()
* Create a section to hold who we are, assigning it to the "identity" class
O4WSectionStart("identity_":cntr, "identity")
* Create a section for the address itself, assigning it to the "address" class
O4WsectionStart("address_":cntr, "address")
* ...and output our address information
O4WText("Revelation Software")
o4wbreak()
O4WText("99 Kinderkamack Rd.")
O4WBreak()
O4WText("First Floor")
O4WBreak()
O4WText("Westwood, NJ 07675")
O4WSectionEnd("address_":cntr)
* Display a logo with the "logo" class
O4WSectionStart("logo_":cntr, "logo")
o4wimage("logo", "../images/logo.gif")
O4WSectionEnd("logo_":cntr)
O4WSectionEnd("identity_":cntr)
* Some css to make things align properly
o4wsectionstart("clearing_":cntr, O4WPositionStyle("","","","","","both"));o4wsectionend("clearing_":cntr)
* Create the customer section using the "customer" class
O4WSectionStart("customer_":cntr, "customer")
* Output the customer information, assigned to the "customer-title" class
* O4W will automatically make each value its own line in the display
* Let's put this all together
custOutput = ""
custOutput<1,-1> = CUST_NAME
custOutput<1,-1> = TRIM(ADD1)
If trim(ADD2) <> "" Then custOutput<1,-1> = TRIM(ADD2)
custOutput<1,-1> = CITY:", ":ST:" ":ZIP
If COUNTRY _eqc "US" or COUNTRY _eqc "USA" Then
country = ""
End
If trim(COUNTRY) <> "" Then custOutput<1,-1> = COUNTRY
O4WText(custOutput, "", "customer-title")
* Display a table of overall information about this invoice
O4WTableStart("meta_":cntr, "meta")
* Move to cell (1,1), and assign that cell to the "meta-head" class
O4WSetCell(1,1,"","meta-head")
O4WText("Invoice #")
* Shorthand to move to the next cell - (1,2) in this case
O4WSetCell()
O4WText(@ID)
O4WSetCell(2, 1, "", "meta-head")
O4WText("Date")
O4WSetCell()
O4WText(Oconv(INV_DATE, "D"))
O4WSetCell(3, 1, "", "meta-head")
O4WText("Amount Due")
O4WSetCell()
O4WText(Oconv(AMOUNT, "MD2,$"))
O4WTableEnd("meta_":cntr)
O4WSectionEnd("customer_":cntr)
* Create a table to display the line items, and the subtotals/totals
O4WTableStart("items_":cntr, "items")
* Display the column headings
O4WTableHeader("Item")
O4WTableHeader("Description")
O4WTableHeader("Unit Price")
O4WTableHeader("Quantity")
O4WTableHeader("Ext")
num.lines = dcount(items, @VM)
total = 0
For each.item = 1 To num.lines
O4WSetCell(each.item, 1, "", "item-name")
o4wtext(items<1,each.item>)
O4WSetCell(each.item, 2, "", "description")
O4WText(descs<1,each.item>)
O4WSetCell(each.item, 3, "", "cost")
O4WText(Oconv(PRICEs<1,EACH.ITEM>, "MD2,$"), "", rightAlignStyle)
O4WSetCell(each.item, 4, "", "qty")
O4WText(qtys<1,each.item>, "", rightAlignStyle)
O4WSetCell(each.item, 5, "", "price")
O4WText(Oconv(extended<1,each.item>, "MD2,$"), "", rightAlignStyle)
total += extended<1,each.item>
Next each.item
* Move to the next row, first column, and use "column spanning" to consume 2 columns; also, mark this as the "blank" style
O4WSetCell(num.items+1, 1, "", O4WTableCellOptions(2):"blank")
* Move to the 3rd column, and use column spanning to consume 2 more columnes; mark this as the "total-line" style
O4WSetCell("", 3, "", O4WTableCellOptions(2):"total-line")
O4WText("Subtotal")
O4WSetCell("", 5, "", "total-value")
O4WText(Oconv(total, "MD2,$"), "", rightAlignStyle)
O4WSetCell(num.items+2, 1, "", O4WTableCellOptions(2):"blank")
O4WSetCell("", 3, "", O4WTableCellOptions(2):"total-line")
O4WText("Total")
O4WSetCell("", 5, "", "total-value")
O4WText(Oconv(total, "MD2,$"), "", rightAlignStyle)
O4WTableEnd("items_":cntr)
* Done with the line items and subtotals/totals
* Start the terms section, assigning it to the "terms" style
O4WSectionStart("terms_":cntr, "terms")
O4WHeader("Terms", 5)
O4WText("NET 30 days. Finance charges of 1.5% will be made on unpaid balances after 30 days")
O4WSectionEnd("terms_":cntr)
o4wsectionend("invoice_":cntr)
O4WBreak()
O4WBreak()
* Finally, display a line using the "dashes" style
O4WDivider("", "dashes")
Next each.invoice
*
* Display our forward/back buttons
* Only enable them, though, if appropriate
If stno > 1 Then
* Create the button, and make sure it's enabled
O4WButton("< Back", "BTN_PREV", O4WInputStyle("","1", "0"))
O4WQualifyEvent("BTN_PREV", "CLICK")
End Else
* Create the button, but make it disabled and read-only
O4WButton("< Back", "BTN_PREV", O4WInputStyle("", "0","1"))
End
o4wspace(5)
If edno < num.items Then
O4WButton("Next >", "BTN_NEXT", O4WInputStyle("","1","0"))
O4WQualifyEvent("BTN_NEXT", "CLICK")
End Else
O4WButton("Next >", "BTN_NEXT", O4WInputStyle("", "0","1"))
End
*
O4WSectionEnd("invOutput")
Return
{{image710.jpg?622x180}}
{{image712.jpg?627x561}}
=== Order Entry ===
Subroutine O4W_ORDER_ENTRY(ctlentid, event, request)
*
* O4W coding example
*
* Create, edit, or delete records in the ORDERS table
* URL: http://.../oecgi4.exe/O4W_ORDER_ENTRY
*
* Prompt the user for the order number: allow for lookup, manual entry, or left blank => new order
*
* Main Program flow: CREATE event (to draw form initially)
*
* RETURNVALUE event/ONUM if order search button pressed or
* LOSTFOCUS event/ONUM if order number entered explicitly
* handleOrderNumber {may optionally display dialog if existing record has been changed, and then CLICK\BTN_READ or CLICK\BTN_READ_CANCEL} => loadRecord => retrieveRecord => displayHeader => displayDetails
*
* RETURNVALUE event/OCUST if customer search button pressed
* CHANGE event/OCUST to update the customer name
* markAsChanged
*
* CLICK event/BTN_SEARCH_PROD_ if product search button pressed to ask which type of search
* RETURNVALUE event/ITEM after product search completed
* CHANGE event/ITEM, QTY, or PRICE to update the order details
* displayDetails => markAsChanged
*
* CLICK event/BTN_SAVE to save the record
* lockrecord => saverecord => resetpages
* CLICK event/BTN_DELETE to confirm deletion of record => CLICK event/BTN_DELETE2 to delete the record
* lockrecord => deleterecord => resetpages
* CLICK event/BTN_CANCEL to reload the original order record
* retrieveRecord => displayHeader => displayDetails => markAsFresh
* Insert required equates and commons
$Insert O4WCOMMON
$Insert O4WEQUATES
* Since we're going to check the configuration record, include this equate as well
$Insert O4WConfigEquates
Declare Function Repository
* Open our data and dictionary tables, otherwise we have an error
Open "ORDERS" To ORDER.TBL Else
O4WError("Unable to access ORDERS table")
Return 0
End
Open "DICT","ORDERS" To @DICT Else
O4WError("Unable to access DICT.ORDERS table")
Return 0
End
* define some O4W "styles"
selectedStyle = O4WMarkedOptions("1")
deselectedStyle = O4WMarkedOptions("0")
textReplace = O4WResponseOptions("1")
textReplaceTrigger = O4WResponseOptions("1", "", "1")
borderStyle = O4WTableStyle("", "1", "1")
roStyle = O4WInputOptions("0","1"):O4WColorStyle("", "lightblue")
size10pct = O4WSizeStyle("", "10%")
size50pct = O4WSizeStyle("", "50%")
rtJustn = O4WAlignStyle("", "2")
* retrieve (if set) our unique id
uniqueID = O4WGetValue("O4WUniqueID")
* read the configuration record (using the appropriate repository method)
configRec = Repository("ACCESS", @APPID<1>:"*CONFIG*O4W*CFG_O4W")
Call Set_Status(0)
* determine the "lock procedure" that has been specified in the configuration record
LOCK_PROC = configRec
If LOCK_PROC = "" Then LOCK_PROC = "O4WI_LOCKHANDLER"
Begin Case
Case EVENT _EQC "CREATE"
* Generate the base form
* Since no template has been explicitly specified, use the default template
O4WForm()
* Save this variable in the web page
O4WStore("", "activeRecord", "activeRecord")
* After the O4WForm call, the unique ID has been created - load it in
uniqueID = O4WGetValue("O4WUniqueID")
* Display a header
O4WHeader("Order Entry/Inquiry", 3)
* Establish the tabs
O4WTabs("orderForm", "orderHeader":@VM:"orderDetails", "Header":@VM:"Details")
* Create the header section
O4WSectionStart("orderHeader", deselectedStyle)
* and a table to contain the order header information
O4WTableStart("tableHeader")
O4WSetCell(1,1)
O4WText("Order Number: ")
O4WSetCell()
O4WButton("?", "BTN_SEARCH_ORDERS")
* Associate a popup with this button
O4WPopup("Order Search", O4W_LINKTYPE_POPUP$, "ORDER_POPUPS", "", "orderpopup", "BTN_SEARCH_ORDERS")
O4WTextbox("", "", "", "ONUM","ONUM")
* Tell O4W we want to be notified when the ONUM textbox has lost focus
o4wqualifyevent("ONUM", "LOSTFOCUS")
O4WSetCell(4, 1)
O4WText("Customer Number: ")
O4WSetCell()
O4WButton("?", "BTN_SEARCH_CUST")
* Associate a popup with this button too
O4WPopup("Customer Search", O4W_LINKTYPE_POPUP$, "CUSTOMER_ID_POPUP", "", "custpopup", "BTN_SEARCH_CUST")
O4WTextbox("", "", "", "OCUST", "OCUST")
* Tell O4W we want to be notified when the OCUST textbox has changed
o4wqualifyevent("OCUST", "CHANGE", "textbox")
O4WSetCell()
O4WSetCell(5, 2, "", O4WTableCellOptions(2))
* Display a textbox, but mark it as "read only" and style it so that it looks different
O4WTextbox("", "40", "", "OCUSTNAME", "OCUSTNAME", roStyle)
O4WSetCell(6,1)
O4WText("Order Date: ")
O4WSetCell()
O4WDatePicker("","12","1","","ODATE", "ODATE")
O4WTableEnd("tableHeader")
O4WSectionEnd("orderHeader")
O4WSectionStart("orderDetails", deselectedStyle)
* Can't fill in the order details yet (without an order being selected), but set up this section as a placeholder
O4WText("Please select an existing or new order...")
O4WSectionEnd("orderDetails")
O4WSectionEnd("orderForm")
* Define this section for our special dialogs
O4WSectionStart("specialDialog", deselectedStyle)
O4WSectionEnd("specialDialog")
* Define the buttoms
O4WButton("Save", "BTN_SAVE")
O4WButton("Delete", "BTN_DELETE")
O4WButton("Cancel", "BTN_CANCEL")
* And set them so they generate the 'click' event
O4WQualifyEvent("BTN_SAVE", "CLICK")
O4WQualifyEvent("BTN_DELETE", "CLICK")
O4WQualifyEvent("BTN_CANCEL", "CLICK")
Case event _eqc "LOSTFOCUS"
* Generated when a control loses focus (if the appropriate O4WQualifyEvent on that control has been set)
Begin Case
Case ctlentid _eqc "ONUM"
O4WResponse()
@ID = O4WGetValue("ONUM")
* Load in the value of the ONUM textbox, and call handleOrderNumber to retrieve that record (if appropriate)
Gosub handleOrderNumber
End case
Case event _eqc "CHANGE"
* Generated when a control's value changes (if the appropriate O4WQualifyEvnet on that control has been set)
* Note that O4W provides 2 additional values: O4WChangeID (the ID of the control that made the change), and O4WChangeValue (the value it's been changed to)
Begin Case
Case ctlentid _eqc "OCUST"
* Customer # has changed - update our customer name display
O4WResponse()
@RECORD = ""
@ID = O4WGetValue("ONUM")
{CUST_NO} = O4WGetValue("O4WChangeValue")
O4WUpdate("OCUSTNAME", {CUSTOMER_NAME}, textReplace)
* make sure we know that something's changed, so we can't just navigate away from this without being prompted to save our changes
Gosub markAsChanged
Case ctlentid _eqc "ITEM" Or ctlentid _eqc "QTY" Or ctlentid _eqc "PRICE"
* One of our detail lines has been added or changed
O4WResponse()
* who changed? which line, which control? This way, we can determine who to set the focus to...
whichOne = O4WGetValue("O4WChangeID")
* Our controls are defined as "ITEM_1", "ITEM_2", etc. However, if a new line has been added, it will have a more complex (auto-generated) ID, such as ITEM_3_o4wid_2
If Count(whichOne, "_") > 1 Then
* More than one "_" in the ID? This must be a newly-added line
changeLine = -1
End Else
changeLine = Field(whichOne, "_", 2)
End
* Load in the current contents of all our fields
Gosub retrieveCurrentRecord
* fill in any defaults, and determine where to set the focus to
items = {ITEM}
qtys = {QTY}
cost = {PRICE}
num.items = dcount(items, @VM)
For each.item = num.items To 1 step -1
* default the quantity and price if they're not set
If qtys<1,each.item> = "" Then
qtys<1,each.item> = 1
End
If cost<1,each.item> = "" then
cost<1,each.item> = Xlate('PRODUCTS', items<1,each.item>, "PRICE", "")
end
Next each.item
{ITEM} = items
{QTY} = qtys
{PRICE} = cost
* Update the "order details" section
Gosub displayDetails
* now set the focus as appropriate
If changeLine = -1 Then
* this was a newly-added line, so it's the last value
changeLine = dcount(items,@VM)
end
Begin Case
Case ctlentid _eqc "ITEM"
O4WFocus("PRICE_":changeLine)
Case ctlentid _eqc "PRICE"
O4WFocus("QTY_":changeLine)
Case ctlentid _eqc "QTY"
O4WFocus("ITEM_":(changeLine+1))
End Case
* Remember to mark us as having been changed, so we can't navigate away and lose our changes without a verification prompt
Gosub markAsChanged
End Case
Case event _eqc "CLICK"
* Generated when a button is pressed
Begin Case
Case ctlentid _eqc "BTN_CANCEL"
* Throw away any changes, and reload the original contents of the record?
O4WResponse()
* Get the ID
@ID = O4WGetValue("ONUM")
* see if there are any changes, and if there are prompt before reloading
Gosub handleOrderNumber
Case CTLENTID _EQC "BTN_SAVE"
* called when the 'save' button is pressed
* make sure we can lock the record, and it hasn't been changed by anyone else since we originally read it in
Gosub lockRecord
If error = "" Then
* No problems - write it out
Gosub saveRecord
* Display our "update successful" response
O4WError("Order '":@ID:"' updated", "Save Order")
* blank the fields, mark us as unchanged, and return to first tab
Gosub resetPages
End
Case ctlentid _eqc "BTN_DELETE"
* called to delete the record
* put up a dialog box to verify the deletion first
O4WResponse()
* retrieve the item id
@ID = O4WGetValue("ONUM")
* build our dialog to verify the deletion
O4WSectionStart('specialDialog', selectedStyle:O4WResponseStyle())
* save the order ID in the dialog
O4WStore(@ID, "ONUM", "ONUM")
O4WText("Please verify deletion of order '":@ID:"'")
O4WBreak()
O4WButton("Delete", "BTN_DELETE2", selectedStyle)
O4WButton("Cancel", "BTN_DIALOG_CANCEL")
* Notify us when these buttons are pressed
O4WQualifyEvent("BTN_DELETE2", "CLICK")
O4WQualifyEvent("BTN_DIALOG_CANCEL", "CLICK")
O4WSectionEnd('specialDialog')
* and then show the dialog
O4WDialog('specialDialog', 'Confirm Deletion','' ,'' , 'width:350')
Case ctlentid _eqc "BTN_DELETE2"
* called after confirming the delete request
* first, make sure we can lock the record and no one else has changed it since we read it
Gosub lockRecord
If error = "" Then
* no problems - proceed with the deletion
Gosub deleteRecord
* display our 'deletion successful' message
O4WError("Order '":@ID:"' deleted", "Delete Order")
* blank the fields, mark us as unchanged, and return to first tab
Gosub resetPages
End
* the following 2 controls are displayed on the "record has changed - do you want to discard these changes" dialog box
Case ctlentid _eqc "BTN_READ"
* yes, the user wants to discard any changes and load in the new record
O4WResponse()
* dismiss the dialog box
O4WDialog("specialDialog")
* retrieve their new ID
@ID = O4WGetValue("ONUM")
* load in the record
Gosub loadRecord
Case ctlentid _eqc "BTN_CANCEL_READ"
* no, the user does _not_ want to throw away their changes to the current record
O4WResponse()
* retrieve the original ID
origID = O4WGetValue("ID")
* dismiss the dialog box
O4WDialog("specialDialog")
* and just reset the value in the order number textbox
O4WUpdate("ONUM", origID, textReplace)
* this is generated when the 'search' button is pressed in one of the order detail lines
* the user is given a choice of search methods
Case ctlentid[1,16] _eqc "BTN_SEARCH_PROD_"
O4WResponse()
* determine which line the user was on (each button is identified with its line number)
whichOne = ctlentid[17, Len(ctlentid)]
* build a dialog box to ask what type of search to perform
O4WSectionStart("specialDialog", O4WResponseOptions())
* Note the button contains the line number (so we'll know what to update after the user makes their choice)
O4WButton("Search for product by text", "BTN_SEARCH3_PROD_":whichOne)
* associate an index lookup popup with this button
O4WPopup("Product Search", O4W_LINKTYPE_INDEXLOOKUP$, "", "PRODUCTS":@FM:"DESCRIPTION_XREF":@fm:"ID":@VM:"DESCRIPTION", "prodpopup2", "BTN_SEARCH3_PROD_":whichOne)
O4WText(" or ")
O4WButton("List all products", "BTN_SEARCH2_PROD_":whichOne)
* associate a regular popup with this button
O4WPopup("Product Search", O4W_LINKTYPE_POPUP$, "PRODUCT_POPUP", "", "prodpopup1", "BTN_SEARCH2_PROD_":whichOne)
* Provide a 'cancel' button to dismiss the dialog
O4WBreak()
O4WBreak()
O4WButton("Cancel", "BTN_DIALOG_CANCEL")
* Generate the 'click' event when it's pressed
O4WQualifyEvent("BTN_DIALOG_CANCEL", "CLICK")
O4WSectionEnd("specialDialog")
O4WDialog("specialDialog", "Product Search",'' ,'' , 'width:550')
Case ctlentid _eqc "BTN_DIALOG_CANCEL"
O4WResponse()
* dismiss the dialog box
O4WDialog("specialDialog")
End Case
Case event _eqc "RETURNVALUE"
* The user has selected a value from a popup
O4WResponse()
* determine which control had the popup, and what the user selected
callingCtl = O4WGetValue('o4wPopupCtl')
popupValue = O4WGetValue('o4wValue')
Begin Case
Case callingCtl _eqc "BTN_SEARCH_ORDERS"
* this was the order search popup
* update the order number with the selected value
O4WUpdate("ONUM", popupValue, textReplace)
@ID = popupValue
* Fill in the rest of the form based on this record ID
* If "automatic lose focus" is not desired, disable the following line:
Gosub handleOrderNumber
Case callingCtl _eqc "BTN_SEARCH_CUST"
* this was the customer search popup
* update the customer number textbox with the selected value
* note the use of the "textReplaceTrigger" style - this not only replaces the text, but also triggers the "change" event
* the change event (previously defined) will derive the customer name from this value
O4WUpdate("OCUST", popupValue, textReplaceTrigger)
Case callingCtl[1,17] _eqc "BTN_SEARCH2_PROD_" Or callingCtl[1,17] _eqc "BTN_SEARCH3_PROD_"
* this was either of the 2 different product search popups (regular or index lookup)
* first, dismiss the dialog box that asked which type of search to use
O4WDialog("specialDialog")
* determine which line item in the order details called the popup
whichLine = callingCtl[18, Len(callingCtl)]
* update the product on that line of the order details, and trigger the "change" event for that item
O4WUpdate("ITEM_":whichLine, popupValue, textReplaceTrigger)
End case
End Case
Return 0
retrieveRecord:
* call the lockhandler routine to read the original record
Call @LOCK_PROC(O4W_LOCKHANDLER_ACTION_READ$, order.tbl, @ID, @RECORD, UniqueID:"*ORDERS*":@id:"*ORIG")
Return
lockRecord:
* call the lockhandler routine to lock (if possible) the original record
* this will verify that the underlying record is unchanged, And we can lock it
error = "" ;* assume success
* load in the current ID and record contents from the browser form
Gosub retrieveCurrentRecord
* call the lockhandler to see if the record is able to be locked, and is unchanged from its original state
stat = Function(@lock_proc(O4W_LOCKHANDLER_ACTION_CHECK$, order.tbl, @id, curr.record, UniqueID:"*ORDERS*":@ID:"*ORIG", O4W_LOCKHANDLER_OPTION_LOCK$))
* check for results from the 'check' call
If stat = O4W_LOCKHANDLER_NO_LOCK$ Then
* couldn't get the lock on this item - let the user choose another ID
error = "Unable to lock order '":@ID:"'"
O4WError(error)
Return
End
If stat = O4W_LOCKHANDLER_ITEM_CHANGED$ Then
* someone else changed the record while we worked on it - let the user choose another ID
error = "Order '":@ID:"' has been changed by another user"
* remember to unlock our current record, though
Call @LOCK_PROC(O4W_LOCKHANDLER_ACTION_UNLOCK$, order.tbl, @ID)
O4WError(ERROR)
Return
End
Return
saveRecord:
* call the lockhandler routine to save the modified record
Call @LOCK_PROC(O4W_LOCKHANDLER_ACTION_WRITE$, ORDER.TBL, @ID, @RECORD, UniqueID:"*ORDERS*":@ID:"*ORIG")
Return
deleteRecord:
* delete the record from the orders table, and release any lock
Delete order.tbl, @ID
* release the record lock
Call @LOCK_PROC(O4W_LOCKHANDLER_ACTION_UNLOCK$, ORDER.TBL, @ID)
Delete O4WTempFile%, UniqueID:"*ORDERS*":@ID:"*ORIG"
return
retrieveCurrentRecord:
@ID = O4WGetValue("ONUM")
@RECORD = ""
{CUST_NO} = O4WGetValue("OCUST")
odate = O4WGetValue("ODATE")
* if no date filled in, use todays date
If odate = "" Then
odate = date()
End Else
odate = Iconv(odate,"D")
end
{ORDER_DATE} = odate
items = O4WGetValue("ITEM")
qtys = O4WGetValue("QTY")
prices = O4WGetValue("PRICE")
* trim off any blank lines
num.items = dcount(items, @VM)
For each.item = num.items To 1 step -1
If items<1,each.item> = "" Then
items = Delete(items, 1, each.item, 0)
qtys = Delete(qtys, 1, each.item, 0)
prices = Delete(prices, 1, each.item, 0)
End
Next each.item
{ITEM} = items
{QTY} = qtys
{PRICE} = Iconv(prices, "MD2")
Return
resetPages:
* blank out the order number
O4WUpdate("ONUM", "", textReplace)
@RECORD = ""
Gosub displayHeader
* mark as unchanged (as of now)
Gosub markAsFresh
* go to the first tab
O4WGoToTab("orderForm", 1)
return
handleOrderNumber:
* do we currently have an 'active' (changed) record in process?
isActive = O4WGetValue("activeRecord")
If isActive <> "" Then
* yes; build our dialog to verify the change of record
O4WSectionStart('specialDialog', selectedStyle:O4WResponseStyle())
* save the newly-entered order ID in the dialog
O4WStore(@ID, "ONUM", "ONUM")
* save the original item ID in the dialog, too
O4WStore(isActive, "ID", "ID")
O4WText("Discard any changes to existing record?")
O4WBreak()
O4WButton("Yes, Discard and Load New Record", "BTN_READ", selectedStyle)
O4WButton("No, Cancel and Keep Current Record", "BTN_CANCEL_READ")
* Notify us when these buttons are pressed with the 'click' event
O4WQualifyEvent("BTN_READ", "CLICK")
O4WQualifyEvent("BTN_CANCEL_READ", "CLICK")
O4WSectionEnd('specialDialog')
* and then show the dialog
O4WDialog('specialDialog', 'Confirm Discard of Any Changes','' ,'' , 'width:650')
return
End
* no, no currently active record - just load in the record for this @ID
Gosub loadRecord
Return
loadRecord:
If @ID = "" Then
* new order - get next sequential number
Lock @DICT, "%SK%" Else
O4WError("Unable to lock sequential counter record")
Return
END
Read NEXT.NUM From @DICT, "%SK%" Else NEXT.NUM = 1000
@ID = NEXT.NUM
Write NEXT.NUM +1 On @DICT, "%SK%"
Unlock @DICT, "%SK%"
* Update the text box with this order number
O4WUpdate("ONUM", @ID, textReplace)
End
* read in the record for this @ID
Gosub RetrieveRecord
* display the header and details
Gosub displayHeader
* Mark this record as unchanged (for now)
Gosub markAsFresh
* make sure we're on the first tab
O4WGoToTab("orderForm", 1)
Return
markAsFresh:
* turn off the browser page warning
O4WPlugin("$", "o4wsetConfirmUnload", "false")
* and clear out our own flag that indicates the record has changed
o4wUpdate("activeRecord", "", textReplace)
Return
markAsChanged:
* tell the browser that we need the "don't navigate away!" warning message
O4WPlugin("$", "o4wsetConfirmUnload", "true")
* remember what our current record ID is in case someone tries to change it
o4wUpdate("activeRecord", @ID, textReplace)
Return
displayHeader:
* load up the header fields
O4WUpdate("OCUST", {CUST_NO}, textReplace)
O4WUpdate("OCUSTNAME", {CUSTOMER_NAME}, textReplace)
O4WUpdate("ODATE", Oconv({ORDER_DATE}, "D"), textReplace)
* and fall through to update the details...
displayDetails:
* rebuild the section containing our order details
o4wSectionStart("orderDetails", O4WResponseStyle():deselectedStyle)
* build a table for our order lines
O4WTableStart("tableDetails", borderStyle:O4WSizeStyle("","100%"))
O4WTableHeader("Item", "2", "", size10pct)
O4WTableHeader("Description", "", "", size50pct)
O4WTableHeader("Cost", "", "", size10pct)
O4WTableHeader("Qty", "", "", size10pct)
O4WTableHeader("Ext Cost")
num.items = dcount({ITEM}, @vm) +1 ;* always have one blank row at the end
For each.item = 1 To num.items
O4WSetCell(each.item, 1,'' , borderStyle)
O4WButton("?", "BTN_SEARCH_PROD_":each.item)
* display some choices as to what type of popup should be run when this button is pressed
O4WQualifyEvent("BTN_SEARCH_PROD_":each.item, "CLICK")
O4WSetCell('','' ,'' , borderStyle)
* mark these with the 'o4wClearDuplicateVal' and 'o4wClearDuplicateText' styles so that the "Add" button clears out these fields when a new row is added
O4WTextBox({ITEM}<1,EACH.ITEM>, "", "", "ITEM", "ITEM_":each.item, "o4wClearDuplicateVal")
O4WSetCell('','','',borderStyle)
O4WText({DESCRIPTION}<1,EACH.ITEM>, "DESC_":each.item, "o4wClearDuplicateText")
O4WSetCell('','','',borderStyle)
O4WTextBox(Oconv({PRICE}<1,EACH.ITEM>, "MD2,$"), "", "", "PRICE", "PRICE_":each.item, rtJustn:"o4wClearDuplicateVal")
O4WSetCell('','','',borderStyle)
O4WTextBox({QTY}<1,EACH.ITEM>, "", "", "QTY", "QTY_":each.item, rtJustn:"o4wClearDuplicateVal")
O4WSetCell("", "", "", rtJustn:borderStyle)
O4WText(Oconv({EXT_COST}<1,EACH.ITEM>, "MD2,$"), "EXT_":each.item, "o4wClearDuplicateText")
Next each.item
O4WTableEnd("tableDetails")
* build another table to display the sub total
O4WTableStart("tableSummary", O4WSizeStyle("","100%"))
O4WSetCell(1,1,'', O4WSizeStyle("","90%"))
O4WSpace(5)
O4WSetCell(1,2,'' , rtJustn:borderStyle)
O4WText(Oconv({SUB_TOTAL}, "MD2,$"))
O4WTableEnd("tableSummary")
O4WButton("Add Row", "BTN_ADD")
O4WButton("Delete Row", "BTN_DEL")
* Automatically add or remove the last row when these buttons are pressed
O4WQualifyEvent("BTN_ADD", "ADDTOTABLE", "tableDetails", "-1")
O4WQualifyEvent("BTN_DEL", "DELETEFROMTABLE", "tableDetails", "-1")
* Notify us when any of the ITEM, QTY, or PRICE field values are changed
O4WQualifyEvent("ITEM", "CHANGE", "textbox")
O4WQualifyEvent("PRICE","CHANGE", "textbox")
O4WQualifyEvent("QTY", "CHANGE", "textbox")
o4wSectionEnd("orderDetails")
Return
{{image714.jpg?623x403}}
{{image716.jpg?623x403}}
{{image718.jpg?623x403}}
{{image720.jpg?623x403}}
{{image722.jpg?623x403}}
{{image724.jpg?623x403}}
=== Generic Edit Record Routine ===
Subroutine O4W_EDIT_RECORD(CtlEntId, Event, Request)
*
* O4W coding example
*
* Create, edit, or delete records in any table
* URL: http://.../oecgi4.exe/O4W_EDIT_RECORD
* or : http://.../oecgi4.exe/O4W_EDIT_RECORD?TABLE=
* or : http://.../oecgi4.exe/O4W_EDIT_RECORD?TABLE=&ITEM=
*
* Prompt the user for the table name, and (after it's selected) the item ID, or allow for entry of a new item ID, or
* Prompt the user for the item ID, or allow for entry of a new item ID, when a table name is passed in
* After the table and item name have been specified, determine which fields in the dictionary we can use, and build
* editable fields for each allowed dictionary item
*
* Main Program flow: CREATE event (which may call getID)
* CHANGE event (if table not specified in URL), which then calls getID
* CLICK event/BTNEDIT which then calls DisplaySection
*
* CLICK event/BTNCANCEL which then calls DisplaySection, or
* CLICK event/BTNSAVE which calls LockIT (may then call ChooseAnother), or
* CLICK event/BTNDELETE which calls LockIT (may then call ChooseAnother)
*
*
* Insert required equates and commons
$Insert O4WCommon
$Insert O4WEquates
* Since we're going to check the configuration record, include this equate as well
$Insert O4WConfigEquates
Declare Function Repository
* define some O4W "styles"
textReplace = O4WResponseStyle('','1','')
styleReplace = O4WResponseStyle('','','1')
selectMe = O4WMarkedStyle('','1')
deSelectMe = O4WMarkedStyle('','0')
enableMe = O4WInputStyle('','1')
disableMe = O4WInputStyle('','0')
promptColor = O4WColorStyle("", "lightblue")
* retrieve (if set) our unique id
uniqueID = O4WGetValue("O4WUniqueID")
* read the configuration record (using the appropriate repository method)
configRec = Repository("ACCESS", @APPID<1>:"*CONFIG*O4W*CFG_O4W")
Call Set_Status(0)
* determine the "filter procedure" that has been specified in the configuration record
FILTER_PROC = configRec
If FILTER_PROC = "" Then FILTER_PROC = "O4WI_FILTER"
Begin Case
Case Event _eqc "CREATE"
* Initial form creation
O4WForm()
* get our unique ID (set by o4wform)
uniqueID = O4WGetValue("O4WUniqueID")
O4WHeader("OpenInsight for Web: Create/Edit Records", 3)
O4WBreak()
O4WBreak()
* define the area for our 'breadcrumbs'
O4WSectionStart("breadcrumb", deSelectMe)
O4WSectionEnd("breadcrumb")
*...and define the breadcrumbs themselves
O4WBreadCrumbs("breadcrumb", "SELECTION":@VM:"EDITSECTION", O4WI_FORMATMSG(O4W_MESSAGE_BREADCRUMB_SELECT$):@VM:"Edit")
O4WBreak()
O4WBreak()
* this is the 'selection' page - allow the user to specify the table and item to edit
O4WSectionStart("SELECTION", selectMe)
* Might we be called with a table and item already specified?
TABLE = O4WGetValue("TABLE")
ID = O4WGetValue("ITEM")
bHaveBoth = 1
O4WTableStart("promptTable")
If table = "" Then
bHaveBoth = 0
* build the prompt for the table name
O4WSetCell(1,1)
O4WText("Please select the table: ")
* use the shorthand to move to the next cell in the current row
O4WSetCell()
* call the filter procedure to retrieve what table(s) we are allowed to work on
TLIST = Function(@FILTER_PROC("O4W_EDIT_RECORD", O4WSessionInfo%))
* build the list of tables into a listbox - and select 'none' to start
O4WListBox("Please select...", "", "TABLE", "", "tblNONE", selectMe)
O4WListbox(tlist, tlist, "TABLE",'' , tlist)
* mark the table name input so we know when one has been selected
O4WQualifyEvent("TABLE", "CHANGE", "LISTBOX")
* define a section for getting the ID once the table is selected
* of course, we can't actually fill this in yet - these are "placeholders" until the table has been chosen
O4WSetCell(2,1)
O4WText("Please select the record ID: ")
O4WSetCell(2,2)
O4WSectionStart("idSection")
O4WText("")
O4WSectionEnd("idSection")
O4WSetCell(3,1)
O4WText("Or enter the name of a record to create: ")
O4WSetCell(3,2)
O4WSectionStart("newidSection")
O4WText("")
O4WSectionEnd("newidSection")
End Else
* have table specified; what about item?
If ID = "" Then
* No, the item ID has not been passed in - build the list of available item ids
bHaveBoth = 0
O4WSetCell(1,1)
O4WText("Please select the ":TABLE:" record ID: ")
O4WSetCell()
Gosub getID
O4WSetCell(2,1)
O4WText("Or enter the name of a record to create: ")
O4WSetCell(2,2)
O4WTextbox("", "", "", "NEWITEM")
End
End
If bHaveBoth = 0 Then
* since we don't have both, put up the button to proceed when they _do_ have both specified
* use "+1" to increment the row (whatever it currently is)
O4WSetCell("+1", 2)
O4WButton("Edit", "BTNEDIT", selectMe)
* Qualify our "click" event
O4WQualifyEvent("BTNEDIT", "CLICK")
End
* finish up our table for the prompts
O4WTableEnd("promptTable")
* finish up the section (page) for the prompts
O4WSectionEnd("SELECTION")
* define the section (page) for the actual editing
O4WSectionStart("EDITSECTION", selectMe)
If id = "" Or table = "" Then
* don't have all the required pieces - just leave us on the selection page
O4WSetBreadcrumb("SELECTION")
End Else
* have both table and item id - move directly to the editing
O4WSetBreadcrumb("EDITSECTION")
Open TABLE To CODE.FL Else
O4WError("Unable to open table '":TABLE:"'")
Return
End
* call the lockhandler routine to read the original record
Call o4wi_lockhandler(O4W_LOCKHANDLER_ACTION_READ$, code.fl, id, info, UniqueID:"*":table:"*":id:"*ORIG")
Gosub displaySection ;* re-entry point to redisplay
end
o4wsectionEnd("EDITSECTION")
* preserve a section for our special messages
O4WSectionStart("specialDialog", selectMe)
O4WSectionEnd("specialDialog")
Case event _eqc "CHANGE"
* table to operate on has changed
O4WResponse()
* what table have they selected?
TABLE = O4WGetValue("O4WChangeID")
* rebuild the "placeholders" with the prompts for the id
O4WSectionStart("idSection", o4wresponsestyle())
Gosub getID
O4WSectionEnd("idSection")
*...and the prompt for a "new item"
O4WSectionStart("newidSection", o4wresponsestyle())
O4WTextbox("", "", "", "NEWITEM")
O4WSectionEnd("newidSection")
Case event _eqc "CLICK"
Begin Case
Case CTLENTID _EQC "BTNCANCEL"
* Throw away any changes, and refresh the page with a current copy of the record
O4WResponse()
TABLE = O4WGetValue("TABLE")<1,1>
ID = O4WGetValue("ID")<1,1>
If ID = "" Or TABLE = "" Then
* don't know what we were working on? That's a problem
O4WError("Unable to retrieve record")
Return
End
Open TABLE To CODE.FL Else
* Can't open the table we think we're working on? That's a problem
O4WError("Unable to open table '":table:"'")
Return
End
* re-read the record
Call o4wi_lockhandler(O4W_LOCKHANDLER_ACTION_READ$, code.fl, ID, info, UniqueID:"*":TABLE:"*":ID:"*ORIG")
* recreate the section containing the editable fields
O4WSectionStart("EDITSECTION", O4WResponseOptions():selectMe)
Gosub displaySection ;* redisplay this record
O4WSectionEnd("EDITSECTION")
Case CTLENTID _EQC "BTNSAVE" Or ctlentid _eqc "BTNSAVE2"
* called either on the original 'save' button press, or after selecting a new item ID
* make sure we can lock the record, and it hasn't been changed by anyone else since we originally read it in
Action = "Save"
Actionbtn = "BTNSAVE"
Gosub lockIT
If error = "" Then
* No problems - write it out
Call O4WI_Lockhandler(O4W_LOCKHANDLER_ACTION_WRITE$, code.fl, ID, INFO, UniqueID:"*":TABLE:"*":ID:"*ORIG")
* Display our "update successful" response
O4WError("Record '":ID:"' updated", "Save Record")
End
Case ctlentid _eqc "BTNCANCEL2"
* Called when cancelling the save/delete dialog
* Just dismiss the dialog
O4WDialog("specialDialog")
Case ctlentid _eqc "BTNDELETE"
* called to delete the record
* verify the deletion first
O4WResponse()
* retrieve the table and item id
ID = O4WGetValue("ID")<1,1>
TABLE = O4WGetValue("TABLE")<1,1>
* build our dialog to verify the deletion
O4WSectionStart('specialDialog', SelectMe:O4WResponseStyle())
* save the table and Item ID in the dialog
O4WStore(ID, "ID", "ID")
O4WStore(TABLE, "TABLE", "TABLE")
O4WText("Please verify deletion of record '":ID:"' in table '":table:"'")
O4WBreak()
O4WButton("Delete", "BTNDELETE2", selectMe)
O4WButton("Cancel", "BTNCANCEL2")
O4WQualifyEvent("BTNDELETE2", "CLICK")
O4WQualifyEvent("BTNCANCEL2", "CLICK")
O4WSectionEnd('specialDialog')
* and then show the dialog
O4WDialog('specialDialog', 'Confirm Deletion')
Case ctlentid _eqc "BTNDELETE2"
* called after confirmation of deletion action
* first, make sure we can lock the record and no one else has changed it since we read it
Action = "Delete"
Actionbtn = "BTNDELETE"
Gosub lockIT
If error = "" Then
* no problems - proceed with the deletion
* Check to see if this record already existed (ie, it wasn't a new record request)
Open table To code.fl Else
O4WError("Unable to open table '":TABLE:"'")
Return
End
Readv tstExist From code.fl, ID, 1 Else tstExist = ""
* do the actual deletion
Delete code.fl, ID
* release the record lock
Call O4WI_Lockhandler(O4W_LOCKHANDLER_ACTION_UNLOCK$, code.fl, ID)
Delete O4WTempFile%, UniqueID:"*":TABLE:"*":ID:"*ORIG"
* display our 'deletion successful' message
O4WError("Record '":ID:"' deleted", "Delete Record")
* If the record existed, remove it from our list of records on the selection page
If tstExist <> "" And bIsNew = 0 then
* refresh our list of available records
O4WScript('','o4wMoveValue("ITEM","","1");')
End
*...and move back to that selection page
O4WSetBreadcrumb("SELECTION")
End
Case CTLENTID _EQC "BTNEDIT"
* Called when the "Edit" button is pressed
O4WResponse()
* determine which table the user entered
table = O4WGetValue("TABLE")<1,1>
If table = "" Then table = ""
* determine whether the user selected a record name from the list, or entered a new one
existingItem = O4WGetValue("ITEM")
If existingItem = "" Then existingItem = ""
newItem = O4WGetValue("NEWITEM")
* make sure we have all the information we need, and it's valid
If existingItem = "" And newItem = "" Then
O4WError("You must specify a record to edit or create.")
Return
End
If table = "" Then
O4WError("You must specify which table to use")
Return
End
Open table To code.fl Else
o4werror("Unable to open table '":table:"'")
Return
end
If existingItem <> "" Then
* try to read the record
Call o4wi_lockhandler(O4W_LOCKHANDLER_ACTION_READ$, code.fl, existingItem, info, UniqueID:"*":table:"*":existingItem:"*ORIG")
* didn't read anything? That's not right...
If info = "" then
O4WError("Record '":existingItem:"' not on file in table '":TABLE:"'")
Return
End
ID = existingItem
End Else
* even if they keyed in the item id explicitly, still try to read it (maybe it _does_ exist)
Call o4wi_lockhandler(O4W_LOCKHANDLER_ACTION_READ$, code.fl, newItem, info, UniqueID:"*":table:"*":newItem:"*ORIG")
ID = newItem
End
* rebuild the section where the editable fields are displayed
O4WSectionStart("EDITSECTION", selectMe:O4WResponseStyle())
Gosub displaySection
O4WSectionEnd("EDITSECTION")
* set our breadcrumb so we display the editable section
O4WSetBreadcrumb("EDITSECTION")
End case
End Case
*
*
Return 0
*
*
*
lockIT: * verify underlying record is unchanged, And we can Lock it
error = "" ;* assume success
O4WDialog('specialDialog') ;* Dismiss dialog (if it's up)
TABLE = O4WGetValue("TABLE")<1,1>
Open TABLE To code.fl Else
error = "Table '":TABLE:"' could not be opened"
O4WError(error)
Return
End
* This may be a new record (potentially), or an existing record
bIsNew = 0
ID = O4WGetValue("NEWID")
If ID <> "" Then
bIsNew = 1
End else
ID = O4WGetValue("ID")<1,1>
End
If ID = "" Then
* couldn't retrieve the item ID
error = "Unable to access record ID"
O4WError(error)
Return
End
* call the lockhandler to see if the record is able to be locked, and is unchanged from its original state
stat = O4WI_LOCKHANDLER(O4W_LOCKHANDLER_ACTION_CHECK$, code.fl, id, curr.info, UniqueID:"*":table:"*":ID:"*ORIG", O4W_LOCKHANDLER_OPTION_LOCK$)
* the "check" method of the lockhandler will also retrieve the current contents of the record
* load in any changes made by the user into this current record
info = curr.info ;* we start with the original record, because in this routine we may not modify all fields
MAXFIELDS = O4WGetValue("MAXFIELDS")
For each.field = 1 To MAXFIELDS
* get the value (if any) for this field
* note that, since we may not have an entry for each field, we have to see if there was a field present for this field number
this.value = o4wgetvalue("FIELD_":EACH.FIELD, bStatus)
If bStatus Then
* yes, this field was present - continue processing
* if this value contained @VM or @SVM originally, and it wasn't marked as a multivalued field, we recorded that information
maybeConvert = o4wgetvalue("FIELD_":EACH.FIELD:"_TYPE")
If maybeConvert <> "" Then
* we had VM or SVM in the original - but not "M" in the dict
* we converted (for display) to a text area - that means each line is @TM delimited
* convert back to VM or SVM as appropriate
If maybeConvert = "0" Then
* we had @SVM in the original
Convert @TM To @SVM In this.value
End Else
* we had @VM in the original
Convert @TM To @VM In this.value
End
End
* record this information in the record
info = this.value
end
Next each.field
* finally, check for results from the 'check' call
If stat = O4W_LOCKHANDLER_NO_LOCK$ Then
* couldn't get the lock on this item - let the user choose another ID
error = "Unable to lock record '":ID:"' in table '":table:"'"
Gosub chooseAnother
Return
End
If stat = O4W_LOCKHANDLER_ITEM_CHANGED$ Then
* someone else changed the record while we worked on it - let the user choose another ID
error = "Record '":ID:"' in table '":TABLE:"' has been changed by another user"
* remember to unlock our current record, though
Call o4wi_lockhandler(O4W_LOCKHANDLER_ACTION_UNLOCK$, table, ID)
Gosub chooseAnother
Return
End
If bIsNew Then
* this is supposed to be a new record - is it?
Read tst From code.fl, id Else tst = ""
If tst <> "" Then
* some contents for this record already exists - we can't overwrite it - let the user choose another ID
error = "Record '":ID:"' already on file"
Gosub chooseAnother
return
end
O4WUpdate("ID", ID, textReplace)
end
Return
*
*
*
chooseAnother: * Give users option To rename record
* Use our special dialog for the entry prompts
O4WSectionStart('specialDialog', selectMe:O4WResponseStyle())
* save the loaded-in contents from the browser
O4WStore(INFO, "INFO", "INFO")
O4WText(Error)
O4WBreak()
O4WText("Enter a new name for this record (if desired): ")
O4WTextBox("", "", "",'' ,"NEWID")
O4WBreak()
O4WBreak()
O4WButton(ACTION, ACTIONBTN:"2", selectMe)
O4WQualifyEvent(ACTIONBTN:"2", "CLICK")
O4WSectionEnd('specialDialog')
* show the dialog
O4WDialog('specialDialog', 'Error During ':ACTION)
Return
*
*
displaySection: * show the editable record
O4WHeader("Table: ":TABLE:"; Record: ":ID, 3)
* Determine which fields to display, and how to display them...
* call the filter procedure to retrieve the list of valid dictionary items for us
DICT.IDS = Function(@FILTER_PROC("O4W_EDIT_RECORD", O4WSessionInfo%, TABLE))
* for each of the dictionaries, determine which one is the 'master' for each field
num.ids = dcount(DICT.IDS, @VM)
attinfo = ""
For each.id = 1 To num.ids
thisID = dict.ids<1,each.id>
dictInfo = Xlate("DICT.":table, thisID, "", "X")
If dictInfo <> "" Then
If dictInfo<1> = "F" And dictInfo<28> = "1" Then
fno = dictInfo<2>
If fno <> "0" Then
* determine the various pieces of information about this dictionary that we care about
isMV = dictInfo<4>
justn = dictInfo<9>
Locate justn In "L,R,C,T" Using "," Setting justPosn Then
* convert into O4W alignment code
justn = Field("0,2,1,-1", ",", justPosn)
end
colwidth = dictInfo<10>
Locate fno In attInfo<1> by "AR" Using @VM Setting posn Else
* store this relevant information away in the attInfo array for each field we'll work on
attInfo = Insert(attInfo, 1, posn, 0, fno)
attInfo = Insert(attInfo, 2, posn, 0, thisID)
attInfo = Insert(attInfo, 3, posn, 0, isMV)
attInfo = Insert(attInfo, 4, posn, 0, justn)
attInfo = Insert(attInfo, 5, posn, 0, colwidth)
End
end
end
end
Next each.id
* Start the table that will contain all the fields to display/edit
O4WTableStart('bigEdit')
num.atts = dcount(attInfo<1>, @VM)
For each.att = 1 To num.atts
* retrieve the relevant formatting,etc. information from the attInfo array we built
fno = attInfo<1,each.att>
fname = attInfo<2,each.att>
isMV = attInfo<3,each.att>
justn = attInfo<4, each.att>
colwidth = attInfo<5,each.att>
* set our cell to column one on each row, and set our color for this cell
O4WSetCell(each.att, 1,'' , promptColor)
* display the field number and the field name
O4WText(fmt(fno, "R#3"):". ":fname)
* move to column 2
O4WSetCell()
* get the current value
thisField = info
If isMV = "M" Then
* display the multivalues in a 'growing/shrinking' table with a fixed maximum size
O4WSectionStart("mvfield_":fno, O4WSizeStyle("", "", "300"))
num.val = dcount(thisField, @VM)
If num.val = 0 Then num.val = 1 ;* always allow at least one value so we draw at least one textbox
O4WTableStart("subtable_":fno)
* display some table headers to look nice
o4wtableheader("Action")
O4WTableHeader("Value")
For each.val = 1 To num.val
* get the current value
thisVal = thisField<1,each.val>
* move to the next row, column 1
O4WSetCell("+1", 1)
* add in our insert and delete buttons
* note the use of a "named style" for each button - either "insbutton" or "delbutton"
O4WButton("Ins", "BTN_INS_":fno:"_":EACH.VAL, "insbutton")
O4WButton("Del", "BTN_DEL_":fno:"_":EACH.VAL, "delbutton")
* move to column 2
O4WSetCell()
* display the contents, using the width and alignment from the dictionary
* we mark this with the "o4wClearDuplicateVal" named style, so that O4W knows to clear this out when it's duplicated with the "insert" button
O4WTextbox(thisVal, colwidth,'' , "FIELD_":fno, "", O4WTextStyle("", "", "", "", justn):"o4wClearDuplicateVal")
Next each.val
O4WTableEnd("subtable_":fno)
* add an additional "add" and "delete" set of buttons to add and delete the last row
O4WButton("Add Value", "BTN_ADD_":fno)
O4WButton("Delete Value", "BTN_DEL_":fno)
* qualify the add and delete buttons
O4WQualifyEvent("BTN_ADD_":fno, "ADDTOTABLE", "subtable_":fno, "-1")
O4WQualifyEvent("BTN_DEL_":fno, "DELETEFROMTABLE", "subtable_":fno, "-1")
O4WSectionEnd("mvfield_":fno)
* use a plugin so that, if the number of multivalues exceeds our fixed size, we'll have a scroll bar
O4WPlugin("$", "o4wScrollTable", "'subtable_":fno:"','mvfield_":fno:"','0'")
End Else
* _should_ be single valued display here
HAVE.VM = Count(thisField, @VM)
HAVE.SVM = Count(thisField, @SVM)
If HAVE.VM+HAVE.SVM Then
* what do we do about multivalue data here? Treat this as a text area...
Convert @VM:@SVM To @tm:@tm In thisField
O4WTextArea(thisField, colwidth, 5, "0", "FIELD_":fno)
* remember whether we had any @VM - if we did, that's what we'll use when we read the data back in
O4WStore(HAVE.VM, "", "FIELD_":fno:"_TYPE")
End Else
* actual single valued data, as expected
* display in a text box, justified and sized as specified in the dictionary
O4WTextbox(thisField, colwidth,'' , "FIELD_":fno, "", O4WTextStyle("", "", "", "", justn))
end
end
Next each.att
O4WTableEnd('bigEdit')
* use our "named style" for the insert and delete buttons to send a single qualify event for _all_ those buttons
* note the use of "." before the style name - this tells the qualify event that this applies to an entire named style, and not a specific O4W control
O4WQualifyEvent(".delbutton", "deleterow")
O4WQualifyEvent(".insbutton", "insertrow")
* save the ID and table name
O4WStore(ID, "", "ID")
O4WStore(TABLE, "", "TABLE")
* save the number of fields we operated on (so we know how many to retrieve)
O4WStore(NUM.ATTS, "", "MAXFIELDS")
O4WBreak()
* display our buttons
O4WButton("Save", "BTNSAVE")
O4WSpace(5)
O4WButton("Cancel", "BTNCANCEL")
O4WSpace(5)
O4WButton("Delete", "BTNDELETE")
* and qualify our buttons
O4WQualifyEvent("BTNSAVE", "CLICK")
O4WQualifyEvent("BTNCANCEL", "CLICK")
O4WQualifyEvent("BTNDELETE", "CLICK")
Return
*
*
getID: * build section For entry of ID
Call Set_Status(0)
Call Rlist("SELECT ":TABLE:" BY @ID", '5')
DONE = 0
ids = ""
Loop
Readnext thisid Else DONE = 1
Until DONE Do
ids<1,-1> = thisid
Repeat
If ids <> "" Then
O4WListBox('Select...', '', 'ITEM','' , 'itmNONE')
O4WListBox(ids, ids, 'ITEM')
End Else
O4WText("")
end
return
{{image726.jpg?623x351}}
{{image728.jpg?623x350}}
{{image730.jpg?623x496}}
=== Creating a subroutine to populate an O4W Listbox ===
{{image732.jpg?625x418}}
=== Creating a subroutine to populate an O4W Type ahead Listbox ===
{{image733.jpg?623x523}}