
Changes made to the application framework
that the application builder should know:
===========================================

-------- constructing an HTML page -----------
* - WebApp::getHtmlPage($tpl)
    Constructs the page given as a parameter and returns
    it as an HTML string. It saves whatever is constructed
    in the current page and then resumes it again after
    constructing the requested page, so it can be called from
    anywhere in the application, e.g. from an event handler.
    This function is usefull when you want to construct a page 
    for sending it by e-mail.
        
-------- external link to an application page -----------
* - The function WebApp::external_page() returns a link that can
    be used to jump to this page of the application from any
    external page. Also the constant "SHOW_EXTERNAL_LINK", which
    is defined in 'config/const.Settings.php' makes possible to
    display the external link to the end of the page.

    The external links are useful e.g. for generating an index
    page for search engines, so that they can access and index
    the content pages of the application.


-------- the PHP code of a webox -----------------------
* - The PHP code of a webox: <WebBox ID="boxID" 
    is placed in the file "boxID.php" which is in the
    same folder as the template containing the webox.
    
    The code of the webox now is organized inside a class:
    "class boxID extends IWebBox {...}"
    which extends the interface (or the abstract class) IWebBox.
    This makes the PHP code of the application more object-oriented
    and better organized.
    
    The class "boxID" can override the functions:
        eventHandler($event), onParse() and onRender()
    of IWebBox, or can define other functions that can be
    used inside these functions. These functions replace 
    the old functions: boxID_eventHandler($event), boxID_onParse()
    and boxID_onRender()


---------- the function init() ----------------------------------
* - The class of the webox can also define the function init(),
    which is like the functions eventHandler(), onParse() and
    onRender(), and overrides the abstract function with the same
    name of the class IWebBox. This function is called only when
    the webox is loaded for the first time (only once in a session
    of the application). 

    This function is the right place for initializing the state 
    vars of the webox with default values. Previously, this was 
    done in the onParse() with a statement like this:
         if (!isset($session->Vars["state_var"]))
         {
                $session->Vars["state_var"] = "initial_value";
         }
    Now it should be done in the init() function, like this:
         $this->addSVar("state_var", "initial_value");


----- state vars (or session or persistent vars) added to webox ----
* - Now each webox can have its own state vars (or session vars, or
    persistent vars). Inside the class of the webox, its state vars
    can be accessed like this:
        $this->addSVar ($var_name, $var_value);
        $this->addSVars($associated_array);
        $this->setSVar ($var_name, $var_value);
        $this->setSVars($associated_array);
        $var_value = $this->getSVar($var_name);
        $assoc_arr = $this->getSVars();
    These variables can be accessed inside the webox in the usual way:
          {{var_name}} 
    and they are valid only in the scope of this webox (and shadow any
    other {{variables}} with the same name that are defined in the
    enclosing scopes.

    In case that some state variable of a webox needs to be used
    from the template of another webox, they can be accessed like this:
         {{boxID->var_name}}

    From the JS code as well, they can be accessed like this:
         session.setVar("boxID->var_name", var_value);   etc.

    Also, when you need to access the state var of another box from
    the PHP code of this webox, you can use this function:
        $var_value = WebApp::getSVar("otherBoxID->var_name");
    The function $var_value=WebApp::getSVar($var_name) can also 
    be used to get the session variables (instead of 
    $var_value=$session->Vars[$var_name]).
    Also the function:  WebApp::setSVar($var_name, $var_value)
    is available (instead of $session->Vars[$var_name] = $var_value;),
    and the function:  $wb = WebApp::getWBox("wbox_id");
    which returns a reference to the webox with the given id (this
    reference can be used to access the variables, state variable or
    functions of this webox, e.g. $wb->getQuery(); ).
    
    If the constant DEBUG_STATEVARS in the 'config/const.Settings.php'
    is set to true, then the framework outputs the state variables
    for each webox.

------- MISC ------------------------------------------------
* - Variables can also be used in the 'rs' attribute of a <Repeat> tag,
    e.g.   <Repeat rs="{{rs_id}}"> . . . </Repeat> .
    This allows a repeat block to use different queries in different
    cases (according to the logic of the program). These variables
    are evaluated at the parse time, at the time that the repeat
    element is parsed. So, if you give value to this variable inside
    the function onRender(), it will not get it; instead it should be
    given value in the function onParse(), or it should be a state 
    variable or global variable.

* - Variables can be nested, like this: {{checked_{{id}}}}
    First the innermost variable is replaced, then the outer variable.
    If {{id}} has the value "2" and {{checked_2}} has the value "true",
    then the whole variable above will be replaced by "true";

    If the value of a variable contains another variable inside,
    it will be replaced as well. E.g, if the variable {{nr}} has the 
    value "5" and the variable {{msg}} has the value
    "This is message number {{nr}}.", then using {{msg}} inside a
    template will produce the string: "This is message number 5."

* - The framework defies a constant UNDEFINED (which has the value 
    "UNDEFINED" or something else) and is used in the framework 
    and in the application whenever a variable has no value.
    E.g. if the function WebApp::getWBox("wb_id") returns UNDEFINED,
    it means that such a webbox does not exist in the application,
    or if the function Recordset::Field($fld_name) returns UNDEFINED,
    it means that such a field does not exist or it has no value, etc.

* - The callback function onLoad() is renamed to onParse(). As before,
    it is called just before the webbox is parsed. 

------------------ editForm -------------------------------------------
* - Added these new JS functions (in editForm.js):

    function getFormData(form)
    //returns all the data filled in the given form

    function setFormData(form, formData)
    //fills the form with the data in the given array,
    //this is the array returned by getFormData() for the same form

    function getEventArgs(formData)
    //returns a string that can be sent as the 
    //arguments of an event in the GoTo() function
    //formData is the array returned by getFormData()

    This will be improved further, so that it becomes more general 
    and more easy to use.

----------------- Session -------------------------------------
* - The special variable 'sessChange' is removed as obsolete. The
    programer can change the session on client side, before calling
    GoTo(), instead of changing session variables using 'sessChange'.

* - 'init.Session.php' is removed as obsolete. The session (state)
    variables can be initialized either in the 'init()' function
    of the weboxes or in the 'on.firstTime.php'.

* - Added session.rmVar(var_name) so that session vars can be
    removed from JS code as well. The names of the session functions
    in JS have been changed so that they are more consistent with the
    other function names in framework. Now they are:
        session.addVar("var_name", "var_value"); 
        session.rmVar("var_name");
        session.setVar("var_name", "var_value"); 
        session.getVar("var_name");

* - The names of the functions of the session object are:
        $session->addVar($var_name, $var_value);
        $session->rmVar($var_name);  //removes a variable from session
        $session->setVar($var_name, $var_value);  //sets a new value
        $session->getVar($var_name); //get the value of the var

    The names of the functions for the state vars of a webox are:
        $this->addSVar($var_name, $var_value);
        $this->addSVars($arr_vars);
        $this->setSVar($var_name, $var_value);
        $this->setSVars($arr_vars);
        $this->getSVar($var_value);
        $this->getSVars();

    The session and state vars can also be accessed using this functions:
        WebApp::addSVar($var_name, $var_value);
        WebApp::setSVar($var_name, $var_value);
        WebApp::getSVar($var_name);
        

* - DB Session Vars (or DB State Vars)
    Some of the state (session) variables now can be optionally stored
    in DB instead of storing them in the HTML page itself (using JS code).
    This increses the security of an application based on the framework,
    because the variables that are stored in the JS code potentially can
    be viewed and manipulated by malicious users. So, some of the
    session vars can be stored in DB and they are invisible on the client
    side, and the others (most of them) can be stored in the page, so that
    they can be accessed and used by the JS code of the application.

    To add a DB var, we use the same functions that are used to add a JS
    var, but add a third parameter that is not false, like this:

        $session->addVar($var_name, $var_value, true);
        $session->addVar($var_name, $var_value, "DB");
        $session->addVar($var_name, $var_value, "secure");  etc.

        $this->addSVar($var_name, $var_value,"DB");
        WebApp::addSVar($var_name, $var_value, "DB");

    To change or get the value of a DB variable we use the same "set"
    and "get" functions that we use for JS vars, without additional
    parameters (the framework finds itself whether this is a DB or a
    JS state variable). Usually a DB and a JS var have different names,
    but in case that they have the same name, DB vars have priority
    over JS vars (which means that "get" returns the value of the
    DB var and "set" sets the value to the DB var, instead of to the
    JS var).

    The array: '$session->dbVars' can be used to access the DB vars
    as well, like this:
        $session->dbVars[$var_name] = $var_value;
        $var_value = $session->dbVars[$var_name];
    but it is not neccessary and it is not recomended to use it
    (in fact, it is discouraged to use it).

    The function $this->getSVars() behaves a little bit different
    from the others. Without argument it returns a list of all
    the state vars of the webox, both DB vars and JS vars. With
    an argument "DB" it returns only the DB vars, and with argument
    "JS" it returns only the JS vars.

    For DB vars to work properly, there should be a DB connection
    with a database and the USES_DB constant in 'config/cont.Settings.php'
    must be true. Otherwise the DB vars are converted and stored as
    JS vars. Also, in database there must be the table session(id, vars),
    but if it does not egzist, it is created automatically by the framework
    (if the connection has permition to create tables).


------------------ event handling -------------------------------
* - The class of a webox can declare an event handler function,
    with the name "on_eventName". If such a function exists,
    then this function is called to handle the event, otherwise
    the function eventHandler($event) is called, as before. This
    is useful both for backward compatibility and for flexibility:
    the programer chooses how to handle the events, either with a
    separate event handler for each event, or with a common event
    handler for all the events.

------------------- WebApp::message() ---------------------------
* - The function:  WebApp::message("msg") can be used in PHP code to
    display a message to the user after the page is loaded in browser.
    This can be used to display an error message, e.g. "Wrong username
    or password", or an information message, e.g. "Project Data Saved".

---------------- session var values ----------------------------
* - The session JS vars can contain: ' (single quote), " (double
    quote), \n (new line character), \ (slash), \t (tab), etc.

    They cannot contain, however, \' (slash single quote),
    \" (slash double quote), \n (slash n).

---------------- Recordsets ------------------------------------
* - Satic Recordsets:  <Recordset rs="rsID" static="true">
    These are recordsets that are opened only once during the
    page construction. Usually the recordsets are opened as
    many times as they are needed (i.e. their query is executed
    and the results retrieved from DB). This has the advantage 
    that the query can be different each time that the recordset
    is opened (depending on the {{variables}} that it contains),
    and this provides for more flexibility and dynamicity.

    However, in some cases, the same query is executed all the
    times that the recordset is opened, e.g. when this recordset
    is used to fill a listbox and this listbox can be 20 times
    in the page. In this case it is more efficent that the
    recordset is opened only once and it is used in the 20 cases.

* - The syntax of tag Recordset now is:
        <Recordset ID="rsID" type="rsType">
    where 'rsType' can be one of the values: "StaticRS", "DynamicRS",
    "EditableRS", "PagedRS", "TableRS". The attibute type can be
    omitted; in this case the default value is "StaticRS".

    A 'static' recordset is the recordset described above, a RS that
    cannot be opened more than once per page. A 'dynamic' RS is a
    recordset that evaluates its query (replaces its {{variables}}),
    executes it and refreshes the content each time that its
    method Open() is called. Notice that before a recordset was
    'dynamic' by default and 'static' only if specified, but now a
    RS is 'static' by default (if no type is given). This is
    because 'static' recordsets are more common in web applications
    and 'dynamic' recordsets are useful only in special cases, 
    e.g. when we have two nested recordsets (associated with two
    nested <Repeat>s) and the inner RS uses a {{variable}} provided
    by the outer RS.

    A 'PagedRS' is a recordset that divides  the results of the
    query into pages of certain size, and retrives from DB only
    one page of them. It requires the attribute 'recs_per_page',
    which specifies the size of the page. It is used to display
    big recordsets, when they cannot fit in a single HTML page.

    An 'EditableRS' is a RS that can be modified from the PHP code.
    The programer can retrive the results of a query from DB and
    then modify them, or start with an empty RS and fill it 
    programatically. It makes possible to use templates for results
    that don't come from DB (e.g. when you want to display a folder
    listing and you get the files and folders using some PHP functions).

        This feature can be used in the "folderListing" webbox, for
        example. Instead of generating all the html code of the 
        folder listing programatically, a <Repeat> template, associated
        with a <Recordset> could be used, and this recordset could be
        filled from an array or from php code (instead of being filled
        from database).
        The benefit of this aproach (vs. generatin all the html code
        in php) would be that we are able to change the layout of the
        'folderListing' webbox more easily, because instead of changing
        the php code, we change only a template.

    The functions of EditableRS are:
        $rs->apply($fun_name)
                //applies the function $fun_name on each record
                //of the recordset; $fun_name is a global function
                //that takes as parameter a reference to an associated 
                //array (a reference to a record), like this:
                // function fun_to_be_applied(&$rec)
        $rs->setFld($fld_name, $fld_value)
                //sets a new value to the given field (in the current record)
        $rs->setFlds($arr_flds)
                //changes some fields of the current recordset
        $rs->addRecs($arr_recs)
        $rs->addRec($rec)
                //adds a new record after the current record,
                //the new record becomes current
        $rs->insRecs($arr_recs)
        $rs->insRec($rec)
                //insert a new record before the current record,
                //the new record becomes the current record
        $rs->rmRec()  //removes the current record
        $rs->rmRecs($nr)
                //removes $nr recs from the recordset, 
                //starting with the current record;
                //if $nr is not given or exeeds the EOF, 
                //then removes all the recs up to the EOF
        $rs->slice($offset, $length)
                //returns a new recordset that contains a slice of this recordset;
                //see the documentation of array_slice of PHP
        $rs->match($condition, $pos)
                //returns true if the query at the given position
                //matches the $condition (usually used by the functions
                //find() and filter() above); if no position is given
                //matches the current record;
                //currently the $condition supports only one field
        $rs->filter($condition)
                //returns a new recordset with the recs that match the
                //given condition, $condition is like the WHERE condition
                //of a query, but it matches using regexp-s, e.g.
                //(username=/^d.*/ AND (firstname=/[^a]+/ OR NOT lastname='Hoxha'))
                //(currently it supports only one field, no AND, OR, (, ) etc.)
        $rs->find($condition)
                //finds the subset of the recordset that matches the
                //condition and positions the pointer to the first
                //record found; $condition is like the condition in filter();
                //if called without parameter, if finds the next one,
                //and so on up to EOF;
        $rs->search($condition)
                //used by find(), finds all the records that match 
                //the condition and stores their indeces in
                //the array $this->found_positions
        $rs->find_next()
                //used by find(), returns the next found record
                //or UNDEFINED if there are no more records
        $rs->getColumn($fld_name)
                //returns an array with the values of the specified field
        $rs->getColumns($fld_names)
                //$fld_names is a comma separated list of field names;
                //returns a new recordset that contains only the specified
                //columns

    A "TableRS" is an editable RS which is associated with a table in
    a DB. After editing this RS, the programer can save the changes
    back to DB. (This is not implemented yet.)

* - WebApp::execQuery($query) now returns an EditableRS.

* - Function: WebApp::openTable($table, $condition) added.
        //opens the given table and returns the records that
        //satisfy the given $condition; returns a TableRS
----------------------------------------------------------------
* - The constant DB_TYPE in 'config/const.Settings.php' specifies
    the type of the DB that the application is using, like this:

    define("DB_TYPE", "MySQL");
            //this constant defines the type of DB that the application uses
            //it can be: "MySQL", "Oracle", "ODBC", "ProgreSQL", etc.
            //(except "MySQL", the others are not implemented yet)

-----------------------------------------------------------------
* - Parser separated from Template.
-----------------------------------------------------------------
* - The framework supports WebClasses and WebObjects.

        <WebClass ID="className" Path="path/to/className.php">
                <Parameter name="param1" default="default value" />
                <Parameter name="param2" />
            <!--# . . . . . . . . . . . . . . . . #-->
            <!--# the template of the web class   #-->
            <!--# . . . . . . . . . . . . . . . . #-->
        </WebClass>

        <WebObject Class="className" name="wObj1" param1="value1" param2="value2" />
        <WebObject Class="className" name="wObj2" param2="value2" />
        <WebObject Class="className" name="wObj3" param1="{{nr}}+1" param2="red" />

    The element <WebClass> defines a web class, but it by itself
    does not produce any HTML output in the rendered page. The element
    <WebObject> declares an object of the class and the content (the template)
    of the <WebClass> is used to render this object.

    The 'Path' attribute of the <WebClass> declares the path of the 
    file that defines the PHP code of the WebClass. It is optional, 
    and if it is not given, then the current folder (the folder of the
    template that contains the <WebClass> definition) is searched for
    the file "className.php".

    The <Parameter> elements declare the names and optionally the default
    values of the parameters of the webobjects. (The current implementation
    requires that they come immediately after the <WebClass> line and have
    no empty lines or other lines between them, otherwise they will not be
    parsed correctly.) These parameters can be used inside the template of
    the webclass like template variables, e.g. {{param1}}. If a parameter
    doesn't get a value in the <WebObject> declaration, then its default
    value is used (if it doesn;t have a default value, then it is handled
    like an undefined variable). When a <WebObject> is rendered, the value 
    of the parameters is evaluated as a mixed expression (a PHP expression
    that contains {{template vars}}).

    When several objects of the same class are declared, the template of the
    webclass is repeated for each of them. The webclass designer should
    take this into account when building the webclass. E.g. if there is
    such an input in the webclass template:
        <input type="text" name="staff">
    There will be several such inputs in the HTML code, and its value
    cannot be accessed like this: document.form.staff.value

    ToDo: The framework declares some variables like: {{className}}
    {{objName}}, {{objID}} (which usually is {{className}}::{{objName}}),
    {{objCount}} (counts the objects of the same class, starting from 1),
    etc. These vars can be used inside the template of the webclass,
    if the webclass designer needs them, e.g.:
        <input type="text" name="staff_{{objCount}}">

    The PHP code 
    -------------
    The file "className.php", if it egzists, contains this class definition:
        <?
        class className extends WebObject
        {
          . . . . .
        }       
        ?>
    Where 'WebObject' is a class defined by the framework that supplies
    some useful functionality for all webclasses. 
    This functionality is:
        1 - The callback functions that are called by the framework at 
            certain moments during the time that the webobject is processesed.
            These callback functions are:
                + init()
                + on_eventName($event_args)
                + eventHandler($event)
                + onParse()
                + onRender()

        2 - The ability to keep persistent variables that define the
            state of the object. These state variables can be used 
            inside the "className" like this:
                + $this->addSVar($var_name, $var_value);   
                + $this->addSVar($var_name, $var_value, "DB");  
                + $this->setSVar($var_name, $var_value);
                + $this->setSVars($var_name, $var_value);
                + $var_value = $this->getSVar($var_name); 
                + $arr_values = $this->getSVars($var_name);
                + etc.
            Outside the scope of the WebClass, these state variables can 
            be accessed like this: 
                + WebApp::setSVar("className::objName->var_name", "var_value")
                + $var_value = WebApp::getSVar("className::objName->var_name");
                + {{className::objName->var_name}} (in templates)
                + session.setVar("className::objName->var_name", "var_value")
                + etc.


    WebBox-es
    ---------
    The <WebBox>-es are handled by the framework as a special case of 
    <WebClass>-es and <WebObject>-s. When the framework parses:
        <WebBox ID="boxID">
          . . . . .
        </WebBox>
    it interprets it as:
        <WebClass ID="boxID">
          . . . . .
        </WebClass>
        <WebObject Class="boxID" />
    and the ID of the created object, instead of being "className::objName"
    is just "boxID", so it is handled the same as before 
    (e.g. $var_value = WebApp::getSVar("boxID->var_name"), etc. )
    Thus, when upgrading an egzisting application, the only change that
    needs to be done is to replace:
        class boxID extends IWebBox
    with
        class boxID extends WebObject
-----------------------------------------------------------------
* - The function:
         WebApp::debug_msg($msg, $comment);
    is added to the framework. It makes the framework to display
    the given message after the page is rendered. The comment is
    optional. You can also print a debug message like this:
         print "$comment: $msg<br />\n";
    but the output of this statement may be mixed with the HTML
    code and sometimes it may break the page, so the first
    method is safer and cleaner. The message $msg can be a large
    message that contains tags, e.g.
        WebApp::debug_msg($tpl->toHtmlTable()); 
        WebApp::debug_msg($rs->toHtmlTable(), "The content of recordset");
        WebApp::debug_msg($tplVars->toHtmlTable(), 
                    "The content of varstack at this point");
        WebApp::debug_msg($webPage->template_list(),
                    "All the templates parsed up to this point");
        etc.
-----------------------------------------------------------------
* WebApp::openRS($rs_id, $params =array())
  WebApp::execDBCmd($cmd_id, $params =array())
  
  These functions now take an optional array of parameters, which
  are replaced in the query as {{tpl_vars}}.
-----------------------------------------------------------------
* $webPage->append_to_head($line);
  $webPage->append_to_body($line);

  These functions can be used to add more lines to the content
  of the <head> and <body> elements of a web page. The first
  one (that appends to <head>) cannot be used inside onRender(),
  because the <head> of the page has been already sent to the 
  browser.
-----------------------------------------------------------------
