PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/fuel/modules/fuel/libraries/Form_builder.php

http://github.com/daylightstudio/FUEL-CMS
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

  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * FUEL CMS
  4. * http://www.getfuelcms.com
  5. *
  6. * An open source Content Management System based on the
  7. * Codeigniter framework (http://codeigniter.com)
  8. *
  9. * @package FUEL CMS
  10. * @author David McReynolds @ Daylight Studio
  11. * @copyright Copyright (c) 2018, Daylight Studio LLC.
  12. * @license http://docs.getfuelcms.com/general/license
  13. * @link http://www.getfuelcms.com
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * A form creation class
  18. *
  19. * The Form_builder class allows you to create forms by passing in configurable
  20. * array values. Each field has a base set of parameters that can be set
  21. * for it. Other fields have additional parameters you can pass to it
  22. * (e.g. the date field). This class works with the
  23. * <a href="[user_guide_url]libraries/my_model#func_form_fields">MY_Model form_fields</a>
  24. * method which returns table meta information regarding the fields of a
  25. * table.
  26. *
  27. * The <a href="[user_guide_url]libraries/form">Form.php</a> class is required if a
  28. * form object is not passed in the initialization process.
  29. *
  30. * Custom form fields can be configured in the <span class="file">fuel/application/config/custom_fields.php</span> file.
  31. *
  32. * <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>.
  33. *
  34. * @package FUEL CMS
  35. * @subpackage Libraries
  36. * @category Libraries
  37. * @author David McReynolds @ Daylight Studio
  38. * @link http://docs.getfuelcms.com/libraries/form_builder
  39. */
  40. class Form_builder {
  41. public $form; // form object used to create the form fields and associate errors with
  42. public $id = ''; // id to be used for the containing table or div
  43. public $css_class = 'form'; // css class to be used with the form
  44. public $form_attrs = 'method="post" action=""'; // form tag attributes
  45. public $label_colons = FALSE; // add colons to form labels?
  46. public $textarea_rows = 10; // number of rows for a textarea
  47. public $textarea_cols = 60; // number of columns for a textarea
  48. public $text_size_limit = 40; // text size for a text input
  49. public $submit_name = ''; // submit id and name values
  50. public $submit_value = 'Submit'; // submit value (what the button says)
  51. public $cancel_value = ''; // cancel value (what the button says)
  52. public $cancel_action = ''; // what the cancel button does
  53. public $reset_value = ''; // reset button value (what the button says)
  54. public $other_actions = ''; // additional actions to be displayed at the bottom of the form
  55. public $use_form_tag = TRUE; // include the form opening/closing tags in rendered output
  56. public $exclude = array(); // exclude these fields from the form
  57. public $hidden = array('id'); // hidden fields
  58. public $readonly = array(); // readonly fields
  59. public $disabled = array(); // disabled fields
  60. public $displayonly = array(); // for display purposes only
  61. public $date_format = 'm/d/Y'; // date format for date type fields
  62. public $section_tag = 'h3'; // section html tag
  63. public $copy_tag = 'p'; // copy html tag
  64. public $fieldset = ''; // field set name
  65. public $name_array = ''; // put the form fields into an array for namespacing
  66. public $name_prefix = ''; // prefix the form fields as an alternatie to an array for namespacing
  67. public $class_type_prefix = 'field_type_'; // the CSS class prefix to associate with each field type
  68. public $names_id_match = TRUE; // determines if the names and ids match if using a name_prefix or name_array
  69. public $key_check = ''; // the keycheck value used for forms that create session unique session variables to prevent spamming
  70. public $key_check_name = ''; // the keycheck form name used for forms that create session unique session variables to prevent spamming
  71. public $tooltip_format = '<span title="{?}" class="tooltip">[?]</span>'; // tooltip formatting string
  72. public $tooltip_labels = TRUE; // use tooltip labels?
  73. 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
  74. 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
  75. public $boolean_mode = 'checkbox'; // boolean mode can be checkbox or enum (which will display radio inputs)
  76. public $display_errors_func = 'display_errors'; // the function used to generate errors... usually display_errors is the name
  77. public $display_errors = FALSE; // displays errors at the top of the form if TRUE
  78. 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
  79. public $show_required = TRUE; // show the required fields text at the bottom of the form
  80. public $required_indicator = '*'; // indicator for a required field
  81. public $required_text = '<span class="required">{required_indicator}</span> required fields'; // the required field text
  82. public $label_layout = 'left'; // label layout... can be left or top
  83. public $has_required = FALSE; // does the form have required fields
  84. public $render_format = 'table'; // default render format
  85. public $row_id_prefix = ''; // the row id prefix
  86. public $lang_prefix = 'form_label_'; // language prefix to be applied before a label
  87. public $custom_fields = array(); // custom fields
  88. public $auto_execute_js = TRUE; // automatically execute the javascript for the form
  89. public $html_prepend = ''; // prepended HTML to the form HINT: Can include JS script tags
  90. public $html_append = ''; // appended HTML to the form HINT: Can include JS script tags
  91. 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')
  92. public $js; // javascript files to associate with the form fields to be executed once per render
  93. public $css; // CSS files to associate with the form fields to be executed once per render
  94. public $no_css_js = FALSE; // used to not display the CSS and JS when rendering to prevent issues with nested forms and post_processing
  95. public $template = ''; // the html template view file to use for rendering the form when using "render_template"
  96. public $is_pre_processing = FALSE; // flag set when form builder is pre processing fields
  97. public $is_post_processing = FALSE; // flag set when form builder is post processing fields
  98. protected $_html; // html string
  99. protected $_fields; // fields to be used for the form
  100. protected $_values; // an array of the field values
  101. protected $_cached; // cached parameters
  102. protected $_pre_process; // pre_process functions
  103. protected $_post_process; // post_process functions
  104. protected $_rendering = FALSE; // used to prevent infinite loops when calling form_builder reference from within a custom form field
  105. protected $_rendered_field_types = array(); // holds all the fields types rendered
  106. protected $_is_nested = FALSE; // used to detect nested fields
  107. protected $CI;
  108. // --------------------------------------------------------------------
  109. /**
  110. * Constructor
  111. *
  112. * Accepts an associative array as input, containing preferences (optional)
  113. *
  114. * @access public
  115. * @param array config preferences
  116. * @return void
  117. */
  118. public function __construct($params = array())
  119. {
  120. $this->CI =& get_instance();
  121. $this->initialize($params);
  122. }
  123. // --------------------------------------------------------------------
  124. /**
  125. * Initialize preferences
  126. *
  127. * @access public
  128. * @param array
  129. * @return void
  130. */
  131. public function initialize($params = array())
  132. {
  133. // clear out any data before initializing
  134. $this->reset();
  135. $this->set_params($params);
  136. // setup custom fields
  137. if (!empty($this->custom_fields))
  138. {
  139. $this->load_custom_fields($this->custom_fields);
  140. }
  141. // create form object if not in initialization params
  142. if (is_null($this->form))
  143. {
  144. $this->CI->load->library('form');
  145. $this->CI->load->library('encryption');
  146. $this->form = new Form();
  147. // load localization helper if not already
  148. if (!function_exists('lang'))
  149. {
  150. $this->CI->load->helper('language');
  151. }
  152. // CSRF protections
  153. if ($this->CI->config->item('csrf_protection') === TRUE AND empty($this->key_check))
  154. {
  155. $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
  156. $this->key_check = $this->CI->security->get_csrf_hash();
  157. $this->key_check_name = $this->CI->security->get_csrf_token_name();
  158. }
  159. }
  160. }
  161. // --------------------------------------------------------------------
  162. /**
  163. * Set object parameters
  164. *
  165. * @access public
  166. * @param array
  167. * @return void
  168. */
  169. public function set_params($params)
  170. {
  171. if (is_array($params) AND count($params) > 0)
  172. {
  173. foreach ($params as $key => $val)
  174. {
  175. if (isset($this->$key))
  176. {
  177. $method = 'set_'.$key;
  178. if (method_exists($this, $method))
  179. {
  180. $this->$method($val);
  181. }
  182. else
  183. {
  184. $this->$key = $val;
  185. }
  186. }
  187. }
  188. }
  189. }
  190. // --------------------------------------------------------------------
  191. /**
  192. * Same as reset
  193. *
  194. * @access public
  195. * @return void
  196. */
  197. public function clear()
  198. {
  199. $this->reset();
  200. }
  201. // --------------------------------------------------------------------
  202. /**
  203. * Clear class values
  204. *
  205. * @access public
  206. * @return void
  207. */
  208. public function reset()
  209. {
  210. $this->_fields = array();
  211. $this->_values = array();
  212. $this->_html = '';
  213. $this->js = array();
  214. $this->css = array();
  215. $this->_pre_process = array();
  216. $this->_post_process = array();
  217. $this->key_check = NULL;
  218. $this->key_check_name = NULL;
  219. }
  220. // --------------------------------------------------------------------
  221. /**
  222. * Set the fields for the form
  223. *
  224. * Check the normalize_params method for possible values
  225. *
  226. * @access public
  227. * @param array
  228. * @return void
  229. */
  230. public function set_fields($fields)
  231. {
  232. $i = 1;
  233. // clear it out first
  234. $this->_fields = array();
  235. foreach ($fields as $key => $val)
  236. {
  237. $this->add_field($key, $val, $i);
  238. $i++;
  239. }
  240. }
  241. // --------------------------------------------------------------------
  242. /**
  243. * Set the fields for the form
  244. *
  245. * Check the normalize_params method for possible values
  246. *
  247. * @access public
  248. * @param string The key to associate with the field
  249. * @param array The field parameters
  250. * @param int The order value of the parameter
  251. * @return void
  252. */
  253. public function add_field($key, $val, $order = NULL)
  254. {
  255. // __FORM_BUILDER__ allows you to set properties on the class
  256. // convenient for models setting values
  257. if (strtoupper($key) == '__FORM_BUILDER__')
  258. {
  259. $this->set_params($val);
  260. }
  261. else
  262. {
  263. if (is_string($val))
  264. {
  265. $this->_fields[$key] = array('name' => $key, 'value' => $val);
  266. }
  267. else
  268. {
  269. $this->_fields[$key] = $val;
  270. }
  271. // set the key value
  272. if (empty($this->_fields[$key]['key']))
  273. {
  274. $this->_fields[$key]['key'] = $key;
  275. }
  276. if (empty($val['name']))
  277. {
  278. $this->_fields[$key]['name'] = $key;
  279. }
  280. // set the order of the field
  281. if (isset($order) AND empty($val['order']))
  282. {
  283. $this->_fields[$key]['order'] = $order;
  284. }
  285. if (empty($this->_fields[$key]['order']))
  286. {
  287. $this->_fields[$key]['order'] = count($this->_fields);
  288. }
  289. }
  290. }
  291. // --------------------------------------------------------------------
  292. /**
  293. * Removes a field before rendering
  294. *
  295. * @access public
  296. * @param string
  297. * @return void
  298. */
  299. public function remove_field($key)
  300. {
  301. if (is_array($key))
  302. {
  303. foreach($key as $k)
  304. {
  305. $this->remove_field($k);
  306. }
  307. }
  308. else
  309. {
  310. if (isset($this->_fields[$key]))
  311. {
  312. unset($this->_fields[$key]);
  313. }
  314. }
  315. }
  316. // --------------------------------------------------------------------
  317. /**
  318. * Returns the fields for the form. If a key value is passed, it will only return that one field
  319. *
  320. * @access public
  321. * @param string field key
  322. * @return array
  323. */
  324. public function fields($key = NULL)
  325. {
  326. if (!empty($key))
  327. {
  328. if (isset($this->_fields[$key]))
  329. {
  330. return $this->_fields[$key];
  331. }
  332. return FALSE;
  333. }
  334. return $this->_fields;
  335. }
  336. // --------------------------------------------------------------------
  337. /**
  338. * Returns the values of the form fields. If a key value is passed, it will only return that one value
  339. *
  340. * @access public
  341. * @param string field key
  342. * @return array
  343. */
  344. public function values($key = NULL)
  345. {
  346. if (!empty($key))
  347. {
  348. if (isset($this->_values[$key]))
  349. {
  350. return $this->_values[$key];
  351. }
  352. return FALSE;
  353. }
  354. return $this->_values;
  355. }
  356. // --------------------------------------------------------------------
  357. /**
  358. * Sets the value attribute for the fields of the form
  359. *
  360. * Often times this is database or post data
  361. *
  362. * @access public
  363. * @param array
  364. * @return void
  365. */
  366. public function set_field_values($values)
  367. {
  368. if (!is_array($values))
  369. {
  370. return FALSE;
  371. }
  372. // set the values in a different array to keep track of them separate from the form field...
  373. // this is in case the form field gets removed
  374. $this->_values = $values;
  375. // set values for fields that are arrays
  376. foreach($values as $key => $val)
  377. {
  378. if (is_array($values[$key]))
  379. {
  380. foreach($values[$key] as $k => $v)
  381. {
  382. $values[$key.'['.$k.']'] = $v;
  383. }
  384. }
  385. }
  386. if (!empty($this->_fields))
  387. {
  388. foreach($this->_fields as $key => $val)
  389. {
  390. if (isset($values[$key]))
  391. {
  392. if (empty($val['type']))
  393. {
  394. $is_checkbox = FALSE;
  395. }
  396. // don't set the values of these form types'
  397. else if ($val['type'] == 'submit' OR $val['type'] == 'button')
  398. {
  399. continue;
  400. }
  401. else
  402. {
  403. $is_checkbox = (($val['type'] == 'checkbox') OR ($val['type'] == 'boolean' AND $this->boolean_mode == 'checkbox'));
  404. }
  405. if (!$is_checkbox)
  406. {
  407. $this->_fields[$key]['value'] = $values[$key];
  408. }
  409. if (!empty($val['type']))
  410. {
  411. if ($is_checkbox)
  412. {
  413. $this->_fields[$key]['checked'] = ((isset($this->_fields[$key]['value']) AND $values[$key] == $this->_fields[$key]['value']) OR
  414. $values[$key] === TRUE OR
  415. $values[$key] === 1 OR
  416. $values[$key] === 'y' OR
  417. $values[$key] === 'yes') ? TRUE : FALSE;
  418. }
  419. }
  420. }
  421. }
  422. }
  423. }
  424. // --------------------------------------------------------------------
  425. /**
  426. * Render the HTML output
  427. *
  428. * @access public
  429. * @param array fields values... will overwrite anything done with the set_fields method previously
  430. * @param string 'divs or table
  431. * @param string 'a view path (only used for the template)
  432. * @return string
  433. */
  434. public function render($fields = NULL, $render_format = NULL, $template = NULL)
  435. {
  436. if (empty($render_format)) $render_format = $this->render_format;
  437. if ($render_format == 'divs')
  438. {
  439. return $this->render_divs($fields);
  440. }
  441. else if ($render_format == 'template')
  442. {
  443. if (empty($template))
  444. {
  445. $template = $this->template;
  446. }
  447. return $this->render_template($template, $fields);
  448. }
  449. else
  450. {
  451. return $this->render_table($fields);
  452. }
  453. }
  454. // --------------------------------------------------------------------
  455. /**
  456. * Render the HTML output
  457. *
  458. * @access public
  459. * @param array fields values... will overwrite anything done with the set_fields method previously
  460. * @return string
  461. */
  462. public function render_divs($fields = NULL)
  463. {
  464. if (!empty($fields)) $this->set_fields($fields);
  465. // reorder
  466. $this->set_field_order();
  467. // pre process field values
  468. $this->pre_process_field_values();
  469. $this->_html = $this->html_prepend;
  470. $str = '';
  471. $begin_str = '';
  472. $end_str = '';
  473. if ($this->display_errors)
  474. {
  475. $func = $this->display_errors_func;
  476. if (function_exists($func))
  477. {
  478. $str .= $func();
  479. }
  480. }
  481. $colspan = ($this->label_layout == 'top') ? '1' : '2';
  482. $first = $this->_find_first_renderable_field();;
  483. $is_fieldset_first = FALSE;
  484. if ($first['type'] != 'fieldset')
  485. {
  486. $str .= $this->_open_div();
  487. }
  488. else
  489. {
  490. $is_fieldset_first = TRUE;
  491. }
  492. $fieldset_on = FALSE;
  493. foreach($this->_fields as $key => $val)
  494. {
  495. $val = $this->normalize_params($val);
  496. if ($val['type'] == 'fieldset' OR !empty($val['fieldset']))
  497. {
  498. // don't close the table if it isn't opened earlier
  499. if ($is_fieldset_first == FALSE)
  500. {
  501. $str .= $this->_close_div();
  502. }
  503. $is_fieldset_first = FALSE;
  504. // close any existing field sets
  505. if ($fieldset_on)
  506. {
  507. $fieldset_val['open'] = FALSE;
  508. $str .= $this->create_fieldset($fieldset_val);
  509. }
  510. $fieldset_val['open'] = TRUE;
  511. if (!empty($val['fieldset']))
  512. {
  513. $fieldset_val['value'] = $val['fieldset'];
  514. }
  515. else
  516. {
  517. $fieldset_val = $val;
  518. }
  519. $str .= $this->create_fieldset($fieldset_val);
  520. $str .= $this->_open_div();
  521. $fieldset_on = TRUE;
  522. // continue if the fieldset is part of the field values and not the "type"
  523. if (empty($val['fieldset']))
  524. {
  525. continue;
  526. }
  527. }
  528. if ($val['type'] == 'section')
  529. {
  530. $str .= "<div".$this->_open_row_attrs($val).'>';
  531. $str .= "<div class=\"section\">".$this->create_section($val)."</div>\n";
  532. $str .= "</div>\n";
  533. continue;
  534. }
  535. else if (!empty($val['section']))
  536. {
  537. $str .= "<div class=\"section\"><".$this->section_tag.">".$val['section']."</".$this->section_tag."></div>\n";
  538. }
  539. if ($val['type'] == 'copy')
  540. {
  541. $str .= "<div".$this->_open_row_attrs($val).'>';
  542. $str .= "<div class=\"copy\">".$this->create_copy($val)."</div>\n";
  543. $str .= "</div>\n";
  544. continue;
  545. }
  546. else if (!empty($val['copy']))
  547. {
  548. $str .= "<div".$this->_open_row_attrs($val).'>';
  549. $str .= "<div class=\"copy\"><".$this->copy_tag.">".$val['copy']."</".$this->copy_tag."></div>\n";
  550. $str .= "</div>\n";
  551. }
  552. if (!empty($val['custom']))
  553. {
  554. $str .= "<div".$this->_open_row_attrs($val).'>';
  555. $str .= "<span class=\"label\">";
  556. $str .= $this->create_label($val, TRUE);
  557. $str .= "</span>";
  558. $str .= "<span".$this->_open_field_attrs($val).">";
  559. $str .= $val['custom'];
  560. $str .= "</span>";
  561. $str .= "</div>\n";
  562. }
  563. else if (in_array($val['name'], $this->hidden) OR $val['type'] == 'hidden')
  564. {
  565. $end_str .= $this->create_hidden($val);
  566. }
  567. 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'))
  568. {
  569. if (isset($val['displayonly']) AND !is_bool($val['displayonly']))
  570. {
  571. $display_value = $val['displayonly'];
  572. }
  573. else
  574. {
  575. $display_value = (is_array($val['value'])) ? print_r($val['value'], TRUE) : $val['value'];
  576. }
  577. $str .= "<div".$this->_open_row_attrs($val).'>';
  578. $str .= "<span class=\"label\">";
  579. $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label'];
  580. $str .= "</span>";
  581. $str .= "<span".$this->_open_field_attrs($val)."><span class=\"displayonly noclone\">";
  582. $str .= $val['before_html'].$display_value.$val['after_html'];
  583. $str .= "</span></span>";
  584. $str .= "</div>\n";
  585. }
  586. else if (!in_array($val['name'], $this->exclude))
  587. {
  588. $str .= "<div".$this->_open_row_attrs($val).'>';
  589. $str .= "<span class=\"label\">";
  590. $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label'];
  591. $str .= "</span>";
  592. $str .= "<span".$this->_open_field_attrs($val).">";
  593. $str .= $this->create_field($val, FALSE);
  594. $str .= "</span>";
  595. $str .= "</div>\n";
  596. }
  597. }
  598. // close any open fieldsets
  599. if ($fieldset_on)
  600. {
  601. $str .= $this->_close_div();
  602. $val['open'] = FALSE;
  603. $str .= $this->create_fieldset($val);
  604. $str .= $this->_open_div();
  605. }
  606. $actions = $this->_render_actions();
  607. if (!empty($actions))
  608. {
  609. $str .= "<div class=\"actions\"><div class=\"actions_inner\">";
  610. $str .= $actions;
  611. $str .= "</div></div>\n";
  612. }
  613. if ($this->has_required AND ($this->show_required AND strtolower($this->show_required) != 'top'))
  614. {
  615. $str .= "<div class=\"required\">";
  616. $str .= str_replace('{required_indicator}', $this->required_indicator, $this->required_text);
  617. $str .= "</div>\n";
  618. }
  619. $str .= "</div>\n";
  620. $str = $begin_str . $str . $end_str;
  621. $this->_close_form($str);
  622. return $this->_html;
  623. }
  624. // --------------------------------------------------------------------
  625. /**
  626. * Render the HTML output
  627. *
  628. * @access public
  629. * @param array fields values... will overwrite anything done with the set_fields method previously
  630. * @return string
  631. */
  632. public function render_table($fields = NULL)
  633. {
  634. if (!empty($fields)) $this->set_fields($fields);
  635. // reorder
  636. $this->set_field_order();
  637. // pre process field values
  638. $this->pre_process_field_values();
  639. $this->_html = $this->html_prepend;
  640. $str = '';
  641. $begin_str = '';
  642. $end_str = '';
  643. if ($this->display_errors)
  644. {
  645. $func = $this->display_errors_func;
  646. if (function_exists($func))
  647. {
  648. $str .= $func();
  649. }
  650. }
  651. $colspan = ($this->label_layout == 'top') ? '1' : '2';
  652. $first = $this->_find_first_renderable_field();
  653. $is_fieldset_first = FALSE;
  654. if ($first['type'] != 'fieldset')
  655. {
  656. $str .= $this->_open_table();
  657. }
  658. else
  659. {
  660. $is_fieldset_first = TRUE;
  661. }
  662. $fieldset_on = FALSE;
  663. foreach($this->_fields as $key => $val)
  664. {
  665. $val = $this->normalize_params($val);
  666. if ($val['type'] == 'fieldset' OR !empty($val['fieldset']))
  667. {
  668. // don't close the table if it isn't opened earlier
  669. if ($is_fieldset_first == FALSE)
  670. {
  671. $str .= $this->_close_table();
  672. }
  673. $is_fieldset_first = FALSE;
  674. // close any existing field sets
  675. if ($fieldset_on)
  676. {
  677. $fieldset_val['open'] = FALSE;
  678. $str .= $this->create_fieldset($fieldset_val);
  679. }
  680. $fieldset_val['open'] = TRUE;
  681. if (!empty($val['fieldset']))
  682. {
  683. $fieldset_val['value'] = $val['fieldset'];
  684. }
  685. else
  686. {
  687. $fieldset_val = $val;
  688. }
  689. $str .= $this->create_fieldset($fieldset_val);
  690. $str .= $this->_open_table();
  691. $fieldset_on = TRUE;
  692. // continue if the fieldset is part of the field values and not the "type"
  693. if (empty($val['fieldset']))
  694. {
  695. continue;
  696. }
  697. }
  698. if ($val['type'] == 'section')
  699. {
  700. $str .= "<tr".$this->_open_row_attrs($val);
  701. $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"section\">".$this->create_section($val)."</td>\n</tr>\n";
  702. continue;
  703. }
  704. else if (!empty($val['section']))
  705. {
  706. $str .= "<tr".$this->_open_row_attrs($val);
  707. $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"section\"><".$this->section_tag.">".$val['section']."</".$this->section_tag."></td>\n</tr>\n";
  708. }
  709. if ($val['type'] == 'copy')
  710. {
  711. $str .= "<tr".$this->_open_row_attrs($val);
  712. $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"copy\">".$this->create_copy($val)."</td></tr>\n";
  713. continue;
  714. }
  715. else if (!empty($val['copy']))
  716. {
  717. $str .= "<tr".$this->_open_row_attrs($val);
  718. $str .= ">\n\t<td colspan=\"".$colspan."\" class=\"copy\"><".$this->copy_tag.">".$val['copy']."</".$this->copy_tag."></td>\n</tr>\n";
  719. }
  720. if (!empty($val['custom']))
  721. {
  722. $str .= "<tr".$this->_open_row_attrs($val);
  723. $str .= ">\n\t";
  724. if ($val['display_label'] !== FALSE)
  725. {
  726. $str .= "<td class=\"label\">";
  727. if ($this->label_layout != 'top')
  728. {
  729. $str .= $this->create_label($val, TRUE);
  730. $str .= "</td>\n\t<td".$this->_open_field_attrs($val).">".$val['custom']."</td>\n</tr>\n";
  731. }
  732. else
  733. {
  734. $str .= $this->create_label($val, TRUE)."</td></tr>\n";
  735. $str .= "<tr".$this->_open_row_attrs($val);
  736. $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$val['custom']."</td>\n</tr>\n";
  737. }
  738. }
  739. else
  740. {
  741. $str .= "<td class=\"value\" colspan=\"2\">".$val['custom']."</td>\n</tr>\n";
  742. }
  743. }
  744. else if (in_array($val['name'], $this->hidden) OR $val['type'] == 'hidden')
  745. {
  746. $end_str .= $this->create_hidden($val);
  747. }
  748. 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)
  749. {
  750. $str .= "<tr".$this->_open_row_attrs($val);
  751. $str .= ">\n\t<td class=\"label\">";
  752. if (isset($val['displayonly']) AND !is_bool($val['displayonly']))
  753. {
  754. $display_value = $val['displayonly'];
  755. }
  756. else
  757. {
  758. $display_value = (is_array($val['value'])) ? print_r($val['value'], TRUE) : $val['value'];
  759. }
  760. if ($this->label_layout != 'top')
  761. {
  762. $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label'];
  763. $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";
  764. }
  765. else
  766. {
  767. $str .= $val['before_label'].$this->create_label($val, FALSE).$val['after_label']."</td></tr>\n";
  768. $str .= "<tr".$this->_open_row_attrs($val);
  769. $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$val['before_html'].$display_value.$val['after_html']."</td>\n</tr>\n";
  770. }
  771. }
  772. else if (!in_array($val['name'], $this->exclude))
  773. {
  774. $str .= "<tr".$this->_open_row_attrs($val);
  775. $str .= ">\n\t";
  776. if ($val['display_label'] !== FALSE)
  777. {
  778. $str .= "<td class=\"label\">";
  779. if ($this->label_layout != 'top')
  780. {
  781. $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label'];
  782. $str .= "</td>\n\t<td".$this->_open_field_attrs($val).">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
  783. }
  784. else
  785. {
  786. $str .= $val['before_label'].$this->create_label($val, TRUE).$val['after_label']."</td></tr>\n";
  787. $str .= "<tr".$this->_open_row_attrs($val);
  788. $str .= ">\n\t<td".$this->_open_field_attrs($val).">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
  789. }
  790. }
  791. else
  792. {
  793. $str .= "<td class=\"value\" colspan=\"2\">".$this->create_field($val, FALSE)."</td>\n</tr>\n";
  794. }
  795. }
  796. }
  797. // close any open fieldsets
  798. if ($fieldset_on)
  799. {
  800. $str .= $this->_close_table();
  801. $val['open'] = FALSE;
  802. $str .= $this->create_fieldset($val);
  803. $str .= $this->_open_table();
  804. }
  805. $actions = $this->_render_actions();
  806. if (!empty($actions))
  807. {
  808. if ($this->label_layout != 'top')
  809. {
  810. $str .= "<tr";
  811. if (!empty($this->row_id_prefix))
  812. {
  813. $str .= ' id="'.$this->row_id_prefix.'actions"';
  814. }
  815. $str .= ">\n\t<td></td>\n\t<td class=\"actions\"><div class=\"actions_inner\">";
  816. }
  817. else
  818. {
  819. $str .= "<tr>\n\t<td class=\"actions\"><div class=\"actions\">";
  820. }
  821. $str .= $actions;
  822. $str .= "</div></td>\n</tr>\n";
  823. }
  824. if ($this->has_required AND ($this->show_required AND strtolower($this->show_required) != 'top'))
  825. {
  826. $str .= "<tr>\n\t<td colspan=\"".$colspan."\" class=\"required\">";
  827. $str .= str_replace('{required_indicator}', $this->required_indicator, $this->required_text);
  828. $str .= "</td>\n</tr>\n";
  829. }
  830. $str .= $this->_close_table();
  831. $str = $begin_str . $str . $end_str;
  832. $this->_close_form($str);
  833. return $this->_html;
  834. }
  835. // --------------------------------------------------------------------
  836. /**
  837. * Render the HTML output using a specified template.
  838. *
  839. * Will provide an array of form fields that can be parsed like so {my_field}
  840. *
  841. * @access public
  842. * @param string the name of the template view file to use
  843. * @param array fields values... will overwrite anything done with the set_fields method previously
  844. * @return string
  845. */
  846. public function render_template($template, $fields = NULL, $parse = TRUE)
  847. {
  848. if (!empty($fields)) $this->set_fields($fields);
  849. // reorder
  850. $this->set_field_order();
  851. // pre process field values
  852. $this->pre_process_field_values();
  853. $this->_html = $this->html_prepend;
  854. $errors = NULL;
  855. if ($this->display_errors)
  856. {
  857. $func = $this->display_errors_func;
  858. if (function_exists($func))
  859. {
  860. $errors = $func();
  861. }
  862. }
  863. $fields = array();
  864. foreach($this->_fields as $key => $field)
  865. {
  866. $fields[$key]['field'] = $this->create_field($field);
  867. $fields[$key]['label'] = $this->create_label($field);
  868. }
  869. $vars['fields'] = $fields;
  870. $vars['errors'] = $errors;
  871. if (is_array($template))
  872. {
  873. $module = key($template);
  874. $view = current($template);
  875. $str = $this->CI->load->module_view($module, $view, $vars, TRUE);
  876. }
  877. else
  878. {
  879. $str = $this->CI->load->view($template, $vars, TRUE);
  880. }
  881. if ($parse === TRUE)
  882. {
  883. $this->CI->load->library('parser');
  884. $str = parse_template_syntax($str, $vars, 'ci');
  885. }
  886. $actions = $this->_render_actions();
  887. if (!empty($actions))
  888. {
  889. $str .= '<div class="actions">';
  890. $str .= $actions;
  891. $str .= "</div>";
  892. }
  893. $this->_html = $this->_close_form($str);
  894. return $this->_html;
  895. }
  896. // --------------------------------------------------------------------
  897. /**
  898. * Finds the first field that is not hidden and renderable
  899. *
  900. * @access protected
  901. * @return array
  902. */
  903. protected function _find_first_renderable_field()
  904. {
  905. foreach($this->_fields as $key => $field)
  906. {
  907. $invalid_types = array('hidden');
  908. if ( ! in_array($field['type'], $invalid_types) AND ! in_array($key, $this->hidden))
  909. {
  910. return $field;
  911. }
  912. }
  913. return reset($this->_fields);
  914. }
  915. // --------------------------------------------------------------------
  916. /**
  917. * Creates the opening div element that contains the form fields
  918. *
  919. * @access protected
  920. * @return string
  921. */
  922. protected function _open_div()
  923. {
  924. $str = '';
  925. $str .= "<div>\n";
  926. return $str;
  927. }
  928. // --------------------------------------------------------------------
  929. /**
  930. * Creates the opening table element
  931. *
  932. * @access protected
  933. * @return string
  934. */
  935. protected function _open_table()
  936. {
  937. $str = '';
  938. $str .= "<table>\n";
  939. $str .= "<colgroup>\n";
  940. $str .= "<col class=\"label_column\">\n";
  941. $str .= "<col class=\"field_column\">\n";
  942. $str .= "</colgroup>\n";
  943. $str .= "<tbody>\n";
  944. return $str;
  945. }
  946. // --------------------------------------------------------------------
  947. /**
  948. * Creates the closing element
  949. *
  950. * @access protected
  951. * @return string
  952. */
  953. protected function _close_div()
  954. {
  955. $str = '';
  956. $str .= "</div>\n";
  957. return $str;
  958. }
  959. // --------------------------------------------------------------------
  960. /**
  961. * Creates the closing table elements
  962. *
  963. * @access protected
  964. * @return string
  965. */
  966. protected function _close_table()
  967. {
  968. $str = '';
  969. $str .= "</tbody>\n";
  970. $str .= "</table>\n";
  971. return $str;
  972. }
  973. // --------------------------------------------------------------------
  974. /**
  975. * Creates the opening row TR or div with attrs
  976. *
  977. * @access protected
  978. * @param array fields parameters
  979. * @return string
  980. */
  981. protected function _open_row_attrs($val)
  982. {
  983. $str = '';
  984. if (!empty($this->row_id_prefix))
  985. {
  986. $str .= ' id="'.$this->row_id_prefix.Form::create_id($val['name']).'"';
  987. }
  988. if (!empty($val['row_class']))
  989. {
  990. $str .= ' class="'.$val['row_class'].'"';
  991. }
  992. if (!empty($val['row_style']))
  993. {
  994. $str .= ' style="'.$val['row_style'].'"';
  995. }
  996. return $str;
  997. }
  998. // --------------------------------------------------------------------
  999. /**
  1000. * Creates the opening field td.value or div.value with attrs
  1001. *
  1002. * @access protected
  1003. * @param array fields parameters
  1004. * @return string
  1005. */
  1006. protected function _open_field_attrs($val)
  1007. {
  1008. $str = ' class="field';
  1009. if (!empty($val['field_class']))
  1010. {
  1011. $str .= ' '.$val['field_class'];
  1012. }
  1013. $str .= '"';
  1014. if (!empty($val['field_style']))
  1015. {
  1016. $str .= ' style="'.$val['field_style'].'"';
  1017. }
  1018. return $str;
  1019. }
  1020. // --------------------------------------------------------------------
  1021. /**
  1022. * Outputs the actions for the form
  1023. *
  1024. * @access protected
  1025. * @param string
  1026. * @return string
  1027. */
  1028. protected function _render_actions()
  1029. {
  1030. $str = '';
  1031. if ( ! empty($this->reset_value))
  1032. {
  1033. if (preg_match("/^</i", $this->reset_value))
  1034. {
  1035. $str .= $this->reset_value;
  1036. }
  1037. else
  1038. {
  1039. $str .= $this->form->reset($this->reset_value, '', array('class' => 'reset'));
  1040. }
  1041. }
  1042. if ( ! empty($this->cancel_value))
  1043. {
  1044. if (preg_match("/^</i", $this->cancel_value))
  1045. {
  1046. $str .= $this->cancel_value;
  1047. }
  1048. else
  1049. {
  1050. $cancel_attrs = array('class' => 'cancel');
  1051. if ( ! empty($this->cancel_action))
  1052. {
  1053. $cancel_attrs['onclick'] = $this->cancel_action;
  1054. }
  1055. $str .= $this->form->button($this->cancel_value, '', $cancel_attrs);
  1056. }
  1057. }
  1058. if (!empty($this->submit_value) AND $this->displayonly != 'all')
  1059. {
  1060. // check if the string has a tag and if so just pump in the string
  1061. if (preg_match("/^</i", $this->submit_value))
  1062. {
  1063. $str .= $this->submit_value;
  1064. }
  1065. else
  1066. {
  1067. $submit_btn = (preg_match("/(.)+\\.(jp(e){0,1}g$|gif$|png$)/i", $this->submit_value)) ? 'image' : 'submit';
  1068. $submit_name = (empty($this->submit_name)) ? url_title($this->submit_value, '_') : $this->submit_name;
  1069. if (empty($submit_name)) $submit_name = 'submit_form';
  1070. $submit_name = (!empty($this->name_prefix) AND $this->names_id_match) ? $this->name_prefix.'--'.$submit_name : $submit_name;
  1071. $submit_id = $submit_name;
  1072. // if (!empty($this->name_prefix))
  1073. // {
  1074. // $submit_id = $this->name_prefix.'--'.$submit_id;
  1075. // }
  1076. $str .= $this->form->$submit_btn($this->submit_value, $submit_name, array('class' => 'submit', 'id' => $submit_id));
  1077. }
  1078. }
  1079. if (!empty($this->other_actions)) $str .= $this->other_actions;
  1080. return $str;
  1081. }
  1082. // --------------------------------------------------------------------
  1083. /**
  1084. * Outputs the last part of the form rendering for both a table and div
  1085. *
  1086. * @access protected
  1087. * @param string
  1088. * @return string
  1089. */
  1090. protected function _close_form($str)
  1091. {
  1092. if ($this->use_form_tag)
  1093. {
  1094. $this->_html .= $this->form->open($this->form_attrs);
  1095. }
  1096. if (!empty($this->fieldset))
  1097. {
  1098. $this->_html .= $this->form->fieldset_open($this->fieldset);
  1099. }
  1100. // wrapper div to apply ID
  1101. $wrapper_open_str = "<div class=\"".$this->css_class."\"";
  1102. if (empty($this->id))
  1103. {
  1104. $this->id = $this->id();
  1105. }
  1106. $wrapper_open_str .= ' id="'.$this->id.'"';
  1107. $wrapper_open_str .= ">\n";
  1108. $wrapper_close_str = "</div>";
  1109. // apply any CSS first
  1110. foreach($this->css as $css)
  1111. {
  1112. $this->_html .= $this->_apply_asset_files('css', $css);
  1113. }
  1114. $this->_html .= $wrapper_open_str.$str.$wrapper_close_str;
  1115. if (!empty($this->key_check))
  1116. {
  1117. $this->_html .= $this->create_hidden(array('name' => $this->key_check_name, 'value' => $this->key_check));
  1118. }
  1119. if (!empty($this->fieldset))
  1120. {
  1121. $this->_html .= $this->form->fieldset_close();
  1122. }
  1123. if ($this->use_form_tag)
  1124. {
  1125. $this->_html .= $this->form->close('', FALSE); // we set the token above just in case form tags are turned off
  1126. }
  1127. $this->_html .= $this->_render_js();
  1128. $this->_html .= $this->html_append;
  1129. return $this->_html;
  1130. }
  1131. // --------------------------------------------------------------------
  1132. /**
  1133. * Normalize the fields so that the other methods can expect certain field attributes
  1134. *
  1135. * @access protected
  1136. * @param array fields values... will overwrite anything done with the set_fields method previously
  1137. * @return array
  1138. */
  1139. protected function _default($val)
  1140. {
  1141. if (is_object($val)) $val = get_object_vars($val);
  1142. $defaults = array(
  1143. '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
  1144. '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
  1145. 'name' => '', // the name attribute of the field
  1146. 'type' => '', // the type attribute of the field (e.g. text, select, password, etc.)
  1147. 'default' => '', // the default value of the field
  1148. 'max_length' => 0, // the maxlength parameter to associate with the field
  1149. 'comment' => '', // a comment to associate with the field's label
  1150. 'label' => '', // the label to associate with the field
  1151. 'before_label' => '', // for HTML before the label
  1152. 'after_label' => '', // for HTML after the label
  1153. 'required' => FALSE, // puts a required flag next to field label
  1154. 'size' => '', // the size attribute of the field
  1155. 'class' => '', // the CSS class attribute to associate with the field
  1156. 'style' => '', // inline style
  1157. 'value' => '', // the value of the field
  1158. 'readonly' => '', // sets readonly attribute on field
  1159. 'disabled' => '', // sets disabled attribute on the field
  1160. 'tabindex' => '', // adds the tab index attribute to a field
  1161. 'label_colons' => NULL, // whether to display the label colons
  1162. 'display_label' => TRUE, // whether to display the label
  1163. 'order' => NULL, // the display order value to associate with the field
  1164. 'before_html' => '', // for HTML before the field
  1165. 'after_html' => '', // for HTML after the field
  1166. 'displayonly' => FALSE, // only displays the value (no field)
  1167. 'pre_process' => NULL, // a pre process function
  1168. 'post_process' => NULL, // a post process function run on post
  1169. 'js' => '', // js file or script using <script> tag
  1170. 'css' => '', // css to associate with the field
  1171. 'represents' => '', // specifies what other types of fields that this field should represent
  1172. 'ignore_representative' => FALSE, // ignores any representative
  1173. 'data' => array(), // data attributes
  1174. 'title' => NULL, // the title attribute
  1175. 'attributes' => '', // a generic string value of attributes for the form field (e.g. 'class="myclass"')
  1176. '__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
  1177. );
  1178. $params = array_merge($defaults, $val);
  1179. if (empty($params['orig_name'])) $params['orig_name'] = $params['name']; // for labels in case the name_array is used
  1180. if (empty($params['key']))
  1181. {
  1182. $params['key'] = Form::create_id($params['orig_name']);
  1183. }
  1184. if (!isset($val['value']) AND ($params['type'] != 'checkbox' AND !($params['type'] == 'boolean' AND $this->boolean_mode == 'checkbox')))
  1185. {
  1186. $params['value'] = $params['default'];
  1187. }
  1188. if (!isset($params['label_colons']))
  1189. {
  1190. $params['label_colons'] = $this->label_colons;
  1191. }
  1192. if (!empty($val['name']))
  1193. {
  1194. if ((is_array($this->readonly) AND in_array($val['name'], $this->readonly)) OR (is_string($this->readonly) AND strtolower($this->readonly) == 'all'))
  1195. {
  1196. $params['readonly'] = 'readonly';
  1197. }
  1198. if ((is_array($this->disabled) AND in_array($val['name'], $this->disabled)) OR (is_string($this->disabled) AND strtolower($this->disabled) == 'all'))
  1199. {
  1200. $params['disabled'] = 'disabled';
  1201. }
  1202. }
  1203. if (!empty($this->name_array) AND strpos($params['name'], '[') === FALSE)
  1204. {
  1205. if (!$this->names_id_match)
  1206. {
  1207. if ($params['id'] !== FALSE)
  1208. {
  1209. $params['id'] = $this->name_array.'['.$params['orig_name'].']';
  1210. }
  1211. $params['name'] = $params['orig_name'];
  1212. }
  1213. else
  1214. {
  1215. if ($this->key_check_name != $params['orig_name'])
  1216. {
  1217. $params['name'] = $this->name_array.'['.$params['orig_name'].']';
  1218. }
  1219. else
  1220. {
  1221. $params['name'] = $params['orig_name'];
  1222. }
  1223. }
  1224. if (in_array($params['orig_name'], $this->hidden) AND !in_array($params['name'], $this->hidden)) $this->hidden[] = $params['name'];
  1225. }
  1226. if (!empty($this->name_prefix))
  1227. {
  1228. if (!$this->names_id_match)
  1229. {
  1230. if ($params['id'] !== FALSE)
  1231. {
  1232. $params['id'] = $this->name_prefix.'--'.$params['orig_name']; // used double hyphen so easier to explode
  1233. }
  1234. $params['name'] = $params['orig_name'];
  1235. }
  1236. else
  1237. {
  1238. if ($this->key_check_name != $params['orig_name'])
  1239. {
  1240. $params['name'] = $this->name_prefix.'--'.$params['orig_name'];
  1241. }
  1242. else
  1243. {
  1244. $params['name'] = $params['orig_name'];
  1245. }
  1246. }
  1247. if (in_array($params['orig_name'], $this->hidden) AND !in_array($params['name'], $this->hidden)) $this->hidden[] = $params['name'];
  1248. }
  1249. // grab options from a model if a model is specified
  1250. if (!empty($params['model']))
  1251. {
  1252. $model_params = (!empty($params['model_params'])) ? $params['model_params'] : array();
  1253. $params['options'] = $this->options_from_model($params['model'], $model_params);
  1254. }
  1255. if ($params['type'] == 'enum' OR $params['type'] == 'select')
  1256. {
  1257. if (!isset($params['options']))
  1258. {
  1259. $params['options'] = array();
  1260. }
  1261. if ((empty($params['options']) AND is_array($params['options'])) AND is_array($params['max_length']) AND !empty($params['max_length']))
  1262. {
  1263. $params['options'] = $params['max_length'];
  1264. }
  1265. if (!empty($params['hide_if_one']) AND count($params['options']) <= 1)
  1266. {
  1267. $params['type'] = 'hidden';
  1268. $params['display_label'] = FALSE;
  1269. }
  1270. }
  1271. // fix common errors
  1272. if (!empty($params['maxlength']) AND empty($params['max_length']))
  1273. {
  1274. $params['max_length'] = $params['maxlength'];
  1275. unset($params['maxlength']);
  1276. }
  1277. // take out javascript so we execute it only once per render
  1278. if (!empty($params['js']))
  1279. {
  1280. $this->add_js($params['js']);
  1281. }
  1282. // take out css so we execute it only once per render
  1283. if (!empty($params['css']))
  1284. {
  1285. $this->add_css($params['css']);
  1286. }
  1287. // says whether this field can represent other field types
  1288. if (!empty($params['represents']))
  1289. {
  1290. $this->representatives[$params['type']] = $params['represents'];
  1291. }
  1292. // set the field type CSS class
  1293. $type = (!empty($params['type'])) ? $params['type'] : 'text';
  1294. $field_class = $this->class_type_prefix.$type;
  1295. $params['class'] = (!empty($params['class']) AND strpos($params['class'], $field_class) === FALSE) ? $field_class.' '.$params['class'] : $params['class'];
  1296. $this->_cached[$params['name']] = $params;
  1297. return $params;
  1298. }
  1299. // --------------------------------------------------------------------
  1300. /**
  1301. * Returns the id for a form
  1302. *
  1303. * @access public
  1304. * @return string
  1305. */
  1306. public function id()
  1307. {
  1308. if (empty($this->id))
  1309. {
  1310. $this->id = uniqid('form_');
  1311. }
  1312. return $this->id;
  1313. }
  1314. // --------------------------------------------------------------------
  1315. /**
  1316. * Get the default values for any field
  1317. *
  1318. * @access public
  1319. * @param array fields values... will overwrite anything done with the set_fields method previously
  1320. * @return array
  1321. */
  1322. public function normalize_params($val, $defaults = array())
  1323. {
  1324. if ($val == '')
  1325. {
  1326. $val = array();
  1327. }
  1328. // check to see if the array is already normalized
  1329. if (!$this->_has_defaults($val))
  1330. {
  1331. $val = $this->_default($val);
  1332. }
  1333. // set up defaults
  1334. $params = array_merge($defaults, $val);
  1335. return $params;
  1336. }
  1337. // --------------------------------------------------------------------
  1338. /**
  1339. * Renders the custom field
  1340. *
  1341. * @access protected
  1342. * @param array fields values... will overwrite anything done with the set_fields method previously
  1343. * @return array
  1344. */
  1345. protected function _render_custom_field($params)
  1346. {
  1347. $field = FALSE;
  1348. if (is_array($params) AND isset($this->custom_fields[$params['type']]))
  1349. {
  1350. $func = $this->custom_fields[$params['type']];
  1351. if (is_a($func, 'Form_builder_field'))
  1352. {
  1353. // give custom fields a reference to the current object
  1354. $params['instance'] =& $this;
  1355. $this->_rendering = TRUE;
  1356. // take out CSS so we execute it only once per render
  1357. if (!empty($params['css']))
  1358. {
  1359. $this->add_css($params['css'], $params['type']);
  1360. }
  1361. // same here... but we are looking for CSS on the object
  1362. if (!empty($func->css))
  1363. {
  1364. $this->add_css($func->css, $params['type']);
  1365. }
  1366. // take out javascript so we execute it only once per render
  1367. if (!empty($params['js']))
  1368. {
  1369. $this->add_js($params['js'], $params['type']);
  1370. }
  1371. // same here... but we are looking for js on the object
  1372. if (!empty($func->js))
  1373. {
  1374. $this->add_js($func->js, $params['type']);
  1375. }
  1376. $field = $func->render($params);
  1377. }
  1378. else if (is_callable($func))
  1379. {
  1380. $this->_rendering = TRUE;
  1381. $field = $this->create_custom($func, $params);
  1382. }
  1383. }
  1384. else if (is_string($params))
  1385. {
  1386. $field = $params;
  1387. }
  1388. $this->_rendering = FALSE;
  1389. return $field;
  1390. }
  1391. // --------------------------------------------------------------------
  1392. /**
  1393. * Checks to see if the array to initialize a field is normalized or not
  1394. *
  1395. * @access protected
  1396. * @param array fields parameters
  1397. * @return string
  1398. */
  1399. protected function _has_defaults($vals)
  1400. {
  1401. return (!empty($vals['__DEFAULTS__']));
  1402. }
  1403. // --------------------------------------------------------------------
  1404. /**
  1405. * Looks at the field type attribute and determines which form field to render
  1406. *
  1407. * IMPORTANT! You probably shouldn't call this method from within a custom field type because it may create an infinite loop!
  1408. *
  1409. * @access public
  1410. * @param array fields parameters
  1411. * @param boolean should the normalization be ran again?
  1412. * @return string
  1413. */
  1414. public function create_field($params, $normalize = TRUE)
  1415. {
  1416. // needed to prevent runaway loops from custom fields... actually the template field type wont work with this
  1417. // if ($this->_rendering)
  1418. // {
  1419. // return FALSE;
  1420. // }
  1421. if ($normalize) $params = $this->normalize_params($params); // done again here in case you create a field without doing the render method
  1422. // now we look at all the fields that may represent other field types based on parameters
  1423. if (!empty($this->representatives) AND is_array($this->representatives) AND empty($params['ignore_representative']))
  1424. {
  1425. foreach($this->representatives as $key => $val)
  1426. {
  1427. $matched = FALSE;
  1428. // 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
  1429. if (is_array($val) AND is_string(key($val)))
  1430. {
  1431. foreach($val as $k => $v)
  1432. {
  1433. $matched = (is_array($v) AND in_array($params[$k], $v) OR (is_string($v) AND preg_match('#'.$v.'#', $params[$k]))) ? TRUE : FALSE;
  1434. if (!$matched)
  1435. {
  1436. break;
  1437. }
  1438. }
  1439. }
  1440. // if the representative is an array and the param type is in that array then we are a match
  1441. else if (is_array($val) AND in_array($params['type'], $val))
  1442. {
  1443. $matched = TRUE;
  1444. }
  1445. // if the representative is a string, then we do a regex to see if we are a match
  1446. else if (is_string($val) AND preg_match('#'.$val.'#', $params['type']))
  1447. {
  1448. $matched = TRUE;
  1449. }
  1450. // if we matched,then set the param type to it's representative and we break the loop and continue on
  1451. if ($matched)
  1452. {
  1453. $params['type'] = $key;
  1454. break;
  1455. }
  1456. }
  1457. }
  1458. $str = $this->_render_custom_field($params);
  1459. if (!$str)
  1460. {
  1461. switch($params['type'])
  1462. {
  1463. case 'none': case 'blank' :
  1464. $str = '';
  1465. break;
  1466. case 'custom':
  1467. $func = (isset($params['func'])) ? $params['func'] : function($params) { return (isset($params["value"])) ? $params["value"] : "" ; };
  1468. $str = $this->create_custom($func, $params);
  1469. break;
  1470. default :
  1471. $method = 'create_'.$params['type'];
  1472. if (method_exists($this, $method) AND $params['type'] != 'field')
  1473. {
  1474. $str = $this->$method($params);
  1475. }
  1476. else
  1477. {
  1478. $params['type'] = 'text';
  1479. $str = $this->create_text($params);
  1480. }
  1481. }
  1482. }
  1483. // cache the field types being rendered
  1484. $rendered_type = (!empty($matched)) ? $key : $params['type'];
  1485. $this->_rendered_field_types[$rendered_type] = $rendered_type;
  1486. // $this->_rendered_field_types[$params['type']] = $params['type'];
  1487. // add before/after html
  1488. $str = $params['before_html'].$str.$params['after_html'];
  1489. return $str;
  1490. }
  1491. // --------------------------------------------------------------------
  1492. /**
  1493. * Creates the label for the form
  1494. *
  1495. * By default, if no label value is given, the method will generate one
  1496. * based on the name of the field
  1497. *
  1498. * @access public
  1499. * @param array fields parameters
  1500. * @param boolean should the label be displayed?
  1501. * @return string
  1502. */
  1503. public function create_label($params, $use_label = TRUE)
  1504. {
  1505. if (is_string($params))
  1506. {
  1507. $params = array('label' => $params);
  1508. }
  1509. $params = $this->normalize_params($params);
  1510. $str = '';
  1511. if (isset($params['display_label']) AND $params['display_label'] === FALSE) return $str;
  1512. if (empty($params['label']))
  1513. {
  1514. if ($lang = $this->label_lang($params['orig_name']))
  1515. {
  1516. $params['label'] = $lang;
  1517. }
  1518. else
  1519. {
  1520. $params['label'] = ucfirst(str_replace('_', ' ', $params['orig_name']));
  1521. }
  1522. $label_words = explode(' ', $params['label']);
  1523. if (in_array(strtolower($label_words[0]), $this->question_keys))
  1524. {
  1525. $params['label'] .= '?';
  1526. }
  1527. }
  1528. $mode = (!empty($params['mode'])) ? $params['mode'] : $this->single_select_mode;
  1529. if (($params['type'] == 'enum' OR $params['type'] == 'multi' OR $params['type'] == 'array') AND ($mode == 'radios' OR ($mode == 'auto' AND count($params['options']) <= 2)))
  1530. {
  1531. $use_label = FALSE;
  1532. }
  1533. if ($use_label)
  1534. {
  1535. if (!empty($params['id']))
  1536. {
  1537. $id_name = $params['id'];
  1538. }
  1539. elseif (!empty($this->name_prefix))
  1540. {
  1541. $name_parts = explode($this->name_prefix.'--', $params['name']);
  1542. $id_name = $this->name_prefix.'--'.end($name_parts); // ugly... bug needed for nested repeatable fields
  1543. }
  1544. else
  1545. {
  1546. $id_name = $params['orig_name'];
  1547. }
  1548. $class = '';
  1549. if (isset($params['label_class']) AND !empty($params['label_class']))
  1550. {
  1551. $class = ' class="'.$params['label_class'].'"';
  1552. }
  1553. $styles = (isset($params['nowrap'])

Large files files are truncated, but you can click here to view the full file