]> git.donarmstrong.com Git - roundcube.git/blobdiff - program/include/rcube_html.inc
Imported Upstream version 0.1~rc2
[roundcube.git] / program / include / rcube_html.inc
diff --git a/program/include/rcube_html.inc b/program/include/rcube_html.inc
new file mode 100644 (file)
index 0000000..a31594a
--- /dev/null
@@ -0,0 +1,671 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | rcube_html.inc                                                        |
+ |                                                                       |
+ | This file is part of the RoundCube PHP suite                          |
+ | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
+ | Licensed under the GNU GPL                                            |
+ |                                                                       |
+ | CONTENTS:                                                             |
+ |   Common Classes to create HTML output                                |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ +-----------------------------------------------------------------------+
+
+ $Id:  $
+
+*/
+
+
+/**
+ * HTML page builder class
+ *
+ * @package HTML
+ */
+class rcube_html_page
+{
+  var $scripts_path = '';
+  var $script_files = array();
+  var $scripts = array();
+  var $charset = 'UTF-8';
+  
+  var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n";
+  var $script_tag      = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n";
+  var $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
+
+  var $title = 'RoundCube Mail';
+  var $header = '';
+  var $footer = '';
+  var $body = '';
+  var $body_attrib = array();
+  var $meta_tags = array();
+  
+  
+  /**
+   * Link an external script file
+   *
+   * @param string File URL
+   * @param string Target position [head|foot]
+   */
+  function include_script($file, $position='head')
+  {
+    static $sa_files = array();
+    
+    if (in_array($file, $sa_files))
+      return;
+      
+    if (!is_array($this->script_files[$position]))
+      $this->script_files[$position] = array();
+      
+    $this->script_files[$position][] = $file;
+  }
+  
+  /**
+   * Add inline javascript code
+   *
+   * @param string JS code snippet
+   * @param string Target position [head|head_top|foot]
+   */
+  function add_script($script, $position='head')
+  {
+    if (!isset($this->scripts[$position]))
+      $this->scripts[$position] = "\n".rtrim($script);
+    else
+      $this->scripts[$position] .= "\n".rtrim($script);
+  }
+
+  /**
+   * Add HTML code to the page header
+   */
+  function add_header($str)
+  {
+    $this->header .= "\n".$str;
+  }
+
+  /**
+   * Add HTML code to the page footer
+   * To be added right befor </body>
+   */
+  function add_footer($str)
+  {
+    $this->footer .= "\n".$str;
+  }
+
+  /**
+   * Setter for page title
+   */
+  function set_title($t)
+  {
+    $this->title = $t;
+  }
+
+
+  /**
+   * Setter for output charset.
+   * To be specified in a meta tag and sent as http-header
+   */
+  function set_charset($charset)
+  {
+    global $MBSTRING;
+    
+    $this->charset = $charset;
+    
+    if ($MBSTRING && function_exists("mb_internal_encoding"))
+      {
+      if(!@mb_internal_encoding($charset))
+        $MBSTRING = FALSE;
+      }
+  }
+
+  /**
+   * Getter for output charset
+   */
+  function get_charset()
+  {
+    return $this->charset;
+  }
+
+
+  /**
+   * Reset all saved properties
+   */
+  function reset()
+  {
+    $this->script_files = array();
+    $this->scripts = array();
+    $this->title = '';
+    $this->header = '';
+    $this->footer = '';
+  }
+
+
+  /**
+   * Process template and write to stdOut
+   *
+   * @param string HTML template
+   * @param string Base for absolute paths
+   */
+  function write($templ='', $base_path='')
+  {
+    $output = empty($templ) ? $this->default_template : trim($templ);
+    
+    // replace specialchars in content
+    $__page_title = Q($this->title, 'show', FALSE);
+    $__page_header = $__page_body = $__page_footer = '';
+    
+    
+    // include meta tag with charset
+    if (!empty($this->charset))
+    {
+      header('Content-Type: text/html; charset='.$this->charset, true);
+      $__page_header = '<meta http-equiv="content-type" content="text/html; charset='.$this->charset.'" />'."\n";
+    }
+  
+  
+    // definition of the code to be placed in the document header and footer
+    if (is_array($this->script_files['head']))
+      foreach ($this->script_files['head'] as $file)
+        $__page_header .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+
+    $head_script = $this->scripts['head_top'] . $this->scripts['head'];
+    if (!empty($head_script))
+      $__page_header .= sprintf($this->script_tag, $head_script);
+
+    if (!empty($this->header))
+      $__page_header .= $this->header;
+
+    if (is_array($this->script_files['foot']))
+      foreach ($this->script_files['foot'] as $file)
+        $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file);
+
+    if (!empty($this->scripts['foot']))
+      $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']);
+      
+    if (!empty($this->footer))
+      $__page_footer .= $this->footer;
+
+    // find page header
+    if ($hpos = strpos(strtolower($output), '</head>'))
+      $__page_header .= "\n";
+    else 
+    {
+      if (!is_numeric($hpos))
+        $hpos = strpos(strtolower($output), '<body');
+      if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
+      {
+        while($output[$hpos]!='>')
+          $hpos++;
+        $hpos++;
+      }
+  
+      $__page_header = "<head>\n<title>$__page_title</title>\n$__page_header\n</head>\n";
+    }
+  
+    // add page hader
+    if ($hpos)
+      $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
+    else
+      $output = $__page_header . $output;
+  
+  
+    // find page body
+    if($bpos = strpos(strtolower($output), '<body'))
+    {
+      while($output[$bpos]!='>') $bpos++;
+      $bpos++;
+    }
+    else
+      $bpos = strpos(strtolower($output), '</head>')+7;
+  
+    // add page body
+    if($bpos && $__page_body)
+      $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output));
+  
+  
+    // find and add page footer
+    $output_lc = strtolower($output);
+    if(($fpos = strrstr($output_lc, '</body>')) ||
+       ($fpos = strrstr($output_lc, '</html>')))
+      $output = substr($output, 0, $fpos) . "$__page_footer\n" . substr($output, $fpos);
+    else
+      $output .= "\n$__page_footer";
+  
+  
+    // reset those global vars
+    $__page_header = $__page_footer = '';
+  
+  
+    // correct absolute paths in images and other tags
+    $output = preg_replace('/(src|href|background)=(["\']?)(\/[a-z0-9_\-]+)/Ui', "\\1=\\2$base_path\\3", $output);
+    $output = str_replace('$__skin_path', $base_path, $output);
+  
+    print rcube_charset_convert($output, 'UTF-8', $this->charset);
+  }
+    
+}  // end class rcube_html_page
+
+
+
+/**
+ * Base class to build a HTML for element
+ *
+ * @package HTML
+ */
+class rcube_form_element
+  {
+  var $uppertags = FALSE;
+  var $upperattribs = FALSE;
+  var $upperprops = FALSE;
+  var $newline = FALSE;
+  
+  var $attrib = array();
+
+
+  /**
+   * Create string with saved attributes
+   *
+   * @return string HTML formatted tag attributes
+   */
+  function create_attrib_string()
+  {
+    if (!sizeof($this->attrib))
+      return '';
+
+    if ($this->name!='')
+      $this->attrib['name'] = $this->name;
+
+    $attrib_arr = array();
+    foreach ($this->attrib as $key => $value)
+    {
+      // don't output some internally used attributes
+      if (in_array($key, array('form', 'quicksearch')))
+        continue;
+
+      // skip if size if not numeric
+      if (($key=='size' && !is_numeric($value)))
+        continue;
+        
+      // skip empty eventhandlers
+      if ((strpos($key,'on')===0 && $value==''))
+        continue;
+
+      // encode textarea content
+      if ($key=='value')
+        $value = Q($value, 'strict', FALSE);
+
+      // attributes with no value
+      if (in_array($key, array('checked', 'multiple', 'disabled', 'selected', 'nowrap')))
+      {
+        if ($value)
+          $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $key);
+      }
+      // don't convert size of value attribute
+      else if ($key=='value')
+        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $value);
+        
+      // regular tag attributes
+      else
+        $attrib_arr[] = sprintf('%s="%s"', $this->_conv_case($key, 'attrib'), $this->_conv_case($value, 'value'));
+    }
+
+    return sizeof($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
+  }
+    
+    
+  /**
+   * Convert tags and attributes to upper-/lowercase
+   *
+   * @param string Input string
+   * @param string Value type (can either be "tag" or "attrib")
+   * @return string Converted output string
+   * @access private
+   */
+  function _conv_case($str, $type='attrib')
+    {
+    if ($type == 'tag')
+      return $this->uppertags ? strtoupper($str) : strtolower($str);
+    else if ($type == 'attrib')
+      return $this->upperattribs ? strtoupper($str) : strtolower($str);
+    else if ($type == 'value')
+      return $this->upperprops ? strtoupper($str) : strtolower($str);
+    }    
+  }
+
+
+/**
+ * Builder for an <input> field
+ *
+ * @package HTML
+ */
+class input_field extends rcube_form_element
+{
+  var $type = 'text';
+  
+  /**
+   * Constructor
+   * @param array Named tag attributes
+   */
+  function input_field($attrib=array())
+  {
+    if (is_array($attrib))
+      $this->attrib = $attrib;
+
+    if ($attrib['type'])
+      $this->type = $attrib['type'];    
+
+    if ($attrib['newline'])
+      $this->newline = TRUE;    
+  }  
+
+  /**
+   * Compose input tag
+   *
+   * @param string Field value
+   * @param array  Additional tag attributes
+   * @return string Final HTML code
+   */
+  function show($value=NULL, $attrib=NULL)
+  {
+    // overwrite object attributes
+    if (is_array($attrib))
+      $this->attrib = array_merge($this->attrib, $attrib);
+
+    // set value attribute
+    if ($value!==NULL)
+      $this->attrib['value'] = $value;
+
+    $this->attrib['type'] = $this->type;
+
+    // return final tag
+    return sprintf(
+      '<%s%s />%s',
+      $this->_conv_case('input', 'tag'),
+      $this->create_attrib_string(),
+      ($this->newline ? "\n" : ""));
+  }  
+}
+
+
+/**
+ * Builder for a <input type="text"> field
+ *
+ * @package HTML
+ */
+class textfield extends input_field
+{
+  var $type = 'text';
+}
+
+/**
+ * Builder for a <input type="password"> field
+ *
+ * @package HTML
+ */
+class passwordfield extends input_field
+{
+  var $type = 'password';
+}
+
+/**
+ * Builder for <input type="radio"> fields
+ *
+ * @package HTML
+ */
+class radiobutton extends input_field
+{
+  var $type = 'radio';
+}
+
+/**
+ * Builder for <input type="checkbox"> fields
+ *
+ * @package HTML
+ */
+class checkbox extends input_field
+{
+  var $type = 'checkbox';
+
+
+  /**
+   * Compose input tag
+   *
+   * @param string Field value
+   * @param array  Additional tag attributes
+   * @return string Final HTML code
+   */
+  function show($value='', $attrib=NULL)
+  {
+    // overwrite object attributes
+    if (is_array($attrib))
+      $this->attrib = array_merge($this->attrib, $attrib);    
+
+    $this->attrib['type'] = $this->type;
+
+    if ($value && (string)$value==(string)$this->attrib['value'])
+      $this->attrib['checked'] = TRUE;
+    else
+      $this->attrib['checked'] = FALSE;
+
+    // return final tag
+    return sprintf(
+      '<%s%s />%s',
+      $this->_conv_case('input', 'tag'),
+      $this->create_attrib_string(),
+      ($this->newline ? "\n" : ""));
+  }
+}
+
+
+/**
+ * Builder for a <textarea> field
+ *
+ * @package HTML
+ */
+class textarea extends rcube_form_element
+  {
+
+  /**
+   * Constructor
+   * @param array Named tag attributes
+   */
+  function textarea($attrib=array())
+  {
+    $this->attrib = $attrib;
+
+    if ($attrib['newline'])
+      $this->newline = TRUE;
+  }
+  
+  /**
+   * Create HTML representation for this field
+   *
+   * @param string Field value
+   * @param array  Additional tag attributes
+   * @return string Final HTML code
+   */
+  function show($value='', $attrib=NULL)
+  {
+    // overwrite object attributes
+    if (is_array($attrib))
+      $this->attrib = array_merge($this->attrib, $attrib);
+    
+    // take value attribute as content
+    if ($value=='')
+      $value = $this->attrib['value'];
+    
+    // make shure we don't print the value attribute
+    if (isset($this->attrib['value']))
+      unset($this->attrib['value']);
+
+    if (!empty($value) && !isset($this->attrib['mce_editable']))
+      $value = Q($value, 'strict', FALSE);
+
+    // return final tag
+    return sprintf(
+      '<%s%s>%s</%s>%s',
+      $this->_conv_case('textarea', 'tag'),
+      $this->create_attrib_string(),
+      $value,
+      $this->_conv_case('textarea', 'tag'),
+      ($this->newline ? "\n" : ""));       
+  }
+}
+
+
+/**
+ * Builder for group of hidden form fields
+ *
+ * @package HTML
+ */
+class hiddenfield extends rcube_form_element
+{
+  var $fields_arr = array();
+  var $newline = TRUE;
+
+  /**
+   * Constructor
+   *
+   * @param array Named tag attributes
+   */
+  function hiddenfield($attrib=NULL)
+  {
+    if (is_array($attrib))
+      $this->add($attrib);
+  }
+
+  /**
+   * Add a hidden field to this instance
+   * @param array Named tag attributes
+   */
+  function add($attrib)
+  {
+    $this->fields_arr[] = $attrib;
+  }
+
+
+  /**
+   * Create HTML code for the hidden fields
+   *
+   * @return string Final HTML code
+   */
+  function show()
+  {
+    $out = '';
+    foreach ($this->fields_arr as $attrib)
+    {
+      $this->attrib = $attrib;
+      $this->attrib['type'] = 'hidden';
+      
+      $out .= sprintf(
+        '<%s%s />%s',
+        $this->_conv_case('input', 'tag'),
+        $this->create_attrib_string(),
+        ($this->newline ? "\n" : ""));
+    }
+
+    return $out;
+  }
+}
+
+
+/**
+ * Builder for HTML drop-down menus
+ * Syntax:<pre>
+ * // create instance. arguments are used to set attributes of select-tag
+ * $select = new select(array('name' => 'fieldname'));
+ *
+ * // add one option
+ * $select->add('Switzerland', 'CH');
+ *
+ * // add multiple options
+ * $select->add(array('Switzerland','Germany'), array('CH','DE'));
+ *
+ * // generate pulldown with selection 'Switzerland'  and return html-code
+ * // as second argument the same attributes available to instanciate can be used
+ * print $select->show('CH');
+ * </pre>
+ *
+ * @package HTML
+ */
+class select extends rcube_form_element
+{
+  var $options = array();
+
+  /**
+   * Constructor
+   *
+   * @param array Named tag attributes
+   */
+  function select($attrib=NULL)
+  {
+    if (is_array($attrib))
+      $this->attrib = $attrib;
+
+    if ($attrib['newline'])
+      $this->newline = TRUE;
+  }
+
+
+  /**
+   * Add one ore more menu options
+   *
+   * @param mixed Array with names or single option name
+   * @param mixed Array with values or single option value
+   */
+  function add($names, $values=NULL)
+  {
+    if (is_array($names))
+    {
+      foreach ($names as $i => $text)
+        $this->options[] = array('text' => $text, 'value' => (string)$values[$i]);
+    }
+    else
+      $this->options[] = array('text' => $names, 'value' => (string)$values);
+  }
+
+
+  /**
+   * Generate HTML code for this drop-down menu
+   *
+   * @param string Value of the selected option
+   * @param array Additional tag attributes
+   * @return string Final HTML code
+   */
+  function show($select=array(), $attrib=NULL)
+  {
+    $options_str = "\n";
+    $value_str = $this->_conv_case(' value="%s"', 'attrib');
+    
+    if (!is_array($select))
+      $select = array((string)$select);
+
+    foreach ($this->options as $option)
+    {
+      $selected = ((isset($option['value']) &&
+                    in_array($option['value'], $select, TRUE)) ||
+                   (in_array($option['text'], $select, TRUE))) ?
+        $this->_conv_case(' selected="selected"', 'attrib') : '';
+                   
+      $options_str .= sprintf("<%s%s%s>%s</%s>\n",
+                             $this->_conv_case('option', 'tag'),
+                             !empty($option['value']) ? sprintf($value_str, Q($option['value'])) : '',
+                             $selected, 
+                             Q($option['text'], 'strict', FALSE),
+                             $this->_conv_case('option', 'tag'));
+    }
+
+    // return final tag
+    return sprintf('<%s%s>%s</%s>%s',
+                   $this->_conv_case('select', 'tag'),
+                   $this->create_attrib_string(),
+                   $options_str,
+                   $this->_conv_case('select', 'tag'),
+                   ($this->newline ? "\n" : ""));    
+  }
+}
+
+
+?>