Skip to content
Browse files

Merge pull request #18 from shrop/add-webform

Added the webform module
  • Loading branch information...
2 parents 225e14b + 2be4e0d commit 3e0bb6ba981b17bf45be6ddb5270daacb7109c2f @shrop committed Jan 15, 2013
Showing with 17,891 additions and 0 deletions.
  1. +37 −0 www/sites/all/modules/webform/CHANGELOG.txt
  2. +339 −0 www/sites/all/modules/webform/LICENSE.txt
  3. +41 −0 www/sites/all/modules/webform/README.txt
  4. +115 −0 www/sites/all/modules/webform/THEMING.txt
  5. +433 −0 www/sites/all/modules/webform/components/date.inc
  6. +285 −0 www/sites/all/modules/webform/components/email.inc
  7. +100 −0 www/sites/all/modules/webform/components/fieldset.inc
  8. +531 −0 www/sites/all/modules/webform/components/file.inc
  9. +428 −0 www/sites/all/modules/webform/components/grid.inc
  10. +179 −0 www/sites/all/modules/webform/components/hidden.inc
  11. +80 −0 www/sites/all/modules/webform/components/markup.inc
  12. +704 −0 www/sites/all/modules/webform/components/number.inc
  13. +101 −0 www/sites/all/modules/webform/components/pagebreak.inc
  14. +981 −0 www/sites/all/modules/webform/components/select.inc
  15. +217 −0 www/sites/all/modules/webform/components/textarea.inc
  16. +254 −0 www/sites/all/modules/webform/components/textfield.inc
  17. +430 −0 www/sites/all/modules/webform/components/time.inc
  18. +119 −0 www/sites/all/modules/webform/css/webform-admin.css
  19. +30 −0 www/sites/all/modules/webform/css/webform.css
  20. BIN www/sites/all/modules/webform/images/calendar.png
  21. +297 −0 www/sites/all/modules/webform/includes/webform.admin.inc
  22. +1,100 −0 www/sites/all/modules/webform/includes/webform.components.inc
  23. +578 −0 www/sites/all/modules/webform/includes/webform.emails.inc
  24. +170 −0 www/sites/all/modules/webform/includes/webform.export.inc
  25. +132 −0 www/sites/all/modules/webform/includes/webform.options.inc
  26. +417 −0 www/sites/all/modules/webform/includes/webform.pages.inc
  27. +1,005 −0 www/sites/all/modules/webform/includes/webform.report.inc
  28. +925 −0 www/sites/all/modules/webform/includes/webform.submissions.inc
  29. +56 −0 www/sites/all/modules/webform/js/select-admin.js
  30. +119 −0 www/sites/all/modules/webform/js/webform-admin.js
  31. +80 −0 www/sites/all/modules/webform/js/webform.js
  32. +8 −0 www/sites/all/modules/webform/templates/webform-calendar.tpl.php
  33. +29 −0 www/sites/all/modules/webform/templates/webform-confirmation.tpl.php
  34. +27 −0 www/sites/all/modules/webform/templates/webform-form.tpl.php
  35. +36 −0 www/sites/all/modules/webform/templates/webform-mail.tpl.php
  36. +35 −0 www/sites/all/modules/webform/templates/webform-results-submissions.tpl.php
  37. +24 −0 www/sites/all/modules/webform/templates/webform-submission-information.tpl.php
  38. +30 −0 www/sites/all/modules/webform/templates/webform-submission-navigation.tpl.php
  39. +35 −0 www/sites/all/modules/webform/templates/webform-submission-page.tpl.php
  40. +19 −0 www/sites/all/modules/webform/templates/webform-submission.tpl.php
  41. +37 −0 www/sites/all/modules/webform/tests/components.test
  42. +67 −0 www/sites/all/modules/webform/tests/permissions.test
  43. +174 −0 www/sites/all/modules/webform/tests/submission.test
  44. +808 −0 www/sites/all/modules/webform/tests/webform.test
  45. +308 −0 www/sites/all/modules/webform/views/webform.views.inc
  46. +42 −0 www/sites/all/modules/webform/views/webform_handler_field_form_body.inc
  47. +18 −0 www/sites/all/modules/webform/views/webform_handler_field_is_draft.inc
  48. +30 −0 www/sites/all/modules/webform/views/webform_handler_field_node_link_edit.inc
  49. +30 −0 www/sites/all/modules/webform/views/webform_handler_field_node_link_results.inc
  50. +60 −0 www/sites/all/modules/webform/views/webform_handler_field_submission_count.inc
  51. +100 −0 www/sites/all/modules/webform/views/webform_handler_field_submission_link.inc
  52. +38 −0 www/sites/all/modules/webform/views/webform_handler_field_webform_status.inc
  53. +25 −0 www/sites/all/modules/webform/views/webform_handler_filter_is_draft.inc
  54. +15 −0 www/sites/all/modules/webform/views/webform_handler_filter_webform_status.inc
  55. +858 −0 www/sites/all/modules/webform/webform.api.php
  56. +32 −0 www/sites/all/modules/webform/webform.info
  57. +833 −0 www/sites/all/modules/webform/webform.install
  58. +3,890 −0 www/sites/all/modules/webform/webform.module
View
37 www/sites/all/modules/webform/CHANGELOG.txt
@@ -0,0 +1,37 @@
+Webform 2.x Changelog
+---------------------
+
+2.x to 3.0
+----------
+- Module directory structure moved around.
+- Webform configuration moved to an entirely separate tab.
+- E-mail templates are now editable by administrators.
+- Conditional fields.
+- Submissions may be saved as a draft and resumed later.
+- Webform may now be attached to any content type.
+- Public API for allowing other modules to provide components.
+- Public API for interacting with submission save, insert, update, and delete.
+- New rendering capabilities for HTML presentation of submissions and e-mails.
+- Print module support.
+- Basic Views module support.
+- Popup calendar support on Date components (with Date Popup module).
+- New Mollom module integration.
+
+1.x to 2.0
+----------
+- Redirect POST option removed.
+- Webform components moved to the "Form components" tab when editing.
+- Webform node structure changed. All webform additions to the node are placed in $node->webform.
+- Clone option added to components.
+- Database storage improved to be more consistent and efficient.
+- Additional e-mails may be sent by modifying the $node->webform['additional_emails'] variable in the Additional Validation field.
+- The values of select and hidden fields may receive e-mails by using the option in Conditional e-mail recipients field.
+- E-mail from name, from address, and from subject may be entered in a text field.
+- The complete webform may be shown in the teaser view of a node.
+- Submit button text may be changed.
+- Theme function theme_webform_create_mailmessage() has been renamed to theme_webform_mail_message().
+- $cid parameter added to theme_webform_mail_message() to create unique e-mails depending on a particular recipient or component.
+- Theme function theme_webform_mail_headers added.
+- Component descriptions are textareas rather than textfields.
+- _webform_filtervalues() has been renamed to _webform_filter_values.
+
View
339 www/sites/all/modules/webform/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
View
41 www/sites/all/modules/webform/README.txt
@@ -0,0 +1,41 @@
+Description
+-----------
+This module adds a webform content type to your Drupal site.
+A webform can be a questionnaire, contact or request form. These can be used
+by visitor to make contact or to enable a more complex survey than polls
+provide. Submissions from a webform are saved in a database table and
+can optionally be mailed to e-mail addresses upon submission.
+
+Requirements
+------------
+Drupal 7.x
+
+Installation
+------------
+1. Copy the entire webform directory the Drupal sites/all/modules directory.
+
+2. Login as an administrator. Enable the module in the "Administer" -> "Modules"
+
+3. (Optional) Edit the settings under "Administer" -> "Configuration" ->
+ "Content authoring" -> "Webform settings"
+
+4. Create a webform node at node/add/webform.
+
+Upgrading from previous versions
+--------------------------------
+Note that if you are upgrading from a Drupal 6 installation of Webform, you MUST
+have been running Webform 3.x on your Drupal 6 site before upgrading to Drupal
+7 and Webform 3.x. You cannot upgrade directly from Webform 6.x-2.x to Webform
+7.x-3.x.
+
+1. Copy the entire webform directory the Drupal modules directory.
+
+2. Login as the FIRST user or change the $access_check in update.php to FALSE
+
+3. Run update.php (at http://www.example.com/update.php)
+
+Support
+-------
+Please use the issue queue for filing bugs with this module at
+http://drupal.org/project/issues/webform
+
View
115 www/sites/all/modules/webform/THEMING.txt
@@ -0,0 +1,115 @@
+Overview
+--------
+Webform supports theming similar to the CCK or Views modules. Any webform
+may be themed on the server side, though doing so may require a reasonable
+amount of knowledge about the Drupal Form API. More information about the Form
+API may be found at http://api.drupal.org/api/file/developer/topics/forms_api.html
+
+Theme submission e-mails
+-----------------------
+The default e-mails sent by webform are fairly basic. If you like, you may
+customize the display of e-mails sent by each individual webform.
+
+- Open the Webform module directory.
+
+- Copy (do not move!) the "webform-mail.tpl.php" file to your theme directory.
+
+- Open up the new file and edit it to your liking. The webform-mail.tpl.php file
+ contains further instructions on how to get started with theming the e-mail.
+
+- If you want to edit the e-mail sent by only one particular webform, rename the
+ file "webform-mail-[node id here].tpl.php", replacing [node id here] with the
+ node ID of the webform.
+
+- Clear the theme cache! Visit admin/settings/performance and click the
+ "Clear cached data" button at the bottom of the page. You may also find
+ using devel module will speed up this process a bit. This needs to be done
+ every time you create or rename a .tpl.php file, but isn't necessary once
+ these files already exist.
+
+- To get a better idea of what variables are available to you, you can include
+ the print_r function in your email. Simply include the line:
+
+ <?php print_r($submission) ?>
+
+ to get a listing of all the available fields you can use in your mail.
+
+- Advanced Webform e-mail Theming: Theming the e-mail headers may also be done
+ by overriding the theme_webform_mail_headers() function from webform.module.
+ Just copy the code out of webform.module and change as necessary in your
+ template.php file. This allows you to customize the e-mail headers.
+
+Theme the confirmation page
+---------------------------
+
+After a user submits a webform, they are directed to a page that contains the
+confirmation message set in the webform node settings (assuming the form doesn't
+direct to a complete URL). These instructions let you customize the format of
+the confirmation page of a single node or all webforms on your site.
+
+- Open the Webform module directory.
+
+- Copy (do not move!) the "webform-confirmation.tpl.php" file to your theme
+ directory.
+
+- Open the new file and change it's contents to the your liking. Here's an
+ example that inserts some additional HTML around the confirmation message and
+ gives links to edit the submission.
+
+ <?php /* Begin sample webform confirmation page */ ?>
+
+ <div class="confirmation-message">
+ <?php print $confirmation_message ?>
+ </div>
+
+ <ul>
+ <li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid)?>">View your submission</a></li>
+ <li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid .'/edit')?>">Edit your submission</a></li>
+ </ul>
+
+ <?php /* End sample webform confirmation page */ ?>
+
+- You may edit the webform-confirmation.tpl.php file in your theme directory,
+ this will affect all the webform mails sent by your entire site. Or, if you
+ want to edit the e-mail sent by only one particular webform, rename the file
+ "webform-confirmation-[node id here].tpl.php", replacing [node id here] with
+ the node ID of the webform.
+
+- Visit admin/settings/performance and click the "Clear cached data" button.
+
+Theme display of an entire webform
+----------------------------------
+
+Theming a webform can be useful for rearranging elements or customizing the
+appearance of multiple components at once. This tutorial assumes usage
+of the phptemplate engine.
+
+- Copy the "webform-form.tpl.php" file from the webform directory to your
+ theme directory. You may rename this file
+ "webform-form-[node id here].tpl.php" if you want to theme one particular
+ webform on your site. Replace [node id here] with the node ID of the webform.
+
+- Open up your new file and customize the webform however you like.
+
+- Visit admin/settings/performance and click the "Clear cached data" button.
+
+- All Webform forms have 2 main fieldsets: "submitted", and "details". Although
+ you may move things around as you wish, keep all your components within the
+ "submitted" fieldset. Only the "submitted" fieldset is displayed and Webform
+ depends on the other two to operate properly, so don't mess with them unless
+ you have good reason to do so (like you're forwarding your webform to a custom
+ PHP or PERL script).
+
+Theme display of a webform submission display
+---------------------------------------------
+
+Theming the display of a webform submission works the same way as theming a
+webform form. Webform uses Drupal "renderable" style arrays for the display of
+submissions, just like most forms in Drupal.
+
+The template file for theming submissions is webform-submission.tpl.php. You can
+use webform-submission-[node id here].tpl.php for individual nodes if desired.
+Note that the contents of this template are used not only for display of
+submissions in the Webform interface but also in e-mails when printing out
+the %email_values token.
+
View
433 www/sites/all/modules/webform/components/date.inc
@@ -0,0 +1,433 @@
+<?php
+
+/**
+ * @file
+ * Webform module date component.
+ */
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_date() {
+ return array(
+ 'name' => '',
+ 'form_key' => NULL,
+ 'pid' => 0,
+ 'weight' => 0,
+ 'value' => '',
+ 'mandatory' => 0,
+ 'extra' => array(
+ 'timezone' => 'user',
+ 'start_date' => '-2 years',
+ 'end_date' => '+2 years',
+ 'year_textfield' => 0,
+ 'datepicker' => 1,
+ 'title_display' => 0,
+ 'description' => '',
+ 'private' => FALSE,
+ ),
+ );
+}
+
+/**
+ * Implements _webform_theme_component().
+ */
+function _webform_theme_date() {
+ return array(
+ 'webform_date' => array(
+ 'render element' => 'element',
+ 'file' => 'components/date.inc',
+ ),
+ 'webform_display_date' => array(
+ 'render element' => 'element',
+ 'file' => 'components/date.inc',
+ ),
+ 'webform_calendar' => array(
+ 'variables' => array('component' => NULL, 'calendar_classes' => NULL),
+ 'template' => 'templates/webform-calendar',
+ ),
+ );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_date($component) {
+ $form = array();
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Default value'),
+ '#default_value' => $component['value'],
+ '#description' => t('The default value of the field.') . '<br />' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.'),
+ '#size' => 60,
+ '#maxlength' => 127,
+ '#weight' => 0,
+ );
+ $form['extra']['timezone'] = array(
+ '#type' => 'radios',
+ '#title' => t('Default value timezone'),
+ '#default_value' => empty($component['extra']['timezone']) ? 'user' : $component['extra']['timezone'],
+ '#description' => t('If using relative dates for a default value (e.g. "today") base the current day on this timezone.'),
+ '#options' => array('user' => t('User timezone'), 'site' => t('Website timezone')),
+ '#weight' => 2,
+ '#access' => variable_get('configurable_timezones', 1),
+ );
+
+ $form['display']['datepicker'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable popup calendar'),
+ '#default_value' => $component['extra']['datepicker'],
+ '#description' => t('Enable a JavaScript date picker next to the date field.'),
+ '#weight' => 2,
+ '#parents' => array('extra', 'datepicker'),
+ );
+
+ $form['display']['year_textfield'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use a textfield for year'),
+ '#default_value' => $component['extra']['year_textfield'],
+ '#description' => t('If checked, the generated date field will use a textfield for the year. Otherwise it will use a select list.'),
+ '#weight' => 5,
+ '#parents' => array('extra', 'year_textfield'),
+ );
+
+ $form['validation']['start_date'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Start date'),
+ '#default_value' => $component['extra']['start_date'],
+ '#description' => t('The earliest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
+ '#size' => 30,
+ '#weight' => 3,
+ '#parents' => array('extra', 'start_date'),
+ );
+ $form['validation']['end_date'] = array(
+ '#type' => 'textfield',
+ '#title' => t('End date'),
+ '#default_value' => $component['extra']['end_date'],
+ '#description' => t('The latest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
+ '#size' => 30,
+ '#weight' => 4,
+ '#parents' => array('extra', 'end_date'),
+ );
+
+ return $form;
+}
+
+/**
+ * Implements _webform_render_component().
+ */
+function _webform_render_date($component, $value = NULL, $filter = TRUE) {
+ $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+ $element = array(
+ '#type' => 'date',
+ '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+ '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+ '#weight' => $component['weight'],
+ '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+ '#required' => $component['mandatory'],
+ '#start_date' => trim($component['extra']['start_date']),
+ '#end_date' => trim($component['extra']['end_date']),
+ '#year_textfield' => $component['extra']['year_textfield'],
+ '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
+ '#timezone' => $component['extra']['timezone'],
+ '#process' => array('webform_expand_date'),
+ '#theme' => 'webform_date',
+ '#theme_wrappers' => array('webform_element'),
+ '#element_validate' => array('webform_validate_date'),
+ '#translatable' => array('title', 'description'),
+ );
+
+ if ($component['extra']['datepicker']) {
+ $element['#datepicker'] = TRUE;
+ $element['#attached'] = array(
+ 'library' => array(
+ array('system', 'ui.datepicker'),
+ ),
+ );
+ }
+
+ // Set the value from Webform.
+ if (isset($value[0]) && $value[0] !== '') {
+ $value = webform_date_array($value[0], 'date');
+ $element['#default_value'] = $value;
+ }
+
+ return $element;
+}
+
+/**
+ * Form API #process function for Webform date fields.
+ */
+function webform_expand_date($element) {
+ // Accept a string or array value for #default_value.
+ if (!empty($element['#default_value']) && is_string($element['#default_value'])) {
+ $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
+ $timestring = webform_strtodate('c', $element['#default_value'], $timezone);
+ $element['#default_value'] = webform_date_array($timestring, 'date');
+ }
+
+ // Set defaults according to existing #default_value (set by Form API)
+ if (isset($element['#default_value']['month']) || isset($element['#default_value']['day']) || isset($element['#default_value']['year'])) {
+ $default_values = array(
+ 'month' => $element['#default_value']['month'],
+ 'day' => $element['#default_value']['day'],
+ 'year' => $element['#default_value']['year'],
+ );
+ }
+ else {
+ $default_values = array(
+ 'day' => NULL,
+ 'month' => NULL,
+ 'year' => NULL,
+ );
+ }
+
+ // Let Drupal do it's normal expansion.
+ $element = form_process_date($element);
+
+ // Set default values.
+ foreach ($default_values as $type => $value) {
+ switch ($type) {
+ case 'month':
+ $none = t('Month');
+ break;
+ case 'day':
+ $none = t('Day');
+ break;
+ case 'year':
+ $none = t('Year');
+ break;
+ }
+ unset($element[$type]['#value']);
+ $element[$type]['#default_value'] = isset($default_values[$type]) ? $default_values[$type] : NULL;
+ $element[$type]['#options'] = array('' => $none) + $element[$type]['#options'];
+ }
+
+ // Convert relative dates to absolute ones.
+ foreach (array('start_date', 'end_date') as $start_end) {
+ $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
+ $date = webform_strtodate('Y-m-d', $element['#' . $start_end], $timezone);
+ $element['#' . $start_end] = $date ? $date : '';
+ }
+
+ // Tweak the year field.
+ if ($element['#year_textfield']) {
+ $element['year']['#type'] = 'textfield';
+ $element['year']['#size'] = 5;
+ $element['year']['#maxlength'] = 4;
+ unset($element['year']['#options']);
+ }
+ elseif ($element['#start_date'] || $element['#end_date']) {
+ $start_year = $element['#start_date'] ? webform_strtodate('Y', $element['#start_date']) : webform_strtodate('Y', '-2 years');
+ $end_year = $element['#end_date'] ? webform_strtodate('Y', $element['#end_date']) : webform_strtodate('Y', '+2 years');
+ $element['year']['#options'] = array('' => t('Year')) + drupal_map_assoc(range($start_year, $end_year));
+ }
+
+ return $element;
+}
+
+/**
+ * Theme a webform date element.
+ */
+function theme_webform_date($variables) {
+ $element = $variables['element'];
+
+ $element['year']['#attributes']['class'] = array('year');
+ $element['month']['#attributes']['class'] = array('month');
+ $element['day']['#attributes']['class'] = array('day');
+
+ // Add error classes to all items within the element.
+ if (form_get_error($element)) {
+ $element['year']['#attributes']['class'][] = 'error';
+ $element['month']['#attributes']['class'][] = 'error';
+ $element['day']['#attributes']['class'][] = 'error';
+ }
+
+ $class = array('webform-container-inline');
+
+ // Add the JavaScript calendar if available (provided by Date module package).
+ if (!empty($element['#datepicker'])) {
+ $class[] = 'webform-datepicker';
+ $calendar_class = array('webform-calendar');
+ if ($element['#start_date']) {
+ $calendar_class[] = 'webform-calendar-start-' . $element['#start_date'];
+ }
+ if ($element['#end_date']) {
+ $calendar_class[] = 'webform-calendar-end-' . $element['#end_date'];
+ }
+ $calendar_class[] ='webform-calendar-day-' . variable_get('date_first_day', 0);
+
+ $calendar = theme('webform_calendar', array('component' => $element['#webform_component'], 'calendar_classes' => $calendar_class));
+ }
+
+ $output = '';
+ $output .= '<div class="' . implode(' ', $class) . '">';
+ $output .= drupal_render_children($element);
+ $output .= isset($calendar) ? $calendar : '';
+ $output .= '</div>';
+
+ return $output;
+}
+
+/**
+ * Element validation for Webform date fields.
+ */
+function webform_validate_date($element, $form_state) {
+ // Check if the user filled the required fields.
+ foreach (array('day', 'month', 'year') as $field_type) {
+ if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
+ form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
+ return;
+ }
+ }
+
+ if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
+ // Check for a valid date.
+ if (!checkdate((int) $element['month']['#value'], (int) $element['day']['#value'], (int) $element['year']['#value'])) {
+ form_error($element, t('Entered !name is not a valid date.', array('!name' => $element['#title'])));
+ return;
+ }
+
+ // Create a timestamp of the entered value for comparison.
+ $timestamp = strtotime($element['year']['#value'] . '-' . $element['month']['#value'] . '-' . $element['day']['#value']);
+ $format = webform_date_format('short');
+
+ // Flip start and end if needed.
+ $date1 = strtotime($element['#start_date']);
+ $date2 = strtotime($element['#end_date']);
+ if ($date1 !== FALSE && $date2 !== FALSE) {
+ $start_date = $date1 < $date2 ? $date1 : $date2;
+ $end_date = $date1 > $date2 ? $date1 : $date2;
+ }
+ else {
+ $start_date = $date1;
+ $end_date = $date2;
+ }
+
+ // Check that the date is after the start date.
+ if ($start_date !== FALSE) {
+ if ($timestamp < $start_date) {
+ form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
+ }
+ }
+
+ // Check that the date is before the end date.
+ if ($end_date !== FALSE) {
+ if ($timestamp > $end_date) {
+ form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
+ }
+ }
+ }
+}
+
+/**
+ * Implements _webform_submit_component().
+ */
+function _webform_submit_date($component, $value) {
+ // Convert the date to an ISO 8601 format.
+ return ($value['year'] && $value['month'] && $value['day']) ? webform_date_string($value, 'date') : '';
+}
+
+/**
+ * Implements _webform_display_component().
+ */
+function _webform_display_date($component, $value, $format = 'html') {
+ $value = webform_date_array(isset($value[0]) ? $value[0] : '', 'date');
+
+ return array(
+ '#title' => $component['name'],
+ '#weight' => $component['weight'],
+ '#theme' => 'webform_display_date',
+ '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+ '#format' => $format,
+ '#value' => $value,
+ '#translatable' => array('title'),
+ );
+}
+
+/**
+ * Format the text output for this component.
+ */
+function theme_webform_display_date($variables) {
+ $element = $variables['element'];
+ $output = ' ';
+ if ($element['#value']['year'] && $element['#value']['month'] && $element['#value']['day']) {
+ $timestamp = webform_strtotime($element['#value']['month'] . '/' . $element['#value']['day'] . '/' . $element['#value']['year']);
+ $format = webform_date_format('medium');
+ $output = format_date($timestamp, 'custom', $format, 'UTC');
+ }
+
+ return $output;
+}
+
+/**
+ * Implements _webform_analysis_component().
+ */
+function _webform_analysis_date($component, $sids = array()) {
+ $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('wsd', array('no', 'data'))
+ ->condition('nid', $component['nid'])
+ ->condition('cid', $component['cid'])
+ ->orderBy('sid');
+
+ if (count($sids)) {
+ $query->condition('sid', $sids, 'IN');
+ }
+
+ $result = $query->execute();
+
+ $dates = array();
+ $submissions = 0;
+ foreach ($result as $row) {
+ $submissions++;
+ if ($row['data']) {
+ $dates[] = webform_date_array($row['data']);
+ }
+ }
+
+ // Display stats.
+ $nonblanks = count($dates);
+ $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+ $rows[1] = array(t('User entered value'), $nonblanks);
+ return $rows;
+}
+
+/**
+ * Implements _webform_table_component().
+ */
+function _webform_table_date($component, $value) {
+ if ($value[0]) {
+ $timestamp = webform_strtotime($value[0]);
+ $format = webform_date_format('short');
+ return format_date($timestamp, 'custom', $format, 'UTC');
+ }
+ else {
+ return '';
+ }
+}
+
+/**
+ * Implements _webform_csv_headers_component().
+ */
+function _webform_csv_headers_date($component, $export_options) {
+ $header = array();
+ $header[0] = '';
+ $header[1] = '';
+ $header[2] = $component['name'];
+ return $header;
+}
+
+/**
+ * Implements _webform_csv_data_component().
+ */
+function _webform_csv_data_date($component, $export_options, $value) {
+ if ($value[0]) {
+ $timestamp = webform_strtotime($value[0]);
+ $format = webform_date_format('short');
+ return format_date($timestamp, 'custom', $format, 'UTC');
+ }
+ else {
+ return '';
+ }
+}
View
285 www/sites/all/modules/webform/components/email.inc
@@ -0,0 +1,285 @@
+<?php
+
+/**
+ * @file
+ * Webform module email component.
+ */
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_email() {
+ return array(
+ 'name' => '',
+ 'form_key' => NULL,
+ 'pid' => 0,
+ 'weight' => 0,
+ 'value' => '',
+ 'mandatory' => 0,
+ 'extra' => array(
+ 'width' => '',
+ 'unique' => 0,
+ 'disabled' => 0,
+ 'title_display' => 0,
+ 'description' => '',
+ 'attributes' => array(),
+ 'private' => FALSE,
+ ),
+ );
+}
+
+/**
+ * Implements _webform_theme_component().
+ */
+function _webform_theme_email() {
+ return array(
+ 'webform_email' => array(
+ 'render element' => 'element',
+ 'file' => 'components/email.inc',
+ ),
+ 'webform_display_email' => array(
+ 'render element' => 'element',
+ 'file' => 'components/email.inc',
+ ),
+ );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_email($component) {
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Default value'),
+ '#default_value' => $component['value'],
+ '#description' => t('The default value of the field.') . theme('webform_token_help'),
+ '#size' => 60,
+ '#maxlength' => 127,
+ '#weight' => 0,
+ '#attributes' => ($component['value'] == '%useremail' && count(form_get_errors()) == 0) ? array('disabled' => TRUE) : array(),
+ '#id' => 'email-value',
+ );
+ $form['user_email'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('User email as default'),
+ '#default_value' => $component['value'] == '%useremail' ? 1 : 0,
+ '#description' => t('Set the default value of this field to the user email, if he/she is logged in.'),
+ '#attributes' => array('onclick' => 'getElementById("email-value").value = (this.checked ? "%useremail" : ""); getElementById("email-value").disabled = this.checked;'),
+ '#weight' => 0,
+ '#element_validate' => array('_webform_edit_email_validate'),
+ );
+ $form['display']['width'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Width'),
+ '#default_value' => $component['extra']['width'],
+ '#description' => t('Width of the textfield.') . ' ' . t('Leaving blank will use the default size.'),
+ '#size' => 5,
+ '#maxlength' => 10,
+ '#parents' => array('extra', 'width'),
+ );
+ $form['display']['disabled'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Disabled'),
+ '#return_value' => 1,
+ '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'),
+ '#weight' => 11,
+ '#default_value' => $component['extra']['disabled'],
+ '#parents' => array('extra', 'disabled'),
+ );
+ $form['validation']['unique'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Unique'),
+ '#return_value' => 1,
+ '#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
+ '#weight' => 1,
+ '#default_value' => $component['extra']['unique'],
+ '#parents' => array('extra', 'unique'),
+ );
+ return $form;
+}
+
+/**
+ * Element validation function for the email edit form.
+ */
+function _webform_edit_email_validate($element, &$form_state) {
+ if ($form_state['values']['user_email']) {
+ $form_state['values']['value'] = '%useremail';
+ }
+}
+
+/**
+ * Implements _webform_render_component().
+ */
+function _webform_render_email($component, $value = NULL, $filter = TRUE) {
+ global $user;
+ $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+ $element = array(
+ '#type' => 'webform_email',
+ '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+ '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+ '#default_value' => $filter ? _webform_filter_values($component['value'], $node) : $component['value'],
+ '#required' => $component['mandatory'],
+ '#weight' => $component['weight'],
+ '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+ '#attributes' => $component['extra']['attributes'],
+ '#element_validate' => array('_webform_validate_email'),
+ '#theme_wrappers' => array('webform_element'),
+ '#translatable' => array('title', 'description'),
+ );
+
+ // Add an e-mail class for identifying the difference from normal textfields.
+ $element['#attributes']['class'][] = 'email';
+
+ // Enforce uniqueness.
+ if ($component['extra']['unique']) {
+ $element['#element_validate'][] = 'webform_validate_unique';
+ }
+
+ if (isset($value)) {
+ $element['#default_value'] = $value[0];
+ }
+
+ if ($component['extra']['disabled']) {
+ if ($filter) {
+ $element['#attributes']['readonly'] = 'readonly';
+ }
+ else {
+ $element['#disabled'] = TRUE;
+ }
+ }
+
+ // Change the 'width' option to the correct 'size' option.
+ if ($component['extra']['width'] > 0) {
+ $element['#size'] = $component['extra']['width'];
+ }
+
+ return $element;
+}
+
+/**
+ * Theme function to render an email component.
+ */
+function theme_webform_email($variables) {
+ $element = $variables['element'];
+
+ // This IF statement is mostly in place to allow our tests to set type="text"
+ // because SimpleTest does not support type="email".
+ if (!isset($element['#attributes']['type'])) {
+ $element['#attributes']['type'] = 'email';
+ }
+
+ // Convert properties to attributes on the element if set.
+ foreach (array('id', 'name', 'value', 'size') as $property) {
+ if (isset($element['#' . $property]) && $element['#' . $property] !== '') {
+ $element['#attributes'][$property] = $element['#' . $property];
+ }
+ }
+ _form_set_class($element, array('form-text', 'form-email'));
+
+ return '<input' . drupal_attributes($element['#attributes']) . ' />';
+}
+
+/**
+ * A Drupal Form API Validation function. Validates the entered values from
+ * email components on the client-side form.
+ *
+ * @param $form_element
+ * The e-mail form element.
+ * @param $form_state
+ * The full form state for the webform.
+ * @return
+ * None. Calls a form_set_error if the e-mail is not valid.
+ */
+function _webform_validate_email($form_element, &$form_state) {
+ $component = $form_element['#webform_component'];
+ $value = trim($form_element['#value']);
+ if ($value !== '' && !valid_email_address($value)) {
+ form_error($form_element, t('%value is not a valid email address.', array('%value' => $value)));
+ }
+ else {
+ form_set_value($form_element, $value, $form_state);
+ }
+}
+
+/**
+ * Implements _webform_display_component().
+ */
+function _webform_display_email($component, $value, $format = 'html') {
+ return array(
+ '#title' => $component['name'],
+ '#weight' => $component['weight'],
+ '#theme' => 'webform_display_email',
+ '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+ '#format' => $format,
+ '#value' => isset($value[0]) ? $value[0] : '',
+ '#translatable' => array('title'),
+ );
+}
+
+/**
+ * Format the text output for this component.
+ */
+function theme_webform_display_email($variables) {
+ $element = $variables['element'];
+ $element['#value'] = empty($element['#value']) ? ' ' : $element['#value'];
+ return $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
+}
+
+/**
+ * Implements _webform_analysis_component().
+ */
+function _webform_analysis_email($component, $sids = array()) {
+ $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('wsd', array('no', 'data'))
+ ->condition('nid', $component['nid'])
+ ->condition('cid', $component['cid']);
+
+ if (count($sids)) {
+ $query->condition('sid', $sids, 'IN');
+ }
+
+ $nonblanks = 0;
+ $submissions = 0;
+ $wordcount = 0;
+
+ $result = $query->execute();
+ foreach ($result as $data) {
+ if (drupal_strlen(trim($data['data'])) > 0) {
+ $nonblanks++;
+ $wordcount += str_word_count(trim($data['data']));
+ }
+ $submissions++;
+ }
+
+ $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+ $rows[1] = array(t('User entered value'), $nonblanks);
+ $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
+ return $rows;
+}
+
+/**
+ * Implements _webform_table_component().
+ */
+function _webform_table_email($component, $value) {
+ return check_plain(empty($value[0]) ? '' : $value[0]);
+}
+
+
+/**
+ * Implements _webform_csv_headers_component().
+ */
+function _webform_csv_headers_email($component, $export_options) {
+ $header = array();
+ $header[0] = '';
+ $header[1] = '';
+ $header[2] = $component['name'];
+ return $header;
+}
+
+/**
+ * Implements _webform_csv_data_component().
+ */
+function _webform_csv_data_email($component, $export_options, $value) {
+ return empty($value[0]) ? '' : $value[0];
+}
View
100 www/sites/all/modules/webform/components/fieldset.inc
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Webform module fieldset component.
+ */
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_fieldset() {
+ return array(
+ 'name' => '',
+ 'form_key' => NULL,
+ 'pid' => 0,
+ 'weight' => 0,
+ 'extra' => array(
+ 'title_display' => 0,
+ 'collapsible' => 0,
+ 'collapsed' => 0,
+ 'description' => '',
+ 'private' => FALSE,
+ ),
+ );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_fieldset($component) {
+ $form = array();
+ $form['display']['collapsible'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Collapsible'),
+ '#default_value' => $component['extra']['collapsible'],
+ '#description' => t('If this fieldset is collapsible, the user may open or close the fieldset.'),
+ '#weight' => 0,
+ '#parents' => array('extra', 'collapsible'),
+ );
+ $form['display']['collapsed'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Collapsed by Default'),
+ '#default_value' => $component['extra']['collapsed'],
+ '#description' => t('Collapsible fieldsets are "open" by default. Select this option to default the fieldset to "closed."'),
+ '#weight' => 3,
+ '#parents' => array('extra', 'collapsed'),
+ );
+ return $form;
+}
+
+/**
+ * Implements _webform_render_component().
+ */
+function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
+ $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+ $element = array(
+ '#type' => 'fieldset',
+ '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+ '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : NULL,
+ '#weight' => $component['weight'],
+ '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+ '#collapsible' => $component['extra']['collapsible'],
+ '#collapsed' => $component['extra']['collapsed'],
+ '#attributes' => array('class' => array('webform-component-fieldset'), 'id' => 'webform-component-' . $component['form_key']),
+ '#pre_render' => array('webform_fieldset_prerender', 'webform_element_title_display'),
+ '#translatable' => array('title', 'description'),
+ );
+
+ return $element;
+}
+
+/**
+ * Pre-render function to set a fieldset ID.
+ */
+function webform_fieldset_prerender($element) {
+ $element['#attributes']['id'] = 'webform-component-' . str_replace('_', '-', implode('--', array_slice($element['#parents'], 1)));
+ return $element;
+}
+
+/**
+ * Implements _webform_display_component().
+ */
+function _webform_display_fieldset($component, $value, $format = 'html') {
+ if ($format == 'text') {
+ $element = array(
+ '#title' => $component['name'],
+ '#weight' => $component['weight'],
+ '#theme_wrappers' => array('webform_element_text'),
+ '#translatable' => array('title'),
+ );
+ }
+ else {
+ $element = _webform_render_fieldset($component, $value);
+ }
+
+ $element['#format'] = $format;
+
+ return $element;
+}
View
531 www/sites/all/modules/webform/components/file.inc
@@ -0,0 +1,531 @@
+<?php
+
+/**
+ * @file
+ * Webform module file component.
+ */
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_file() {
+ return array(
+ 'name' => '',
+ 'form_key' => NULL,
+ 'mandatory' => 0,
+ 'pid' => 0,
+ 'weight' => 0,
+ 'extra' => array(
+ 'filtering' => array(
+ 'types' => array('gif', 'jpg', 'png'),
+ 'addextensions' => '',
+ 'size' => '2 MB',
+ ),
+ 'scheme' => 'public',
+ 'directory' => '',
+ 'progress_indicator' => 'throbber',
+ 'title_display' => 0,
+ 'description' => '',
+ 'attributes' => array(),
+ 'private' => FALSE,
+ ),
+ );
+}
+
+/**
+ * Implements _webform_theme_component().
+ */
+function _webform_theme_file() {
+ return array(
+ 'webform_edit_file_extensions' => array(
+ 'render element' => 'element',
+ 'file' => 'components/file.inc',
+ ),
+ 'webform_display_file' => array(
+ 'render element' => 'element',
+ 'file' => 'components/file.inc',
+ ),
+ );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_file($component) {
+ $form = array();
+ $form['#element_validate'] = array('_webform_edit_file_check_directory');
+ $form['#after_build'] = array('_webform_edit_file_check_directory');
+
+ $form['validation']['size'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Max upload size'),
+ '#default_value' => $component['extra']['filtering']['size'],
+ '#description' => t('Enter the max file size a user may upload such as 2 MB or 800 KB. Your server has a max upload size of @size.', array('@size' => format_size(file_upload_max_size()))),
+ '#size' => 10,
+ '#parents' => array('extra', 'filtering', 'size'),
+ '#element_validate' => array('_webform_edit_file_size_validate'),
+ '#weight' => 1,
+ );
+
+ $form['validation']['extensions'] = array(
+ '#element_validate' => array('_webform_edit_file_extensions_validate'),
+ '#parents' => array('extra', 'filtering'),
+ '#theme' => 'webform_edit_file_extensions',
+ '#theme_wrappers' => array('form_element'),
+ '#title' => t('Allowed file extensions'),
+ '#attached' => array(
+ 'js' => array(drupal_get_path('module', 'webform') . '/js/webform-admin.js'),
+ 'css' => array(drupal_get_path('module', 'webform') . '/css/webform-admin.css'),
+ ),
+ '#weight' => 2,
+ );
+
+ // Find the list of all currently valid extensions.
+ $current_types = isset($component['extra']['filtering']['types']) ? $component['extra']['filtering']['types'] : array();
+
+ $types = array('gif', 'jpg', 'png');
+ $form['validation']['extensions']['types']['webimages'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Web images'),
+ '#options' => drupal_map_assoc($types),
+ '#default_value' => array_intersect($current_types, $types),
+ );
+
+ $types = array('bmp', 'eps', 'tif', 'pict', 'psd');
+ $form['validation']['extensions']['types']['desktopimages'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Desktop images'),
+ '#options' => drupal_map_assoc($types),
+ '#default_value' => array_intersect($current_types, $types),
+ );
+
+ $types = array('txt', 'rtf', 'html', 'odf', 'pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'xml');
+ $form['validation']['extensions']['types']['documents'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Documents'),
+ '#options' => drupal_map_assoc($types),
+ '#default_value' => array_intersect($current_types, $types),
+ );
+
+ $types = array('avi', 'mov', 'mp3', 'ogg', 'wav');
+ $form['validation']['extensions']['types']['media'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Media'),
+ '#options' => drupal_map_assoc($types),
+ '#default_value' => array_intersect($current_types, $types),
+ );
+
+ $types = array('bz2', 'dmg', 'gz', 'jar', 'rar', 'sit', 'tar', 'zip');
+ $form['validation']['extensions']['types']['archives'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Archives'),
+ '#options' => drupal_map_assoc($types),
+ '#default_value' => array_intersect($current_types, $types),
+ );
+
+ $form['validation']['extensions']['addextensions'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Additional extensions'),
+ '#default_value' => $component['extra']['filtering']['addextensions'],
+ '#description' => t('Enter a list of additional file extensions for this upload field, seperated by commas.<br /> Entered extensions will be appended to checked items above.'),
+ '#size' => 20,
+ '#weight' => 3,
+ );
+
+ $scheme_options = array();
+ foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
+ $scheme_options[$scheme] = $stream_wrapper['name'];
+ }
+ $form['extra']['scheme'] = array(
+ '#type' => 'radios',
+ '#title' => t('Upload destination'),
+ '#options' => $scheme_options,
+ '#default_value' => $component['extra']['scheme'],
+ '#description' => t('Private file storage has significantly more overhead than public files, but restricts file access to users who can view submissions.'),
+ '#weight' => 4,
+ '#access' => count($scheme_options) > 1,
+ );
+ $form['extra']['directory'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Upload directory'),
+ '#default_value' => $component['extra']['directory'],
+ '#description' => t('You may optionally specify a sub-directory to store your files.'),
+ '#weight' => 5,
+ '#field_prefix' => 'webform/',
+ );
+
+ $form['display']['progress_indicator'] = array(
+ '#type' => 'radios',
+ '#title' => t('Progress indicator'),
+ '#options' => array(
+ 'throbber' => t('Throbber'),
+ 'bar' => t('Bar with progress meter'),
+ ),
+ '#default_value' => $component['extra']['progress_indicator'],
+ '#description' => t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
+ '#weight' => 16,
+ '#access' => file_progress_implementation(),
+ '#parents' => array('extra', 'progress_indicator'),
+ );
+
+ // TODO: Make managed_file respect the "size" parameter.
+ /*
+ $form['display']['width'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Width'),
+ '#default_value' => $component['extra']['width'],
+ '#description' => t('Width of the file field.') . ' ' . t('Leaving blank will use the default size.'),
+ '#size' => 5,
+ '#maxlength' => 10,
+ '#weight' => 4,
+ '#parents' => array('extra', 'width')
+ );
+ */
+
+ return $form;
+}
+
+/**
+ * A Form API element validate function to check filesize is valid.
+ */
+function _webform_edit_file_size_validate($element) {
+ if (!empty($element['#value'])) {
+ $set_filesize = parse_size($element['#value']);
+ if ($set_filesize == FALSE) {
+ form_error($element, t('File size @value is not a valid filesize. Use a value such as 2 MB or 800 KB.', array('@value' => $element['#value'])));
+ }
+ else {
+ $max_filesize = parse_size(file_upload_max_size());
+ if ($max_filesize < $set_filesize) {
+ form_error($element, t('An upload size of @value is too large, you are allow to upload files @max or less.', array('@value' => $element['#value'], '@max' => format_size($max_filesize))));
+ }
+ }
+ }
+}
+
+/**
+ * A Form API after build and validate function.
+ *
+ * Ensure that the destination directory exists and is writable.
+ */
+function _webform_edit_file_check_directory($element) {
+ $scheme = $element['extra']['scheme']['#value'];
+ $directory = $element['extra']['directory']['#value'];
+
+ $destination_dir = file_stream_wrapper_uri_normalize($scheme . '://' . $directory . '/webform');
+
+ // Sanity check input to prevent use parent (../) directories.
+ if (preg_match('/\.\.[\/\\\]/', $destination_dir . '/')) {
+ form_error($element['extra']['directory'], t('The save directory %directory is not valid.', array('%directory' => $directory)));
+ }
+ else {
+ $destination_success = file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
+ if (!$destination_success) {
+ form_error($element['extra']['directory'], t('The save directory %directory could not be created. Check that the webform files directory is writable.', array('%directory' => $directory)));
+ }
+ }
+
+ return $element;
+}
+
+/**
+ * A Form API element validate function.
+ *
+ * Change the submitted values of the component so that all filtering extensions
+ * are saved as a single array.
+ */
+function _webform_edit_file_extensions_validate($element, &$form_state) {
+ // Predefined types.
+ $extensions = array();
+ foreach (element_children($element['types']) as $category) {
+ foreach (array_keys($element['types'][$category]['#value']) as $extension) {
+ if ($element['types'][$category][$extension]['#value']) {
+ $extensions[] = $extension;
+ }
+ }
+ }
+
+ // Additional types.
+ $additional_extensions = explode(',', $element['addextensions']['#value']);
+ foreach ($additional_extensions as $extension) {
+ $clean_extension = drupal_strtolower(trim($extension));
+ if (!empty($clean_extension) && !in_array($clean_extension, $extensions)) {
+ $extensions[] = $clean_extension;
+ }
+ }
+
+ form_set_value($element['types'], $extensions, $form_state);
+}
+
+/**
+ * Output the list of allowed extensions as checkboxes.
+ */
+function theme_webform_edit_file_extensions($variables) {
+ $element = $variables['element'];
+
+ // Format the components into a table.
+ $rows = array();
+ foreach (element_children($element['types']) as $filtergroup) {
+ $row = array();
+ $first_row = count($rows);
+ if ($element['types'][$filtergroup]['#type'] == 'checkboxes') {
+ $select_link = ' <a href="#" class="webform-select-link webform-select-link-' . $filtergroup . '">(' . t('select') . ')</a>';
+ $row[] = $element['types'][$filtergroup]['#title'];
+ $row[] = array('data' => $select_link, 'width' => 40);
+ $row[] = array('data' => drupal_render_children($element['types'][$filtergroup]), 'class' => array('webform-file-extensions', 'webform-select-group-' . $filtergroup));
+ $rows[] = array('data' => $row);
+ unset($element['types'][$filtergroup]);
+ }
+ }
+
+ // Add the row for additional types.
+ $row = array();
+ $title = $element['addextensions']['#title'];
+ $element['addextensions']['#title'] = NULL;
+ $row[] = array('data' => $title, 'colspan' => 2);
+ $row[] = drupal_render($element['addextensions']);
+ $rows[] = $row;
+
+ $header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types')));
+
+ // Create the table inside the form.
+ $element['types']['table'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ '#attributes' => array('class' => array('webform-file-extensions')),
+ );
+
+ return drupal_render_children($element);
+}
+
+/**
+ * Implements _webform_render_component().
+ */
+function _webform_render_file($component, $value = NULL, $filter = TRUE) {
+ $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+ // Cap the upload size according to the PHP limit.
+ $max_filesize = parse_size(file_upload_max_size());
+ $set_filesize = $component['extra']['filtering']['size'];
+ if (!empty($set_filesize) && parse_size($set_filesize) < $max_filesize) {
+ $max_filesize = parse_size($set_filesize);
+ }
+
+ $element = array(
+ '#type' => 'managed_file',
+ '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+ '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+ '#required' => $component['mandatory'],
+ '#default_value' => isset($value[0]) ? $value[0] : NULL,
+ '#attributes' => $component['extra']['attributes'],
+ '#upload_validators' => array(
+ 'file_validate_size' => array($max_filesize),
+ 'file_validate_extensions' => array(implode(' ', $component['extra']['filtering']['types'])),
+ ),
+ '#pre_render' => array_merge(element_info_property('managed_file', '#pre_render'), array('webform_file_allow_access')),
+ '#upload_location' => $component['extra']['scheme'] . '://webform/' . $component['extra']['directory'],
+ '#progress_indicator' => $component['extra']['progress_indicator'],
+ '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+ '#weight' => $component['weight'],
+ '#theme_wrappers' => array('webform_element'),
+ '#translatable' => array('title', 'description'),
+ );
+
+ return $element;
+}
+
+/**
+ * Implements _webform_submit_component().
+ */
+function _webform_submit_file($component, $value) {
+ if (is_array($value)) {
+ return !empty($value['fid']) ? $value['fid'] : '';
+ }
+ else {
+ return !empty($value) ? $value : '';
+ }
+}
+
+/**
+ * Pre-render callback to allow access to uploaded files.
+ *
+ * Files that have not yet been saved into a submission must be accessible to
+ * the user who uploaded it, but no one else. After the submission is saved,
+ * access is granted through the file_usage table. Before then, we use a
+ * $_SESSION value to record a user's upload.
+ *
+ * @see webform_file_download()
+ */
+function webform_file_allow_access($element) {
+ if (!empty($element['#value']['fid'])) {
+ $fid = $element['#value']['fid'];
+ $_SESSION['webform_files'][$fid] = $fid;
+ }
+
+ return $element;
+}
+
+/**
+ * Implements _webform_display_component().
+ */
+function _webform_display_file($component, $value, $format = 'html') {
+ $fid = isset($value[0]) ? $value[0] : NULL;
+ return array(
+ '#title' => $component['name'],
+ '#value' => $fid ? webform_get_file($fid) : NULL,
+ '#weight' => $component['weight'],
+ '#theme' => 'webform_display_file',
+ '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
+ '#format' => $format,
+ '#translatable' => array('title'),
+ );
+}
+
+/**
+ * Format the output of text data for this component
+ */
+function theme_webform_display_file($variables) {
+ $element = $variables['element'];
+
+ $file = $element['#value'];
+ $url = !empty($file) ? webform_file_url($file->uri) : t('no upload');
+ return !empty($file) ? ($element['#format'] == 'text' ? $url : l($file->filename, $url)) : ' ';
+}
+
+/**
+ * Implements _webform_delete_component().
+ */
+function _webform_delete_file($component, $value) {
+ // Delete an individual submission file.
+ if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
+ file_delete($file);
+ }
+}
+
+/**
+ * Implements _webform_attachments_component().
+ */
+function _webform_attachments_file($component, $value) {
+ $file = (array) webform_get_file($value[0]);
+ //This is necessary until the next release of mimemail is out, see [#1388786]
+ $file['filepath'] = $file['uri'];
+ $files = array($file);
+ return $files;
+}
+/**
+ * Implements _webform_analysis_component().
+ */
+function _webform_analysis_file($component, $sids = array()) {
+ $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('wsd', array('no', 'data'))
+ ->condition('nid', $component['nid'])
+ ->condition('cid', $component['cid']);
+
+ if (count($sids)) {
+ $query->condition('sid', $sids, 'IN');
+ }
+
+ $nonblanks = 0;
+ $sizetotal = 0;
+ $submissions = 0;
+
+ $result = $query->execute();
+ foreach ($result as $data) {
+ $file = webform_get_file($data['data']);
+ if (isset($file->filesize)) {
+ $nonblanks++;
+ $sizetotal += $file->filesize;
+ }
+ $submissions++;
+ }
+
+ $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
+ $rows[1] = array(t('User uploaded file'), $nonblanks);
+ $rows[2] = array(t('Average uploaded file size'), ($sizetotal != 0 ? (int) (($sizetotal/$nonblanks)/1024) . ' KB' : '0'));
+ return $rows;
+}
+
+/**
+ * Implements _webform_table_component().
+ */
+function _webform_table_file($component, $value) {
+ $output = '';
+ $file = webform_get_file($value[0]);
+ if (!empty($file->fid)) {
+ $output = '<a href="' . webform_file_url($file->uri) . '">' . check_plain(webform_file_name($file->uri)) . '</a>';
+ $output .= ' (' . (int) ($file->filesize/1024) . ' KB)';
+ }
+ return $output;
+}
+
+/**
+ * Implements _webform_csv_headers_component().
+ */
+function _webform_csv_headers_file($component, $export_options) {
+ $header = array();
+ // Two columns in header.
+ $header[0] = array('', '');
+ $header[1] = array($component['name'], '');
+ $header[2] = array(t('Name'), t('Filesize (KB)'));
+ return $header;
+}
+
+/**
+ * Implements _webform_csv_data_component().
+ */
+function _webform_csv_data_file($component, $export_options, $value) {
+ $file = webform_get_file($value[0]);
+ return empty($file->filename) ? array('', '') : array(webform_file_url($file->uri), (int) ($file->filesize/1024));
+}
+
+/**
+ * Helper function to create proper file names for uploaded file.
+ */
+function webform_file_name($filepath) {
+ if (!empty($filepath)) {
+ $info = pathinfo($filepath);
+ $file_name = $info['basename'];
+ }
+ return isset($file_name) ? $file_name : '';
+}
+
+/**
+ * Helper function to create proper URLs for uploaded file.
+ */
+function webform_file_url($uri) {
+ if (!empty($uri)) {
+ $file_url = file_create_url($uri);
+ }
+ return isset($file_url) ? $file_url : '';
+}
+
+/**
+ * Helper function to load a file from the database.
+ */
+function webform_get_file($fid) {
+ // Simple check to prevent loading of NULL values, which throws an entity
+ // system error.
+ return $fid ? file_load($fid) : FALSE;
+}
+
+/**
+ * Given a submission with file_usage set, add or remove file usage entries.
+ */
+function webform_file_usage_adjust($submission) {
+ if (isset($submission->file_usage)) {
+ $files = file_load_multiple($submission->file_usage['added_fids']);
+ foreach ($files as $file) {
+ $file->status = 1;
+ file_save($file);
+ file_usage_add($file, 'webform', 'submission', $submission->sid);
+ }
+
+ $files = file_load_multiple($submission->file_usage['deleted_fids']);
+ foreach ($files as $file) {
+ file_usage_delete($file, 'webform', 'submission', $submission->sid);
+ file_delete($file);
+ }
+ }
+}
+
View
428 www/sites/all/modules/webform/components/grid.inc
@@ -0,0 +1,428 @@
+<?php
+
+/**
+ * @file
+ * Webform module grid component.
+ */
+
+// Grid depends on functions provided by select.
+webform_component_include('select');
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_grid() {
+ return array(
+ 'name' => '',
+ 'form_key' => NULL,
+ 'mandatory' => 0,
+ 'pid' => 0,
+ 'weight' => 0,
+ 'extra' => array(
+ 'options' => '',
+ 'questions' => '',
+ 'optrand' => 0,
+ 'qrand' => 0,
+ 'title_display' => 0,
+ 'custom_option_keys' => 0,
+ 'custom_question_keys' => 0,
+ 'description' => '',
+ 'private' => FALSE,
+ ),
+ );
+}
+
+
+/**
+ * Implements _webform_theme_component().
+ */
+function _webform_theme_grid() {
+ return array(
+ 'webform_grid' => array(
+ 'render element' => 'element',
+ 'file' => 'components/grid.inc',
+ ),
+ 'webform_display_grid' => array(
+ 'render element' => 'element',
+ 'file' => 'components/grid.inc',
+ ),
+ );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_grid($component) {
+ $form = array();
+
+ if (module_exists('options_element')) {
+ $form['options'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Options'),
+ '#collapsible' => TRUE,
+ '#description' => t('Options to select across the top. Usually these are ratings such as "poor" through "excellent" or "strongly disagree" through "strongly agree".'),
+ '#attributes' => array('class' => array('webform-options-element')),
+ '#element_validate' => array('_webform_edit_validate_options'),
+ );
+ $form['options']['options'] = array(
+ '#type' => 'options',
+ '#options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
+ '#optgroups' => FALSE,
+ '#default_value' => FALSE,
+ '#optgroups' => FALSE,
+ '#key_type' => 'mixed',
+ '#key_type_toggle' => t('Customize option keys (Advanced)'),
+ '#key_type_toggled' => $component['extra']['custom_option_keys'],
+ );
+
+ $form['questions'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Questions'),
+ '#collapsible' => TRUE,
+ '#description' => t('Questions list down the side of the grid.'),
+ '#attributes' => array('class' => array('webform-options-element')),
+ '#element_validate' => array('_webform_edit_validate_options'),
+ );
+ $form['questions']['options'] = array(
+ '#type' => 'options',
+ '#options' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
+ '#optgroups' => FALSE,
+ '#default_value' => FALSE,
+ '#optgroups' => FALSE,
+ '#key_type' => 'mixed',
+ '#key_type_toggle' => t('Customize question keys (Advanced)'),
+ '#key_type_toggled' => $component['extra']['custom_question_keys'],
+ );
+ }
+ else {
+ $form['extra']['options'] = array(
+ '#type' => 'textarea',
+ '#title' => t(