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()) {
  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. // Any hooks to alter this render array?
  30. $modules = modules_implement_hook("content_alter");
  31. foreach ($modules as $module) {
  32. call_user_func_array($module . '_content_alter', array(&$render_array, $render_id));
  33. }
  34. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  35. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  36. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  37. // The first the I want to do is find out, what are the defined weights in this form, if any.
  38. $defined_weights = array();
  39. foreach ($render_array as $element) {
  40. if (!is_array($element)) continue;
  41. if (!isset($element["weight"])) {
  42. $element["weight"] = 0;
  43. }
  44. $weight = (int)$element["weight"];
  45. if (!in_array($weight, $defined_weights)) {
  46. $defined_weights[] = $weight;
  47. }
  48. }
  49. // Okay, now sort our weights.
  50. sort($defined_weights);
  51. // Before we get to assigning weights, we need to make sure
  52. // that none of our form elements have a name which might cause us trouble.
  53. // Namely, no element can be named "submit" (like a button) because it will
  54. // interfere with our javascript functions.
  55. $form2 = array();
  56. foreach ($render_array as $key => $element) {
  57. $name = $key;
  58. if ($name == "submit") {
  59. $name = "btn_submit";
  60. }
  61. $form2[$name] = $element;
  62. }
  63. $form = $form2;
  64. // Okay, now go through the weights and create a new form in THAT order.
  65. $new_form = array();
  66. foreach ($defined_weights as $dw) {
  67. foreach ($form as $key => $element) {
  68. if (!is_array($element)) {
  69. $new_form[$key] = $element;
  70. continue;
  71. }
  72. if (!isset($element["weight"])) $element["weight"] = 0;
  73. $weight = (int)$element["weight"];
  74. if ($weight == $dw) {
  75. $new_form[$key] = $element;
  76. }
  77. }
  78. }
  79. // Okay, we should now be good to go!
  80. $render_array = $new_form;
  81. // We can now proceed with rendering this render_array. It will be similar to fp_render_form.
  82. $rtn .= "<div class='renderapi-content' id='render-$render_id'>";
  83. $rtn .= fp_render_array($render_array);
  84. $rtn .= "</div>";
  85. return $rtn;
  86. }
  87. /**
  88. * This takes a render_array and generates the HTML for it. This usually is not called directly, but
  89. * instead you should call fp_render_content() or fp_render_form()
  90. */
  91. function fp_render_array($render_array, $use_callback = "") {
  92. $rtn = "";
  93. foreach ($render_array as $name => $element) {
  94. if (is_array($element) && (isset($element["type"]) || isset($element["value"]))) {
  95. // Is this a cfieldset (collapsible fieldset)?
  96. if (@$element["type"] == "cfieldset") {
  97. $celements = $element["elements"]; // get our list of form elements within this fieldset.
  98. // Go through these new elements and prepare to display them inside a collapsible fieldset.
  99. $html = "";
  100. foreach ($celements as $k => $v) {
  101. foreach ($celements[$k] as $name => $celement) {
  102. $html .= fp_render_element($name, $celement, $use_callback);
  103. }
  104. }
  105. // add to c_fieldset
  106. $rtn .= fp_render_c_fieldset($html, @$element["label"], @$element["start_closed"]);
  107. }
  108. else {
  109. // No, this is a normal element. Not in a fieldset.
  110. $rtn .= fp_render_element($name, $element, $use_callback);
  111. }
  112. }
  113. }
  114. return $rtn;
  115. }
  116. /**
  117. * This function gets the form array, where the callback is the same as form_id.
  118. * It will also look for modules which may want to alter the form, using hook_form_alter,
  119. * and go ahead and apply that.
  120. *
  121. * It will also reorder the elements by weight.
  122. *
  123. */
  124. function fp_get_form($form_id, $params = array()) {
  125. $form = call_user_func_array($form_id, $params);
  126. // Add in the default submit_handlers and validate_handlers, if not all ready set.
  127. if (!isset($form["#submit_handlers"])) $form["#submit_handlers"] = array($form_id . "_submit");
  128. if (!isset($form["#validate_handlers"])) $form["#validate_handlers"] = array($form_id . "_validate");
  129. $modules = modules_implement_hook("form_alter");
  130. foreach ($modules as $module) {
  131. call_user_func_array($module . '_form_alter', array(&$form, $form_id));
  132. }
  133. // Okay, now the fun part. Re-order the elements by weight. Lighter weights
  134. // should float to the top. Elements w/o a weight listed are assumed to have a weight of 0.
  135. // Unfortunately we cannot use uasort, as it re-orders our indexes when weights are identical.
  136. // The first the I want to do is find out, what are the defined weights in this form, if any.
  137. $defined_weights = array();
  138. foreach ($form as $element) {
  139. if (!isset($element["weight"])) $element["weight"] = 0;
  140. $weight = (int)$element["weight"];
  141. if (!in_array($weight, $defined_weights)) {
  142. $defined_weights[] = $weight;
  143. }
  144. }
  145. // Okay, now sort our weights.
  146. sort($defined_weights);
  147. // Before we get to assigning weights, we need to make sure
  148. // that none of our form elements have a name which might cause us trouble.
  149. // Namely, no element can be named "submit" (like a button) because it will
  150. // interfere with our javascript functions.
  151. $form2 = array();
  152. foreach ($form as $key => $element) {
  153. $name = $key;
  154. if ($name == "submit") {
  155. $name = "btn_submit";
  156. }
  157. $form2[$name] = $element;
  158. }
  159. $form = $form2;
  160. // Okay, now go through the weights and create a new form in THAT order.
  161. $new_form = array();
  162. foreach ($defined_weights as $dw) {
  163. foreach ($form as $key => $element) {
  164. if (!isset($element["weight"])) $element["weight"] = 0;
  165. $weight = (int)$element["weight"];
  166. if ($weight == $dw) {
  167. $new_form[$key] = $element;
  168. }
  169. }
  170. }
  171. // Okay, we should now be good to go!
  172. return $new_form;
  173. }
  174. /**
  175. * Render the form array from the callback to the screen, and
  176. * set the form to save itself in our default submit handler.
  177. * Valid form_types are:
  178. * "system_settings" => values automatically saved to variables table.
  179. * "normal" or BLANK => values are forwarded to $callback_submit() function, if it exists.
  180. */
  181. function fp_render_form($callback, $form_type = "") {
  182. global $current_student_id, $user;
  183. $rtn = "";
  184. // Were there extra params after callback and form_type? Wrap them up
  185. // and send them along to fp_get_form
  186. $params = array();
  187. if (func_num_args() > 2) {
  188. // Remove first 2 arguments, so all we have left is what the user added to it.
  189. $params = func_get_args();
  190. array_shift($params);
  191. array_shift($params);
  192. }
  193. $form = fp_get_form($callback, $params);
  194. // Base64 enc the params, so we can easily handle if there are quotation marks, line breaks, etc.
  195. $form_params = base64_encode(serialize($params));
  196. // Figure out the current page's title and display it.
  197. $path = fp_no_html_xss($_GET["q"]); // Sanitize _GET valuses.
  198. $default_path = $path;
  199. $default_query = "";
  200. // Figure out the "default_query" from $_GET
  201. $new_query = array();
  202. foreach ($_GET as $key => $val) {
  203. // Sanitize since it is coming from _GET.
  204. $key = fp_no_html_xss($key);
  205. $val = fp_no_html_xss($val);
  206. if ($key != "q") {
  207. $new_query[] = "$key=$val";
  208. }
  209. }
  210. if (count($new_query)) {
  211. $default_query = join("&", $new_query);
  212. }
  213. $page_title = $GLOBALS["fp_current_menu_router_item"]["title"];
  214. if (isset($GLOBALS["fp_set_title"])) {
  215. $page_title = $GLOBALS["fp_set_title"];
  216. }
  217. if ($page_title != "") {
  218. //$rtn .= "<h2 class='title'>" . $page_title . "</h2>";
  219. fp_show_title(TRUE);
  220. }
  221. //fpm($GLOBALS["fp_current_menu_router_item"]);
  222. $form_path = $GLOBALS["fp_current_menu_router_item"]["path"];
  223. // Are there any files required to get to the submit handler for this form?
  224. $form_include = "";
  225. // Set the form_include to the current page's "file" requirement, if any.
  226. if (is_array($GLOBALS["fp_current_menu_router_item"])) {
  227. if (isset($GLOBALS["fp_current_menu_router_item"]["file"])) {
  228. $form_include = $GLOBALS["fp_current_menu_router_item"]["file"];
  229. }
  230. }
  231. if (@$form["#form_include"]) {
  232. $form_include = $form["#form_include"];
  233. }
  234. $extra_form_class = "";
  235. if ($form_type == "system_settings") {
  236. $extra_form_class = "fp-system-form";
  237. }
  238. $form_token = md5($callback . fp_token());
  239. // Set up our form's attributes.
  240. $attributes = @$form["#attributes"];
  241. if (!is_array($attributes)) $attributes = array();
  242. if (!isset($attributes["class"])) $attributes["class"] = "";
  243. $attributes["class"] .= " $extra_form_class fp-form fp-form-$callback ";
  244. // Convert the attributes array into a string.
  245. $new_attr = "";
  246. foreach ($attributes as $key => $val) {
  247. $new_attr .= " $key='$val' ";
  248. }
  249. $attributes = $new_attr;
  250. // Did the user specify a submit method (like GET or POST)? POST is default.
  251. $submit_method = (@$form["#submit_method"] == "") ? "POST" : $form["#submit_method"];
  252. $rtn .= "<form action='" . fp_url("system-handle-form-submit", "", TRUE) . "' method='$submit_method' id='fp-form-$callback' name='fp_form_name_$callback' $attributes>";
  253. $rtn .= "<input type='hidden' name='callback' value='$callback'>";
  254. $rtn .= "<input type='hidden' name='form_token' value='$form_token'>";
  255. $rtn .= "<input type='hidden' name='form_type' value='$form_type'>";
  256. $rtn .= "<input type='hidden' name='form_path' value='$form_path'>";
  257. $rtn .= "<input type='hidden' name='form_params' value='$form_params'>";
  258. $rtn .= "<input type='hidden' name='form_include' value='$form_include'>";
  259. $rtn .= "<input type='hidden' name='default_redirect_path' value='$default_path'>";
  260. $rtn .= "<input type='hidden' name='default_redirect_query' value='$default_query'>";
  261. $rtn .= "<input type='hidden' name='current_student_id' value='$current_student_id'>";
  262. $use_callback = "";
  263. if (form_has_errors()) {
  264. // We will only pull previous POST's values if there are errors on the form.
  265. $use_callback = $callback;
  266. }
  267. $rtn .= fp_render_array($form, $use_callback);
  268. // If this is a system settings form, go ahead and display the save button.
  269. if ($form_type == "system_settings") {
  270. $rtn .= "<div class='buttons'>";
  271. //$rtn .= fp_render_button("Save settings", "\$(\"#sysform\").submit()");
  272. $rtn .= "<input type='submit' name='submit_button' value='" . t("Save settings") . "'>";
  273. $rtn .= "</div>";
  274. }
  275. $rtn .= "</form>";
  276. // Clear any existing form errors and values
  277. unset($_SESSION["fp_form_errors"]);
  278. clear_session_form_values($callback);
  279. return $rtn;
  280. }
  281. /**
  282. * Clear the form submissions variable from the SESSION for this callback.
  283. */
  284. function clear_session_form_values($callback) {
  285. unset($_SESSION["fp_form_submissions"][$callback]);
  286. }
  287. /**
  288. * This is a very basic valiator for form API submission.
  289. * All I really care about is making sure required fields have
  290. * a value in them. If they do not, we will file a form_error.
  291. */
  292. function form_basic_validate($form, $form_submitted) {
  293. foreach ($form as $name => $element) {
  294. if (is_array($element) && @$element["required"]) {
  295. // Okay, this is a required field. So, check that it has a non-blank value
  296. // in form_submitted.
  297. if ($form_submitted["values"][$name] == "") {
  298. // It's blank! ERROR!
  299. $label = $element["label"];
  300. if ($label == "") $label = $name;
  301. form_error($name, t("You must enter a value for <b>%element_label</b>", array("%element_label" => $label)));
  302. }
  303. }
  304. }
  305. }
  306. /**
  307. * Register a form_error in the SESSION.
  308. */
  309. function form_error($element_name, $message) {
  310. $_SESSION["fp_form_errors"][] = array("name" => $element_name, "msg" => $message);
  311. fp_add_message($message, "error");
  312. }
  313. /**
  314. * Returns TRUE or FALSE if there have been errors for this form submission
  315. * (We will just look in the SESSION to find out).
  316. */
  317. function form_has_errors() {
  318. if (@count($_SESSION["fp_form_errors"]) > 0) {
  319. return TRUE;
  320. }
  321. return FALSE;
  322. }
  323. /**
  324. * Returns the HTML to render this form (or content) element to the screen.
  325. * $name is the HTML machine name. $element is an array containing all we need to render it.
  326. * If you want default values to be taken from the SESSION (because we had form_errors, say, and we
  327. * want values to keep what we had between submissions) specify the callback to use in the
  328. * use_session_submission_values_for_callback variable.
  329. */
  330. function fp_render_element($name, $element, $use_session_submission_values_for_callback = "") {
  331. $rtn = "";
  332. $type = @$element["type"];
  333. if ($type == "") $type = "markup";
  334. // Make sure the "css name" is friendly.
  335. $cssname = fp_get_machine_readable($name);
  336. if ($type == "do_not_render") return; // not supposed to render this element.
  337. // Does the name start with a # character? If so, do not attempt to render.
  338. if (substr($name, 0, 1) == "#") return;
  339. $value = @$element["value"];
  340. $label = @$element["label"];
  341. $options = @$element["options"];
  342. $description = @$element["description"];
  343. $popup_description = @$element["popup_description"];
  344. $prefix = @$element["prefix"];
  345. $suffix = @$element["suffix"];
  346. $multiple = @$element["multiple"];
  347. if ($multiple == TRUE) {
  348. $multiple = "multiple=multiple";
  349. }
  350. else {
  351. $multiple = "";
  352. }
  353. $required = @$element["required"];
  354. $no_please_select = @$element["no_please_select"];
  355. if (isset($element["hide_please_select"])) {
  356. $no_please_select = @$element["hide_please_select"];
  357. }
  358. $confirm = @$element["confirm"];
  359. // Let's also add our cssname as a class to the element, so that even markup will get it...
  360. if ($type == "markup") {
  361. if (!isset($element["attributes"]) || is_array($element["attributes"])) {
  362. @$element["attributes"]["class"] .= " markup-element form-element markup-element-$cssname";
  363. }
  364. }
  365. $attributes = @$element["attributes"];
  366. if (is_array($attributes)) {
  367. // Convert the attributes array into a string.
  368. $new_attr = "";
  369. foreach ($attributes as $key => $val) {
  370. $new_attr .= " $key='$val' ";
  371. }
  372. $attributes = $new_attr;
  373. }
  374. $popup_help_link = "";
  375. if ($popup_description) {
  376. //$popup_help_link = " <a href='javascript: alert(\"" . $popup_description . "\");' class='form-popup-description'>[?]</a>";
  377. $popup_help_link = fp_get_js_alert_link($popup_description, "<span class='pop-q-mark'>?</span>", "form-popup-description");
  378. }
  379. $element_error_css = "";
  380. if (isset($_SESSION["fp_form_errors"]) && is_array($_SESSION["fp_form_errors"])) {
  381. foreach ($_SESSION["fp_form_errors"] as $err) {
  382. if ($err["name"] == $name) {
  383. // There is an error on this element! Add an extra CSS element.
  384. $element_error_css .= "form-element-error";
  385. }
  386. }
  387. }
  388. if ($use_session_submission_values_for_callback && is_array(@$_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"])) {
  389. // Check the SESSION for a previous value which we should use.
  390. $ignore_types = array("hidden", "markup", "submit", "password");
  391. if (!in_array($type, $ignore_types)) {
  392. $value = $_SESSION["fp_form_submissions"][$use_session_submission_values_for_callback]["values"][$name];
  393. }
  394. }
  395. if ($type != "markup") {
  396. $rtn .= "<div id='element-wrapper-$cssname' class='form-element element-type-$type'>";
  397. }
  398. if ($prefix) {
  399. $rtn .= $prefix;
  400. }
  401. if ($type != "markup") {
  402. $rtn .= "<div id='element-inner-wrapper-$cssname' class='form-element element-type-$type $element_error_css'>";
  403. }
  404. $ast = "";
  405. if ($required) {
  406. $ast = "<span class='form-required-ast'>*</span>";
  407. }
  408. // First of all, what is it's "type"?
  409. if ($type == "markup") {
  410. if (is_string($attributes) && $attributes != "") {
  411. $rtn .= "<div $attributes>";
  412. }
  413. // If a label is set, go ahead and display, even though its markup...
  414. if ($label != "") {
  415. $rtn .= "<label>$ast$label$popup_help_link</label>";
  416. }
  417. $rtn .= "$value";
  418. if (is_string($attributes) && $attributes != "") {
  419. $rtn .= "</div>";
  420. }
  421. }
  422. else if ($type != "hidden" && $type != "checkbox") {
  423. $rtn .= "<label>$ast$label$popup_help_link</label>";
  424. }
  425. if ($type == "textarea") {
  426. $rows = (isset($element["rows"])) ? $element["rows"] : "5";
  427. $rtn .= "<textarea name='$name' id='element-$cssname' rows='$rows' $attributes>$value</textarea>";
  428. }
  429. if ($type == "textfield" || $type == "text" || $type == "password") {
  430. if ($type == "textfield") $type = "text";
  431. $size = (isset($element["size"])) ? $element["size"] : "60";
  432. $maxlength = (isset($element["maxlength"])) ? $element["maxlength"] : "255";
  433. $value = htmlentities($value, ENT_QUOTES);
  434. $rtn .= "<input type='$type' name='$name' id='element-$cssname' size='$size' maxlength='$maxlength' value='$value' $attributes>";
  435. }
  436. if ($type == "hidden") {
  437. $value = htmlentities($value, ENT_QUOTES);
  438. $rtn .= "<input type='hidden' name='$name' id='element-$cssname' value='$value'>";
  439. }
  440. if ($type == "file") {
  441. $tname = $name;
  442. if ($multiple != "") {
  443. $tname .= "[]"; // if we allow uploading multiple files, we MUST put a [] behind it, or HTML will not upload correctly. Weird but true.
  444. }
  445. $rtn .= "<input type='file' name='$tname' id='element-$cssname' $multiple $attributes>";
  446. }
  447. if ($type == "radios") {
  448. $rtn .= "<div class='form-radios form-radios-$cssname'>";
  449. foreach ($options as $key => $val) {
  450. $checked = "";
  451. if ($value == $key) {
  452. $checked = "checked=checked";
  453. }
  454. $csskey = fp_get_machine_readable($key);
  455. $rtn .= "<div class='radio-element radio-element-$csskey'>
  456. <label class='label-for-radio'><input type='radio' name='$name' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  457. </div>";
  458. }
  459. $rtn .= "</div>";
  460. }
  461. if ($type == "select") {
  462. $rtn .= "<select name='$name' id='element-$cssname' $attributes>";
  463. if ($no_please_select != TRUE) {
  464. $rtn .= "<option value=''>- Please select -</option>";
  465. }
  466. foreach ($options as $key => $val) {
  467. $selected = "";
  468. if ($value == $key) {
  469. $selected = "selected";
  470. }
  471. $rtn .= "<option value='$key' $selected>$val</option>";
  472. }
  473. $rtn .= "</select>";
  474. }
  475. // Multiple checkboxes...
  476. if ($type == "checkboxes") {
  477. $rtn .= "<div class='form-checkboxes form-checkboxes-$cssname'>";
  478. foreach ($options as $key => $val) {
  479. $checked = "";
  480. if (is_array($value) && isset($value[$key]) && $value[$key] == $key) {
  481. $checked = "checked=checked";
  482. }
  483. $csskey = fp_get_machine_readable($key);
  484. $rtn .= "<div class='checkbox-element checkbox-element-$csskey'>
  485. <label class='label-for-checkbox'><input type='checkbox' name='$name" . "[$key]' id='element-$cssname-$csskey' value='$key' $checked $attributes> $val</label>
  486. </div>";
  487. }
  488. $rtn .= "</div>";
  489. }
  490. // A single checkbox... The values will be with 0 (zero) or 1 (one), and boolean
  491. // values are accepted/saved
  492. if ($type == "checkbox") {
  493. $rtn .= "<div class='form-checkbox form-checkbox-$cssname'>";
  494. $checked = "";
  495. if ((bool)($value) == TRUE) {
  496. $checked = "checked=checked";
  497. }
  498. $rtn .= "<div class='checkbox-element'>
  499. <label class='label-for-checkbox'><input type='checkbox' name='$name' id='element-$cssname' value='1' $checked $attributes> $label$popup_help_link</label>
  500. </div>";
  501. $rtn .= "</div>";
  502. }
  503. if ($type == "submit") {
  504. if ($confirm != "") {
  505. $confirm = htmlentities($confirm, ENT_QUOTES);
  506. $confirm = str_replace("\n", "\\n", $confirm);
  507. $attributes .= " onClick='return confirm(\"$confirm\");' ";
  508. }
  509. $rtn .= "<input type='submit' name='$name' value='$value' $attributes>";
  510. }
  511. if ($type == "button") {
  512. $rtn .= "<input type='button' name='$name' value='$value' $attributes>";
  513. }
  514. if ($description) {
  515. $rtn .= "<div class='form-element-description'>$description</div>";
  516. }
  517. if ($type != "markup") {
  518. $rtn .= "</div>"; // close the inner wrapper
  519. }
  520. if ($suffix) {
  521. $rtn .= $suffix;
  522. }
  523. if ($type != "markup") {
  524. $rtn .= "</div>"; // close the over-all wrapper
  525. }
  526. return $rtn;
  527. }

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 valiator 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…