// WebHat setup: // // // // A Web object has an HTML representation in the output to the browser. It is an object that on // the command DoWriteHtml with some appropriate parameters writes itself out into the HTML output // stream. // // // Use WebPageBroker.nui // // // Image availability // ------------------ // // 1. Public. Anybody can request them as a separate URL without bothering // the Web Application. // // 2. Semi private. This means that they are in fact publicly available but they // reside in a folder that has its directory listing attribute set to false // and the images are named in an non sequential way (using 64 random // characters). This is security by obscurity. // // 3. Private. The image is located in a non-shared folder and is only sent // out by a request sanctioned by the web app (the Archie-strategy) // // // Image enumeration // ----------------- // // Public images (1) aren't enumerated. // // // // Design // ------ // // Design mekanismen skal baseres p† en stack. Set Design_Folder to lsFolderName // // // // // // // // // // // // Problem areas: // // Outer shell of system // // Form handling // // Page layout in general // // A common interface for integrating: // // Forms // Reports // Menues // Images // Image galleries // // // Note on WAF: // // The thingy may be used in three ways: // // 1. As the way to develop Web applications (that's what I do). I use the DDBuilder of course, and // the Studio to handcode the WAIP stuff. You have a nice overview of the project. // 2. // // 3. In conjunction with FastView that is now able to update a remotely running WebApp with DDO's // compiled into it. Very much in the FastView tradition. (I do this too) // //> doc.begin //> Motivated by the wish to generate larger and more complex web applications I have come //> up with a technique of letting all the HTML code be generated from within //> the WebApp itself. In the process the number of ASP files are reduced to 1 which is a //> very simple one: //> //> <% //> Dim SessionVariables //> SessionVariables = session ("SessionVariables") //> oWebApp1Page.Call "msg_DoSetSessionVariables", SessionVariables //> oWebApp1Page.Call "msg_DoWriteHtmlFullPage" //> SessionVariables = oWebApp1Page.Call("get_SessionVariables") //> session ("SessionVariables") = SessionVariables //> %> //> //> The DoWriteHtmlFullPage class writes the entire document. The remaining lines are //> concerned with session variables. Session variables are defined in the VDF code //> code and stored in the ASP layer where they belong. This is achieved by encoding //> all the values of session variables defined in the VDF code into one single value. //> //> The oWebApp1Page object is an empty shell except for the three messages called above. //> these messages are delegated to a global WebPageBroker object which is where the //> action starts taking place. //> //> This is the very basic idea. The rest is about figuring out a sensible way to //> structure the insides of such an application. //> //> A few notes: //> //> * There is nothing hindering the normal use of the WebApp framework at the same //> time as using the WAF approach (for the backend for example). //> //> * In designing the WAF I always used a process pooling license. It may or may not //> be possible to run a WAF application on a non PP license. //> //> //> Foundation - writing XHTML code //> ------------------------------- //> //> The cXmlBuilder class (XmlBuilder.nui) let's you build standard XML DOM in memory //> documents with no pain of object handle house keeping. As a second feature //> it lets you output the XML to a sequential channel as elements are being added (as //> opposed to building the complete document in memory first, which is the standard //> XML way). //> //> The WebAppXhtmlBuilder.nui package transforms this basic service into a set of //> globally defined procedures for writing XHTML code directly into the output //> stream of a web application. Brilliant, if I may say so. //> //> Using these procedures a XHTML document can be generated this way: //> //> send XHTML_StartXhtml //> send XHTML_Add_Open_Element "html" //> send XHTML_Add_Attribute "xmlns" "http://www.w3.org/1999/xhtml" //> //> send XHTML_Add_Attribute "xml:lang" "en" //> send XHTML_Add_Attribute "lang" "en" //> //> send XHTML_Add_Open_Element "head" //> send XHTML_Add_Closed_Element "title" "test page" //> send XHTML_Close_Element // head //> send XHTML_Add_Open_Element "body" //> // Generate the body of the document here. //> send XHTML_Close_Element // body //> send XHTML_Close_Element // html //> send XHTML_EndXhtml //> //> It's a technique one gets used to very fast. It lets you maintain the //> overview of the page structure at the same time as it lets you focus on //> the detail. //> //> At the same time it makes it pretty hard not to produce XHTML 1.0 compliant code. //> //> This is in contrast to the current implementation of the WebApp classes where //> HTML code is written out in a writeln sort of way. //> //> //> Layout objects //> -------------- //> A layout object is used whenever you want to //> //> //> //> //> //> The application structure //> ------------------------- //> //> In trying not to make any assumptions about the nature of the applications that //> need to built within this framework, I have come up with the following: //> //> //> Modules (WebModule) //> ------------------------- //> //> A WAF system is composed from a number of modules. A module is a group of pages //> that benefit from having access to a locally defined set of procedures and objects. //> //> These pages can be expected to have a (more or less) common page layout (or not). //> A module is a part of the system that you'd like to program as one unit. A module //> object functions as an encapsulation of web page objects that are likely to utilize //> the same set of functions (and page items). //> //> An example of a module could be the user login system of an application. That //> constitutes a number of pages with "sorry, wrong password" and "forgotten password" //> dialogs. //> //> Another example is that of a number of reports untilizing the same basic search //> mechanisms. //> //> Layout objects //> -------------- //> A layout object defines a set of div layers (areas) and their attributes expressed //> in terms of CSS proties (colors, sizes, positions, background image). More pages //> can be associated with the same layout object. Layout objects can be declared locally //> within modules or globally so that pages in all modules can use them. //> //> //> Pages (WebPage) //> --------------------- //> A module is composed of pages. Each page points to a layout object and the page //> object determines what goes inside the different div layers. It does so by means of //> the OnWriteLayer procedure. //> //> //> Web Forms //> --------- //> Lives an independant life inside WebBusinessProcess objects where they feed on //> the services of conventional DataDictionary's. Web forms may or may not be data //> base aware. //> //> //> Page items //> ---------- //> Page items are what the page objects puts inside a div layer (div layers that are defined a //> layout object). Page items are thing likes forms, menues, reports, image or image galleries, //> documents (by the time of writing these things aren't available). They are generating //> the actual XHTML. //> //> The point here is that you declare objects to hold the actual data needed to render the //> object and then you define other objects (or use the standard ones) for the actual //> XHTML rendering. //> //> For example, you would declare a cWebMenu object and define what items are in that menu. Then //> you will call a method in your preferred menu renderer passing a handle to the menu object //> as a parameter. //> //> Structuring the objects this way has the advantage of developers being able to create custom //> renderes that better suits their design. //> //> //> //> //> //> //> //> Preface //> ------- //> This package was deviced so that all the programming of a web application may go in //> the VDF code. The ASP files are done away with and there's only one ASP page left //> with 5 sorry lines of code in it (could be rewritten as one, but then clarity //> suffers ;-). This is the driving motivation. //> //> //> * No ASP pages (=faster development) //> * Full utilisation of DataDictionaries //> * Handles data aware as well as non data aware forms. //> * True XHTML 1.0 output (if you behave) //> * Faster rendering (based on div layers) //> * Still possible to get a decent design. //> * Checkboxes no problem //> //> //> doc.end //> //> Request sequence: //> //> Identification of module/page //> //> //> //> //> //> //> Use css.nui // CSS things Use LanguageDictionary.nui // cLanguageDictionary class Use WebAppXhtmlBuilder.nui // Global procedures for writing XHTML Use copyright.nui // sCopyrightText function Use WebSessionVariables.nui // Web session variables for ASP pages Use WebForm.nui // WebForm class Use WebError.nui Use WebQueryString.nui // Functions for constructing valid links Use WebMenu.nui Use WebLayout.nui // Different layout objects Use WebGlobalFunctions.nui // Use WebSelectionList.nui Use WebBrowser.nui // oWebBrowserInfo object Use WebFormNew.nui // ghoPageBroker points to the WebPageBroker object of the application integer ghoPageBroker Use ExtendedItemProp.nui // cExtendedItemPropertyArray class //> A web page makes use of a layout object which it most //> likely share with other objects (maybe there's only one layout object //> in the whole application). The different layers of of the layout_object //> are filled in by the web page object class WebPage is a cArray procedure construct_object forward send construct_object //> The WebPageBroker identifies pages using the value of the psPageName property //> (in combination with the value of the psModuleName property of the encapsulating //> WebModule object) property string psPageName //> Default behavior of procedure DoWriteHtml is to send DoWriteHtml //> to this object. property integer phPageLayoutObject property integer piRefreshSeconds public 0 // Set to 60 in order to have the page refreshed every minut // Setting pbIndependant to TRUE stops the object from automatically registering // with the encapsulating WebModule object. This makes it possible to declare a // WebPage object outside a WebModule structure and manually sending register_page // to the WebModules that should include the page. There you are: reusable web // pages!!! property integer pbIndependant public FALSE end_procedure procedure OnWriteCell string lsName integer liAux end_procedure function bAvailable returns integer // WebPage function_return TRUE end_function //> Make use of the session variables. Prepare data for display. Can also be used for //> refusing to accept to display by delegating the displaying to another webmodule/webpage. //> This may be achieved by calling the GotoPage method from within OnSetup. procedure OnPageSetup string lsSubmitButton string lsFormName string lsFormCollection ifnot (bAvailable(self)) send GotoPage "system" "pagenotavailable" end_procedure //> Store session variables. Clean up. I personally, have not used this yet. procedure OnDebrief end_procedure procedure DoWriteHtml // WebPage send DoWriteHtml of (phPageLayoutObject(self)) MSG_OnWriteCell self end_procedure procedure end_construct_object // WebPage forward send end_construct_object ifnot (pbIndependant(self)) send register_page self end_procedure end_class // WebPage //> Modules should be used for encapsulating a set of pages (a set of //> WebPage objects) that makes up some amount of functionality. //> The login system for instance, could be such a module. There's a //> a page for logging in, a page for 'forgotten password' a page for //> 'sign up new user' asf. //> class WebModule is a cArray procedure construct_object forward send construct_object property string psModuleName property string psDefaultPage end_procedure item_property_list item_property string psPageName.i item_property integer phPage.i end_item_property_list WebModule function hFindPage.s string lsPage returns integer integer liRow liMax get row_count to liMax decrement liMax for liRow from 0 to liMax if (psPageName.i(self,liRow)=lsPage) function_return (phPage.i(self,liRow)) loop function_return 0 end_function function DefaultPage returns string string lsPageName get psDefaultPage to lsPageName if (lsPageName="") get psPageName.i 0 to lsPageName // If none is set, we just take the first function_return lsPageName end_function procedure register_page integer lhObj integer liRow lhTmp string lsName get psPageName of lhObj to lsName get hFindPage.s lsName to lhTmp if lhTmp error 235 (replace("#","Page already registered (#)",lsName)) else begin get row_count to liRow set psPageName.i liRow to lsName set phPage.i liRow to lhObj end end_procedure procedure OnModuleSetup string lsPage string lsSubmitButton string lsFormName string lsFormCollection integer lhPage if (lsPage="") get DefaultPage to lsPage // If no page, get default get hFindPage.s lsPage to lhPage ifnot lhPage error 238 (replace("#","Page could not be found (#)",lsPage)) else begin send DetectRedirectionRecursion of ghoPageBroker lhPage send OnPageSetup of lhPage lsSubmitButton lsFormName lsFormCollection end end_procedure procedure onDebrief string lsPage integer lhPage if (lsPage="") get DefaultPage to lsPage // If no page, get default get hFindPage.s lsPage to lhPage ifnot lhPage error 239 (replace("#","Page could not be found (#)",lsPage)) else send onDebrief of lhPage end_procedure procedure DoWriteHTML string lsPage // WebModule. If lsFormName is <>"" then there was a form submitted integer lhPage if (lsPage="") get DefaultPage to lsPage // If no page, get default get hFindPage.s lsPage to lhPage ifnot lhPage error 237 (replace("#","Page could not be found (#)",lsPage)) else begin send DoWriteHtml of lhPage end end_procedure procedure end_construct_object // WebModule forward send end_construct_object send WafRegisterModule self end_procedure end_class // WebModule // Every WebModule object declared will register with // this object (oWafModuleList) object oWafModuleList is a cArray item_property_list item_property string psModuleName.i item_property integer phModule.i end_item_property_list function hFindModule.s string lsName returns integer integer liRow liMax get row_count to liMax decrement liMax for liRow from 0 to liMax if (psModuleName.i(self,liRow)=lsName) function_return (phModule.i(self,liRow)) loop function_return 0 end_function procedure register_module integer lhObj integer liRow lhTmp string lsName get psModuleName of lhObj to lsName get hFindModule.s lsName to lhTmp if lhTmp error 234 (replace("#","Module already registered (#)",lsName)) else begin get row_count to liRow set psModuleName.i liRow to lsName set phModule.i liRow to lhObj end end_procedure end_object // oWafModuleList function WafModuleObject global string lsModule returns integer integer lhObj get hFindModule.s of oWafModuleList lsModule to lhObj function_return lhObj end_function function WafPageObject global string lsModule string lsPage returns integer integer lhObj get WafModuleObject lsModule to lhObj if lhObj get hFindPage.s of lhObj lsPage to lhObj function_return lhObj end_function procedure WafRegisterModule global integer lhObj send register_module of oWafModuleList lhObj end_procedure function WafPageLink global string lsModule string lsPage returns string string lsAction get waf_config_value WACFG_ASP_FILE to lsAction send QryString_Prepare lsAction send QryString_AddParam "m" lsModule send QryString_AddParam "p" lsPage function_return (QryString_Value()) end_function function WafPageLinkSelect global string lsModule string lsPage string lsSelect string lsParam returns string string lsAction get waf_config_value WACFG_ASP_FILE to lsAction send QryString_Prepare lsAction send QryString_AddParam "m" lsModule send QryString_AddParam "p" lsPage send QryString_AddParam "s" lsSelect send QryString_AddParam "r" lsParam // r is used because it's mostly a ecord id. function_return (QryString_Value()) end_function class WebPageBroker is a cArray procedure construct_object forward send construct_object property string psHtmlLanguage public "en" property string psHtmlHeaderTitle public "My fantastic application" property string psHtmlHeaderCopyrightCompany public "Lego Ego" property string psHtmlHeaderCopyrightYear public "2004" property string psHtmlHeaderGenerator public "Visual DataFlex" // property string psHtmlHeaderAppName public "CoolApp" // property string psHtmlHeaderAppVer public "1.0" // If module can't be determined any other way, we use this: property string psDefaultModule // property string psNextModule property string psNextPage property integer pbRedirectionRecursion move self to ghoPageBroker object oRedirectionRecursion is a cStack end_object end_procedure item_property_list item_property string psPageName.i item_property integer phPage.i end_item_property_list WebPageBroker function DefaultModule returns string function_return (psDefaultModule(self)) end_function procedure HandleError integer liError integer liErrorLine string lsErrorText string lsError move "Error # line #: #" to lsError move (replace("#",lsError,string(liError))) to lsError move (replace("#",lsError,string(liErrorLine))) to lsError move (replace("#",lsError,lsErrorText)) to lsError send XHTML_Add_Closed_Element "p" lsError end_procedure procedure DetectRedirectionRecursionReset integer lhPage set pbRedirectionRecursion to false send delete_data of oRedirectionRecursion end_procedure procedure DetectRedirectionRecursion integer lhPage integer lbErr get bIsOnStack.i of oRedirectionRecursion lhPage to lbErr if lbErr set pbRedirectionRecursion to true else send push.i of oRedirectionRecursion lhPage end_procedure procedure HandleErrorsDuringPreSubmit #IFDEF Is$WebApp // For this we use the standard WebApp way: send OutputHTML of ghInetSession "" send ReportAllErrors of ghInetSession "Errors occurred during pre-submit" send OutputHTML of ghInetSession "" send ClearErrors of ghInetSession #ENDIF end_procedure procedure onNewRequest end_procedure procedure PreWriteBody end_procedure procedure PostWriteBody end_procedure procedure DoWriteHtmlHeaderSection integer lhPage string lsValue integer liValue get psHtmlHeaderTitle to lsValue if (lsValue="") move "No title" to lsValue send XHTML_Add_Closed_Element "title" lsValue get psHtmlHeaderGenerator to lsValue if (lsValue<>"") begin send XHTML_Add_Closed_Element "meta" "" send XHTML_Add_Attribute "name" "generator" send XHTML_Add_Attribute "content" lsValue end if (lhPage and piRefreshSeconds(lhPage)) begin // Set page refresh rate send XHTML_Add_Closed_Element "meta" "" send XHTML_Add_Attribute "http-equiv" "refresh" send XHTML_Add_Attribute "content" (piRefreshSeconds(lhPage)) end // Set no-cache send XHTML_Add_Closed_Element "meta" "" send XHTML_Add_Attribute "http-equiv" "pragma" send XHTML_Add_Attribute "content" "no-cache" get psHtmlHeaderCopyrightCompany to lsValue get psHtmlHeaderCopyrightYear to liValue if (lsValue<>"") begin send XHTML_Add_Closed_Element "meta" "" send XHTML_Add_Attribute "name" "copyright" send XHTML_Add_Attribute "content" (sCopyrightText(liValue,lsValue)) end send XHTML_Add_Closed_Element "script" "" send XHTML_Add_Attribute "type" "text/javascript" send XHTML_Add_Attribute "src" "inc/waf.js" // get Waf_MetaInfo WA_STYLESHEET1 to lsValue // if (lsValue<>"") begin // send XHTML_Add_Closed_Element "link" "" // send XHTML_Add_Attribute "rel" "stylesheet" // send XHTML_Add_Attribute "href" lsValue // send XHTML_Add_Attribute "type" "text/css" // end end_procedure procedure DoSetUrlAndQueryString string lsUrl string lsQueryStr string lsPrevQueryStr get value of oBaseSessionVariables WSV_CURRENT_QRYSTR to lsPrevQueryStr set value of oBaseSessionVariables WSV_PREV_QRYSTR to lsPrevQueryStr set value of oBaseSessionVariables WSV_CURRENT_URL to lsUrl set value of oBaseSessionVariables WSV_CURRENT_QRYSTR to lsQueryStr end_procedure //Firefox: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1 //Opera: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54 [en] //Mozilla: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040608 //IE 6.0: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) procedure DoSetBrowser string lsBrowser string lsVersion send DecodeUserAgent of oWebBrowserInfo lsBrowser end_procedure procedure OnNewSession end_procedure register_function HandleSubmit returns string register_procedure OnEndOfRequest // Called when the web application is done generating each html response procedure DoWriteHTML // WebPageBroker integer lbSessionActive lhModule lhPage lhWebForm lhErrHnd lbHtmlTest lbOk lbContinue liLng lhLayout string lsModule lsPage lsError lsLang lsSubmitButton string lsFormName lsFormCollection // We start by setting the language, if the session is new get value of oBaseSessionVariables WSV_SESSION_ACTIVE to lbSessionActive ifnot lbSessionActive begin set value of oBaseSessionVariables WSV_SESSION_ACTIVE to 1 set value of oBaseSessionVariables WSV_LANGUAGE to LNG_DEFAULT // Get session language to global variable send OnNewSession end get value of oBaseSessionVariables WSV_LANGUAGE to liLng // Get session language to global variable send select_current_language liLng move 0 to ghFormSubmitted // Reset indication of form having been submitted. (It's set from within WebForm.nui) #IFDEF Is$WebApp send ErrorQueueStart To ghInetSession // Pick up errors during pre-submit code. #ENDIF // Get name of submitted form (if any): get WafGetHtmlFormValue "htmlform_name" to lsFormName // If lsFormName is <>"" then there was a form submitted // Get name of form collection for submitted form (if any): get WafGetHtmlFormValue "htmlform_collection" to lsFormCollection move (lowercase(WafGetQueryString("html"))="true") to lbHtmlTest if lbHtmlTest set pbTest of oWebAppHtmlBuilder to true send onNewRequest #IFDEF Is$WebApp send ErrorQueueEnd To ghInetSession // Stop error queue and report errors if any. if (ErrorCount(ghInetSession)) send HandleErrorsDuringPreSubmit else begin #ELSE if TRUE begin #ENDIF if (lbSessionActive<>0 and lsFormName<>"") begin // A form has been submitted! We now have to identify this form within the application // and let that handle the thing. Note that this happens at a time when the XHTML output // hasn't been initiated yet: get WebForm_FindFormObject lsFormName lsFormCollection to lhWebForm set psNextModule to "" set psNextPage to "" get HandleSubmit of lhWebForm to lsSubmitButton // Now check if the handling of the submit has determined which page // we should now call: get psNextModule to lsModule get psNextPage to lsPage end else begin move "" to lsModule move "" to lsPage send WebForm_ClearErrors // No errors hanging from somebody elses submit. end if (lsModule="" and lsPage="") begin // Figure out which module/page we should call. // First we see if page/module was passed on the HTML request query string: get WafGetQueryString "m" to lsModule move (lowercase(lsModule)) to lsModule // If module was specified by the query string, we'll look for a page if (lsModule<>"") begin get WafGetQueryString "p" to lsPage move (lowercase(lsPage)) to lsPage end else move "" to lsPage // If module is blank, ignore page parameter end if (integer(value(oBaseSessionVariables,WSV_SESSION_ACTIVE))) begin // If module is blank, get previous module if (lsModule="") begin get value of oBaseSessionVariables WSV_MODULE_NAME to lsModule if (lsModule<>"") get value of oBaseSessionVariables WSV_PAGE_NAME to lsPage end end // If module is still blank, get default module if (lsModule="") begin get DefaultModule to lsModule // If page is blank, get previous page end send DetectRedirectionRecursionReset move 1 to lbOk repeat get WafModuleObject lsModule to lhModule ifnot lhModule begin move "Module could not be found (#)" to lsError move (replace("#",lsError,lsModule)) to lsError error 236 lsError move 0 to lbOk end if (lsPage="") get DefaultPage of lhModule to lsPage set psNextModule to lsModule set psNextPage to lsPage send OnModuleSetup of lhModule lsPage lsSubmitButton lsFormName lsFormCollection move (psNextModule(self)=lsModule and psNextPage(self)=lsPage) to lbContinue ifnot lbContinue begin get psNextModule to lsModule get psNextPage to lsPage end until lbContinue if (pbRedirectionRecursion(self)) begin move "system" to lsModule move "error" to lsPage end if lbOk begin // Activate our own web error handler: move oWebErrorHandler to lhErrHnd send delete_data of lhErrHnd send DoActivate of lhErrHnd set value of oBaseSessionVariables WSV_MODULE_NAME to lsModule set value of oBaseSessionVariables WSV_PAGE_NAME to lsPage get WafModuleObject lsModule to lhModule get WafPageObject lsModule lsPage to lhPage get phPageLayoutObject of lhPage to lhLayout if (lhLayout<>0 and piType(lhLayout)=LAYOUTTYPE_HTML_PAGE) begin send XHTML_StartXhtml send DoDeactivate of lhErrHnd send DoWriteHtml of lhModule lsPage send XHTML_EndXhtml end else begin send XHTML_StartXhtml send XHTML_OpeningOath // This complete XHTML document. send XHTML_Add_Open_Element "html" send XHTML_Add_Attribute "xmlns" "http://www.w3.org/1999/xhtml" get psHtmlLanguage to lsLang if (lsLang="") move "en" to lsLang send XHTML_Add_Attribute "xml:lang" lsLang send XHTML_Add_Attribute "lang" lsLang send XHTML_Add_Open_Element "head" send DoWriteHtmlHeaderSection (WafPageObject(lsModule,lsPage)) send XHTML_Close_Element // head send XHTML_Add_Open_Element "body" send PreWriteBody send DoWriteHtml of lhModule lsPage if (ErrorCount(lhErrHnd)) begin // Here we handle the incident that the error handling object // has some un-handled errors. send XHTML_Add_Open_Element "div" send XHTML_Add_Attribute "class" "UnhandledErrors" send DoDeactivate of lhErrHnd send CallBack of lhErrHnd MSG_HandleError self send XHTML_Close_Element // div end send PostWriteBody send XHTML_Close_Element // body send XHTML_Close_Element // html send XHTML_EndXhtml end if lbHtmlTest set pbTest of oWebAppHtmlBuilder to false send DoDeactivate of lhErrHnd // Very important!! Otherwise the error handler will survive to next request send onDebrief of lhModule lsPage broadcast recursive send OnEndOfRequest to desktop // get value of oBaseSessionVariables WSV_SESSION_ACTIVE to lbSessionActive // ifnot lbSessionActive set value of oBaseSessionVariables WSV_SESSION_ACTIVE to 1 // set value of oBaseSessionVariables WSV_MODULE_NAME to lsModule // set value of oBaseSessionVariables WSV_PAGE_NAME to lsPage end end // end_procedure end_class // WebPageBroker procedure GotoPage global string lsModule string lsPage set psNextModule of ghoPageBroker to lsModule set psNextPage of ghoPageBroker to lsPage end_procedure //send Delete_data to (oErrorHandlerQuiet(self)) //send DoActivate to (oErrorHandlerQuiet(self))