/fuel/modules/fuel/libraries/Form_builder.php
PHP | 4334 lines | 2895 code | 488 blank | 951 comment | 460 complexity | 7bde994c3a244e1146b6b31d7d67cea5 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
- /**
- * FUEL CMS
- * http://www.getfuelcms.com
- *
- * An open source Content Management System based on the
- * Codeigniter framework (http://codeigniter.com)
- *
- * @package FUEL CMS
- * @author David McReynolds @ Daylight Studio
- * @copyright Copyright (c) 2018, Daylight Studio LLC.
- * @license http://docs.getfuelcms.com/general/license
- * @link http://www.getfuelcms.com
- */
- // ------------------------------------------------------------------------
- /**
- * A form creation class
- *
- * The Form_builder class allows you to create forms by passing in configurable
- * array values. Each field has a base set of parameters that can be set
- * for it. Other fields have additional parameters you can pass to it
- * (e.g. the date field). This class works with the
- * <a href="[user_guide_url]libraries/my_model#func_form_fields">MY_Model form_fields</a>
- * method which returns table meta information regarding the fields of a
- * table.
- *
- * The <a href="[user_guide_url]libraries/form">Form.php</a> class is required if a
- * form object is not passed in the initialization process.
- *
- * Custom form fields can be configured in the <span class="file">fuel/application/config/custom_fields.php</span> file.
- *
- * <p class="important">Additional information about <a href="[user_guide_url]general/forms">creating forms using Form_builder can be found in the General Topics area</a>.
- *
- * @package FUEL CMS
- * @subpackage Libraries
- * @category Libraries
- * @author David McReynolds @ Daylight Studio
- * @link http://docs.getfuelcms.com/libraries/form_builder
- */
- class Form_builder {
- public $form; // form object used to create the form fields and associate errors with
- public $id = ''; // id to be used for the containing table or div
- public $css_class = 'form'; // css class to be used with the form
- public $form_attrs = 'method="post" action=""'; // form tag attributes
- public $label_colons = FALSE; // add colons to form labels?
- public $textarea_rows = 10; // number of rows for a textarea
- public $textarea_cols = 60; // number of columns for a textarea
- public $text_size_limit = 40; // text size for a text input
- public $submit_name = ''; // submit id and name values
- public $submit_value = 'Submit'; // submit value (what the button says)
- public $cancel_value = ''; // cancel value (what the button says)
- public $cancel_action = ''; // what the cancel button does
- public $reset_value = ''; // reset button value (what the button says)
- public $other_actions = ''; // additional actions to be displayed at the bottom of the form
- public $use_form_tag = TRUE; // include the form opening/closing tags in rendered output
- public $exclude = array(); // exclude these fields from the form
- public $hidden = array('id'); // hidden fields
- public $readonly = array(); // readonly fields
- public $disabled = array(); // disabled fields
- public $displayonly = array(); // for display purposes only
- public $date_format = 'm/d/Y'; // date format for date type fields
- public $section_tag = 'h3'; // section html tag
- public $copy_tag = 'p'; // copy html tag
- public $fieldset = ''; // field set name
- public $name_array = ''; // put the form fields into an array for namespacing
- public $name_prefix = ''; // prefix the form fields as an alternatie to an array for namespacing
- public $class_type_prefix = 'field_type_'; // the CSS class prefix to associate with each field type
- public $names_id_match = TRUE; // determines if the names and ids match if using a name_prefix or name_array
- public $key_check = ''; // the keycheck value used for forms that create session unique session variables to prevent spamming
- public $key_check_name = ''; // the keycheck form name used for forms that create session unique session variables to prevent spamming
- public $tooltip_format = '<span title="{?}" class="tooltip">[?]</span>'; // tooltip formatting string
- public $tooltip_labels = TRUE; // use tooltip labels?
- public $single_select_mode = 'auto'; // auto will use enum if 2 or less and a single select if greater than 2. Other values are enum or select
- public $multi_select_mode = 'auto'; // auto will use a series of checkboxes if 5 or less and a multiple select if greater than 5. Other values are multi or checkbox
- public $boolean_mode = 'checkbox'; // boolean mode can be checkbox or enum (which will display radio inputs)
- public $display_errors_func = 'display_errors'; // the function used to generate errors... usually display_errors is the name
- public $display_errors = FALSE; // displays errors at the top of the form if TRUE
- public $question_keys = array('how', 'do', 'when', 'what', 'why', 'where', 'how', 'is', 'which', 'did', 'any','would', 'should', 'could'); // adds question marks to the label if has these words in the label
- public $show_required = TRUE; // show the required fields text at the bottom of the form
- public $required_indicator = '*'; // indicator for a required field
- public $required_text = '<span class="required">{required_indicator}</span> required fields'; // the required field text
- public $label_layout = 'left'; // label layout... can be left or top
- public $has_required = FALSE; // does the form have required fields
- public $render_format = 'table'; // default render format
- public $row_id_prefix = ''; // the row id prefix
- public $lang_prefix = 'form_label_'; // language prefix to be applied before a label
- public $custom_fields = array(); // custom fields
- public $auto_execute_js = TRUE; // automatically execute the javascript for the form
- public $html_prepend = ''; // prepended HTML to the form HINT: Can include JS script tags
- public $html_append = ''; // appended HTML to the form HINT: Can include JS script tags
- public $representatives = array(); // an array of fields that have arrays or regular expression values to match against different field types (e.g. 'number'=>'bigint|smallint|tinyint|int')
- public $js; // javascript files to associate with the form fields to be executed once per render
- public $css; // CSS files to associate with the form fields to be executed once per render
- public $no_css_js = FALSE; // used to not display the CSS and JS when rendering to prevent issues with nested forms and post_processing
- public $template = ''; // the html template view file to use for rendering the form when using "render_template"
- public $is_pre_processing = FALSE; // flag set when form builder is pre processing fields
- public $is_post_processing = FALSE; // flag set when form builder is post processing fields
- protected $_html; // html string
- protected $_fields; // fields to be used for the form
- protected $_values; // an array of the field values
- protected $_cached; // cached parameters
- protected $_pre_process; // pre_process functions
- protected $_post_process; // post_process functions
- protected $_rendering = FALSE; // used to prevent infinite loops when calling form_builder reference from within a custom form field
- protected $_rendered_field_types = array(); // holds all the fields types rendered
- protected $_is_nested = FALSE; // used to detect nested fields
- protected $CI;
-
- // --------------------------------------------------------------------
-
- /**
- * Constructor
- *
- * Accepts an associative array as input, containing preferences (optional)
- *
- * @access public
- * @param array config preferences
- * @return void
- */
- public function __construct($params = array())
- {
- $this->CI =& get_instance();
- $this->initialize($params);
- }
- // --------------------------------------------------------------------
- /**
- * Initialize preferences
- *
- * @access public
- * @param array
- * @return void
- */
- public function initialize($params = array())
- {
-
- // clear out any data before initializing
- $this->reset();
- $this->set_params($params);
-
- // setup custom fields
- if (!empty($this->custom_fields))
- {
- $this->load_custom_fields($this->custom_fields);
- }
-
- // create form object if not in initialization params
- if (is_null($this->form))
- {
- $this->CI->load->library('form');
- $this->CI->load->library('encryption');
- $this->form = new Form();
-
- // load localization helper if not already
- if (!function_exists('lang'))
- {
- $this->CI->load->helper('language');
- }
- // CSRF protections
- if ($this->CI->config->item('csrf_protection') === TRUE AND empty($this->key_check))
- {
- $this->CI->security->csrf_set_cookie(); // need to set it again here just to be sure ... on initial page loads this may not be there
- $this->key_check = $this->CI->security->get_csrf_hash();
- $this->key_check_name = $this->CI->security->get_csrf_token_name();
- }
- }
- }
-
- // --------------------------------------------------------------------
- /**
- * Set object parameters
- *
- * @access public
- * @param array
- * @return void
- */
- public function set_params($params)
- {
- if (is_array($params) AND count($params) > 0)
- {
- foreach ($params as $key => $val)
- {
- if (isset($this->$key))
- {
- $method = 'set_'.$key;
- if (method_exists($this, $method))
- {
- $this->$method($val);
- }
- else
- {
- $this->$key = $val;
- }
- }
- }
- }
- }
-
- // --------------------------------------------------------------------
- /**
- * Same as reset
- *
- * @access public
- * @return void
- */
- public function clear()
- {
- $this->reset();
- }
-
- // --------------------------------------------------------------------
- /**
- * Clear class values
- *
- * @access public
- * @return void
- */
- public function reset()
- {
- $this->_fields = array();
- $this->_values = array();
- $this->_html = '';
- $this->js = array();
- $this->css = array();
- $this->_pre_process = array();
- $this->_post_process = array();
- $this->key_check = NULL;
- $this->key_check_name = NULL;
- }
-
- // --------------------------------------------------------------------
- /**
- * Set the fields for the form
- *
- * Check the normalize_params method for possible values
- *
- * @access public
- * @param array
- * @return void
- */
- public function set_fields($fields)
- {
- $i = 1;
- // clear it out first
- $this->_fields = array();
- foreach ($fields as $key => $val)
- {
- $this->add_field($key, $val, $i);
- $i++;
- }
- }
-
- // --------------------------------------------------------------------
- /**
- * Set the fields for the form
- *
- * Check the normalize_params method for possible values
- *
- * @access public
- * @param string The key to associate with the field
- * @param array The field parameters
- * @param int The order value of the parameter
- * @return void
- */
- public function add_field($key, $val, $order = NULL)
- {
- // __FORM_BUILDER__ allows you to set properties on the class
- // convenient for models setting values
- if (strtoupper($key) == '__FORM_BUILDER__')
- {
- $this->set_params($val);
- }
- else
- {
- if (is_string($val))
- {
- $this->_fields[$key] = array('name' => $key, 'value' => $val);
- }
- else
- {
- $this->_fields[$key] = $val;
- }
-
- // set the key value
- if (empty($this->_fields[$key]['key']))
- {
- $this->_fields[$key]['key'] = $key;
- }
-
- if (empty($val['name']))
- {
- $this->_fields[$key]['name'] = $key;
- }
-
- // set the order of the field
- if (isset($order) AND empty($val['order']))
- {
- $this->_fields[$key]['order'] = $order;
- }
- if (empty($this->_fields[$key]['order']))
- {
- $this->_fields[$key]['order'] = count($this->_fields);
- }
- }
- }
-
- // --------------------------------------------------------------------
- /**
- * Removes a field before rendering
- *
- * @access public
- * @param string
- * @return void
- */
- public function remove_field($key)
- {
- if (is_array($key))
- {
- foreach($key as $k)
- {
- $this->remove_field($k);
- }
- }
- else
- {
- if (isset($this->_fields[$key]))
- {
- unset($this->_fields[$key]);
- }
- }
- }
-
- // --------------------------------------------------------------------
- /**
- * Returns the fields for the form. If a key value is passed, it will only return that one field
- *
- * @access public
- * @param string field key
- * @return array
- */
- public function fields($key = NULL)
- {
- if (!empty($key))
- {
- if (isset($this->_fields[$key]))
- {
- return $this->_fields[$key];
- }
- return FALSE;
- }
- return $this->_fields;
- }
-
- // --------------------------------------------------------------------
- /**
- * Returns the values of the form fields. If a key value is passed, it will only return that one value
- *
- * @access public
- * @param string field key
- * @return array
- */
- public function values($key = NULL)
- {
- if (!empty($key))
- {
- if (isset($this->_values[$key]))
- {
- return $this->_values[$key];
- }
- return FALSE;
- }
- return $this->_values;
- }
- // --------------------------------------------------------------------
- /**
- * Sets the value attribute for the fields of the form
- *
- * Often times this is database or post data
- *
- * @access public
- * @param array
- * @return void
- */
- public function set_field_values($values)
- {
- if (!is_array($values))
- {
- return FALSE;
- }
- // set the values in a different array to keep track of them separate from the form field...
- // this is in case the form field gets removed
- $this->_values = $values;
- // set values for fields that are arrays
- foreach($values as $key => $val)
- {
- if (is_array($values[$key]))
- {
- foreach($values[$key] as $k => $v)
- {
- $values[$key.'['.$k.']'] = $v;
- }
- }
- }
-
- if (!empty($this->_fields))
- {
- foreach($this->_fields as $key => $val)
- {
- if (isset($values[$key]))
- {
- if (empty($val['type']))
- {
- $is_checkbox = FALSE;
- }
-
- // don't set the values of these form types'
- else if ($val['type'] == 'submit' OR $val['type'] == 'button')
- {
- continue;
- }
- else
- {
- $is_checkbox = (($val['type'] == 'checkbox') OR ($val['type'] == 'boolean' AND $this->boolean_mode == 'checkbox'));
- }
- if (!$is_checkbox)
- {
- $this->_fields[$key]['value'] = $values[$key];
- }
-
- if (!empty($val['type']))
- {
- if ($is_checkbox)
- {
- $this->_fields[$key]['checked'] = ((isset($this->_fields[$key]['value']) AND $values[$key] == $this->_fields[$key]['value']) OR
- $values[$key] === TRUE OR
- $values[$key] === 1 OR
- $values[$key] === 'y' OR
- $values[$key] === 'yes') ? TRUE : FALSE;
- }
- }
- }
- }
- }
- }
- // --------------------------------------------------------------------
- /**
- * Render the HTML output
- *
- * @access public
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @param string 'divs or table
- * @param string 'a view path (only used for the template)
- * @return string
- */
- public function render($fields = NULL, $render_format = NULL, $template = NULL)
- {
- if (empty($render_format)) $render_format = $this->render_format;
- if ($render_format == 'divs')
- {
- return $this->render_divs($fields);
- }
- else if ($render_format == 'template')
- {
- if (empty($template))
- {
- $template = $this->template;
- }
- return $this->render_template($template, $fields);
- }
- else
- {
- return $this->render_table($fields);
- }
- }
- // --------------------------------------------------------------------
- /**
- * Render the HTML output
- *
- * @access public
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return string
- */
- public function render_divs($fields = NULL)
- {
- if (!empty($fields)) $this->set_fields($fields);
- // reorder
- $this->set_field_order();
-
- // pre process field values
- $this->pre_process_field_values();
-
- $this->_html = $this->html_prepend;
- $str = '';
- $begin_str = '';
- $end_str = '';
- if ($this->display_errors)
- {
- $func = $this->display_errors_func;
- if (function_exists($func))
- {
- $str .= $func();
- }
- }
- $colspan = ($this->label_layout == 'top') ? '1' : '2';
-
- $first = $this->_find_first_renderable_field();;
- $is_fieldset_first = FALSE;
- if ($first['type'] != 'fieldset')
- {
- $str .= $this->_open_div();
- }
- else
- {
- $is_fieldset_first = TRUE;
- }
- $fieldset_on = FALSE;
-
- foreach($this->_fields as $key => $val)
- {
- $val = $this->normalize_params($val);
-
- if ($val['type'] == 'fieldset' OR !empty($val['fieldset']))
- {
- // don't close the table if it isn't opened earlier
- if ($is_fieldset_first == FALSE)
- {
- $str .= $this->_close_div();
- }
- $is_fieldset_first = FALSE;
- // close any existing field sets
-
- if ($fieldset_on)
- {
- $fieldset_val['open'] = FALSE;
- $str .= $this->create_fieldset($fieldset_val);
- }
- $fieldset_val['open'] = TRUE;
- if (!empty($val['fieldset']))
- {
- $fieldset_val['value'] = $val['fieldset'];
- }
- else
- {
- $fieldset_val = $val;
- }
- $str .= $this->create_fieldset($fieldset_val);
- $str .= $this->_open_div();
- $fieldset_on = TRUE;
-
- // continue if the fieldset is part of the field values and not the "type"
- if (empty($val['fieldset']))
- {
- continue;
- }
- }
-
- if ($val['type'] == 'section')
- {
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<div class=\"section\">".$this->create_section($val)."</div>\n";
- $str .= "</div>\n";
- continue;
- }
- else if (!empty($val['section']))
- {
- $str .= "<div class=\"section\"><".$this->section_tag.">".$val['section']."</".$this->section_tag."></div>\n";
- }
-
- if ($val['type'] == 'copy')
- {
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<div class=\"copy\">".$this->create_copy($val)."</div>\n";
- $str .= "</div>\n";
- continue;
- }
- else if (!empty($val['copy']))
- {
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<div class=\"copy\"><".$this->copy_tag.">".$val['copy']."</".$this->copy_tag."></div>\n";
- $str .= "</div>\n";
- }
-
- if (!empty($val['custom']))
- {
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<span class=\"label\">";
- $str .= $this->create_label($val, TRUE);
- $str .= "</span>";
- $str .= "<span".$this->_open_field_attrs($val).">";
- $str .= $val['custom'];
- $str .= "</span>";
- $str .= "</div>\n";
- }
- else if (in_array($val['name'], $this->hidden) OR $val['type'] == 'hidden')
- {
- $end_str .= $this->create_hidden($val);
- }
- else if ((is_array($val['name']) AND in_array($val['name'], $this->displayonly)) OR $val['displayonly'] OR (is_string($this->displayonly) AND strtolower($this->displayonly) == 'all'))
- {
- if (isset($val['displayonly']) AND !is_bool($val['displayonly']))
- {
- $display_value = $val['displayonly'];
- }
- else
- {
- $display_value = (is_array($val['value'])) ? print_r($val['value'], TRUE) : $val['value'];
- }
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<span class=\"label\">";
- $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label'];
- $str .= "</span>";
- $str .= "<span".$this->_open_field_attrs($val)."><span class=\"displayonly noclone\">";
- $str .= $val['before_html'].$display_value.$val['after_html'];
- $str .= "</span></span>";
- $str .= "</div>\n";
- }
- else if (!in_array($val['name'], $this->exclude))
- {
- $str .= "<div".$this->_open_row_attrs($val).'>';
- $str .= "<span class=\"label\">";
- $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label'];
- $str .= "</span>";
- $str .= "<span".$this->_open_field_attrs($val).">";
- $str .= $this->create_field($val, FALSE);
- $str .= "</span>";
- $str .= "</div>\n";
- }
- }
- // close any open fieldsets
- if ($fieldset_on)
- {
- $str .= $this->_close_div();
- $val['open'] = FALSE;
- $str .= $this->create_fieldset($val);
- $str .= $this->_open_div();
- }
-
- $actions = $this->_render_actions();
- if (!empty($actions))
- {
- $str .= "<div class=\"actions\"><div class=\"actions_inner\">";
- $str .= $actions;
- $str .= "</div></div>\n";
- }
-
- if ($this->has_required AND ($this->show_required AND strtolower($this->show_required) != 'top'))
- {
- $str .= "<div class=\"required\">";
- $str .= str_replace('{required_indicator}', $this->required_indicator, $this->required_text);
- $str .= "</div>\n";
- }
- $str .= "</div>\n";
-
- $str = $begin_str . $str . $end_str;
- $this->_close_form($str);
- return $this->_html;
- }
- // --------------------------------------------------------------------
- /**
- * Render the HTML output
- *
- * @access public
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return string
- */
- public function render_table($fields = NULL)
- {
- if (!empty($fields)) $this->set_fields($fields);
- // reorder
- $this->set_field_order();
-
- // pre process field values
- $this->pre_process_field_values();
-
- $this->_html = $this->html_prepend;
- $str = '';
- $begin_str = '';
- $end_str = '';
- if ($this->display_errors)
- {
- $func = $this->display_errors_func;
- if (function_exists($func))
- {
- $str .= $func();
- }
- }
- $colspan = ($this->label_layout == 'top') ? '1' : '2';
- $first = $this->_find_first_renderable_field();
- $is_fieldset_first = FALSE;
- if ($first['type'] != 'fieldset')
- {
- $str .= $this->_open_table();
- }
- else
- {
- $is_fieldset_first = TRUE;
- }
- $fieldset_on = FALSE;
- foreach($this->_fields as $key => $val)
- {
- $val = $this->normalize_params($val);
-
- if ($val['type'] == 'fieldset' OR !empty($val['fieldset']))
- {
- // don't close the table if it isn't opened earlier
- if ($is_fieldset_first == FALSE)
- {
- $str .= $this->_close_table();
- }
- $is_fieldset_first = FALSE;
- // close any existing field sets
- if ($fieldset_on)
- {
- $fieldset_val['open'] = FALSE;
- $str .= $this->create_fieldset($fieldset_val);
- }
- $fieldset_val['open'] = TRUE;
- if (!empty($val['fieldset']))
- {
- $fieldset_val['value'] = $val['fieldset'];
- }
- else
- {
- $fieldset_val = $val;
- }
- $str .= $this->create_fieldset($fieldset_val);
- $str .= $this->_open_table();
- $fieldset_on = TRUE;
-
- // continue if the fieldset is part of the field values and not the "type"
- if (empty($val['fieldset']))
- {
- continue;
- }
- }
-
- if ($val['type'] == 'section')
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"section\">".$this->create_section($val)."</td>\n</tr>\n";
- continue;
- }
- else if (!empty($val['section']))
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"section\"><".$this->section_tag.">".$val['section']."</".$this->section_tag."></td>\n</tr>\n";
- }
-
- if ($val['type'] == 'copy')
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"copy\">".$this->create_copy($val)."</td></tr>\n";
- continue;
- }
- else if (!empty($val['copy']))
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"copy\"><".$this->copy_tag.">".$val['copy']."</".$this->copy_tag."></td>\n</tr>\n";
- }
-
- if (!empty($val['custom']))
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t";
- if ($val['display_label'] !== FALSE)
- {
- $str .= "<td class=\"label\">";
- if ($this->label_layout != 'top')
- {
- $str .= $this->create_label($val, TRUE);
- $str .= "</td>\n\t<td".$this->_open_field_attrs($val).">".$val['custom']."</td>\n</tr>\n";
- }
- else
- {
- $str .= $this->create_label($val, TRUE)."</td></tr>\n";
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$val['custom']."</td>\n</tr>\n";
- }
- }
- else
- {
- $str .= "<td class=\"value\" colspan=\"2\">".$val['custom']."</td>\n</tr>\n";
- }
- }
- else if (in_array($val['name'], $this->hidden) OR $val['type'] == 'hidden')
- {
- $end_str .= $this->create_hidden($val);
- }
- else if ((is_array($val['name']) AND in_array($val['name'], $this->displayonly)) OR $val['displayonly'] OR (is_string($this->displayonly) AND strtolower($this->displayonly) == 'all') OR $this->displayonly === TRUE)
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td class=\"label\">";
- if (isset($val['displayonly']) AND !is_bool($val['displayonly']))
- {
- $display_value = $val['displayonly'];
- }
- else
- {
- $display_value = (is_array($val['value'])) ? print_r($val['value'], TRUE) : $val['value'];
- }
-
- if ($this->label_layout != 'top')
- {
- $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label'];
- $str .= "</td>\n\t<td".$this->_open_field_attrs($val)."><span class=\"displayonly noclone\">".$val['before_html'].$display_value.$val['after_html']."\n".$this->create_hidden($val)."</span></td>\n</tr>\n";
- }
- else
- {
- $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label']."</td></tr>\n";
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$val['before_html'].$display_value.$val['after_html']."</td>\n</tr>\n";
- }
- }
- else if (!in_array($val['name'], $this->exclude))
- {
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t";
- if ($val['display_label'] !== FALSE)
- {
- $str .= "<td class=\"label\">";
- if ($this->label_layout != 'top')
- {
- $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label'];
- $str .= "</td>\n\t<td".$this->_open_field_attrs($val).">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
- }
- else
- {
- $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label']."</td></tr>\n";
- $str .= "<tr".$this->_open_row_attrs($val);
- $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
- }
- }
- else
- {
- $str .= "<td class=\"value\" colspan=\"2\">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
- }
- }
- }
- // close any open fieldsets
- if ($fieldset_on)
- {
- $str .= $this->_close_table();
- $val['open'] = FALSE;
- $str .= $this->create_fieldset($val);
- $str .= $this->_open_table();
- }
- $actions = $this->_render_actions();
- if (!empty($actions))
- {
- if ($this->label_layout != 'top')
- {
- $str .= "<tr";
- if (!empty($this->row_id_prefix))
- {
- $str .= ' id="'.$this->row_id_prefix.'actions"';
- }
- $str .= ">\n\t<td></td>\n\t<td class=\"actions\"><div class=\"actions_inner\">";
- }
- else
- {
- $str .= "<tr>\n\t<td class=\"actions\"><div class=\"actions\">";
- }
- $str .= $actions;
- $str .= "</div></td>\n</tr>\n";
- }
- if ($this->has_required AND ($this->show_required AND strtolower($this->show_required) != 'top'))
- {
- $str .= "<tr>\n\t<td colspan=\"".$colspan."\" class=\"required\">";
- $str .= str_replace('{required_indicator}', $this->required_indicator, $this->required_text);
- $str .= "</td>\n</tr>\n";
- }
- $str .= $this->_close_table();
- $str = $begin_str . $str . $end_str;
- $this->_close_form($str);
- return $this->_html;
- }
- // --------------------------------------------------------------------
- /**
- * Render the HTML output using a specified template.
- *
- * Will provide an array of form fields that can be parsed like so {my_field}
- *
- * @access public
- * @param string the name of the template view file to use
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return string
- */
- public function render_template($template, $fields = NULL, $parse = TRUE)
- {
- if (!empty($fields)) $this->set_fields($fields);
- // reorder
- $this->set_field_order();
-
- // pre process field values
- $this->pre_process_field_values();
-
- $this->_html = $this->html_prepend;
- $errors = NULL;
- if ($this->display_errors)
- {
- $func = $this->display_errors_func;
- if (function_exists($func))
- {
- $errors = $func();
- }
- }
-
- $fields = array();
- foreach($this->_fields as $key => $field)
- {
- $fields[$key]['field'] = $this->create_field($field);
- $fields[$key]['label'] = $this->create_label($field);
- }
-
- $vars['fields'] = $fields;
- $vars['errors'] = $errors;
- if (is_array($template))
- {
- $module = key($template);
- $view = current($template);
- $str = $this->CI->load->module_view($module, $view, $vars, TRUE);
- }
- else
- {
- $str = $this->CI->load->view($template, $vars, TRUE);
- }
-
- if ($parse === TRUE)
- {
- $this->CI->load->library('parser');
- $str = parse_template_syntax($str, $vars, 'ci');
- }
- $actions = $this->_render_actions();
- if (!empty($actions))
- {
- $str .= '<div class="actions">';
- $str .= $actions;
- $str .= "</div>";
- }
- $this->_html = $this->_close_form($str);
-
- return $this->_html;
- }
- // --------------------------------------------------------------------
- /**
- * Finds the first field that is not hidden and renderable
- *
- * @access protected
- * @return array
- */
- protected function _find_first_renderable_field()
- {
- foreach($this->_fields as $key => $field)
- {
- $invalid_types = array('hidden');
- if ( ! in_array($field['type'], $invalid_types) AND ! in_array($key, $this->hidden))
- {
- return $field;
- }
- }
- return reset($this->_fields);
- }
- // --------------------------------------------------------------------
- /**
- * Creates the opening div element that contains the form fields
- *
- * @access protected
- * @return string
- */
- protected function _open_div()
- {
- $str = '';
- $str .= "<div>\n";
- return $str;
- }
- // --------------------------------------------------------------------
- /**
- * Creates the opening table element
- *
- * @access protected
- * @return string
- */
- protected function _open_table()
- {
- $str = '';
- $str .= "<table>\n";
- $str .= "<colgroup>\n";
- $str .= "<col class=\"label_column\">\n";
- $str .= "<col class=\"field_column\">\n";
- $str .= "</colgroup>\n";
- $str .= "<tbody>\n";
- return $str;
- }
-
- // --------------------------------------------------------------------
- /**
- * Creates the closing element
- *
- * @access protected
- * @return string
- */
- protected function _close_div()
- {
- $str = '';
- $str .= "</div>\n";
- return $str;
- }
- // --------------------------------------------------------------------
- /**
- * Creates the closing table elements
- *
- * @access protected
- * @return string
- */
- protected function _close_table()
- {
- $str = '';
- $str .= "</tbody>\n";
- $str .= "</table>\n";
- return $str;
- }
- // --------------------------------------------------------------------
- /**
- * Creates the opening row TR or div with attrs
- *
- * @access protected
- * @param array fields parameters
- * @return string
- */
- protected function _open_row_attrs($val)
- {
- $str = '';
- if (!empty($this->row_id_prefix))
- {
- $str .= ' id="'.$this->row_id_prefix.Form::create_id($val['name']).'"';
- }
- if (!empty($val['row_class']))
- {
- $str .= ' class="'.$val['row_class'].'"';
- }
- if (!empty($val['row_style']))
- {
- $str .= ' style="'.$val['row_style'].'"';
- }
- return $str;
- }
- // --------------------------------------------------------------------
- /**
- * Creates the opening field td.value or div.value with attrs
- *
- * @access protected
- * @param array fields parameters
- * @return string
- */
- protected function _open_field_attrs($val)
- {
- $str = ' class="field';
- if (!empty($val['field_class']))
- {
- $str .= ' '.$val['field_class'];
- }
- $str .= '"';
- if (!empty($val['field_style']))
- {
- $str .= ' style="'.$val['field_style'].'"';
- }
- return $str;
- }
- // --------------------------------------------------------------------
- /**
- * Outputs the actions for the form
- *
- * @access protected
- * @param string
- * @return string
- */
- protected function _render_actions()
- {
- $str = '';
- if ( ! empty($this->reset_value))
- {
- if (preg_match("/^</i", $this->reset_value))
- {
- $str .= $this->reset_value;
- }
- else
- {
- $str .= $this->form->reset($this->reset_value, '', array('class' => 'reset'));
- }
- }
- if ( ! empty($this->cancel_value))
- {
- if (preg_match("/^</i", $this->cancel_value))
- {
- $str .= $this->cancel_value;
- }
- else
- {
- $cancel_attrs = array('class' => 'cancel');
- if ( ! empty($this->cancel_action))
- {
- $cancel_attrs['onclick'] = $this->cancel_action;
- }
- $str .= $this->form->button($this->cancel_value, '', $cancel_attrs);
- }
- }
- if (!empty($this->submit_value) AND $this->displayonly != 'all')
- {
- // check if the string has a tag and if so just pump in the string
- if (preg_match("/^</i", $this->submit_value))
- {
- $str .= $this->submit_value;
- }
- else
- {
- $submit_btn = (preg_match("/(.)+\\.(jp(e){0,1}g$|gif$|png$)/i", $this->submit_value)) ? 'image' : 'submit';
- $submit_name = (empty($this->submit_name)) ? url_title($this->submit_value, '_') : $this->submit_name;
- if (empty($submit_name)) $submit_name = 'submit_form';
- $submit_name = (!empty($this->name_prefix) AND $this->names_id_match) ? $this->name_prefix.'--'.$submit_name : $submit_name;
- $submit_id = $submit_name;
- // if (!empty($this->name_prefix))
- // {
- // $submit_id = $this->name_prefix.'--'.$submit_id;
- // }
- $str .= $this->form->$submit_btn($this->submit_value, $submit_name, array('class' => 'submit', 'id' => $submit_id));
- }
- }
- if (!empty($this->other_actions)) $str .= $this->other_actions;
- return $str;
- }
-
- // --------------------------------------------------------------------
- /**
- * Outputs the last part of the form rendering for both a table and div
- *
- * @access protected
- * @param string
- * @return string
- */
- protected function _close_form($str)
- {
- if ($this->use_form_tag)
- {
- $this->_html .= $this->form->open($this->form_attrs);
- }
- if (!empty($this->fieldset))
- {
- $this->_html .= $this->form->fieldset_open($this->fieldset);
- }
-
- // wrapper div to apply ID
- $wrapper_open_str = "<div class=\"".$this->css_class."\"";
- if (empty($this->id))
- {
- $this->id = $this->id();
- }
- $wrapper_open_str .= ' id="'.$this->id.'"';
- $wrapper_open_str .= ">\n";
-
- $wrapper_close_str = "</div>";
-
- // apply any CSS first
- foreach($this->css as $css)
- {
- $this->_html .= $this->_apply_asset_files('css', $css);
- }
- $this->_html .= $wrapper_open_str.$str.$wrapper_close_str;
-
- if (!empty($this->key_check))
- {
- $this->_html .= $this->create_hidden(array('name' => $this->key_check_name, 'value' => $this->key_check));
- }
- if (!empty($this->fieldset))
- {
- $this->_html .= $this->form->fieldset_close();
- }
-
- if ($this->use_form_tag)
- {
- $this->_html .= $this->form->close('', FALSE); // we set the token above just in case form tags are turned off
- }
- $this->_html .= $this->_render_js();
- $this->_html .= $this->html_append;
- return $this->_html;
- }
-
- // --------------------------------------------------------------------
- /**
- * Normalize the fields so that the other methods can expect certain field attributes
- *
- * @access protected
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return array
- */
- protected function _default($val)
- {
- if (is_object($val)) $val = get_object_vars($val);
-
- $defaults = array(
- 'key' => '', // a unique identifier for the field. By default, it will be the the same as the ID. This parameter is used mostly for post processing of a field
- 'id' => '', // the ID attribute of the field. This value will be auto generated if not provided. Set to FALSE if you don't want an ID value
- 'name' => '', // the name attribute of the field
- 'type' => '', // the type attribute of the field (e.g. text, select, password, etc.)
- 'default' => '', // the default value of the field
- 'max_length' => 0, // the maxlength parameter to associate with the field
- 'comment' => '', // a comment to associate with the field's label
- 'label' => '', // the label to associate with the field
- 'before_label' => '', // for HTML before the label
- 'after_label' => '', // for HTML after the label
- 'required' => FALSE, // puts a required flag next to field label
- 'size' => '', // the size attribute of the field
- 'class' => '', // the CSS class attribute to associate with the field
- 'style' => '', // inline style
- 'value' => '', // the value of the field
- 'readonly' => '', // sets readonly attribute on field
- 'disabled' => '', // sets disabled attribute on the field
- 'tabindex' => '', // adds the tab index attribute to a field
- 'label_colons' => NULL, // whether to display the label colons
- 'display_label' => TRUE, // whether to display the label
- 'order' => NULL, // the display order value to associate with the field
- 'before_html' => '', // for HTML before the field
- 'after_html' => '', // for HTML after the field
- 'displayonly' => FALSE, // only displays the value (no field)
- 'pre_process' => NULL, // a pre process function
- 'post_process' => NULL, // a post process function run on post
- 'js' => '', // js file or script using <script> tag
- 'css' => '', // css to associate with the field
- 'represents' => '', // specifies what other types of fields that this field should represent
- 'ignore_representative' => FALSE, // ignores any representative
- 'data' => array(), // data attributes
- 'title' => NULL, // the title attribute
- 'attributes' => '', // a generic string value of attributes for the form field (e.g. 'class="myclass"')
- '__DEFAULTS__' => TRUE // set so that we no that the array has been processed and we can check it so it won't process it again
- );
-
- $params = array_merge($defaults, $val);
-
- if (empty($params['orig_name'])) $params['orig_name'] = $params['name']; // for labels in case the name_array is used
- if (empty($params['key']))
- {
- $params['key'] = Form::create_id($params['orig_name']);
- }
- if (!isset($val['value']) AND ($params['type'] != 'checkbox' AND !($params['type'] == 'boolean' AND $this->boolean_mode == 'checkbox')))
- {
- $params['value'] = $params['default'];
- }
-
- if (!isset($params['label_colons']))
- {
- $params['label_colons'] = $this->label_colons;
- }
-
- if (!empty($val['name']))
- {
- if ((is_array($this->readonly) AND in_array($val['name'], $this->readonly)) OR (is_string($this->readonly) AND strtolower($this->readonly) == 'all'))
- {
- $params['readonly'] = 'readonly';
- }
- if ((is_array($this->disabled) AND in_array($val['name'], $this->disabled)) OR (is_string($this->disabled) AND strtolower($this->disabled) == 'all'))
- {
- $params['disabled'] = 'disabled';
- }
- }
- if (!empty($this->name_array) AND strpos($params['name'], '[') === FALSE)
- {
- if (!$this->names_id_match)
- {
- if ($params['id'] !== FALSE)
- {
- $params['id'] = $this->name_array.'['.$params['orig_name'].']';
- }
- $params['name'] = $params['orig_name'];
- }
- else
- {
- if ($this->key_check_name != $params['orig_name'])
- {
- $params['name'] = $this->name_array.'['.$params['orig_name'].']';
- }
- else
- {
- $params['name'] = $params['orig_name'];
- }
- }
- if (in_array($params['orig_name'], $this->hidden) AND !in_array($params['name'], $this->hidden)) $this->hidden[] = $params['name'];
- }
- if (!empty($this->name_prefix))
- {
- if (!$this->names_id_match)
- {
- if ($params['id'] !== FALSE)
- {
- $params['id'] = $this->name_prefix.'--'.$params['orig_name']; // used double hyphen so easier to explode
- }
- $params['name'] = $params['orig_name'];
- }
- else
- {
- if ($this->key_check_name != $params['orig_name'])
- {
- $params['name'] = $this->name_prefix.'--'.$params['orig_name'];
- }
- else
- {
- $params['name'] = $params['orig_name'];
- }
- }
-
- if (in_array($params['orig_name'], $this->hidden) AND !in_array($params['name'], $this->hidden)) $this->hidden[] = $params['name'];
- }
- // grab options from a model if a model is specified
- if (!empty($params['model']))
- {
- $model_params = (!empty($params['model_params'])) ? $params['model_params'] : array();
- $params['options'] = $this->options_from_model($params['model'], $model_params);
- }
- if ($params['type'] == 'enum' OR $params['type'] == 'select')
- {
- if (!isset($params['options']))
- {
- $params['options'] = array();
- }
- if ((empty($params['options']) AND is_array($params['options'])) AND is_array($params['max_length']) AND !empty($params['max_length']))
- {
- $params['options'] = $params['max_length'];
- }
- if (!empty($params['hide_if_one']) AND count($params['options']) <= 1)
- {
- $params['type'] = 'hidden';
- $params['display_label'] = FALSE;
- }
- }
-
- // fix common errors
- if (!empty($params['maxlength']) AND empty($params['max_length']))
- {
- $params['max_length'] = $params['maxlength'];
- unset($params['maxlength']);
- }
-
- // take out javascript so we execute it only once per render
- if (!empty($params['js']))
- {
- $this->add_js($params['js']);
- }
- // take out css so we execute it only once per render
- if (!empty($params['css']))
- {
- $this->add_css($params['css']);
- }
-
- // says whether this field can represent other field types
- if (!empty($params['represents']))
- {
- $this->representatives[$params['type']] = $params['represents'];
- }
-
- // set the field type CSS class
- $type = (!empty($params['type'])) ? $params['type'] : 'text';
- $field_class = $this->class_type_prefix.$type;
- $params['class'] = (!empty($params['class']) AND strpos($params['class'], $field_class) === FALSE) ? $field_class.' '.$params['class'] : $params['class'];
- $this->_cached[$params['name']] = $params;
- return $params;
- }
- // --------------------------------------------------------------------
- /**
- * Returns the id for a form
- *
- * @access public
- * @return string
- */
- public function id()
- {
- if (empty($this->id))
- {
- $this->id = uniqid('form_');
- }
- return $this->id;
- }
-
- // --------------------------------------------------------------------
- /**
- * Get the default values for any field
- *
- * @access public
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return array
- */
- public function normalize_params($val, $defaults = array())
- {
- if ($val == '')
- {
- $val = array();
- }
- // check to see if the array is already normalized
- if (!$this->_has_defaults($val))
- {
- $val = $this->_default($val);
- }
- // set up defaults
- $params = array_merge($defaults, $val);
-
- return $params;
- }
- // --------------------------------------------------------------------
- /**
- * Renders the custom field
- *
- * @access protected
- * @param array fields values... will overwrite anything done with the set_fields method previously
- * @return array
- */
- protected function _render_custom_field($params)
- {
- $field = FALSE;
- if (is_array($params) AND isset($this->custom_fields[$params['type']]))
- {
- $func = $this->custom_fields[$params['type']];
- if (is_a($func, 'Form_builder_field'))
- {
- // give custom fields a reference to the current object
- $params['instance'] =& $this;
- $this->_rendering = TRUE;
-
- // take out CSS so we execute it only once per render
- if (!empty($params['css']))
- {
- $this->add_css($params['css'], $params['type']);
- }
- // same here... but we are looking for CSS on the object
- if (!empty($func->css))
- {
- $this->add_css($func->css, $params['type']);
- }
- // take out javascript so we execute it only once per render
- if (!empty($params['js']))
- {
- $this->add_js($params['js'], $params['type']);
- }
- // same here... but we are looking for js on the object
- if (!empty($func->js))
- {
- $this->add_js($func->js, $params['type']);
- }
-
- $field = $func->render($params);
- }
- else if (is_callable($func))
- {
- $this->_rendering = TRUE;
- $field = $this->create_custom($func, $params);
- }
- }
- else if (is_string($params))
- {
- $field = $params;
- }
-
- $this->_rendering = FALSE;
- return $field;
- }
- // --------------------------------------------------------------------
- /**
- * Checks to see if the array to initialize a field is normalized or not
- *
- * @access protected
- * @param array fields parameters
- * @return string
- */
- protected function _has_defaults($vals)
- {
- return (!empty($vals['__DEFAULTS__']));
- }
- // --------------------------------------------------------------------
- /**
- * Looks at the field type attribute and determines which form field to render
- *
- * IMPORTANT! You probably shouldn't call this method from within a custom field type because it may create an infinite loop!
- *
- * @access public
- * @param array fields parameters
- * @param boolean should the normalization be ran again?
- * @return string
- */
- public function create_field($params, $normalize = TRUE)
- {
- // needed to prevent runaway loops from custom fields... actually the template field type wont work with this
- // if ($this->_rendering)
- // {
- // return FALSE;
- // }
- if ($normalize) $params = $this->normalize_params($params); // done again here in case you create a field without doing the render method
- // now we look at all the fields that may represent other field types based on parameters
- if (!empty($this->representatives) AND is_array($this->representatives) AND empty($params['ignore_representative']))
- {
- foreach($this->representatives as $key => $val)
- {
- $matched = FALSE;
-
- // if the representative is an associative array with keys being parameters to match (e.g. type and name), then we loop through those parameters to find a match
- if (is_array($val) AND is_string(key($val)))
- {
- foreach($val as $k => $v)
- {
- $matched = (is_array($v) AND in_array($params[$k], $v) OR (is_string($v) AND preg_match('#'.$v.'#', $params[$k]))) ? TRUE : FALSE;
- if (!$matched)
- {
- break;
- }
- }
- }
-
- // if the representative is an array and the param type is in that array then we are a match
- else if (is_array($val) AND in_array($params['type'], $val))
- {
- $matched = TRUE;
- }
-
- // if the representative is a string, then we do a regex to see if we are a match
- else if (is_string($val) AND preg_match('#'.$val.'#', $params['type']))
- {
- $matched = TRUE;
- }
-
- // if we matched,then set the param type to it's representative and we break the loop and continue on
- if ($matched)
- {
- $params['type'] = $key;
- break;
- }
- }
- }
-
- $str = $this->_render_custom_field($params);
-
- if (!$str)
- {
- switch($params['type'])
- {
- case 'none': case 'blank' :
- $str = '';
- break;
- case 'custom':
- $func = (isset($params['func'])) ? $params['func'] : function($params) { return (isset($params["value"])) ? $params["value"] : "" ; };
- $str = $this->create_custom($func, $params);
- break;
- default :
- $method = 'create_'.$params['type'];
- if (method_exists($this, $method) AND $params['type'] != 'field')
- {
- $str = $this->$method($params);
- }
- else
- {
- $params['type'] = 'text';
- $str = $this->create_text($params);
- }
- }
- }
- // cache the field types being rendered
- $rendered_type = (!empty($matched)) ? $key : $params['type'];
- $this->_rendered_field_types[$rendered_type] = $rendered_type;
- // $this->_rendered_field_types[$params['type']] = $params['type'];
-
- // add before/after html
- $str = $params['before_html'].$str.$params['after_html'];
- return $str;
-
- }
-
- // --------------------------------------------------------------------
- /**
- * Creates the label for the form
- *
- * By default, if no label value is given, the method will generate one
- * based on the name of the field
- *
- * @access public
- * @param array fields parameters
- * @param boolean should the label be displayed?
- * @return string
- */
- public function create_label($params, $use_label = TRUE)
- {
- if (is_string($params))
- {
- $params = array('label' => $params);
- }
-
- $params = $this->normalize_params($params);
-
- $str = '';
- if (isset($params['display_label']) AND $params['display_label'] === FALSE) return $str;
-
- if (empty($params['label']))
- {
- if ($lang = $this->label_lang($params['orig_name']))
- {
- $params['label'] = $lang;
- }
- else
- {
- $params['label'] = ucfirst(str_replace('_', ' ', $params['orig_name']));
-
- }
- $label_words = explode(' ', $params['label']);
- if (in_array(strtolower($label_words[0]), $this->question_keys))
- {
- $params['label'] .= '?';
- }
-
- }
- $mode = (!empty($params['mode'])) ? $params['mode'] : $this->single_select_mode;
- if (($params['type'] == 'enum' OR $params['type'] == 'multi' OR $params['type'] == 'array') AND ($mode == 'radios' OR ($mode == 'auto' AND count($params['options']) <= 2)))
- {
- $use_label = FALSE;
- }
- if ($use_label)
- {
- if (!empty($params['id']))
- {
- $id_name = $params['id'];
- }
- elseif (!empty($this->name_prefix))
- {
- $name_parts = explode($this->name_prefix.'--', $params['name']);
- $id_name = $this->name_prefix.'--'.end($name_parts); // ugly... bug needed for nested repeatable fields
- }
- else
- {
- $id_name = $params['orig_name'];
- }
-
- $class = '';
- if (isset($params['label_class']) AND !empty($params['label_class']))
- {
- $class = ' class="'.$params['label_class'].'"';
- }
- $styles = (isset($params['nowrap'])…
Large files files are truncated, but you can click here to view the full file