Generating Columns from an Array

Installed to support alpha features on this server as of 2005-06-12.

This page presents new code for the Wikka Core to generate columns of items from an array of items to be presented - without using a table for layout.

Why?


In many cases we get an array back from some procedure and want to display the result in the form of a number of easy to read columns. The current Wikka code now does this "manually" and generates a table layout which is not only not very structural code but also not very accessible. (Example: the Category action can generate its output in "columns" but they need to be read horizontally rather than vertically - making it hard to "scan" so a particular name is hard to find - and the code generated is a layout table.)

Using a standard way to generate columns is more efficient, can ensure consistent and structural code and makes it easier to write methods (or actions or handlers) that need columns of items as output.

How?


Two separate methods were written to make it easy to generate well-structured columns with 'hooks' for styling: the first does nothing but generate a list from an array (with an id); the second wraps that in a bit of code with a heading and a bit of text instead of the list if the array happens to be empty.

The Code


Constants

The methods make use of some constants (limits and texts used for error messages, ready for internationalization) that should be defined in the constants section in wikka.php.

See ArrayToList for the code and where to insert it.

makeCols()

This method does the hard work of creating columnar output from an array, using floated divs instead of a layout table. It requires the makeId() method to be already present - see GenerateUniqueId.

Add the following code in the //MISC section right after the makeMemberList() method (see ArrayToList for that):

makeCols()
  1.     /**
  2.      * Build vertically-arranged columns from an array.
  3.      *
  4.      * Given an array and number of columns, this method builds vertically-
  5.      * arranged columns (meaning they are read vertically, one by one)
  6.      * implemented as floated divs. Column width is derived from the
  7.      * specified number of columns, implemented as an embedded style because
  8.      * it's dynamically generated; left float is added to the style (hardcoded
  9.      * for now but alignment could become an option later).
  10.      *
  11.      * @author      {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
  12.      * @copyright   Copyright © 2005, Marjolein Katsma
  13.      * @license     http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  14.      * @version     0.4
  15.      *
  16.      * @todo    - make alignment configurable
  17.      *          - class as extra parameter (for each column)
  18.      *          - replace clear: both style at end with a class (?)
  19.      *
  20.      * @access  public
  21.      *
  22.      * @param   array   $array  required: flat array with content items; must be array but may be empty
  23.      * @param   integer $cols   optional: number of columns to generate; default: 1
  24.      *                          (will be cast to positive integer)
  25.      * @return  string  generated divs (or empty string if array was empty)
  26.      */
  27.     function makeCols($array,$cols=1)
  28.     {
  29.         // validate/treat input
  30.         if (!is_array($array))
  31.         {
  32.             return '<p class="error">'.sprintf(ERR_CANNOTGEN,STRUC_COLS,STRUC_ARRAY).'</p>'."\n";
  33.         }
  34.         $cols  = abs((int)$cols);                           # make sure we have a positive integer
  35.         // build columns
  36.         $count = count($array);
  37.         $width = (int) (100 / $cols);
  38.         $lines = ($count % $cols == 0) ? (int)($count / $cols) : (int)(($count + $cols) / $cols);
  39.         $line = 0;
  40.         $out = '';
  41.         // data columns
  42.         foreach ($array as $val)
  43.         {
  44.             if (($line++ % $lines) == 0) $out .= "\n".' <div style="width: '.$width.'%; float: left;">'."\n";
  45.             $out .= '       '.$val.'<br />'."\n";
  46.             if (($line % $lines) == 0) $out .= "    </div>";
  47.         }
  48.         if ($count > 0)
  49.         {
  50.             if (($line % $lines) != 0) $out .= "    </div>";
  51.             $out .= '<br style="clear: both;">'."\n";
  52.         }
  53.         // return result
  54.         return $out;
  55.     }


makeMemberCols()

This method is a wrapper around the makeCols() method: it wraps the output in a div and adds a heading or outputs a paragraph of text in case the array turns out to be empty. It's meant for cases where items are to be presented as "members" of a collection; the heading is used to indicate the number of members.

As with the makeMemberList() method there is deliberately no 'outer' div with an id: this is so a wrapper div may be created with a single heading containing several occurrences of the output of this method. Such a wrapper should be generated in the calling code.

Add the following code in the //MISC section right after the makeCols() method:

makeMemberCols()
  1.     /**
  2.      * Display members of a collection in vertical columns; a heading precedes
  3.      * the columns; alternatively output is just a paragraph of text in case the
  4.      * array provided turns out to be empty.
  5.      *
  6.      * There is deliberately no 'outer' div with an id: this is so a div may be
  7.      * created with a single heading containing several occurrences of the
  8.      * output of this method. Such a wrapper should be generated in the calling code.
  9.      *
  10.      * @author      {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
  11.      * @copyright   Copyright © 2005, Marjolein Katsma
  12.      * @license     http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  13.      * @version     0.6
  14.      *
  15.      * @access  public
  16.      * @uses    makeId()
  17.      * @uses    makeCols()
  18.      *
  19.      * @param   array   $array      required: flat array with collection items
  20.      * @param   string  $hd         required: heading for the whole
  21.      * @param   string  $hdid       required: id for the heading
  22.      * @param   string  $txtnone    required: text to display when the array is empty
  23.      * @param   integer $level      optional: level of the heading to generate; default: 6
  24.      * @return  string  div containing heading and list, or paragraph
  25.      */
  26.     function makeMemberCols($array,$cols,$hd,$hdid,$txtnone,$level=6)
  27.     {
  28.         // validate/sanitize input
  29.         if (!is_array($array))
  30.         {
  31.             return '<p class="error">'.sprintf(ERR_CANNOTGEN,STRUC_COLS,STRUC_ARRAY).'</p>'."\n";
  32.         }
  33.         $cols  = abs((int)$cols);                           # make sure we have a positive integer
  34.         $level = max(min((int)$level,6),3);                 # make sure level is in range 3-6
  35.         // initializations
  36.         $count = count($array);
  37.         $out = '';
  38.         // build structure
  39.         if ($count > 0)
  40.         {
  41.             $out .= '   <h6 id="'.$this->makeId('hn',$hdid).'">'.$hd.'</h6>'."\n";
  42.             $out .= $this->makeCols($array,$cols);
  43.         }
  44.         else
  45.         {
  46.             $out  = '   <p>'.$txtnone.'</p>'."\n";
  47.         }
  48.         // return result
  49.         return $out;
  50.     }



When and where to use


In general, you can use these methods anywhere you get (or build) an array and want to display the result in the form of columns - for instance to avoid over-long pages when there are a lot of items to show.

Several current actions and handlers could take advantage of these methods, in particular:
Updates for these (and possibly others) taking advantage of these new methods will soon be published on this site!

Status


As can be seen from the @version numbers and @todo items in the docblocks, the code is far from "finished".

Still, code as published here will change as it's being refined - so keep an eye on the page!


CategoryDevelopmentCore
There is one comment on this page. [Display comment]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki