render.inc

  1. 6.x includes/render.inc
  2. 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(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(@$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 cfieldset (collapsible fieldset)?
  108. if (@$element["type"] == "cfieldset") {
  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 $name => $celement) {
  114. $html .= fp_render_element($name, $celement, $use_callback);
  115. }
  116. }
  117. // add to c_fieldset
  118. $rtn .= fp_render_c_fieldset($html, @$element["label"], @$element["start_closed"], @$element['attributes']['class']);
  119. }
  120. else {
  121. // No, this is a normal element. Not in a fieldset.
  122. $rtn .= fp_render_element($name, $element, $use_callback);
  123. }
  124. }
  125. }
  126. return $rtn;
  127. }
  128. /**
  129. * This function gets the form array, where the callback is the same as form_id.
  130. * It will also look for modules which may want to alter the form, using hook_form_alter,
  131. * and go ahead and apply that.
  132. *
  133. * It will also reorder the elements by weight.
  134. *
  135. */
  136. function fp_get_form($form_id, $params = array()) {
  137. $form = call_user_func_array($form_id, $params);
  138. // Add in the default submit_handlers and validate_handlers, if not all ready set.
  139. if (!isset($form["#submit_handlers"])) $form["#submit_handlers"] = array($form_id . "_submit");
  140. if (!isset($form["#validate_handlers"])) $form["#validate_handlers"] = array($form_id . "_validate");
  141. $modules = modules_implement_hook("form_alter");
  142. foreach ($modules as $module) {
  143. call_user_func_array($module . '_form_alter', array(&$form, $form_id));
  144. }
  145. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  146. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  147. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  148. // The first the I want to do is find out, what are the defined weights in this form, if any.
  149. $defined_weights = array();
  150. foreach ($form as $element) {
  151. if (!isset($element["weight"])) $element["weight"] = 0;
  152. $weight = (int)$element["weight"];
  153. if (!in_array($weight, $defined_weights)) {
  154. $defined_weights[] = $weight;
  155. }
  156. }
  157. // Okay, now sort our weights.
  158. sort($defined_weights);
  159. // Before we get to assigning weights, we need to make sure
  160. // that none of our form elements have a name which might cause us trouble.
  161. // Namely, no element can be named "submit" (like a button) because it will
  162. // interfere with our javascript functions.
  163. $form2 = array();
  164. foreach ($form as $key => $element) {
  165. $name = $key;
  166. if ($name == "submit") {
  167. $name = "btn_submit";
  168. }
  169. $form2[$name] = $element;
  170. }
  171. $form = $form2;
  172. // Okay, now go through the weights and create a new form in THAT order.
  173. $new_form = array();
  174. foreach ($defined_weights as $dw) {
  175. foreach ($form as $key => $element) {
  176. if (!isset($element["weight"])) $element["weight"] = 0;
  177. $weight = (int)$element["weight"];
  178. if ($weight == $dw) {
  179. $new_form[$key] = $element;
  180. }
  181. }
  182. }
  183. // Okay, we should now be good to go!
  184. return $new_form;
  185. }
  186. /**
  187. * Render the form array from the callback to the screen, and
  188. * set the form to save itself in our default submit handler.
  189. * Valid form_types are:
  190. * "system_settings" => values automatically saved to variables table.
  191. * "normal" or BLANK => values are sent to {$callback}_validate() and {$callback}_submit() function, if it exists.
  192. */
  193. function fp_render_form($callback, $form_type = "") {
  194. global $current_student_id, $user;
  195. $rtn = "";
  196. // Were there extra params after callback and form_type? Wrap them up
  197. // and send them along to fp_get_form
  198. $params = array();
  199. if (func_num_args() > 2) {
  200. // Remove first 2 arguments, so all we have left is what the user added to it.
  201. $params = func_get_args();
  202. array_shift($params);
  203. array_shift($params);
  204. }
  205. $form = fp_get_form($callback, $params);
  206. // Base64 enc the params, so we can easily handle if there are quotation marks, line breaks, etc.
  207. $form_params = base64_encode(serialize($params));
  208. // Figure out the current page's title and display it.
  209. $path = fp_no_html_xss($_GET["q"]); // Sanitize _GET valuses.
  210. $default_path = $path;
  211. $default_query = "";
  212. // Figure out the "default_query" from $_GET
  213. $new_query = array();
  214. foreach ($_GET as $key => $val) {
  215. // Sanitize since it is coming from _GET.
  216. $key = fp_no_html_xss($key);
  217. $val = fp_no_html_xss($val);
  218. if ($key != "q" && $key != "scroll_top") {
  219. $new_query[] = "$key=$val";
  220. }
  221. }
  222. if (count($new_query)) {
  223. $default_query = join("&", $new_query);
  224. }
  225. $page_title = $GLOBALS["fp_current_menu_router_item"]["title"];
  226. if (isset($GLOBALS["fp_set_title"])) {
  227. $page_title = $GLOBALS["fp_set_title"];
  228. }
  229. if ($page_title != "") {
  230. fp_show_title(TRUE);
  231. }
  232. $form_path = $GLOBALS["fp_current_menu_router_item"]["path"];
  233. // Are there any files required to get to the submit handler for this form?
  234. $form_include = "";
  235. // Set the form_include to the current page's "file" requirement, if any.
  236. if (is_array($GLOBALS["fp_current_menu_router_item"])) {
  237. if (isset($GLOBALS["fp_current_menu_router_item"]["file"])) {
  238. $form_include = $GLOBALS["fp_current_menu_router_item"]["file"];
  239. }
  240. }
  241. if (@$form["#form_include"]) {
  242. $form_include = $form["#form_include"];
  243. }
  244. $extra_form_class = "";
  245. if ($form_type == "system_settings") {
  246. $extra_form_class = "fp-system-form";
  247. }
  248. $form_token = md5($callback . fp_token());
  249. // Set up our form's attributes.
  250. $attributes = @$form["#attributes"];
  251. if (!is_array($attributes)) $attributes = array();
  252. if (!isset($attributes["class"])) $attributes["class"] = "";
  253. $attributes["class"] .= " $extra_form_class fp-form fp-form-$callback ";
  254. // Convert the attributes array into a string.
  255. $new_attr = "";
  256. foreach ($attributes as $key => $val) {
  257. $new_attr .= " $key='$val' ";
  258. }
  259. $attributes = $new_attr;
  260. // Did the user specify a submit method (like GET or POST)? POST is default.
  261. $submit_method = (@$form["#submit_method"] == "") ? "POST" : $form["#submit_method"];
  262. // 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.
  263. $url_query = "";
  264. if (isset($_GET['window_mode']) && $_GET['window_mode'] == 'popup') {
  265. $url_query = "window_mode=popup";
  266. }
  267. $form_q_64 = base64_encode($_REQUEST['q']); // what was q set to when this form was rendered?
  268. $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>";
  269. $rtn .= "<input type='hidden' name='callback' value='$callback'>";
  270. $rtn .= "<input type='hidden' name='form_token' value='$form_token'>";
  271. $rtn .= "<input type='hidden' name='form_type' value='$form_type'>";
  272. $rtn .= "<input type='hidden' name='form_path' value='$form_path'>";
  273. $rtn .= "<input type='hidden' name='form_q_64' value='$form_q_64'>";
  274. $rtn .= "<input type='hidden' name='form_params' value='$form_params'>";
  275. $rtn .= "<input type='hidden' name='form_include' value='$form_include'>";
  276. $rtn .= "<input type='hidden' name='default_redirect_path' value='$default_path'>";
  277. $rtn .= "<input type='hidden' name='default_redirect_query' value='$default_query'>";
  278. $rtn .= "<input type='hidden' name='current_student_id' value='$current_student_id'>";
  279. $use_callback = "";
  280. if (form_has_errors()) {
  281. // We will only pull previous POST's values if there are errors on the form.
  282. $use_callback = $callback;
  283. }
  284. $rtn .= fp_render_array($form, $use_callback);
  285. // If this is a system settings form, go ahead and display the save button.
  286. if ($form_type == "system_settings") {
  287. $rtn .= "<div class='buttons form-element element-type-submit'>";
  288. $rtn .= "<input type='submit' name='submit_button' value='" . t("Save settings") . "'>";
  289. $rtn .= "</div>";
  290. }
  291. $rtn .= "</form>";
  292. // Clear any existing form errors and values
  293. unset($_SESSION["fp_form_errors"]);
  294. clear_session_form_values($callback);
  295. return $rtn;
  296. }
  297. /**
  298. * Clear the form submissions variable from the SESSION for this callback.
  299. */
  300. function clear_session_form_values($callback) {
  301. unset($_SESSION["fp_form_submissions"][$callback]);
  302. }
  303. /**
  304. * This is a very basic validator for form API submission.
  305. * All I really care about is making sure required fields have
  306. * a value in them. If they do not, we will file a form_error.
  307. */
  308. function form_basic_validate($form, $form_state) {
  309. foreach ($form as $name => $element) {
  310. if (is_array($element) && @$element["required"]) {
  311. // Okay, this is a required field. So, check that it has a non-blank value
  312. // in form_submitted.
  313. if ($form_state["values"][$name] == "") {
  314. // It's blank! ERROR!
  315. $label = $element["label"];
  316. if ($label == "") $label = $name;
  317. form_error($name, t("You must enter a value for <b>%element_label</b>.", array("%element_label" => $label)));
  318. }
  319. } // if is_array element and required
  320. if (is_array($element) && isset($element['type']) && $element['type'] == 'value') {
  321. $should_be_value = @trim($form[$name]['value']);
  322. $found_value = @trim($form_state['values'][$name]);
  323. if ($should_be_value !== $found_value) {
  324. form_error('', t("Invalid value found in form, possible hacking attempt or bug. This incident has been logged.", array("%element_label" => $label)));
  325. 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);
  326. }
  327. } // if element is of type "value"
  328. }
  329. }
  330. /**
  331. * Register a form_error in the SESSION.
  332. */
  333. function form_error($element_name, $message) {
  334. $_SESSION["fp_form_errors"][] = array("name" => $element_name, "msg" => $message);
  335. fp_add_message($message, "error");
  336. }
  337. /**
  338. * Returns TRUE or FALSE if there have been errors for this form submission
  339. * (We will just look in the SESSION to find out).
  340. */
  341. function form_has_errors() {
  342. if (!isset($_SESSION["fp_form_errors"]) || !is_array($_SESSION["fp_form_errors"])) return FALSE;
  343. if (@count($_SESSION["fp_form_errors"]) > 0) {
  344. return TRUE;
  345. }
  346. return FALSE;
  347. }
  348. /**
  349. * Returns the HTML to render this form (or content) element to the screen.
  350. * $name is the HTML machine name. $element is an array containing all we need to render it.
  351. * If you want default values to be taken from the SESSION (because we had form_errors, say, and we
  352. * want values to keep what we had between submissions) specify the callback to use in the
  353. * use_session_submission_values_for_callback variable.
  354. */
  355. function fp_render_element($name, $element, $use_session_submission_values_for_callback = "") {
  356. $rtn = "";
  357. $type = @$element["type"];
  358. if ($type == "") $type = "markup_no_wrappers";
  359. // Make sure the "css name" is friendly.
  360. $cssname = fp_get_machine_readable($name);
  361. if ($type == "do_not_render") return; // not supposed to render this element.
  362. // Does the name start with a # character? If so, do not attempt to render.
  363. if (substr($name, 0, 1) == "#") return;
  364. $value = @$element["value"];
  365. $label = @$element["label"];
  366. $options = @$element["options"];
  367. $description = @$element["description"];
  368. $popup_description = @$element["popup_description"];
  369. $prefix = @$element["prefix"];
  370. $suffix = @$element["suffix"];
  371. $multiple = @$element["multiple"];
  372. $spinner = @$element["spinner"];
  373. if ($multiple == TRUE) {
  374. $multiple = "multiple=multiple";
  375. }
  376. else {
  377. $multiple = "";
  378. }
  379. $autocomplete_path = @$element["autocomplete_path"];
  380. $required = @$element["required"];
  381. $no_please_select = @$element["no_please_select"];
  382. if (isset($element["hide_please_select"])) {
  383. $no_please_select = @$element["hide_please_select"];
  384. }
  385. $confirm = @$element["confirm"];
  386. // Let's also add our cssname as a class to the element, so that even markup will get it...
  387. if ($type == "markup") {
  388. if (!isset($element["attributes"]) || is_array($element["attributes"])) {
  389. @$element["attributes"]["class"] .= " markup-element form-element markup-element-$cssname";
  390. }
  391. }
  392. $attributes = @$element["attributes"];
  393. if (!is_array($attributes)) {
  394. $attributes = array();
  395. $attributes['style'] = '';
  396. $attributes['class'] = '';
  397. }
  398. if ($type == 'textarea_editor') {
  399. // Add the "html-editor" class to attributes.
  400. $attributes['class'] .= ' html-editor';
  401. }
  402. if ($spinner) {
  403. $attributes['class'] .= " show-spinner ";
  404. }
  405. $popup_help_link = "";
  406. if ($popup_description) {
  407. //$popup_help_link = " <a href='javascript: alert(\"" . $popup_description . "\");' class='form-popup-description'>[?]</a>";
  408. $popup_help_link = fp_get_js_alert_link($popup_description, "<span class='pop-q-mark'><i class='fa fa-question-circle'></i></span>", "form-popup-description");
  409. }
  410. $element_error_css = "";
  411. if (isset($_SESSION["fp_form_errors"]) && is_array($_SESSION["fp_form_errors"])) {
  412. foreach ($_SESSION["fp_form_errors"] as $err) {
  413. if ($err["name"] == $name) {
  414. // There is an error on this element! Add an extra CSS element.
  415. $element_error_css .= " form-element-error ";
  416. }
  417. }
  418. }
  419. if ($use_session_submission_values_for_callback && is_array(@$_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"])) {
  420. // Check the SESSION for a previous value which we should use.
  421. $ignore_types = array("hidden", "markup", "markup_no_wrappers", "submit", "password");
  422. if (!in_array($type, $ignore_types)) {
  423. $value = $_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"][$name];
  424. }
  425. }
  426. if ($type == "markup" && $element_error_css) {
  427. if (!isset($attributes)) {
  428. $attributes = array();
  429. }
  430. if (is_array($attributes)) {
  431. $attributes['class'] .= $element_error_css;
  432. }
  433. }
  434. $extra_wrapper_class = ""; // We will give the wrapper a similar class as are defined in attributes, if any.
  435. if (is_array($attributes)) {
  436. // Convert the attributes array into a string.
  437. $new_attr = "";
  438. foreach ($attributes as $key => $val) {
  439. $new_attr .= " $key='$val' ";
  440. if ($key == 'class') {
  441. $extra_wrapper_class .= " element-wrapper--" . trim($val);
  442. }
  443. }
  444. $attributes = $new_attr;
  445. }
  446. if ($type != "markup" && $type != "markup_no_wrappers") {
  447. $rtn .= "<div id='element-wrapper-$cssname' class='form-element element-type-$type $extra_wrapper_class'>";
  448. }
  449. if ($prefix) {
  450. $rtn .= $prefix;
  451. }
  452. if ($type != "markup" && $type != "markup_no_wrappers") {
  453. $rtn .= "<div id='element-inner-wrapper-$cssname' class='form-element element-type-$type $element_error_css'>";
  454. }
  455. if ($type == 'datetime-local') {
  456. // 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,
  457. // even though they support it for mobile. Every other modern browser supports it as well.
  458. // Anyway, we will need to include a workaround in jquery as a result if this field is being used:
  459. fp_add_js(fp_get_module_path("system") . '/lib/jquery.datetimepicker/jquery.datetimepicker.min.js');
  460. fp_add_css(fp_get_module_path("system") . '/lib/jquery.datetimepicker/jquery.datetimepicker.min.css');
  461. fp_add_js(fp_get_module_path("system") . '/lib/fp_datetimepicker_shim/fp_datetimepicker_shim.js');
  462. }
  463. $ast = "";
  464. if ($required) {
  465. $ast = "<span class='form-required-ast'>*</span>";
  466. }
  467. // First of all, what is it's "type"?
  468. if ($type == "markup") {
  469. if (is_string($attributes) && $attributes != "") {
  470. $rtn .= "<div $attributes>";
  471. }
  472. // If a label is set, go ahead and display, even though its markup...
  473. if ($label != "") {
  474. $rtn .= "<label>$ast$label$popup_help_link</label>";
  475. }
  476. $rtn .= $value;
  477. if (is_string($attributes) && $attributes != "") {
  478. $rtn .= "</div>";
  479. }
  480. }
  481. else if ($type == "markup_no_wrappers") {
  482. // If a label is set, go ahead and display, even though its markup...
  483. if ($label != "") {
  484. $rtn .= "<label>$ast$label$popup_help_link</label>";
  485. }
  486. $rtn .= $value; // plain value, no wrapper divs at all.
  487. }
  488. else if ($type != "hidden" && $type != "checkbox") {
  489. $rtn .= "<label>$ast$label$popup_help_link</label>";
  490. }
  491. if ($type == "textarea" || $type == 'textarea_editor') {
  492. $rows = (isset($element["rows"])) ? $element["rows"] : "5";
  493. $maxlength = (isset($element["maxlength"])) ? $element["maxlength"] : "";
  494. $extra_span = "";
  495. // if maxlength is set, then we want to show the char count upon change.
  496. if ($maxlength != "") {
  497. fp_add_css(fp_get_module_path('system') . '/css/style.css');
  498. fp_add_js(fp_get_module_path('system') . '/js/textarea-maxlength.js');
  499. $extra_span = "<span class='textarea-maxlength-count' id='textarea-maxlength-count___$cssname'>
  500. <span class='current-count' id='element-{$cssname}__current_count'>0</span>/<span class='maxlength-chars'>$maxlength</span>
  501. <span class='maxlength-description'>" . t("Max Characters") . "</span>
  502. </span>";
  503. }
  504. $rtn .= "<textarea name='$name' id='element-$cssname' rows='$rows' maxlength='$maxlength' $attributes>$value</textarea>$extra_span";
  505. }
  506. if ($type == "textfield" || $type == "text" || $type == "search" || $type == "password" || $type == 'datetime-local' || $type == 'time' || $type == 'date') {
  507. if ($type == "textfield") $type = "text";
  508. $size = (isset($element["size"])) ? $element["size"] : "60";
  509. $maxlength = (isset($element["maxlength"])) ? $element["maxlength"] : "255";
  510. // if there is an autocomplete_path, we need to include some javascript.
  511. if ($autocomplete_path != "") {
  512. fp_add_js(array("autocomplete_fields" => array(array("id" => "element-$cssname", "path" => $autocomplete_path))), 'setting');
  513. }
  514. $value = htmlentities($value, ENT_QUOTES);
  515. $rtn .= "<input type='$type' name='$name' id='element-$cssname' size='$size' maxlength='$maxlength' value='$value' $attributes>";
  516. }
  517. if ($type == "hidden" || $type == "value") {
  518. $value = htmlentities($value, ENT_QUOTES);
  519. $rtn .= "<input type='hidden' name='$name' id='element-$cssname' value='$value'>";
  520. }
  521. if ($type == "file") {
  522. $tname = $name;
  523. // Always going to put [] for a file, no matter what.
  524. //if ($multiple != "") {
  525. $tname .= "[]"; // if we allow uploading multiple files, we MUST put a [] behind it, or HTML will not upload correctly. Weird but true.
  526. //}
  527. $rtn .= "<input type='file' name='$tname' id='element-$cssname' $multiple $attributes>";
  528. }
  529. if ($type == "radios") {
  530. $rtn .= "<div class='form-radios form-radios-$cssname'>";
  531. foreach ($options as $key => $val) {
  532. $checked = "";
  533. // For radios, it's possible we've been sent an array for the value (though a string is more common and prefered).
  534. // We need to check both.
  535. if (is_array($value) && $value[$key] == $key) {
  536. $checked = "checked=checked";
  537. }
  538. else if (!is_array($value) && $value == $key) {
  539. $checked = "checked=checked";
  540. }
  541. $csskey = fp_get_machine_readable($key);
  542. $rtn .= "<div class='radio-element radio-element-$csskey'>
  543. <label class='label-for-radio'><input type='radio' name='$name' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  544. </div>";
  545. }
  546. $rtn .= "</div>";
  547. }
  548. if ($type == "select") {
  549. $rtn .= "<select name='$name' id='element-$cssname' $attributes>";
  550. if ($no_please_select != TRUE) {
  551. $rtn .= "<option value=''>- Please select -</option>";
  552. }
  553. foreach ($options as $key => $val) {
  554. if (is_array($val)) {
  555. // We need to establish an optgroup and then descend one level.
  556. $rtn .= "<optgroup label='" . htmlentities($key) . "'>";
  557. foreach ($val as $k => $v) {
  558. $selected = "";
  559. if ($value == $k) {
  560. $selected = "selected";
  561. }
  562. $rtn .= "<option value='$k' $selected>$v</option>";
  563. }
  564. $rtn .= "</optgroup>";
  565. }
  566. else {
  567. // This is just a normal string, so we can continue as-is
  568. $selected = "";
  569. if ($value == $key) {
  570. $selected = "selected";
  571. }
  572. $rtn .= "<option value='$key' $selected>$val</option>";
  573. }
  574. }
  575. $rtn .= "</select>";
  576. }
  577. // Multiple checkboxes...
  578. if ($type == "checkboxes") {
  579. $rtn .= "<div class='form-checkboxes form-checkboxes-$cssname'>";
  580. foreach ($options as $key => $val) {
  581. if (is_array($val)) {
  582. // Similar to select lists above, we need to simulate having "optgroup"s for checkboxes.
  583. $rtn .= "<div class='checkbox-pseudo-optgroup-wrapper'>
  584. <label>$key</label>";
  585. foreach ($val as $k => $v) {
  586. $checked = "";
  587. if (is_array($value) && isset($value[$k]) && $value[$k] == $k) {
  588. $checked = "checked=checked";
  589. }
  590. $csskey = fp_get_machine_readable($key);
  591. $rtn .= "<div class='checkbox-element checkbox-element-$csskey'>
  592. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$k]' id='element-$cssname-$csskey' value='$k' $checked $attributes> $v</label>
  593. </div>";
  594. }
  595. $rtn .= "</div>"; // close the pseudo-optgroup-wrapper
  596. }
  597. else {
  598. $checked = "";
  599. if (is_array($value) && isset($value[$key]) && $value[$key] == $key) {
  600. $checked = "checked=checked";
  601. }
  602. $csskey = fp_get_machine_readable($key);
  603. $rtn .= "<div class='checkbox-element checkbox-element-$csskey'>
  604. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$key]' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  605. </div>";
  606. }
  607. }
  608. $rtn .= "</div>";
  609. }
  610. // A single checkbox... The values will be with 0 (zero) or 1 (one), and boolean
  611. // values are accepted/saved
  612. if ($type == "checkbox") {
  613. $rtn .= "<div class='form-checkbox form-checkbox-$cssname'>";
  614. $checked = "";
  615. if ((bool)($value) == TRUE) {
  616. $checked = "checked=checked";
  617. }
  618. $rtn .= "<div class='checkbox-element'>
  619. <label class='label-for-checkbox'><input type='checkbox' name='$name' id='element-$cssname' value='1' $checked $attributes> $label$popup_help_link</label>
  620. </div>";
  621. $rtn .= "</div>";
  622. }
  623. if ($type == "submit") {
  624. if ($confirm != "") {
  625. $confirm = htmlentities($confirm, ENT_QUOTES);
  626. $confirm = str_replace("\n", "\\n", $confirm);
  627. $attributes .= " onClick='return confirm(\"$confirm\");' ";
  628. }
  629. $rtn .= "<input type='$type' name='$name' value='$value' $attributes>";
  630. }
  631. if ($type == "button") {
  632. $rtn .= "<input type='button' name='$name' value='$value' $attributes>";
  633. }
  634. if ($spinner) {
  635. fp_add_css(fp_get_module_path("system") . "/css/style.css");
  636. fp_add_js(fp_get_module_path("system") . "/js/spinner.js");
  637. $rtn .= "<span class='loading-spinner loading-spinner-$name' style='display:none;'></span>";
  638. }
  639. if ($description) {
  640. $rtn .= "<div class='form-element-description'>$description</div>";
  641. }
  642. if ($type != "markup" && $type != 'markup_no_wrappers') {
  643. $rtn .= "</div>"; // close the inner wrapper
  644. }
  645. if ($suffix) {
  646. $rtn .= $suffix;
  647. }
  648. if ($type != "markup" && $type != 'markup_no_wrappers') {
  649. $rtn .= "</div>"; // close the over-all wrapper
  650. }
  651. return $rtn;
  652. }

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…