render.inc

  1. 7.x includes/render.inc
  2. 6.x includes/render.inc
  3. 5.x includes/render.inc

File

includes/render.inc
View source
  1. <?php
  2. /*
  3. * This include file contains functions pertaining to the
  4. * creation of forms through FlightPath's form API
  5. */
  6. /**
  7. * This is very similar to fp_get_form / fp_render_form, except in this case we are being passed
  8. * the completed "render_array", which already contains all of our elements. We will call
  9. * hooks on it, sort by weights, and then return the rendered HTML.
  10. */
  11. function fp_render_content($render_array = array(), $bool_include_wrappers = TRUE) {
  12. $rtn = "";
  13. if (!isset($render_array["#id"])) {
  14. // An #id wasn't set, which is required, so we're going to
  15. // create one based on the function that called this function.
  16. $x = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
  17. $render_array['#id'] = trim(@$x[1]['class'] . "_" . @$x[1]['function']);
  18. // If nothing was discovered, just ditch it...
  19. if ($render_array['#id'] == "_") unset($render_array["#id"]);
  20. }
  21. // First, check to see if this render array has an "#id" field defined. This is required.
  22. $render_id = fp_get_machine_readable(fp_trim(@$render_array["#id"]));
  23. if ($render_id == "") {
  24. fp_add_message(t("The render array supplied does not have an #id field set. This must be
  25. machine-readable and unique.<br>Ex: \$arr['#id'] = 'advise_course_description_popup';
  26. <br>It may be easiest to simply name it after the function which is creating the render array."), "error");
  27. return "";
  28. }
  29. $class = trim((string) @$render_array['#class']);
  30. // Any hooks to alter this render array?
  31. $modules = modules_implement_hook("content_alter");
  32. foreach ($modules as $module) {
  33. call_user_func_array($module . '_content_alter', array(&$render_array, $render_id));
  34. }
  35. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  36. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  37. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  38. // The first the I want to do is find out, what are the defined weights in this form, if any.
  39. $defined_weights = array();
  40. foreach ($render_array as $key => $element) {
  41. // If we were just passed a string, treat it as plain HTML markup.
  42. if (!strstr($key, "#") && is_string($element)) {
  43. $element = array('value' => $element);
  44. $render_array[$key] = $element; // make sure we pick up any changes we've made
  45. }
  46. if (!is_array($element)) {
  47. continue;
  48. }
  49. if (!isset($element["weight"])) {
  50. $element["weight"] = 0;
  51. }
  52. $weight = (float)$element["weight"];
  53. if (!in_array($weight, $defined_weights)) {
  54. $defined_weights[] = $weight;
  55. }
  56. }
  57. // Okay, now sort our weights.
  58. sort($defined_weights);
  59. // Before we get to assigning weights, we need to make sure
  60. // that none of our form elements have a name which might cause us trouble.
  61. // Namely, no element can be named "submit" (like a button) because it will
  62. // interfere with our javascript functions.
  63. $form2 = array();
  64. foreach ($render_array as $key => $element) {
  65. $name = $key;
  66. if ($name == "submit") {
  67. $name = "btn_submit";
  68. }
  69. $form2[$name] = $element;
  70. }
  71. $form = $form2;
  72. // Okay, now go through the weights and create a new form in THAT order.
  73. $new_form = array();
  74. foreach ($defined_weights as $dw) {
  75. foreach ($form as $key => $element) {
  76. if (!is_array($element)) {
  77. $new_form[$key] = $element;
  78. continue;
  79. }
  80. if (!isset($element["weight"])) $element["weight"] = 0;
  81. $weight = (float)$element["weight"];
  82. if ($weight == $dw) {
  83. $new_form[$key] = $element;
  84. }
  85. }
  86. }
  87. // Okay, we should now be good to go!
  88. $render_array = $new_form;
  89. // We can now proceed with rendering this render_array. It will be similar to fp_render_form.
  90. if ($bool_include_wrappers) {
  91. $rtn .= "<div class='renderapi-content $class' id='render-$render_id'>";
  92. }
  93. $rtn .= fp_render_array($render_array);
  94. if ($bool_include_wrappers) {
  95. $rtn .= "</div>";
  96. }
  97. return $rtn;
  98. }
  99. /**
  100. * This takes a render_array and generates the HTML for it. This usually is not called directly, but
  101. * instead you should call fp_render_content() or fp_render_form()
  102. */
  103. function fp_render_array($render_array, $use_callback = "") {
  104. $rtn = "";
  105. foreach ($render_array as $name => $element) {
  106. if (is_array($element) && (isset($element["type"]) || isset($element["value"]))) {
  107. // Is this a fieldset or cfieldset (collapsible fieldset)?
  108. if (@$element["type"] == "cfieldset" || @$element["type"] == "fieldset") {
  109. $celements = $element["elements"]; // get our list of form elements within this fieldset.
  110. // Go through these new elements and prepare to display them inside a collapsible fieldset.
  111. $html = "";
  112. foreach ($celements as $k => $v) {
  113. foreach ($celements[$k] as $ename => $celement) {
  114. $html .= fp_render_element($ename, $celement, $use_callback);
  115. }
  116. }
  117. $description = trim($element['description'] ?? '');
  118. if ($description) {
  119. $html = "<div class='fieldset-description'>$description</div>" . $html;
  120. }
  121. if ($element['type'] == 'cfieldset') {
  122. // add to c_fieldset
  123. $rtn .= fp_render_c_fieldset($html, @$element["label"], @$element["start_closed"], @$element['attributes']['class']);
  124. }
  125. else {
  126. // This is a normal fielset.
  127. $machine_name = strtolower(fp_get_machine_readable($name));
  128. $rtn .= " <fieldset class='fp-fieldset' id='fs_$machine_name'>
  129. <legend>{$element['label']}</legend>
  130. <div id='fs_content_$machine_name' class='fieldset-content'>
  131. $html
  132. </div>
  133. </fieldset>";
  134. }
  135. }
  136. else {
  137. // No, this is a normal element. Not in a fieldset.
  138. $rtn .= fp_render_element($name, $element, $use_callback);
  139. }
  140. }
  141. }
  142. return $rtn;
  143. }
  144. /**
  145. * This function gets the form array, where the callback is the same as form_id.
  146. * It will also look for modules which may want to alter the form, using hook_form_alter,
  147. * and go ahead and apply that.
  148. *
  149. * It will also reorder the elements by weight.
  150. *
  151. */
  152. function fp_get_form($form_id, $params = array()) {
  153. $form = call_user_func_array($form_id, $params);
  154. // Add in the default submit_handlers and validate_handlers, if not all ready set.
  155. if (!isset($form["#submit_handlers"])) $form["#submit_handlers"] = array($form_id . "_submit");
  156. if (!isset($form["#validate_handlers"])) $form["#validate_handlers"] = array($form_id . "_validate");
  157. $modules = modules_implement_hook("form_alter");
  158. foreach ($modules as $module) {
  159. call_user_func_array($module . '_form_alter', array(&$form, $form_id));
  160. }
  161. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  162. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  163. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  164. // The first the I want to do is find out, what are the defined weights in this form, if any.
  165. $defined_weights = array();
  166. foreach ($form as $element) {
  167. if (!isset($element["weight"])) $element["weight"] = 0;
  168. $weight = (int)$element["weight"];
  169. if (!in_array($weight, $defined_weights)) {
  170. $defined_weights[] = $weight;
  171. }
  172. }
  173. // Okay, now sort our weights.
  174. sort($defined_weights);
  175. // Before we get to assigning weights, we need to make sure
  176. // that none of our form elements have a name which might cause us trouble.
  177. // Namely, no element can be named "submit" (like a button) because it will
  178. // interfere with our javascript functions.
  179. $form2 = array();
  180. foreach ($form as $key => $element) {
  181. $name = $key;
  182. if ($name == "submit") {
  183. $name = "btn_submit";
  184. }
  185. $form2[$name] = $element;
  186. }
  187. $form = $form2;
  188. // Okay, now go through the weights and create a new form in THAT order.
  189. $new_form = array();
  190. foreach ($defined_weights as $dw) {
  191. foreach ($form as $key => $element) {
  192. if (!isset($element["weight"])) $element["weight"] = 0;
  193. $weight = (int)$element["weight"];
  194. if ($weight == $dw) {
  195. $new_form[$key] = $element;
  196. }
  197. }
  198. }
  199. // Okay, we should now be good to go!
  200. return $new_form;
  201. }
  202. /**
  203. * Render the form array from the callback to the screen, and
  204. * set the form to save itself in our default submit handler.
  205. * Valid form_types are:
  206. * "system_settings" => values automatically saved to variables table.
  207. * "normal" or BLANK => values are sent to {$callback}_validate() and {$callback}_submit() function, if it exists.
  208. */
  209. function fp_render_form($callback, $form_type = "") {
  210. global $current_student_id, $user;
  211. $rtn = "";
  212. // Were there extra params after callback and form_type? Wrap them up
  213. // and send them along to fp_get_form
  214. $params = array();
  215. if (func_num_args() > 2) {
  216. // Remove first 2 arguments, so all we have left is what the user added to it.
  217. $params = func_get_args();
  218. array_shift($params);
  219. array_shift($params);
  220. }
  221. $form = fp_get_form($callback, $params);
  222. // Base64 enc the params, so we can easily handle if there are quotation marks, line breaks, etc.
  223. $form_params = base64_encode(serialize($params));
  224. // Figure out the current page's title and display it.
  225. $path = fp_no_html_xss($_GET["q"]); // Sanitize _GET valuses.
  226. $default_path = $path;
  227. $default_query = "";
  228. // Figure out the "default_query" from $_GET
  229. $new_query = array();
  230. foreach ($_GET as $key => $val) {
  231. // Sanitize since it is coming from _GET.
  232. $key = fp_no_html_xss($key);
  233. $val = fp_no_html_xss($val);
  234. if ($key != "q" && $key != "scroll_top") {
  235. $new_query[] = "$key=$val";
  236. }
  237. }
  238. if (count($new_query)) {
  239. $default_query = join("&", $new_query);
  240. }
  241. $page_title = $GLOBALS["fp_current_menu_router_item"]["title"];
  242. if (isset($GLOBALS["fp_set_title"])) {
  243. $page_title = $GLOBALS["fp_set_title"];
  244. }
  245. if ($page_title != "") {
  246. fp_show_title(TRUE);
  247. }
  248. $form_path = $GLOBALS["fp_current_menu_router_item"]["path"];
  249. // Are there any files required to get to the submit handler for this form?
  250. $form_include = "";
  251. // Set the form_include to the current page's "file" requirement, if any.
  252. if (is_array($GLOBALS["fp_current_menu_router_item"])) {
  253. if (isset($GLOBALS["fp_current_menu_router_item"]["file"])) {
  254. $form_include = $GLOBALS["fp_current_menu_router_item"]["file"];
  255. }
  256. }
  257. if (@$form["#form_include"]) {
  258. $form_include = $form["#form_include"];
  259. }
  260. $extra_form_class = "";
  261. if ($form_type == "system_settings") {
  262. $extra_form_class = "fp-system-form";
  263. }
  264. $form_token = md5($callback . fp_token());
  265. // Set up our form's attributes.
  266. $attributes = @$form["#attributes"];
  267. if (!is_array($attributes)) $attributes = array();
  268. if (!isset($attributes["class"])) $attributes["class"] = "";
  269. $attributes["class"] .= " $extra_form_class fp-form fp-form-$callback ";
  270. // Convert the attributes array into a string.
  271. $new_attr = "";
  272. foreach ($attributes as $key => $val) {
  273. $new_attr .= " $key='$val' ";
  274. }
  275. $attributes = $new_attr;
  276. // Did the user specify a submit method (like GET or POST)? POST is default.
  277. $submit_method = (@$form["#submit_method"] == "") ? "POST" : $form["#submit_method"];
  278. // If the window_mode has been set in the _GET, then include it as a query in the fp_url() function. But force it to either be "popup" or another valid option.
  279. $url_query = "";
  280. if (isset($_GET['window_mode']) && $_GET['window_mode'] == 'popup') {
  281. $url_query = "window_mode=popup";
  282. }
  283. $form_q_64 = base64_encode($_REQUEST['q']); // what was q set to when this form was rendered?
  284. $rtn .= "<form action='" . fp_url("system-handle-form-submit", $url_query, TRUE) . "' method='$submit_method' id='fp-form-$callback' name='fp_form_name_$callback' $attributes>";
  285. $rtn .= "<input type='hidden' name='callback' value='$callback'>";
  286. $rtn .= "<input type='hidden' name='form_token' value='$form_token'>";
  287. $rtn .= "<input type='hidden' name='form_type' value='$form_type'>";
  288. $rtn .= "<input type='hidden' name='form_path' value='$form_path'>";
  289. $rtn .= "<input type='hidden' name='form_q_64' value='$form_q_64'>";
  290. $rtn .= "<input type='hidden' name='form_params' value='$form_params'>";
  291. $rtn .= "<input type='hidden' name='form_include' value='$form_include'>";
  292. $rtn .= "<input type='hidden' name='default_redirect_path' value='$default_path'>";
  293. $rtn .= "<input type='hidden' name='default_redirect_query' value='$default_query'>";
  294. $rtn .= "<input type='hidden' name='current_student_id' value='$current_student_id'>";
  295. /* // Note: This bit doesn't make a difference right now, because it's only in the "render_form" function.
  296. * // All of these values need to be in the "get_form" function, in order for them to be detected if someone tries
  297. * // to change them.
  298. // Instead of using hidden input types (which can be modified by malicious actors),
  299. // we will use "values" added to the form itself.
  300. $form['callback'] = ['type' => 'value', 'value' => $callback];
  301. $form['form_token'] = ['type' => 'value', 'value' => $form_token];
  302. $form['form_type'] = ['type' => 'value', 'value' => $form_type];
  303. $form['form_path'] = ['type' => 'value', 'value' => $form_path];
  304. $form['form_q_64'] = ['type' => 'value', 'value' => $form_q_64];
  305. $form['form_params'] = ['type' => 'value', 'value' => $form_params];
  306. $form['form_include'] = ['type' => 'value', 'value' => $form_include];
  307. $form['default_redirect_path'] = ['type' => 'value', 'value' => $default_path];
  308. $form['default_redirect_query'] = ['type' => 'value', 'value' => $default_query];
  309. $form['current_student_id'] = ['type' => 'value', 'value' => $current_student_id];
  310. */
  311. $use_callback = "";
  312. if (form_has_errors()) {
  313. // We will only pull previous POST's values if there are errors on the form.
  314. $use_callback = $callback;
  315. }
  316. $rtn .= fp_render_array($form, $use_callback);
  317. // If this is a system settings form, go ahead and display the save button.
  318. if ($form_type == "system_settings") {
  319. $rtn .= "<div class='buttons form-element element-type-submit'>";
  320. $rtn .= "<input type='submit' name='submit_button' value='" . t("Save settings") . "'>";
  321. $rtn .= "</div>";
  322. }
  323. $rtn .= "</form>";
  324. // Clear any existing form errors and values
  325. unset($_SESSION["fp_form_errors"]);
  326. clear_session_form_values($callback);
  327. return $rtn;
  328. }
  329. /**
  330. * Clear the form submissions variable from the SESSION for this callback.
  331. */
  332. function clear_session_form_values($callback) {
  333. unset($_SESSION["fp_form_submissions"][$callback]);
  334. }
  335. /**
  336. * This is a very basic validator for form API submission.
  337. * All I really care about is making sure required fields have
  338. * a value in them. If they do not, we will file a form_error.
  339. */
  340. function form_basic_validate($form, $form_state) {
  341. $label = '';
  342. foreach ($form as $name => $element) {
  343. if (is_array($element) && @$element["required"]) {
  344. // Okay, this is a required field. So, check that it has a non-blank value
  345. // in form_submitted.
  346. if ($form_state["values"][$name] == "") {
  347. // It's blank! ERROR!
  348. $label = $element["label"];
  349. if ($label == "") $label = $name;
  350. form_error($name, t("You must enter a value for <b>%element_label</b>.", array("%element_label" => $label)));
  351. }
  352. } // if is_array element and required
  353. if (is_array($element) && isset($element['type']) && $element['type'] == 'value') {
  354. $should_be_value = @trim($form[$name]['value']);
  355. $found_value = @trim($form_state['values'][$name]);
  356. if ($should_be_value !== $found_value) {
  357. form_error('', t("Invalid value found in form, possible hacking attempt or bug. This incident has been logged.", array("%element_label" => $label)));
  358. watchdog('system', "Invalid value found in form, possible hacking attempt or bug. Should be value: '$should_be_value', Found value: '$found_value' ", array(), WATCHDOG_ERROR);
  359. }
  360. } // if element is of type "value"
  361. }
  362. }
  363. /**
  364. * Register a form_error in the SESSION.
  365. *
  366. * If bool_stop_futher_validators is set to TRUE, then (in system_handle_form_submit) we will
  367. * not continue with any other form validators which may be present.
  368. *
  369. */
  370. function form_error($element_name, $message, $bool_stop_further_validators = FALSE) {
  371. $_SESSION["fp_form_errors"][] = array("name" => $element_name, "msg" => $message);
  372. fp_add_message($message, "error");
  373. if ($bool_stop_further_validators) {
  374. $GLOBALS['form_error_stop_further_validators'] = TRUE;
  375. }
  376. }
  377. /**
  378. * Returns TRUE or FALSE if there have been errors for this form submission
  379. * (We will just look in the SESSION to find out).
  380. */
  381. function form_has_errors() {
  382. if (!isset($_SESSION["fp_form_errors"]) || !is_array($_SESSION["fp_form_errors"])) return FALSE;
  383. if (@count($_SESSION["fp_form_errors"]) > 0) {
  384. return TRUE;
  385. }
  386. return FALSE;
  387. }
  388. /**
  389. * Returns the HTML to render this form (or content) element to the screen.
  390. * $name is the HTML machine name. $element is an array containing all we need to render it.
  391. * If you want default values to be taken from the SESSION (because we had form_errors, say, and we
  392. * want values to keep what we had between submissions) specify the callback to use in the
  393. * use_session_submission_values_for_callback variable.
  394. */
  395. function fp_render_element($name, $element, $use_session_submission_values_for_callback = "") {
  396. $rtn = "";
  397. $type = @$element["type"];
  398. if ($type == "") $type = "markup_no_wrappers";
  399. // Make sure the "css name" is friendly.
  400. $cssname = fp_get_machine_readable($name);
  401. if ($type == "do_not_render") return; // not supposed to render this element.
  402. // Does the name start with a # character? If so, do not attempt to render.
  403. if (substr($name, 0, 1) == "#") return;
  404. $value = @$element["value"];
  405. $label = @$element["label"];
  406. $options = @$element["options"];
  407. $description = @$element["description"];
  408. $popup_description = @$element["popup_description"];
  409. $prefix = @$element["prefix"];
  410. $suffix = @$element["suffix"];
  411. $multiple = @$element["multiple"];
  412. $spinner = @$element["spinner"];
  413. $inline = @$element['inline'] ?? FALSE;
  414. if ($multiple == TRUE) {
  415. $multiple = "multiple=multiple";
  416. }
  417. else {
  418. $multiple = "";
  419. }
  420. $autocomplete_path = @$element["autocomplete_path"];
  421. $required = @$element["required"];
  422. $no_please_select = @$element["no_please_select"];
  423. if (isset($element["hide_please_select"])) {
  424. $no_please_select = @$element["hide_please_select"];
  425. }
  426. $confirm = @$element["confirm"];
  427. // Let's also add our cssname as a class to the element, so that even markup will get it...
  428. if ($type == "markup") {
  429. if (!isset($element["attributes"]) || is_array($element["attributes"])) {
  430. @$element["attributes"]["class"] .= " markup-element form-element markup-element-$cssname";
  431. }
  432. }
  433. $attributes = $element["attributes"] ?? array();
  434. if (!is_array($attributes)) {
  435. $attributes = array();
  436. $attributes['style'] = '';
  437. $attributes['class'] = '';
  438. }
  439. if (!isset($attributes['class'])) $attributes['class'] = '';
  440. if (!isset($attributes['style'])) $attributes['style'] = '';
  441. if ($type == 'textarea_editor') {
  442. // Add the "html-editor" class to attributes.
  443. $attributes['class'] .= ' html-editor';
  444. }
  445. if ($spinner) {
  446. $attributes['class'] .= " show-spinner ";
  447. }
  448. $popup_help_link = "";
  449. if ($popup_description) {
  450. //$popup_help_link = " <a href='javascript: alert(\"" . $popup_description . "\");' class='form-popup-description'>[?]</a>";
  451. $popup_help_link = fp_get_js_alert_link($popup_description, NULL, "form-popup-description");
  452. }
  453. $element_error_css = "";
  454. if (isset($_SESSION["fp_form_errors"]) && is_array($_SESSION["fp_form_errors"])) {
  455. foreach ($_SESSION["fp_form_errors"] as $err) {
  456. if ($err["name"] == $name) {
  457. // There is an error on this element! Add an extra CSS element.
  458. $element_error_css .= " form-element-error ";
  459. }
  460. }
  461. }
  462. if ($use_session_submission_values_for_callback && is_array(@$_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"])) {
  463. // Check the SESSION for a previous value which we should use.
  464. $ignore_types = array("hidden", "markup", "markup_no_wrappers", "submit", "password");
  465. if (!in_array($type, $ignore_types)) {
  466. $value = $_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"][$name];
  467. }
  468. }
  469. if ($type == "markup" && $element_error_css) {
  470. if (is_array($attributes)) {
  471. $attributes['class'] .= $element_error_css;
  472. }
  473. }
  474. $extra_wrapper_class = ""; // We will give the wrapper a similar class as are defined in attributes, if any.
  475. if (is_array($attributes)) {
  476. // Convert the attributes array into a string.
  477. $new_attr = "";
  478. foreach ($attributes as $key => $val) {
  479. $new_attr .= " $key='$val' ";
  480. if ($key == 'class') {
  481. $extra_wrapper_class .= " element-wrapper--" . trim($val);
  482. }
  483. }
  484. $attributes = $new_attr;
  485. }
  486. if ($inline === TRUE) {
  487. $extra_wrapper_class .= " element-inline-element";
  488. }
  489. if ($type != "markup" && $type != "markup_no_wrappers" && $type != 'value') {
  490. $rtn .= "<div id='element-wrapper-$cssname' class='form-element element-type-$type $extra_wrapper_class'>";
  491. }
  492. if ($prefix) {
  493. $rtn .= $prefix;
  494. }
  495. if ($type != "markup" && $type != "markup_no_wrappers" && $type != 'value') {
  496. $rtn .= "<div id='element-inner-wrapper-$cssname' class='form-element element-type-$type $element_error_css'>";
  497. }
  498. if ($type == 'datetime-local') {
  499. // As of the time of this comment (8-16-2021) FireFox STILL does not support datetime-local as a field type for their desktop browser,
  500. // even though they support it for mobile. Every other modern browser supports it as well.
  501. // Anyway, we will need to include a workaround in jquery as a result if this field is being used:
  502. fp_add_js(fp_get_module_path("system") . '/lib/jquery.datetimepicker/jquery.datetimepicker.min.js');
  503. fp_add_css(fp_get_module_path("system") . '/lib/jquery.datetimepicker/jquery.datetimepicker.min.css');
  504. fp_add_js(fp_get_module_path("system") . '/lib/fp_datetimepicker_shim/fp_datetimepicker_shim.js');
  505. }
  506. $ast = "";
  507. if ($required) {
  508. $ast = "<span class='form-required-ast'>*</span>";
  509. }
  510. // First of all, what is it's "type"?
  511. if ($type == "markup") {
  512. if (is_string($attributes) && $attributes != "") {
  513. $rtn .= "<div $attributes>";
  514. }
  515. // If a label is set, go ahead and display, even though its markup...
  516. if ($label != "") {
  517. $rtn .= "<label>$ast$label$popup_help_link</label>";
  518. }
  519. $rtn .= $value;
  520. if (is_string($attributes) && $attributes != "") {
  521. $rtn .= "</div>";
  522. }
  523. }
  524. else if ($type == "markup_no_wrappers") {
  525. // If a label is set, go ahead and display, even though its markup...
  526. if ($label != "") {
  527. $rtn .= "<label>$ast$label$popup_help_link</label>";
  528. }
  529. $rtn .= $value; // plain value, no wrapper divs at all.
  530. }
  531. else if ($type != "hidden" && $type != 'value' && $type != "checkbox") {
  532. $rtn .= "<label>$ast$label$popup_help_link</label>";
  533. }
  534. if ($type == "textarea" || $type == 'textarea_editor') {
  535. $rows = (isset($element["rows"])) ? $element["rows"] : "5";
  536. $maxlength = (isset($element["maxlength"])) ? $element["maxlength"] : "";
  537. $extra_span = "";
  538. // if maxlength is set, then we want to show the char count upon change.
  539. if ($maxlength != "") {
  540. fp_add_css(fp_get_module_path('system') . '/css/style.css');
  541. fp_add_js(fp_get_module_path('system') . '/js/textarea-maxlength.js');
  542. $extra_span = "<span class='textarea-maxlength-count' id='textarea-maxlength-count___$cssname'>
  543. <span class='current-count' id='element-{$cssname}__current_count'>0</span>/<span class='maxlength-chars'>$maxlength</span>
  544. <span class='maxlength-description'>" . t("Max Characters") . "</span>
  545. </span>";
  546. }
  547. $rtn .= "<textarea name='$name' id='element-$cssname' rows='$rows' maxlength='$maxlength' $attributes>$value</textarea>$extra_span";
  548. }
  549. if ($type == "textfield" || $type == "text" || $type == "search" || $type == "password" || $type == 'datetime-local' || $type == 'time' || $type == 'date') {
  550. if ($type == "textfield") $type = "text";
  551. $size = (isset($element["size"])) ? $element["size"] : "60";
  552. $maxlength = (isset($element["maxlength"])) ? $element["maxlength"] : "255";
  553. // if there is an autocomplete_path, we need to include some javascript.
  554. if ($autocomplete_path != "") {
  555. fp_add_js(array("autocomplete_fields" => array(array("id" => "element-$cssname", "path" => $autocomplete_path))), 'setting');
  556. }
  557. $value = htmlentities((string) $value, ENT_QUOTES);
  558. $rtn .= "<input type='$type' name='$name' id='element-$cssname' size='$size' maxlength='$maxlength' value='$value' $attributes>";
  559. }
  560. if ($type == "hidden" || $type == "value") {
  561. if (!$value) $value = ''; // Force it to be a string
  562. $value = htmlentities($value, ENT_QUOTES);
  563. $rtn .= "<input type='hidden' name='$name' id='element-$cssname' value='$value' data-type='$type'>";
  564. }
  565. if ($type == "file") {
  566. $tname = $name;
  567. // Always going to put [] for a file, no matter what.
  568. //if ($multiple != "") {
  569. $tname .= "[]"; // if we allow uploading multiple files, we MUST put a [] behind it, or HTML will not upload correctly. Weird but true.
  570. //}
  571. $rtn .= "<input type='file' name='$tname' id='element-$cssname' $multiple $attributes>";
  572. }
  573. if ($type == "select") {
  574. $rtn .= "<select name='$name' id='element-$cssname' $attributes>";
  575. if ($no_please_select != TRUE) {
  576. $rtn .= "<option value=''>- Please select -</option>";
  577. }
  578. foreach ($options as $key => $val) {
  579. if (is_array($val)) {
  580. // We need to establish an optgroup and then descend one level.
  581. $rtn .= "<optgroup label='" . htmlentities($key) . "'>";
  582. foreach ($val as $k => $v) {
  583. $selected = "";
  584. if ($value == $k) {
  585. $selected = "selected";
  586. }
  587. $rtn .= "<option value='$k' $selected>$v</option>";
  588. }
  589. $rtn .= "</optgroup>";
  590. }
  591. else {
  592. // This is just a normal string, so we can continue as-is
  593. $selected = "";
  594. if ($value == $key) {
  595. $selected = "selected";
  596. }
  597. $rtn .= "<option value='$key' $selected>$val</option>";
  598. }
  599. }
  600. $rtn .= "</select>";
  601. }
  602. // Multiple checkboxes...
  603. if ($type == "checkboxes") {
  604. $rtn .= "<div class='form-checkboxes form-checkboxes-$cssname'>";
  605. foreach ($options as $key => $val) {
  606. if (is_array($val)) {
  607. // Similar to select lists above, we need to simulate having "optgroup"s for checkboxes.
  608. $rtn .= "<div class='checkbox-pseudo-optgroup-wrapper'>
  609. <label>$key</label>";
  610. foreach ($val as $k => $v) {
  611. $checked = "";
  612. if (is_array($value) && isset($value[$k]) && $value[$k] == $k) {
  613. $checked = "checked=checked";
  614. }
  615. $csskey = fp_get_machine_readable($key . '_' . $k);
  616. $rtn .= "<div class='checkbox-element checkbox-element-$csskey'>
  617. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$k]' id='element-$cssname-$csskey' value='$k' $checked $attributes> $v</label>
  618. </div>";
  619. }
  620. $rtn .= "</div>"; // close the pseudo-optgroup-wrapper
  621. }
  622. else {
  623. $checked = "";
  624. if (is_array($value) && isset($value[$key]) && $value[$key] == $key) {
  625. $checked = "checked=checked";
  626. }
  627. $csskey = fp_get_machine_readable($key);
  628. $rtn .= "<div class='checkbox-element checkbox-element-$csskey'>
  629. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$key]' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  630. </div>";
  631. }
  632. }
  633. $rtn .= "</div>";
  634. }
  635. if ($type == "radios") {
  636. $rtn .= "<div class='form-radios form-radios-$cssname'>";
  637. foreach ($options as $key => $val) {
  638. $checked = "";
  639. if (is_array($val)) {
  640. // Similar to select lists above, we need to simulate having "optgroup"s for checkboxes.
  641. $rtn .= "<div class='radio-pseudo-optgroup-wrapper'>
  642. <label>$key</label>";
  643. foreach ($val as $k => $v) {
  644. $checked = "";
  645. // For radios, it's possible we've been sent an array for the value (though a string is more common and prefered).
  646. // We need to check both.
  647. if (is_array($value) && isset($value[$k]) && $value[$k] == $k) {
  648. $checked = "checked=checked";
  649. }
  650. else if (!is_array($value) && $value == $k) {
  651. $checked = "checked=checked";
  652. }
  653. $csskey = fp_get_machine_readable($key . '_' . $k);
  654. $rtn .= "<div class='radio-element radio-element-$csskey'>
  655. <label class='label-for-radio'><input type='radio' name='$name' id='element-$cssname-$csskey' value='$k' $checked $attributes> $v</label>
  656. </div>";
  657. } // foreach val
  658. $rtn .= "</div>"; // close the pseudo-optgroup-wrapper
  659. } // if isarray val
  660. else {
  661. // For radios, it's possible we've been sent an array for the value (though a string is more common and prefered).
  662. // We need to check both.
  663. if (is_array($value) && isset($value[$key]) && $value[$key] == $key) {
  664. $checked = "checked=checked";
  665. }
  666. else if (!is_array($value) && $value == $key) {
  667. $checked = "checked=checked";
  668. }
  669. $csskey = fp_get_machine_readable($key);
  670. $rtn .= "<div class='radio-element radio-element-$csskey'>
  671. <label class='label-for-radio'><input type='radio' name='$name' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  672. </div>";
  673. } // else
  674. } // foreach options
  675. $rtn .= "</div>";
  676. } // if radios
  677. // A single checkbox... The values will be with 0 (zero) or 1 (one), and boolean
  678. // values are accepted/saved
  679. if ($type == "checkbox") {
  680. $rtn .= "<div class='form-checkbox form-checkbox-$cssname'>";
  681. $checked = "";
  682. if ((bool)($value) == TRUE) {
  683. $checked = "checked=checked";
  684. }
  685. $rtn .= "<div class='checkbox-element'>
  686. <label class='label-for-checkbox'><input type='checkbox' name='$name' id='element-$cssname' value='1' $checked $attributes> $label$popup_help_link</label>
  687. </div>";
  688. $rtn .= "</div>";
  689. }
  690. if ($type == "submit") {
  691. if ($confirm != "") {
  692. $confirm = htmlentities($confirm, ENT_QUOTES);
  693. $confirm = str_replace("\n", "\\n", $confirm);
  694. //$attributes .= " onClick='return confirm(\"$confirm\");' ";
  695. $attributes .= " onClick='return fp_confirm_form_submit(event, \"$confirm\");' ";
  696. }
  697. $rtn .= "<input type='$type' name='$name' value='$value' $attributes>";
  698. }
  699. if ($type == "button") {
  700. $rtn .= "<input type='button' name='$name' value='$value' $attributes>";
  701. }
  702. if ($spinner) {
  703. fp_add_css(fp_get_module_path("system") . "/css/style.css");
  704. fp_add_js(fp_get_module_path("system") . "/js/spinner.js");
  705. $rtn .= "<span class='loading-spinner loading-spinner-$name' style='display:none;'></span>";
  706. }
  707. if ($description) {
  708. $rtn .= "<div class='form-element-description'>$description</div>";
  709. }
  710. if ($type != "markup" && $type != 'markup_no_wrappers' && $type != 'value') {
  711. $rtn .= "</div>"; // close the inner wrapper
  712. }
  713. if ($suffix) {
  714. $rtn .= $suffix;
  715. }
  716. if ($type != "markup" && $type != 'markup_no_wrappers' && $type != 'value') {
  717. $rtn .= "</div>"; // close the over-all wrapper
  718. }
  719. return $rtn;
  720. }

Functions

Namesort descending Description
clear_session_form_values Clear the form submissions variable from the SESSION for this callback.
form_basic_validate This is a very basic validator for form API submission. All I really care about is making sure required fields have a value in them. If they do not, we will file a form_error.
form_error Register a form_error in the SESSION.
form_has_errors Returns TRUE or FALSE if there have been errors for this form submission (We will just look in the SESSION to find out).
fp_get_form This function gets the form array, where the callback is the same as form_id. It will also look for modules which may want to alter the form, using hook_form_alter, and go ahead and apply that.
fp_render_array This takes a render_array and generates the HTML for it. This usually is not called directly, but instead you should call fp_render_content() or fp_render_form()
fp_render_content This is very similar to fp_get_form / fp_render_form, except in this case we are being passed the completed "render_array", which already contains all of our elements. We will call hooks on it, sort by weights, and then return the rendered…
fp_render_element Returns the HTML to render this form (or content) element to the screen. $name is the HTML machine name. $element is an array containing all we need to render it. If you want default values to be taken from the SESSION (because we had form_errors,…
fp_render_form Render the form array from the callback to the screen, and set the form to save itself in our default submit handler. Valid form_types are: "system_settings" => values automatically saved to variables table. "normal" or BLANK…