Revision: 1837
          http://mrbs.svn.sourceforge.net/mrbs/?rev=1837&view=rev
Author:   cimorrison
Date:     2011-06-21 08:51:00 +0000 (Tue, 21 Jun 2011)

Log Message:
-----------
- On the Report page, converted input fields into auto-complete fields for 
custom fields that have select_options defined
- For custom fields allowed $select_options to be an associative array, thus 
making it easy to change the displayed value without having to change the 
database.  (See SF #3315966)

Modified Paths:
--------------
    mrbs/trunk/INSTALL
    mrbs/trunk/web/Themes/default/header.inc
    mrbs/trunk/web/dbsys.inc
    mrbs/trunk/web/edit_users.php
    mrbs/trunk/web/functions.inc
    mrbs/trunk/web/functions_mail.inc
    mrbs/trunk/web/functions_view.inc
    mrbs/trunk/web/report.php
    mrbs/trunk/web/search.php
    mrbs/trunk/web/systemdefaults.inc.php

Modified: mrbs/trunk/INSTALL
===================================================================
--- mrbs/trunk/INSTALL  2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/INSTALL  2011-06-21 08:51:00 UTC (rev 1837)
@@ -221,6 +221,20 @@
 would define the 'conference_facilities' custom field to have three
 possible values.
 
+For custom fields only (will be extended later) it is also possible to use
+an associative array for $select_options, for example
+
+$select_options['entry.catering'] = array('c' => 'Coffee', 
+                                          's' => 'Sandwiches',
+                                          'h' => 'Hot Lunch');
+
+In this case the key (eg 'c') is stored in the database, but the value
+(eg 'Coffee') is displayed and can be searched for using Search and Report.
+This allows you to alter the displayed values, for example changing 'Coffee'
+to 'Coffee, Tea and Biscuits', without having to alter the database.   It can 
also
+be useful if the database table is being shared with another application.
+MRBS will auto-detect whether the array is associative.
+
 2)
 
 You can specify that a field is mandatory. This will ensure that the

Modified: mrbs/trunk/web/Themes/default/header.inc
===================================================================
--- mrbs/trunk/web/Themes/default/header.inc    2011-06-08 10:31:11 UTC (rev 
1836)
+++ mrbs/trunk/web/Themes/default/header.inc    2011-06-21 08:51:00 UTC (rev 
1837)
@@ -3,34 +3,28 @@
 // $Id$
 
 // Generates the JavaScript code to turn the input with id $id
-// into an autocomplete box.  The options will be contained in the
-// first element of each row of the result from the SQL query $sql
-// (eg "SELECT area_name FROM $tbl_area ORDER BY area_name")
-function generate_autocomplete($id, $sql)
+// into an autocomplete box, with options contained in the
+// array $options.
+function generate_autocomplete($id, $options)
 {
   global $autocomplete_length_breaks;
   
   $js = '';
 
-  $res = sql_query($sql);
-  if ($res && (sql_count($res) > 0))
+  $n_options = count($options);
+  if ($n_options > 0)
   {
-    $names = array();
-    for ($i = 0; ($row = sql_row($res, $i)); $i++)
-    {
-      $names[] = escape_js($row[0]);
-    }
     // Work out a suitable value for the autocomplete minLength
     // option, ie the number of characters that must be typed before
     // a list of options appears.   We want to avoid presenting a huge 
     // list of options.
-    $n_names = count($names);
+    
     $min_length = 0;
     if (isset($autocomplete_length_breaks) && 
is_array($autocomplete_length_breaks))
     {
       foreach ($autocomplete_length_breaks as $break)
       {
-        if ($n_names < $break)
+        if ($n_options < $break)
         {
           break;
         }
@@ -38,7 +32,12 @@
       }
     }
     // Start forming the array literal
-    $names_string = "'" . implode("','", $names) . "'";
+    // Escape the options
+    for ($i=0; $i < $n_options; $i++)
+    {
+      $options[$i] = escape_js($options[$i]);
+    }
+    $options_string = "'" . implode("','", $options) . "'";
     // Build the JavaScript.   We don't support autocomplete in IE6 and below
     // because the browser doesn't render the autocomplete box properly - it
     // gets hidden behind other elements.   Although there are fixes for this,
@@ -46,7 +45,7 @@
     $js .= "if ($('#ielte6').length == 0)\n";
     $js .= "{\n";
     $js .= "  $('#$id').autocomplete({\n";
-    $js .= "    source: [$names_string],\n";
+    $js .= "    source: [$options_string],\n";
     $js .= "    minLength: $min_length\n";
     $js .= "  })";
     // If the minLength is 0, then the autocomplete widget doesn't do
@@ -76,6 +75,7 @@
   global $default_language_tokens, $disable_automatic_language_changing, 
$override_locale;
   global $lang_map_windows, $langs, $server_os;
   global $default_duration_all_day;
+  global $select_options;
   
   $page = basename($PHP_SELF, ".php");
   $user = getUserName();
@@ -932,14 +932,30 @@
   if ($page == 'report')
   {
     // Make the area match input on the report page into an auto-complete input
-    $sql = "SELECT area_name FROM $tbl_area ORDER BY area_name";
-    echo generate_autocomplete('areamatch', $sql);
+    $options = sql_query_array("SELECT area_name FROM $tbl_area ORDER BY 
area_name");
+    if ($options !== FALSE)
+    {
+      echo generate_autocomplete('areamatch', $options);
+    }
 
     // Make the room match input on the report page into an auto-complete input
     // (We need DISTINCT because it's possible to have two rooms of the same 
name
     // in different areas)
-    $sql = "SELECT DISTINCT room_name FROM $tbl_room ORDER BY room_name";
-    echo generate_autocomplete('roommatch', $sql);
+    $options = sql_query_array("SELECT DISTINCT room_name FROM $tbl_room ORDER 
BY room_name");
+    if ($options !== FALSE)
+    {
+      echo generate_autocomplete('roommatch', $options);
+    }
+    
+    // Make any custom fields for the entry table that have an array of options
+    // into auto-complete inputs
+    foreach ($select_options as $field => $options)
+    {
+      if (strpos($field, 'entry.') == 0)
+      {
+        echo generate_autocomplete('match_' . substr($field, 
strlen('entry.')), $options);
+      }
+    }
   }
 
   // SEARCH.PHP

Modified: mrbs/trunk/web/dbsys.inc
===================================================================
--- mrbs/trunk/web/dbsys.inc    2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/dbsys.inc    2011-06-21 08:51:00 UTC (rev 1837)
@@ -99,6 +99,35 @@
 }
 
 
+// Run an SQL query that returns a simple one dimensional array of results.
+// The SQL query must select only one column.   Returns an empty array if
+// no results, or FALSE if there's an error
+function sql_query_array($sql)
+{
+  if (func_num_args() > 1)
+  {
+    $handle = func_get_arg(1);
+    $db_conn = $handle['connection'];
+  }
+  
+  $res = ($db_conn) ? sql_query($sql, $db_conn) : sql_query($sql);
+  
+  if ($res === FALSE)
+  {
+    return FALSE;
+  }
+  else
+  {
+    $result = array();
+    for ($i = 0; ($row = sql_row($res, $i)); $i++)
+    {
+      $result[] = $row[0];
+    }
+    return $result;
+  }
+}
+
+
 // Run a SQL query, returns a result object
 function sql_query($sql)
 {
@@ -115,7 +144,6 @@
     $db_sys = $dbsys;
     $db_conn = null;
   }
-
   $f = "sql_${db_sys}_query";
   return $f($sql, $db_conn);
 }

Modified: mrbs/trunk/web/edit_users.php
===================================================================
--- mrbs/trunk/web/edit_users.php       2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/edit_users.php       2011-06-21 08:51:00 UTC (rev 1837)
@@ -134,6 +134,7 @@
   global $tbl_users, $PHP_SELF;
   global $user, $level, $min_user_editing_level, $max_content_length;
   global $fields, $auth;
+  global $select_options;
   
   $html = '';
   $html .= "<div class=\"$class\">\n";
@@ -216,7 +217,14 @@
             $html .= "<td><div>" . htmlspecialchars($col_value) . 
"</div></td>\n";
             break;
           default:
-            if (($field['nature'] == 'boolean') || 
+            // Where there's an associative array of options, display
+            // the value rather than the key
+            if (is_assoc($select_options["users.$key"]))
+            {
+              $col_value = $select_options["users.$key"][$line[$key]];
+              $html .= "<td><div>" . htmlspecialchars($col_value) . 
"</div></td>\n";
+            }
+            elseif (($field['nature'] == 'boolean') || 
                 (($field['nature'] == 'integer') && isset($field['length']) && 
($field['length'] <= 2)) )
             {
               // booleans: represent by a checkmark

Modified: mrbs/trunk/web/functions.inc
===================================================================
--- mrbs/trunk/web/functions.inc        2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/functions.inc        2011-06-21 08:51:00 UTC (rev 1837)
@@ -359,8 +359,8 @@
 
 // Generates a select box from $options, an array of options
 // If $disabled is TRUE, then the select box is disabled and a hidden
-// input is generated to pass through $value
-function generate_select($label_text, $name, $value, $options, 
+// input is generated to pass through $current
+function generate_select($label_text, $name, $current, $options, 
                          $mandatory = FALSE, $disabled=FALSE)
 {
   // generate the HTML
@@ -370,20 +370,33 @@
   $html .= ">\n";
   if ($mandatory)
   {
-    $options = array_merge(array(""),$options);
+    $options = array_merge(array('' => ''),$options);
   }
-  foreach ($options as $option)
+  // We can cope with both associative and ordinary arrays
+  if (is_assoc($options))
   {
-    $html .= "<option";
-    $html .= (isset($value) && ($value == $option)) ? " selected=\"selected\"" 
: '';
-    $html .= ">".htmlspecialchars($option)."</option>\n";
+    foreach ($options as $key => $value)
+    {
+      $html .= "<option value=\"$key\"";
+      $html .= (isset($current) && ($current == $key)) ? " 
selected=\"selected\"" : '';
+      $html .= ">".htmlspecialchars($value)."</option>\n";
+    }
   }
+  else
+  {
+    foreach ($options as $option)
+    {
+      $html .= "<option";
+      $html .= (isset($current) && ($current == $option)) ? " 
selected=\"selected\"" : '';
+      $html .= ">".htmlspecialchars($option)."</option>\n";
+    }
+  }
   $html .= "</select>\n";
   // and a hidden input if the select box is disabled
   if ($disabled)
   {
     $html .= "<input type=\"hidden\" name=\"$name\" value=\"".
-      htmlspecialchars($value)."\">\n";
+      htmlspecialchars($current)."\">\n";
   }
   
   echo $html;
@@ -1859,4 +1872,11 @@
   return $uid;
 }
 
+// Tests whether an array is associative
+//
+// Thanks to magentix at gmail dot com at 
http://php.net/manual/function.is-array.php
+function is_assoc($arr)
+{
+  return (is_array($arr) && count(array_filter(array_keys($arr),'is_string')) 
== count($arr));
+}
 ?>

Modified: mrbs/trunk/web/functions_mail.inc
===================================================================
--- mrbs/trunk/web/functions_mail.inc   2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/functions_mail.inc   2011-06-21 08:51:00 UTC (rev 1837)
@@ -388,6 +388,7 @@
   global $enable_periods, $approval_enabled, $confirmation_enabled;
   global $typel, $mail_settings, $standard_fields, $url_base;
   global $tbl_entry;
+  global $select_options;
 
   // set up the body
   $body = "";
@@ -595,11 +596,22 @@
             (($field['nature'] == 'integer') && isset($field['length']) && 
($field['length'] <= 2)) )
         {
           $value = ($value) ? get_mail_vocab("yes") : get_mail_vocab("no");
-          if (!$compare)
+          if ($compare)
           {
             $mail_previous[$key] = ($mail_previous[$key]) ? 
get_mail_vocab("yes") : get_mail_vocab("no");
           }
         }
+        // For any associative arrays we want the value rather than the key
+        if (is_assoc($select_options["entry.$key"]) && 
+            array_key_exists($value, $select_options["entry.$key"]))
+        {
+          $value = $select_options["entry.$key"][$value];
+          if ($compare &&
+              array_key_exists($mail_previous[$key], 
$select_options["entry.$key"]))
+          {
+            $mail_previous[$key] = 
$select_options["entry.$key"][$mail_previous[$key]];
+          }
+        }
         $body .= create_body_table_row (get_mail_field_name($tbl_entry, $key),
                                         convertToMailCharset($value),
                                         
convertToMailCharset($mail_previous[$key]),

Modified: mrbs/trunk/web/functions_view.inc
===================================================================
--- mrbs/trunk/web/functions_view.inc   2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/functions_view.inc   2011-06-21 08:51:00 UTC (rev 1837)
@@ -40,6 +40,7 @@
   global $is_private_field, $standard_fields, $typel;
   global $strftime_format;
   global $tbl_entry;
+  global $select_options;
   
   // Get the duration if we haven't got it already
   if (!isset($data['duration']))
@@ -174,7 +175,24 @@
       // Otherwise output a string
       else
       {
-        $value = (isset($data[$key])) ? $data[$key] : "&nbsp;"; 
+        if (isset($data[$key]))
+        {
+          // If the custom field is an associative array then we want
+          // the value rather than the array key
+          if (is_assoc($select_options["entry.$key"]) && 
+              array_key_exists($data[$key], $select_options["entry.$key"]))
+          {
+            $value = $select_options["entry.$key"][$data[$key]];
+          }
+          else
+          {
+            $value = $data[$key];
+          }
+        }
+        else
+        {
+          $value = "&nbsp;";
+        }
       }
       $class = ($keep_private && $is_private_field["entry.$key"]) ? "private" 
: "";
       $tbody .= create_details_row($label, $value, $as_html, $class);

Modified: mrbs/trunk/web/report.php
===================================================================
--- mrbs/trunk/web/report.php   2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/report.php   2011-06-21 08:51:00 UTC (rev 1837)
@@ -196,6 +196,7 @@
   global $custom_fields, $field_natures, $field_lengths, $tbl_entry;
   global $approval_somewhere, $confirmation_somewhere;
   global $strftime_format;
+  global $select_options;
   
   // Initialise the line for CSV reports
   $line = "";
@@ -397,9 +398,23 @@
       $output = empty($row[$key]) ? get_vocab("no") : get_vocab("yes");
     }
     // Otherwise output a string
+    elseif (isset($row[$key]))
+    {
+      // If the custom field is an associative array then we want
+      // the value rather than the array key
+      if (is_assoc($select_options["entry.$key"]) && 
+          array_key_exists($row[$key], $select_options["entry.$key"]))
+      {
+        $output = $select_options["entry.$key"][$row[$key]];
+      }
+      else
+      {
+        $output = $row[$key]; 
+      }
+    }
     else
     {
-      $output = (isset($row[$key])) ? $row[$key] : ''; 
+      $output = '';
     }
     
     if ($output_as_csv)
@@ -978,8 +993,31 @@
   foreach ($custom_fields as $key => $value)
   {
     $var = "match_$key";
+    // Associative arrays
+    if (!empty($var) && is_assoc($select_options["entry.$key"]))
+    {
+      $sql .= " AND ";
+      $or_array = array();
+      foreach($select_options["entry.$key"] as $option_key => $option_value)
+      {
+        // We have to use strpos() rather than stripos() because we cannot
+        // assume PHP5
+        if (strpos(strtolower($option_value), strtolower($$var)) !== FALSE)
+        {
+          $or_array[] = "E.$key='" . addslashes($option_key) . "'";
+        }
+      }
+      if (count($or_array) > 0)
+      {
+        $sql .= "(". implode( " OR ", $or_array ) .")";
+      }
+      else
+      {
+        $sql .= "FALSE";
+      }
+    }
     // Booleans (or integers <= 2 bytes which we assume are intended to be 
booleans)
-    if (($field_natures[$key] == 'boolean') || 
+    elseif (($field_natures[$key] == 'boolean') || 
        (($field_natures[$key] == 'integer') && isset($field_lengths[$key]) && 
($field_lengths[$key] <= 2)) )
     {
       if (!empty($$var))

Modified: mrbs/trunk/web/search.php
===================================================================
--- mrbs/trunk/web/search.php   2011-06-08 10:31:11 UTC (rev 1836)
+++ mrbs/trunk/web/search.php   2011-06-21 08:51:00 UTC (rev 1837)
@@ -81,14 +81,29 @@
   . " OR " . sql_syntax_caseless_contains("E.name", $search_str)
   . " OR " . sql_syntax_caseless_contains("E.description", $search_str);
 
-// Also need to search custom fields (but only those with character data)
+// Also need to search custom fields (but only those with character data,
+// which can include fields that have an associative array of options)
 $fields = sql_field_info($tbl_entry);
 foreach ($fields as $field)
 {
   if (!in_array($field['name'], $standard_fields['entry']))
   {
-    if ($field['nature'] == 'character')
+    // If we've got a field that is represented by an associative array of 
options
+    // then we have to search for the keys whose values match the search string
+    if (is_assoc($select_options["entry." . $field['name']]))
     {
+      foreach($select_options["entry." . $field['name']] as $key => $value)
+      {
+        // We have to use strpos() rather than stripos() because we cannot
+        // assume PHP5
+        if (strpos(strtolower($value), strtolower($search_str)) !== FALSE)
+        {
+          $sql_pred .= " OR E." . $field['name'] . "='" . addslashes($key) . 
"'";
+        }
+      }
+    }
+    elseif ($field['nature'] == 'character')
+    {
       $sql_pred .= " OR " . sql_syntax_caseless_contains("E." . 
$field['name'], $search_str);
     }
   }
@@ -162,6 +177,7 @@
       ORDER BY E.start_time asc "
   . sql_syntax_limit($search["count"], $search_pos);
 
+
 // this is a flag to tell us not to display a "Next" link
 $result = sql_query($sql);
 if (! $result)

Modified: mrbs/trunk/web/systemdefaults.inc.php
===================================================================
--- mrbs/trunk/web/systemdefaults.inc.php       2011-06-08 10:31:11 UTC (rev 
1836)
+++ mrbs/trunk/web/systemdefaults.inc.php       2011-06-21 08:51:00 UTC (rev 
1837)
@@ -429,10 +429,24 @@
 
 //$select_options['entry.name'] = array('Physics', 'Chemistry', 'Biology');
 
-// At the moment this feature is only supported as follows:
+// At the moment $select_options is only supported as follows:
 //     - Entry table: name, description and custom fields
 //     - Users table: custom fields
 
+// For custom fields only (will be extended later) it is also possible to use
+// an associative array for $select_options, for example
+
+//$select_options['entry.catering'] = array('c' => 'Coffee', 
+//                                          's' => 'Sandwiches',
+//                                          'h' => 'Hot Lunch');
+
+// In this case the key (eg 'c') is stored in the database, but the value
+// (eg 'Coffee') is displayed and can be searched for using Search and Report.
+// This allows you to alter the displayed values, for example changing 'Coffee'
+// to 'Coffee, Tea and Biscuits', without having to alter the database.   It 
can also
+// be useful if the database table is being shared with another application.
+// MRBS will auto-detect whether the array is associative.
+
 $is_mandatory_field = array();
 // You can define custom entry fields to be mandatory by setting
 // items in the array $is_mandatory_field.   (Note that making a checkbox


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
EditLive Enterprise is the world's most technically advanced content
authoring tool. Experience the power of Track Changes, Inline Image
Editing and ensure content is compliant with Accessibility Checking.
http://p.sf.net/sfu/ephox-dev2dev
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits

Reply via email to