* TUTOSERVER.PRG
* FoxInCloud Application Server classes (shared by test and production versions of Web Application)
* C:\PROGRAM FILES (X86)\ABAQUE\FICSAMPLES\FICTUTO\PROGS\TUTOSERVER.PRG (included in c:\program files (x86)\abaque\ficsamples\fictuto\fictuto.exe)
* (1,405 lines before localization)
* ========================================================================================================================

&& FoxInCloud Adaptation Assistant (FAA) step 3-Publish created this program

#if File('aw.h')
  #include aw.h && in <Home(1)>\tools\ab\aw\ licensed users
#else
  #include ab.h && in <Home(1)>\tools\ab\ all users
#endif

* ================================================================================
DEFINE CLASS tutoServer AS awServer OF awServer.prg
&& tutoServer is your FoxInCloud Application Server (FAS) class
&& FoxInCloud Adaptation Assistant (FAA) creates 2 OLEPUBLIC sub-classes of this class:
&& - tutoServerTest as your test server,
&& - tutoServerProd as your production server.
&& We recommend you install both these servers on your physical production server to that
&& your clients and you can test the new features before pushing them to production.
&& As both versions share the same code, you can develop on either one.
* ================================================================================

&& To add static properties to your server,
&& make sure to declare these additional properties PROTECTED to leave your COM server's signature unchanged (otherwise you'll need to re-register it on your production server(s))

#if .F.
  protected yourServerProperty
  yourServerProperty = someValue
#endif

&& all protected properties of your server are automatically added to your application host class (xxxAppHost as awAppHost of awAppHost.fxp)
&& you'll gain access to these properties:

#if .F.

&& - from your xxxProcess or xxxAjax object through:
this.oAppHost.yourServerProperty

&& - from your application code through:
local oAppHost
if wlAppHost(@m.oAppHost)
  m.oAppHost.yourServerProperty = someValue
endif

#endif

* ===========================================
&& BASE SETTINGS
* ===========================================

cawServerIni = ''
&& REQUIRED
&& .ini file for awServerConfig; must be in the same folder as the project
&& to be defined in your tutoServerTest|Prod subclasses
&& Typical values: tutoTest.ini / tutoProd.ini

&& ------------------------------------------------
&& The 3 following settings allow you to define the code module which SETs you application's execution environment
&& This code may be either a class in a .prg or a .vcx, a standalone procedure in a .prg or a .prg
&& Ideally this code is shared with the LAN version to ensure a identical execution environement in both modes
&& You may SET almost anything; if necessary, FoxInCloud will save/restore conflicting settings
&& ------------------------------------------------

cAppSetsLib = 'tutoSets.prg' && tutoSets.prg
&& REQUIRED
&& Fullpath of .prg or .vcx where resides class or procedure SETting application's environment

cAppSets = 'tutoSets' && tutoSets
&& Name of class or procedure SETting application's environment located in <this.cAppSetsLib>
&& If Empty(), <this.cAppSetsLib> is executed
&& <this.cAppSetsLib>
&& <this.cAppSetsLib> est exécutée

lAppSetsClass = .T. && .T.
&& this.cAppSets is a class defined in <this.cAppSetsLib>.prg
&& <this.cAppSetsLib>.prg

&& ------------------------------------------------
&& Here you will decide how your master forms will be included into an HTML page; you may either:
&& - generate them with a sub-class of 'awProcess' AS ILLUSTRATED IN THE EXAMPLE BELOW
&& - produce them with ASP, ASPX, PHP, etc. by including HTML code produced by FoxInCloud with a server-side Include Directive
&& ------------------------------------------------

cawProcessClass = 'tutoProcess' && tutoProcess AS awProcess OF awServer.prg
&& REQUIRED
&& FoxInCloud Process class
&& Sub-class if you want to build HTML pages with wConnect
&& This method is preferrable as FoxInCloud instantiates forms dynamically with whatever parameter passed.
&& To build a standard form page, just call <your sub-class of awProcess>::wFormStandardPage(<form>[, <parameter1>[, <parameter2>[, ...]]])
&& <votre sous-class d'awProcess>::wFormStandardPage(<formulaire>[, <paramètre1>[, <paramètre2>[, ...]]])

cawAppConfigClass = 'tutoAppConfig' && tutoAppConfig AS awAppConfig OF awServer.prg
&& FoxInCloud application configuration class
&& sub-class if you need extra parameters that you can modify on line

uFormsLaunchAtStartup = Iif(Empty(_VFP.Startmode); && development
  , '';
  , 'index.scx, event.scx'; && , dataUpdate.scx, modal.scx, report.scx, rowSourceType.scx, userChoice.scx, valuesDelayed.scx, pagedGrid.scx, keyPress.scx, eventLog.scx, rowColChange.scx, remoteGrids.scx
  )
&& Top-Level form(s) to be instantiated at server startup, .T. to launch all forms, empty() launches none
&& Declare Top-Level forms if you use ASP, ASPX, PHP or any mean to build your HTML pages, rather than a sub-class of 'awProcess' (this.cawProcessClass)
&& If you use a sub-class of 'awProcess' (recommended as explained above), you can instantiate forms just when needed by calling a tutoProcess::wForm*() method
&& Coma-separated list: *.scx, class, *.vcx
&& *.vcx: all form classes contained in the class library are instantiated; in this cas, awAppConfig::cPrgPath is REQUIRED
&& *()
&& *.scx, class, *.vcx
&& *.vcx : toutes les classes Form contenues dans le .vcx sont instanciées; dans ce cas awAppConfig::cPrgPath est REQUIS

&& ------------------------------------------------
&& Special users for the web application
&& ------------------------------------------------

wUserAnonymous = .null.
&& User ID meaning 'anonymous user' for your application
&& Generally, it's a value of users table primary key that does not exist in the table
&& For example, if User table PK is an integer, it could probably be 0

wUserDemo = .NULL.
&& Demo User ID for your application
&& The Demo User may have several sessions opened simultaneously
&& If isNull(), no Demo User exist

wlUserTemp = .F.
&& Your Application manages user identity impersonnation

* ===========================================
&& EXPERT SETTINGS
* ===========================================

&& Properties thereafter have, by default, the value inherited from awServer

&& ------------------------------------------------
&& Using jQuery for client scripts
&& ------------------------------------------------

ljQueryAdd = .T.
&& Add jQuery scripts and CSS to HTML pages /!\ please note that FoxInCloud.js will soon enter into a migration from Prototype.js to jQuery.js, so in a next release jQuery.js will be loaded be default and this will deprecate this option.

ljQueryUIadd = .T.
&& Add jQuery UI scripts and CSS to HTML pages /!\ please note that FoxInCloud.js will soon enter into a migration from Scriptaculous.js to jQueryUI.js, so in a next release jQueryUI.js will be loaded be default and this will deprecate this option.

cjQueryUItheme = 'cupertino' && 'base', 'black-tie', 'blitzer', 'cupertino', 'dark-hive', 'dot-luv', 'eggplant', 'excite-bike', 'flick', 'hot-sneaks', 'humanity', 'le-frog', 'mint-choc', 'overcast', 'pepper-grinder', 'redmond', 'smoothness', 'south-street', 'start', 'sunny', 'swanky-purse', 'trontastic', 'ui-darkness', 'ui-lightness', 'vader'
&& jQuery UI theme; must match a folder name in awScripts/jQuery-ui-*/themes
&& You can also define this theme in your app's configuration file: tutoTest|Prod.ini
&& http://jqueryui.com/themeroller/ demonstrates these standard themes and allows you,
&& if you wish, to create your own custom theme.
&& */themes

&& ------------------------------------------------
&& Using Bootstrap HTML generation
&& http://getbootstrap.com/

&& 2016-11-30 -- {FiC V 2.23.0} added
&& ------------------------------------------------

lBootstrapAdd = .T.
&& Add Bootstrap JavaScript and CSS to the HTML page
&& forces this.ljQueryAdd = .T.
&& Set at form level using form.wBSlHTMLgen = .T.
&& Régler au niveau de chaque formulaire par form.wBSlHTMLgen = .T.

lFontAwesomeAdd = .T. && 2016-11-30 thn -- {FiC V 2.23.0} added for Bootstrap support
&& Add 'Font Awesome' CSS to the HTML page

lPrototypeAdd = .F.
&& load Prototype.js (http://prototypejs.org/) and dependent scripts: Scriptaculous, PrototypeWindowClass, event.simulate, etc.
&& if .F. and !this.BSlHTMLgen, this.ljQueryUIdialog forces to .T.
&& please run your application with .F. ASAP because default will soon change to .F.
&& make sure to:
&& - REPLACE $() calls by jQuery calls in: your event methods, .wcHTMLgen() and xxx.js
&& - REPLACE 'Object.extend' by 'jQuery.extend' in xxx.js

&& ------------------------------------------------
&& Sub-classing the FoxInCloud framework
&& ------------------------------------------------

cawAppHostClass = 'awAppHost' && tutoAppHost AS awAppHost OF awAppHost.fxp
&& FoxInCloud Application Host class
&& Sub-class awAppHost if you want to implement some hook method:
&&   .Init_App_Ante(): before Application is initialised
&&   .Init_App_Post(): after Application is initialised
&&   .Destroy_App_Ante(): before Application is destroyed
&&   .Destroy_App_Post(): after Application is destroyed

cawHTMLGenClass = 'tutoHTMLgen' && tutoHTMLgen AS awHTMLgen OF awHTML.fxp && awHTMLgen
&& FoxInCloud HTML generation class
&& Sub-class awHTMLgen if you have specific HTML generation needs that objects' .wcHTMLgen() method cannot meet

cawAJAXClass = 'tutoAJAX' && tutoAJAX AS awAJAX OF awServer.fxp
&& FoxInCloud AJAX class
&& sub-class awAJAX if you have specific AJAX requests
&& In this cas you may need to extend FoxInCloud.js with specific methods and/or handler events

cawSessionClass = 'awSession' && tutoSession AS awSession OF awServer.fxp
&& Session class ('awSession' sub-class)
&& Sub-class awSession if you need some extra fields or indexes in session standard table 'wwSession'

cawProcessSetsClass = 'awProcessSets' && tutoProcessSets AS awProcessSets OF awServer.fxp
&& Request environment SETter class
&& Sub-class awProcessSets if you need specific SETs when processing 'conventional' requests

cDataSyncClass = 'acDataSyncVFP' && as acDataSyncVFP of acData.prg
&& Up data Synchronization class
&& Sub-class acDataSyncVFP if you need additional functionalities

cFrmIBclass = 'ficFrmIB' && as awFrmIB of aw.vcx
&& InputBox() Web form class

cFrmLogErrorClass = 'ficFrmLogError' && as awFrmLogError of aw.vcx
&& Error browsing form class

cFrmMBclass = 'ficFrmMB' && as awFrmMB of aw.vcx
&& MessageBox() Web form class

cScriptMapExts = 'php,pl,vfp,zip'
&& URL extensions processed by this.cawProcessClass
&& These extensions must be 'mapped' to ...\bin\wc.dll in the web server

&& --------------------------------------------------------------------------------------------------------------------------------------
&& Adjusting the PUBLIC variables, _Screen.properties and _VFP.properties automatic, user-based save and restore feature
&& --------------------------------------------------------------------------------------------------------------------------------------

lAppUserEnvSave = .T.
&& save / restore application environment for each user
&& (.F. is the default setting for back compatibility)
&& IF your application makes no use of user-dependent 'global' (application level) elements:
&& - no menu (_msysmenu or others),
&& - no toolbar,
&& - no PUBLIC variables, _Screen.properties or _VFP.properties where your application stores user-dependent data,
&& (IOW what your application stores in PUBLIC variables / _Screen.properties / _VFP.properties are application-wide data that never change during user actions),
&& THEN you can keep tutoServer.lAppUserEnvSave = .F.
&& OTHERWISE you need tutoServer.lAppUserEnvSave = .T.
&& tutoProcess.lAppUserEnvSave() lets you fine tune which users or requests you'll save application environment for.

&& The following settings assume this.lAppUserEnvSave = .T.

lPublicVariablesAllAtStartup = .T.
&& Are all PUBLIC variables created at application startup?
&& = .T. (optimized): all PUBLIC variables are created at application startup, don't check their existence at each request
&& = .F. (discouraged): at each request, check each PUBLIC variable in in scope, declare it if not
&& To use the .T. setting, you need to make sure all your PUBLIC declarations are in your application initialization program (tutoSets.prg)
&& To do so, you can simply copy or move them all into tutoSets.prg!tutoSets.init()

cPublicVariablesObjectSave = 'goApp'
&& Public variables of type Object that you need to save for each user, delimited by ',', case-insensitive
&& = empty or .null.: no PUBLIC variable of type Array is saved
&& = string: save PUBLIC variable indicated if they exist and are of type Object
&& You must indicate exact names; skeletons are not supported
&& Public variables of any other type (including arrays) are saved automatically

_ScreenPropertiesSave = .null.
&& Names and or skeletons of _Screen.Properties that need be saved, delimited by ',', case-insensitive
&& = .null. : save all properties added to _Screen
&& = '' ou .F.: save no property added to _Screen
&& Indicate here the properties added to _screen the value of which depends on user actions, hence must be saved
&& You can combine exact names and name skeletons (eg. 'zzz*' to save all properties with a name starting by 'zzz')
&& You can add properties to _Screen by addProperty(_Screen, 'myProperty', maValue) or _Screen.addProperty('myProperty', maValue)
&& Properties dynamically added to _Screen (during the course of user actions) are supported.
&& Note: objects added to _Screen by _Screen.AddObject() are not currently supported && if you need this kind of support, please let us know at support@foxincloud.com
&& If you use many _Screen.Properties, this setting will optimize request response time.
&& *' pour sauver toutes les propriétés dont le nom commence par 'zzz')

_ScreenPropertiesSaveNot = ''
&& _Screen.Properties that you don't need to save, delimited by ',', case-insensitive
&& = empty or .null.: save properties defined by this._ScreenPropertiesSave
&& = string: save properties defined by this._ScreenPropertiesSave except those matching the names or skeleton indicated
&& Indicate here the properties added to _screen the value of which does not depend on user actions, hence need not be saved
&& You can combine exact names and name skeletons (eg. 'zzz*' to not save properties with a name starting by 'zzz')
&& You can add properties to _Screen by addProperty(_Screen, 'myProperty', maValue) or _Screen.addProperty('myProperty', maValue)
&& If you use many _Screen.Properties, this setting will optimize request response time.
&& *' pour ne pas sauvegarder les propriétés dont le nom commence par 'zzz')

_VFPpropertiesSave = .null.
&& Names and or skeletons of _VFP.Properties that need be saved, delimited by ',', case-insensitive
&& = .null. : save all properties added to _VFP, except arrays which are not supported
&& = '' ou .F.: save no property added to _VFP
&& Indicate here the properties added to _VFP the value of which depends on user actions, hence must be saved
&& You can combine exact names and name skeletons (eg. 'zzz*' to save all properties with a name starting by 'zzz')
&& You can add properties to _VFP by addProperty(_VFP, 'myProperty', maValue) or _VFP.addProperty('myProperty', maValue)
&& Properties dynamically added to _VFP (during the course of user actions) are supported.
&& Arrays are NOT supported.
&& If you use many _VFP.Properties, this setting will optimize request response time.
&& *' pour sauver toutes les propriétés dont le nom commence par 'zzz')

_VFPpropertiesSaveNot = ''
&& _VFP.Properties that you don't need to save, delimited by ',', case-insensitive
&& = empty or .null.: save properties defined by this._VFPpropertiesSave
&& = string: save properties defined by this._VFPpropertiesSave except those matching the names or skeleton indicated
&& Indicate here the properties added to _VFP the value of which does not depend on user actions, hence need not be saved
&& You can combine exact names and name skeletons (eg. 'zzz*' to not save properties with a name starting by 'zzz')
&& You can add properties to _VFP by addProperty(_VFP, 'myProperty', maValue) or _VFP.addProperty('myProperty', maValue)
&& If you use many _VFP.Properties, this setting will optimize request response time.
&& *' pour ne pas sauvegarder les propriétés dont le nom commence par 'zzz')

lFormVariableCreate = .F.
&& create public variables named as the form(.scx) as in DO FORM

&& ------------------------------------------------
&& Miscellaneous settings
&& ------------------------------------------------

lHTML5placeHolder = .T.
&& define <input placeholder="" /> according to Textbox.ToolTipText | Editbox.ToolTipText
&& <input placeholder="" /> selon Textbox.ToolTipText | Editbox.ToolTipText

lHTML5type = .T.
&& define <input type="" /> according Textbox's data type
&& <input type="" /> selon le type de données de la Textbox

cLangUser = '' && [cLangUser()]
&& Developer's preferred language (defaults to cLangUser())

nMemoryMB = 256 && Between(m.this.nMemoryMB, 64, 512)
&& Maximum memory used in MB

&& ------------------------------------------------
&& See also settings in application configuration class 'tutoAppConfig as awAppConfig of awServer.prg'
&& ------------------------------------------------

* ------------------------------------------------------------

procedure init

lparameters ;
tuFormsLaunch; && @ [m.this.uFormsLaunchAtStartup]
, tlHTMLcomment && [no change]

local success

success = dodefault(@m.tuFormsLaunch, m.tlHTMLcomment)
if m.success and lEmailAddrOK(this.oConfig.cAdminEmail)

  this.oAppHost.oIPstuff.cSenderEmail = this.oConfig.cAdminEmail && usually on same service as SMTP server
  #if .F.
    This is the mail system at host relay7-d.mail.gandi.net.

    I'm sorry to have to inform you that your message could not
    be delivered to one or more recipients. It'
s attached below.

    <ecor.technique@xxx.fr>: host mx1.xxx.fr[212.27.48.6] said: 550 spam detected
    (in reply to end of DATA command)
    
    AppAdminEmail = ecor.technique@xxx.fr && should be on mail.gandi.net
  #endif
endif
return m.success
endproc

* ================================================================================
ENDDEFINE && CLASS tutoServer
* ================================================================================

* ================================================================================

DEFINE CLASS tutoAppConfig AS awAppConfig OF awServer.prg
* ================================================================================

&& Add any property you need to modify on line through this test URL:
&& - http://localhost/tutoTest/bin/wc.dll?wwMaint~EditConfig && development
&& - http://yourDomain/bin/wc.dll?wwMaint~EditConfig && production
&& e.g.

#if .F.
cMyProperty = '' && always use a type prefix, eg 'c' for string
#endif
&& for more information about application configuration object:
&& - modify command awServer.prg (licensed FoxInCloud developer)
&& - http://www.west-wind.com/webconnection/docs/_s8103hqw9.htm

* ================================================================================

ENDDEFINE && CLASS tutoAppConfig
* ================================================================================

* ================================================================================

DEFINE CLASS tutoProcess AS awProcess OF awServer.prg
* ================================================================================

* ===================================================================================================
* == 1 == 1 == 1 == 1 == 1 == 1 == 1 == 1 == 1 == 1 == 1 == 1 ==
* ===================================================================================================

&& USER IDENTIFICATION FOR YOUR APPLICATION
&& ----------------------------------------
&& Implement if your application manages user's identification and/or credentials globally,
&& for instance stores user's ID and/or credentials in a public variable or a _Screen property
&& If your application manages user's identification and/or credentials at form level,
&& implement the wUserSet() and wUserGet() methods in your subclass of aw.vcx!awFrm

* ------------------------------------------------------------

PROTECTED PROCEDURE wUserSet && Sets current user
  && executed before each request against the application
  LPARAMETERS ;
    twUser,; && User ID for application (=this.wUserAnonymous if anonymous)
  tlTemp && [.F.] This user ID is impersonated (see awServer.wlUserTemp)

  #IF .F. && SAMPLE IMPLEMENTATION CODE START

    _SCREEN.ADDPROPERTY('myUserID', m.twUser)
    _SCREEN.ADDPROPERTY('myUserRights', myUserRights(m.twUser))

    DO myUserPublicVariablesSetProcedure(m.twUser)

  #ENDIF && SAMPLE IMPLEMENTATION CODE END

  RETURN DODEFAULT(m.twUser, m.tlTemp) && Always keep this instruction!
endproc

* ------------------------------------------------------------
PROTECTED FUNCTION wUserGet && Indicates FoxInCloud current user's ID
LPARAMETERS tlTemp && [.F.] This user ID is impersonated (see awServer.wlUserTemp)

  #IF .F. && SAMPLE IMPLEMENTATION CODE START

    RETURN _SCREEN.myUserID

  #ELSE

    RETURN DODEFAULT(m.tlTemp) && delete this instruction if you implement

  #ENDIF && SAMPLE IMPLEMENTATION CODE END
endfunc

* ------------------------------------------------------------
function wUserName as String && Name of a user based on his application ID
lparameters ;
twUser as Variant; && User ID for application (this is NOT FoxInCloud session ID ...)
, tcEmail as String; && [''] @ email of this User

tcEmail = 'support@foxincloud.com'
return 'FoxInCloud Support'

* ===================================================================================================
* == 2 == 2 == 2 == 2 == 2 == 2 == 2 == 2 == 2 == 2 == 2 == 2 ==
* ===================================================================================================

&& HTML IN MASTER FORMS HEADER AND FOOTER
&& --------------------------------------
&& With the following methods you can add custom HTML in header and footer
&& of form HTML pages built with this.wFormStandardPage()

* ------------------------------------------------------------

PROTECTED FUNCTION wFormHTML_cHeader && Form header
  && Implement to add HTML before your Forms

  RETURN DODEFAULT() && + Textmerge([<p class="FIC"><<this.oConfig.cAppName>></p>]) && Just a sample
endfunc

* ------------------------------------------------------------
PROTECTED FUNCTION wFormHTML_cFormBottom && below the form
&& Implement / override in your subclass xxxProcess

  
  local cResult
  
  if !lDevMode() && or File('az.h')
    text to cResult textmerge noshow flags 1 pretext 3
    <hr>
    <div id="disqus_thread"></div>
   <script>
   var disqus_config = function () {
   this.page.url = "<<Trim(m.request.getCurrentURL(), '?')>>";
   this.page.identifier = "<<this.cForm>>";
   this.page.category_id = "";
   };
   (function() { // NO EDIT BELOW THIS LINE!
   var d = document, s = d.createElement('script');
   s.src = '//foxincloud.disqus.com/embed.js';
   s.setAttribute('data-timestamp', +new Date());
   (d.head || d.body).appendChild(s);
   })();
   </script>
   <script id="dsq-count-scr" src="//foxincloud.disqus.com/count.js" async></script>
   endtext
  endif

  return DoDefault() + Evl(m.cResult, '')
endfunc

* ------------------------------------------------------------
PROTECTED FUNCTION wFormHTML_cFooter && Form footer
  && Implement to add HTML after your Form
  return DoDefault()
endfunc

* ------------------------------------------------------------
PROTECTED FUNCTION wFormHTML_cSignature && ISV Signature
  RETURN '' && DoDefault('') && DoDefault('<span>Abaque</span>') && Just a sample
endfunc

* ------------------------------------------------------------
protected function wFormStandardPage_cKeyWords && [<meta name="keywords" content="?">] keywords for this meta tag
return ICase(;
  m.this.cLangUser = 'fr',   [FoxInCloud, SaaS, Cloud, FoxPro, Web, adapter une application client lourd au web, tutoriel],; && Copy-paste this line to add another language support
                            [FoxInCloud, SaaS, Cloud, FoxPro, Web, adapt desktop application to the Web, tutorial]; && Default: English
  )
endfunc

* ===================================================================================================
* == 3 == 3 == 3 == 3 == 3 == 3 == 3 == 3 == 3 == 3 == 3 == 3 ==
* ===================================================================================================

&& MASTER FORMS METHODS
&& To display a HTML page containing a master form,
&&   add a method named as the form, calling this.wFormStandardPage() as in the sample methods below

* -------------------------------------------

procedure Index && home page &&
return this.wFormStandardPage('Index.scx')
external form Index && makes sure 'Index.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure PagedGrid
return this.wFormStandardPage('PagedGrid.scx')
external form PagedGrid && makes sure 'PagedGrid.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure EventLog
return this.wFormStandardPage('EventLog.scx')
external form EventLog && makes sure 'EventLog.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure ErrorLog
return this.wFormStandardPage('ficFrmLogError')
endproc

* -------------------------------------------
procedure RowSourceType
return this.wFormStandardPage('RowSourceType.scx')
external form RowSourceType && makes sure 'RowSourceType.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure RowColChange
return this.wFormStandardPage('RowColChange.scx')
external form RowColChange && makes sure 'RowColChange.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure Report
return this.wFormStandardPage('Report.scx')
external form Report && makes sure 'Report.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure Modal
return this.wFormStandardPage('Modal.scx')
external form Modal && makes sure 'Modal.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure KeyPress
return this.wFormStandardPage('KeyPress.scx')
external form KeyPress && makes sure 'KeyPress.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure Event
return this.wFormStandardPage('Event.scx')
external form Event && makes sure 'Event.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure DataUpdate
return this.wFormStandardPage('DataUpdate.scx')
external form DataUpdate && makes sure 'DataUpdate.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure valuesDelayed
return this.wFormStandardPage('valuesDelayed.scx')
external form valuesDelayed && makes sure 'valuesDelayed.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure remoteGrids && 2015-12-16 thn added
return this.wFormStandardPage('remoteGrids.scx')
external form remoteGrids && makes sure 'remoteGrids.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure googleMap && 2016-04-20 thn -- {FiC V 2.21.1-beta.0} added
return this.wFormStandardPage('googleMap.scx')
external form googleMap && makes sure 'googleMap.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure signature && 2016-07-05 thn -- {FiC V 2.22.0-beta.0} added
return this.wFormStandardPage('signature.scx')
external form signature.scx && makes sure 'signature.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure imgUpload && 2016-08-09 thn -- {FiC V 2.22.0-beta.3} added
return this.wFormStandardPage('imgUpload.scx')
external form imgUpload.scx && makes sure 'imgUpload.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure foxel && 2016-10-31 thn -- {FiC V 2.22.1-beta.1} added for Foxels support
return this.wFormStandardPage('foxel.scx')
external form foxel.scx && makes sure 'foxel.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure ie && 2016-11-29 thn -- {FiC V 2.23.0-beta.5} added to demo support for OLEcontrol of OLEclass Shell.Explorer.2
return this.wFormStandardPage('ie.scx')
external form ie.scx && makes sure 'ie.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure treeView && 2017-09-26 thn -- {FiC V 2.25.0-beta.9} added to demo support for OLEcontrol of OLEclass MSComctlLib.TreeCtrl.2
return this.wFormStandardPage('treeView.scx')
external form treeView.scx && makes sure 'treeView.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure eventClient && 2018-06-01 thn -- {FiC V 2.27.0-beta.3} added; demoes client-side event implementation
return this.wFormStandardPage('eventClient.scx')
external form eventClient.scx && makes sure 'eventClient.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure DynamicGrid
return this.wFormStandardPage('DynamicGrid.scx')
external form DynamicGrid && makes sure 'DynamicGrid.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure autoComp
return this.wFormStandardPage('autoComp.scx')
external form autoComp && makes sure 'autoComp.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure dragDrop
return this.wFormStandardPage('dragDrop.scx')
external form dragDrop && makes sure 'dragDrop.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure tipsTricks
return this.wFormStandardPage('tipsTricks.scx')
external form tipsTricks && makes sure 'tipsTricks.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure sel
return this.wFormStandardPage('sel.scx')
external form sel && makes sure 'sel.scx' is included into the web app project &&
endproc

* -------------------------------------------
procedure bsGrid
return this.wFormStandardPage('bsGrid.scx')
external form bsGrid && makes sure 'bsGrid.scx' is included into the web app project &&
endproc

* -------------------------------------------
PROTECTED FUNCTION cawJSinc
&& 2016-04-20 thn -- {FiC V 2.21.1-beta.0} added as sample for M. Gilles Lajot-Sarthou
LPARAMETERS ;
tcJSAdd; && [''] Application, current form[, and custom]
, toForm as awFrm of aw.vcx; && Reference to form && {FiC V 2.21.1-beta.0} added paramter
, tcForm; && .Name of form {FiC V 2.21.1-beta.0} added parameter

local result

result = DoDefault(m.tcJSAdd, m.toForm, m.tcForm)

if InList(Lower(m.tcForm), Lower('index.scx'), Lower('googleMap.scx'))
  result = '<script charset="utf-8" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAwpU1TJ1ZmurqlZgs9xn78U-NvrKju76I"></script>' + CRLF + m.result && before standard JS files
endif
if InList(Lower(m.tcForm), Lower('index.scx'), Lower('signature.scx'))
  result = m.result;
    + Textmerge([<script charset="utf-8" src="<<this.oConfig.cScriptPathVirtual>>/bower/jSignature/<<Iif(lDevMode(), 'src/jSignature.js', 'libs/jSignature.min.noconflict.js')>>"></script>]) + CRLF && after standard JS files, eg jQuery
endif

return m.result
endfunc

* -------------------------------------------
procedure index_scx
return this.fileDisplay('index.scx.src')
external file index.scx.src

* -------------------------------------------
procedure userChoice_scx
return this.fileDisplay('userChoice.scx.src')
external file userChoice.scx.src

* -------------------------------------------
procedure rowSourceType_scx
return this.fileDisplay('rowSourceType.scx.src')
external file rowSourceType.scx.src

* -------------------------------------------
procedure rowColChange_scx
return this.fileDisplay('rowColChange.scx.src')
external file rowColChange.scx.src

* -------------------------------------------
procedure reportChild_scx
return this.fileDisplay('reportChild.scx.src')
external file reportChild.scx.src

* -------------------------------------------
procedure report_scx
return this.fileDisplay('report.scx.src')
external file report.scx.src

* -------------------------------------------
procedure pagedGrid_scx
return this.fileDisplay('pagedGrid.scx.src')
external file pagedGrid.scx.src

* -------------------------------------------
procedure modal_scx
return this.fileDisplay('modal.scx.src')
external file modal.scx.src

* -------------------------------------------
procedure keyPress_scx
return this.fileDisplay('keyPress.scx.src')
external file keyPress.scx.src

* -------------------------------------------
procedure eventLog_scx
return this.fileDisplay('eventLog.scx.src')
external file eventLog.scx.src

* -------------------------------------------
procedure event_scx
return this.fileDisplay('event.scx.src')
external file event.scx.src

* -------------------------------------------
procedure dataUpdate_scx
return this.fileDisplay('dataUpdate.scx.src')
external file dataUpdate.scx.src

* -------------------------------------------
procedure valuesDelayed_scx
return this.fileDisplay('valuesDelayed.scx.src')
external file valuesDelayed.scx.src

* -------------------------------------------
procedure remoteGrids_scx && 2015-12-16 thn added
return this.fileDisplay('remoteGrids.scx.src')
external file remoteGrids.scx.src

* -------------------------------------------
procedure googleMap_scx && 2016-04-20 thn -- {FiC V 2.21.1-beta.0} added
return this.fileDisplay('googleMap.scx.src')
external file googleMap.scx.src

* -------------------------------------------
procedure signature_scx && 2016-04-20 thn -- {FiC V 2.21.1-beta.0} added
return this.fileDisplay('signature.scx.src')
external file signature.scx.src

* -------------------------------------------
procedure foxel_scx && 2016-10-31 thn -- {FiC V 2.22.1-beta.1} added for Foxels support
return this.fileDisplay('foxel.scx.src')
external file foxel.scx.src

* -------------------------------------------
procedure ie_scx && 2016-10-31 thn -- {FiC V 2.22.1-beta.1} added
return this.fileDisplay('ie.scx.src')
external file ie.scx.src

* -------------------------------------------
procedure treeView_scx && 2017-09-28 thn -- {FiC V 2.25.0-beta.9} added
return this.fileDisplay('treeView.scx.src')
external file treeView.scx.src

* -------------------------------------------
procedure eventClient_scx && 2018-06-01 thn -- {FiC V 2.27.0-beta.3} added; demoes client-side event implementation
return this.fileDisplay('eventClient.scx.src')
external file eventClient.scx.src

* -------------------------------------------
procedure dynamicGrid_scx
return this.fileDisplay('dynamicGrid.scx.src')
external file dynamicGrid.scx.src

* -------------------------------------------
procedure autoComp_scx
return this.fileDisplay('autoComp.scx.src')
external file autoComp.scx.src

* -------------------------------------------
procedure dragDrop_scx
return this.fileDisplay('dragDrop.scx.src')
external file dragDrop.scx.src

* -------------------------------------------
procedure tipsTricks_scx
return this.fileDisplay('tipsTricks.scx.src')
external file tipsTricks.scx.src

* -------------------------------------------
procedure sel_scx
return this.fileDisplay('sel.scx.src')
external file sel.scx.src

* -------------------------------------------
procedure FormMemberSourceCode && source code of a form or any of its members

&& 2016-10-20 thn -- {FiC V 2.22.0-beta.8} added

local result as String;
, cForm , oForm as ficFrm of ficSample;
, cMember, oMember, cAddress;

cForm = request.queryString('Form')
oForm = this.oAppHost.oFormOfName(m.cForm)
cMember = Chrtran(request.queryString('Member'), '-', '.')
cAddress = c2Words('m.oForm', '.', m.cMember)
oMember = Iif(Vartype(m.oForm) == 'O' and Type(m.cAddress) == 'O', Evaluate(m.cAddress), .null.)

result = Iif(Vartype(m.oMember) == 'O' and lProperty(m.oMember, 'cSrceCode');
  , abLocalized(; && modify command abTxt && text where localized comments are removed except those in the users language
     m.oMember.cSrceCode; && Text to localize (source code in general)
    , m.this.cLangUser; && [cLangUser()] user's preferred language as ISO 639-1 code
    );
  , 'N/A';
  )

text to result textmerge noshow flags 1 pretext 3
<!doctype html>
<html>
<head>
<meta charset="iso-8859-1">
<title>Source code for <<c2Words(Strtran(m.cForm, '_scx', '.scx'), '.', m.cMember)>></title>
<link type="text/css" rel="stylesheet" href="/awScripts/FoxInCloud.css" />
<link type="text/css" rel="stylesheet" href="/tutotest/tuto.css" />
</head>
<body>
<<result>>
</body>
</html>
endtext

response.Write(m.result)

endproc

* -------------------------------------------
procedure fileDisplay
lparameters file as String
&& displays a file contents in a page
&& if you're viewing this program in the browser, it's because you're executing it.

local success as Boolean;
, fileContent as String;
, fileSupported as Boolean;
, UTF8 as Boolean;
, ext as String;
, title as String;
, body as String;
, commentLineStart as String;
, commentLineStarts as String;
, oSeparator as abSet of abDev.prg;
, oRegExp as abRegExp of abTxt.prg;
, VFPcode as Boolean;

#define tuto_indent CRLF+Replicate('&nbsp;', 2)

file = Evl(m.file, Lower(request.QueryString()))
ext = Lower(JustExt(m.file))
success = File(m.file)
fileContent = Iif(m.success, FileToStr(m.file), '')
fileSupported = m.success
oRegExp = abRegExp()

do case
case !m.success
case InList(m.file, Lower('tutoTest.prg'), Lower('tutoTestBS.prg'))
  body = ICase(;
    this.cLangUser = 'fr',  [Programme principal du Serveur d'Application FoxInCloud - notez que la classe tutoServerTest est OLEPUBLIC pour exécution en mode COM],; && copy-paste this line to add another language support
                            [FoxInCloud Application Server main program - note that the tutoServerTest class is OLEPUBLIC for execution in COM mode]; && default: English
    )
case InList(m.file, Lower('tutoTest.ini'), Lower('tutoTestBS.ini'))
  if m.oRegExp.setup('(id\s*=\s*)[^\s]+$', 'gmi')
    fileContent = m.oRegExp.replace(@m.fileContent, '$1{' + Strconv(ICase(;
      this.cLangUser = 'fr',  [identifiant caché],; && copy-paste this line to add another language support
                              [hidden ID]; && default: English
      ), 9) + '}' + CR)
  endif
  body = ICase(;
    this.cLangUser = 'fr',  [Paramètres du Serveur d'Application FoxInCloud - modifiables en ligne],; && copy-paste this line to add another language support
                            [FoxInCloud Application Server parameters - can be modified on line]; && default: English
    )
case m.file == Lower('tutoServer.prg')
  body = ICase(;
    this.cLangUser = 'fr',  [classes du Serveur d'Application FoxInCloud (partagées par les versions de test et de production de l'Application Web)],; && copy-paste this line to add another language support
                            [FoxInCloud Application Server classes (shared by test and production versions of Web Application)]; && default: English
    )
case m.file == Lower('tutoSets.prg')
  body = ICase(;
    this.cLangUser = 'fr',  [Classe réglant l'environnement au démarrage de l'application (partagée par les distributions Web et desktop (LAN) de l'application)],; && copy-paste this line to add another language support
                            [Application's startup environment settings (shared by Web and LAN versions)]; && default: English
    )
case m.file == Lower('awDefaultAll.css')
  body = ICase(;
    this.cLangUser = 'fr',  [Feuille de styles générée par le Serveur d'Application FoxInCloud],; && copy-paste this line to add another language support
                            [Custom Cascading Style Sheet generated by FoxInCloud Application Server]; && default: English
    )
case m.file == Lower('tuto.css')
  body = ICase(;
    this.cLangUser = 'fr',  [Feuille de styles ajustable pour l'Application Web FoxInCloud (où vous pouvez surcharger)],; && copy-paste this line to add another language support
                            [Custom Cascading Style Sheet for FoxInCloud Web Application Site (you can override here)]; && default: English
    )
case m.file == Lower('FoxInCloud.js')
  if m.oRegExp.setup(';(?!\s)', 'gmi')
    fileContent = m.oRegExp.replace(@m.fileContent, ';' + CRLF)
  endif
  body = ICase(;
    this.cLangUser = 'fr',  [Programme JavaScript FoxInCloud standard, partagé par toutes les Applications Web FoxInCloud (partiellement obscurci)],; && copy-paste this line to add another language support
                            [Standard JavaScript for any FoxInCloud Web Application (slightly obfuscated)]; && default: English
    )
case m.file == Lower('tuto.js')
  body = ICase(;
    this.cLangUser = 'fr',  [Programme JavaScript ajustable pour l'Application Web FoxInCloud (où vous pouvez surcharger les options FoxInCloud et ajouter vos propres scripts)],; && copy-paste this line to add another language support
                            [Custom JavaScript for FoxInCloud Web Application Site (you can override here)]; && default: English
    )
case m.ext == Lower('mpr')
  body = cL(Evl(cFileCased(FullPath('awGenMenu.prg')), 'awGenMenu.prg'))
  body = Textmerge(ICase(;
    this.cLangUser = 'fr',  [Programme de menu généré par <<m.body>> à partir de <<ForceExt(m.file, 'mnx')>> (partagé par les versions desktop et Web de l'application)],; && copy-paste this line to add another language support
                            [Application main Menu program generated by <<m.body>> from <<ForceExt(m.file, 'mnx')>> (shared by desktop and Web versions)]; && default: English
    ))
  fileSupported = .F. && no cLocalized() below
case m.file == Lower('ficSample.vcx.src')
  body = ICase(;
    this.cLangUser = 'fr',  [Bibliothèque de classes dérivée des 'classes de base FoxInCloud' aw.vcx, partagée par les versions desktop et web],; && copy-paste this line to add another language support
                            [Class library derived from 'FoxInCloud base classes' aw.vcx, shared by desktop/LAN ans web versions of the application]; && default: English
    )
case m.file == Lower('tutoLAN.prg')
  body = ''
case m.ext == Lower('src')
  body = ICase(;
    this.cLangUser = 'fr',  [Formulaire],; && copy-paste this line to add another language support
                            [Form]; && default: English
    ) + [ "<<JustStem(Chrtran(m.file, '_', '.'))>>"]
otherwise
  body = ICase(;
    this.cLangUser = 'fr',  [Le contenu du fichier <<m.file>> est indisponible],; && copy-paste this line to add another language support
                            [Contents of file <<m.file>> is not available]; && default: English
    )
  fileSupported = .F.
endcase

commentLineStart = ICase(;
  InList(m.ext, 'js', 'cs'),;
    '//',;
  m.ext == 'ini',;
    ';',;
    '*';
  ) + [ ]

commentLineStarts = ICase(;
  InList(m.ext, 'prg', 'mpr'),;
    '',; && use abLocalized() default
    Trim(m.commentLineStart);
  )
  
UTF8 = InList(m.ext, 'css', 'js', 'ini')
oSeparator = abSet('SEPARATOR', ',')

VFPcode = InList(m.ext, 'prg', 'mpr', 'src')

body = Iif(m.success;
  , cSrceCodeColoredHTML(''; && modify command awtxt (licensed users)
     + m.commentLineStart + Upper(m.file);
     + Iif(Empty(m.body);
       , '';
       , CRLF + m.commentLineStart + Textmerge(Iif(m.UTF8, Strconv(m.body, 9), m.body));
       );
     + CRLF + m.commentLineStart + cFileCased(m.file, .T.) + Iif(lFile(FullPath(m.file)), '', ' (included in ' + _VFP.ServerName + ')'); && JustFname()
     + CRLF + m.commentLineStart + [(] + Trim(Transform(Cast(Max(Occurs(Chr(13), m.fileContent), Occurs(Chr(10), m.fileContent)) as I), '@B 999,999')) + [ lines before localization)];
     + CRLF + m.commentLineStart + Replicate('=', 120);
     + CRLF2 + Iif(m.fileSupported;
       , abLocalized(; && modify command abTxt && text where localized comments are removed except those in the user's language
          m.fileContent; && Text to localize (source code in general)
         , m.this.cLangUser; && [cLangUser()] user's preferred language as ISO 639-1 code
         , m.commentLineStarts; && ['*|&&|note'] strings beginning a comment line in code source
         );
       , m.fileContent;
       );
    , ICase(;
      m.VFPcode,;
        'vfp',;
      m.ext == 'js',;
        'javascript',;
      m.ext == 'css',;
        'css2',;
      m.ext == 'ini',;
        'c',;
        m.ext;
      );
    );
  , Textmerge([File '<<m.file>>' could not be found]);
)

title = Textmerge(Iif(m.success;
  , [Code in file '<<m.file>>'];
  , [Error displaying code in file '<<m.file>>'!];
  ))

text to body textmerge noshow flag 1 pretext 3
  <!DOCTYPE html>
  <head>
    <meta charset="<<Iif(m.UTF8, 'utf-8', 'iso-8859-1')>>">
    <title><<m.title>></title>
    <link type="text/css" rel="stylesheet" href="/awScripts/FoxInCloud.css" />
    <link type="text/css" rel="stylesheet" href="tuto.css" />
  </head>
  <body style="padding:.5em;">
    <<m.body>>
  </body>
endtext

return Response.Write(m.body)

external file ; && for executing this.fileDisplay() in exe mode
tutoTest.prg;
, tutoTestBS.prg;
, tutoServer.prg;
, tutoSets.prg;
, tuto.mpr;
, tutoLAN.prg;
, suppliers.qpr;

endproc

* ===================================================================================================
* == 4 == 4 == 4 == 4 == 4 == 4 == 4 == 4 == 4 == 4 == 4 == 4 ==
* ===================================================================================================

&& ADVANCED METHODS

* -------------------------------------------

PROCEDURE process_ante
&& just before FoxInCloud Application Server executes a request
&& this.oServer, this.oRequest and this.oResponse are available

this.oResponse.addCookie('ficTutoTestCookie', Sys(2015))
&& check cookie in your browser's development tools (eg firebug for firefox)

* -------------------------------------------

PROCEDURE process_post
&& just after FoxInCloud Application Server has executed a request
&& this.oServer, this.oRequest and this.oResponse are available
&& /!\ this.oResponse is already complete

* -------------------------------------------

protected function cawCustomerID && override in your subclass if you don't want your ID to be displayed on the dashboard for privacy
  return 'N/A'
endfunc
* -------------------------------------------
protected function cawBasePackID && override in your subclass if you don't want your ID to be displayed on the dashboard for privacy
  return 'N/A'
endfunc
* -------------------------------------------
protected function cWClicenseID && override in your subclass if you don't want your ID to be displayed on the dashboard for privacy
  return 'N/A'
endfunc
* ------------------------------------------------------------
procedure FoxInCloud_Status && FoxInCloud Application Server dashboard
  return this.FoxInCloud_Status_(.T.) && public, no authentication
endproc
* ------------------------------------------------------------
procedure custOrderReport && Asynchronous customer report

&& see also
&& modify form report.scx method cmdRptAsync.click

  local success;
  , result as String;
  , lcPDFout as String;

  success = .T.;
   and custOrderReport(;
     @m.result; && @
    ,@m.lcPDFout; && @
    , m.request.Params('custID'); && customerID
    , m.request.Params('PDFengine');
    );
    and this.oAJAX.FileToSiteTempDir(;
     @m.lcPDFout;
    ,@m.result;
    )
  
  if m.success and this.lProduction
    Sleep(5000) && wait a little bit to make it more realistic
  endif
  
  Response.ContentTypeHeader('application/json')
  Response.fastWrite(Textmerge([{];
   + ["success":<<cLitteralJS(m.success)>>];
   + [, "result" :<<cLitteralJS(Iif(m.success, this.oAJAX.cTempPathVirtual+JustFname(m.lcPDFout), m.result),.T., .T.)>>];
   + [}];
   ))

endproc

* ================================================================================
ENDDEFINE && CLASS tutoProcess
* ================================================================================

* ================================================================================

DEFINE CLASS tutoHTMLgen AS awHTMLgen OF awHTML.prg
* ================================================================================

* ------------------------------------------------------------

protected procedure getHTML_grd_AW_cScript_Events && Grid events script
lparameters ;
result; && @ cumulative result from sub methods
, oJS as Empty; && @ result Script snippets
, lRequest as Boolean; && XML data need a reload
, lRefresh as Boolean; &&

local success as Boolean;
, cSelectionMode as String;

* setStepOn(m.this.cObjID == 'report_scx-grdorders')
success = DoDefault(;
   @m.result;
  , m.oJS;
  , m.lRequest;
  , m.lRefresh;
  )
if m.success and m.this.wcID == 'report_scx-grdorders'

  cSelectionMode = ICase(;
    Cast(m.this.oControl.Parent.chkDisable.value as L),; && m.this.oControl holds a reference to the VFP grid
      'none',;
    this.oControl.AllowCellSelection,;
      'single-cell',;
      'single-row';
    )

  oJS.currentColRow = m.oJS.currentColRow;
    + Textmerge([oGrid.setSelectionMode("<<m.cSelectionMode>>");]); && http://www.activewidgets.com/javascript.forum.22070.4/cancel-row-clicks-and-changes.html
   + CRLF

endif

return m.success
endproc

* ----------------------------------------------------
protected procedure getHTML_BS_ColSpec_User && Bootstrap For inplementation in sub-class to override column alignment, width and or offset computed by FoxInCloud
lparameters ;
colAlign as String; && @ column alignment: 'L'eft, 'R'ight or 'C'enter (applies to all Bootstrap sizes) - to be adjusted in subclass as expected
, colOffBS as Integer; && @ column offset in 12th of parent column: Between(m.colOffBS, 0, 12-m.colWid12) - to be adjusted in subclass as expected
, colWidBS as Integer; && @ column width in 12th of parent column: Between(m.colWidBS, 1, 12) - to be adjusted in subclass as expected
;
, cntCSSclass as String; && CSS class of parent container - see in generated HTML the first parent <div class="address relative to VFP Form"><div class="addresse relative au Form VFP"> parent
, rowID as Integer; && Bootstrap row ID: see in generated HTML <div|fieldset class="row row-999">: '999' is the row ID <div|fieldset class="row row-999">: '999' est l'ID de la rangée
, rowName as String; && Bootstrap row name: see in generated HTML <div|fieldset class="row row-999 row-xxx">: 'xxx' is the row name <div|fieldset class="row row row-999 row-xxx">: 'xxx' est le nom de la rangée
, colID as Integer; && Bootstrap col ID: see in generated HTML <div class="col col-999 col-xx-...">: '999' is the column ID <div class="col col-999 col-xx-...">: '999' est l'ID de la colonne
, colName as String; && Bootstrap col name: see in generated HTML <div|fieldset class="col col-999 col-xxx">: 'xxx' is the col name <div|fieldset class="col col col-999 col-xxx">: 'xxx' est le nom de la rangée
, cBSsize as String; && Bootstrap col size code: 'xs', 'sm', 'md' or 'lg': see in generated HTML <div class="col col-999 col-xx-...">: 'xx' is the column size <div class="col col-999 col-xx-...">: 'xx' est la taille de la colonne

colAlign = ICase(;
  InList(m.colName, 'lblfic', 'cntsignature'),;
    'L',;
  InList(m.colName, 'cntok'),;
    'C',;
    m.colAlign;
    )

colWidBS = ICase(;
  InList(m.colName, 'imgsignature', 'cntsignature') and m.cBSsize == 'md',;
    5,;
  m.cntCSSclass == 'index_scx' and InList(m.colName, 'cntok') and m.cBSsize == 'md',;
    3,;
  m.cntCSSclass == 'event_scx-pgf-pag2' and m.cBSsize == 'xs',;
    6,; && 2017-08-17 thn -- {FiC V 2.25.0-beta.7}
    m.colWidBS;
  )

endproc

* ================================================================================
ENDDEFINE && CLASS tutoHTMLgen
* ================================================================================

* ================================================================================

DEFINE CLASS tutoAJAX as awAJAX of awServer.prg
* ================================================================================

* ------------------------------------------------------------

FUNCTION lSuccess && AJAX error manager
LPARAMETERS ;
tlResult; && [.T.] Result to be checked for
, tcError; && ["not specified"] Error Message - @complete
, tuVar1; && [''] Error variable # 1
, tuVar2; && [''] Error variable # 2
, tuVar3; && [''] Error variable # 3
, tlTablesNo; && [.F.] do not join state tables to notification email

local lnDelay, lcMsg

lnDelay = 6 && seconds

lcMsg = Chr(160) + CRLF + ICase(;
  this.cLangUser = 'fr',  [A cause de cette erreur, vous allez être redirigé vers la page d'accueil dans],; && copy-paste this line to add another language support
                          [Because of this error, you will be redirected to home page in]; && Default: English
  ) + ' ' + cSecs(m.lnDelay)

do case
case lTrue(m.tlResult) && or any other condition based on tcError
case empty(m.tuVar1)
tuVar1 = m.lcMsg
case empty(m.tuVar2)
tuVar2 = m.lcMsg
case empty(m.tuVar3)
tuVar3 = m.lcMsg
endcase

if !DoDefault(m.tlResult, @m.tcError, m.tuVar1, m.tuVar3, m.tuVar3, m.tlTablesNo)

this.BackHome(;
   .F.; && [.F.] session has expired
   , m.lnDelay; && [.null.] delay in seconds before navigating back home
   )

endif

* ================================================================================
ENDDEFINE && CLASS tutoAJAX
* ================================================================================