Tony Marston's Blog About software development, PHP and OOP

RADICORE for PHP - Inserting optional JavaScript

Posted on 9th August 2006 by Tony Marston

Amended on 1st November 2016

Introduction
Disclaimer
Implementation
Adding javascript to the <HEAD> element
Adding javascript to the <BODY> element
Adding javascript at the foot of the <BODY> element
Adding javascript to individual controls
Adding javascript to controls with options
Hide and Seek
Adding an ID element to <tr> tags
Headers and Footers
Example of 'submit()' function
Global javascript
Amendment History
Comments

Introduction

I am not a fan of javascript for reasons which are stated in the FAQ. Anyone who says you must use javascript is making a mistake, and anyone who creates a web application which cannot run without it is making an even bigger mistake. It is an option, not a requirement, and it is an option which some users choose to disable.

However, there are some people who think it is really cool to use javascript, even more so with the current hype of the buzzword du jour which is AJAX. As the RADICORE framework contains many features which are entirely optional I have decided to make the ability to insert javascript into the HTML pages also optional. The purpose of this document is therefore to explain how you can insert the javascript of your choice into the pages of your choice.

Disclaimer

Just because I am providing the ability to use javascript within the RADICORE framework does not mean that I support its use. Please bear in mind the following:.

In other words... use javascript at your own risk, and don't come crying to me if it breaks.

Implementation

The ability to add javascript into the RADICORE framework requires changes in the following areas:

The only reason that I could include this ability into the framework was because I was provided with some HTML documents which contained working javascript code, so all I had to do was change the framework until the same code appeared in the HTML output.

The following sections refer to a custom method called _cm_setJavaScript which you can use or not use as you see fit. This method will be called in script include.xml.php5.inc when constructing the HTML output.

Adding javascript to the <HEAD> element

The first step is to allow entres to be inserted into the documents <HEAD> element, as shown in the following example:

  <head>
    <title>This is a title</title>
    <script language="javascript">...code...</script>  (1)
    <script language="javascript" src="...filename..."/> (2)
  </head>

Note that there are two types of entry:

  1. This contains a block of javascript code.
  2. This contains a reference to an external file which contains a block of javascript code.

Note also that there can be any number of these entries in any order. They can be included in a web page by inserting code into an object's _cm_setJavaScript() method similar to the following:

    function _cm_setJavaScript ($javascript)
    // insert any javascript to be included in the <HEAD> or <BODY> elements.
    {
        global $mode;

        if ($mode == 'insert' or $mode == 'update') {
            $javascript['head'][]['file'] = 'javascript/usableforms.js';
            $javascript['head'][]['file'] = 'javascript/CalendarPopup.js';
            $javascript['head'][]['code'] = 'document.write(getCalendarStyles());';
            $javascript['head'][]['code'] = 'var cal1 = new CalendarPopup(); cal1.showYearNavigation();';
        } // if

        ....

        return $javascript;

    } // _cm_setJavaScript

Adding javascript to the <BODY> element

The next step is to allow entries to be inserted into the documents <BODY> element, as shown in the following example:

  <head>
  <body onload="...code..." onunload="...code...">
    ...

These can be included in a web page by inserting more code into an object's _cm_setJavaScript() method similar to the following:

    // specify scripting events on <body> tag
    $javascript['body']['onload'] = 'startForm()';
    $javascript['body']['onunload'] = 'endForm()';

Adding javascript at the foot of the <BODY> element

It is sometimes necessary to add some javascript at the end of the <BODY> element instead of the start. This can now be achieved with code similar to the following:

    function _cm_setJavaScript ($javascript)
    // insert any javascript to be included in the <HEAD> or <BODY> elements.
    {
        $javascript['foot'][]['file'] = 'javascript/whatever.js';
        $javascript['foot'][]['code'] = '...code...';

        return $javascript;

    } // _cm_setJavaScript

Adding javascript to individual controls

This is more tricky as there are several different variations that all need to be covered. Take a simple example of a TEXT control which should appear in the HTML output as follows:

<input type="text" name="col27" value="initial value" 
       onfocus="doStuff(2);" onblur="doStuff(3);">

This can be achieved by inserting code into an object's _cm_setJavaScript() method similar to the following:

    $this->fieldspec['col27']['javascript'] = array('onclick' => 'doStuff(1);',
                                                    'onfocus' => 'doStuff(2);',
                                                    'onblur' => 'doStuff(3);',
                                                    'onselect' => 'doStuff(4);',
                                                    'onchange' => 'doStuff(5)');

Note here that the array can contain an entry for any valid scripting event, not just those which are shown.

Here is a more complicated version:

<td>
    <script language="javascript">...code1...</script>
    <input name="col27" type="text" value=""/>
    <a href="#" onClick="...code2..." name="name27" id="id27">label27</a>
</td>

This can be achieved by inserting code into an object's _cm_setJavaScript() method similar to the following:

    $this->fieldspec['col27']['javascript'] = array('javascript' => '...code1...',
                                                    'href_onclick' => '...code2...',
                                                    'href_name' => 'name27',
                                                    'href_id' => 'id27',
                                                    'href_label' => 'label27');
                                                    // variations
                                                    'href_image' => '...image...'
                                                    'href_link' => '...url...'
                                                    'hidecontrol' => 'y'

Note the following variations:

For very simple javascript, such as adding a submit() to the onchange event, you can use the _cm_changeConfig() method as shown in Example of 'submit()' function.

Adding javascript to controls with options

Some controls, such as radio groups and dropdown lists, do not have single values but a group of options, and it is possible to have different scripting events on each option, as shown in the followng:

  <select name="star_sign" onchange="alert('change');">
    <option value=""> </option>
    <option value="ARI" onkeypress="alert('1');">Aries</option>
    <option value="AQU" onkeypress="alert('2');">Aquarius</option>
    <option value="CAN" onkeypress="alert('3');">Cancer</option>
    <option value="CAP" onkeypress="alert('4');">Capricorn</option>
    <option value="GEM" onkeypress="alert('5');">Gemini</option>
    <option value="LEO" onkeypress="alert('6');">Leo</option>
    <option value="LIB" onkeypress="alert('7');">Libra</option>
    <option value="PIS" onkeypress="alert('8');">Pisces</option>
    <option value="SAG" onkeypress="alert('9');">Sagittarius</option>
    <option value="SCO" onkeypress="alert('10');">Scorpio</option>
    <option value="TAU" onkeypress="alert('11');">Taurus</option>
    <option value="VIR" onkeypress="alert('12');" selected="selected">Virgo</option>
  </select>

The options are normally supplied in an associative array consisting of a key and a value, as in:

$array['star_sign'] = array('ARI' => 'Aries',
                            ...
                            'VIR' => 'Virgo');

In order to supply an additional set of scripting events for each key it is necessary to replace the value part with an array, as in the following:

$array['star_sign'] = array('ARI' => array('value' => 'Aries',
                                           'onkeyup' => "alert('up');",
                                           'onkeydown' => "alert('down');"),
                            ...
                            'VIR' => array('value' => 'Virgo',
                                           'onkeypress' => "alert('12');"));

Note that it is possible to specify any valid scripting event for each key, and if a particular key does not have any scripting events it can be specified in the short form.

Hide and Seek

One of the javascript effects that I was asked to incorporate into my framework was the ability to make fields appear and disappear dynamically. Take the following snippet of HTML:

    .....
    <script language="JavaScript" src="usableforms.js"/>       <-- (1)
    <script language="JavaScript">document.write();</script>   <-- (1)
  </head>
  <body onload="prepareForm()">    <-- (2)
    <form method="post" action="script.php">
      <table>                                            <-- (3)
        <tbody id="waitingRoom" style="display:none"/>   <-- (3)
      </table>                                           <-- (3)
      <table>
        <tr>
          <td>Type</td>
          <td>
            <select name="report_type">
              <option value="1" show="relationONE">One</option>       <-- (4)
              <option value="2" show="relationTWO">Two</option>       <-- (4)
              <option value="3" show="relationTHREE">Three</option>   <-- (4)
            </select>
          </td>
        </tr>
              
        <tr relation="relationONE">    <-- (5)
          <td>One</td>
          <td>
            <input name="field_1" type="text" value="ONE" />
          </td>
        </tr>
              
        <tr relation="relationTWO">    <-- (5)
          <td>Two</td>
          <td>
            <input name="field_2" type="text" value="TWO" />
          </td>
        </tr>
              
        <tr relation="relationTHREE">   <-- (5)
          <td">Three</td>
          <td>
            <input name="field_3" type="text" value="THREE" />
          </td>
        </tr>
      </table>
    </form>  
  </body>
  .....

What this does is make various rows in the table appear or disappear depending on which option in a dropdown list is selected. What the javascript does is link the relation="something" on individual rows to the show="something" against each selectable option. If the relation attribute does not match the show attribute then the row is hidden.

To make use of this javascript module the following elements need to appear in the HTML output, and this can be achieved with the following steps:

  1. This can be added in to the <HEAD> element using this technique.
  2. This can be added in to the <BODY> element using this technique.
  3. This can be included by inserting code into the object's _cm_setJavaScript() method similar to the following:
    $javascript['tbody'] = array('id' => 'waitingRoom', 'style' => 'display:none');
    
  4. This can be added to individual options by using this technique to add 'show' => '...' to the array of option values.
  5. As the contents of each row in the screen is defined in the screen structure file this is the best place to identify additional attributes for particular rows. Depending on how many fields there are to a row the additional code is slightly different:

    If the row contains only one field:

    $structure['main']['fields'][] = array('field1' => 'Id', 'colspan' => 3, 
                                           'javascript' => array('relation' => 'relationONE'));
    

    If the row contains more than one field:

    $structure['main']['fields'][2][] = array('label' => 'Foo Bar');
    $structure['main']['fields'][2][] = array('field' => 'foobar');
    $structure['main']['fields'][2][] = array('javascript' => array('relation' => 'relationTWO'));
    

Note that at present this feature can only be employed in screens which utlise the ADD 1 or UPDATE 1 patterns.

Adding an ID element to <tr> tags

This tip was provided by Kyle Brost.

How do you to add an ID element to a <tr> (table row) tag, such as in the following sample?

<tr id="tracker_stop_row">
  <td class="label"><span class="required">* </span>Stop Time</td>
  <td>
    <input name="tracker_stop" class="text" type="text" value="" maxlength="20" size="20" />
  </td>
</tr>

If the row contains a single field then this can be achieved with code in your screen structure file which is similar to the following:

$structure['main']['fields'][] = array('tracker_stop' => 'Stop Time',
                                       'javascript' => array('id'=>'tracker_stop_row'));

If the row contains more than one field then you will need something like the following:

$structure['main']['fields'][1][] = array('javascript' => array('id'=>'tracker_start_row'));
$structure['main']['fields'][1][] = array('label' => 'Date');
$structure['main']['fields'][1][] = array('field' => 'tracker_date');
$structure['main']['fields'][1][] = array('label' => 'Time');
$structure['main']['fields'][1][] = array('field' => 'tracker_time');

Headers and Footers

This section is redundant and has therefore been removed.

Example of 'submit()' function

There may be occasions when you want a change in a field's value in the client's browser sent to the server so that some action can be taken. This can be done using the javascript submit() function as in the following example:

function _cm_changeConfig ($where, $fieldarray)
// Change the table configuration for the duration of this instance.
{
    if ($GLOBALS['task_id'] == 'dict_related_column(multi4)a' OR $GLOBALS['task_id'] == 'dict_related_column(multi4)b') {
        // insert some javascript to submit form when a different value is selected in this dropdown list
        $this->fieldspec['key_name']['javascript'] = array('onchange' => 'this.form.submit();');
    } // if

    return $fieldarray;

} // _cm_changeConfig

This will send the entire form to the browser using the POST method, but because it is not done via a button whose name begins with "submit" it will not update the database. Instead it will go through the updateFieldArray() method where it can be dealt with locally within the customisable _cm_updateFieldArray() method as shown in the following example:

function _cm_updateFieldarray ($fieldarray, $postarray, $rownum)
// allow object to deal with any changes POSTed from the form (eg. by javascript)
// $fieldarray contains current data from one row.
// $postarray contains any changes made in the form for this row.
// $rownum identifies which row is being processed
{
    if (is_object($this->child_object) AND $this->child_object instanceof dict_related_column) {
        if (isset($postarray['key_name']) AND isset($fieldarray['key_name']) AND $postarray['key_name'] != $fieldarray['key_name']) {
            // deal with change of value in 'key_name'
            ....
        } // if
    } // if

    return $fieldarray;

} // _cm_updateFieldarray

Global javascript

There may be times when you have some javascript which needs to be inserted into every form, or every field of a certain type, and it becomes a tedious task to insert that code manually into every affected class. To make this easier I have created a new file in the includes directory called custom_javascript.class.inc which is automatically processed within script include.xml.php5.inc when constructing the HTML output. This class contains the following methods:


Amendment history:

01 Nov 2016 Added Global javascript.
01 Oct 2015 Added Adding javascript at the foot of the <BODY> element.
01 Dec 2013 Added Example of 'submit()' function.
02 May 2008 Added Adding an ID element to <tr> tags.
25 Jul 2007 Amended Headers and Footers to indicate that this section no longer applies.

counter