From 1a3b06297cf25d5c5e7cb5f3456689e71b8b2b88 Mon Sep 17 00:00:00 2001
From: Eric Rasmussen <eric@unl.edu>
Date: Tue, 8 Nov 2011 23:04:58 +0000
Subject: [PATCH] [gh-226] Merging test into staging -c1177 -c1157 -c1046

git-svn-id: file:///tmp/wdn_thm_drupal/branches/drupal-7.x/staging@1270 20a16fea-79d4-4915-8869-1ea9d5ebf173
---
 README-UNL.txt                                |   23 +-
 sites/all/modules/form_builder/LICENSE.txt    |  274 +++++
 .../examples/form_builder_examples.info       |   11 +
 .../examples/form_builder_examples.module     |  479 ++++++++
 .../all/modules/form_builder/form_builder.css |  361 ++++++
 .../form_builder/form_builder.garland.css     |   21 +
 .../modules/form_builder/form_builder.info    |   11 +
 .../modules/form_builder/form_builder.install |   86 ++
 .../all/modules/form_builder/form_builder.js  |  948 +++++++++++++++
 .../modules/form_builder/form_builder.module  |  359 ++++++
 .../form_builder/form_builder_hooks.php       |  260 ++++
 .../all/modules/form_builder/images/blank.gif |  Bin 0 -> 43 bytes
 .../modules/form_builder/images/configure.png |  Bin 0 -> 625 bytes
 .../modules/form_builder/images/delete.png    |  Bin 0 -> 349 bytes
 .../form_builder/images/fields/body.png       |  Bin 0 -> 973 bytes
 .../form_builder/images/fields/checkboxes.png |  Bin 0 -> 974 bytes
 .../form_builder/images/fields/date.png       |  Bin 0 -> 178 bytes
 .../form_builder/images/fields/email.png      |  Bin 0 -> 966 bytes
 .../form_builder/images/fields/fieldset.png   |  Bin 0 -> 190 bytes
 .../form_builder/images/fields/file.png       |  Bin 0 -> 377 bytes
 .../form_builder/images/fields/grid.png       |  Bin 0 -> 194 bytes
 .../form_builder/images/fields/hidden.png     |  Bin 0 -> 205 bytes
 .../form_builder/images/fields/image.png      |  Bin 0 -> 703 bytes
 .../form_builder/images/fields/markup.png     |  Bin 0 -> 952 bytes
 .../form_builder/images/fields/menu.png       |  Bin 0 -> 205 bytes
 .../form_builder/images/fields/number.png     |  Bin 0 -> 225 bytes
 .../form_builder/images/fields/pagebreak.png  |  Bin 0 -> 178 bytes
 .../form_builder/images/fields/path.png       |  Bin 0 -> 228 bytes
 .../form_builder/images/fields/radios.png     |  Bin 0 -> 224 bytes
 .../form_builder/images/fields/revisions.png  |  Bin 0 -> 976 bytes
 .../form_builder/images/fields/select.png     |  Bin 0 -> 210 bytes
 .../form_builder/images/fields/taxonomy.png   |  Bin 0 -> 219 bytes
 .../form_builder/images/fields/textarea.png   |  Bin 0 -> 216 bytes
 .../form_builder/images/fields/textfield.png  |  Bin 0 -> 967 bytes
 .../form_builder/images/fields/time.png       |  Bin 0 -> 209 bytes
 .../form_builder/images/status-active.gif     |  Bin 0 -> 2196 bytes
 .../includes/form_builder.admin.inc           |  762 ++++++++++++
 .../includes/form_builder.api.inc             |  354 ++++++
 .../includes/form_builder.cache.inc           |  174 +++
 .../includes/form_builder.properties.inc      |  358 ++++++
 .../all/modules/form_builder/modules/menu.inc |  197 +++
 .../all/modules/form_builder/modules/node.inc |  892 ++++++++++++++
 .../modules/node/form_builder_node.info       |   11 +
 .../modules/node/form_builder_node.install    |   52 +
 .../modules/node/form_builder_node.module     |   70 ++
 .../all/modules/form_builder/modules/path.inc |  151 +++
 .../all/modules/form_builder/modules/poll.inc |  115 ++
 .../modules/form_builder/modules/taxonomy.inc |  256 ++++
 .../modules/form_builder/modules/upload.inc   |  169 +++
 .../form_builder_webform.components.inc       | 1063 +++++++++++++++++
 .../modules/webform/form_builder_webform.info |   12 +
 .../webform/form_builder_webform.module       |  441 +++++++
 52 files changed, 7909 insertions(+), 1 deletion(-)
 create mode 100644 sites/all/modules/form_builder/LICENSE.txt
 create mode 100644 sites/all/modules/form_builder/examples/form_builder_examples.info
 create mode 100644 sites/all/modules/form_builder/examples/form_builder_examples.module
 create mode 100644 sites/all/modules/form_builder/form_builder.css
 create mode 100644 sites/all/modules/form_builder/form_builder.garland.css
 create mode 100644 sites/all/modules/form_builder/form_builder.info
 create mode 100644 sites/all/modules/form_builder/form_builder.install
 create mode 100644 sites/all/modules/form_builder/form_builder.js
 create mode 100644 sites/all/modules/form_builder/form_builder.module
 create mode 100644 sites/all/modules/form_builder/form_builder_hooks.php
 create mode 100644 sites/all/modules/form_builder/images/blank.gif
 create mode 100644 sites/all/modules/form_builder/images/configure.png
 create mode 100644 sites/all/modules/form_builder/images/delete.png
 create mode 100644 sites/all/modules/form_builder/images/fields/body.png
 create mode 100644 sites/all/modules/form_builder/images/fields/checkboxes.png
 create mode 100644 sites/all/modules/form_builder/images/fields/date.png
 create mode 100644 sites/all/modules/form_builder/images/fields/email.png
 create mode 100644 sites/all/modules/form_builder/images/fields/fieldset.png
 create mode 100644 sites/all/modules/form_builder/images/fields/file.png
 create mode 100644 sites/all/modules/form_builder/images/fields/grid.png
 create mode 100644 sites/all/modules/form_builder/images/fields/hidden.png
 create mode 100644 sites/all/modules/form_builder/images/fields/image.png
 create mode 100644 sites/all/modules/form_builder/images/fields/markup.png
 create mode 100644 sites/all/modules/form_builder/images/fields/menu.png
 create mode 100644 sites/all/modules/form_builder/images/fields/number.png
 create mode 100644 sites/all/modules/form_builder/images/fields/pagebreak.png
 create mode 100644 sites/all/modules/form_builder/images/fields/path.png
 create mode 100644 sites/all/modules/form_builder/images/fields/radios.png
 create mode 100644 sites/all/modules/form_builder/images/fields/revisions.png
 create mode 100644 sites/all/modules/form_builder/images/fields/select.png
 create mode 100644 sites/all/modules/form_builder/images/fields/taxonomy.png
 create mode 100644 sites/all/modules/form_builder/images/fields/textarea.png
 create mode 100644 sites/all/modules/form_builder/images/fields/textfield.png
 create mode 100644 sites/all/modules/form_builder/images/fields/time.png
 create mode 100644 sites/all/modules/form_builder/images/status-active.gif
 create mode 100644 sites/all/modules/form_builder/includes/form_builder.admin.inc
 create mode 100644 sites/all/modules/form_builder/includes/form_builder.api.inc
 create mode 100644 sites/all/modules/form_builder/includes/form_builder.cache.inc
 create mode 100644 sites/all/modules/form_builder/includes/form_builder.properties.inc
 create mode 100644 sites/all/modules/form_builder/modules/menu.inc
 create mode 100644 sites/all/modules/form_builder/modules/node.inc
 create mode 100644 sites/all/modules/form_builder/modules/node/form_builder_node.info
 create mode 100644 sites/all/modules/form_builder/modules/node/form_builder_node.install
 create mode 100644 sites/all/modules/form_builder/modules/node/form_builder_node.module
 create mode 100644 sites/all/modules/form_builder/modules/path.inc
 create mode 100644 sites/all/modules/form_builder/modules/poll.inc
 create mode 100644 sites/all/modules/form_builder/modules/taxonomy.inc
 create mode 100644 sites/all/modules/form_builder/modules/upload.inc
 create mode 100644 sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
 create mode 100644 sites/all/modules/form_builder/modules/webform/form_builder_webform.info
 create mode 100644 sites/all/modules/form_builder/modules/webform/form_builder_webform.module

diff --git a/README-UNL.txt b/README-UNL.txt
index 274e5212..fbbef896 100644
--- a/README-UNL.txt
+++ b/README-UNL.txt
@@ -26,8 +26,24 @@ modules/image/image.field.inc
  * http://drupal.org/node/1025796#comment-4298698
  * http://drupal.org/files/issues/1025796.patch
 
-------------------------------------
+-------------------------------------
  
+includes/common.inc
+ * EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7392 of /var/www/unl.edu/htdocs/includes/common.inc).
+ * http://gforge.unl.edu/gf/project/wdn_thm_drupal/tracker/?action=TrackerItemEdit&tracker_item_id=993&start=0
+ * http://drupal.org/node/1067750#comment-4941822
+ * Applied patch: http://drupal.org/files/issues/empty_string_bundle.patch
+
+-------------------------------------
+
+sites/all/modules/form_builder/modules/webform/form_builder_webform.module
+ * In form_builder_webform_components_page() load jquery.ui.datepicker.min.js so the Date element will work on a new form that does not have ui.datepicker loaded
+ * http://drupal.org/node/1307838
+
+*****************************************
+** Other
+*****************************************
+
 sites/sites.php
  * Added support for $default_domains array. See includes/bootstrap.inc conf_path().
 
@@ -36,3 +52,8 @@ sites/sites.php
 sites/example.sites.php
  * Added an example of the $default_domains array.
  * Added the stub record needed for creating site aliases.
+
+-------------------------------------
+
+rewrite.php
+used to allow public files to be accessed without the sites/<site_dir>/files prefix
diff --git a/sites/all/modules/form_builder/LICENSE.txt b/sites/all/modules/form_builder/LICENSE.txt
new file mode 100644
index 00000000..2c095c8d
--- /dev/null
+++ b/sites/all/modules/form_builder/LICENSE.txt
@@ -0,0 +1,274 @@
+GNU GENERAL PUBLIC LICENSE
+
+              Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
+Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
+verbatim copies of this license document, but changing it is not allowed.
+
+                  Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public License
+applies to most of the Free Software Foundation's software and to any other
+program whose authors commit to using it. (Some other Free Software
+Foundation software is covered by the GNU Library General Public License
+instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this service if
+you wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have. You must make
+sure that they, too, receive or can get the source code. And you must show
+them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients
+to know that what they have is not the original, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will individually
+obtain patent licenses, in effect making the program proprietary. To prevent
+this, we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+           GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
+               MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms
+of this General Public License. The "Program", below, refers to any such
+program or work, and a "work based on the Program" means either the
+Program or any derivative work under copyright law: that is to say, a work
+containing the Program or a portion of it, either verbatim or with
+modifications and/or translated into another language. (Hereinafter, translation
+is included without limitation in the term "modification".) Each licensee is
+addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made
+by running the Program). Whether that is true depends on what the Program
+does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that
+you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in
+part contains or is derived from the Program or any part thereof, to be
+licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+c) If the modified program normally reads commands interactively when run,
+you must cause it, when started running for such interactive use in the most
+ordinary way, to print or display an announcement including an appropriate
+copyright notice and a notice that there is no warranty (or else, saying that
+you provide a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this License.
+(Exception: if the Program itself is interactive but does not normally print such
+an announcement, your work based on the Program is not required to print
+an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you distribute
+them as separate works. But when you distribute the same sections as part
+of a whole which is a work based on the Program, the distribution of the
+whole must be on the terms of this License, whose permissions for other
+licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to
+work written entirely by you; rather, the intent is to exercise the right to
+control the distribution of derivative or collective works based on the
+Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the scope
+of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1
+and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1 and 2 above
+on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give
+any third party, for a charge no more than your cost of physically performing
+source distribution, a complete machine-readable copy of the corresponding
+source code, to be distributed under the terms of Sections 1 and 2 above on
+a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute
+corresponding source code. (This alternative is allowed only for
+noncommercial distribution and only if you received the program in object
+code or executable form with such an offer, in accord with Subsection b
+above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with the
+object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy,
+modify, sublicense or distribute the Program is void, and will automatically
+terminate your rights under this License. However, parties who have received
+copies, or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance
+of this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms and
+conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose
+that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original copyright
+holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In such
+case, this License incorporates the limitation as if written in the body of this
+License.
+
+9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address new
+problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies
+a version number of this License which applies to it and "any later version",
+you have the option of following the terms and conditions either of that
+version or of any later version published by the Free Software Foundation. If
+the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+               NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
+PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
+ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
+LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
+OR DATA BEING RENDERED INACCURATE OR LOSSES
+SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
+IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.
+
+          END OF TERMS AND CONDITIONS
diff --git a/sites/all/modules/form_builder/examples/form_builder_examples.info b/sites/all/modules/form_builder/examples/form_builder_examples.info
new file mode 100644
index 00000000..18828f40
--- /dev/null
+++ b/sites/all/modules/form_builder/examples/form_builder_examples.info
@@ -0,0 +1,11 @@
+name = Form builder examples
+description = Form builder support for CCK, Webform, and Profile modules.
+core = 7.x
+dependencies[] = form_builder
+
+; Information added by drupal.org packaging script on 2011-06-06
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "form_builder"
+datestamp = "1307319364"
+
diff --git a/sites/all/modules/form_builder/examples/form_builder_examples.module b/sites/all/modules/form_builder/examples/form_builder_examples.module
new file mode 100644
index 00000000..4766f8bf
--- /dev/null
+++ b/sites/all/modules/form_builder/examples/form_builder_examples.module
@@ -0,0 +1,479 @@
+<?php
+
+/**
+ * @file form_builder_examples.module
+ * Sample implementations of form_builder.
+ */
+
+/**
+ * Implementation of hook_menu().
+ */
+function form_builder_examples_menu() {
+  $items = array();
+
+  $items['form-builder-example'] = array(
+    'title' => 'Form builder example',
+    'page callback' => 'form_builder_interface',
+    'page arguments' => array('example', 'sample'),
+    'access arguments' => array('access content'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'form_builder.admin.inc',
+    'file path' => drupal_get_path('module', 'form_builder') . '/includes',
+  );
+
+  $items['form-builder-example/edit'] = array(
+    'title' => 'Edit',
+    'page callback' => 'form_builder_interface',
+    'page arguments' => array('example', 'sample'),
+    'access arguments' => array('access content'),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+
+  $items['form-builder-example/import'] = array(
+    'title' => 'Import',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_builder_examples_import_form'),
+    // TODO: Make a form import.
+    'access callback' => FALSE,
+    'access arguments' => array('access content'),
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  $items['form-builder-example/export'] = array(
+    'title' => 'Export',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_builder_examples_export_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  return $items;
+}
+
+/**
+ * A sample form array for testings.
+ */
+function form_builder_examples_example() {
+  $form = array(
+    'sample_textfield' => array(
+      '#form_builder' => array(
+        'element_id' => 'sample_textfield',
+        'element_type' => 'textfield',
+        'configurable' => TRUE,
+        'removable' => TRUE,
+      ),
+      '#type' => 'textfield',
+      '#title' => 'Sample textfield',
+      '#default_value' => 'a sample value',
+      '#field_prefix' => 'Prefix: ',
+      '#field_suffix' => ' :Suffix',
+      '#size' => 20,
+      '#weight' => 0,
+    ),
+    'sample_checkboxes' => array(
+      '#form_builder' => array(
+        'element_id' => 'sample_checkboxes',
+        'element_type' => 'checkboxes',
+        'configurable' => TRUE,
+        'removable' => TRUE,
+      ),
+      '#type' => 'checkboxes',
+      '#title' => 'Sample checkboxes',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => array('two'),
+      '#weight' => 1,
+      '#multiple' => 1,
+    ),
+    'sample_textarea' => array(
+      '#form_builder' => array(
+        'element_id' => 'sample_textarea',
+        'element_type' => 'textarea',
+        'configurable' => TRUE,
+        'removable' => TRUE,
+      ),
+      '#type' => 'textarea',
+      '#title' => 'Sample textarea',
+      '#default_value' => 'Text area sample value',
+      '#weight' => 2,
+    ),
+    'sample_radios' => array(
+      '#form_builder' => array(
+        'element_id' => 'sample_radios',
+        'element_type' => 'radios',
+        'configurable' => TRUE,
+        'removable' => TRUE,
+      ),
+      '#type' => 'radios',
+      '#title' => 'Sample radios',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'two',
+      '#weight' => 3,
+    ),
+    'sample_select' => array(
+      '#form_builder' => array(
+        'element_id' => 'sample_select',
+        'element_type' => 'select',
+        'configurable' => TRUE,
+        'removable' => TRUE,
+      ),
+      '#type' => 'select',
+      '#title' => 'Sample select',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+      '#default_value' => 'two',
+      '#weight' => 4,
+      '#multiple_toggle' => TRUE,
+    ),
+  );
+
+  return $form;
+}
+
+/**
+ * Implementation of hook_form_builder_field_access().
+ */
+function form_builder_examples_form_builder_field_access($op, $form_type, $form_id, $element) {
+  // If desiring to add extra access permissions return FALSE if access is denied.
+  // return user_access('administer content types');
+}
+
+/**
+ * Implementation of hook_form_builder_types().
+ *
+ * Define the supported fields and properties supported by CCK.
+ */
+function form_builder_examples_form_builder_types() {
+  $fields = array();
+
+  $fields['fieldset'] = array(
+    'title' => t('Fieldset'),
+    'properties' => array(
+      'title',
+      'description',
+      'collapsible',
+      'collapsed',
+    ),
+    'default' => array(
+      '#title' => t('New fieldset'),
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => FALSE,
+    ),
+  );
+
+  $fields['number'] = array(
+    'title' => t('Number'),
+    'properties' => array(
+      'title',
+      'description',
+      'field_prefix',
+      'field_suffix',
+      'default_value',
+      'required',
+    ),
+    // TODO: how to handle validate functions?
+    'validate' => array(
+      'number',
+    ),
+    'default' => array(
+      '#key' => 'number',
+      '#title' => t('New number'),
+      '#type' => 'textfield',
+    ),
+  );
+
+  $fields['select'] = array(
+    'title' => t('Select list'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple', // Handled by options element.
+      'key_type', // Handled by options element.
+      'key_type_toggle', // Handled by options element.
+      'key_type_toggled', // Handled by options element.
+    ),
+    'default' => array(
+      '#title' => t('New select list'),
+      '#type' => 'select',
+      '#options' => array('1' => 'one', '2' => 'two', '3' => 'three'),
+      '#multiple_toggle' => TRUE,
+    ),
+  );
+
+  // TODO: Merge checkbox with checkboxes?
+  /*
+  $fields['checkbox'] = array(
+    'title' => t('Checkbox'),
+    'properties' => array(
+      'title',
+      'description',
+      'return_value',
+      'default_value',
+      'required',
+     ),
+    'default' => array(
+      '#title' => t('New checkbox'),
+      '#type' => 'checkbox',
+    ),
+  );
+  */
+
+  $fields['checkboxes'] = array(
+    'title' => t('Checkboxes'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key_type', // Handled by options element.
+      'key_type_toggle', // Handled by options element.
+      'key_type_toggled', // Handled by options element.
+    ),
+    'default' => array(
+      '#title' => t('New checkboxes'),
+      '#type' => 'checkboxes',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+    ),
+  );
+
+  $fields['radios'] = array(
+    'title' => t('Radios'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'key_type', // Handled by options element.
+      'key_type_toggle', // Handled by options element.
+      'key_type_toggled', // Handled by options element.
+    ),
+    'default' => array(
+      '#title' => t('New radios'),
+      '#type' => 'radios',
+      '#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
+    ),
+  );
+
+  $fields['textfield'] = array(
+    'title' => t('Textfield'),
+    'properties' => array(
+      'title',
+      'description',
+      'field_prefix',
+      'field_suffix',
+      'default_value',
+      'required',
+      'size',
+    ),
+    'default' => array(
+      '#title' => t('New textfield'),
+      '#type' => 'textfield',
+    ),
+  );
+
+  $fields['textarea'] = array(
+    'title' => t('Textarea'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'rows',
+      'cols',
+    ),
+    'default' => array(
+      '#title' => t('New textarea'),
+      '#type' => 'textarea',
+    ),
+  );
+
+  $fields['file'] = array(
+    'title' => t('File'),
+    'properties' => array(
+      'title',
+      'description',
+      'required',
+      'size',
+      'file_extension_validate',
+      'file_size_validate',
+    ),
+    'default' => array(
+      '#title' => t('New file'),
+      '#type' => 'file',
+      '#size' => 30,
+    ),
+  );
+
+  $fields['image'] = array(
+    'title' => t('Image'),
+    'properties' => array(
+      'title',
+      'description',
+      'required',
+    ),
+    'validate' => array(
+      'file_extension_validate',
+      'file_size_validate',
+      'file_image_size',
+    ),
+    'default' => array(
+      '#title' => t('New image'),
+      '#type' => 'file',
+      '#size' => 30,
+    ),
+  );
+
+  return array(
+    'example' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_preview_alter().
+ */
+function form_builder_examples_form_builder_preview_alter($element, $form_type, $form_id) {
+  if ($form_type == 'form_builder_examples') {
+    if (isset($element['#description'])) {
+      $element['#description'] = filter_xss($element['#description']);
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_load().
+ *
+ * Convert a CCK content type into a standard form builder array.
+ *
+ * @param $form_id
+ *   The unique identifier for the form being edited. For CCK, this is the
+ *   content type name.
+ */
+function form_builder_examples_form_builder_load($form_type, $form_id) {
+  if ($form_type == 'example') {
+    $form = form_builder_examples_example();
+
+    return $form;
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ *
+ * Take a form builder array and save it to the content type.
+ */
+function form_builder_examples_form_builder_save($form, $form_type, $form_id) {
+  if ($form_type == 'example') {
+    // Save the settings based on the changes to the $form array.
+  }
+}
+
+/**
+ * Menu callback for importing an entire FAPI array.
+ */
+function form_builder_examples_import_form(&$form_state) {
+  $form = array();
+
+  $form['import'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Import code'),
+  );
+
+  return $form;
+}
+
+/**
+ * Menu callback for exporting an entire FAPI array.
+ */
+function form_builder_examples_export_form() {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  $form = array();
+
+  $current = form_builder_cache_load('example', 'sample');
+
+  $form['export'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Export code'),
+    '#default_value' => form_builder_examples_export($current),
+    '#attributes' => array('readonly' => 'readonly', 'style' => 'font-family: monospace;'),
+    '#rows' => 20,
+  );
+
+  return $form;
+}
+
+
+function form_builder_examples_export($form) {
+  $output = '';
+  $output .= form_builder_examples_export_recurse($form);
+  $output .= 'return $form;';
+  return $output;
+}
+
+/**
+ * Recursive function for pretty-printing of FAPI arrays.
+ */
+function form_builder_examples_export_recurse($form, $parents = array()) {
+  $output = '';
+
+  // Sort this level of the array according to weight.
+  uasort($form, 'element_sort');
+
+  // Print out this parent element and it's properties.
+  $properties = element_properties($form);
+  $omit = array('#form_builder', '#key');
+  if (count($properties)) {
+    $output .= form_builder_examples_export_variable_name($parents) . " = array(\n";
+    foreach (element_properties($form) as $property) {
+      if (!in_array($property, $omit)) {
+        if (is_array($form[$property])) {
+          $output .= "  '". $property . "' => array(\n";
+          foreach ($form[$property] as $key => $value) {
+            if ($property == '#options') {
+              $output .= "    '" . $key . "' => t('". $value ."'),\n";
+            }
+            else {
+              $output .= "    '" . $key . "' => '". $value ."',\n";
+            }
+          }
+          $output .= "  ),\n";
+        }
+        else {
+          if (($property == '#title') || ($property == '#description')) {
+            $output .= "  '". $property . "' => t('" . $form[$property] ."'),\n";
+          }
+          else {
+            $output .= "  '". $property . "' => '" . $form[$property] ."',\n";
+          }
+        }
+      }
+    }
+    $output .= ");\n";
+  }
+  else {
+    $output .= form_builder_examples_export_variable_name($parents) . " = array();\n";
+  }
+
+  foreach (element_children($form) as $key) {
+    $parents[] = $key;
+    $output .= form_builder_examples_export_recurse($form[$key], $parents);
+    array_pop($parents);
+  }
+
+  return $output;
+}
+
+
+function form_builder_examples_export_variable_name($parents) {
+  $output = '$form';
+  foreach ($parents as $parent) {
+    $output .= "['". $parent ."']";
+  }
+  return $output;
+}
diff --git a/sites/all/modules/form_builder/form_builder.css b/sites/all/modules/form_builder/form_builder.css
new file mode 100644
index 00000000..8de5c3ae
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.css
@@ -0,0 +1,361 @@
+
+#form-builder-wrapper {
+  overflow: hidden;
+  padding: 10px 0;
+}
+
+#form-builder-wrapper.with-palette #form-builder-fields {
+  float: right;
+  padding-left: 10px;
+  width: 260px;
+}
+
+#form-builder-wrapper.with-palette #form-builder {
+  float: none;
+  margin-right: 270px;
+  padding-right: 9px;
+  border-right: 1px solid #CCC;
+  position: relative;
+}
+
+#center #form-builder form,
+#form-builder form {
+  margin: 0;
+}
+
+#form-builder form.confirmation {
+  padding: 10px;
+}
+
+div.form-builder-wrapper {
+  padding: 1px;
+  margin-top: 4px; /* Match this to the Sortable drag threshold option. */
+  position: relative;
+}
+
+div.form-builder-element {
+  margin: 4px 10px 4px 10px;
+}
+
+div.form-builder-hover {
+  border: 1px dashed #999;
+  padding: 0;
+}
+
+div.form-builder-active {
+  padding: 0;
+  border: 1px solid #999;
+}
+
+div.form-builder-wrapper form {
+  border-top: 1px dashed #999;
+}
+
+div.form-builder-element {
+  position: relative;
+}
+
+div.form-builder-draggable,
+div.form-builder-draggable input,
+div.form-builder-draggable textarea,
+div.form-builder-draggable label,
+div.form-builder-draggable .grippie {
+  cursor: move;
+}
+
+div.form-builder-clickable,
+div.form-builder-clickable input,
+div.form-builder-clickable textarea,
+div.form-builder-clickable label,
+div.form-builder-clickable .grippie {
+  cursor: pointer;
+}
+
+div.form-builder-element .form-builder-disable {
+  z-index: 100;
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
+/* Empty fieldsets */
+#form-builder fieldset {
+  padding-bottom: 20px;
+}
+
+fieldset.form-builder-empty-fieldset,
+div.form-builder-empty-fieldset {
+  overflow: hidden;
+}
+
+div.form-builder-empty-placeholder {
+  border: none;
+  text-align: center;
+  color: #CCC;
+  overflow: hidden;
+}
+
+div.form-builder-empty-placeholder span {
+  display: block;
+  margin: 40px;
+}
+
+/* Placeholders for drop position */
+div.form-builder-placeholder {
+  height: 60px;
+  margin-top: -30px;
+  position: absolute;
+  width: 100%;
+}
+
+div.form-builder-placeholder-hover {
+  margin: 0;
+  position: relative;
+  border: 1px dashed #999;
+}
+
+/* This affects the fieldset placeholder text on hover */
+div.form-builder-placeholder-hover span {
+  visibility: hidden;
+}
+
+/* The item being dragged */
+#form-builder .ui-draggable-dragging {
+  width: 100%;
+}
+
+/* Title bar for form builder items */
+div.form-builder-title-bar {
+  position: relative;
+  z-index: 10;
+  padding-top: 4px;
+  height: 14px;
+  margin-bottom: -18px;
+  border-bottom: none;
+}
+
+div.ui-draggable div.form-builder-title-bar {
+  display: none;
+}
+
+div.ui-draggable div.form-builder-title-bar {
+  cursor: move;
+}
+
+span.form-builder-links {
+  position: absolute;
+  right: 0;
+  z-index: 40;
+}
+
+div.form-builder-hover div.form-builder-title-bar,
+div.form-builder-active div.form-builder-title-bar {
+  display: block;
+}
+
+div.form-builder-hover div.form-builder-wrapper div.form-builder-title-bar,
+div.form-builder-active div.form-builder-wrapper div.form-builder-title-bar {
+  display: none;
+}
+
+span.form-builder-links a.remove,
+span.form-builder-links a.configure {
+  float: right;
+  display: block;
+  height: 1.7em;
+  text-decoration: none;
+  height: 13px;
+  width: 13px;
+  padding: 2px 3px;
+  cursor: pointer;
+}
+
+span.form-builder-links a.remove span,
+span.form-builder-links a.configure span {
+  display: none;
+}
+
+span.form-builder-links a.remove {
+  background: url(images/delete.png) no-repeat 0 1px;
+}
+
+span.form-builder-links a.configure {
+  background: url(images/configure.png) no-repeat 0 1px;
+}
+
+span.form-builder-links a.remove:hover,
+span.form-builder-links a.configure:hover {
+  background-position: 0 -19px;
+}
+
+span.form-builder-links a.progress,
+span.form-builder-links a.progress:hover {
+  background: url(images/status-active.gif) no-repeat 0 1px;
+}
+
+/* Field form tabs */
+#form-builder ul.form-builder-tabs {
+  margin: 0;
+  padding: 0;
+}
+
+#form-builder ul.form-builder-tabs li {
+  float: left; /* RTL */
+  display: block;
+  border-width: 0 1px 0 0;
+  border-color: #999;
+  border-style: solid;
+  padding: 6px 10px;
+  margin: -1px -1px -1px 0px;
+  list-style-type: none;
+  list-style-image: none;
+  background: none;
+  cursor: pointer;
+  z-index: 20;
+  position: relative;
+}
+
+#form-builder ul.form-builder-tabs li.active {
+  margin-left: -1px;
+  border-left: 1px solid #999;
+  border-top: 1px dashed #999;
+  border-bottom: 1px solid #ebf4fa;
+  background: #ebf4fa;
+}
+
+#form-builder-field-configure .form-submit {
+  display: none;
+}
+
+#form-builder-field-configure a.close {
+  border: none;
+  margin: 0;
+  font-size: 80%;
+  float: right;
+  padding: 6px 10px;
+}
+
+#form-builder fieldset.form-builder-group {
+  margin: 0;
+  border: none;
+  border-top: 1px solid #CCC;
+}
+
+/* Weight and parents form */
+form#form-builder-positions {
+  display: none;
+}
+
+/* New fields block */
+div.form-builder-new-field {
+  padding: 10px 20px;
+}
+
+div.form-builder-new-field span.progress {
+  padding-left: 16px;
+  background: url(images/status-active.gif) no-repeat center left;
+}
+
+#form-builder-field-palette .item-list {
+  margin: 0 0 10px 0;
+}
+
+#form-builder-field-palette h3 {
+  margin: 0;
+}
+
+#form-builder-field-palette ul.form-builder-fields {
+  width: 260px;
+  padding: 0;
+}
+
+#form-builder-field-palette ul li {
+  list-style-type: none;
+  background: white none no-repeat 6px center;
+  padding: 2px 2px 2px 28px;
+  border: 1px solid #999;
+  margin: 2px;
+  float: left;
+  width: 80px;
+  font-size: 11px;
+  cursor: move;
+  display: block;
+}
+
+#form-builder-field-palette ul li a,
+#form-builder-field-palette ul li a:hover,
+#form-builder-field-palette ul li a:active,
+#form-builder-field-palette ul li a:visited {
+  text-decoration: none;
+  cursor: move;
+  color: black;
+}
+
+#form-builder-field-palette ul li.field-body_field {
+  background-image: url(images/fields/body.png);
+}
+#form-builder-field-palette ul li.field-checkboxes {
+  background-image: url(images/fields/checkboxes.png);
+}
+#form-builder-field-palette ul li.field-date {
+  background-image: url(images/fields/date.png);
+}
+#form-builder-field-palette ul li.field-email {
+  background-image: url(images/fields/email.png);
+}
+#form-builder-field-palette ul li.field-fieldset {
+  background-image: url(images/fields/fieldset.png);
+}
+#form-builder-field-palette ul li.field-file,
+#form-builder-field-palette ul li.field-upload_settings {
+  background-image: url(images/fields/file.png);
+}
+#form-builder-field-palette ul li.field-grid {
+  background-image: url(images/fields/grid.png);
+}
+#form-builder-field-palette ul li.field-hidden {
+  background-image: url(images/fields/hidden.png);
+}
+#form-builder-field-palette ul li.field-image {
+  background-image: url(images/fields/image.png);
+}
+#form-builder-field-palette ul li.field-markup {
+  background-image: url(images/fields/markup.png);
+}
+#form-builder-field-palette ul li.field-menu_settings {
+  background-image: url(images/fields/menu.png);
+}
+#form-builder-field-palette ul li.field-number {
+  background-image: url(images/fields/number.png);
+}
+#form-builder-field-palette ul li.field-pagebreak {
+  background-image: url(images/fields/pagebreak.png);
+}
+#form-builder-field-palette ul li.field-path_settings {
+  background-image: url(images/fields/path.png);
+}
+#form-builder-field-palette ul li.field-radios {
+  background-image: url(images/fields/radios.png);
+}
+#form-builder-field-palette ul li.field-revision_information {
+  background-image: url(images/fields/revisions.png);
+}
+#form-builder-field-palette ul li.field-select {
+  background-image: url(images/fields/select.png);
+}
+#form-builder-field-palette ul li.field-time {
+  background-image: url(images/fields/time.png);
+}
+#form-builder-field-palette ul li.field-taxonomy {
+  background-image: url(images/fields/taxonomy.png);
+}
+#form-builder-field-palette ul li.field-textarea {
+  background-image: url(images/fields/textarea.png);
+}
+#form-builder-field-palette ul li.field-textfield {
+  background-image: url(images/fields/textfield.png);
+}
+#form-builder-field-palette ul li.field-title {
+  background-image: url(images/fields/title.png);
+}
+
diff --git a/sites/all/modules/form_builder/form_builder.garland.css b/sites/all/modules/form_builder/form_builder.garland.css
new file mode 100644
index 00000000..abe75b97
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.garland.css
@@ -0,0 +1,21 @@
+
+/**
+ * @file
+ *   Garland-specific theming for Form Builder. Expand the column to fit
+ *   the add new field block (260px wide). 
+ */
+
+body.sidebar-right #center {
+  margin-right: -280px;
+}
+body.sidebars #center {
+  margin: 0 -280px 0 -210px;
+}
+
+/* And add blanks left and right for the sidebars to fill */
+body.sidebar-right #squeeze {
+  margin-right: 280px;
+}
+body.sidebars #squeeze {
+  margin: 0 280px 0 210px;
+}
diff --git a/sites/all/modules/form_builder/form_builder.info b/sites/all/modules/form_builder/form_builder.info
new file mode 100644
index 00000000..70320e87
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.info
@@ -0,0 +1,11 @@
+name = Form builder
+description = Form building framework.
+dependencies[] = options_element
+core = 7.x
+
+; Information added by drupal.org packaging script on 2011-06-06
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "form_builder"
+datestamp = "1307319364"
+
diff --git a/sites/all/modules/form_builder/form_builder.install b/sites/all/modules/form_builder/form_builder.install
new file mode 100644
index 00000000..7a3ba3e0
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.install
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function form_builder_uninstall() {
+  $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'form_builder_%'");
+  foreach ($result as $row) {
+    variable_del($row->name);
+  }
+}
+
+/**
+ * Implementation of hook_requirements().
+ */
+function form_builder_requirements($phase) {
+  $requirements = array();
+  $t = get_t();
+  if ($phase == 'runtime') {
+    $form_builder_types = module_invoke_all('form_builder_types');
+    if (empty($form_builder_types)) {
+      $requirements['form_builder_types']['title'] = $t('Form builder');
+      $requirements['form_builder_types']['severity'] = REQUIREMENT_ERROR;
+      $requirements['form_builder_types']['description'] = t('Form builder module is installed but no modules implement support for it. You may want to disable Form builder module until it is needed.');
+    }
+  }
+
+  return $requirements;
+}
+
+/**
+ * Implementation of hook_schema().
+ */
+function form_builder_schema() {
+  $schema = array();
+
+  $schema['form_builder_cache'] = array(
+    'fields' => array(
+      'sid' => array(
+        'type' => 'varchar',
+        'length' => '64',
+        'not null' => FALSE,
+        ),
+      'form_id' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => FALSE,
+      ),
+      'type' => array(
+          'type' => 'varchar',
+          'length' => '32',
+          'not null' => FALSE,
+      ),
+      'updated' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'disp-width' => '10',
+      ),
+      'data' => array(
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big',
+      ),
+    ),
+    'indexes' => array(
+       'sid_obj_name' => array('sid', 'type', 'form_id'),
+       'updated' => array('updated'),
+    ),
+  );
+
+  return $schema;
+}
+
+/**
+ * Change the {form_builder_cache} table to use a 'longblob' data column.
+ */
+function form_builder_update_7000() {
+  $spec = array(
+    'type' => 'blob',
+    'not null' => FALSE,
+    'size' => 'big',
+  );
+  db_change_field('form_builder_cache', 'data', 'data', $spec);
+}
diff --git a/sites/all/modules/form_builder/form_builder.js b/sites/all/modules/form_builder/form_builder.js
new file mode 100644
index 00000000..a8d4da24
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.js
@@ -0,0 +1,948 @@
+(function($) {
+
+/**
+ * @file form_builder.js
+ * Provide enhancements to the form building user interface.
+ */
+
+Drupal.behaviors.formBuilderElement = {};
+Drupal.behaviors.formBuilderElement.attach = function(context) {
+  var $wrappers = $('div.form-builder-wrapper', context);
+  var $elements = $('div.form-builder-element', context);
+
+  // If the context itself is a wrapper, add it to the list.
+  if ($(context).is('div.form-builder-wrapper')) {
+    $wrappers = $wrappers.add(context);
+  }
+
+  // Add over effect on rollover.
+  // The .hover() method is not used to avoid issues with nested hovers.
+  $wrappers.not('div.form-builder-empty-placeholder')
+    .bind('mouseover', Drupal.formBuilder.addHover)
+    .bind('mouseout', Drupal.formBuilder.removeHover);
+
+  // Add AJAX to edit links.
+  $wrappers.find('span.form-builder-links a.configure').click(Drupal.formBuilder.editField);
+
+  // Add AJAX to remove links.
+  $wrappers.find('span.form-builder-links a.remove').click(Drupal.formBuilder.editField);
+
+  // Add AJAX to entire field for easy editing.
+  $elements.each(function() {
+    if ($(this).children('fieldset.form-builder-fieldset').length == 0) {
+      var link = $(this).parents('div.form-builder-wrapper:first').find('a.configure').get(0);
+      if (link) {
+        $(this).click(Drupal.formBuilder.clickField).addClass('form-builder-clickable');
+        $(this).find('div.form-builder-element label').click(Drupal.formBuilder.clickField);
+      }
+      else {
+        $(this).addClass('form-builder-draggable');
+      }
+    }
+  });
+
+  // Disable field functionality on click.
+  $elements.find('input, textarea').bind('mousedown', Drupal.formBuilder.disableField);
+};
+
+/**
+ * Behavior to disable preview fields and instead open up the configuration.
+ */
+Drupal.behaviors.formBuilderFields = {};
+Drupal.behaviors.formBuilderFields.attach = function(context) {
+  // Bind a function to all elements to update the preview on change.
+  var $configureForm = $('#form-builder-field-configure', context);
+
+  $configureForm.find('input, textarea, select')
+    .not('.form-builder-field-change')
+    .addClass('form-builder-field-change')
+    .bind('change', Drupal.formBuilder.elementPendingChange);
+
+  $configureForm.find('input.form-text, textarea')
+    .not('.form-builder-field-keyup')
+    .addClass('form-builder-field-keyup')
+    .bind('keyup', Drupal.formBuilder.elementPendingChange);
+};
+
+/**
+ * Behavior for the entire form builder. Add drag and drop to elements.
+ */
+Drupal.behaviors.formBuilder = {};
+Drupal.behaviors.formBuilder.attach = function(context) {
+  var formbuilder = $('#form-builder', context);
+
+  $('.form-builder-wrapper:not(.ui-draggable)', formbuilder).draggable({
+    opacity: 0.8,
+    helper: 'clone',
+    scroll: true,
+    scrollSensitivity: 50,
+    containment: 'body',
+    start: Drupal.formBuilder.startDrag,
+    stop: Drupal.formBuilder.stopDrag,
+    change: Drupal.formBuilder.checkFieldsets,
+    distance: 4,
+    scope: 'fields',
+    addClasses: false,
+    appendTo: '#form-builder-wrapper'
+  });
+
+  // This sets the height of the drag target to be at least as hight as the field
+  // palette so that field can be more easily dropped into an empty form.  IE6
+  // does not respect min-height but does treat height in the same manner that
+  // min-height would be expected.  So a check for browser and version is needed
+  // here.
+  var property = $.browser.msie && $.browser.version < 7 ? 'height' : 'min-height';
+  formbuilder.css(property, $('#form-builder-fields').height());
+};
+
+/**
+ * Behavior that renders fieldsets as tabs within the field configuration form.
+ */
+Drupal.behaviors.formBuilderTabs = {};
+Drupal.behaviors.formBuilderTabs.attach = function(context) {
+  var $fieldsets = $('fieldset.form-builder-group:not(.form-builer-tabs-processed)', context);
+  var $close = $('<a class="close" href="#">' + Drupal.t('Close') + '</a>');
+  var $tabs;
+  var tabs = '';
+
+  // Convert fieldsets to tabs.
+  tabs = '<ul class="form-builder-tabs tabs clearfix">';
+  $fieldsets.children('legend').each(function() {
+    tabs += '<li>' + this.innerHTML + '</li>';
+    $(this).remove();
+  });
+  tabs += '</ul>';
+
+  // Add the new tabs to the page.
+  $tabs = $(tabs);
+  $fieldsets.filter(':first').before($close).before($tabs);
+
+  // Hide all the fieldsets except the first.
+  $fieldsets.not(':first').css('display', 'none');
+  $tabs.find('li:first').addClass('active').click(Drupal.formBuilder.clickCancel);
+
+  // Enable tab switching by clicking on each tab.
+  $tabs.find('li:not(.close)').each(function(index) {
+    $(this).click(function() {
+      $fieldsets.filter(':visible').css('display', 'none');
+      $fieldsets.eq(index).css('display', 'block');
+      $tabs.find('li.active').removeClass('active').unbind('click', Drupal.formBuilder.clickCancel);
+      $(this).addClass('active').click(Drupal.formBuilder.clickCancel);
+      Drupal.formBuilder.fixTableDragTabs($fieldsets.eq(index).get(0));
+    });
+  });
+
+  $close.click(Drupal.formBuilder.clickCancel);
+
+  // Add guard class.
+  $fieldsets.addClass('form-builer-tabs-processed');
+};
+
+/**
+ * Submit the delete form via AJAX or close the form with the cancel link.
+ */
+Drupal.behaviors.formBuilderDeleteConfirmation = {};
+Drupal.behaviors.formBuilderDeleteConfirmation.attach = function(context) {
+  var $confirmForm = $('form.confirmation', context);
+  if ($confirmForm.length) {
+    $confirmForm.find('input[type=submit]').bind('click', function(event) {
+      event.preventDefault();
+      // Store the form and the options
+      var form = $confirmForm;
+      Drupal.formBuilder.ajaxOptions = {
+        url: form.attr('action'),
+        success: Drupal.formBuilder.deleteField,
+        error: Drupal.formBuilder.ajaxError,
+        type: 'post',
+        dataType: 'json',
+        action: 'deleteConfirmation',
+        data: form.serialize(),
+        tryCount: 0,
+        maxTry: 3
+      };
+      // Submit the form via ajax
+      $.ajax(Drupal.formBuilder.ajaxOptions);
+      // Bind this action to disable any submit buttons on the page.  It will be
+      // removed on success or after the retries have been exhausted.
+      $('form').submit(Drupal.formBuilder.preventSubmit);
+    });
+    $confirmForm.find('a').click(Drupal.formBuilder.clickCancel);
+  }
+};
+
+/**
+ * Keeps record of if a mouse button is pressed.
+ */
+Drupal.behaviors.formBuilderMousePress = {};
+Drupal.behaviors.formBuilderMousePress.attach = function(context) {
+  if (context == document) {
+    $('body').mousedown(function() { Drupal.formBuilder.mousePressed = 1; });
+    $('body').mouseup(function() { Drupal.formBuilder.mousePressed = 0; });
+  }
+};
+
+/**
+ * Scrolls the add new field block with the window.
+ */
+Drupal.behaviors.formBuilderBlockScroll = {};
+Drupal.behaviors.formBuilderBlockScroll.attach = function(context) {
+  var $list = $('ul.form-builder-fields', context);
+
+  if ($list.length && $list.hasClass('block-scroll')) {
+    var $block = $list.parents('div.block:first').css('position', 'relative');
+    var blockScrollStart = $block.offset().top;
+
+    function blockScroll() {
+      // Do not move the palette while dragging a field.
+      if (Drupal.formBuilder.activeDragUi) {
+        return;
+      }
+
+      var windowOffset = $(window).scrollTop();
+      var blockHeight = $block.height();
+      var formBuilderHeight = $('#form-builder').height();
+      if (windowOffset - blockScrollStart > 0) {
+        // Do not scroll beyond the bottom of the editing area.
+        var newTop = Math.min(windowOffset - blockScrollStart + 20, formBuilderHeight - blockHeight);
+        $block.animate({ top: (newTop + 'px') }, 'fast');
+      }
+      else {
+        $block.animate({ top: '0px' }, 'fast');
+      }
+    }
+
+    var timeout = false;
+    function scrollTimeout() {
+      if (timeout) {
+        clearTimeout(timeout);
+      }
+      timeout = setTimeout(blockScroll, 100);
+    }
+
+    $(window).scroll(scrollTimeout);
+  }
+};
+
+/**
+ * Behavior for the Add a field block.
+ * @param {Object} context
+ */
+Drupal.behaviors.formBuilderNewField = {};
+Drupal.behaviors.formBuilderNewField.attach = function(context) {
+  var $list = $('ul.form-builder-fields', context);
+
+  if ($list.length) {
+    // Allow items to be copied from the list of new fields.
+    $list.children('li:not(.ui-draggable)').draggable({
+      opacity: 0.8,
+      helper: 'clone',
+      scroll: true,
+      scrollSensitivity: 50,
+      containment: 'body',
+      start: Drupal.formBuilder.startDrag,
+      stop: Drupal.formBuilder.stopDrag,
+      distance: 4,
+      scope: 'fields',
+      appendTo: '#form-builder-wrapper'
+    })
+    .bind('click', function(event) {
+      event.preventDefault();
+      event.stopPropagation();
+      var item = $(this).clone();
+      // Add a drop target at the bottom of the form to automatically drop the
+      // element onto.
+      var placeholder = $('<div class="form-builder-placeholder"></div>');
+      placeholder
+        .appendTo('#form-builder')
+        .droppable({
+          scope: 'fields',
+          drop: Drupal.formBuilder.drop
+        });
+      Drupal.formBuilder.drop({data: placeholder}, {draggable: item});
+      // Pass the element to the stopDrag method so that unique elements are
+      // properly hidden in the palette.
+      Drupal.formBuilder.stopDrag.apply(this);
+    });
+  }
+};
+
+Drupal.formBuilder = {
+  // Variable to prevent multiple requests.
+  updatingElement: false,
+  // Variables to allow delayed updates on textfields and textareas.
+  updateDelayElement: false,
+  updateDelay: false,
+  // Variable holding the actively edited element (if any).
+  activeElement: false,
+  // Variable holding the active drag object (if any).
+  activeDragUi: false,
+  // Variable of the time of the last update, used to prevent old data from
+  // replacing newer updates.
+  lastUpdateTime: 0,
+  // Status of mouse click.
+  mousePressed: 0,
+  // Field configure form target
+  fieldConfigureHolder: false
+};
+
+/**
+ * Event callback for mouseover of fields. Adds hover class.
+ */
+Drupal.formBuilder.addHover = function() {
+  // Do not add hover effect while dragging over other fields.
+  if (!Drupal.formBuilder.activeDragUi && !Drupal.formBuilder.mousePressed) {
+    if ($(this).find('div.form-builder-hover').length == 0) {
+      $(this).addClass('form-builder-hover');
+    }
+  }
+};
+
+/**
+ * Event callback for mouseout of fields. Removes hover class.
+ */
+Drupal.formBuilder.removeHover = function() {
+  // Do not add hover effect while dragging over other fields.
+  if (!Drupal.formBuilder.activeDragUi && !Drupal.formBuilder.mousePressed) {
+    $(this).removeClass('form-builder-hover');
+  }
+};
+
+/**
+ * Click handler for fields.
+ *
+ * Note this is applied to both the entire field and to the labels within the
+ * field, as they have special browser behavior that needs to be overridden.
+ */
+Drupal.formBuilder.clickField = function(e) {
+  // Allow select lists to be clicked on without opening the edit options.
+  if ($(e.target).is('select')) {
+    return;
+  }
+
+  var wrapper = $(this).parents('.form-builder-wrapper:first');
+  // This will get the first configure link that does not belong to a nested form element
+  // inside this form element.
+  var link = wrapper.find('a.configure').not(wrapper.find('.form-builder-element .form-builder-element a')).get(0);
+  
+  Drupal.formBuilder.editField.apply(link);
+
+  return false;
+};
+
+/**
+ * Mousedown event on element previews.
+ */
+Drupal.formBuilder.disableField = function(e) {
+  return false;
+};
+
+/**
+ * Load the edit form from the server.
+ */
+Drupal.formBuilder.editField = function(event) {
+  if (event && $(event.target).is('a')) {
+    event.stopPropagation();
+  }
+  var element = $(this).parents('div.form-builder-wrapper').get(0);
+  var link = $(this);
+
+  // Prevent duplicate clicks from taking effect if already handling a click.
+  if (Drupal.formBuilder.updatingElement) {
+    return false;
+  }
+
+  link.addClass('progress');
+
+  // If clicking on the link a second time, close the form instead of open.
+  if (element == Drupal.formBuilder.activeElement && link.get(0) == Drupal.formBuilder.activeLink) {
+    Drupal.formBuilder.closeActive(function() {
+      link.removeClass('progress');
+      if (Drupal.formBuilder.fieldConfigureForm) {
+        Drupal.formBuilder.fieldConfigureForm.html($('<div class="field-settings-message">' + Drupal.t('No field selected') + '</div>'));
+      }
+    });
+    Drupal.formBuilder.unsetActive();
+    return false;
+  }
+
+  if (!Drupal.formBuilder.fieldConfigureForm) {
+    $('<div id="#form-builder-field-configure" class="form-builder-field-configure"><div class="field-settings-message">' + Drupal.t('Loading...') + '</div></div>').appendTo(element);
+  } else {
+    $('.field-settings-message').remove();
+    Drupal.formBuilder.fieldConfigureForm.append($('<div class="field-settings-message">' + Drupal.t('Loading...') + '</div>'));
+  }
+  
+
+  var getForm = function() {
+    Drupal.formBuilder.ajaxOptions = {
+      url: link.attr('href'),
+      type: 'GET',
+      dataType: 'json',
+      data: 'js=1',
+      success: Drupal.formBuilder.displayForm,
+      error: Drupal.formBuilder.ajaxError,
+      errorMessage: Drupal.t('Form could not be loaded at this time. Please try again later.'),
+      tryCount: 0,
+      maxTry: 3
+    }
+    
+    $.ajax(Drupal.formBuilder.ajaxOptions);
+  };
+
+  Drupal.formBuilder.updatingElement = true;
+  Drupal.formBuilder.closeActive(getForm);
+  Drupal.formBuilder.setActive(element, link.get(0));
+
+  return false;
+};
+
+/**
+ * Click handler for deleting a field.
+ */
+Drupal.formBuilder.deleteField = function(callback) {
+  var active = $(Drupal.formBuilder.activeElement);
+  // Renable form submission.
+  $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
+  active.fadeOut(function() {
+    // If this is a unique field, show the field in the palette again.
+    var elementId = active.find('.form-builder-element').attr('id');
+    $('ul.form-builder-fields').find('li.' + elementId).show('slow');
+    // Remove the field from the form.
+    active.remove();
+    // Close the form and unset the active element
+    Drupal.formBuilder.clickCancel();
+    // Check for empty fieldsets.
+    Drupal.formBuilder.checkFieldsets(null, null, true);
+
+    if (callback && $.isFunction(callback)) {
+      callback();
+    }
+  });
+};
+
+Drupal.formBuilder.clickCancel = function() {
+  Drupal.formBuilder.closeActive();
+  Drupal.formBuilder.unsetActive();
+  return false;
+};
+
+/**
+ * Display the edit form from the server.
+ */
+Drupal.formBuilder.displayForm = function(response) {
+  if (response.settings) {
+    $.extend(true, Drupal.settings, response.settings);
+  }
+  var $preview = $('#form-builder-element-' + response.elementId);
+  var $form = $(response.html)
+  if (!Drupal.formBuilder.fieldConfigureForm) {
+    $('.form-builder-field-configure').html($form);
+    $form.css('display', 'none');
+  } else {
+    Drupal.formBuilder.fieldConfigureForm.html($form);
+    $form.css('visibility: hidden');
+  }
+  $('.field-settings-message').remove();
+  Drupal.attachBehaviors($form.parent().get(0));
+
+  $form
+    // Add the ajaxForm behavior to the new form.
+    .ajaxForm()
+    // Using the 'data' $.ajaxForm property doesn't seem to work.
+    // Manually add a hidden element to pass additional data on submit.
+    .prepend('<input type="hidden" name="return" value="field" />')
+    // Add in any messages from the server.
+    .find('fieldset:visible:first').prepend(response.messages);
+
+  $form.css({visibility: 'visible', display: 'none'});
+  $form.slideDown(function() {
+    $preview.parents('.form-builder-wrapper:first').find('a.progress').removeClass('progress');
+  });
+
+  // Give focus to the form
+  $form.find('input:visible:first').focus();
+
+  Drupal.formBuilder.updatingElement = false;
+};
+
+/**
+ * Upon changing a field, submit via AJAX to the server.
+ */
+Drupal.formBuilder.elementChange = function() {
+  if (!Drupal.formBuilder.updatingElement) {
+    // Store the form and the options
+    var form = $(this).parents('form:first');
+    Drupal.formBuilder.ajaxOptions = {
+      url: form.attr('action'),
+      success: Drupal.formBuilder.updateElement,
+      error: Drupal.formBuilder.ajaxError,
+      type: 'post',
+      dataType: 'json',
+      errorMessage: Drupal.t('Field could not be updated at this time. Please try again later.'),
+      data: form.serialize(),
+      tryCount: 0,
+      maxTry: 3
+    };
+    // Submit the form via ajax
+    $.ajax(Drupal.formBuilder.ajaxOptions);
+
+    // Bind this action to disable any submit buttons on the page.  It will be
+    // removed on success or after the retries have been exhausted.
+    $('form').submit(Drupal.formBuilder.preventSubmit);
+  }
+
+  // Clear any pending updates until further changes are made.
+  if (Drupal.formBuilder.updateDelay) {
+    clearTimeout(Drupal.formBuilder.updateDelay);
+  }
+
+  Drupal.formBuilder.updatingElement = true;
+};
+
+Drupal.formBuilder.ajaxError = function (XMLHttpRequest, textStatus, errorThrown) {
+  var options = Drupal.formBuilder.ajaxOptions;
+  var message = this.errorMessage ? this.errorMessage : 'Unable to reach server.  Please try again later.';
+
+  options.tryCount++;
+  if (options.tryCount <= options.maxTry) {
+    $.ajax(options);
+  } else {
+    $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
+    alert(message);
+  }
+};
+
+Drupal.formBuilder.preventSubmit = function (event) {
+  event.preventDefault();
+}
+
+/**
+ * Update a field after a delay.
+ *
+ * Similar to immediately changing a field, this field as pending changes that
+ * will be updated after a delay. This includes textareas and textfields in
+ * which updating continuously would be a strain the server and actually slow
+ * down responsiveness.
+ */
+Drupal.formBuilder.elementPendingChange = function(e) {
+  // Only operate on "normal" keys, excluding special function keys.
+  // http://protocolsofmatrix.blogspot.com/2007/09/javascript-keycode-reference-table-for.html
+  if (e.type == 'keyup' && !(
+    e.keyCode >= 48 && e.keyCode <= 90 || // 0-9, A-Z.
+    e.keyCode >= 93 && e.keyCode <= 111 || // Number pad.
+    e.keyCode >= 186 && e.keyCode <= 222 || // Symbols.
+    e.keyCode == 8) // Backspace.
+    ) {
+    return;
+  }
+
+  if (Drupal.formBuilder.updateDelay) {
+    clearTimeout(Drupal.formBuilder.updateDelay);
+  }
+  Drupal.formBuilder.updateDelayElement = this;
+  Drupal.formBuilder.updateDelay = setTimeout("Drupal.formBuilder.elementChange.apply(Drupal.formBuilder.updateDelayElement, [true])", 500);
+};
+
+/**
+ * After submitting the change to the server, display the updated element.
+ */
+Drupal.formBuilder.updateElement = function(response) {
+  var $configureForm = $('.form-builder-field-configure');
+
+  // Do not let older requests replace newer updates.
+  if (response.time < Drupal.formBuilder.lastUpdateTime) {
+    return;
+  }
+  else {
+    Drupal.formBuilder.lastUpdateTime = response.time;
+  }
+
+  // Update Drupal.settings.
+  if (response.settings) {
+    $.extend(true, Drupal.settings, response.settings);
+  }
+
+  // Set the error class on fields.
+  $configureForm.find('.error').removeClass('error');
+  if (response.errors) {
+    for (var elementName in response.errors) {
+      elementName = elementName.replace(/([a-z0-9_]+)\](.*)/, '$1$2]');
+      $configureForm.find('[name=' + elementName + ']').addClass('error');
+    }
+  }
+
+  // Display messages, if any.
+  $configureForm.find('.messages').remove();
+  if (response.messages) {
+    $configureForm.find('fieldset:visible:first').prepend(response.messages);
+  }
+
+  // Do not update the element if errors were received.
+  if (!response.errors) {
+    var $exisiting = $('#form-builder-element-' + response.elementId);
+    var $new = $(response.html).find('.form-builder-element:first');
+    $exisiting.replaceWith($new);
+
+    // Expand root level fieldsets after updating to prevent them from closing
+    // after every update.
+    $new.children('fieldset.collapsible').removeClass('collapsed');
+    Drupal.attachBehaviors($new.parent().get(0));
+  }
+
+  // Set the variable stating we're done updating.
+  Drupal.formBuilder.updatingElement = false;
+  $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
+};
+
+/**
+ * When adding a new field, remove the placeholder and insert the new element.
+ */
+Drupal.formBuilder.addElement = function(response) {
+  // This is very similar to the update element callback, only we replace the
+  // entire wrapper instead of just the element.
+  if (response.settings) {
+    $.extend(true, Drupal.settings, response.settings);
+  }
+  var $exisiting = $('.form-builder-new-field');
+  var $new = $(response.html);
+  $exisiting.replaceWith($new);
+  Drupal.attachBehaviors($new.get(0));
+
+  $new.draggable('destroy');
+  $new.draggable({
+    opacity: 0.8,
+    helper: 'clone',
+    scroll: true,
+    scrollSensitivity: 50,
+    containment: 'body',
+    start: Drupal.formBuilder.startDrag,
+    stop: Drupal.formBuilder.stopDrag,
+    change: Drupal.formBuilder.checkFieldsets,
+    distance: 4,
+    scope: 'fields',
+    addClasses: false,
+    appendTo: '#form-builder-wrapper'
+  });
+
+  // Set the variable stating we're done updating.
+  Drupal.formBuilder.updatingElement = false;
+
+  // Insert the new position form containing the new element.
+  $('#form-builder-positions').replaceWith(response.positionForm);
+
+  // Submit the new positions form to save the new element position.
+  Drupal.formBuilder.updateElementPosition($new);
+};
+
+/**
+ * Given an element, update it's position (weight and parent) on the server.
+ */
+Drupal.formBuilder.updateElementPosition = function(element) {
+  // Update weights of all children within this element's parent.
+  element.parent().children('.form-builder-wrapper').each(function(index) {
+    var child_id = $(this).children('.form-builder-element:first').attr('id');
+    $('#form-builder-positions input.form-builder-weight').filter('.' + child_id).val(index);
+  });
+
+  // Update this element's parent.
+  var $parent = element.parents('.form-builder-element:first');
+  var parent_id = $parent.length ? $parent.attr('id').replace(/form-builder-element-(.*)/, '$1') : 0;
+  var child_id = element.children('.form-builder-element:first').attr('id');
+  $('#form-builder-positions input.form-builder-parent').filter('.' + child_id).val(parent_id);
+
+  // Submit the position form via AJAX to save the new weights and parents.
+  $('#form-builder-positions').ajaxSubmit();
+};
+
+/**
+ * Called when a field has been moved via Sortables.
+ *
+ * @param e
+ *   The event object containing status information about the event.
+ * @param ui
+ *   The jQuery Sortables object containing information about the sortable.
+ */
+Drupal.formBuilder.drop = function(e, ui) {
+  var element = ui.draggable;
+  var placeholder = e.data ? $(e.data) : $(this);
+  
+  // If no drop target is hit, add the component to the end of the form.
+  if (placeholder.is('#form-builder')) {
+    placeholder = placeholder.children(':last');
+  } else if (placeholder.is('.form-builder-wrapper:not(.form-builder-empty-placeholder)')) {
+    placeholder = placeholder.next('.form-builder-placeholder');
+  }
+
+  // If the element is a new field from the palette, update it with a real field.
+  if (element.is('.ui-draggable')) {
+    var name = 'new_' + new Date().getTime();
+    // If this is a "unique" element, its element ID is hard-coded.
+    if (element.is('.form-builder-unique')) {
+      name = element.className.replace(/^.*?form-builder-element-([a-z0-9_]+).*?$/, '$1');
+    }
+
+    var $ajaxPlaceholder = $('<div class="form-builder-wrapper form-builder-new-field"><div id="form-builder-element-' + name + '" class="form-builder-element"><span class="progress">' + Drupal.t('Please wait...') + '</span></div></div>');
+    placeholder.replaceWith($ajaxPlaceholder);
+
+    Drupal.formBuilder.ajaxOptions = {
+      url: element.find('a').attr('href'),
+      type: 'GET',
+      dataType: 'json',
+      data: 'js=1&element_id=' + name,
+      success: Drupal.formBuilder.addElement,
+      error: Drupal.formBuilder.ajaxError,
+      errorMessage: Drupal.t('Element could not be added at this time. Please try again later.'),
+      tryCount: 0,
+      maxTry: 3
+    };
+    $.ajax(Drupal.formBuilder.ajaxOptions);
+
+    Drupal.formBuilder.updatingElement = true;
+  }
+  // Update the positions (weights and parents) in the form cache.
+  else {
+    placeholder.replaceWith(element);
+    element.removeClass('original').show();
+    ui.helper.remove();
+    Drupal.formBuilder.updateElementPosition(element);
+
+    // Select the element
+    element.find('a.configure').click();
+  }
+
+  Drupal.formBuilder.activeDragUi = false;
+  $('#form-builder .form-builder-placeholder').remove();
+  
+  // Update empty fieldsets
+  Drupal.formBuilder.checkFieldsets();
+
+  // Scroll the palette into view.
+  $(window).scroll();
+};
+
+/**
+ * Called when a field is about to be moved from the new field palette.
+ *
+ * @param e
+ *   The event object containing status information about the event.
+ * @param ui
+ *   The jQuery Sortables object containing information about the sortable.
+ */
+Drupal.formBuilder.startDrag = function(e, ui) {
+  var $this = $(this);
+  // Check to see if this has been pulled out of a fieldset.
+  Drupal.formBuilder.checkFieldsets();
+
+  ui.helper.width($(this).width());
+
+  if ($this.is('.form-builder-unique')) {
+    $this.css('visibility', 'hidden');
+  }
+  if ($this.is('.form-builder-wrapper')) {
+    $this.hide();
+  }
+  $this.addClass('original');
+
+  var isPagebreak = false;
+  if ($this.children('.form-builder-element-pagebreak').length > 0) {
+    isPagebreak = true;
+  }
+  if ($this.is('.field-pagebreak')) {
+    isPagebreak = true;
+  }
+
+  // Grab the formbuilder and fields and store the placeholder markup.
+  var formbuilder = $('#form-builder');
+  var fields = $('#form-builder').find('.form-builder-wrapper')
+    .not(this)
+    .not('.form-builder-empty-placeholder')
+    .not($('.original *'));
+  var placeholder = '<div class="form-builder-placeholder"></div>';
+
+  // Add a drop target at the bottom of the form.
+  $(placeholder).appendTo(formbuilder);
+
+  if (fields.length) {
+    // Insert a drop target after each field.
+    $(placeholder).insertBefore(fields);
+    // If we're not dragging a page break, add a drop target at the bottom of each fieldset.
+    if (!isPagebreak) {
+      $(placeholder).appendTo('.fieldset-wrapper:not(:has(.form-builder-empty-placeholder))');
+    }
+  } else {
+    // The form is empty, so make the placeholder at least the size of the form.
+    formbuilder.find('.form-builder-placeholder').css('min-height', formbuilder.css('height'));
+  }
+
+  var height = formbuilder.height();
+  formbuilder.children(':visible:not(.form-builder-placeholder)').each(function() {
+    height = height - $(this).outerHeight(true);
+  });
+  if (height > 0) {
+    $('.form-builder-placeholder:last').css('min-height', height);
+  }
+
+  // Activate all the placeholders as drop targets.
+  var placeholders = $('.form-builder-placeholder, .form-builder-empty-placeholder');
+  if (isPagebreak) {
+    placeholders = placeholders.not('.fieldset-wrapper .form-builder-placeholder').not('.fieldset-wrapper .form-builder-empty-placeholder');
+  }
+  
+  placeholders.droppable({
+    scope: 'fields',
+    tolerance: 'touch',
+    over: Drupal.formBuilder.over,
+    out: Drupal.formBuilder.out,
+    drop: Drupal.formBuilder.drop
+  });
+
+  // Add droppable to form elements without the over / out methods
+  $('.form-builder-wrapper').droppable({
+    scope: 'fields',
+    tolerance: 'touch',
+    drop: Drupal.formBuilder.drop
+  });
+
+  // Retain the dimensions of the draggable
+  ui.helper.width($this.width());
+  ui.helper.height($this.height());
+
+  Drupal.formBuilder.activeDragUi = ui;
+};
+
+/**
+ * Called after a field has been moved from the new field palette.
+ *
+ * @param e
+ *   The event object containing status information about the event.
+ * @param ui
+ *   The jQuery Sortables object containing information about the sortable.
+ */
+Drupal.formBuilder.stopDrag = function(e, ui) {
+  var $this = $(this);
+  // Remove the droppable from all elements within the form
+  $('#form-builder .ui-droppable').droppable('destroy');
+
+  // If the activeDragUi is still set, we did not drop onto the form.
+  if (Drupal.formBuilder.activeDragUi) {
+    ui.helper.remove();
+    Drupal.formBuilder.activeDragUi = false;
+    $this.css('visibility', '').show().removeClass('original');
+    $(window).scroll();
+    // Remove the placeholders
+    $('#form-builder .form-builder-placeholder').remove();
+    
+    Drupal.formBuilder.checkFieldsets();
+  }
+  // If dropped onto the form and a unique field, remove it from the palette.
+  else if ($this.is('.form-builder-unique')) {
+    $this.animate({height: '0', width: '0'}, function() {
+      $this.css({visibility: '', height: '', width: '', display: 'none'});
+    });
+  }
+};
+
+/**
+ * These functions add and remove a class to a drop target and adjust its height
+ * to the height of the item being dragged.
+ */
+Drupal.formBuilder.over = function(e, ui) {
+  var $this = $(this);
+  if (!$this.is('.form-builder-empty-placeholder')) {
+    $this.height(ui.draggable.height());
+  }
+  $this.parent().find('.over').height(0);
+  $this.addClass('over');
+}
+
+Drupal.formBuilder.out = function(e, ui) {
+  var $this = $(this);
+  if (!$this.is('.form-builder-empty-placeholder')) {
+    $this.height(0);
+  }
+  $this.removeClass('over');
+};
+
+/**
+ * Insert DIVs into empty fieldsets so that items can be dropped within them.
+ *
+ * This function is called every time an element changes positions during
+ * a Sortables drag and drop operation.
+ *
+ * @param e
+ *   The event object containing status information about the event.
+ * @param ui
+ *   The jQuery Sortables object containing information about the sortable.
+ * @param
+ */
+Drupal.formBuilder.checkFieldsets = function(e, ui, expand) {
+  var $fieldsets = $('#form-builder div.form-builder-element fieldset.form-builder-fieldset div.fieldset-wrapper');
+
+  // Find all empty fieldsets.
+  $fieldsets.each(function() {
+    // Remove placeholders.
+    $(this).children('.form-builder-empty-placeholder').remove();
+    // If there are no visible children after placeholders are removed, add a placeholder.
+    if ($(this).children(':not(.description):visible').length == 0) {
+      $(Drupal.settings.formBuilder.emptyFieldset).appendTo(this);
+      }
+  });
+};
+
+Drupal.formBuilder.setActive = function(element, link) {
+  Drupal.formBuilder.unsetActive();
+  Drupal.formBuilder.activeElement = element;
+  Drupal.formBuilder.activeLink = link;
+  $(Drupal.formBuilder.activeElement).addClass('form-builder-active');
+};
+
+Drupal.formBuilder.unsetActive = function() {
+  if (Drupal.formBuilder.activeElement) {
+    $(Drupal.formBuilder.activeElement).removeClass('form-builder-active');
+    Drupal.formBuilder.activeElement = false;
+    Drupal.formBuilder.activeLink = false;
+  }
+};
+
+Drupal.formBuilder.closeActive = function(callback) {
+  if (Drupal.formBuilder.activeElement) {
+    var $activeForm = Drupal.formBuilder.fieldConfigureForm ? Drupal.formBuilder.fieldConfigureForm.find('form') : $(Drupal.formBuilder.activeElement).find('form');
+
+    if ($activeForm.length) {
+      Drupal.freezeHeight();
+      $activeForm.slideUp(function(){
+        $(this).remove();
+        if (callback && $.isFunction(callback)) {
+          callback.call();
+        }
+      });
+    }
+  }
+  else if (callback) {
+    callback.call();
+  }
+
+  return false;
+};
+
+/**
+ * Work around for tabledrags within tabs. On load, if the tab was hidden the
+ * offsets cannot be calculated correctly. Recalculate and update the tableDrag.
+ */
+Drupal.formBuilder.fixTableDragTabs = function(context) {
+  if (Drupal.tableDrag && Drupal.tableDrag.length > 1) {
+    for (var n in Drupal.tableDrag) {
+      if (typeof(Drupal.tableDrag[n]) == 'object') {
+        var table = $('#' + n, context).get(0);
+        if (table) {
+          var indent = Drupal.theme('tableDragIndentation');
+          var testCell = $('tr.draggable:first td:first', table).prepend(indent).prepend(indent);
+          Drupal.tableDrag[n].indentAmount = $('.indentation', testCell).get(1).offsetLeft - $('.indentation', testCell).get(0).offsetLeft;
+          $('.indentation', testCell).slice(0, 2).remove();
+        }
+      }
+    }
+  }
+};
+
+})(jQuery);
\ No newline at end of file
diff --git a/sites/all/modules/form_builder/form_builder.module b/sites/all/modules/form_builder/form_builder.module
new file mode 100644
index 00000000..84b8fec9
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder.module
@@ -0,0 +1,359 @@
+<?php
+
+/**
+ * @file form_builder.module
+ * Generic form building framework and user interface.
+ */
+
+define('FORM_BUILDER_ROOT', 0);
+
+/**
+ * Implementation of hook_menu().
+ */
+function form_builder_menu() {
+  $items = array();
+
+  $items['admin/build/form-builder/add'] = array(
+    'title' => 'Add field',
+    'description' => 'Add a field to a form.',
+    'page callback' => 'form_builder_add_page',
+    'access callback' => 'form_builder_menu_field_access',
+    'access arguments' => array('add', 4, 5, 6),
+    'type' => MENU_CALLBACK,
+    'file' => 'form_builder.admin.inc',
+    'file path' => drupal_get_path('module', 'form_builder') . '/includes',
+  );
+
+  $items['admin/build/form-builder/configure'] = array(
+    'title' => 'Configure field',
+    'description' => 'Configure a field within a form.',
+    'page callback' => 'form_builder_configure_page',
+    'access callback' => 'form_builder_menu_field_access',
+    'access arguments' => array('configure', 4, 5, 6),
+    'type' => MENU_CALLBACK,
+    'file' => 'form_builder.admin.inc',
+    'file path' => drupal_get_path('module', 'form_builder') . '/includes',
+  );
+
+  $items['admin/build/form-builder/remove'] = array(
+    'title' => 'Remove field',
+    'description' => 'Remove a field from a form.',
+    'page callback' => 'form_builder_remove_page',
+    'access callback' => 'form_builder_menu_field_access',
+    'access arguments' => array('remove', 4, 5, 6),
+    'type' => MENU_CALLBACK,
+    'file' => 'form_builder.admin.inc',
+    'file path' => drupal_get_path('module', 'form_builder') . '/includes',
+  );
+
+  $items['admin/build/form-builder/json'] = array(
+    'title' => 'JSON representation',
+    'description' => 'Display a form field as a JSON string.',
+    'page callback' => 'form_builder_field_json',
+    'access callback' => 'form_builder_menu_field_access',
+    'access arguments' => array('view', 4, 5, 6),
+    'type' => MENU_CALLBACK,
+    'file' => 'form_builder.admin.inc',
+    'file path' => drupal_get_path('module', 'form_builder') . '/includes',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function form_builder_theme() {
+  return array(
+    'form_builder_element_wrapper' => array(
+      'render element' => 'element',
+      'file' => 'includes/form_builder.admin.inc',
+    ),
+    'form_builder_wrapper' => array(
+      'render element' => 'element',
+      'file' => 'includes/form_builder.admin.inc',
+    ),
+    'form_builder_empty_fieldset' => array(
+      'variables' => array(),
+      'file' => 'includes/form_builder.admin.inc',
+    ),
+    'form_builder_field_palette' => array(
+      'variables' => array('fields' => NULL, 'groups' => NULL, 'form_type' => NULL, 'form_id' => NULL),
+      'file' => 'includes/form_builder.admin.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_block_info().
+ */
+function form_builder_block_info() {
+  $blocks = array();
+  $blocks['fields'] = array(
+    'info' => t('Form builder fields'),
+    'weight' => 0,
+  );
+  return $blocks;
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function form_builder_block_view($delta = '') {
+  $block = array();
+  if ($delta == 'fields') {
+    module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
+    $block['content'] = form_builder_field_palette();
+  }
+  return $block;
+}
+
+/**
+ * Access callback for field configuration, viewing, addition, and deletion.
+ */
+function form_builder_menu_field_access($op, $form_type, $form_id, $element_id) {
+  if (empty($form_type) || empty($form_id) || empty($element_id)) {
+    // If called by menu API to check access, we should not try and check
+    // with fake data, which ends up in PHP errors.
+    return;
+  }
+
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+  $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
+  $access = FALSE;
+
+  if ($op == 'add' || $op == 'view') {
+    $access = TRUE;
+  }
+  if ($op == 'configure' && !empty($element['#form_builder']['configurable'])) {
+    $access = TRUE;
+  }
+  if ($op == 'remove' && !empty($element['#form_builder']['removable'])) {
+    $access = TRUE;
+  }
+
+  $module_accesses = module_invoke_all('form_builder_field_access', $op, $form_type, $form_id, $element);
+  if (!empty($module_accesses)) {
+    $access = array_pop($module_accesses);
+  }
+
+  return $access;
+
+}
+
+/**
+ * Implementation of hook_form_builder_properties().
+ */
+function form_builder_form_builder_properties($form_type) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.properties');
+
+  return array(
+    'key' => array(
+      'form' => 'form_builder_property_key_form',
+    ),
+    'title' => array(
+      'form' => 'form_builder_property_title_form',
+    ),
+    'title_display' => array(
+      'form' => 'form_builder_property_title_display_form',
+    ),
+    'description' => array(
+      'form' => 'form_builder_property_description_form',
+    ),
+    'weight' => array(
+      'form' => 'form_builder_property_weight_form',
+    ),
+    'default_value' => array(
+      'form' => 'form_builder_property_default_value_form',
+    ),
+    'markup' => array(
+      'form' => 'form_builder_property_markup_form',
+      'submit' => array('form_builder_property_markup_form_submit'),
+    ),
+    'required' => array(
+      'form' => 'form_builder_property_required_form',
+    ),
+    'options' => array(
+      'form' => 'form_builder_property_options_form',
+      'submit' => array('form_builder_property_options_form_submit'),
+    ),
+    'size' => array(
+      'form' => 'form_builder_property_size_form',
+    ),
+    'rows' => array(
+      'form' => 'form_builder_property_rows_form',
+    ),
+    'cols' => array(
+      'form' => 'form_builder_property_cols_form',
+    ),
+    'field_prefix' => array(
+      'form' => 'form_builder_property_field_prefix_form',
+    ),
+    'field_suffix' => array(
+      'form' => 'form_builder_property_field_suffix_form',
+    ),
+    'collapsible' => array(
+      'form' => 'form_builder_property_collapsible_form',
+    ),
+    'collapsed' => array(
+      'form' => 'form_builder_property_collapsed_form',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_property_groups().
+ */
+function form_builder_form_builder_property_groups($form_type) {
+  return array(
+    'default' => array(
+      'weight' => 0,
+      'title' => t('Properties'),
+    ),
+    'hidden' => array(
+      'weight' => 100,
+      'title' => t('Advanced'),
+      'collapsed' => TRUE,
+      'collapsible' => TRUE,
+    ),
+    'display' => array(
+      'weight' => 1,
+      'title' => t('Display'),
+    ),
+    'options' => array(
+      'weight' => 2,
+      'title' => t('Options'),
+    ),
+    'validation' => array(
+      'weight' => 3,
+      'title' => t('Validation'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_palette_groups().
+ */
+function form_builder_form_builder_palette_groups() {
+  return array(
+    'default' => array(
+      'weight' => 0,
+      'title' => t('Standard'),
+    ),
+    'special' => array(
+      'weight' => 5,
+      'title' => t('Special'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_validators().
+ */
+function form_builder_form_builder_validators($form_type) {
+  return array(
+    'form_validate_integer' => array(
+      'form' => 'form_builder_validate_integer',
+    ),
+    'form_validate_decimal' => array(
+      'form' => 'form_builder_validate_decimal',
+    ),
+    'form_validate_email' => array(
+      'form' => 'form_builder_validate_email',
+    ),
+    'form_validate_url' => array(
+      'form' => 'form_builder_validate_url',
+    ),
+  );
+}
+
+/**
+ * Static storage of the current type of form being edited (if any).
+ *
+ * @param $new_type_name
+ *   The name of the type being edited. If this value is passed in, the static
+ *   variable is set. If this parameter is ommited, the current type is
+ *   returned. Pass in FALSE to reset current type.
+ */
+function form_builder_active_form($new_type = NULL, $new_id = NULL) {
+  static $active_form = FALSE;
+
+  if (isset($new_type) && isset($new_id)) {
+    if (!$new_type && !$new_id) {
+      $active_form = FALSE;
+    }
+    else {
+      $active_form['form_type'] = $new_type;
+      $active_form['form_id'] = $new_id;
+    }
+  }
+
+  return $active_form;
+}
+
+/**
+ * Generic validation function to check that an element has a integer value.
+ */
+function form_validate_integer(&$element, &$form_state) {
+  $value = $element['#value'];
+
+  // Remove commas from numbers.
+  $new_value = str_replace(array(' ', ','), '', $element);
+  if (is_int($new_value) && $new_value != $value) {
+    form_set_value($element, $new_value, $form_state);
+    drupal_set_message(t('Commas and spaces were removed from the %title field.', array('%title' => $element['#title'])));
+  }
+  elseif (!is_int($new_value)) {
+    form_error($element, t('The %title field value must be an integer.', array('%title' => $element['#title'])));
+  }
+}
+
+/**
+ * Generic validation function to check that an element has a decimal value.
+ */
+function form_validate_decimal(&$element, &$form_state) {
+  $value = $element['#value'];
+
+  // Remove commas from numbers.
+  $new_value = str_replace(array(' ', ','), '', $element);
+  if (is_int($new_value) && $new_value != $value) {
+    form_set_value($element, $new_value, $form_state);
+    drupal_set_message(t('Commas and spaces were removed from the %title field.', array('%title' => $element['#title'])));
+  }
+  elseif (!is_int($new_value)) {
+    form_error($element, t('The %title field value must be a decimal.', array('%title' => $element['#title'])));
+  }
+}
+
+/**
+ * Generic validation function to check for a valid e-mail value.
+ */
+function form_validate_email(&$element, &$form_state) {
+  if (valid_email_address($element['#value'])) {
+    form_error($element, t('The %title field value must be a valid e-mail address.', array('%title' => $element['#title'])));
+  }
+}
+
+/**
+ * Generic validation function to check for a valid url value.
+ */
+function form_validate_url(&$element, &$form_state) {
+  if (valid_url($element['#value'], isset($element['#absolute_url']) ? $element['#absolute_url'] : TRUE)) {
+    form_error($element, t('The %title field value must be a valid URL.', array('%title' => $element['#title'])));
+  }
+}
+
+/**
+ * Implementation of hook_registry_files_alter().
+ *
+ * Reassign formbuilder include files to their respective modules.
+ * Required to make module_invoke() type of calls working.
+ */
+function form_builder_registry_files_alter(&$files, $module_cache) {
+  $module_files = file_scan_directory(drupal_get_path('module', 'form_builder') . '/modules', '!^.*\.inc$!');
+  foreach ($module_files as $path => $file) {
+    $files[$file->uri]['module'] = $file->name;
+    $files[$file->uri]['weight'] = 0;
+  }
+}
diff --git a/sites/all/modules/form_builder/form_builder_hooks.php b/sites/all/modules/form_builder/form_builder_hooks.php
new file mode 100644
index 00000000..38a996e6
--- /dev/null
+++ b/sites/all/modules/form_builder/form_builder_hooks.php
@@ -0,0 +1,260 @@
+<?php
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * @file
+ * These are the hooks that are invoked by Form Builder.
+ */
+
+/**
+ * Define the fields and properties supported by a form type.
+ *
+ * All modules that wish to create an configurable form need implement this hook. It
+ * defines to Form Builder what types of fields the implementing module knows
+ * how to modify. Within each field that is modifiable, the properties that
+ * may be changed are also listed.
+ *
+ * @return
+ *   An array of form types that this module may edit. Within each form type,
+ *   a list of fields that can be edited. Each field contains the following
+ *   properties:
+ *   - title: The name of the field type that is displayed in the new fields
+ *     block.
+ *   - properties: An array of properties that are configurable. Configuration
+ *     of these properties is defined by hook_form_builder_properties().
+ *   - default: A complete sample form element that will be used when a new
+ *     element of this type is added to the form. Further modification of this
+ *     default element may be done in hook_form_builder_element_alter().
+ */
+function hook_form_builder_types() {
+  $fields = array();
+
+  // The #type property of the field is used as the key.
+  $fields['textfield'] = array(
+    'title' => t('Textfield'),
+    // Properties that may be edited on this field type.
+    'properties' => array(
+      'title',
+      'description',
+      'field_prefix',
+      'field_suffix',
+      'default_value',
+      'required',
+      'size',
+    ),
+    // A complete default form element used when a new field of this type
+    // is added to a form.
+    'default' => array(
+      '#title' => t('New textfield'),
+      '#type' => 'textfield',
+    ),
+    // If needing only a single field of this type in an entire form, specify
+    // the "unique" property. The form element will be remove from the new
+    // field pallette when added. If the field is deleted from the form, the
+    // field option will reappear in the new field block.
+    // 'unique' => TRUE,
+  );
+
+  // Return the array of supported fields, with a key for the form type that
+  // these fields apply to.
+  return array(
+    'node' => $fields,
+  );
+}
+
+/**
+ * Defined globally available Form API properties.
+ *
+ * The hook_form_builder_properties() hook allows modules to define properties
+ * that are configurable within form elements. Properties defined by any module may be
+ * used inside of any form element, so unique property names are advised.
+ *
+ * Typically, this hook only needs to implemented if your module also has an
+ * implementation of hook_elements(). In which case you would implement
+ * hook_form_builder_properties to inform Form Builder of the new properties
+ * that are configurable.
+ *
+ * @param $form_type
+ *   The type of form for which these properties apply. You may choose to ignore
+ *   the value of this parameter if your properties apply globally to all forms.
+ *
+ * @return
+ *   An array of properties, each containing the name of a function for a form
+ *   to editing that property. If needed additional submit and validate
+ *   handlers may also be added.
+ *
+ * @ingroup form_builder
+ */
+function hook_form_builder_properties($form_type) {
+  return array(
+    'title' => array(
+      'form' => 'form_builder_property_title_form',
+    ),
+    'description' => array(
+      'form' => 'form_builder_property_description_form',
+    ),
+    'options' => array(
+      'form' => 'form_builder_property_options_form',
+      'submit' => array('form_builder_property_options_form_submit'),
+    ),
+  );
+}
+
+/**
+ * Define globally available #element_validate functions.
+ *
+ * @param $form_type
+ *   The form type for which this validator will be available. You may
+ *   optionally check this value if you'd like to limit this validator to only
+ *   certain form types.
+ */
+function hook_form_builder_validators($form_type) {
+  return array(
+    'form_validate_integer' => array(
+      'form' => 'form_builder_validate_integer',
+    ),
+    'form_validate_decimal' => array(
+      'form' => 'form_builder_validate_decimal',
+    ),
+    'form_validate_email' => array(
+      'form' => 'form_builder_validate_email',
+    ),
+    'form_validate_url' => array(
+      'form' => 'form_builder_validate_url',
+    ),
+  );
+}
+
+/**
+ * Designate groups of properties. Displayed as tabs when editing a field.
+ *
+ * Most properties will fall into one of the predefined categories created by
+ * Form Builder, but it may be desired that some properties be split into
+ * entirely different groups to separate them from other property options.
+ *
+ * Form Builder provides the following groups by default:
+ *  - default: The "Properties" tab, used if no group is specified.
+ *  - hidden: Not displayed at all unless JavaScript is disabled.
+ *  - display: The "Display" tab. Use for properties that are purely cosmetic.
+ *  - options: The "Options" tab. Typically used for select list, radio,
+ *    or checkbox options.
+ *  - validation: The "Validation" tab. Use for properties or configuration
+ *    that enables validation functions on the element.
+ *
+ * @param $form_type
+ *   The form type for which this group will be available. You may optionally
+ *   check this value if you'd like to limit this group to only certain form
+ *   types.
+ *
+ * @return
+ *   An array of property groups, keyed by the value used in the
+ *   #form_builder['property_group'] property.
+ *
+ * @see hook_form_builder_load()
+ *
+ * @ingroup form_builder
+ */
+function hook_form_builder_property_groups($form_type) {
+  return array(
+    'my_group' => array(
+      // Low weight values will appear as first tabs.
+      'weight' => 0,
+      // The title will be used as the tab title.
+      'title' => t('My group'),
+    ),
+    'my_hidden_group' => array(
+      'weight' => 100,
+      'title' => t('Advanced'),
+       // When JavaScript is enabled, collapsed groups will not be rendered.
+       // This group will only be displayed when JavaScript is disabled.
+      'collapsible' => TRUE,
+      'collapsed' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Modify an individual element before it is displayed in the form preview.
+ *
+ * This function is typically used to cleanup a form element just before it
+ * is rendered. The most important purpose of this function is to filter out
+ * dangerous markup from unfiltered properties, such as #description.
+ * Properties like #title and #options are filtered by the Form API.
+ */
+function hook_form_builder_preview_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    if (isset($element['#description'])) {
+      $element['#description'] = filter_xss($element['#description']);
+    }
+  }
+}
+
+/**
+ * Modify an individual element before it is added to a new form.
+ *
+ * This function may be helpful for setting a new element #key,
+ * #form_builder['element_id'], or adjusting access in the
+ * #form_builder['configurable'] and #form_builder['removable'] properties.
+ */
+function hook_form_builder_add_element_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $element['#key'] = 'something';
+  }
+}
+
+/**
+ * Take a Form API array and save settings for changed elements.
+ *
+ * @param $form_type
+ *   The type of form being loaded.
+ * @param $form_id
+ *   The unique identifier for the form being edited.
+ */
+function hook_form_builder_load($form_type, $form_id) {
+  if ($form_type == 'node') {
+    $node = (object) array(
+      'type' => preg_replace('/_node_form/', '', $form_id),
+    );
+
+    // Load the form, usually by calling it's function directly.
+    $form = node_form(array(), $node);
+
+    // Allow other modules to extend the form.
+    drupal_alter('form', $form, array(), $form_id);
+
+    // Loop through the form and add #form_builder properties to each element
+    // that is configurable.
+    foreach (element_children($form) as $key) {
+      $form[$key]['#form_builder'] = array(
+        'configurable' => TRUE,
+        'removable' => TRUE,
+        // If unique, when this element is deleted, a new one will appear in the
+        // new field pallette.
+        //'unique' => TRUE,
+      );
+    }
+
+    return $form;
+  }
+}
+
+/**
+ * Take a form builder array and save changes permanently.
+ */
+function hook_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    foreach (element_children($form) as $key) {
+      if (isset($form[$key]['#form_builder']['element_id'])) {
+        // Save settings for this element.
+      }
+    }
+  }
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/sites/all/modules/form_builder/images/blank.gif b/sites/all/modules/form_builder/images/blank.gif
new file mode 100644
index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66
GIT binary patch
literal 43
ucmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7DfgJ1_m7v0g_>0Vsc?*um%9gss{N0

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/configure.png b/sites/all/modules/form_builder/images/configure.png
new file mode 100644
index 0000000000000000000000000000000000000000..ebeb2098900ed84d441d807f5522935457895464
GIT binary patch
literal 625
zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9V9?-TV_;xVtY2`1fq_A?#5JNMI6tkVJh3R1
z!7(L2DOJHUH!(dmC^a#qvhZZ84Fdy{u&0Y-NX4x;Q+H=8Im#Tbf5*9NpOk3#)E9@6
z1br43Bs`2SSem=)fT>xN>!lk}t9z$Dy19z+w1dEth}G5t@)8$*I6Q6o!Q>in<oMq*
z#RBOYo!?jR)qhBSX#RQT&vR$al|QJkVbau|$`!34GEca(<$JC)YfFaN>@`6vpYXCV
zZ;#NCJN$6N_v>YmJFaGJ{P9pQO{0rx@kNjIVXNB%G)jKna@S;Eq!YI=z~J>)skXz4
zJZ#K2a?HMOjCkW&_H28?`s>Y6YuP^kwCR1&yXKAC;)CzL|DNp7`6g-OiB%z5ajUNy
zwI62u_18{t%7Lp{U;Wl!-=AS3#m3%HwbzeD)nMJ{%SAh{^t&y7zvHlc`sPTf)AK#u
zH4k0P_;M=6DE2{K*Vc~}HQmRBdtH=%mnZVvEwS2r?EUowgCER(JgpyQ|IG~eAYRz^
zU*1Ble{<db|2NY%SJrc%OEJ>%y}al6<A)bK<vz}v|15E5j9-b!>Z_+L=K6j3Sz|Iy
zzM#QdNv9!$W6#Z;G#xSSC!Z@drg}MDw&nYwlHG7KCv1-3dW~jHkM<NJ&dDcLdP^($
zy_W{PDck+@V%mLH)dB^9gxz=b)`zW@Y++?}2~d*0Ub6l6+c>Mae2)t(80L#B{dg6d
zv@2$v-LshGmuolQe%s_+bMTKt)$t=U@8*3MJzglD(XdFW<XrT@TN@5%%3aIb?#iz{
l{d79N_2K_~|1=LUY;lcvuEcs{6$1kUgQu&X%Q~loCIEm|BD??q

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/delete.png b/sites/all/modules/form_builder/images/delete.png
new file mode 100644
index 0000000000000000000000000000000000000000..c4ad65da5982f7efeee7d06c0f6f17002e3bbbbc
GIT binary patch
literal 349
zcmeAS@N?(olHy`uVBq!ia0y~yVBlw9V9?-TW?*0tTNv<-fq_A?#5JNMI6tkVJh3R1
z!7(L2DOJHUH!(dmC^a#qvhZZ84Fdy%Q-Dv1tAvEa$B!TT`ueJ?s~H#=zI^#|_3G6d
zH*WOw^c+5X`03N9OiWCZCQahu;i;>uJ9g~YmMvRqYiqY}-_FU&xoOj;|NsA|<$p^7
z*<2Fj7yKU^U|_s-;0Xf*L%*ksV@SoVGZS9(9ai9QV_aRa@>bdBzwxDOTFs)Ty~+1g
zv6L?|IrJmuL$j@yWB!};LyacYsVeR>V_dBD9fNIZcJ7>}KmSX(dwRUVvlR#5O^@tZ
z{{Q#C{qOfmmrpx%cSrbxg8`F^8aT~v9z5qAAi{q?XxXM1yL-QLbU6GkI9P<v<o#gq
l-y=WNWBZ@^(;1i<rfkss?0mgKhk=2C!PC{xWt~$(69Br^p+5is

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/body.png b/sites/all/modules/form_builder/images/fields/body.png
new file mode 100644
index 0000000000000000000000000000000000000000..b8b4221aef821d1ff4bb1073c12b2e3d8de0527d
GIT binary patch
literal 973
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+Fc1UGwfg{qO&OCnu->V8F)4#?H>p!NI}F
z$;rjV#m&vl!^6YN%ge{d$Is6%ARr(pC@3T(BrGf}A|fIxDk>%>CN3^6At50tDJdl-
zB`qy2BO@a#D=Q}_CoeCrprD|rsHmi*q^zv0qN1Xzs;Z`@rmn88p`oFvsi~!<rLC>4
zqobp%tE;D{r?0PXU|?WqXlP_)WNd6~Vq#)yYHDU?W^Qh7VPRouX=!C;Wo>P3V`F1$
zYinm`XK!!s;Nals=;-9+<m~M1;^N}!>gwj^=I-w9;o;%w>FMR=<?Ze5<KyG&>+9#|
z=kM<y5D*X;7#I{36dW8J5)u*`8X6WB79JiR5fKp?85tE76&)QN6B82~8ygoF7at#=
zkdTm=n3$B5l$@NLl9G~|nwplDmY$xTk&%&^nVFT9m7SfPlarI1o12%Hm!F?sP*6}<
zSXfk4R9swKQc_Y{T3S|CR$g9SQBhG@Sy@$8Rb5?OQ&Ur0TU%FGS6^S>(9qD>*x1z6
z)ZE<M($dn}+S=CE*52OU(b3V_+1b_A)!p6Q)6>)2+uPUI*WceiVZwxo6DLlZG->kW
z$y26GnL2gqv}x0(PoF+x#*CRWXU>{6YxeBfbLPyMJ9qB9dGqGapTA(if`tngE?Tr`
z@#4ixmMmGibm_8X%a$)+zGB6Sl`B`STD5BR>eXx3tXaEu?YedA)~{c`VZ(-v8#iv+
zv}yC^&0Dr?*}8S>wr$(CZ{NOS$BvylckbG?YxnNmd-m+vyLa!tef#$B-+$o1frAGR
z9y)aB@ZrNpjvP69^ysl;$BrLAe&WQ5lP6D}I(6#w>C<P<oH={;?74I2&YwSj;lhQB
z7cXAAbm{Wt%U7;kxq9{LwQJX|U%!6i#*LddZ{E6f>-O#2ckbM|d-v|Wd-v|&zyILD
zgNF|vK6>=%@#Du&o;-Q_^y#x_&z?Vj{^G@pmoHzwdiCn{>(_7Iym|Zf?YnpH-oJnU
z;lqcIA3uKj^y%~G&tJZL`TF(iw{PFRfB*jD$B&;sfByRQ>-X>9fByXW`}gm^fB*jf
z|Id25A(?@JfvqISFBqKs88+`<vY&y0A<)ysF{I*FO}``G0R;}0#+LrC|I_zvP6})>
zE99A8*y!-9@n4g+-VLoBy(gXmOiF<fO`qQ$>HH#j)5t!VMK3z+ndpfF_ks#8<{OIN
f>bt0TfI)Yf@9|&v**X~*7#KWV{an^LB{Ts5ZVJ^N

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/checkboxes.png b/sites/all/modules/form_builder/images/fields/checkboxes.png
new file mode 100644
index 0000000000000000000000000000000000000000..522e1b7803cdcf4d1beda827a657caa8b10e7dc3
GIT binary patch
literal 974
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+G=a|GReWns@(cCnu+W|Dk}Lot=Y&gOih!
zi;Ih!o12G+hnJU^kB^U^pI<;gKu}OnNJvOnSXe|vL{wB%OiWB%TwFpzLQ+yvN=iyv
zT3SX%Mpjl<PEJl<US2^#K~YgrNl8grSy@FzMO9T*O-)T*U0p*%LsL^zOG`^zTU$p*
zM^{%@Pft%@U*EvMz|hdp$jHdp*x1Cx#MIQ(%*@Q(+}y&#!qU>x%F4>x+S<m(#@5!>
z&d$!>-rm8%!O_vt$;rvt+1bU##nsi-&CSi--QB~(!_(8#%gf8#+uO&-$Jf`_&(F`_
z-#;KAATTg6C@3g6I5;FEBs4TMEG#TMJUk*IA~G^EDk>^EIyxpMCN?%UE-o%UK0YBK
zAu%yADJdyAIXNXIB{elQEiElQJv}2MBQrBID=RBIJ3A*QCpR}YFE1}YKfj=$ps=v8
zsHmv8xVWUGq_niOtgNiOyu6~KqO!8Gs;a8Gy1J&Orna`WuCA`WzP_QMp|P>Csi~>C
zxw)mKrM0!St*x!Sy}hHOqqDQKtE;QKySt~Sr?<DaudlDazkkAn2@@wyoHS|D<jIq#
zOqnuu>eOk|rcIwdea4I#GiT16HEY)F*|X=&nKO6p+<Ein&7VJi!GZ+~7cN}1Xwl-u
zi<c}}vUKUvWy_W=U%q_BiWMtYu3WWh)#}x&*Q{BycJ11A>(;Gbzkb7p4I4LZ+_Y)a
z=FOY8Y}vAP>(*`Cwr$_OeaDU+J9qBfwQJYz-Mjbf*|T@=-hKP_?ccxuz<~n?4<0;p
z=+NQAhmRaNa`foYW5<piKYskgi4!MJo;-Ex)alcw&zw1P_Uzen=gyr!fBwRS3l}e5
zymaZ(<;$0^T)A@f>eXx4u3f)={l<+OH*em&b?esc+qduBxpVjK-Fx@$-M@eT!Gi}6
zA3l8a=+WcHkDokw^7QG`XV0EJfByW%ix)3nzI^rS)$7-<-@JMA_U+qu@7}$C|Ng^=
z4<A2%{PgM5=g*(NeEIVA>(_7JzJ34x{l||VKY#xG_3PK~-@pI-`SbVh-+%u=>3#d=
zb(0tv7}!gK{DL8=pFzr-*^PmLA<)ysF{I*FPX9?>215>JU6I_xcmLm(ePeJsq4oK*
zf?kY$fxxvNEu6^;21|F?7Im$eeCNpQ(58v2Tl+SorQ|s)f7iYBP9x^a<*Da0i++6*
bOkhY*R4+?+3An_-z`)??>gTe~DWM4fB*fTl

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/date.png b/sites/all/modules/form_builder/images/fields/date.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cd974592939fbc2222e669f51353f3c6c6f2889
GIT binary patch
literal 178
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3_JloA+G=b|M%`ceeK${|Ns9hN|y03Ffg!`1o;L3
z|No!CL2Km~1_lNlPZ!6Kid#tuZp=I`90p3vJdA2<n0R=63|IscoEW55Ih3;ta~=31
d<Iup!!1;smhQO5*dJGH<44$rjF6*2Ung9VKG(G?T

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/email.png b/sites/all/modules/form_builder/images/fields/email.png
new file mode 100644
index 0000000000000000000000000000000000000000..4f4da0687c397efa0bf286e7c703ab696e1b287a
GIT binary patch
literal 966
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+G=b|G#$ans@(cCnu->|NpbHva+$Uv9q&t
zaBy&Pa&mETadUI?@bK{R^78TV@$>Tw2nYxY3JM7c2@4C0h=_=aii(MeiHnO%NJvOZ
zN=ivdNlQ!1$jHdb%F4;f$;-<tC@3f@Dk>={DJv_hsHmu_s;a4}sjI7NXlQ6^YHDd|
zX=`ii=;-L`>gws~>Feto7#J8D8X6fH85<j$n3$NFnwpuJnVXwiSXfwET3T6ISzBA%
z*x1<G+S=LK+1uMYI5;>uIyyNyIXgSMxVX5wy1Kc!xx2f2czAevdU|<zd3$^N`1ttx
z`uh3#`TP3^1Ox;I1_lKM1qTO*goK2KhK7ZOg@=bnL_|bJMn*+NMMp=+#KgqL#>U0P
z#mC1dBqSszCMG2%B_}7Rq@<*#rlzH(rKhK7WMpJ!W@cq&WoKvS<mBY$=H}()<>%)Y
z6ciK|78Vs16&Dwml$4Z~mX?*3m6w-SR8&+}R#sJ2RaaNn)YR10*4EY4)z{ZIG&D3e
zHa0aiH8(f6w6wIgwzjpkwYRr-baZrfc6N1jb$567^z`)h_V)Gl_4oHrm@r}D#EFw8
zO`1G;@{}o4rcRwYZQ8Wy)2GjvF=OV;nX_iinmv2=oH=vm&Ye4N-n{wq=Py{WVBx}r
zixw?fym;}FB}<krUAk=9vgON{uUN5S<;s<-R;^mSdi9z$Yu2t^yKddO_3PJf*sx*a
z#*LdcZQ8tf^Oh}Jwr<_JZQHi(+qdu7v18}Xox67J+P!=Co;`c^?%lg@-@g6(_a8WL
z;NZc7hYlS&eE9H@BS(%NJ$mfevE#>&pEz;i<jIq#PMtb^`t+GIXU?8Id+yx1^XJcB
zxNza(#fz6NUAlbv@|7!Bu3o)*?b@~L*RS8WapUIAo40P=x_$fhojZ5#-o1P8-o5+x
z?>~6(;NioEj~+dG{P^*cCr_R}efsR#v**vBzj*QD<;$0^UcGw#`t_SPZ{EIr`|jPl
z_wV0-`0(N5$B&;refs?Q^OrAQzJC4s?c2BS-@pI(@#E*upTB<n`u+R&pFe;8{{8#!
z-@pI=|F;{yRbXIXU@Zyq3;zHA|9^(x+xS2^$lKG!F{I*FPk%HQg8~POv(?P+|G!yn
zUE>-pXwvjR!OqK8L;jEm2lr8?MV!Gu99&NOFh1s3CUS66R;fTe|JAL(mof%!4}SlA
c7XvecfpY#!hvMWd3=9kmp00i_>zopr035Z**Z=?k

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/fieldset.png b/sites/all/modules/form_builder/images/fields/fieldset.png
new file mode 100644
index 0000000000000000000000000000000000000000..c03a61167c8f0251d8d825d2adc8ddd105f20695
GIT binary patch
literal 190
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+G=b|G#$ans@(cCnu->|NqO){9wz#z`$A(
z<QM$^|Ns9Czqj#$3^eg{aSW-rm6YJf%;Umgu+gBIkz1Iffkh%x;vj>Ip<xq?gg}A<
oYXCz4!z(|D10Q4@8W<T=B^fWi`T8S;fq{X+)78&qol`;+0Axx#1ONa4

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/file.png b/sites/all/modules/form_builder/images/fields/file.png
new file mode 100644
index 0000000000000000000000000000000000000000..0aa1ca4052d95019d4459f858b56631f10303f5a
GIT binary patch
literal 377
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3>5)BA+G=a|MTuYeeK${l$4a%9Sm{lkr{iWV|Fk^
zZDNSq!H}Ao(!MbxG|#2;L}Yeedg;7~(A5m#>ll)glao>tlXnX&-ajEdGc_?SE-5`e
zVJCCf$=Il^47vN%lTzcu*E1xg#iwVc&ED9XlA2t)EGV|pXTgpMS$XOI|Nm!NbaNia
zy(K|@!T*T^4Et8;NiZ-lBzw9zhE&{Ia^792L4n61P(kV2z3T7(%tPEZ=>6?J^JJ~i
zmVHh&2@_d%CKoaMV-Whwo?PK1H2bFPuAA$QePLRze<h}TWsB;Z5LZpz1<#k}9+|=R
qNPJUxcHLvo2aGHXGG>fy3>$ofync7@6J%guVDNPHb6Mw<&;$VIFQ}CO

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/grid.png b/sites/all/modules/form_builder/images/fields/grid.png
new file mode 100644
index 0000000000000000000000000000000000000000..9ed4979568bf6282b507db5dba338b37e2739abd
GIT binary patch
literal 194
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+G=b|G#$ans@(cCnu->|NqO){9wz#z`$A(
z<QM$^|Ns9Czqj#$47BicaSW-rb)?&oi$Q_s@UCtD>o?~$8GOxCn0}#&SGtFDyJSvq
t(9DH`>$|hKboR%}^h)xrGhmTmU{zw0Q0%slVqjok@O1TaS?83{1OTY&KpX%7

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/hidden.png b/sites/all/modules/form_builder/images/fields/hidden.png
new file mode 100644
index 0000000000000000000000000000000000000000..23cd13b4de5d1cd64a44dad0d0e568acc4af16de
GIT binary patch
literal 205
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3_JloA+G=b|G#$ans@){Wfy+*+eHd7Ffg!`1o;L3
z|No!CL2Km~1_lOqPZ!6Kid!}Pj9d%~9L(n5|JyHj*`{<WAcQaQg^);lE5q4|EDujb
zhN~*SV2M1awrXysaP|k)oa4XwzQ{5be-h$<TvyLwz%c72ql)jNo8K517#KWV{an^L
HB{Ts57Dh(v

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/image.png b/sites/all/modules/form_builder/images/fields/image.png
new file mode 100644
index 0000000000000000000000000000000000000000..8999542e3609181dfcd0376b7a6cf1c7bc8f6c06
GIT binary patch
literal 703
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@j1~btA+Fy2r~m)|pOTVt<;s<)O$>4Aky9?ciP^yr
zyMrNPk96}+pWd^t64T<A9NRSS$il_fUdQcV*nj`c%4<(LPeev-Wk}e`9J-pJ>tyWa
zJ8%2f1*K=Eef;=w-~D$fsmZ0wf|61bOXo#wzH)Wb<tr^a+`86Pbe(y9;NF{-ZO*M5
zTsK_0RJ|Z6dAC6G2G?0v-}Ib)Gvnf$+==nK?>+BYmN9!{@4U+|n@_$>&rEGP@glcB
zsC}bDYHCVWUV836^`x};l{emOxbbS!?bnO<PndH4RqN?j$;rtRFTUwqku>$f%jyMj
z;p-XNH)hPb{A$g){pFKwV=H~O-g>?J{)ffKH*C1`HajmpDK$Pc&t>tIS1Yf*T7Bzn
zTDy5tdVJ^E*ArH!_N|TBaN+WT9TO&9eBFQcRrorF#V0mR-8rFTg462jFaQ7l-`s!n
zA_D_MMoExg@PGOM2KhICy%`u7R(iTPhE&{2@^EM7dC8-}pmLytMS*G6old`BRTs}K
zdltZ0KG`6@F4k-tOZW<hS$peu#JWsqX%+}^a0}2qU@$@draG(Ef|V;oj<0^2xFCs9
zw7|HlbLto0t&@6NxFWJ%tk5o=X<6lJsI=2rEAEC{AG^|lGdgEwa&*pVYArax6`ZL1
z{`kp*ibAK3aDDGyYi4cDE$qQ9(y~FNvdeI(GRuq^F*9Z~FflN)G06Gr7G$2DxPyU#
Ofx*+&&t;ucLK6Th_J`X5

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/markup.png b/sites/all/modules/form_builder/images/fields/markup.png
new file mode 100644
index 0000000000000000000000000000000000000000..19a15fdf52cb6c4beccbdafdde05607d83dbf9c9
GIT binary patch
literal 952
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+G=b|95h7`v3nwGcz*_3kxeND;padJ3BiE
z2L~r7Cl?nNH#avA4-YRdFCQNtKR>^KfPkQ&ppcM|u&}U*h={1DsF;|TxVX54goLD|
zq?DADw6wI0jEt<Ttel*jyu7@Ef`X!=qLPx5va+&@ii)bLs+yXby1KfChK8o5rk0kL
zwzjs8j*hObuAZKrzP`SJfq|i+p^=f1v9Ym<iHWJHshOFXxw*N8g@vW1rInSHwY9a4
zjg76Xt(~2ny}iAIgM*`^qmz@9v$L~{i;JtPtDBpfySuxGhli)9r<a$Px3{;CkB_gf
zub-cvzrTM#KtNz%U{Fv{aBy%)NJwaCXjoWSczAe3L_}m{WK>jCbaZq~OiXNSY+PJi
ze0+RDLPBC<Vp394a&mG?N=j;KYFb)adU|?BMn-04W>!{Kc6N47PEKxaZeCtqetv#I
zK|x_*VNp?0adB};Nl9sGX<1oWd3kw7MMY(0WmQ#Gb#--3O-*fWZCzbmeSLjHLqlU@
zV^dR8b8~Y`OG|5OYg=1edwY9FM@MI8XIEEOcXxMBPfu@eZ(m<ue}Dgk2@@txoH%LH
zq{)*fPnj}h>eQ*zrcIkZefo?UGiJ`5IcwIe*|TTQnKNhZ+`04S&6_`e{(=Py7A{=4
zXwjm@ix)3hvSjJfrOTErTfThxiWMtXu3Wil)vDF2SFc&KX6@Rw>(;GXzkdCO4I4IY
z+_-7erp=o-Z`rbC>(;H?wr$(Kefy3bJ9h5exog+1-Me@1*|TTw-o5+w?c2Y9|A7Ms
z4jw#s=+L3VhYue)a^&dIqsNXNJAVB5i4!MIo;-Q#)Tz^_PoFt+=Iq(C=gyrwfByW1
z3l}b4ym;x-rOTHuU%7JS>eZ{)u3fu+{rZg?H*Vg%dF$4#+qZAuxpU|4-Mjbh-MfGP
z{(}b(9zJ~d=+UFcj~_pI^5p5$r_Y`}d;a|Six)3mzI^%W)vMR9U%z?t=Iz_J@7}$8
z|Ni}l4<9~${P^k9r_Y~1fBEv|>({T}zJ2@t{ris}KYsrF`RmuO-@kwV`Sa)R-@pI<
z{rms_|NW@yUknTk%q2m7!T<j=TtCI@$iTp0@9E+gQgJIO!HJoth4tTJ#y3oU1}uUF
zO&=5lG#Vzb1@k0`2{>%EPz-VSp^^5deFo!Yo@;HVWi^;sY}o}87?!b2jlJP?bUy<F
O1B0ilpUXO@geCyMeY-XQ

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/menu.png b/sites/all/modules/form_builder/images/fields/menu.png
new file mode 100644
index 0000000000000000000000000000000000000000..acabe95a6ff52e2657581c0b0584bd1ad24251e7
GIT binary patch
literal 205
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+Fy2r>|YR_V52cCnu->|NrMt%ByE!U|=l?
z@(cd||Nno6-`n^=20DAXIEGZ*TGM}#i$Q^dIsMoF`!PN%H$LZUv6!y$prvu@%%}*r
z|H;v53O8O$mO2;+)@*;#(jm_&zWI`<X}hgr4kH`G4?8CFjH|y^GcYhPc)I$ztaD0e
F0sv9ONr3<W

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/number.png b/sites/all/modules/form_builder/images/fields/number.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba736ce48be6802553abc7da17dd1b258ba37d5c
GIT binary patch
literal 225
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3_<}uA+G=b|G#$ans@){fB*kGIXV6R|KHd0co+i%
z16xUuU+{krVA#BW$$ka~hG0(@$B>F!J^g`P2Mjoz7ccw1|C3OJ_1!u#kypwt-Cu?3
z8r}$<cyUTVL*y<?0W;SQz6&bewhsQcFF07T9e#L6%uDy-Ifu#1Dl<9O6u$aiJe`4=
ap|6Z-+DfSfvl$o|7(8A5T-G@yGywnv|5c~}

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/pagebreak.png b/sites/all/modules/form_builder/images/fields/pagebreak.png
new file mode 100644
index 0000000000000000000000000000000000000000..7cb7e9538374f47c47cef2694e5e8ed02ccf55bc
GIT binary patch
literal 178
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+AnNPTu{euU)(L9}HeCRk*>xz`$A(<QEJQ
zVEDa_4`iT*r;B4q#jT_SM`j)u4g(`YWd>#8tt=7}GZHygHF5T>Naa>M&&VRdFn==B
V?@KIod<+Z>44$rjF6*2UngHflH@*M>

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/path.png b/sites/all/modules/form_builder/images/fields/path.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a825ff00561b5efe968afe1e577f6b0bd7bdd01
GIT binary patch
literal 228
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4AKEUA+G=b|M%`ceeK#cCnu-$%+%N&44o$;OP2-x
z|Nno=PwxN*1_sWOAiv=MP{0uEUm?W6z~JTS;uunKtLA(pAA<l7%Z04m@AexVFQ^*U
zo$(g-y4%X6BF*qxM?utt*C=|OoY!1)8B2!90(GfqhvPq*-*1-AkvKhb|MA>*24;q-
YQB3PLT|Jr4z`(%Z>FVdQ&MBb@06z;+cK`qY

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/radios.png b/sites/all/modules/form_builder/images/fields/radios.png
new file mode 100644
index 0000000000000000000000000000000000000000..a4f22dca13cd59ad57b42123ef27004585dce0d5
GIT binary patch
literal 224
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3_<}uA+G=a|MTuYeeK#cCnu->V6Y(kVHE=d16xUu
zUocpJVe|ea`xzJ*f;?RuLn>}fIUmS(K!JxTV8Q2q;oEf8UTvEH@%r+MO&_`THBRMS
zqP46==Az)%2Zjd@SoL?PwsD;1-*HcZWnFyD)0R6|lFz<d^iJt*(cPm@moYFi^dvGZ
V)@OHCU|?Wi@O1TaS?83{1OO*4T8RJv

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/revisions.png b/sites/all/modules/form_builder/images/fields/revisions.png
new file mode 100644
index 0000000000000000000000000000000000000000..05e29be9481303c148981c9ff7cd36fe046ae3ba
GIT binary patch
literal 976
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+Fc1UGwfg{qO&OCnu->V8F)4#?H>p!NI}F
z$;rjV#m&vl!^6YN%ge{d$Is6%ARr(pC@3T(BrGf}A|fIxDk>%>CN3^6At50tDJdl-
zB`qy2BO@a#D=Q}_CoeCrprD|rsHmi*q^zv0qN1Xzs;Z`@rmn88p`oFvsi~!<rLC>4
zqobp%tE;D{r?0PXU|?WqXlP_)WNd6~Vq#)yYHDU?W^Qh7VPRouX=!C;Wo>P3V`F1$
zYinm`XK!!s;Nals=;-9+<m~M1;^N}!>gwj^=I-w9;o;%w>FMR=<?Ze5<KyG&>+9#|
z=kM<y5D*X;7#I{36dW8J5)u*`8X6WB79JiR5fKp?85tE76&)QN6B82~8ygoF7at#=
zkdTm=n3$B5l$@NLl9G~|nwplDmY$xTk&%&^nVFT9m7SfPlarI1o12%Hm!F?sP*6}<
zSXfk4R9swKQc_Y{T3S|CR$g9SQBhG@Sy@$8Rb5?OQ&Ur0TU%FGS6^S>(9qD>*x1z6
z)ZE<M($dn}+S=CE*52OU(b3V_+1b_A)!p6Q)6>)2+uPUI*WceiVZwxo6DLlZG->kW
z$y26GnL2gqv}x0(PoF+x#*CRWXU>{6YxeBfbLPyMJ9qB9dGqGapTA(if`tngE?Tr`
z@#4ixmMmGibm_8X%a$)+zGB6Sl`B`STD5BR>eXx3tXaEu?YedA)~{c`VZ(-v8#iv+
zv}yC^&0Dr?*}8S>wr$(CZ{NOS$BvylckbG?YxnNmd-m+vyLa!tef#$B-+$o1frAGR
z9y)aB@ZrNpjvP69^ysl;$BrLAe&WQ5lP6D}I(6#w>C<P<oH={;?74I2&YwSj;lhQB
z7cXAAbm{Wt%U7;kxq9{LwQJX|U%!6i#*LddZ{E6f>-O#2ckbM|d-v|Wd-v|&zyILD
zgNF|vK6>=%@#Du&o;-Q_^y#x_&z?Vj{^G@pmoHzwdiCn{>(_7Iym|Zf?YnpH-oJnU
z;lqcIA3uKj^y%~G&tJZL`TF(iw{PFRfB*jD$B&;sfByRQ>-X>9fByXW`}gm^fB*jf
z|Id25A(?@JfvqISFBqKs88+`<vY&y0A;i<gF{I*FNxvgsg98WiLQeV5|I_ycFFmE@
zRy{|PQ73L={)4&P6=g9Am6tBJiC6q$Iy|3Y_91Bj2Ga+Un<on1wa|LXx`OG+>q}eB
ieov44{rRol0furlcOz}<=d2723=E#GelF{r5}E*zc+}<q

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/select.png b/sites/all/modules/form_builder/images/fields/select.png
new file mode 100644
index 0000000000000000000000000000000000000000..94d3f66b58126c5552872032add95904c44d2245
GIT binary patch
literal 210
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+Fc1UGwfg{r~@eCnu->|Nj?W_`<}%z`$A(
z<QM$^|Ns9Czqj#$4D|4HaSW-rRnq6kcR+#X@SLUp>pw?r^wmvz){?4pK}FztvqF9>
z$J7}PAwM@BsbZ{aeJga%m^*5sue7b$ao*3yyZ)QZIC4z)0K;;2#yCIu8#5Ug7#KWV
L{an^LB{Ts5ADvA6

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/taxonomy.png b/sites/all/modules/form_builder/images/fields/taxonomy.png
new file mode 100644
index 0000000000000000000000000000000000000000..285aa3540c07b8f28b73e470503f095915a4108c
GIT binary patch
literal 219
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+Fy2r>|YR=H%q`?>`7IE;ic1z`(#-666;Q
z;xqi-#s@Mm(9^{+q~cc0c}Knj1{}<ew;%q`&r>LkI&rXFR7$hsV?o(|xob?%UAYxE
zvKoFd?%KjVxvbW4_YM`!cJEbAiE=3(Z{{9ZY~bIv_M>!C-G9LZh7Mk)Wem^HE@oh0
OVDNPHb6Mw<&;$Tgj8Ccn

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/textarea.png b/sites/all/modules/form_builder/images/fields/textarea.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c41a8890fdb2a02ecf0633751d336d520344e59
GIT binary patch
literal 216
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@3_<}uA+Fc1UGwfg{qO&OCnu->U@-CSL|Fy~2DXwQ
zzhJNc!{+@<_A@XrczL=whE&|D>Axt%Ai%+*{rrD@<jExxWuJ=HcKl+z%b0GGaB9QU
zEevuFNBBP&Z42t%k>o4icwYPTOh%^(sVXKbcE5OEI@d>@iH9LWl*wJVR&NIb0|SGn
LtDnm{r-UW|4X03s

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/textfield.png b/sites/all/modules/form_builder/images/fields/textfield.png
new file mode 100644
index 0000000000000000000000000000000000000000..945a9742cb7ec8f68a7ccc8bd1356708fa368045
GIT binary patch
literal 967
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@%nSiOA+G=b|G#$ans@(cCnu->|NpbHva+$Uv9q&t
zaBy&Pa&mETadUI?@bK{R^78TV@$>Tw2nYxY3JM7c2@4C0h=_=aii(MeiHnO%NJvOZ
zN=ivdNlQ!1$jHdb%F4;f$;-<tC@3f@Dk>={DJv_hsHmu_s;a4}sjI7NXlQ6^YHDd|
zX=`ii=;-L`>gws~>Feto7#J8D8X6fH85<j$n3$NFnwpuJnVXwiSXfwET3T6ISzBA%
z*x1<G+S=LK+1uMYI5;>uIyyNyIXgSMxVX5wy1Kc!xx2f2czAevdU|<zd3$^N`1ttx
z`uh3#`TP3^1Ox;I1_lKM1qTO*goK2KhK7ZOg@=bnL_|bJMn*+NMMp=+#KgqL#>U0P
z#mC1dBqSszCMG2%B_}7Rq@<*#rlzH(rKhK7WMpJ!W@cq&WoKvS<mBY$=H}()<>%)Y
z6ciK|78Vs16&Dwml$4Z~mX?*3m6w-SR8&+}R#sJ2RaaNn)YR10*4EY4)z{ZIG&D3e
zHa0aiH8(f6w6wIgwzjpkwYRr-baZrfc6N1jb$567^z`)h_V)Gl_4oHrm@r}D#EFw8
zO`1G;@{}o4rcRwYZQ8Wy)2GjvF=OV;nX_iinmv2=oH=vm&Ye4N-n{wq=Py{WVBx}r
zixw?fym;}FB}<krUAk=9vgON{uUN5S<;s<-R;^mSdi9z$Yu2t^yKddO_3PJf*sx*a
z#*LdcZQ8tf^Oh}Jwr<_JZQHi(+qdu7v18}Xox67J+P!=Co;`c^?%lg@-@g6(_a8WL
z;NZc7hYlS&eE9H@BS(%NJ$mfevE#>&pEz;i<jIq#PMtb^`t+GIXU?8Id+yx1^XJcB
zxNza(#fz6NUAlbv@|7!Bu3o)*?b@~L*RS8WapUIAo40P=x_$fhojZ5#-o1P8-o5+x
z?>~6(;NioEj~+dG{P^*cCr_R}efsR#v**vBzj*QD<;$0^UcGw#`t_SPZ{EIr`|jPl
z_wV0-`0(N5$B&;refs?Q^OrAQzJC4s?c2BS-@pI(@#E*upTB<n`u+R&pFe;8{{8#!
z-@pI=|F;{yRbXIXU@Zyq3;zHA|9^(x+xS2^$j8&gF{I*FPk%HQg8~POv(?Re|Et$0
z&vHy-;eB!ZheNdf7JfxZ;X^$aTG&2(5outbwm@7^lO^4>^VUMc{pA^lj#O&;etCT5
e_fEwF416n#?yl&q+|0nhz~JfX=d#Wzp$Pzham`c!

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/fields/time.png b/sites/all/modules/form_builder/images/fields/time.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba55d4b435b1d3f267f254eef33c0632f6fd25bd
GIT binary patch
literal 209
zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU<L*T$r9IylHmNblJdl&R0hYC
z{G?O`&)mfH)S%SFl*+=BsWuD@4EzB;A+AnNPTu{euU)(L9}HeCRk*>xz`$A(<QEJQ
zVEDa_4`iUbr;B4q#jT$6o_q`n9Lxute*T}m_K3@YZr?8k6J3vR*d54Xd1m^IX_`ud
zgWO$qj~umI-E2$zA4C_;?%P-!EbbEh_3s^_1co3*CeM>wY+o=iFfe$!`njxgN@xNA
DvmQ)^

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/images/status-active.gif b/sites/all/modules/form_builder/images/status-active.gif
new file mode 100644
index 0000000000000000000000000000000000000000..207e95c3fa8cc31a89af150ad74059b1667922b6
GIT binary patch
literal 2196
zcmZ?wbhEHb<YnMx_|5<V9L0Nis`pA%ACqZ0W;)@N+njSzi!NucztO$_;nuBN7o2;(
z_1gQrd-v|W_x{+iW9QDDyLRo`y?gggJ^Fm@`S*M8zdwKe{Q3Lu&%ghF|Ni~^@BhDp
z!2j?6K>%d>C>{-gK^y{#|GE8KLxP<h16+;t444@i7#I|Pvaqr-FfizVoDIq*3>@VQ
zj2tWuii}OHqHKI?5)>Mo+u2QYL<Afd8X3e5iv(_LaA;*=6!O{8(U5SITh2l4gTcXt
zZLEv}6&{jBY0hjMS(jp7DyB0{FtRnUIB+11flb8kT+A(_h9iBVGx$0*H!vM#U=uL8
zV)5b7wRR2_EtMS)5)L&oGGcQ}0>~`}iH=MRQfyi=8WRp5;AUZ9(I{BZaDa(Zyy}62
z!hwc%E?X6jgaeHSxVg1GLNYHNbYx-T*O;<1fstV*gPuZx#f5_`ojj~u9}EnV{M+2}
zqgXbWWcW<s4wQ?L5Wr?>7|7Cs#DvyHW^N^s6#@qw8`;E)A~Y^Ew{tSF`7sD2EMRA6
zwc`4q@PWa3G9yQTi-rQDD+`CHSOSN_V<&bQX|Wp`6VeYg8Y^>MNho-Fq}8sIkB0-B
zRf!<0Kw;g;!5HG95y0%k$e^HPpfG{qaElmgP)7&IP6j3mmI8r>W)=<Mh?D|@Mu+K)
zNo))aLW<4I7W`}OR0ygxOk@&|3*iuKXq?2rQ6N##sK~T{*<4OU%Rm8}tw|tTv4m<u
zLSqY$aoh=x1C0lIx%3rwJUHmw*vBr&u|`9ovAv61j9~>wLUIEGi=WjDg}{Z)OpFX1
z9}Em0Ij}Q{NzJVkatQ7-c5GuQC`fd`W^FjgTC{Lw5Ro{M`0x-TvpNGuLf~QsekOi}
zH5>|yTpKwZ^js7+FdgU8;$#vqFmPmG<})+XSul~Av5%u%?@Gc470(taRv}sJaTo`(
z%Yl)h32VTLwNw~3I5#uNsuVO#ICzkSDUi=*rIBg_iyT8hN<cwE6N7=eiA%)8v?fmG
ziXs&O1!YD)W_<&f4}ysYo4MK9Sg?679%Q8fqXT+cMGw^j5eptWvM^~cVhJcb$TUrs
znd5-Q1;>L73|uS`4-ywN%wuBr`SRf4<3k;m{8P@HEPTK?L6O%8d-{n0*-1D^Icy>X
z9b8&ugbKEBOk{9pVOAFskvPD>I)OnZC&wd!$*-3~+DT@`L50(kI2xHWtnefoJc+eJ
z(1C%MlR?13;S&RM3lAS#gr<Q?L$e;Y%8Z!@8XdZL%(!+uIC%H~Coj8L#Ep$iE(~mZ
zVNVP`FgdgE3Fp~(gd|{1HsCyhBegOs8;MjnCNVIJuvtCW!O+0S#K@#@AcCQxxtYU4
zhNZzF;pij=zKRb4ip!kXg;nxc6b?8ao6lqVEQhn<<%K!2;$?GIV)ra&$hNSu6-7uW
zEIPo*tZtwqkkIJR%Vfi0^WY#O10yr9&X)%d4>+}ONHAScxRB&Hh1-`cBf{bF@m3qg
V6(SzN4-U5qi~pL_X`sMh4FIKMsvQ6T

literal 0
HcmV?d00001

diff --git a/sites/all/modules/form_builder/includes/form_builder.admin.inc b/sites/all/modules/form_builder/includes/form_builder.admin.inc
new file mode 100644
index 00000000..4665348b
--- /dev/null
+++ b/sites/all/modules/form_builder/includes/form_builder.admin.inc
@@ -0,0 +1,762 @@
+<?php
+
+/**
+ * @file form_builder.admin.inc
+ * Administrative interface for editing forms.
+ */
+
+/**
+ * Main form building interface. Can be used as a menu callback.
+ *
+ * @param $form_type
+ *   The type of form being edited. Usually the name of the providing module.
+ * @param $form_id
+ *   The unique identifier for the form being edited with the type.
+ */
+function form_builder_interface($form_type, $form_id) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  // Set the current form type (used for display of the sidebar block).
+  form_builder_active_form($form_type, $form_id);
+
+  // Load the current state of the form, or create a new cache if needed.
+  $form_structure = form_builder_cache_load($form_type, $form_id);
+  if (!$form_structure) {
+    $form_structure = form_builder_load_form($form_type, $form_id);
+    form_builder_cache_save($form_type, $form_id, $form_structure);
+  }
+
+  $output = array();
+  $output[] = drupal_get_form('form_builder_preview', $form_structure, $form_type, $form_id);
+  $output[] = drupal_get_form('form_builder_positions', $form_structure, $form_type, $form_id);
+
+  return $output;
+}
+
+/**
+ * Menu callback for adding a field.
+ */
+function form_builder_add_page($form_type, $form_id, $element_type) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  $fields = form_builder_get_form_type($form_type);
+  if (isset($fields[$element_type])) {
+    $cache = form_builder_cache_load($form_type, $form_id);
+    $element_id = isset($_REQUEST['element_id']) ? $_REQUEST['element_id'] : 'new_' . time();
+    $element = $fields[$element_type]['default'];
+
+    // Set the element ID to a hard-coded value if a unique field type.
+    if (isset($fields[$element_type]['unique']) && $fields[$element_type]['unique']) {
+      $element_id = $element_type;
+    }
+
+    $element['#form_builder']['element_id'] = $element_id;
+    $element['#form_builder']['is_new'] = TRUE;
+    $element = form_builder_add_default_properties($element, $form_type, $element_id);
+
+    $element['#weight'] = count(element_children($cache));
+
+    drupal_alter('form_builder_add_element', $element, $form_type, $form_id);
+
+    // Save any element ID set by the hook_form_builder_add_element_alter().
+    $element_id = $element['#form_builder']['element_id'];
+
+    form_builder_cache_field_save($form_type, $form_id, $element);
+
+    if (isset($_REQUEST['js'])) {
+      $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
+      $preview_form = form_builder_cache_load($form_type, $form_id);
+
+      $data = array(
+        'formType' => $form_type,
+        'formId' => $form_id,
+        'elementId' => $element_id,
+        'html' => form_builder_field_render($form_type, $form_id, $element_id),
+        'positionForm' => drupal_render(drupal_get_form('form_builder_positions', $preview_form, $form_type, $form_id)),
+      );
+
+      form_builder_json_output($data);
+      exit();
+    }
+  }
+
+  // Otherwise return to the previous page.
+  drupal_goto();
+}
+
+/**
+ * Menu callback for configuring a field.
+ */
+function form_builder_configure_page($form_type, $form_id, $element_id) {
+  $output = drupal_get_form('form_builder_field_configure', $form_type, $form_id, $element_id);
+
+  if (isset($_REQUEST['js'])) {
+    // Return the newly changed field.
+    if (isset($_REQUEST['return'])) {
+      form_builder_field_json($form_type, $form_id, $element_id);
+    }
+    // Display the configuration form for a field.
+    else {
+      $data = array(
+        'formType' => $form_type,
+        'formId' => $form_id,
+        'elementId' => $element_id,
+        'html' => drupal_render($output),
+        'errors' => form_get_errors(),
+      );
+      form_builder_json_output($data);
+      exit();
+    }
+  }
+
+  return $output;
+}
+
+/**
+ * Menu callback for removing a field.
+ */
+function form_builder_remove_page($form_type, $form_id, $element_id) {
+  $output = drupal_get_form('form_builder_field_remove', $form_type, $form_id, $element_id);
+
+  if (isset($_REQUEST['js']) && !isset($_REQUEST['return'])) {
+    // This after build function immediately returns the form as JSON.
+    $data = array(
+      'formType' => $form_type,
+      'formId' => $form_id,
+      'elementId' => $element_id,
+      'html' => drupal_render($output),
+    );
+
+    form_builder_json_output($data);
+    exit();
+  }
+
+  return $output;
+}
+
+/**
+ * Render the palette of fields to add to a form.
+ */
+function form_builder_field_palette() {
+  $active = form_builder_active_form();
+  $output = NULL;
+  if (isset($active)) {
+    $fields = form_builder_get_form_type($active['form_type']);
+    $groups = module_invoke_all('form_builder_palette_groups');
+    // TODO: We shouldn't have to clear the cache here.
+    $form = form_builder_cache_load($active['form_type'], $active['form_id'], NULL, TRUE);
+    $active_fields = form_builder_get_element_ids($form);
+    foreach ($fields as $key => $field) {
+      if ($field['unique'] && in_array($key, $active_fields)) {
+        $fields[$key]['in_use'] = TRUE;
+      }
+      if ($field['addable'] == FALSE) {
+        unset($fields[$key]);
+      }
+    }
+    $output = theme('form_builder_field_palette', array('fields' => $fields, 'groups' => $groups, 'form_type' => $active['form_type'], 'form_id' => $active['form_id']));
+  }
+  return $output;
+}
+
+/**
+ * Form. Given a form array, present it for editing in a preview.
+ */
+function form_builder_preview($f, &$form_state, $form, $form_type, $form_id) {
+
+  // @todo: think about this more. We basically get the form from outside, so
+  // while normally the first argument would be $form, we use the third, which
+  // is provided by the caller.
+
+  // Make modifications to all form elements recursively.
+  $element_ids = form_builder_preview_prepare($form, $form_type, $form_id);
+
+  // Record all the element IDs within the entire form.
+  $form['#form_builder']['element_ids'] = $element_ids;
+  $form['#form_builder']['form_type'] = $form_type;
+  $form['#form_builder']['form_id'] = $form_id;
+
+  // Add a pre_render to the entire form itself.
+  $form['#pre_render'][] = 'form_builder_pre_render_form';
+  $form['#theme_wrappers'] = array('form_builder_wrapper');
+
+  // Add required jQuery UI elements.
+  $form['#attached']['library'][] = array('system', 'ui.draggable');
+  $form['#attached']['library'][] = array('system', 'ui.droppable');
+  $form['#attached']['library'][] = array('system', 'ui.sortable');
+
+  $form['#attached']['library'][] = array('system', 'form');
+  $form['#attached']['js'][] = drupal_get_path('module', 'form_builder') .'/form_builder.js';
+
+  // TODO: This JS file should be loaded dynamically as needed.
+  $form['#attached']['js'][] = drupal_get_path('module', 'options_element') .'/options_element.js';
+  // TODO: Use libraries if available. see http://drupal.org/node/954804
+  $form['#attached']['js'][] = 'misc/tabledrag.js';
+  $form['#attached']['js'][] = 'misc/jquery.cookie.js';
+  $form['#attached']['library'][] = array('system', 'form');
+  $form['#attached']['js'][] = 'misc/form.js';
+  $form['#attached']['js'][] = 'misc/collapse.js';
+  $form['#attached']['js'][] = array('data' => array('formBuilder' => array('emptyFieldset' => theme('form_builder_empty_fieldset'))), 'type' => 'setting');
+
+  $form['#attached']['css'][] = drupal_get_path('module', 'form_builder') .'/form_builder.css';
+  $form['#attached']['css'][] = drupal_get_path('module', 'options_element') .'/options_element.css';
+
+  return $form;
+}
+
+/**
+ * Form containing all the current weights and parents of elements.
+ */
+function form_builder_positions($form, &$form_state, $preview_form, $form_type, $form_id) {
+  $form = array(
+    '#tree' => TRUE,
+    '#form_builder' => array(
+      'form_type' => $form_type,
+      'form_id' => $form_id,
+      'form' => $preview_form,
+    ),
+  );
+
+  form_builder_positions_prepare($form, $preview_form);
+
+  // Drupal MUST have a button to register submissions.
+  // Add a button even though the form is only submitted via AJAX.
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Update'),
+  );
+
+  return $form;
+}
+
+/**
+ * Recursive helper for form_builder_positions(). Add weight fields.
+ */
+function form_builder_positions_prepare(&$form, &$preview_form, $parent_id = FORM_BUILDER_ROOT) {
+  foreach (element_children($preview_form) as $key) {
+    // Keep record of the current parent ID.
+    $previous_parent_id = $parent_id;
+
+    if (isset($preview_form[$key]['#form_builder']['element_id'])) {
+      // Set the parent ID for this element.
+      $preview_form[$key]['#form_builder']['parent_id'] = $parent_id;
+      $element_id = $preview_form[$key]['#form_builder']['element_id'];
+      $parent_id = $element_id;
+
+      $form[$element_id]['weight'] = array(
+        '#type' => 'hidden',
+        '#default_value' => isset($preview_form[$key]['#weight']) ? $preview_form[$key]['#weight'] : 0,
+        '#attributes' => array('class' => array('form-builder-weight form-builder-element-' . $element_id)),
+      );
+      $form[$element_id]['parent'] = array(
+        '#type' => 'hidden',
+        '#default_value' => $preview_form[$key]['#form_builder']['parent_id'],
+        '#attributes' => array('class' => array('form-builder-parent form-builder-element-' . $element_id)),
+      );
+    }
+
+    form_builder_positions_prepare($form, $preview_form[$key], $parent_id);
+    $parent_id = $previous_parent_id;
+  }
+}
+
+/**
+ * Submit handler for the form_builder_positions form.
+ */
+function form_builder_positions_submit(&$form, &$form_state) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  $form_type = $form['#form_builder']['form_type'];
+  $form_id = $form['#form_builder']['form_id'];
+  $preview_form = $form['#form_builder']['form'];
+
+  foreach (element_children($form) as $element_id) {
+    // Skip items without weight value (like the form token, build_id, etc).
+    if (!isset($form[$element_id]['weight'])) {
+      continue;
+    }
+
+    // Check for changed weights or parents.
+    $element = form_builder_get_element($preview_form, $element_id);
+    $element['#weight'] = $form_state['values'][$element_id]['weight'];
+    $element['#form_builder']['parent_id'] = $form_state['values'][$element_id]['parent'];
+    form_builder_set_element($preview_form, $element);
+  }
+
+  // Save all the changes made.
+  form_builder_cache_save($form_type, $form_id, $preview_form);
+}
+
+/**
+ * Output the wrapper around the form_builder preview.
+ *
+ * Optionally outputs the field palette if it is not already available as a
+ * block.
+ */
+function theme_form_builder_wrapper($variables) {
+  $element = $variables['element'];
+
+  $output = '';
+  $output .= '<div id="form-builder-wrapper" class="' . ($element['#block_enabled'] ? 'no-palette' : 'with-palette') . '">';
+  if (!$element['#block_enabled']) {
+    $output .= '<div id="form-builder-fields">';
+    $output .= '<div class="block">';
+    $output .= form_builder_field_palette();
+    $output .= '</div>';
+    $output .= '</div>';
+  }
+
+  $output .= '<div id="form-builder">';
+  if (isset($element['#title'])) {
+    $output .= '<h3>' . $element['#title'] . '</h3>';
+  }
+
+  // Add the contents of the form and close the wrappers.
+  $output .= $element['#children'];
+  $output .= '</div>'; // #form-builder.
+  $output .= '</div>'; // #form-builder-wrapper.
+  return $output;
+}
+
+/**
+ * Output the wrapper around a form_builder element with configure/remove links.
+ */
+function theme_form_builder_element_wrapper($variables) {
+  $element = $variables['element'];
+
+  $removable = isset($element['#form_builder']['removable']) ? $element['#form_builder']['removable'] : TRUE;
+  $configurable  = isset($element['#form_builder']['configurable']) ? $element['#form_builder']['configurable'] : TRUE;
+
+  $output = '';
+  $output .= '<div class="form-builder-wrapper">';
+  if ($removable || $configurable) {
+    $output .= '<div class="form-builder-title-bar">';
+    $output .= '<span class="form-builder-links">';
+    if ($removable) {
+      $output .= l('<span class="remove">'. t('Remove') .'</span>', 'admin/build/form-builder/remove/' . $element['#form_builder']['form_type'] . '/' . $element['#form_builder']['form_id'] . '/' . $element['#form_builder']['element_id'], array('html' => TRUE, 'attributes' => array('class' => array('remove'), 'title' => t('Remove')), 'query' => drupal_get_destination()));
+    }
+    if ($removable && $configurable) {
+      $output .= ' ';
+    }
+    if ($configurable) {
+      $output .= l('<span class="configure">'. t('Configure') .'</span>', 'admin/build/form-builder/configure/' . $element['#form_builder']['form_type'] . '/' . $element['#form_builder']['form_id'] . '/' . $element['#form_builder']['element_id'], array('html' => TRUE, 'attributes' => array('class' => array('configure'), 'title' => t('Configure')), 'query' => drupal_get_destination()));
+    }
+    $output .= '</span>';
+    $output .= '</div>';
+  }
+
+  $output .= '<div class="form-builder-element form-builder-element-' . $element['#type'] . '" id="form-builder-element-' . $element['#form_builder']['element_id'] . '">';
+  // TODO: Overlay image: good idea or bad idea? Prevents any interaction with
+  // form elements in the preview.
+  //$output .= theme('image', drupal_get_path('module', 'form_builder') .'/images/blank.gif', '', '', array('width' => '1', 'height' => '1', 'class' => 'form-builder-disable'));
+  $output .= $element['#children'];
+
+  $output .= '</div></div>';
+
+  return $output;
+}
+
+/**
+ * Placeholder for empty fieldsets during drag and drop.
+ */
+function theme_form_builder_empty_fieldset($variables) {
+  $output = '';
+  $output .= '<div class="form-builder-wrapper form-builder-empty-placeholder">';
+  $output .= '<span>' . t('This fieldset is empty. Drag a form element into it.') .'</span>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Block for adding new fields.
+ *
+ * @param $vars['fields']
+ *   A list of all fields can be added to the current form type.
+ * @param $vars['groups']
+ *   A list of groups that fields may be sorted into. Each field is assigned
+ *   a 'palette_group' property which corresponds to one of these groups.
+ * @param $vars['form_type']
+ *   The form type to which these blocks apply.
+ * @param $vars['form_id']
+ *   The form ID that is being edited.
+ */
+function theme_form_builder_field_palette($vars) {
+  extract($vars);
+
+  $output = '';
+  $lists = array();
+  foreach ($fields as $field_name => $field) {
+    $class = array('field-' . $field_name, 'form-builder-palette-element');
+    $style = '';
+
+    // If a field is unique, add a special class to identify it.
+    if ($field['unique']) {
+      $class[] = 'form-builder-unique';
+      $class[] = 'form-builder-element-' . $field_name;
+
+      // If already in use, do not display it in the list.
+      if (!empty($field['in_use'])) {
+        $style = 'display: none;';
+      }
+    }
+
+    $lists[$field['palette_group']]['#weight'] = $groups[$field['palette_group']]['weight'];
+    $lists[$field['palette_group']][] = array(
+      'data' => l($field['title'], 'admin/build/form-builder/add/' . $form_type . '/' . $form_id . '/' . $field_name, array('query' => drupal_get_destination())),
+      'class' => $class,
+      'style' => $style,
+    );
+  }
+
+  // Sort the lists by weight.
+  uasort($lists, 'element_sort');
+
+  $output .= '<div id="form-builder-field-palette">';
+  foreach ($lists as $group => $list) {
+    unset($list['#weight']);
+    $output .= theme('item_list', array('items' => $list, 'title' => (count($lists) > 1) ? $groups[$group]['title'] : t('Add a field'), 'type' => 'ul', 'attributes' => array('class' => array('form-builder-fields', 'clearfix'))));
+  }
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Take a form structure and add a prebuild function to every element.
+ */
+function form_builder_pre_render($element) {
+  $element['#theme_wrappers'][] = 'form_builder_element_wrapper';
+
+  if ($element['#form_builder']['element_type'] == 'fieldset') {
+    $element['#attributes']['class'][] = 'form-builder-fieldset';
+  }
+
+  if (isset($element['#type']) && $element['#type'] == 'fieldset' && count(element_children($element)) == 0) {
+    $element['#children'] = theme('form_builder_empty_fieldset');
+  }
+
+  // Allow modules to make modifications to this element.
+  drupal_alter('form_builder_preview', $element, $element['#form_builder']['form_type'], $element['#form_builder']['form_id']);
+
+  return $element;
+}
+
+/**
+ * Pre-render function to alter the form being edited by Form builder.
+ *
+ * This function modifies the form element itself and sets a #title to label the
+ * form preview and an #block_enabled property to indicate to the theme wrapper
+ * whether the field palette should be added.
+ */
+function form_builder_pre_render_form($form) {
+  global $theme;
+
+  // We can't have forms inside of forms, so change this entire form a markup.
+  $form['#type'] = 'markup';
+
+  // Set a title for the preview if none exists.
+  $form['#title'] = !isset($form['#title']) ? t('Form preview') : $form['#title'];
+
+  // Remove unnecessary FAPI elements.
+  unset($form['form_build_id']);
+  unset($form['form_token']);
+  unset($form['form_builder_preview']);
+
+  // Check if the Form Builder block is enabled.
+  // Otherwise make our own columns.
+  $form['#block_enabled'] = db_query("SELECT status FROM {block} WHERE module = 'form_builder' AND theme = :theme", array(':theme' => $theme))->fetchField();
+
+  if ($form['#block_enabled'] && ($theme == 'garland' || $theme == 'minnelli')) {
+    $form['#attached']['css'][] = drupal_get_path('module', 'form_builder') . '/form_builder.garland.css';
+  }
+
+  return $form;
+}
+
+function form_builder_after_build($element) {
+  $element['#attributes']['readonly'] = 'readonly';
+  foreach (element_children($element) as $key) {
+    $element[$key] = form_builder_after_build($element[$key]);
+  }
+
+  return $element;
+}
+
+/**
+ * Before editing a form, modify it slightly to add functionality used in
+ * the preview and disable use of the actual form fields in any way.
+ *
+ * @return
+ *   A list of all element_ids currently used within this form.
+ */
+function form_builder_preview_prepare(&$form, $form_type, $form_id, $parent_id = FORM_BUILDER_ROOT) {
+  $element_ids = array();
+  foreach (element_children($form) as $key) {
+    // Keep record of the current parent ID.
+    $previous_parent_id = $parent_id;
+
+    if (isset($form[$key]['#form_builder']['element_id'])) {
+      $element_ids[] = $form[$key]['#form_builder']['element_id'];
+      $form[$key]['#pre_render'][] = 'form_builder_pre_render';
+      $form[$key]['#form_builder']['form_type'] = $form_type;
+      $form[$key]['#form_builder']['form_id'] = $form_id;
+      $form[$key]['#form_builder']['parent_id'] = $parent_id;
+      // Do not allow the #pre_render function we added above to force any
+      // #pre_render functions associated with the element itself to be
+      // skipped; we still want those to run whenever they otherwise would
+      // have.
+      // @todo: Revisit if there is a different way to do this after
+      //   http://drupal.org/node/914792 is committed to core.
+      if (count($form[$key]['#pre_render']) == 1) {
+        $info = element_info($form[$key]['#type']);
+        if (!empty($info['#pre_render'])) {
+          $form[$key]['#pre_render'] = array_merge($info['#pre_render'], $form[$key]['#pre_render']);
+        }
+      }
+
+      $parent_id = $form[$key]['#form_builder']['element_id'];
+    }
+
+    // Search within this element for further form elements.
+    $additional_ids = form_builder_preview_prepare($form[$key], $form_type, $form_id, $parent_id);
+    $element_ids = array_merge($element_ids, $additional_ids);
+    $parent_id = $previous_parent_id;
+  }
+
+  return $element_ids;
+}
+
+/**
+ * Form for editing a field.
+ */
+function form_builder_field_configure($form, $form_state, $form_type, $form_id, $element_id) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+  $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
+
+  // Assemble a form made up of all the configurable properties that this type
+  // of form supports.
+  $form = array();
+  foreach (form_builder_get_element_properties($form_type, $element['#form_builder']['element_type']) as $property => $property_settings) {
+    if (isset($property_settings['form']) && function_exists($property_settings['form'])) {
+      $function = $property_settings['form'];
+      // Set a default value on the property to avoid notices.
+      $element['#' . $property] = isset($element['#' . $property]) ? $element['#' . $property] : NULL;
+      $form = array_merge($form, $function($form_state, $form_type, $element));
+    }
+  }
+
+  $form['#_edit_form_type'] = $form_type;
+  $form['#_edit_form_id'] = $form_id;
+  $form['#_edit_element_id'] = $element_id;
+  $form['#_edit_element'] = $element;
+  $form['#pre_render'][] = 'form_builder_field_configure_pre_render';
+
+  $form['form_builder_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+    '#weight' => 100,
+  );
+
+  return $form;
+}
+
+/**
+ * Pre-render function for the field configuration form.
+ */
+function form_builder_field_configure_pre_render($form) {
+  $groups = module_invoke_all('form_builder_property_groups', $form['#form_type']);
+
+  foreach (element_children($form) as $key) {
+    // If no group is specified, put the element into the default group.
+    if (!isset($form[$key]['#form_builder']['property_group']) || !isset($groups[$form[$key]['#form_builder']['property_group']])) {
+      if (!isset($form[$key]['#type']) || (isset($form[$key]['#type']) && !in_array($form[$key]['#type'], array('hidden', 'button', 'submit', 'value', 'token')))) {
+        $form[$key]['#form_builder']['property_group'] = 'default';
+      }
+    }
+
+    if (isset($form[$key]['#form_builder']['property_group'])) {
+      $group = $form[$key]['#form_builder']['property_group'];
+
+      // We add "_property_group" to the field key to prevent conflicts of
+      // property names and group names.
+      if (!isset($form[$group . '_property_group'])) {
+        $form[$group . '_property_group'] = array(
+          '#type' => 'fieldset',
+          '#title' => $groups[$group]['title'],
+          '#weight' => $groups[$group]['weight'],
+          '#collapsible' => isset($groups[$group]['collapsible']) ? $groups[$group]['collapsible'] : FALSE,
+          '#collapsed' => isset($groups[$group]['collapsed']) ? $groups[$group]['collapsed'] : FALSE,
+          '#attributes' => array('class' => array('form-builder-group')),
+        );
+      }
+
+      $form[$group .'_property_group'][$key] = $form[$key];
+      unset($form[$key]);
+    }
+  }
+
+  return $form;
+}
+
+function form_builder_field_configure_submit(&$form, &$form_state) {
+  $form_type = $form['#_edit_form_type'];
+  $form_id = $form['#_edit_form_id'];
+  $element_id = $form['#_edit_element_id'];
+  $element = $form['#_edit_element'];
+
+  // Allow each element to do any necessary submission handling.
+  foreach (form_builder_get_element_properties($form_type, $element['#form_builder']['element_type']) as $property => $property_settings) {
+    if (isset($property_settings['submit'])) {
+      foreach ($property_settings['submit'] as $function) {
+        if (function_exists($function)) {
+          $function($form, $form_state);
+        }
+      }
+    }
+  }
+
+  // Allow the element to be updated in a hard-coded fashion by altering the
+  // $form['#element'] item. Using this approach skips the property check.
+  $element = $form['#_edit_element'];
+
+  // Update the field according to the settings in $form_state['values'].
+  $saveable = form_builder_get_saveable_properties($form_type, $element);
+  foreach ($form_state['values'] as $property => $value) {
+    if (in_array($property, $saveable)) {
+      // Remove empty properties entirely.
+      if ($value == '') {
+        unset($element['#'. $property]);
+      }
+      else {
+        $element['#'. $property] = $value;
+      }
+    }
+  }
+
+  // Update the form builder cache.
+  form_builder_cache_field_save($form_type, $form_id, $element);
+
+  if (isset($_GET['js'])) {
+    // Option A: Use the destination variable to do a drupal_goto(). Allows
+    // other submit handlers to add on extra functionality.
+    // The destination variable takes precedence over $form_state['redirect'].
+    //$_REQUEST['destination'] = 'admin/build/form-builder/json/' . $form_type . '/' . $form_id . '/' . $element_id;
+
+    // Option B: Immediately print the JSON and exit. Faster and requires only
+    // one HTTP request instead of two. Other submit handlers must be before
+    // this on.
+    form_builder_field_json($form_type, $form_id, $element_id);
+  }
+}
+
+/**
+ * Form for removing a field.
+ */
+function form_builder_field_remove($form, $form_state, $form_type, $form_id, $element_id) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+  $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
+
+  $form = array();
+  $form['#_edit_form_type'] = $form_type;
+  $form['#_edit_form_id'] = $form_id;
+  $form['#_edit_element_id'] = $element_id;
+
+  $question = t('Remove the field %title?', array('%title' => $element['#title']));
+  $path = isset($_GET['destination']) ? $_GET['destination'] : NULL;
+  $description = t('Remove the field %title? This field will not be permanently removed until the form configuration is saved.', array('%title' => isset($element['#title']) ? $element['#title'] : $element['#form_builder']['element_id']));
+  $yes = t('Remove');
+
+  return confirm_form($form, $question, $path, $description, $yes);
+}
+
+function form_builder_field_remove_submit(&$form, &$form_state) {
+  $form_type = $form['#_edit_form_type'];
+  $form_id = $form['#_edit_form_id'];
+  $element_id = $form['#_edit_element_id'];
+
+  // Update the form builder cache.
+  form_builder_cache_field_delete($form_type, $form_id, $element_id);
+
+  if (isset($_GET['js'])) {
+    // See form_builder_field_configure_submit() for comparison between using
+    // redirect and immediately printing the JSON.
+    //$form_state['redirect'] = 'admin/build/form-builder/json/' . $form_type . '/' . $form_id . '/' . $element_id;
+    form_builder_field_json($form_type, $form_id, $element_id);
+  }
+}
+
+/**
+ * Render a single field independent of other settings.
+ */
+function form_builder_field_render($form_type, $form_id, $element_id, $wrapper = FALSE) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  // Load the current state of the form and prepare it for rendering.
+  $form = form_builder_cache_load($form_type, $form_id);
+  if (!$form) {
+    $form = form_builder_load_form($form_type, $form_id);
+    form_builder_cache_save($form_type, $form_id, $form);
+  }
+  $form_state = array('submitted' => FALSE, 'build_info' => array('args' => array($form, $form_type, $form_id)), 'values' => array(), 'method' => 'get');
+  $form = drupal_retrieve_form('form_builder_preview', $form_state);
+  drupal_prepare_form('form_builder_preview', $form, $form_state);
+  $form['#post'] = array();
+  $form = form_builder('form_builder_preview', $form, $form_state);
+
+  // Get only the element wanted and render it.
+  $element = form_builder_get_element($form, $element_id);
+
+  if ($wrapper) {
+    $element['#theme_wrappers'][] = 'form_builder_element_wrapper';
+  }
+
+  return drupal_render($element);
+}
+
+/**
+ * Menu callback to display a field as a JSON string.
+ */
+function form_builder_field_json($form_type, $form_id, $element_id) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+  $element = form_builder_cache_field_load($form_type, $form_id, $element_id);
+
+  $data = array(
+    'formType' => $form_type,
+    'formId' => $form_id,
+    'elementId' => $element_id,
+    'html' => !empty($element) ? form_builder_field_render($form_type, $form_id, $element_id) : '',
+    'errors' => form_get_errors(),
+  );
+
+  form_builder_json_output($data);
+  exit();
+}
+
+/**
+ * Generic function for outputing Form Builder JSON return responses.
+ *
+ * Adds status messages, settings, and timestamp to a form builder JSON response
+ * and outputs it.
+ */
+function form_builder_json_output($data) {
+  if (!isset($data['messages'])) {
+    $data['messages'] = theme('status_messages');
+  }
+  if (!isset($data['settings'])) {
+    $scripts = drupal_add_js();
+    if (!empty($scripts['settings'])) {
+      $data['settings'] = drupal_array_merge_deep_array($scripts['settings']['data']);
+    }
+  }
+  if (!isset($data['time'])) {
+    $data['time'] = time();
+  }
+  drupal_json_output($data);
+}
diff --git a/sites/all/modules/form_builder/includes/form_builder.api.inc b/sites/all/modules/form_builder/includes/form_builder.api.inc
new file mode 100644
index 00000000..c4203076
--- /dev/null
+++ b/sites/all/modules/form_builder/includes/form_builder.api.inc
@@ -0,0 +1,354 @@
+<?php
+
+/**
+ * @file form_builder.api.inc
+ * Universally used API functions within the Form builder module.
+ */
+
+/**
+ * Get a list of all properties that are supported within a form type.
+ */
+function form_builder_get_properties($form_type, $reset = FALSE) {
+  static $properties = array();
+
+  if ($reset) {
+    $properties = array();
+  }
+
+  if (!isset($properties[$form_type])) {
+    // Get the list of all properties for all elements.
+    $properties = module_invoke_all('form_builder_properties', $form_type);
+    drupal_alter('form_builder_properties', $properties, $form_type);
+  }
+
+  return $properties;
+}
+
+/**
+ * Get a list of all properties that are supported by a particular form type.
+ */
+function form_builder_get_form_type($form_type = NULL, $reset = FALSE) {
+  static $types;
+
+  if (!isset($types) || $reset) {
+    $types = array();
+    // Get the list of all properties for all elements.
+    $types = module_invoke_all('form_builder_types');
+
+    // Add default values for undefined properties.
+    foreach ($types as $type_key => &$type) {
+      $groups = module_invoke_all('form_builder_palette_groups', $type_key);
+
+      foreach ($type as $field_key => &$field) {
+        $field['unique'] = isset($field['unique']) && $field['unique'];
+        $field['configurable'] = isset($field['configurable']) ? $field['configurable'] : TRUE;
+        $field['removable'] = isset($field['removable']) ? $field['removable'] : TRUE;
+        $field['addable'] = isset($field['addable']) ? $field['addable'] : $field['removable'] && isset($field['default']);
+        $field['palette_group'] = isset($field['palette_group']) && isset($groups[$field['palette_group']]) ? $field['palette_group'] : 'default';
+        $field['properties'] = isset($field['properties']) ? $field['properties'] : array();
+
+        // All fields must support weight.
+        if (!in_array('weight', $field['properties'])) {
+          $field['properties'][] = 'weight';
+        }
+
+        // Update the default elements with some defaults.
+        // Note that if a field is not removable, it doesn't have a default.
+        if ($field['addable']) {
+          if ($field['unique']) {
+            $field['default']['#form_builder']['element_id'] = $field_key;
+            $field['default']['#form_builder']['element_type'] = $field_key;
+          }
+          elseif (!isset($field['default']['#form_builder']['element_type'])) {
+            $field['default']['#form_builder']['element_type'] = $field_key;
+          }
+        }
+
+      }
+    }
+
+    drupal_alter('form_builder_types', $types);
+  }
+
+  return isset($form_type) ? $types[$form_type] : $types;
+}
+
+/**
+ * Given an element type, return properties that are supported by Form builder.
+ *
+ * @param $form_type
+ *   The type of form being edited (profile, node, webform, etc.)
+ * @param $element_type
+ *   A the #type property of a FAPI element.
+ * @param
+ *   An associative array of properties supported for editing, keyed by
+ *   the property name and containing an array of the form, submit, and
+ *   validate functions (if any).
+ */
+function form_builder_get_element_properties($form_type, $element_type) {
+  // Get the list of all properties for this type.
+  $properties = form_builder_get_properties($form_type);
+  // Get the list of supported properties per field in this form type.
+  $form_type = form_builder_get_form_type($form_type);
+
+  $element_properties = array();
+  if (isset($form_type[$element_type]['properties'])) {
+    foreach ($form_type[$element_type]['properties'] as $property) {
+      if (isset($properties[$property])) {
+        $element_properties[$property] = $properties[$property];
+      }
+    }
+  }
+
+  return $element_properties;
+}
+
+/**
+ * Get a list of properties that are supported in any way by an element.
+ *
+ * This returns a list of all supported properties within an element, even
+ * if some of those properties do not have an interface for editing or are
+ * only used internally by the module providing the form type this element
+ * is being saved in.
+ *
+ * @param $form_type
+ *   The type of form being edited (profile, node, webform, etc.)
+ * @param $element
+ *   A standard FAPI element whose properties are being checked.
+ * @return
+ *   A non-indexed list of properties that may be saved for this element.
+ * */
+function form_builder_get_saveable_properties($form_type, $element) {
+  // Get the list of supported properties on each element.
+  $form_type = form_builder_get_form_type($form_type);
+
+  $saveable = array();
+  if (isset($form_type[$element['#form_builder']['element_type']]['properties'])) {
+    $saveable = $form_type[$element['#form_builder']['element_type']]['properties'];
+  }
+
+  return $saveable;
+}
+
+/**
+ * Function to retrieve a single element within a form structure.
+ *
+ * If needing to retreive multiple elements at once, use
+ * form_builder_get_elements().
+ *
+ * @param $form
+ *   A complete hierarchical FAPI structure.
+ * @param $element_id
+ *   The unique identifier for an element that is to be retrieved.
+ * @return
+ *   A single Form API element array.
+ *
+ * @see form_builder_get_elements().
+ */
+function form_builder_get_element(&$form, $element_id) {
+  $elements = form_builder_get_elements($form, array($element_id));
+  return isset($elements[$element_id]) ? $elements[$element_id] : FALSE;
+}
+
+/**
+ * Recursive function to retrieve multiple elements within a form structure.
+ *
+ * @param $form
+ *   A complete hierarchical FAPI structure.
+ * @param $element_ids
+ *   An array of unique identifiers for elements that are to be retreived. These
+ *   identifiers match against the special property
+ *   "#form_builder['element_id']", which is not available in normal FAPI
+ *   structures. It must be added by the respective module that is providing
+ *   support for a certain field type.
+ *
+ *   For example, CCK provides a unique identifier for each field such as
+ *   "field_my_name". This field name must be added to the form array as
+ *   #form_builder['element_id'] = 'field_my_name' in CCK's implementation of
+ *   hook_form_builder_load().
+ * @return
+ *   A single Form API element array.
+ */
+function form_builder_get_elements(&$form, $element_ids) {
+  $elements = array();
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#form_builder']['element_id']) && in_array($form[$key]['#form_builder']['element_id'], $element_ids)) {
+      $elements[$form[$key]['#form_builder']['element_id']] = $form[$key];
+    }
+    $additional_elements = form_builder_get_elements($form[$key], $element_ids);
+    $elements = array_merge($elements, $additional_elements);
+  }
+  return $elements;
+}
+
+/**
+ * Recursive function to set an element within a form structure.
+ *
+ * @return
+ *   TRUE if an element was updated, FALSE if it was not found.
+ */
+function form_builder_set_element(&$form, $element, &$entire_form = NULL, $parent_id = FORM_BUILDER_ROOT) {
+  $return = FALSE;
+
+  if (!isset($entire_form)) {
+    $entire_form = &$form;
+  }
+
+  // Add new elements into the current parent.
+  if (isset($element['#form_builder']['is_new']) && strcmp($element['#form_builder']['parent_id'], $parent_id) == 0) {
+    unset($element['#form_builder']['is_new']);
+    unset($element['#form_builder']['parent_id']);
+    $new_key = $element['#key'];
+    $form[$new_key] = $element;
+    return TRUE;
+  }
+
+  foreach (element_children($form) as $key) {
+    // Update an existing element if it lives in the current parent.
+    if (isset($form[$key]['#form_builder']['element_id']) && $form[$key]['#form_builder']['element_id'] == $element['#form_builder']['element_id']) {
+
+      // If the parent has changed, re-parent the element to a new fieldset.
+      if (isset($element['#form_builder']['parent_id']) && strcmp($element['#form_builder']['parent_id'], $parent_id) != 0) {
+        // Remove the current element from the form.
+        unset($form[$key]);
+        // Recurse again through the entire form to insert into the new position.
+        $element['#form_builder']['is_new'] = TRUE;
+        $return = form_builder_set_element($entire_form, $element);
+      }
+      // Handle key changes and replace the existing element in place.
+      elseif (isset($element['#key']) && $key != $element['#key']) {
+        $new_key = $element['#key'];
+        $index = array_search($key, $form);
+        $before = array_slice($form, 0, $index + 1, TRUE);
+        $after = array_slice($form, $index + 2, NULL, TRUE);
+        $form = $before + array($new_key => $element) + $after;
+        unset($form[$key]);
+        $return = TRUE;
+      }
+      // Or, most common case scenario, just update the element, no key changes.
+      else {
+        $form[$key] = $element;
+        $return = TRUE;
+      }
+    }
+
+    // Recurse into this element to look for the target element.
+    if (!$return && isset($form[$key]['#form_builder'])) {
+      $return = form_builder_set_element($form[$key], $element, $entire_form, $form[$key]['#form_builder']['element_id']);
+    }
+
+    if ($return) {
+      return $return;
+    }
+  }
+
+  return $return;
+}
+
+/**
+ * Recursive function to unset an element within a form structure.
+ */
+function form_builder_unset_element(&$form, $element_id) {
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#form_builder']['element_id']) && $form[$key]['#form_builder']['element_id'] == $element_id) {
+      unset($form[$key]);
+      break;
+    }
+    form_builder_unset_element($form[$key], $element_id);
+  }
+}
+
+/**
+ * Recursive function to check if an element exists at all within a form.
+ */
+function form_builder_get_element_ids($form) {
+  $element_ids = array();
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#form_builder']['element_id'])) {
+      $element_ids[] = $form[$key]['#form_builder']['element_id'];
+    }
+    $additional_ids = form_builder_get_element_ids($form[$key]);
+    $element_ids = array_merge($element_ids, $additional_ids);
+  }
+
+  return $element_ids;
+}
+
+/**
+ * Loader function to retrieve a form builder configuration array.
+ *
+ * @param $form_type
+ *   The type of form being edited. Usually the name of the providing module.
+ * @param $form_id
+ *   The unique identifier for the form being edited with the type.
+ */
+function form_builder_load_form($form_type, $form_id) {
+  $form = module_invoke_all('form_builder_load', $form_type, $form_id);
+  drupal_alter('form_builder_load', $form, $form_type, $form_id);
+
+  // Convert the form array keys to #key properties for editing.
+  return form_builder_add_default_properties($form, $form_type);
+}
+
+/**
+ * Execute the save methods for a form array.
+ */
+function form_builder_save_form(&$form, $form_type, $form_id) {
+  module_invoke_all('form_builder_save', $form, $form_type, $form_id);
+  form_builder_cache_delete($form_type, $form_id);
+}
+
+
+/**
+ * Helper function to add default #form_builder properties to a form.
+ */
+function form_builder_add_default_properties($form, $form_type, $key = NULL, $parent_id = FORM_BUILDER_ROOT) {
+  $form_type_fields = form_builder_get_form_type($form_type);
+
+  // Add properties to this element.
+  if (isset($form['#form_builder']['element_id'])) {
+    $element_id = $form['#form_builder']['element_id'];
+
+    // Add a #key property.
+    $form['#key'] = isset($form['#key']) ? $form['#key'] : $key;
+
+    // Add a #form_builder['parent_id'] property.
+    $form['#form_builder']['parent_id'] = $parent_id;
+    $parent_id = $element_id;
+
+    // Set defaults based on the form type.
+    if (isset($form_type_fields[$element_id]) && $form_type_fields[$element_id]['unique']) {
+      $form['#form_builder']['unique'] = TRUE;
+      $form['#form_builder']['element_type'] = isset($form['#form_builder']['element_type']) ? $form['#form_builder']['element_type'] : $element_id;
+      $settings = $form_type_fields[$element_id];
+    }
+    else {
+      $form['#form_builder']['element_type'] = isset($form['#form_builder']['element_type']) ? $form['#form_builder']['element_type'] : $form['#type'];
+      if (isset($form_type_fields[$form['#form_builder']['element_type']])) {
+        $settings = $form_type_fields[$form['#form_builder']['element_type']];
+      }
+      else {
+        // If the type cannot be found, prevent editing of this field.
+        unset($form['#form_builder']);
+        return;
+      }
+    }
+
+    // Set defaults for configurable and removable.
+    if (!isset($form['#form_builder']['configurable'])) {
+      $form['#form_builder']['configurable'] = isset($settings['configurable']) ? $settings['configurable'] : TRUE;
+    }
+    if (!isset($form['#form_builder']['removable'])) {
+      $form['#form_builder']['removable'] = isset($settings['removable']) ? $settings['removable'] : TRUE;
+    }
+  }
+
+  // Recurse into sub-elements.
+  foreach (element_children($form) as $key) {
+    if (isset($form[$key]['#form_builder']['element_id'])) {
+      $form[$key] = form_builder_add_default_properties($form[$key], $form_type, $key, $parent_id);
+    }
+  }
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/includes/form_builder.cache.inc b/sites/all/modules/form_builder/includes/form_builder.cache.inc
new file mode 100644
index 00000000..5f91cb5a
--- /dev/null
+++ b/sites/all/modules/form_builder/includes/form_builder.cache.inc
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * @file form_builder.cache.inc
+ * Functions for temporary storage of form builder structures while editing.
+ */
+
+/**
+ * Load a form configuration cache.
+ *
+ * @param $form_type
+ *   The type of form being edited.
+ * @param $form_id
+ *   The unique identifier for the form type.
+ * @return
+ *   A FAPI array if a cache entry was found. Boolean FALSE if an entry does not
+ *   yet exist. Note that an empty FAPI array may exist, so be sure to use
+ *   strict comparison (===) when checking return values.
+ */
+function form_builder_cache_load($form_type, $form_id, $sid = NULL, $reset = FALSE) {
+  static $data;
+  $sid = isset($sid) ? $sid : session_id();
+
+  if ($reset) {
+    $data = NULL;
+  }
+
+  if (!isset($data) && isset($form_type) && isset($form_id)) {
+    $data = db_query("SELECT data FROM {form_builder_cache} WHERE type = :type AND form_id = :form_id AND sid = :sid", array(':type' => $form_type, ':form_id' => $form_id, ':sid' => $sid))->fetchField();
+
+    if ($data) {
+      $data = unserialize($data);
+    }
+  }
+
+  return $data;
+}
+
+/**
+ * Save a form builder cache based on the form structure.
+ */
+function form_builder_cache_save($form_type, $form_id, $form, $sid = NULL) {
+  $sid = isset($sid) ? $sid : session_id();
+
+  if (form_builder_cache_load($form_type, $form_id, $sid) === FALSE) {
+    $result = db_insert('form_builder_cache')
+      ->fields(array(
+        'sid' => $sid,
+        'type' => $form_type,
+        'form_id' => $form_id,
+        'updated' => REQUEST_TIME,
+        'data' => serialize($form),
+      ))
+      ->execute();
+  }
+  else {
+    $result = db_update('form_builder_cache')
+      ->fields(array(
+        'updated' => REQUEST_TIME,
+        'data' => serialize($form),
+      ))
+      ->condition('sid', $sid)
+      ->condition('type', $form_type)
+      ->condition('form_id', $form_id)
+      ->execute();
+  }
+
+  // Ensure caches are fresh for any retrievals made this request.
+  form_builder_cache_load(NULL, NULL, NULL, TRUE);
+
+  return $result;
+}
+
+function form_builder_cache_delete($form_type, $form_id, $sid = NULL) {
+  $sid = isset($sid) ? $sid : session_id();
+
+  return db_delete('form_builder_cache')
+    ->condition('sid', $sid)
+    ->condition('type', $form_type)
+    ->condition('form_id', $form_id)
+    ->execute();
+}
+
+/**
+ * Delete outdated cache entries.
+ *
+ * @param $expire_threshold
+ *   The maximum amount of time allowed for entries to be kept, in seconds.
+ */
+function form_builder_cache_purge($expire_threshold = NULL) {
+  $expire_threshold = isset($expire_threshold) ? $expire_threshold : ini_get('session.cache_expire');
+
+  return db_delete('form_builder_cache')
+    ->condition('updated', REQUEST_TIME - $expire_threshold, '<')
+    ->condition('type', $form_type)
+    ->condition('form_id', $form_id)
+    ->execute();
+}
+
+/**
+ * Compare the cached form with the original and return all changed elements.
+ *
+ * @return
+ *   An array of elements keyed by the element_id of the changed element. Each
+ *   value contains an array of the 'original' and 'modified' elements.
+ */
+function form_builder_cache_difference($form_type, $form_id, $exclude_weight = TRUE) {
+  if (($modified_form = form_builder_cache_load($form_type, $form_id)) && $modified_form !== FALSE) {
+    $original_form = form_builder_load_form($form_type, $form_id);
+    $original_ids = form_builder_get_element_ids($original_form);
+    $modified_ids = form_builder_get_element_ids($modified_form);
+
+    // Find the union of IDs in both arrays.
+    $element_ids = array_keys(array_flip($original_ids) + array_flip($modified_ids));
+
+    // Build a list of all elements that have changed.
+    $differences = array();
+    foreach ($element_ids as $element_id) {
+      $original = form_builder_get_element($original_form, $element_id);
+      $modified = form_builder_get_element($modified_form, $element_id);
+
+      if ($exclude_weight) {
+        if (isset($original['#weight'])) {
+          unset($original['#weight']);
+        }
+        if (isset($modified['#weight'])) {
+          unset($modified['#weight']);
+        }
+      }
+
+      if ($original != $modified) {
+        $differences[$element_id] = array(
+          'original' => $original,
+          'modified' => $modified,
+        );
+      }
+    }
+
+    return $differences;
+  }
+  return FALSE;
+}
+
+/**
+ * Retrieve a single field from a form cache..
+ */
+function form_builder_cache_field_load($form_type, $form_id, $element_id, $sid = NULL, $reset = FALSE) {
+  $sid = isset($sid) ? $sid : session_id();
+
+  $form = form_builder_cache_load($form_type, $form_id, $sid, $reset);
+  return form_builder_get_element($form, $element_id);
+}
+
+/**
+ * Add or update a single field in a form builder cache.
+ */
+function form_builder_cache_field_save($form_type, $form_id, $element, $sid = NULL) {
+  $sid = isset($sid) ? $sid : session_id();
+
+  $form = form_builder_cache_load($form_type, $form_id, $sid);
+  form_builder_set_element($form, $element);
+  form_builder_cache_save($form_type, $form_id, $form, $sid);
+}
+
+/**
+ * Remove a single field from a form builder cache.
+ */
+function form_builder_cache_field_delete($form_type, $form_id, $element_id, $sid = NULL) {
+  $sid = isset($sid) ? $sid : session_id();
+
+  $form = form_builder_cache_load($form_type, $form_id, $sid);
+  form_builder_unset_element($form, $element_id);
+  form_builder_cache_save($form_type, $form_id, $form, $sid);
+}
diff --git a/sites/all/modules/form_builder/includes/form_builder.properties.inc b/sites/all/modules/form_builder/includes/form_builder.properties.inc
new file mode 100644
index 00000000..21658cf8
--- /dev/null
+++ b/sites/all/modules/form_builder/includes/form_builder.properties.inc
@@ -0,0 +1,358 @@
+<?php
+
+/**
+ * @file form_builder.properties.inc
+ * Implementations of hook_form_builder_properties in separate functions.
+ */
+
+/**
+ * Configuration form for the "key" property.
+ *
+ * The key property is special in that it's not actually part of the element,
+ * but instead the array key that is used to reference the element in the
+ * Form API structure.
+ */
+function form_builder_property_key_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['key'] = array(
+    '#title' => t('Form key'),
+    '#type' => 'textfield',
+    '#default_value' => $element['#key'],
+    '#required' => TRUE,
+    '#weight' => -9,
+    '#element_validate' => array('form_builder_property_key_form_validate'),
+  );
+
+  return $form;
+}
+
+/**
+ * Element validate function for the "key" property. Ensure safe characters.
+ */
+function form_builder_property_key_form_validate($element, $form_state) {
+  if (!preg_match('/^[a-z0-9_]+$/', $element['#value'])) {
+    form_error($element, t('The form key may only contain lowercase alphanumeric characters and underscores.'));
+  }
+}
+
+/**
+ * Configuration form for the "title" property.
+ */
+function form_builder_property_title_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['title'] = array(
+    '#title' => t('Title'),
+    '#type' => 'textfield',
+    '#default_value' => $element['#title'],
+    '#required' => TRUE,
+    '#weight' => -10,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "title_display" property.
+ */
+function form_builder_property_title_display_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['title_display'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#title' => t('Title display'),
+    '#type' => 'select',
+    '#default_value' => $element['#title_display'],
+    '#options' => array(
+      'before' => t('Before'),
+      'after' => t('After'),
+      'invisible' => t('Invisible'),
+      'attribute' => t('Attribute'),
+    ),
+    '#required' => TRUE,
+    '#weight' => -10,
+  );
+
+  return $form;
+}
+
+
+/**
+ * Configuration form for the "weight" property.
+ *
+ * This field is in the "hidden" builder group, meaning it's never shown in
+ * the main editing interface. However, it's still there if editing without JS.
+ */
+function form_builder_property_weight_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  if (!isset($_REQUEST['js'])) {
+    $form['weight'] = array(
+      '#form_builder' => array('property_group' => 'hidden'),
+      '#type' => 'textfield',
+      '#size' => 6,
+      '#title' => t('Weight'),
+      '#default_value' => $element['#weight'],
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "description" property.
+ */
+function form_builder_property_description_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['description'] = array(
+    '#title' => t('Description'),
+    '#type' => 'textarea',
+    '#default_value' => $element['#description'],
+    '#weight' => 5,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "required" property.
+ */
+function form_builder_property_required_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['required'] = array(
+    '#form_builder' => array('property_group' => 'validation'),
+    '#title' => t('Required'),
+    '#type' => 'checkbox',
+    '#default_value' => $element['#required'],
+    '#weight' => -1,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "options" property.
+ */
+function form_builder_property_options_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  // Checkboxes have an implied "multiple" property.
+  if ($element['#type'] == 'checkboxes') {
+    $element['#multiple'] = TRUE;
+  }
+
+  $form['options'] = array(
+    '#form_builder' => array('property_group' => 'options'),
+    '#title' => t('Options'),
+    '#type' => 'options',
+    '#default_value' => $element['#default_value'],
+    '#options' => $element['#options'],
+    '#required' => TRUE,
+    '#multiple' => isset($element['#multiple']) ? $element['#multiple'] : FALSE,
+    '#multiple_toggle' => isset($element['#multiple_toggle']) ? $element['#multiple_toggle'] : FALSE,
+    '#optgroups' => $element['#type'] == 'select' ? TRUE : FALSE,
+    '#limit' => 100,
+    '#key_type' => isset($element['#key_type']) ? $element['#key_type'] : 'mixed',
+    '#key_type_toggle' => isset($element['#key_type_toggle']) ? $element['#key_type_toggle'] : TRUE,
+    '#key_type_toggled' => isset($element['#key_type_toggled']) ? $element['#key_type_toggled'] : FALSE,
+  );
+
+  // Remove the default value field, since it's handled by the options field.
+  $form['default_value'] = array();
+
+  return $form;
+}
+
+function form_builder_property_options_form_submit(&$form, &$form_state) {
+  $options = $form_state['values']['options']['options'];
+  $default_value = $form_state['values']['options']['default_value'];
+
+  if (isset($form_state['values']['options']['multiple'])) {
+    $multiple = $form_state['values']['options']['multiple'];
+    $form_state['values']['multiple'] = $multiple;
+  }
+
+  if (isset($form_state['values']['options']['custom_keys'])) {
+    $form_state['values']['key_type_toggled'] = $form_state['values']['options']['custom_keys'];
+  }
+
+  $form_state['values']['options'] = $options;
+  $form_state['values']['default_value'] = $default_value;
+}
+
+/**
+ * Configuration form for the "default_value" property.
+ */
+function form_builder_property_default_value_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['default_value'] = array(
+    // Most fields have default values that can be stored on one line, so we
+    // use a textfield to configure their default value. Textareas are an
+    // exception, though.
+    '#type' => $element['#type'] == 'textarea' ? 'textarea' : 'textfield',
+    '#title' => t('Default value'),
+    '#default_value' => $element['#default_value'],
+    '#weight' => 1,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "markup" property.
+ */
+function form_builder_property_markup_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  // TODO: This is a placeholder until "#markup" becomes available in D7.
+  $form['markup'] = array(
+    '#type' => 'text_format',
+    '#title' => t('Markup'),
+    '#default_value' => $element['#markup'],
+    '#format' => isset($element['#format']) ? $element['#format'] : NULL,
+    '#weight' => 1,
+  );
+
+  return $form;
+}
+
+/**
+ * Submit handler for the "markup" property.
+ */
+function form_builder_property_markup_form_submit(&$form, &$form_state) {
+  // The submitted data from an element of type 'text_format' is an array that
+  // contains the text and its format in separate keys. We want these to wind
+  // up in #markup and #format, respectively.
+  $markup_array = $form_state['values']['markup'];
+  $form_state['values']['markup'] = $markup_array['value'];
+  $form_state['values']['format'] = $markup_array['format'];
+}
+
+/**
+ * Configuration form for the "size" property.
+ */
+function form_builder_property_size_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['size'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#title' => t('Size'),
+    '#default_value' => $element['#size'],
+    '#weight' => 2,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "rows" property.
+ */
+function form_builder_property_rows_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['rows'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#title' => t('Rows'),
+    '#default_value' => $element['#rows'],
+    '#weight' => 2,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "cols" property.
+ */
+function form_builder_property_cols_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['cols'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#title' => t('Columns'),
+    '#default_value' => $element['#cols'],
+    '#weight' => 3,
+    '#description' => t('The width of the textarea. This property might not have a visual impact depending on the CSS of your site.'),
+  );
+
+  return $form;
+}
+
+
+/**
+ * Configuration form for the "field_prefix" property.
+ */
+function form_builder_property_field_prefix_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['field_prefix'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'textfield',
+    '#title' => t('Prefix'),
+    '#default_value' => $element['#field_prefix'],
+    '#weight' => -2,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "field_suffix" property.
+ */
+function form_builder_property_field_suffix_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['field_suffix'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'textfield',
+    '#title' => t('Suffix'),
+    '#default_value' => $element['#field_suffix'],
+    '#weight' => -1,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "collapsible" property.
+ */
+function form_builder_property_collapsible_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['collapsible'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'checkbox',
+    '#title' => t('Collapsible'),
+    '#default_value' => $element['#collapsible'],
+    '#weight' => -2,
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "collapsed" property.
+ */
+function form_builder_property_collapsed_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['collapsed'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#type' => 'checkbox',
+    '#title' => t('Collapsed'),
+    '#default_value' => $element['#collapsed'],
+    '#weight' => -1,
+    '#description' => t('This property will not affect the preview immediately.'),
+  );
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/modules/menu.inc b/sites/all/modules/form_builder/modules/menu.inc
new file mode 100644
index 00000000..44c09907
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/menu.inc
@@ -0,0 +1,197 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for menu.module.
+ */
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function menu_form_builder_types() {
+  $fields = array();
+
+  // Make a default menu item to pass into the menu form.
+  $item = array(
+    'mlid' => 0,
+    'plid' => 0,
+    'weight' => 0,
+    'link_title' => '',
+    'module' => '',
+    'hidden' => NULL,
+    'has_children' => NULL,
+    'customized' => NULL, 
+    'options' => NULL,
+    'expanded' => NULL,
+    'parent_depth_limit' => NULL,
+    'menu_name' => NULL,
+  );
+  $default_settings = module_invoke('menu', 'node_form_default_settings');
+
+  $fields['menu_settings'] = array(
+    'title' => t('Menu'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+    ),
+    'default' => menu_fieldset($item, $default_settings['menu']),
+    'unique' => TRUE,
+    'configurable' => TRUE,
+    'removable' => TRUE,
+    'palette_group' => 'special',
+  );
+
+  return array(
+    'node' => $fields,
+    'example' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_load_alter().
+ */
+function menu_form_builder_load_alter(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $menu_settings = node_get_form_settings($form_id, 'menu');
+
+    if ($menu_settings['enabled']) {
+      $form['menu'] = menu_fieldset($form['#node']->menu, $menu_settings);
+      $form['menu']['#form_builder'] = array(
+        'element_id' => 'menu_settings',
+        'element_type' => 'menu_settings',
+      );
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function menu_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $node_type = $form_id;
+    $element = form_builder_get_element($form, 'menu_settings');
+    if ($element) {
+      $settings = array(
+        'enabled' => TRUE,
+        'collapsible' => !empty($element['#collapsible']),
+        'collapsed' => !empty($element['#collapsible']) && !empty($element['#collapsed']),
+        'weight' => $element['#weight'],
+      );
+    }
+    else {
+      $settings = array(
+        'enabled' => FALSE,
+      );
+    }
+    node_set_form_settings($node_type, 'menu', 'menu', $settings);
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into menu_form_alter().
+ */
+function menu_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the menu form item based on the menu node form settings.
+  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
+    $settings = node_get_form_settings($form['#node']->type, 'menu');
+    if ($settings['enabled']) {
+      $form['menu']['#collapsible'] = $settings['collapsible'];
+      $form['menu']['#collapsed'] = $settings['collapsed'];
+      $form['menu']['#weight'] = $settings['weight'];
+    }
+    else {
+      $form['menu']['#access'] = FALSE;
+    }
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ *
+ * Get the default settings for the menu modifications to the node form.
+ */
+function menu_node_form_default_settings($node_type = NULL) {
+  $defaults = array();
+  $defaults['menu'] = array(
+    'enabled' => TRUE,
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'weight' => -2,
+  );
+  return $defaults;
+}
+
+/**
+ * A straight copy/paste of menu_form_alter(). Get the menu node form.
+ *
+ * @param $item
+ *   The contents of $node->menu.
+ * @param $menu_settings
+ *   Settings for the menu form.
+ *
+ * @todo Put this function directly in menu.module, abstracting it from
+ * menu_form_alter().
+ */
+function menu_fieldset($item, $menu_settings = array()) {
+  $form = array(
+    '#type' => 'fieldset',
+    '#title' => t('Menu settings'),
+    '#access' => user_access('administer menu'),
+    '#collapsible' => $menu_settings['collapsible'],
+    '#collapsed' => $menu_settings['collapsible'],
+    '#tree' => TRUE,
+    '#attributes' => array('class' => 'menu-item-form'),
+    '#weight' => $menu_settings['weight'],
+  );
+
+  if ($item['mlid']) {
+    // There is an existing link.
+    $form['delete'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Delete this menu item.'),
+    );
+  }
+  if (!$item['link_title']) {
+    $form['#collapsed'] = TRUE;
+  }
+
+  foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
+    $form[$key] = array('#type' => 'value', '#value' => $item[$key]);
+  }
+  $form['#item'] = $item;
+
+  $form['link_title'] = array('#type' => 'textfield',
+    '#title' => t('Menu link title'),
+    '#default_value' => $item['link_title'],
+    '#description' => t('The link text corresponding to this item that should appear in the menu. Leave blank if you do not wish to add this post to the menu.'),
+    '#required' => FALSE,
+  );
+  // Generate a list of possible parents (not including this item or descendants).
+  $options = menu_parent_options(menu_get_menus(), $item);
+  $default = $item['menu_name'] .':'. $item['plid'];
+  if (!isset($options[$default])) {
+    $default = 'primary-links:0';
+  }
+  $form['parent'] = array(
+    '#type' => 'select',
+    '#title' => t('Parent item'),
+    '#default_value' => $default,
+    '#options' => $options,
+    '#description' => t('The maximum depth for an item and all its children is fixed at !maxdepth. Some menu items may not be available as parents if selecting them would exceed this limit.', array('!maxdepth' => MENU_MAX_DEPTH)),
+    '#attributes' => array('class' => 'menu-title-select'),
+  );
+  $form['#submit'][] = 'menu_node_form_submit';
+
+  $form['weight'] = array(
+    '#type' => 'weight',
+    '#title' => t('Weight'),
+    '#delta' => 50,
+    '#default_value' => $item['weight'],
+    '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
+  );
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/modules/node.inc b/sites/all/modules/form_builder/modules/node.inc
new file mode 100644
index 00000000..4c4d3ce6
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/node.inc
@@ -0,0 +1,892 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for node.module.
+ */
+
+/**
+ * Main page for editing a content type form.
+ *
+ * @param $type
+ *   The content type object being edited.
+ */
+function node_form_edit($type) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
+
+  // TODO: These should be auto-loaded as necessary.
+  drupal_add_js('misc/autocomplete.js');
+  drupal_add_js('misc/collapse.js');
+  drupal_add_js('misc/tableheader.js');
+  drupal_add_js('misc/textarea.js');
+
+  drupal_set_message(t('This is a form preview. Click on a field to edit its properties.'), 'warning');
+
+  $output = array();
+  $output[] = form_builder_interface('node', $type->type);
+  $output[] = drupal_get_form('node_form_builder_save_form', $type);
+  return $output;
+}
+
+/**
+ * Form for saving Form Builder changes.
+ */
+function node_form_builder_save_form($form_state, $type, $review = FALSE) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+
+  $form = array();
+
+  if ($review) {
+    // Allow modules to review dangerous changes before continuing.
+    $differences = form_builder_cache_difference('node', $type->type);
+    if ($differences !== FALSE) {
+      $form['warnings'] = array(
+        '#tree' => TRUE,
+      );
+
+      if (empty($form_state['post'])) {
+        drupal_set_message(t('Please review your changes before saving.'));
+      }
+
+      $changed_fields = array();
+      foreach ($differences as $difference) {
+        $field_name = isset($difference['original']['#title']) ? $difference['original']['#title'] : $difference['original']['#form_builder']['element_id'];
+        if (empty($difference['original'])) {
+          $field_name = isset($difference['modified']['#title']) ? $difference['modified']['#title'] : $difference['modified']['#form_builder']['element_id'];
+          $changed_fields[] = $field_name . ' - <strong>' . t('Added') . '</strong>';
+        }
+        elseif (empty($difference['modified'])) {
+          $changed_fields[] = $field_name . ' - <strong>' . t('Removed') . '</strong>';
+        }
+        else {
+          $changed_fields[] = $field_name . ' - <strong>' . t('Modified') . '</strong>';
+        }
+      }
+
+      $form['changed'] = array(
+        '#type' => 'markup',
+        '#value' => theme('item_list', $changed_fields),
+      );
+
+      foreach ($differences as $difference) {
+        $element_id = $difference['original']['#form_builder']['element_id'];
+        $correction_form = module_invoke_all('form_builder_correction_form', $form_state, 'node', $type->type, $element_id, $difference['original'], $difference['modified']);
+        if (!empty($correction_form)) {
+          $form['warnings'][$element_id] = $correction_form;
+        }
+      }
+
+      $form['offline'] = array(
+        '#title' => t('Site status'),
+        '#type' => 'radios',
+        '#options' => array(
+          '0' => t('Leave site online'),
+          '1' => t('Temporarily take site offline'),
+        ),
+        '#default_value' => '0',
+        '#description' => t('For large sets of changes, it is recommended that you temporarily disable access to your site while data is being saved. After changes are complete, the site will be turned back online. You can change the site status manually be visiting <a href="!url">Site maintenance</a>.', array('!url' => url('admin/settings/site-maintenance'))),
+        '#access' => variable_get('site_offline', '0') == '0',
+      );
+
+      $form['buttons']['cancel'] = array(
+        '#type' => 'markup',
+        '#value' => l('Cancel', 'admin/build/node-type/' . str_replace('_', '-', $type->type) . '/fields'),
+      );
+
+      $form['reviewed'] = array(
+        '#type' => 'value',
+        '#value' => TRUE,
+      );
+    }
+    else {
+      drupal_not_found();
+      exit;
+    }
+  }
+
+  $form['type'] = array(
+    '#type' => 'value',
+    '#value' => $type,
+  );
+
+  $form['buttons']['#weight'] = 100;
+
+  $form['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => -1,
+  );
+
+  return $form;
+}
+
+/**
+ * Submit handler for saving changes to the node form.
+ */
+function node_form_builder_save_form_submit(&$form, &$form_state) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
+  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
+  $type = $form_state['values']['type'];
+
+  if (!isset($form_state['values']['reviewed'])) {
+    $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_', '-', $type->type) .'/fields/confirm';
+    return;
+  }
+
+  // Disable access to the site.
+  if ($form_state['values']['offline'] == '1') {
+    variable_set('site_offline', '1');
+  }
+
+  $node_form = form_builder_cache_load('node', $type->type);
+  form_builder_save_form($node_form, 'node', $type->type);
+
+  // Re-enable access to the site.
+  if ($form_state['values']['offline'] == '1') {
+    variable_set('site_offline', '0');
+  }
+
+  drupal_set_message(t('The changes to the %type content type form have been saved.', array('%type' => $type->name)));
+  $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_', '-', $type->type);
+
+}
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function node_form_builder_types() {
+  global $user;
+
+  module_load_include('inc', 'node', 'node.pages');
+
+  $fields = array();
+
+  $node = array(
+    'uid' => $user->uid,
+    'created' => 280321200, // 19 Nov 1978 05:00:00.
+    'date' => format_date(280321200, 'custom', 'Y-m-d H:i:s O'),
+    'body' => NULL,
+    'title' => NULL,
+    'format' => NULL,
+  );
+  $settings = module_invoke('node', 'node_form_default_settings');
+
+  $node['status'] = $settings['options']['status'];
+  $node['promote'] = $settings['options']['promote'];
+  $node['sticky'] = $settings['options']['sticky'];
+
+  $node = (object) $node;
+
+  $title_form = node_title_field($node, $settings['title']);
+  $title_form['#weight'] = $settings['title']['weight'];
+  $fields['title'] = array(
+    'title' => t('Title'),
+    'properties' => array(
+      'title',
+    ),
+    'default' => $title_form,
+    'unique' => TRUE,
+    'removable' => FALSE,
+    'palette_group' => 'special',
+  );
+
+  /*$body_form = node_body_field($node, $settings['body_field']['label'], $settings['body_field']['min_word_count']);
+  $body_form['#weight'] = $settings['body_field']['weight'];
+  $body_form['#body_settings'] = $settings['body_field'];
+  $fields['body_field'] = array(
+    'title' => t('Body'),
+    'properties' => array(
+      'body_settings',
+    ),
+    'default' => $body_form,
+    'unique' => TRUE,
+    'palette_group' => 'special',
+  );*/
+
+  $revision_fieldset = node_revision_fieldset($node, $settings['revision_information']);
+  $revision_fieldset['#weight'] = $settings['revision_information']['weight'];
+  $revision_fieldset['#revision_settings'] = $settings['revision_information'];
+  $fields['revision_information'] = array(
+    'title' => t('Revisions'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+      'revision_settings',
+    ),
+    'default' => $revision_fieldset,
+    'unique' => TRUE,
+    'palette_group' => 'special',
+  );
+
+  $author_fieldset = node_author_fieldset($node, $settings['author']);
+  $author_fieldset['#author_settings'] = $settings['author'];
+  $author_fieldset['#weight'] = $settings['author']['weight'];
+  $author_fieldset['#form_builder']['removable'] = FALSE;
+  $fields['author'] = array(
+    'title' => t('Authoring'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+    ),
+    'default' => $author_fieldset,
+    'unique' => TRUE,
+    'removable' => FALSE,
+    'palette_group' => 'special',
+  );
+
+  $options_fieldset = node_options_fieldset($node, $settings['options']);
+  $options_fieldset['#options_settings'] = $settings['options'];
+  $options_fieldset['#weight'] = $settings['options']['weight'];
+  $options_fieldset['#form_builder']['removable'] = FALSE;
+  $fields['options'] = array(
+    'title' => t('Options'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+      'options_settings',
+    ),
+    'default' => $options_fieldset,
+    'unique' => TRUE,
+    'removable' => FALSE,
+    'palette_group' => 'special',
+  );
+
+  // Generic field for handling weights.
+  $fields['generic_field'] = array(
+    'title' => t('Generic field'),
+    'properties' => array(),
+    'removable' => FALSE,
+    'configurable' => FALSE,
+  );
+
+  return array(
+    'node' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_properties().
+ */
+function node_form_builder_properties($form_type) {
+  if ($form_type == 'node') {
+    return array(
+      'body_settings' => array(
+        'form' => 'node_body_settings_form',
+        'submit' => array('node_body_settings_form_submit'),
+      ),
+      'revision_settings' => array(
+        'form' => 'node_revision_settings_form',
+      ),
+      'options_settings' => array(
+        'form' => 'node_options_settings_form',
+      ),
+    );
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_preview_alter().
+ *
+ * Update the custom node fields according to the changed node type settings.
+ */
+function node_form_builder_preview_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    switch ($element['#form_builder']['element_id']) {
+      case 'title':
+        // No node title settings yet.
+        break;
+      case 'body_field':
+        $element['body']['#title'] = check_plain($element['#body_settings']['label']);
+        $element['body']['#required'] = $element['#body_settings']['min_word_count'] > 0;
+        break;
+      case 'revision_information':
+        $element['revision']['#default_value'] = $element['#revision_settings']['revision'];
+        break;
+      case 'author':
+        // No node author settings yet.
+        break;
+      case 'options':
+        $element['status']['#default_value'] = $element['#options_settings']['status'];
+        $element['promote']['#default_value'] = $element['#options_settings']['promote'];
+        $element['sticky']['#default_value'] = $element['#options_settings']['sticky'];
+        break;
+    }
+  }
+}
+
+/**
+ * Configuration form for the "body_settings" property.
+ */
+function node_body_settings_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['label'] = array(
+    '#title' => t('Title'),
+    '#type' => 'textfield',
+    '#parents' => array('body_settings', 'label'),
+    '#default_value' => $element['#body_settings']['label'],
+    '#required' => TRUE,
+    '#weight' => -10,
+  );
+
+  $form['min_word_count'] = array(
+    '#form_builder' => array('property_group' => 'validation'),
+    // Manually set parents since we need this to be in the validation group.
+    '#parents' => array('body_settings', 'min_word_count'),
+    '#type' => 'select',
+    '#title' => t('Minimum number of words'),
+    '#default_value' => $element['#body_settings']['min_word_count'],
+    '#options' => drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150, 175, 200)),
+    '#description' => t('The minimum number of words for the body field to be considered valid for this content type. This can be useful to rule out submissions that do not meet the site\'s standards, such as short test posts.')
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "revision_settings" property.
+ */
+function node_revision_settings_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['revision_settings']['revision'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Create new revision by default'),
+    '#parents' => array('revision_settings', 'revision'),
+    '#default_value' => $element['#revision_settings']['revision'],
+  );
+
+  return $form;
+}
+
+/**
+ * Configuration form for the "options_settings" property.
+ */
+function node_options_settings_form(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $form['status'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Published by default'),
+    '#parents' => array('options_settings', 'status'),
+    '#default_value' => $element['#options_settings']['status'],
+  );
+
+  $form['promote'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Promoted by default'),
+    '#parents' => array('options_settings', 'promote'),
+    '#default_value' => $element['#options_settings']['promote'],
+  );
+
+  $form['sticky'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Sticky by default'),
+    '#parents' => array('options_settings', 'sticky'),
+    '#default_value' => $element['#options_settings']['sticky'],
+  );
+
+  return $form;
+}
+
+/**
+ * Implementation of hook_form_builder_load().
+ */
+function node_form_builder_load($form_type, $form_id) {
+  global $user;
+
+  module_load_include('inc', 'node', 'node.pages');
+
+  if ($form_type == 'node') {
+    $form_state = array('submitted' => FALSE);
+    $node_type = $form_id;
+
+    $node = array(
+      'uid' => $user->uid,
+      'created' => 280321200, // 19 Nov 1978 05:00:00.
+      'date' => format_date(280321200, 'custom', 'Y-m-d H:i:s O'),
+      'name' => (isset($user->name) ? $user->name : ''),
+      'type' => $node_type,
+      'language' => '',
+    );
+    $form = node_form($form_state, $node);
+
+    // Setup generic weight handling.
+    drupal_prepare_form($form_id .'_node_form', $form, $form_state);
+    $form['#node_generic_fields'] = array();
+    foreach (element_children($form) as $key) {
+      $element = $form[$key];
+      if (!isset($element['#form_builder']) && (!empty($element['#tree']) || (isset($element['#type']) && !in_array($element['#type'], array('value', 'hidden', 'markup', 'token', 'button', 'submit', 'vertical_tabs', 'horizontal_tabs'))))) {
+        $form[$key]['#form_builder'] = array(
+          'element_id' => $key,
+          'element_type' => 'generic_field',
+        );
+        $form['#node_generic_fields'][] = $key;
+      }
+    }
+
+    if (isset($form['title'])) {
+      $title_settings = node_get_form_settings($node_type, 'title');
+      $form['title']['#title_settings'] = $title_settings;
+      $form['title']['#weight'] = $title_settings['weight'];
+      $form['title']['#form_builder'] = array(
+        'element_id' => 'title',
+        'element_type' => 'title',
+      );
+    }
+
+    if (isset($form['body_field'])) {
+      $body_settings = node_get_form_settings($node_type, 'body_field');
+      $form['body_field']['#body_settings'] = $body_settings;
+      $form['body_field']['#weight'] = $body_settings['weight'];
+      $form['body_field']['#form_builder'] = array(
+        'element_id' => 'body_field',
+        'element_type' => 'body_field',
+      );
+    }
+
+    $revision_settings = node_get_form_settings($node_type, 'revision_information');
+    if ($revision_settings['enabled']) {
+      $form['revision_information'] = node_revision_fieldset($form['#node'], $revision_settings);
+      $form['revision_information']['#revision_settings'] = $revision_settings;
+      $form['revision_information']['#form_builder'] = array(
+        'element_id' => 'revision_information',
+        'element_type' => 'revision_information',
+      );
+    }
+    else {
+      unset($form['revision_information']);
+    }
+
+    $options_settings = node_get_form_settings($node_type, 'options');
+    $form['options'] = node_options_fieldset($form['#node'], $options_settings);
+    $form['options']['#options_settings'] = $options_settings;
+    $form['options']['#form_builder'] = array(
+      'element_id' => 'options',
+      'element_type' => 'options',
+    );
+
+    $author_settings = node_get_form_settings($node_type, 'author');
+    $form['author'] = node_author_fieldset($form['#node'], $author_settings);
+    $form['author']['#author_settings'] = $author_settings;
+    $form['author']['#form_builder'] = array(
+      'element_id' => 'author',
+      'element_type' => 'author',
+    );
+
+    unset($form['buttons']);
+
+    return $form;
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function node_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $node_type = $form_id;
+
+    $node_element_ids = array(
+      'title' => 'title',
+      'body' => 'body_field',
+      'revision' => 'revision_information',
+      'options' => 'options',
+      'author' => 'author',
+    );
+    $node_elements = form_builder_get_elements($form, $node_element_ids);
+
+    foreach ($node_element_ids as $key => $element_id) {
+      $settings = node_get_form_settings($node_type, $element_id);
+      if (!isset($node_elements[$element_id])) {
+        $settings['enabled'] = FALSE;
+      }
+      else {
+        // Merge most settings from the #settings property.
+        foreach ($node_elements[$element_id]['#' . $key . '_settings'] as $setting_key => $setting) {
+          $settings[$setting_key] = $setting;
+        }
+        // If the field exists, it is enabled.
+        $settings['enabled'] = TRUE;
+        // Set the weight from the #weight property.
+        $settings['weight'] = $node_elements[$element_id]['#weight'];
+        // The title label is just the plain title attribute.
+        if ($element_id == 'title') {
+          $settings['label'] = $node_elements[$element_id]['#title'];
+        }
+        // Update settings if a fieldset.
+        if (isset($node_elements[$element_id]['#type']) && $node_elements[$element_id]['#type'] == 'fieldset') {
+          $settings['collapsible'] = !empty($node_elements[$element_id]['#collapsible']);
+          $settings['collapsed'] = !empty($node_elements[$element_id]['#collapsed']);
+        }
+      }
+
+      // Update the settings for this field.
+      node_set_form_settings($node_type, $element_id, 'node', $settings);
+    }
+
+    $generic_field_ids = $form['#node_generic_fields'];
+    $generic_fields = form_builder_get_elements($form, $generic_field_ids);
+    foreach ($generic_fields as $key => $field) {
+      if ($field['#form_builder']['element_type'] == 'generic_field') {
+        $settings = array(
+          'weight' => $field['#weight'],
+        );
+        node_set_form_settings($node_type, $key, 'node', $settings);
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into node_form().
+ */
+function node_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the node form based on the node form settings.
+  if (preg_match('/_node_form$/', $form_id)) {
+    $type = $form['#node']->type;
+    $settings = node_get_form_settings($type);
+
+    $fields = array(
+      'title',
+      'body_field',
+      'revision_information',
+      'author',
+      'options',
+    );
+
+    foreach ($fields as $key) {
+      if (isset($settings[$key]['enabled']) && !$settings[$key]['enabled']) {
+        $form[$key]['#access'] = FALSE;
+      }
+      else {
+        switch ($key) {
+          case 'title':
+            $form[$key] = node_title_field($form['#node'], $settings[$key]);
+            break;
+          case 'revision_information':
+            $form['revision_information'] = node_revision_fieldset($form['#node'], $settings[$key]);
+            break;
+          case 'author':
+            $form[$key] = node_author_fieldset($form['#node'], $settings[$key]);
+            break;
+          case 'options':
+            $form[$key] = node_options_fieldset($form['#node'], $settings[$key]);
+            break;
+        }
+      }
+    }
+
+    // Set generic weights for any field controlled by node module.
+    foreach ($settings as $key => $field_settings) {
+      if (isset($form[$key]) && $field_settings['module'] == 'node') {
+        $form[$key]['#weight'] = $field_settings['weight'];
+      }
+    }
+  }
+}
+
+/**
+ * A copy/paste out of node_content_form(). The title field.
+ */
+function node_title_field($node, $title_settings) {
+  return array(
+    '#type' => 'textfield',
+    '#title' => check_plain($title_settings['label']),
+    '#required' => TRUE,
+    '#default_value' => $node->title,
+    '#maxlength' => 255,
+    '#weight' => $title_settings['weight'],
+  );
+}
+
+/**
+ * A straight copy/paste of a segment of node_form(). The node revision form.
+ *
+ * @param $node
+ *   The node object being edited.
+ * @param $revision_settings
+ *   Settings specific to the revision fieldset.
+ *
+ * @todo Put this function directly in node.pages.inc, abstracting it from
+ * node_form().
+ */
+function node_revision_fieldset($node, $revision_settings) {
+  $form = array(
+    '#type' => 'fieldset',
+    '#title' => t('Revision information'),
+    '#collapsible' => TRUE,
+    // Collapsed by default when "Create new revision" is unchecked
+    '#collapsed' => $revision_settings['collapsed'],
+    '#weight' => $revision_settings['weight'],
+  );
+  $form['revision'] = array(
+    '#access' => user_access('administer nodes'),
+    '#type' => 'checkbox',
+    '#title' => t('Create new revision'),
+    '#default_value' => $revision_settings['revision'],
+  );
+  $form['log'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Log message'),
+    '#rows' => 2,
+    '#description' => t('An explanation of the additions or updates being made to help other authors understand your motivations.'),
+  );
+
+  return $form;
+}
+
+/**
+ * A straight copy/paste of a segment of node_form(). The authoring information form.
+ *
+ * @param $node
+ *   The node object being edited.
+ * @param $authoring_settings
+ *   Settings specific to the authoring information fieldset.
+ *
+ * @todo Put this function directly in node.pages.inc, abstracting it from
+ * node_form().
+ */
+function node_author_fieldset($node, $authoring_settings) {
+  $form = array(
+    '#type' => 'fieldset',
+    '#access' => user_access('administer nodes'),
+    '#title' => t('Authoring information'),
+    '#collapsible' => $authoring_settings['collapsible'],
+    '#collapsed' => $authoring_settings['collapsed'],
+    '#weight' => $authoring_settings['weight'],
+  );
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Authored by'),
+    '#maxlength' => 60,
+    '#autocomplete_path' => 'user/autocomplete',
+    '#default_value' => isset($node->name) ? $node->name : '',
+    '#weight' => -1,
+    '#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
+  );
+  $form['date'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Authored on'),
+    '#maxlength' => 25,
+    '#description' => t('Format: %time. Leave blank to use the time of form submission.', array('%time' => !empty($node->date) ? $node->date : format_date($node->created, 'custom', 'Y-m-d H:i:s O'))),
+  );
+
+  if (isset($node->date)) {
+    $form['date']['#default_value'] = $node->date;
+  }
+
+  return $form;
+}
+
+/**
+ * A straight copy/paste of a segment of node_form(). The publishing options form.
+ *
+ * @param $node
+ *   The node object being edited.
+ * @param $publishing_settings
+ *   Settings specific to the publishing options fieldset.
+ *
+ * @todo Put this function directly in node.pages.inc, abstracting it from
+ * node_form().
+ */
+function node_options_fieldset($node, $publishing_settings) {
+  $form = array(
+    '#type' => 'fieldset',
+    '#access' => user_access('administer nodes'),
+    '#title' => t('Publishing options'),
+    '#collapsible' => $publishing_settings['collapsible'],
+    '#collapsed' => $publishing_settings['collapsed'],
+    '#weight' => $publishing_settings['weight'],
+  );
+  $form['status'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Published'),
+    '#default_value' => $node->status,
+  );
+  $form['promote'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Promoted to front page'),
+    '#default_value' => $node->promote,
+  );
+  $form['sticky'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Sticky at top of lists'),
+    '#default_value' => $node->sticky,
+  );
+
+  return $form;
+}
+
+/**
+ * Retrieve node form settings for a particular field.
+ */
+function node_get_form_settings($node_type, $field = NULL, $reset = FALSE) {
+  static $form_settings = array();
+
+  if ($reset) {
+    $form_settings = array();
+    return;
+  }
+
+  if (!isset($form_settings[$node_type])) {
+    // Get settings from the node form settings table.
+    $form_settings[$node_type] = array();
+    $result = db_select('node_form_settings', 'nfs', array('fetch' => PDO::FETCH_ASSOC))
+      ->fields('nfs')
+      ->condition('nfs.type', $node_type)
+      ->execute();
+    foreach ($result as $settings) {
+      $form_settings[$node_type][$settings->field] = unserialize($settings->settings);
+      $form_settings[$node_type][$settings->field]['module'] = $settings->module;
+    }
+
+    // Get settings from the node type table.
+    $type = node_type_get_type($node_type);
+    $form_settings[$node_type]['title']['enabled'] = $type->has_title ? TRUE : FALSE;
+    $form_settings[$node_type]['title']['label'] = isset($type->title_label) ? $type->title_label : '';
+    $form_settings[$node_type]['body_field']['enabled'] = $type->has_body ? TRUE : FALSE;
+    $form_settings[$node_type]['body_field']['label'] = isset($type->body_label) ? $type->body_label : '';
+
+    // Merge default settings from modules.
+    foreach (module_implements('node_form_default_settings') as $module) {
+      $additional_settings = module_invoke($module, 'node_form_default_settings', $node_type);
+      if (!empty($additional_settings)) {
+        foreach ($additional_settings as $field_id => $field_settings) {
+          $form_settings[$node_type][$field_id]['module'] = $module;
+          if (isset($form_settings[$node_type][$field_id])) {
+            $form_settings[$node_type][$field_id] = array_merge($field_settings, $form_settings[$node_type][$field_id]);
+          }
+          else {
+            $form_settings[$node_type][$field_id] = $field_settings;
+          }
+        }
+      }
+    }
+  }
+
+  if (!isset($field)) {
+    return $form_settings[$node_type];
+  }
+  elseif (isset($form_settings[$node_type][$field])) {
+    return $form_settings[$node_type][$field];
+  }
+
+  return FALSE;
+}
+
+/**
+ * Set the node form settings for a particular field.
+ */
+function node_set_form_settings($node_type, $field, $module, $settings) {
+  $serialized_value = serialize($settings);
+  db_merge('node_form_settings')
+    ->key(array('type' => $node_type, 'field' => $field))
+    ->fields(array(
+      'settings' => $serialized_value,
+      'module' => $module
+    ))
+    ->execute();
+
+  // Special cases for node type settings.
+  if ($field == 'body_field') {
+    $type = node_type_get_type($node_type);
+    $type->has_body = $settings['enabled'];
+    $type->body_label = $settings['label'];
+    $type->min_word_count = $settings['min_word_count'];
+    node_type_save($type);
+    node_types_rebuild();
+    menu_rebuild();
+  }
+  if ($field == 'title') {
+    $type = node_type_get_type($node_type);
+    $type->has_title = $settings['enabled'];
+    $type->title_label = $settings['label'];
+    node_type_save($type);
+    node_types_rebuild();
+    menu_rebuild();
+  }
+
+  // Reset the static cache for the node form settings.
+  node_get_form_settings(NULL, NULL, TRUE);
+}
+
+/**
+ * Delete the node form settings for a node type, field, or module.
+ *
+ * All parameters all optional, but at least one must be specified to have any
+ * effect. Multiple parameters may be passed in to further narrow the settings
+ * that will be deleted.
+ *
+ * @param $node_type
+ *   Optional. String of the node type whose settings are to be deleted.
+ * @param $field
+ *   Optional. The key of the field whose setting will be deleted.
+ * @param $module
+ *   Options. Name of the module that provided the field settings to be deleted.
+ */
+function node_delete_form_settings($node_type = NULL, $field = NULL, $module = NULL) {
+  $delete = db_delete('node_form_settings');
+  if (isset($node_type)) {
+    $delete->condition('type', $node_type);
+  }
+  if (isset($field)) {
+    $delete->condition('field', $field);
+  }
+  if (isset($field)) {
+    // @todo: bogus conditional?
+    $delete->condition('module', $module);
+  }
+
+  if (isset($node_type) || isset($field)) {
+    // @todo: bogus conditional?
+    $delete->execute();
+
+    // Reset the static cache for the node form settings.
+    node_get_form_settings(NULL, NULL, TRUE);
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ */
+function node_node_form_default_settings() {
+  $defaults = array();
+
+  $defaults['title'] = array(
+    'enabled' => TRUE,
+    'label' => t('Title'),
+    'weight' => -5,
+  );
+  $defaults['body_field'] = array(
+    'enabled' => TRUE,
+    'label' => t('Body'),
+    'min_word_count' => 0,
+    'weight' => 0,
+  );
+  $defaults['revision_information'] = array(
+    'enabled' => TRUE,
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'weight' => 20,
+    'revision' => FALSE,
+  );
+  $defaults['author'] = array(
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'weight' => 21,
+  );
+  $defaults['options'] = array(
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'status' => 1,
+    'promote' => 0,
+    'sticky' => 0,
+    'weight' => 25,
+  );
+
+  return $defaults;
+}
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.info b/sites/all/modules/form_builder/modules/node/form_builder_node.info
new file mode 100644
index 00000000..9812dd84
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/node/form_builder_node.info
@@ -0,0 +1,11 @@
+name = Form builder Node UI
+description = Form builder enhancements for node module.
+core = 6.x
+dependencies[] = form_builder
+
+; Information added by drupal.org packaging script on 2011-06-06
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "form_builder"
+datestamp = "1307319364"
+
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.install b/sites/all/modules/form_builder/modules/node/form_builder_node.install
new file mode 100644
index 00000000..4419a037
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/node/form_builder_node.install
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ *   Add the node_settings_table to Drupal.
+ */
+
+/**
+ * Implementation of hook_schema().
+ */
+function form_builder_node_schema() {
+  $schema = array();
+
+  $schema['node_form_settings'] = array(
+    'fields' => array(
+      'type' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+      ),
+      'field' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'module' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'settings' => array(
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('type', 'field'),
+  );
+
+  return $schema;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function form_builder_node_install() {
+  db_update('system')
+    ->fields(array('weight' => 101))
+    ->condition('name', 'form_builder_node')
+    ->execute();
+}
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.module b/sites/all/modules/form_builder/modules/node/form_builder_node.module
new file mode 100644
index 00000000..3be9fe6e
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/node/form_builder_node.module
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ *   Placeholder Form Builder implementations for core.
+ */
+
+
+/**
+ * Implementation of hook_menu().
+ *
+ * Note: This would be merged into node_menu().
+ */
+function form_builder_node_menu() {
+  $items = array();
+
+  foreach (node_type_get_types('types') as $type) {
+    $type_url_str = str_replace('_', '-', $type->type);
+    $items['admin/build/node-type/'. $type_url_str .'/fields'] = array(
+      'title' => 'Fields',
+      'page callback' => 'node_form_edit',
+      'page arguments' => array($type),
+      'access arguments' => array('administer content types'),
+      'type' => MENU_LOCAL_TASK,
+    );
+    $items['admin/build/node-type/'. $type_url_str .'/fields/confirm'] = array(
+      'title' => 'Confirm field changes',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('node_form_builder_save_form', $type, TRUE),
+      'access arguments' => array('administer content types'),
+      'type' => MENU_CALLBACK,
+    );
+  }
+
+  return $items;
+}
+
+/**
+ * Implementation of hook_init().
+ *
+ * @todo Each one of these .inc files should be merged into their respective
+ * modules.
+ */
+function form_builder_node_init() {
+  // Pull in all the module include files.
+  $files = file_scan_directory(drupal_get_path('module', 'form_builder') . '/modules', '!^.*\.inc$!');
+  foreach ($files as $path => $file) {
+    include_once($path);
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Call the node-specific hook_form_alter() in each .inc file.
+ */
+function form_builder_node_form_alter(&$form, &$form_state, $form_id) {
+  foreach (module_implements('node_form_alter') as $module) {
+    // Prevent this function from calling itself recursively.
+    if ($module !== 'form_builder' && $module !== 'node') {
+      $function = $module . '_node_form_alter';
+      $function($form, $form_state, $form_id);
+    }
+  }
+
+  // Node must go last to set any necessary weights.
+  if (function_exists('node_node_form_alter')) {
+    node_node_form_alter($form, $form_state, $form_id);
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/form_builder/modules/path.inc b/sites/all/modules/form_builder/modules/path.inc
new file mode 100644
index 00000000..3a3e6ffe
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/path.inc
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for path.module.
+ */
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function path_form_builder_types() {
+  $fields = array();
+
+  // Make a default path settings to pass into the path form.
+  $settings = module_invoke('path', 'node_form_default_settings');
+
+  $fields['path_settings'] = array(
+    'title' => t('Path'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+    ),
+    'default' => path_fieldset('', $settings['path']),
+    'unique' => TRUE,
+    'removable' => TRUE,
+    'configurable' => TRUE,
+    'palette_group' => 'special',
+  );
+
+  return array(
+    'node' => $fields,
+    'example' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_load_alter().
+ */
+function path_form_builder_load_alter(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $settings = node_get_form_settings($form_id, 'path');
+    if ($settings['enabled']) {
+      $form['path'] = path_fieldset('', $settings);
+      $form['path']['#form_builder'] = array(
+        'element_id' => 'path_settings',
+        'element_type' => 'path_settings',
+      );
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function path_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $element = form_builder_get_element($form, 'path_settings');
+    $node_type = $form_id;
+
+    if ($element) {
+      $settings = array(
+        'enabled' => TRUE,
+        'collapsible' => $element['#collapsible'],
+        'collapsed' => $element['#collapsed'],
+        'weight' => $element['#weight'],
+      );
+    }
+    else {
+      $settings = array(
+        'enabled' => FALSE,
+      );
+    }
+
+    node_set_form_settings($form_id, 'path', 'path', $settings);
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into path_form_alter().
+ */
+function path_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the path form item based on the path node form settings.
+  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
+    $settings = node_get_form_settings($form['#node']->type, 'path');
+
+    if ($settings['enabled']) {
+      $path = isset($form['#node']->path) ? $form['#node']->path : '';
+      $form['path'] = path_fieldset($path, $settings);
+    }
+    else {
+      $form['path']['#access'] = FALSE;
+    }
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ *
+ * Get the settings for the path fieldset on the node form.
+ */
+function path_node_form_default_settings($type = NULL) {
+  $defaults = array();
+  $defaults['path'] = array(
+    'enabled' => TRUE,
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'weight' => 30,
+  );
+  return $defaults;
+}
+
+
+/**
+ * A straight copy/paste of path_form_alter(). Get the path node form.
+ *
+ * @param $path
+ *   The contents of $node->path.
+ * @param $path_settings
+ *   An array with configuring properties of the path fieldset.
+ *
+ * @todo Put this function directly in path.module, abstracting it from
+ * path_form_alter().
+ */
+function path_fieldset($path, $path_settings) {
+  $form = array(
+    '#type' => 'fieldset',
+    '#title' => t('URL path settings'),
+    '#collapsible' => $path_settings['collapsible'],
+    '#collapsed' => $path_settings['collapsed'],
+    '#access' => user_access('create url aliases'),
+    '#weight' => $path_settings['weight'],
+  );
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $path,
+    '#maxlength' => 250,
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
+  );
+  if ($path) {
+    $form['pid'] = array(
+      '#type' => 'value',
+      '#value' => db_query("SELECT pid FROM {url_alias} WHERE dst = :dst AND language = :language", array('path' => $path, 'language' => $form['#node']->language))->fetchField()
+    );
+  }
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/modules/poll.inc b/sites/all/modules/form_builder/modules/poll.inc
new file mode 100644
index 00000000..4354e331
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/poll.inc
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for poll.module.
+ *
+ *   Note this file doesn't actually do much of anything since node.inc
+ *   now handles generic weight handling. But poll-specific functionality
+ *   could be added here.
+ */
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function poll_form_builder_types() {
+  $fields = array();
+
+  $fields['poll_choices'] = array(
+    'title' => t('Menu'),
+    'properties' => array(),
+    'default' => array(),
+    'unique' => TRUE,
+    'configurable' => FALSE,
+    'removable' => FALSE,
+    'palette_group' => 'special',
+  );
+
+  $fields['poll_settings'] = array(
+    'title' => t('Menu'),
+    'properties' => array(),
+    'default' => array(),
+    'unique' => TRUE,
+    'configurable' => FALSE,
+    'removable' => FALSE,
+    'palette_group' => 'special',
+  );
+
+  return array(
+    'node' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_load_alter().
+ */
+function poll_form_builder_load_alter(&$form, $form_type, $form_id) {
+  if ($form_type == 'node' && $form_id == 'poll') {
+
+    $choice_settings = node_get_form_settings($form_id, 'poll_choices');
+    $form['choice_wrapper']['#weight'] = $choice_settings['weight'];
+    $form['choice_wrapper']['#form_builder'] = array(
+      'element_id' => 'poll_choices',
+      'element_type' => 'poll_choices',
+    );
+
+    $poll_settings = node_get_form_settings($form_id, 'poll_settings');
+    $form['settings']['#weight'] = $poll_settings['weight'];
+    $form['settings']['#form_builder'] = array(
+      'element_id' => 'poll_settings',
+      'element_type' => 'poll_settings',
+    );
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function poll_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $node_type = $form_id;
+
+    $element = form_builder_get_element($form, 'poll_choices');
+    $settings = array(
+      'weight' => $element['#weight'],
+    );
+    node_set_form_settings($node_type, 'poll_choices', 'poll', $settings);
+
+    $element = form_builder_get_element($form, 'poll_settings');
+    $settings = array(
+      'weight' => $element['#weight'],
+    );
+    node_set_form_settings($node_type, 'poll_settings', 'poll', $settings);
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into poll_form_alter().
+ */
+function poll_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the poll form item based on the poll node form settings.
+  if ($form_id == 'poll_node_form') {
+    $choice_settings = node_get_form_settings($form['#node']->type, 'poll_choices');
+    $poll_settings = node_get_form_settings($form['#node']->type, 'poll_settings');
+    $form['choice_wrapper']['#weight'] = $choice_settings['weight'];
+    $form['settings']['#weight'] = $poll_settings['weight'];
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ *
+ * Get the default settings for the poll modifications to the node form.
+ */
+function poll_node_form_default_settings($node_type = NULL) {
+  $defaults = array();
+  $defaults['poll_choices'] = array(
+    'weight' => -4,
+  );
+    $defaults['settings'] = array(
+    'weight' => -3,
+  );
+  return $defaults;
+}
diff --git a/sites/all/modules/form_builder/modules/taxonomy.inc b/sites/all/modules/form_builder/modules/taxonomy.inc
new file mode 100644
index 00000000..81dc88cf
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/taxonomy.inc
@@ -0,0 +1,256 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for taxonomy.module.
+ */
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function taxonomy_form_builder_types() {
+  $fields = array();
+
+  $vocabularies = taxonomy_get_vocabularies();
+  $terms = array();
+
+  // If no taxonomies are specified, do not allow the field to be added.
+  if (empty($vocabularies)) {
+    return array();
+  }
+
+  $first_vocab = reset($vocabularies);
+  $vocabularies = array($first_vocab->vid => $first_vocab);
+  $settings = module_invoke('taxonomy', 'node_form_default_settings');;
+  $default_form = taxonomy_fieldset($vocabularies, $terms, $settings['taxonomy']);
+  $default_form['#taxonomy_vocabularies'] = array_keys($vocabularies);
+
+  $fields['taxonomy'] = array(
+    'title' => t('Taxonomy'),
+    'properties' => array(
+      'taxonomy_vocabularies',
+    ),
+    'default' => $default_form,
+    'unique' => TRUE,
+    'palette_group' => 'special',
+  );
+
+  return array(
+    'node' => $fields,
+    'example' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_properties().
+ */
+function taxonomy_form_builder_properties($form_type) {
+  if ($form_type == 'node') {
+    return array(
+      'taxonomy_vocabularies' => array(
+        'form' => 'taxonomy_vocabularies_configuration',
+      ),
+    );
+  }
+}
+
+/**
+ * Form builder property form callback.
+ */
+function taxonomy_vocabularies_configuration(&$form_state, $form_type, $element) {
+  $form = array();
+
+  $vocabularies = taxonomy_get_vocabularies();
+  $options = array();
+  foreach ($vocabularies as $vid => $vocabulary) {
+    $options[$vid] = $vocabulary->name;
+  }
+
+  $form['taxonomy_vocabularies'] = array(
+    '#title' => t('Enabled vocabularies'),
+    '#type' => 'checkboxes',
+    '#default_value' => $element['#taxonomy_vocabularies'],
+    '#options' => $options,
+    '#required' => TRUE,
+    '#description' => t('Configure taxonomy element properties or add new vocabularies by visiting the <a href="!url">Taxonomy administration section</a>. If no vocabularies are desired for this form, remove the taxonomy element entirely.', array('!url' => url('admin/content/taxonomy'))),
+  );
+
+  return $form;
+}
+
+/**
+ * Implementation of hook_form_builder_preview_alter().
+ *
+ * Update the taxonomy element with the new vocabularies.
+ */
+function taxonomy_form_builder_preview_alter(&$element, $form_type, $form_id) {
+  if ($element['#form_builder']['element_id'] == 'taxonomy') {
+    // Remove current taxonomies from the element.
+    foreach (element_children($element) as $key) {
+      if (is_numeric($key)) {
+        unset($element[$key]);
+      }
+    }
+
+    $vocabularies = array_intersect_key(taxonomy_get_vocabularies(), array_flip($element['#taxonomy_vocabularies']));
+    $terms = array();
+    $settings = array(
+      'weight' => $element['#weight'],
+    );
+    $form = taxonomy_fieldset($vocabularies, $terms, $settings);
+    $element = array_merge($form, $element);
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_load_alter().
+ */
+function taxonomy_form_builder_load_alter(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $settings = node_get_form_settings($form_id, 'taxonomy');
+    $vocabularies = taxonomy_get_vocabularies($form['#node']->type);
+    $terms = isset($form['#node']->terms) ? $form['#node']->terms : array();
+
+    if (count($vocabularies)) {
+      $form['taxonomy'] = taxonomy_fieldset($vocabularies, $terms, $settings);
+      $form['taxonomy']['#form_builder'] = array(
+        'element_id' => 'taxonomy',
+        'element_type' => 'taxonomy',
+      );
+      $form['taxonomy']['#taxonomy_vocabularies'] = array_keys($vocabularies);
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into taxonomy_form_alter().
+ */
+function taxonomy_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the menu form item based on the menu node form settings.
+  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
+    if (isset($form['taxonomy'])) {
+      $settings = node_get_form_settings($form['#node']->type, 'taxonomy');
+      $form['taxonomy']['#weight'] = $settings['weight'];
+    }
+  }
+}
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function taxonomy_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $element = form_builder_get_element($form, 'taxonomy');
+    $vocabularies = taxonomy_get_vocabularies();
+    $node_type = $form_id;
+
+    if ($element) {
+      $settings = array('weight' => $element['#weight']);
+      variable_set('taxonomy_settings_' . $node_type, $settings);
+      $enabled_vocabularies = drupal_map_assoc($element['#taxonomy_vocabularies']);
+      foreach ($vocabularies as $vid => $vocabulary) {
+        $vocabulary = (array) $vocabulary;
+        if (isset($enabled_vocabularies[$vid]) && !isset($vocabular['nodes'][$node_type])) {
+          $vocabulary['nodes'][$node_type] = $node_type;
+          taxonomy_save_vocabulary($vocabulary);
+        }
+        elseif (!isset($enabled_vocabularies[$vid]) && isset($vocabulary['nodes'][$node_type])) {
+          unset($vocabulary['nodes'][$node_type]);
+          taxonomy_save_vocabulary($vocabulary);
+        }
+      }
+    }
+    else {
+      variable_del('taxonomy_settings_' . $node_type);
+      foreach ($vocabularies as $vid => $vocabulary) {
+        $vocabulary = (array) $vocabulary;
+        if (isset($vocabulary['nodes'][$node_type])) {
+          unset($vocabulary['nodes'][$node_type]);
+          taxonomy_save_vocabulary($vocabulary);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ *
+ * Get the settings for the taxonomy fieldset on the node form.
+ */
+function taxonomy_node_form_default_settings($type = NULL) {
+  $defaults = array();
+  $defaults['taxonomy'] = array(
+    'weight' => -3,
+  );
+  return $defaults;
+}
+
+/**
+ * A straight copy/paste of taxonomy_form_alter(). Get the taxonomy node form.
+ *
+ * @todo Put this function directly in taxonomy.module, abstracting it from
+ * taxonomy_form_alter().
+ */
+function taxonomy_fieldset($vocabularies, $terms, $settings) {
+  $form = array();
+
+  if (!variable_get('taxonomy_override_selector', FALSE)) {
+    foreach ($vocabularies as $vocabulary) {
+      if ($vocabulary->tags) {
+        if (isset($form_state['node_preview'])) {
+          // Typed string can be changed by the user before preview,
+          // so we just insert the tags directly as provided in the form.
+          $typed_string = $terms['tags'][$vocabulary->vid];
+        }
+        else {
+          $typed_string = taxonomy_implode_tags($terms, $vocabulary->vid) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
+        }
+        if ($vocabulary->help) {
+          $help = $vocabulary->help;
+        }
+        else {
+          $help = t('A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc.".');
+        }
+        $form['tags'][$vocabulary->vid] = array('#type' => 'textfield',
+          '#title' => $vocabulary->name,
+          '#description' => $help,
+          '#required' => $vocabulary->required,
+          '#default_value' => $typed_string,
+          '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid,
+          '#weight' => $vocabulary->weight,
+          '#maxlength' => 255,
+        );
+      }
+      else {
+        // Extract terms belonging to the vocabulary in question.
+        $default_terms = array();
+        foreach ($terms as $term) {
+          // Free tagging has no default terms and also no vid after preview.
+          if (isset($term->vid) && $term->vid == $vocabulary->vid) {
+            $default_terms[$term->tid] = $term;
+          }
+        }
+        $form[$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help);
+        $form[$vocabulary->vid]['#weight'] = $vocabulary->weight;
+        $form[$vocabulary->vid]['#required'] = $vocabulary->required;
+      }
+    }
+    if (!empty($form) && is_array($form)) {
+      if (count($form) > 1) {
+        // Add fieldset only if form has more than 1 element.
+        $form += array(
+          '#type' => 'fieldset',
+          '#title' => t('Vocabularies'),
+          '#collapsible' => TRUE,
+          '#collapsed' => FALSE,
+        );
+      }
+      $form['#weight'] = $settings['weight'];
+      $form['#tree'] = TRUE;
+    }
+  }
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/modules/upload.inc b/sites/all/modules/form_builder/modules/upload.inc
new file mode 100644
index 00000000..c22266f2
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/upload.inc
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * @file
+ *   Form builder implementation for upload.module.
+ */
+
+/**
+ * Implementation of hook_form_builder_types().
+ */
+function upload_form_builder_types() {
+  $fields = array();
+
+  // Make a pseudo node for the upload form.
+  $node = (object) array(
+    'type' => '',
+    'files' => array(),
+  );
+
+  // Make a default path settings to pass into the upload form.
+  $settings = module_invoke('upload', 'node_form_default_settings');
+
+  $fields['upload_settings'] = array(
+    'title' => t('Attachments'),
+    'properties' => array(
+      'collapsible',
+      'collapsed',
+    ),
+    'default' => upload_fieldset($node, $settings['attachments']),
+    'unique' => TRUE,
+    'removable' => TRUE,
+    'configurable' => TRUE,
+    'palette_group' => 'special',
+  );
+
+  return array(
+    'node' => $fields,
+    'example' => $fields,
+  );
+}
+
+/**
+ * Implementation of hook_form_builder_load_alter().
+ */
+function upload_form_builder_load_alter(&$form, $form_type, $form_id) {
+  if ($form_type == 'node' && isset($form['attachments'])) {
+    $form['attachments']['#form_builder'] = array(
+      'element_id' => 'upload_settings',
+      'element_type' => 'upload_settings',
+    );
+    // Unset the the attach button.
+    unset($form['attachments']['wrapper']['new']['attach']['#ahah']);
+    $form['attachments']['wrapper']['new']['attach']['#disabled'] = TRUE;
+  }
+}
+
+/**
+ * Implementation of hook_form_builder_save().
+ */
+function upload_form_builder_save(&$form, $form_type, $form_id) {
+  if ($form_type == 'node') {
+    $element = form_builder_get_element($form, 'upload_settings');
+    $node_type = $form_id;
+
+    if ($element) {
+      $settings = array(
+        'enabled' => TRUE,
+        'collapsible' => $element['#collapsible'],
+        'collapsed' => $element['#collapsed'],
+        'weight' => $element['#weight'],
+      );
+      variable_set('upload_' . $node_type, '1');
+    }
+    else {
+      $settings = array(
+        'enabled' => FALSE,
+      );
+      variable_set('upload_' . $node_type, '0');
+    }
+
+    node_set_form_settings($form_id, 'attachments', 'upload', $settings);
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * @todo Merge this into upload_form_alter().
+ */
+function upload_node_form_alter(&$form, &$form_state, $form_id) {
+  // Set properties of the path form item based on the path node form settings.
+  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
+    if (isset($form['attachments'])) {
+      $settings = node_get_form_settings($form['#node']->type, 'attachments');
+      $form['attachments']['#weight'] = $settings['weight'];
+      $form['attachments']['#collapsible'] = $settings['collapsible'];
+      $form['attachments']['#collapsed'] = $settings['collapsed'];
+    }
+  }
+}
+
+/**
+ * Implementation of hook_node_form_default_settings().
+ *
+ * Get the settings for the path fieldset on the node form.
+ */
+function upload_node_form_default_settings($type = NULL) {
+  $defaults = array();
+  $defaults['attachments'] = array(
+    'enabled' => TRUE,
+    'collapsible' => TRUE,
+    'collapsed' => TRUE,
+    'weight' => 30,
+  );
+  return $defaults;
+}
+
+
+/**
+ * A straight copy/paste of path_form_alter(). Get the path node form.
+ *
+ * @param $path
+ *   The contents of $node->path.
+ * @param $path_settings
+ *   An array with configuring properties of the path fieldset.
+ *
+ * @todo Put this function directly in path.module, abstracting it from
+ * path_form_alter().
+ */
+function upload_fieldset($node, $upload_settings) {
+  // Attachments fieldset
+  $form = array(
+    '#type' => 'fieldset',
+    '#access' => user_access('upload files'),
+    '#title' => t('File attachments'),
+    '#collapsible' => $upload_settings['collapsible'],
+    '#collapsed' => empty($node->files) && $upload_settings['collapsed'],
+    '#description' => t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.'),
+    '#prefix' => '<div class="attachments">',
+    '#suffix' => '</div>',
+    '#weight' => 30,
+  );
+
+  // Wrapper for fieldset contents (used by ahah.js).
+  $form['wrapper'] = array(
+    '#prefix' => '<div id="attach-wrapper">',
+    '#suffix' => '</div>',
+  );
+
+  // Make sure necessary directories for upload.module exist and are
+  // writable before displaying the attachment form.
+  $path = file_directory_path();
+  $temp = file_directory_temp();
+  // Note: pass by reference
+  if (!file_check_directory($path, FILE_CREATE_DIRECTORY) || !file_check_directory($temp, FILE_CREATE_DIRECTORY)) {
+    $form['#description'] =  t('File attachments are disabled. The file directories have not been properly configured.');
+    if (user_access('administer site configuration')) {
+      $form['#description'] .= ' '. t('Please visit the <a href="@admin-file-system">file system configuration page</a>.', array('@admin-file-system' => url('admin/settings/file-system')));
+    }
+    else {
+      $form['#description'] .= ' '. t('Please contact the site administrator.');
+    }
+  }
+  elseif (drupal_function_exists('_upload_form')) {
+    $form['wrapper'] += _upload_form($node);
+  }
+
+  return $form;
+}
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
new file mode 100644
index 00000000..aa00c8df
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
@@ -0,0 +1,1063 @@
+<?php
+
+/**
+ * @file
+ *   Default webform component callbacks for functionality related to the Form Builder.
+ */
+
+/**
+ * @defgroup form-builder-webform-date-callbacks Callbacks for the Date component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_date() {
+  $fields = array();
+
+  $fields['date'] = array(
+    'title' => t('Date'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'key',
+      'title_display',
+      // Date-specific properties.
+      'timezone',
+      'year_start',
+      'year_end',
+      'year_textfield',
+      'datepicker',
+    ),
+  );
+  $fields['date']['default'] = _form_builder_webform_default('date');
+  $fields['date']['default']['#title'] = t('New date');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_date() {
+  return array(
+    'timezone' => array(
+      'form' => 'form_builder_webform_property_date_timezone_form',
+    ),
+    'year_start' => array(
+      'form' => 'form_builder_webform_property_date_year_start_form',
+    ),
+    'year_end' => array(
+      'form' => 'form_builder_webform_property_date_year_end_form',
+    ),
+    'year_textfield' => array(
+      'form' => 'form_builder_webform_property_date_year_textfield_form',
+    ),
+    'datepicker' => array(
+      'form' => 'form_builder_webform_property_date_datepicker_form',
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_date($component, $form_element) {
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  $component['extra']['timezone'] = isset($form_element['#timezone']) ? $form_element['#timezone'] : 'user';
+  $component['extra']['year_start'] = isset($form_element['#year_start']) ? $form_element['#year_start'] : '-2';
+  $component['extra']['year_end'] = isset($form_element['#year_end']) ? $form_element['#year_end'] : '+2';
+  $component['extra']['year_textfield'] = isset($form_element['#year_textfield']) ? $form_element['#year_textfield'] : FALSE;
+  $component['extra']['datepicker'] = isset($form_element['#datepicker']) ? $form_element['#datepicker'] : FALSE;
+  return $component;
+}
+
+/**
+ * Configuration form for the "timezone" property.
+ */
+function form_builder_webform_property_date_timezone_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('date', $element, 'timezone', NULL, array('extra', 'timezone'), array('extra', 'timezone'));
+}
+
+/**
+ * Configuration form for the "year_start" property.
+ */
+function form_builder_webform_property_date_year_start_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('date', $element, 'year_start', 'validation', array('validation', 'year_start'), array('extra', 'year_start'));
+}
+
+/**
+ * Configuration form for the "year_end" property.
+ */
+function form_builder_webform_property_date_year_end_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('date', $element, 'year_end', 'validation', array('validation', 'year_end'), array('extra', 'year_end'));
+}
+
+/**
+ * Configuration form for the "year_textfield" property.
+ */
+function form_builder_webform_property_date_year_textfield_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('date', $element, 'year_textfield', 'display', array('display', 'year_textfield'), array('extra', 'year_textfield'));
+}
+
+/**
+ * Configuration form for the "datepicker" property.
+ */
+function form_builder_webform_property_date_datepicker_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('date', $element, 'datepicker', 'display', array('display', 'datepicker'), array('extra', 'datepicker'));
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-date-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-email-callbacks Callbacks for the Email component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_email() {
+  $fields = array();
+
+  $fields['email'] = array(
+    'title' => t('E-mail'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'size',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['email']['default'] = _form_builder_webform_default('email');
+  $fields['email']['default']['#title'] = t('New e-mail');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_email($component, $form_element) {
+  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-email-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-fieldset-callbacks Callbacks for the Fieldset component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_fieldset() {
+  $fields = array();
+
+  $fields['fieldset'] = array(
+    'title' => t('Fieldset'),
+    'properties' => array(
+      'title',
+      'description',
+      'collapsible',
+      'collapsed',
+      'key',
+    ),
+  );
+  $fields['fieldset']['default'] = _form_builder_webform_default('fieldset');
+  $fields['fieldset']['default']['#title'] = t('New fieldset');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_fieldset($component, $form_element) {
+  $component['extra']['collapsible'] = isset($form_element['#collapsible']) ? $form_element['#collapsible'] : NULL;
+  $component['extra']['collapsed'] = isset($form_element['#collapsed']) ? $form_element['#collapsed'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-fieldset-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-file-callbacks Callbacks for the File component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_file() {
+  $fields = array();
+
+  $fields['file'] = array(
+    'title' => t('File'),
+    'properties' => array(
+      'title',
+      'description',
+      'required',
+      'key',
+      'title_display',
+      'webform_file_filtering',
+      'webform_file_savelocation',
+      'webform_file_width',
+    ),
+  );
+  $file_element = _form_builder_webform_default('file');
+  $fields['file']['default'] = $file_element['default'];
+  $fields['file']['default']['#title'] = t('New file');
+  $fields['file']['default']['#theme_wrappers'] = array('webform_element');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_file() {
+  return array(
+    'webform_file_filtering' => array(
+      'form' => 'form_builder_webform_property_webform_file_filtering_form',
+    ),
+    'webform_file_savelocation' => array(
+      'form' => 'form_builder_webform_property_webform_file_savelocation_form',
+    ),
+    'webform_file_width' => array(
+      'form' => 'form_builder_webform_property_webform_file_width_form',
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_file($form_element) {
+  // If we are loading a file element, _webform_render_file() adds some extra
+  // structure (including several element children) that we don't want here.
+  // Instead, we need the element itself to represent the file component
+  // directly.
+  if (isset($form_element['#webform_component']['type']) && $form_element['#webform_component']['type'] == 'file') {
+    $form_element['#type'] = 'file';
+    unset($form_element['#theme']);
+    foreach (element_children($form_element) as $key) {
+      unset($form_element[$key]);
+    }
+    // Set the custom webform file properties based on the values stored with
+    // the webform component.
+    if (isset($form_element['#webform_component']['extra']['filtering'])) {
+      $form_element['#webform_file_filtering'] = $form_element['#webform_component']['extra']['filtering'];
+    }
+    if (isset($form_element['#webform_component']['extra']['savelocation'])) {
+      $form_element['#webform_file_savelocation'] = $form_element['#webform_component']['extra']['savelocation'];
+    }
+    if (isset($form_element['#webform_component']['extra']['width'])) {
+      $form_element['#webform_file_width'] = $form_element['#webform_component']['extra']['width'];
+    }
+  }
+
+  return $form_element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_file($form_element) {
+  // Map our pseudo-property to the visible "size" property.
+  $form_element['#size'] = $form_element['#webform_file_width'];
+
+  return $form_element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_file($component, $form_element) {
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  $component['extra']['filtering'] = isset($form_element['#webform_file_filtering']) ? $form_element['#webform_file_filtering'] : array();
+  $component['extra']['savelocation'] = isset($form_element['#webform_file_savelocation']) ? $form_element['#webform_file_savelocation'] : NULL;
+  $component['extra']['width'] = isset($form_element['#webform_file_width']) ? $form_element['#webform_file_width'] : NULL;
+
+  return $component;
+}
+
+/**
+ * Configuration form for the "webform_file_filtering" property.
+ */
+function form_builder_webform_property_webform_file_filtering_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_filtering', 'validation', array('validation', 'filtering'), array('extra', 'filtering'));
+}
+
+/**
+ * Configuration form for the "webform_file_savelocation" property.
+ */
+function form_builder_webform_property_webform_file_savelocation_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_savelocation', 'default', array('extra', 'savelocation'), array('extra', 'savelocation'));
+}
+
+/**
+ * Configuration form for the "webform_file_width" property.
+ */
+function form_builder_webform_property_webform_file_width_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_width', 'display', array('display', 'width'), array('extra', 'width'));
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-file-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-grid-callbacks Callbacks for the Grid component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_grid() {
+  $fields = array();
+
+  $fields['grid'] = array(
+    'title' => t('Grid'),
+    'properties' => array(
+      'title',
+      'description',
+      'required',
+      'key',
+      'title_display',
+      // Grid-specific properties.
+      'grid_options',
+      'grid_questions',
+      'custom_grid_option_keys',
+      'custom_grid_question_keys',
+      'optrand',
+      'qrand',
+    ),
+  );
+  $fields['grid']['default'] = _form_builder_webform_default('grid');
+  $fields['grid']['default']['#title'] = t('New grid');
+  $fields['grid']['default']['#grid_options'] = array(t('poor'), t('average'), t('good'), t('excellent'));
+  $fields['grid']['default']['#grid_questions'] = array(t('question one'), t('question two'), t('question three'));
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_grid() {
+  return array(
+    'grid_options' => array(
+      'form' => 'form_builder_webform_property_grid_options_form',
+      'submit' => array('form_builder_webform_property_grid_form_submit'),
+    ),
+    'grid_questions' => array(
+      'form' => 'form_builder_webform_property_grid_questions_form',
+      'submit' => array('form_builder_webform_property_grid_form_submit'),
+    ),
+    'optrand' => array(
+      'form' => 'form_builder_webform_property_grid_optrand_form'
+    ),
+    'qrand' => array(
+      'form' => 'form_builder_webform_property_grid_qrand_form'
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_grid($element) {
+  if (isset($element['#type']) && $element['#type'] == 'webform_grid') {
+    // Elements of type "webform_grid" are known to Form Builder as simply a
+    // "grid" field. This makes it so that we use the generic grid icon.
+    $element['#form_builder']['element_type'] = 'grid';
+
+    // Convert properties used only in Form Builder.
+    $element['#custom_grid_option_keys'] = !empty($element['#webform_component']['extra']['custom_option_keys']);
+    $element['#custom_grid_question_keys'] = !empty($element['#webform_component']['extra']['custom_question_keys']);
+  }
+  return $element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_grid($component, $form_element) {
+  $options = '';
+
+  foreach ($form_element['#grid_options'] as $key => $option_value) {
+    $options .= $key . '|' . $option_value . "\n";
+  }
+
+  $questions = '';
+  foreach ($form_element['#grid_questions'] as $key => $question_value) {
+    $questions .= $key . '|' . $question_value . "\n";
+  }
+
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  $component['extra']['options'] = $options;
+  $component['extra']['questions'] = $questions;
+  $component['extra']['custom_option_keys'] = isset($form_element['#custom_grid_option_keys']) ? $form_element['#custom_grid_option_keys'] : FALSE;
+  $component['extra']['custom_question_keys'] =  isset($form_element['#custom_grid_question_keys']) ? $form_element['#custom_grid_question_keys'] : FALSE;
+  $component['extra']['optrand'] = !empty($form_element['#optrand']);
+  $component['extra']['qrand'] = !empty($form_element['#qrand']);
+
+  return $component;
+}
+
+/**
+ * Configuration form for the "grid_options" property.
+ */
+function form_builder_webform_property_grid_options_form(&$form_state, $form_type, $element) {
+  $element['#grid_options'] = _webform_select_options_to_text($element['#grid_options']);
+  $form = _form_builder_webform_build_edit_form('grid', $element, 'grid_options', 'options', array('options'), array('extra', 'options'));
+  // The _form_builder_webform_build_edit_form() function can only pull in one
+  // property at a time, so we have to set the key toggle manually.
+  $form['grid_options']['options']['#key_type_toggled'] = !empty($element['#custom_grid_option_keys']);
+  return $form;
+}
+
+/**
+ * Configuration form for the "grid_questions" property.
+ */
+function form_builder_webform_property_grid_questions_form(&$form_state, $form_type, $element) {
+  $element['#grid_questions'] = _webform_select_options_to_text($element['#grid_questions']);
+  $form = _form_builder_webform_build_edit_form('grid', $element, 'grid_questions', 'options', array('questions'), array('extra', 'questions'));
+  // The _form_builder_webform_build_edit_form() function can only pull in one
+  // property at a time, so we have to set the key toggle manually.
+  $form['grid_questions']['options']['#key_type_toggled'] = !empty($element['#custom_grid_question_keys']);
+  return $form;
+}
+
+/**
+ * Submit handler for the "grid_options" and "grid_questions" properties.
+ */
+function form_builder_webform_property_grid_form_submit(&$form, &$form_state) {
+  if (empty($form_state['values']['grid_options'])) {
+    $form_state['values']['grid_options'] = _webform_select_options_from_text($form_state['values']['extra']['grid_options']);
+    $form_state['values']['custom_grid_option_keys'] = $form_state['values']['extra']['custom_grid_option_keys'];
+  }
+
+  if (empty($form_state['values']['grid_questions'])) {
+    $form_state['values']['grid_questions'] = _webform_select_options_from_text($form_state['values']['extra']['grid_questions']);
+    $form_state['values']['custom_grid_question_keys'] = $form_state['values']['extra']['custom_grid_question_keys'];
+  }
+}
+
+/**
+ * Configuration form for the "optrand" property.
+ */
+function form_builder_webform_property_grid_optrand_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('grid', $element, 'optrand', 'display', array('display', 'optrand'), array('extra', 'optrand'));
+}
+
+/**
+ * Configuration form for the "qrand" property.
+ */
+function form_builder_webform_property_grid_qrand_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('grid', $element, 'qrand', 'display', array('display', 'qrand'), array('extra', 'qrand'));
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-time-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-hidden-callbacks Callbacks for the Hidden component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_hidden() {
+  $fields = array();
+
+  $fields['hidden'] = array(
+    'title' => t('Hidden'),
+    'properties' => array(
+      'title',
+      'default_value',
+      'key',
+    ),
+  );
+  $fields['hidden']['default'] = _form_builder_webform_default('hidden');
+  $fields['hidden']['default']['#title'] = t('New hidden');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_hidden($form_element) {
+  // Convert the hidden element to a markup element before displaying it.
+  $form_element['#type'] = 'markup';
+  $form_element['#form_builder']['element_type'] = 'markup';
+  unset($form_element['#theme']);
+
+  // Add the 'webform_element' theme wrapper at the beginning, where it would
+  // normally be.
+  array_unshift($form_element['#theme_wrappers'], 'webform_element');
+
+  // Display the title of the hidden field as regular markup.
+  $form_element['#children'] = t('@title - <em>hidden field</em>', array('@title' => $form_element['#title']));
+  $form_element['#title_display'] = 'none';
+
+  // Give the element a wrapper class so that themers can recognize it
+  // represents a hidden element.
+  $form_element['#attributes']['class'][] = 'form-builder-preview-hidden-webform-element';
+  array_unshift($form_element['#theme_wrappers'], 'container');
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-hidden-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-markup-callbacks Callbacks for the Markup component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_markup() {
+  $fields = array();
+
+  $default = '';
+  $default .= '<p><strong>' . t('New HTML Markup') . '</strong></p>' . "\n\n";
+  $default .= '<p>' . t('Enter any text supported by available text formats.') . '</p>';
+
+  $fields['markup'] = array(
+    'title' => t('Markup'),
+    'properties' => array(
+      'title',
+      'markup',
+      'format',
+      'key',
+    ),
+  );
+  $fields['markup']['default'] = _form_builder_webform_default('markup');
+  $fields['markup']['default']['#markup'] = $default;
+  $fields['markup']['default']['#title'] = t('New markup');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_markup($component, $form_element) {
+  $component['value'] = $form_element['#markup'];
+  $component['extra']['format'] = isset($form_element['#format']) ? $form_element['#format'] : filter_default_format();
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_markup($form_element) {
+  // Filter the markup with the appropriate text format before displaying it.
+  $form_element['#markup'] = isset($form_element['#markup']) ? $form_element['#markup'] : '';
+  $format = isset($form_element['#format']) ? $form_element['#format'] : filter_default_format();
+  $form_element['#markup'] = check_markup(_webform_filter_values($form_element['#markup'], NULL, NULL, NULL, FALSE), $format, '', TRUE);
+  if (strlen(trim($form_element['#markup'])) == 0) {
+    $form_element['#markup'] = t('Empty markup field');
+  }
+
+  // Do not show the title, since it will not display in the final webform
+  // either.
+  $form_element['#title_display'] = 'none';
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-markup-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-pagebreak-callbacks Callbacks for the Pagebreak component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_pagebreak() {
+  $fields = array();
+
+  $fields['pagebreak'] = array(
+    'title' => t('Page break'),
+    'properties' => array(
+      'title',
+      'key',
+    ),
+    'default' => array(
+      '#title' => t('Page break'),
+      '#type' => 'pagebreak',
+    ),
+  );
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_pagebreak($form_element) {
+  // Pagebreak components are rendered as hidden elements by webform, but
+  // hidden elements do not have a #title property. So we have to convert the
+  // rendered value to be used as the #title instead.
+  if ($form_element['#type'] == 'pagebreak') {
+    $form_element['#title'] = $form_element['#value'];
+  }
+  return $form_element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_preview_alter_component().
+ */
+function _form_builder_webform_form_builder_preview_alter_pagebreak($form_element) {
+  // Convert the pagebreak element to a markup element before displaying it.
+  $form_element['#type'] = 'markup';
+  $form_element['#form_builder']['element_type'] = 'markup';
+  unset($form_element['#theme']);
+
+  // Add the 'webform_element' theme wrapper at the beginning, where it would
+  // normally be.
+  array_unshift($form_element['#theme_wrappers'], 'webform_element');
+
+  // Display the title of the pagebreak field as regular markup.
+  $form_element['#children'] = '--- ' . check_plain($form_element['#title']) . ' ---';
+  $form_element['#children'] .= '<div class="description">' . t('(Fields below will be displayed on a new page)') . '</div>';
+  $form_element['#title_display'] = 'none';
+
+  // Give the element a wrapper class so that themers can recognize it
+  // represents a pagebreak element.
+  $form_element['#attributes']['class'][] = 'form-builder-preview-pagebreak-webform-element';
+  array_unshift($form_element['#theme_wrappers'], 'container');
+
+  return $form_element;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-pagebreak-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-select-callbacks Callbacks for the Select component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_select() {
+  $fields = array();
+
+  $fields['select'] = array(
+    'title' => t('Select list'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['select']['default'] = _form_builder_webform_default('select', array('aslist' => TRUE, 'multiple' => FALSE));
+  $fields['select']['default']['#options'] = array(t('one'), t('two'), t('three'));
+  $fields['select']['default']['#default_value'] = 0;
+  $fields['select']['default']['#title'] = t('New select');
+  $fields['select']['default']['#webform'] = array('type' => 'select');
+
+  $fields['checkboxes'] = array(
+    'title' => t('Checkboxes'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'multiple',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['checkboxes']['default'] = _form_builder_webform_default('select', array('aslist' => FALSE, 'multiple' => TRUE));
+  $fields['checkboxes']['default']['#options'] = array(t('one'), t('two'), t('three'));
+  $fields['checkboxes']['default']['#default_value'] = array(0, 1);
+  $fields['checkboxes']['default']['#title'] = t('New checkboxes');
+  $fields['checkboxes']['default']['#webform'] = array('type' => 'select');
+
+  $fields['radios'] = array(
+    'title' => t('Radios'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'options',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['radios']['default'] = _form_builder_webform_default('select', array('aslist' => FALSE, 'multiple' => FALSE));
+  $fields['radios']['default']['#options'] = array(t('one'), t('two'), t('three'));
+  $fields['radios']['default']['#default_value'] = 0;
+  $fields['radios']['default']['#title'] = t('New radios');
+  $fields['radios']['default']['#webform'] = array('type' => 'select');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_select($form_element) {
+  if (in_array($form_element['#type'], array('radios', 'checkboxes', 'select'))) {
+    $form_element['#webform']['type'] = 'select';
+    if ($form_element['#type'] == 'checkboxes') {
+      $form_element['#multiple'] = TRUE;
+    }
+    return $form_element;
+  }
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_select($component, $form_element) {
+  $options = '';
+
+  foreach ($form_element['#options'] as $key => $option_value) {
+    $options .= $key . '|' . $option_value . "\n";
+  }
+
+  $component['extra']['items'] = $options;
+  $component['extra']['multiple'] = $form_element['#form_builder']['element_type'] == 'checkboxes';
+  $component['extra']['aslist'] = $form_element['#form_builder']['element_type'] == 'select';
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-select-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-textarea-callbacks Callbacks for the Textarea component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_textarea() {
+  $fields = array();
+
+  $fields['textarea'] = array(
+    'title' => t('Textarea'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'rows',
+      'cols',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['textarea']['default'] = _form_builder_webform_default('textarea');
+  $fields['textarea']['default']['#title'] = t('New textarea');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_textarea($component, $form_element) {
+  $component['extra']['description'] = $form_element['#description'];
+  $component['extra']['cols'] = $form_element['#cols'];
+  $component['extra']['rows'] = $form_element['#rows'];
+  $component['extra']['disabled'] = empty($form_element['#disabled']) ? NULL : TRUE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-textarea-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-textfield-callbacks Callbacks for the Textfield component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_textfield() {
+  $fields = array();
+
+  $fields['textfield'] = array(
+    'title' => t('Textfield'),
+    'properties' => array(
+      'title',
+      'description',
+      'field_prefix',
+      'field_suffix',
+      'default_value',
+      'required',
+      'size',
+      'key',
+      'title_display',
+    ),
+  );
+  $fields['textfield']['default'] = _form_builder_webform_default('textfield');
+  $fields['textfield']['default']['#title'] = t('New textfield');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_textfield($component, $form_element) {
+  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
+  $component['extra']['maxlength'] = isset($form_element['#maxlength']) ? $form_element['#maxlength'] : NULL;
+  $component['extra']['field_prefix'] = isset($form_element['#field_prefix']) ? $form_element['#field_prefix'] : NULL;
+  $component['extra']['field_suffix'] = isset($form_element['#field_suffix']) ? $form_element['#field_suffix'] : NULL;
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  return $component;
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-textfield-callbacks"
+ */
+
+/**
+ * @defgroup form-builder-webform-time-callbacks Callbacks for the Time component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_time() {
+  $fields = array();
+
+  $fields['time'] = array(
+    'title' => t('Time'),
+    'properties' => array(
+      'title',
+      'description',
+      'default_value',
+      'required',
+      'key',
+      'title_display',
+      // Date-specific properties.
+      'timezone',
+      'hourformat',
+    ),
+  );
+  $fields['time']['default'] = _form_builder_webform_default('time');
+  $fields['time']['default']['#title'] = t('New time');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_time() {
+  return array(
+    'timezone' => array(
+      'form' => 'form_builder_webform_property_time_timezone_form',
+    ),
+    'hourformat' => array(
+      'form' => 'form_builder_webform_property_time_hourformat_form',
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_load_component().
+ */
+function _form_builder_webform_form_builder_load_time($element) {
+  if (isset($element['#type']) && $element['#type'] == 'webform_time') {
+    // Elements of type "webform_time" are known to Form Builder as simply a
+    // "time" field. This makes it so that we use the generic time icon.
+    $element['#form_builder']['element_type'] = 'time';
+  }
+  return $element;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_save_component().
+ */
+function _form_builder_webform_form_builder_save_time($component, $form_element) {
+  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
+  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
+  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+  $component['extra']['timezone'] = isset($form_element['#timezone']) ? $form_element['#timezone'] : 'user';
+  $component['extra']['hourformat'] = isset($form_element['#hourformat']) ? $form_element['#hourformat'] : '12-hour';
+  return $component;
+}
+
+/**
+ * Configuration form for the "timezone" property.
+ */
+function form_builder_webform_property_time_timezone_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('time', $element, 'timezone', NULL, array('extra', 'timezone'), array('extra', 'timezone'));
+}
+
+/**
+ * Configuration form for the "hourformat" property.
+ */
+function form_builder_webform_property_time_hourformat_form(&$form_state, $form_type, $element) {
+  return _form_builder_webform_build_edit_form('time', $element, 'hourformat', 'display', array('display', 'hourformat'), array('extra', 'hourformat'));
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-time-callbacks"
+ */
+
+/**
+ * Helper function; Generate a default FAPI element for any component type.
+ */
+function _form_builder_webform_default($component_type, $merge_extras = array()) {
+  $default_component = webform_component_invoke($component_type, 'defaults');
+  $default_component['extra'] = isset($default_component['extra']) ? array_merge($default_component['extra'], $merge_extras) : $merge_extras;
+  $default_element = webform_component_invoke($component_type, 'render', $default_component, NULL, FALSE);
+  return $default_element;
+}
+
+/**
+ * Helper function; builds a form for editing part of a webform component.
+ *
+ * The returned form is derived from a subcomponent of the component form
+ * provided by the Webform module.
+ *
+ * @param $type
+ *   The webform component type to be edited.
+ * @param $element
+ *   A form array representing the element whose configuration form we are
+ *   building.
+ * @param $property
+ *   The property of $element which stores the state of portions of the webform
+ *   component that this form is responsible for configuring. The property
+ *   should be passed in without the leading "#".
+ * @param $form_builder_property_group
+ *   The Form Builder property group in which this configuration form should be
+ *   displayed.
+ * @param $form_nested_keys
+ *   An array of nested keys representing the location of the subcomponent of
+ *   the _webform_edit_[component]() form that this configuration form will be
+ *   taken from. For example, if the part of the configuration form we are
+ *   interested in is located in $form['display']['width'], where $form is the
+ *   output of _webform_edit_[component](), we would pass
+ *   array('display', 'width') in for this parameter.
+ * @param $component_nested_keys
+ *   An array of nested keys representing the location of the portions of the
+ *   webform component that this form is responsible for configuring. For
+ *   example, if this form configures the data that is stored in
+ *   $component['extra']['filtering'], where $component has the structure of
+ *   the array returned by _webform_defaults_[component](), we would pass
+ *   array('extra', 'filtering') in for this parameter.
+ *
+ * @return
+ *   A form array that can be used to edit the specified part of the webform
+ *   component represented by $element.
+ */
+function _form_builder_webform_build_edit_form($type, $element, $property, $form_builder_property_group, $form_nested_keys, $component_nested_keys) {
+  // The Webform module stores existing component data as part of the passed-in
+  // element. If the component doesn't exist yet, initialize a default
+  // component.
+  $defaults_function = '_webform_defaults_' . $type;
+  $component = isset($element['#webform_component']) ? $element['#webform_component'] : $defaults_function();
+
+  // The most up-to-date configuration data stored by Form Builder for the
+  // part of the component we are editing is also stored in the passed-in
+  // element, and should always take precedence.
+  if (isset($element["#$property"])) {
+    drupal_array_set_nested_value($component, $component_nested_keys, $element["#$property"]);
+  }
+
+  // Build the entire _webform_edit_file() form based on the current state of
+  // the component, and obtain the slice of it that we want.
+  $edit_function = '_webform_edit_' . $type;
+  $form = $edit_function($component);
+  $form = drupal_array_get_nested_value($form, $form_nested_keys);
+
+  // Force the form to have a consistent #tree structure so it will appear in
+  // $form_state['values'] the way we want.
+  _form_builder_webform_force_tree($form);
+
+  // Indicate the Form Builder property group that this form will be displayed
+  // in.
+  if ($form_builder_property_group) {
+    $form['#form_builder']['property_group'] = $form_builder_property_group;
+  }
+
+  // Return the form, keyed by the name of the property that is being
+  // configured.
+  return array($property => $form);
+}
+
+/**
+ * Helper function; replaces custom form #parents with a #tree structure.
+ *
+ * This is a helper function to force #tree = TRUE on all parts of a form,
+ * regardless of any custom #parents that were originally defined as part of
+ * the form. It is used to ensure a consistent structure within
+ * $form_state['values'] when the form is submitted.
+ *
+ * @param $form
+ *   The form array to modify.
+ */
+function _form_builder_webform_force_tree(&$form) {
+  unset($form['#parents']); 
+  $form['#tree'] = TRUE; 
+  foreach (element_children($form) as $key) {
+    _form_builder_webform_force_tree($form[$key]);
+  }
+}
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.info b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
new file mode 100644
index 00000000..01dba515
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
@@ -0,0 +1,12 @@
+name = Form builder Webform UI
+description = Form builder integration for the Webform module.
+core = 7.x
+dependencies[] = form_builder
+dependencies[] = webform
+
+; Information added by drupal.org packaging script on 2011-06-06
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "form_builder"
+datestamp = "1307319364"
+
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.module b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
new file mode 100644
index 00000000..9b2764ac
--- /dev/null
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
@@ -0,0 +1,441 @@
+<?php
+
+/**
+ * @file
+ *   Form Builder integration for the Webform module.
+ */
+
+/**
+ * Implements hook_menu_alter().
+ */
+function form_builder_webform_menu_alter(&$items) {
+  $items['node/%webform_menu/webform']['page callback'] = 'form_builder_webform_components_page';
+  $items['node/%webform_menu/webform/components']['page callback'] = 'form_builder_webform_components_page';
+}
+
+/**
+ * Menu callback; display a form builder interface to edit webform components.
+ */
+function form_builder_webform_components_page($node) {
+  module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
+
+  // Load all components.
+  $components = webform_components();
+  foreach ($components as $component_type => $component) {
+    webform_component_include($component_type);
+  }
+
+  $build = array();
+
+  $path = drupal_get_path('module', 'webform');
+  $build['#attached']['css'][] = $path . '/css/webform.css';
+  $build['#attached']['css'][] = $path . '/css/webform-admin.css';
+  $build['#attached']['js'][] = $path . '/js/webform.js';
+  $build['#attached']['js'][] = $path . '/js/webform-admin.js';
+  $build['#attached']['js'][] = $path . '/js/select-admin.js';
+  // START UNL CHANGE SEE README-UNL.txt
+  global $base_path;
+  $build['#attached']['js'][] = $base_path . 'misc/ui/jquery.ui.datepicker.min.js';
+  // END UNL CHANGE
+
+  $build[] = form_builder_interface('webform', $node->nid);
+  $build[] = drupal_get_form('form_builder_webform_save_form', $node->nid);
+
+  return $build;
+}
+
+/**
+ * Form to save the Form Builder interface.
+ *
+ * The actual Form Builder interface is displayed as part of the
+ * form_builder_webform_components_page() function.
+ */
+function form_builder_webform_save_form($form, &$form_state, $nid) {
+  $form['nid'] = array(
+    '#type' => 'value',
+    '#value' => $nid,
+  );
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  $form['cancel'] = array(
+    '#type' => 'submit',
+    '#value' => t('Cancel'),
+    '#submit' => array('form_builder_webform_cancel'),
+  );
+
+  return $form;
+}
+
+/**
+ * Submit handler; save the current Form Builder interface changes.
+ */
+function form_builder_webform_save_form_submit($form, &$form_state) {
+  $node = node_load($form_state['values']['nid']);
+  form_builder_webform_save_node($node);
+  drupal_set_message(t('Changes to the form have been saved.'));
+}
+
+/**
+ * Save the current Form Builder interface changes for a webform node.
+ */
+function form_builder_webform_save_node($node) {
+  $form_cache = form_builder_cache_load('webform', $node->nid);
+  $element_ids = form_builder_preview_prepare($form_cache, 'webform', $node->nid);
+
+  // Save modified or created components.
+  foreach ($element_ids as $id) {
+    form_builder_webform_save_component($node, $id, $form_cache);
+  }
+
+  // Delete components that have been removed.
+  foreach ($node->webform['components'] as $component) {
+    $element_id = 'cid_' . $component['cid'];
+    if (!in_array($element_id, $element_ids)) {
+      webform_component_delete($node, $component);
+    }
+  }
+
+  // Reset the node cache, since $node->webform['components'] has changed.
+  // @todo: Decide if this belongs in the above Webform API functions instead?
+  entity_get_controller('node')->resetCache(array($node->nid));
+
+  // Remove the cached form_builder form.
+  form_builder_cache_delete('webform', $node->nid);
+}
+
+/**
+ * Save the contents of a form component into Webform's database tables.
+ */
+function form_builder_webform_save_component($node, $element_id, $form) {
+  $element = form_builder_get_element($form, $element_id);
+  $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+
+  // Check for existing components.
+  $cid = substr($element_id, 4);
+  if (isset($node->webform['components'][$cid])) {
+    $component = $node->webform['components'][$cid];
+  }
+  // Populate a new default component.
+  elseif (isset($element['#webform']['is_new'])) {
+    if ($component = webform_component_invoke($type, 'defaults')) {
+      $component['type'] = $type;
+    }
+  }
+
+  // If the component type isn't found, don't try to save anything.
+  if (!isset($component)) {
+    return;
+  }
+
+  // Set typical component settings.
+  $component['name'] = $element['#title'];
+  $component['weight'] = $element['#weight'];
+  $component['form_key'] = $element['#key'];
+  $component['mandatory'] = isset($element['#required']) ? $element['#required'] : 0;
+  $component['email'] = 0;
+  $component['nid'] = $node->nid;
+
+  // Set the parent ID to default to the form base.
+  $component['pid'] = 0;
+
+  // Set the parent ID for the component if it is nested inside another component.
+  // This must be done this way so that children of newly added components get a
+  // proper pid when the cid of the new component has just been generated.
+  $parent = form_builder_get_element($form, $element['#form_builder']['parent_id']);
+  if ($parent) {
+    // If the parent is new, the database must be queried for the cid of the parent.
+    if (isset($parent['#webform']['is_new']) && $parent['#webform']['is_new']) {
+      $results = db_query('SELECT cid, form_key FROM {webform_component} WHERE form_key = :key AND nid = :nid', array(':key' => $element['#form_builder']['parent_id'], ':nid' => $node->nid));
+      foreach($results as $result) {
+        $component['pid'] = $result->cid;
+      }
+    }
+    // If the parent is already stored in the webform, grab its cid value.
+    elseif (isset($parent['#webform_component']['cid'])) {
+      $component['pid'] = $parent['#webform_component']['cid'];
+    }
+  }
+
+  // Set the component's value. If the form element doesn't have a default,
+  // then new components should not be modified (they should use whatever the
+  // component default is), but existing components should have their stored
+  // value removed.
+  if (isset($element['#default_value'])) {
+    $component['value'] = is_array($element['#default_value']) ? implode(',', $element['#default_value']) : $element['#default_value'];
+  }
+  elseif (empty($element['#webform']['is_new'])) {
+    $component['value'] = NULL;
+  }
+
+  // Save any specific settings.
+  if ($saved_component = form_builder_webform_component_invoke($type, 'form_builder_save', $component, $element)) {
+    $component = $saved_component;
+  }
+
+  if (!isset($component['cid'])) {
+    webform_component_insert($component);
+  }
+  elseif ($component != $node->webform['components'][$component['cid']]) {
+    webform_component_update($component);
+  }
+}
+
+/**
+ * Submit handler for the "Cancel" button.
+ */
+function form_builder_webform_cancel(&$form, &$form_state) {
+  drupal_set_message(t('Changes to the form have been discarded.'));
+  form_builder_cache_delete('webform', $form_state['values']['nid']);
+}
+
+/**
+ * Implements hook_form_builder_types().
+ *
+ * Define the fields within webforms that are editable.
+ */
+function form_builder_webform_form_builder_types() {
+  $fields = array();
+
+  $components = webform_components();
+  foreach ($components as $type => $component) {
+    if ($additional_fields = form_builder_webform_component_invoke($type, 'form_builder_types')) {
+      $fields = array_merge($fields, $additional_fields);
+    }
+  }
+
+  return array('webform' => $fields);
+}
+
+/**
+ * Implements hook_form_builder_properties().
+ */
+function form_builder_webform_form_builder_properties($form_type) {
+  $properties = array();
+
+  if ($form_type == 'webform') {
+    $components = webform_components();
+    foreach ($components as $type => $component) {
+      if ($additional_properties = form_builder_webform_component_invoke($type, 'form_builder_properties')) {
+        $properties = array_merge($properties, $additional_properties);
+      }
+    }
+  }
+
+  return $properties;
+}
+
+/**
+ * Implements hook_form_builder_load().
+ *
+ * Load a complete FAPI array based on a form type and ID.
+ */
+function form_builder_webform_form_builder_load($form_builder_type, $form_builder_id) {
+  if ($form_builder_type == 'webform') {
+    // Webform identifies its forms by Node Id.
+    $nid = $form_builder_id;
+    $node = node_load($nid);
+
+    // Since webform_client_form() has special handling for the 'pagebreak'
+    // component that we do not want to occur here (here we want to display the
+    // entire webform on a single page, without page breaks), we temporarily
+    // change the component to 'pagebreak_clone' and then change it back
+    // afterwards. See _webform_render_pagebreak_clone().
+    // @todo: Replace this with something cleaner, if webform eventually allows
+    //   us to do that.
+    $pagebreak_component_keys = array();
+    foreach ($node->webform['components'] as &$component) {
+      if ($component['type'] == 'pagebreak') {
+        $component['type'] = 'pagebreak_clone';
+        $pagebreak_component_keys[] = $component['form_key'];
+      }
+    }
+
+    // Get the unfiltered version of the client form.
+    $form = array();
+    $form_state = array();
+    $form = webform_client_form($form, $form_state, $node, array(), TRUE, FALSE);
+
+    // Change 'pagebreak' components back, as described above.
+    foreach ($pagebreak_component_keys as $key) {
+      $form['submitted'][$key]['#type'] = 'pagebreak';
+    }
+
+    // Perform final processing of the form, and return it.
+    $form += array('submitted' => array());
+    form_builder_webform_load_process($form['submitted'], $node);
+    return $form['submitted'];
+  }
+}
+
+/**
+ * Recursive helper function to populate #form_builder['element_id'] values.
+ */
+function form_builder_webform_load_process(&$form, $node, $pid = 0) {
+  foreach (element_children($form) as $key) {
+    $cid = webform_get_cid($node, $key, $pid);
+    $form[$key]['#form_builder'] = array(
+      'element_id' => 'cid_' . $cid,
+    );
+
+    // Add any component-specific loading. Note that all components are
+    // invoked here because the component type isn't yet known.
+    foreach (webform_components() as $type => $info) {
+      if ($element = form_builder_webform_component_invoke($type, 'form_builder_load', $form[$key])) {
+        $form[$key] = $element;
+      }
+    }
+    form_builder_webform_load_process($form[$key], $node, $cid);
+  }
+}
+
+/**
+ * Implements hook_form_builder_add_element_alter().
+ *
+ * Modify a FAPI element before it is added to the form array.
+ */
+function form_builder_webform_form_builder_add_element_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'webform') {
+    $element['#webform']['is_new'] = TRUE;
+  }
+}
+
+/**
+ * Implements hook_form_builder_preview_alter().
+ *
+ * The most common use of the preview altering is filtering field descriptions
+ * via filter_xss() or other functions. Webform has its own filtering function
+ * for this purpose.
+ */
+function form_builder_webform_form_builder_preview_alter(&$element, $form_type, $form_id) {
+  if ($form_type == 'webform') {
+    // Filter all descriptions for all components.
+    if (isset($element['#description'])) {
+      $element['#description'] = _webform_filter_descriptions($element['#description']);
+    }
+
+    if (isset($element['#default_value']) && is_string($element['#default_value'])) {
+      $element['#value'] = _webform_filter_values($element['#default_value'], NULL, NULL, NULL, FALSE);
+    }
+
+    // Add info to the #webform_component array so that theme_webform_element will
+    // work properly.
+    $element['#webform_component']['type'] = $element['#form_builder']['element_type'];
+
+    // Let components do any extra filtering if needed.
+    $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+    if ($new_element = form_builder_webform_component_invoke($type, 'form_builder_preview_alter', $element)) {
+      $element = $new_element;
+    }
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * This form_alter is a workaround for an unfortunate interaction that ends up
+ * duplicating titles and descriptions for radios and checkboxes. By default,
+ * system.module defines a pre_render function for radios and checkboxes
+ * (form_pre_render_conditional_form_element). This pre_render adds the
+ * form_element theme_wrapper if there is a title or a description.
+ * Unfortunately, webform is already adding webform_element, which is nearly
+ * a copy of form_element, and if you have both, you get two titles and
+ * descriptions.
+ *
+ * We can't use the normal mechanism for component alters, because that happens
+ * in a pre_render (so removing the other pre_render isn't going to help).
+ */
+function form_builder_webform_form_form_builder_preview_alter(&$form, $form_state) {
+  if ($form['#form_builder']['form_type'] != 'webform') {
+    return;
+  }
+  $form['#attached']['css'][] = drupal_get_path('module', 'webform') .'/css/webform.css';
+  _form_builder_remove_conditional_form_element_pre_render($form);
+}
+
+/**
+ * Helper function to remove a system.module pre-render function from a form.
+ *
+ * @see form_builder_webform_form_form_builder_preview_alter()
+ */
+function _form_builder_remove_conditional_form_element_pre_render(&$form) {
+  foreach (element_children($form) as $key) {
+    $form_element = &$form[$key];
+    if (isset($form_element['#pre_render'])) {
+      // Remove system_module's pre_render function, if it exists.
+      $k = array_search('form_pre_render_conditional_form_element', $form_element['#pre_render']);
+      if ($k !== FALSE) {
+        unset($form_element['#pre_render'][$k]);
+      }
+    }
+    // Recurse through the child elements (for example, to handle cases where
+    // a set of radios or checkboxes with the above pre-render function is
+    // contained within a fieldset).
+    _form_builder_remove_conditional_form_element_pre_render($form_element);
+  }
+}
+
+/**
+ * Invoke a form builder callback for a webform component.
+ *
+ * If the webform component implements the callback itself, this function
+ * returns the result obtained from that. Otherwise, if this module has a
+ * default implementation of the callback on behalf of the component, the
+ * result obtained from that is returned.
+ *
+ * @param $type
+ *   The component type as a string.
+ * @param $callback
+ *   The callback to execute.
+ * @param ...
+ *   Any additional parameters required by the $callback.
+ */
+function form_builder_webform_component_invoke($type, $callback) {
+  $args = func_get_args();
+
+  // First try invoking the callback in the webform component itself.
+  $result = call_user_func_array('webform_component_invoke', $args);
+  if (isset($result)) {
+    return $result;
+  }
+
+  // Otherwise look for a default implementation provided by this module.
+  $type = array_shift($args);
+  $callback = array_shift($args);
+  $function = '_form_builder_webform_' . $callback . '_' . $type;
+  module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
+  if (function_exists($function)) {
+    return call_user_func_array($function, $args);
+  }
+}
+
+/**
+ * Implements _webform_render_component().
+ *
+ * This "component" is only used as a temporary replacement for the standard
+ * pagebreak component when the form builder version of the webform is being
+ * rendered; this occurs when form_builder_webform_form_builder_load() calls
+ * webform_client_form(). Therefore, we do not need to register it as a regular
+ * webform component anywhere else (and don't want to, since we don't want it
+ * to be available elsewhere in the webform UI).
+ */
+function _webform_render_pagebreak_clone($component, $value = NULL, $filter = TRUE) {
+  return webform_component_invoke('pagebreak', 'render', $component, $value, $filter);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Customizations to the field configuration form to better integrate with webforms.
+ */
+function form_builder_webform_form_form_builder_field_configure_alter(&$form, &$form_state, $form_id) {
+  // Change the list of options from the default Drupal values to the acceptable
+  // webform values.
+  $form['title_display']['#options'] = array(
+    'before' => t('Above'),
+    'inline' => t('Inline'),
+    'none' => t('Hidden'),
+  );
+  $form['title_display']['#default_value'] = isset($form['title_display']['#default_value']) ? $form['title_display']['#default_value'] : 'before';
+}
-- 
GitLab