HTML-FormHandler-0.40064000755000770000024 012576552253 14401 5ustar00gshankstaff000000000000TODO100644000770000024 17412576552253 15134 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064 Unique support for non-top-level fields? Improve example of Repeatable form (BookDB, User) to do adds & deletes with js README100644000770000024 44512576552253 15325 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064 This archive contains the distribution HTML-FormHandler, version 0.40064: HTML forms using Moose This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Changes100644000770000024 10201512576552253 16014 0ustar00gshankstaff000000000000HTML-FormHandler-0.400640.40064 Thu Sep 17, 2015 Don't warn about date format unless set to `date` Wrap checkbox in CheckboxGroup, if requested Create es_es.pm Create ca_es.pm select field invalid value message: encode the select value typo in link to the example app remove css_class from Captcha field 0.40063 Mon Jun 29, 2015 Raised Moose prereq to 2.1403 because 2.0604 causes failing tests 0.40062 Fri Jun 25, 2015 Separate out test using Type::Tiny::Enum to skip_all 0.40061 Thu Jun 25, 2015 Add skip for Type::Tiny::Enum 0.40060 Wed Jun 24, 2015 Field validation can use Type::Tiny subclasses Replace NoTabTests and EOLTests switch from List::AllUtils+List::MoreUtils to List::Util (in core) add render_elementx and renderx methods to allow setting attributes at render time Warning if Date field is html5 and not ISO 0.40059 Thu Feb 25, 2015 Remove clear->item_id that snaked in via merge error Pass subfield name to repeatable element wrapper 0.40058 Thu Feb 25, 2015 add HorizCheckboxGroup for alternative CheckboxGroup rendering minor doc typos do $class->meta->make_immutable after new_with_traits Czech translation 'get_errors' synonym for 'errors' on form add repeatable_element_wrapper ability 0.40057 Fri Aug 1, 2014 added support for tag 'inline' in bootstrap3 wrapper add test for inline-checkboxes add test for prefilled with init_object form reuse clear item and init_object which are required for form reuse add failing test for element_class override through build_update_subfields add a bit of doc about handling DBIC new results & 'use_default_over_obj' =encoding utf-8 in Manual/Rendering.pod remove deprecated css_class and input_class attributes add param_to_values method to convert parameters to init_object-like hashref Add code to respect the label_no_filter tag on checkboxes for Bootstrap and the Base widgets. fix bootstrap3 input_append_button Respect label_no_filter on checkbox labels. add Arabic translations use time_zone and locale options in Date field 0.40056 Mon Feb 20, 2014 use sorted_fields in 'dump_validated' added Type::Tiny support Use alert-danger rather than alert-error with in Bootstrap3 Fixes RT#91966 (deprecated way to call enum warning) bug in reloading repeatable fields; skip inactive fields 0.40055 Thu Jan 2, 2014 handle SelectCSV field in as_label method of Select field 2014 bug in t/compound/basic.t test (rt91793) 0.40054 Tue Nov 26, 2013 Check for old unimplemented parameter to wrap_checkbox, and check for existence of option_wrapper add language handle to bootstrap3 tests pass event to repeatable js click handler stop forcing undefined Checkbox fields to 0; didn't allow undef for value different inline class for Bootstrap3 for checkboxes and radios select options: add coercion of arrayref of hashrefs from arrayref of strings allow Date field to use DateTime subclasses 0.40053 Tue Oct 22, 2013 Bad version number on prereq 0.40052 Mon Oct 21, 2013 allow overriding layout_classes in Bootstrap3 wrapper allow passing in value to 'as_label' method in Select field 0.40051 Thu Oct 17, 2013 Update Italian message file Minor doc updates add errors_by_name and errors_by_id to result add Bootstrap3 theme for those using the Bootstrap theme better form-horizontal Bootstrap 3.0 support provide method in result (form_and_field_errors) to return form and field errors 0.40050 Thu Sep 26, 2013 *** 'widget_tags' in a field have been deprecated for a long time; removing. There are still widget_tags in the form and compound fields. Use 'tags' in a field instead. *** Initial support of Bootstrap3 - still EXPERIMENTAL. Do not use in production yet. Changes in interface may occur over the next few weeks. Supporting Bootstrap 3.0 required a surprising amount of minor refactoring: Bootstrap3 checkboxes and radio elements now have an additional div wrapping them. This required setting flags in the wrapper that could be seen by the field widgets. Used 'wrapper_tags' attribute, which is not the most satisfying solution but does work. The former 'controls' div now doesn't have the 'controls' class, but is used for sizing. Added new attribute 'element_wrapper_class' to provide these classes. Split out addition of classes to the wrapper and element into 'add_standard_wrapper_classes' and 'add_standard_element_classes', because B3.0 now wants 'has-error' and 'has-warning' instead of the former 'error' class. 'control-group' was changed to 'form-group'. The 'form-control' class has been added to text, password, textarea, and select fields. Add 'preserve_case' attribute to Email field 0.40028 Sat Sep 21, 2013 Fixed bug when rendering blocks with 'run' (results) Sort the deflated values of SelectCSV field Allow passing Email::Valid params to Email field Typos fixed Add 'use_init_obj_when_no_accessor_in_item' flag for dual-purpose init_obj 0.40027 Thu Aug 8, 2013 Add 'options_ref' method for using options in TT templates Add unique messages to field messages hash 0.40026 Wed Jul 3, 2013 Add Italian message file Doc tweaks Add errors_by_id and errors_by_name convenience methods 0.40025 Thu May 9, 2013 Add skip in t/setup_form_config.t unless YAML::Syck (Config::Any) 0.40024 Tue May 7, 2013 Add 'no_option_validation' flag to select field. Remove HtmlArea field. (Has always been broken, and there were complaints about not prereqing HTML::Tidy, which I won't do due to difficulty of installing) Change 'use' of GD::SecurityImage to a 'require'. (Will not prereq this one either.) 0.40023 Tue Apr 30, 2013 Add Brazilian Portuguese translation file Fix bug in process of re-loading repeatables without primary keys after db update Add TextCSV field for multiple values in a text field (useful with js libraries) 0.40022 Mon Mar 18, 2013 Remove 'writeonly' flag from Display field, because fix to not pull values from an item/init_object with that flag meant that values were not being applied to Display fields, when people were relying on that. Switch to using github issues instead of RT 0.40021 Mon Mar 4, 2013 Don't validate disabled fields check for existence of field in match_when before getting $field->fif, improve error message add type_attr to Select field; update t/render/ff.t to use it cleanup select field options_method building 0.40020 Sun Feb 20, 2013 More support for repeatable javascript: Tweak Bootsrap wrapper to check do_wrapper instead of do_label when rendering 'controls' div Reminder: It's always a good idea to make your own set of of widgets so that updates don't throw off your rendering. This change was hardly noticeable in the FH testcases, but it's possible you were relying on the old behavior for CSS. Add 'controls_div' to Simple wrapper. Add RmElement example field. 0.40019 Fri Feb 8, 2013 Move back 'before_element' tag; breaks existing rendering. Add additional 'before_element_inside_div' tag instead. 0.40018 Thur Feb 7, 2013 Don't put 'control-group' on Bootstrap hidden field div because of spacing issues Support for repeatable add/remove javascript add 'setup_for_js' flag to Field::Repeatable add HTML::FormHandler::Render::RepeatableJs add HTML::FormHandler::Field::AddElement add before_wrapper and after_wrapper tags add 'id' to wrappers of compound fields update Display field to use 'render_method' allow applying wrapper widget even if field has render method Fix positioning of 'before_element' tag in Bootstrap wrapper 0.40017 Sat Dec 1, 2012 Fix bad html in Span widget Fix unitialized warning processing has_field with '+' Use get_default_value in Submit/Reset field Improve doc for bootstrap theme, use BootstrapFormMessages role Add lazy to render_filter for random failures in 5.17.6 0.40016 Mon Oct 15, 2012 Fix bug with DBIC model interface 0.40015 Sun Oct 14, 2012 Remove extraneous use of Data::Printer Correct spelling of PadWalker 0.40014 Sat Oct 13, 2012 Add useful message and die in field widgets with no result Use string instead of object in LANGUAGE_HANDLE Fix bug in required_when when value is 0 Allow using arrayref for sort_column. Select field as_label for multiple fields. Minor doc fixes Bug - option group label attributes Add info_message to form and rendering. Add 'use_fields_for_input_without_param' flag Call inflate_default_method on repeatable elements 0.40013 Sun Jun 24, 2012 Re-write elimination of PrimaryKey field from repeatable value, add 'no_value_if_empty' attribute Fix bug with labels '0' not being displayed Change 'missing' to an attribute. Submit field has 'submit' html5_type_attr Add html5_type_attr to Hidden, Reset, and Password fields Add new behavior for compound fields and 'not_nullable' flag, where compound field value is not set to undef when all subfields are empty. This is needed for some kinds of db relationships, to ensure that subfields are set to null. 0.40012 Fri Jun 15, 2012 Bug cloning merging repeatable instances; form reference garbage collected Doc typos 0.40011 Tue Jun 5, 2012 Remove automatic building of field results. If you have field tests, you need to add $field->build_result after creating field with 'new'. Possible memory cycle if result is accessed when not built. Add 'required_when' Add Bulgarian message file (dpetrov) Bootstrap input_append/prepend: no linefeeds between input Add input_append_button tag to Bootstrap wrapper Correct camelcase for widgets in two fields Add 'value_when_empty' for multiple select Add SelectCSV multiple field Change Select to use sort_options_method for sorting 0.40010 Sun May 20, 2012 Add 'when' clause to apply actions Fix memory leak on fields with defaults due to missing 'my' causing $self to be closed over so that RAM was leaked if forms were constructed but never processed. (in default_ & validate_ methods) 0.40009 Mon May 14, 2012 Re-implement improved version of 'reload_after_update'. 0.40008 Fri May 11, 2012 Add 'missing' method to Field Use result in Bootstrap render_form_messages Fix Render::Table Propagate errors when they're added, so $form->has_errors works in sub validate Use do_render_label in Bootstrap wrapper to allow setting label class/attributes Add subfield convenience method. Remove 'reload_after_update'. Didn't work anyway. Bug: duplicate results with repeatables. (avoid with reload_after_update => 0) Re-factor RadioGroup widget to allow individually rendered options Support option groups in 'Select', 'RadioGroup' & 'CheckboxGroup' widgets 0.40007 Tues Apr 24, 2012 Re-factor widget to provide 'render_element' method Various doc updates Move 'by_flag' processing into '_merge_updates' Handle disabled fields better; result_from_fields if no input Fix bug: html_attributes callback called with 'input' instead of 'element' 0.40006 Tues Apr 10, 2012 Render::Table incorrect table start Minor doc cleanup Add 'build_label_method' Re-do merging of widget_tags Implement experimental 'include' list for Form/Compound fields Refactor merge_updates and update_subfields to handle contains Add 'by_type' to update_subfields 0.40005 Mon Mar 26, 2012 prevent undef from being passed to maketext expand use of 'posted' flag to check false values add wrap_label method 0.40004 Fri Mar 23, 2012 Don't put element attributes on select options Make render_list lazy Better defaults for compound fields Provide package name for die when not extending Add block_list to provide blocks Defaults for repeatable fields 0.40003 Wed Mar 14, 2012 Move dfv test that fails prereqs 0.40002 Tue Mar 13, 2012 Put form wrappers that are fieldsets inside form tag; outside not legal HTML Doc updates Add 'NonEditable' field and 'Span' field widget Patch HTMLAttributes (compatibility for older style custom widgets) 0.40001 Wed Mar 7, 2012 Remove \K in regex for ucc_widget; doesn't work pre 5.10 Switch DateTime field to use inflate_default_method 0.40000 Tue Mar 6, 2012 **** There are many changes to rendering, many of them incompatible. These changes *will* break existing form rendering. You must check that your rendering works before upgrading. Making a copy of the old code (the widget and rendering roles) may be helpful (or use the compatibility libraries -- see below). I always prefer to maintain backward compatibility if possible, but a number of the improvements were not possible without breaking compatibility, so I did a lot of changes at once. Compatibility libraries are provided to help support rendering that relied on the earlier libriaries at: git://github.com/gshank/html-formhandler_pre-0.40_compat.git README at: https://github.com/gshank/html-formhandler_pre-0.40_compat/blob/master/README Add Twitter Bootstrap 2.0 widget wrapper Add 'no_update' flag to allow skipping model_update. Remove 'deflate_to' flag; provide new inflation/deflation methods. see HTML::FormHandler::Manual::InflationDeflation New 'build_id_method' to provide different builder method for field IDs. 'auto_fieldset' and 'no_auto_fieldset' no longer used. No automatic fieldsets. Can be added with do_wrapper => 1 and a tag of wrapper_tag => 'fieldset' Localize the value of the reset button. Tests and fix for form 'validate_' and 'default_' method for repeatables fields. Change default radiogroup rendering to not use
elements. Add back with tag radio_br_after => 1 Switch to using coderef for deflate_method; custom fields with deflate sub will need to be modified. Add block rendering (HTML::FormHandler::Blocks) Re-do code for default & validate method construction; now provides 'default_method' and 'validate_method' coderef setting Remove 'init_value_*' from Field (deprecated for years). Use Hash::Merge in merging update field info on creation Fix bug in copying tags to fields by cloning field definitions Switch to using name 'element_attr' in fields instead of 'html_attr' Put wrapper class 'hfh-repinst' on Repeatable Instances unless they already have a wrapper class Remove 'javascript' field attribute. Put into *_attr hashref. Automatically put 'error' on element and wrapper. Switch to having the 'class' as a separate attribute from the _attr collection. Use 'element_class', 'wrapper_class' & 'label_class' arrayrefs Switch to having widget names by default be camel case; provide convenience methods for templates - uwidget, uwrapper, twidget, twrapper. ** this change will affect existing template systems, if they use the $field->widget method to get the widget name. See example templates. and conversion methods 'ucc_widget' and 'cc_widget' in HTML::FormHandler::Render::Util Create t/share/templates/form/form_in_one.tt Switch default rendering of checkbox to have label wrap input. Checkboxes are complicated. See t/render/checkbox.t for various options. Add 'build_update_subfields' to 'update_fields' processing to allow moving more of rendering settings into a separate role Change form 'html_attr' to 'form_element_attr', and use builder Change interface of html_field_attributes to also return attr (instead of just in-place) Remove 'label_no_colon', make labels without colon the default. Add widget tag 'label_after'. Use "label_after => ': '" for old behavior Add widget tag 'label_tag'. Default 'label'. Widget_tags replaced with 'form_tags' in form and 'tags' in Field. takes builder 'build_form_tags' instead of default Repeatable elements get automatic 'div' wrapper Remove attribute 'auto_fieldset'; wrapping form is no longer a default; Add back with sub build_do_form_wrapper {1}, and form_tags => { wrapper_tag => 'fieldset' } Remove automatic wrapping of compounds. Enable wrapping with do_wrapper => 1 (there's also do_label => 1) Put form wrapper around form tag instead of inside wrapper_start and wrapper_end tags not used to skip wrapper; use do_wrapper => 0 The 'get_tag' method now returns '' instead of undef if tag doesn't exist. 0.36001 Tues Jan 24, 2012 Add two more widget tags: 'no_auto_fieldset' and 'no_compound_wrapper' Remove automatic addition of 'class="label"' to labels; if you want that behavior, add it in with form sub field_html_attributes. Add 'SKIP' to t/config.t test for Template. Update Captcha so it might actually work. 0.36000 Sun Jan 22, 2012 Switch to using 'process_attrs' function to process attributes in rendering; *** There were lots of updates to rendering. You should verify your custom rendering, to make sure that nothing has broken. The '_add_html_attributes' method is no longer used. Add shorthand method for setting defaults in fields Add widget_tags 'label_no_colon' & 'wrapper_tag' Update and reorganize TT templates Add flags 'use_defaults_over_obj' & 'use_init_obj_over_item' Add 'num_extra' to Repeatable Update Turkish message file; add Float field Add lazy to 'html' attribute in Display field Add 'label_attr' and 'wrapper_attr' to Field Add 'Array' trait to field_name_space and widget_name_space Bug with selected/checked hash key in Multiple; switch to creating default Bug with repeatable contains; not using full name for accessor. Die if using HTML::FormHandler::Moose without HTML::FormHandler Field::TextArea extends Field::Text to reuse its validations (min/max length) Add is_html5 attribute to forms which causes forms to have the additional HTML 5 attributes which can be used by HTML 5 capable clients for validation 0.35005 Sat Oct 8, 2011 Fix bug repeatable result not returned for num_when_empty Fix bug repeatable required flag not propagated Fix bug building nested compound fields Allow html attributes on radio group elements Undefined string warning in select rendering Add Japanese message file 0.35004 Wed Oct 5, 2011 Fix bug setting multiple selects with init_object Provide html_attr for form attributes Use Moose type for field_name_space and widget_name_space 0.35003 Wed Sep 7, 2011 Fix bug constructing classes for Class::Load, revealed by Class::Load 0.10 0.35002 Mon Aug 8, 2011 Change to use Class::Load due to speed. 0.35001 Mon Jul 25, 2011 Undid setting processed flag when building result in BUILD. Breaks existing apps. Re-thinking that part for now. 0.35000 Thu Jul 21, 2011 Add support for tabindex attribute. Generic html attribute setting (html_attr) Set 'processed' flag when building results in BUILD to fix problem with garbage collected results. *** it's possible that this may break code if field values were being set outside of FormHandler, or params were set on new. Pass params on process. Set fields inside FormHandler, or run clear first, then set values. In general, it works best to update fields inside a FormHandler class, in a method or method modifier. Building results in 'new' happened originally because people expected to be able to do $form->render after new, without process. But you're better off always running 'process'. Add flag 'no_preload' to skip building results in new (BUILD) if not needed Add flag 'no_widgets' to skip applying widgets to fields if not needed Fix for Date fields in compounds. Types Printable & SingleWord use class messages Add link to the bug tracker into the HELP section in the Pod. Change how field_traits work: apply traits to field objects, add new class method apply_traits (Stephen Thirlwall) 0.34001 Mon May 16, 2011 Fiz another memory cycle using Select field Tweak code creating results for Field testing 0.34000 Mon May 16, 2011 Fixed memory cycles; 1 in HFH code, others by requiring Moose 2.0007 Localize value of a button Allow limited use of has_many multiple select Add SimpleInline & TableInline widgets to not wrap compound fields 0.33002 Tues Feb 22, 2011 Accidentally left off compatibility for 'required_message' attribute messages => { required => '...' } is new style and worked 0.33001 Mon Feb 21, 2011 Remove unnecessary with of HFH::Validate::Actions 0.33000 Mon Feb 21, 2011 bug - empty_select check defined Add button field, widget, template Check html attributes for definedness not truth Add ability to set field inactive on new & process in addition to setting active Move 'no_render_label' into Field Use form's language_handle in fields Improve PrimaryKey doc Return empty hashref from $form->value instead of undef Merge experimental Wizard into master Render disabled select options Repeatable contains rendering incorrectly, skipping empty elements Add rendering of form_errors to widgets and Render::Simple *** If you were using form_errors (there are none by default) and were using HFH rendering, check for compatibility Allow specifying full class for widget with '+' Document removing wrapper div from Simple wrapper Re-do how field messages are stored and accessed. Use messages => {...} instead of various _message attributes Add utilities in util to pull out class messages and check I18N Update I18N messages files (those that were provided by translators) Change render_filter Coderef setting because of leak; *** Possible incompatibility: if you have a form render_filter, change to function instead of method Change _localize to a Coderef to allow easier changing. *** If you have a custom _localize method, check for compatibility 0.32005 Wed Oct 20, 2010 Removed '//'; incompatible with earlier versions of Perl 0.32004 Wed Oct 20, 2010 Minor doc cleanup Switch away from MooseX::Traits; memory leak because of non-cached composed classes 0.32003 Sun Oct 3, 2010 Fix syntax for 'with', excludes => -excludes Use labels in radio group widgets Add 'is_active' and 'is_inactive' convenience methods in Field Select options - check defined instead of truth Misc minor doc and test improvements Coderef allowed for messages in apply actions Limit removing of numbers when constructing method names Use html_filter when rendering labels Allow undefining min_size and max_size in upload field Return in render_filter if string is not defined Change rendering of repeatable subfields 0.32002 Thu July 29, 2010 Update to handle newer Moose (error msg with Moose::Util::MetaRole API) Swich to Dist::Zilla Add customization of form tag attributes Add test prereqs 0.32001 Fri June 25, 2010 Add prereqs for DateTime::Format::Strptime and Email::Valid 0.32000 Fri June 25, 2010 Accept arrayref messages in add_error Add initial fieldset wrapper Flag (localize_labels) in Select field for rendering; localize empty_select Add posted flag for forms containing only fields with no params when unselected Add 'update_fields' methods and 'update_field_list' for preference-type field updates Fix incorrect error message in duration field Use LANGUAGE_HANDLE instead of LANG in tests Add 'input_class' for class attribute on input fields Allow deflation in fif, flag 'deflate_to' => 'value'/'fif' Fix bug with unselected Select field (move input_without_param & not_nullable into field) Add resultset example to cookbook Doc to look at input for multiple submit fields Fix bug in _set_dependency; use 'has_some_value' to determine emptiness Add form_errors for non-field errors Remove deprecated 'min_length' attribute ('minlength' is supported) Allow upload field to be passed a file handle Pass values to Display field (for display-only db fields) Change I18N to allow duck_type classes; add test for Data::Localize Added 'peek' diagnostic function for viewing field & result trees Fix bug with extra results in repeatable elements Strip empty pks and empty elements from repeatable values (avoid DB errors) Localize value of submit button Make '+' unnecessary in front of field name space types 0.31003 Fri May 7, 2010 Change precedence of defaults over item/init_object; add 'default_over_obj' for cases where that behavior is desired. Fix errors in filtering HTML in rendering Call deflation in InitResult::_result_from_obj Split localization of labels into separate 'loc_label' method Call loc_label where label is used in error messages Enable empty strings for wrapper_start and wrapper_end Set locale to en_us where needed in test Fix widget_name_space use in fields 0.31002 Wed Apr 21, 2010 Remove unused HTML::Entities from Simple form widget Move locale test file into xt because of env variable issues in test 0.31001 Tues Apr 20, 2010 Use full length version number Updates to translated messages & messages in Validate::Actions 0.31 Fri Apr 16, 2010 Remove use of HTML::Entities for filtering. New render_filter coderef for filering. Minor doc fixes for typos Use _html_attributes in widgets (for disabled, readonly, javascript) Localize default required field message Add 'render_upload' to Render::Simple Fix allowing array for field_name_space Selected_option for select lists Add example to cookbook and tests for setting a coderef for validation Checkbox group use 'eq' instead of '==' Fixes to tutorial to match Catalyst tutorial Allow arrayref for 'has_field' (like Moose 'has') Die on maketext errors Move deflation from fif to get_value called by '_result_from_object'. Possible incompatibility, except it was probably not working to start with... 0.30003 Sun Feb 21, 2010 Partial fix for lack of defaults for compound fields Support for using model_fields roles (DBICFields) Use 'eq' instead of '==' when constructing html for multiple selects Remove deprecated 'auto' syntax 0.30002 Thu Feb 11, 2010 Don't convert widget names that contain uppercase Better error messages for missing field classes Field attribute 'input_param' to allow input names different than field names Make field 'default' rw Clean up doc on init_object 0.30001 Fri Feb 5, 2009 Remove unnecessary IO::All use causing dep problems Changes to Turkish messages Russian and Urkainian message files Use HTML::FormHandlerX namespace for fields and widgets Fix bug with defaults set to 0 0.30 Mon Feb 1, 2010 Improve Display Field, adding more ways to set html Add initial pass at more automatic TT rendering Change readonly, html attributes to 'rw' Set widget in Reset field Fix bugs and oddities in HFH::types Fix bug allowing hashref to be passed to constructor Improve doc on 'trim' Add more doc on dynamic form creation Allow 'options_' attributes in form Add Turkish message file Add 'empty_select' to Select field Fix bug displaying empty repeatable element if no values from object Improvements in I18N factoring 0.29002 Wed Dec 16, 2009 Remove locale.t from dist until issues solved 0.29001 Tues Dec 15, 2009 Fix bug with passing widget_wrapper to fields Fix bug with generated method names for form methods 0.29 Wed Dec 2, 2009 Add CheckboxGroup widget, add MooseX::Traits to Form & Field class Fix bug where defaults were not being used with an initial object Fix DateTime field to trap DateTime errors, pass hash in value Use build_label for field labels Remove use of Class::Load, instead use Class::MOP::load_class() Add set_active and make switching fields to active simpler Fix bug when options lists from db are empty Add encode_entities to rendering widgets Switch from init_value_ to default_ Change upload field. Improve setting of method defaults for set_default, set_validate, set_options 0.28 Switched to using native traits Add Widget roles Major refactor to support result classes Reformatting source to more Perl standard Fix bug generating CSS classes in Render::Simple (mazpe) Fix POD example in ::Intro (mazpe) 0.27006 Mon Aug 17, 2009 Add ability to set params class and arguments 0.27005 Wed Aug 12, 2009 DateTime::Format::Strptime dep again 0.27004 Tues Aug 11, 2009 Date inherits from Text. Fix loading compound fields from related. Call load_options for forms with no init_obj & params 0.27003 Sat Aug 2, 2009 Indexing failure missing version in Date 0.27002 Sat Aug 2, 2009 Fix missing dependency on DateTime::Format::Strptime Doc tweaks 0.27001 Fri July 31, 2009 Doc fixes, fix Date field. 0.27 Sat July 25, 2009 Split HTML::FormHandler::Model::DBIC into separate distribution Add 'inactive' flag. Cleanup Makefile.PL. 'size' split into 'size' and 'maxlength'. 'min_length' renamed to 'minlength'. Add Catalyst pod. 'html_name' used for field 'id'. Fix DateMDY field. 0.26 Tues June 23, 2009 Fix dependency test failures on UNIVERSAL::require and version 0.25 Sat June 20, 2009 Add dependency for DateTime::Format::SQLite 0.24 Sat June 20, 2009 Refactor validation processing for api consistency Skip empty undef array elements. Update Password and PrimaryKey fields. Fix bugs: calling validate_ method, recognizing errors in repeatable fields, handling empty repeatable elements, incorrect cloning in Repeatable, rendering fixes/updates. 0.23 Fri May 22, 2009 Refactor HTH to use only 'process'. Deprecate 'validate' and 'update' Add field_list array, deprecate other usages. Clean up documentation Add Repeatable field to support has_many relationships 0.22 Fri May 1, 2009, 17:00 Removed development only test from distribution Expanded apply documentation. 0.21 Thu Apr 30, 2009, 20:00 Removed podcoverage, added skip to generator.t test, added 'apply' sugar for adding actions, doc for compound field 0.20 Thu Apr 23, 2009, 17:00 Added apply constraints, transforms, checks. Refactored code for future use of nested fields. Improvements to compound fields. Bug fix for checkboxes. Added ability to redefine attributes of existing fields with '+fieldname'. 0.19 Thu Mar 05, 2009, 17:00 Fix problem with empty values from form. Add Compound field. 0.18 Sun Feb 22 2009, 15:00 Add missing test prereq DateTime::Format::MySQL. Add 'values' method to form. Add 'accessor' attribute to field. 0.17 Thurs Feb 19 2009, 17:30 Refactor validate, adding validate_form method 0.16 Thurs Feb 19 2009, 17:00 Add ability to use arrayrefs for primary key Clear 'fif' for non-db forms. Allow init_object for non-db forms. 0.15 Mon Feb 16 2009, 19:00 Fix inheritance of has_field. Add ability to use has_field in roles. Some refactoring of 'clear'. If a field is not in params, don't touch in db. 0.14 Fri Feb 06 2009, 18:00 Wrong version in META.yml. Fix fif for password fields. 0.13 Wed Feb 04 2009, 23:00 Fix validate to set params if hash 0.12 Wed Feb 04 2009, 18:00 Fix 'dump_fields'. Add more output for verbose. Change so that 'validate' doesn't require a separate 'clear' for persistent forms. The controller test will only execute with an environment variable. 0.11 Mon Feb 02 2009, 17:00 Change to use BEGIN block in controllers for Catalyst 5.80. 0.10 Thu Jan 29 2009, 07:00 Remove unnecessary 'use' from Render::Simple to eliminate install failures. Change handling of 'has_field'. 0.09 Sun Jan 25 2009, 17:00 Minor changes. 0.08 Sat Jan 24 2009, 11:00 Remove controller and role. Refactor to support persistent forms. Remove update_from_form method. Add 'process', and 'update' methods. Update documentation to match. Update tutorial. 0.07 Thurs Jan 22 2009, 04:00 Add prereq of DateTime. Minor doc changes. 0.06 Wed Jan 21 2009, 04:00 Add prereq skip tests to controller test. Clean up Makefile.PL. Convert test controller Book.pm to use chained. Support empty rows. 0.05 Mon Jan 19 2009, 15:00 Add skip test to htmlarea test. Add action, http_method, & submit to form. Add javascript to field. Create widget directory for templates. 0.04 Fri Jan 16 2009, 19:00 Move example to test directory. Change controller; add controller test. Add use for HashRefInflator. Add more documentation. 0.03 Tues Jan 12 2009, 16:00 Pod fix, remove failing test from htmlarea 0.02 Tues Jan 12 2009, 03:00 Fixed pod formatting, naming of files 0.01 Mon Jan 12 2009, 17:00 Released on an unsuspecting world Conversion of Form::Processor to Moose, including renaming many attributes and methods and refactoring LICENSE100644000770000024 4365012576552253 15517 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2014 by Gerda Shank. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our 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. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, 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 a 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 tell them 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. 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 Agreement 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 work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 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 General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual 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 General Public License. d) 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. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 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 Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying 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. 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. 7. 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 the 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 the license, you may choose any version ever published by the Free Software Foundation. 8. 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 9. 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. 10. 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 Appendix: 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 humanity, 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. Copyright (C) 19yy 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 1, 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) 19xx 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 a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2014 by Gerda Shank. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End INSTALL100644000770000024 172612576552253 15521 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064 This is the Perl distribution HTML-FormHandler. Installing HTML-FormHandler is straightforward. ## Installation with cpanm If you have cpanm, you only need one line: % cpanm HTML::FormHandler If you are installing into a system-wide directory, you may need to pass the "-S" flag to cpanm, which uses sudo to install the module: % cpanm -S HTML::FormHandler ## Installing with the CPAN shell Alternatively, if your CPAN shell is set up, you should just be able to do: % cpan HTML::FormHandler ## Manual installation As a last resort, you can manually install it. Download the tarball, untar it, then build it: % perl Makefile.PL % make && make test Then install it: % make install If you are installing into a system-wide directory, you may need to run: % sudo make install ## Documentation HTML-FormHandler documentation is available as POD. You can run perldoc from a shell to read the documentation: % perldoc HTML::FormHandler dist.ini100644000770000024 335412576552253 16133 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064; Everything starting with ';' is a comment name = HTML-FormHandler main_module = lib/HTML/FormHandler.pm author = FormHandler Contributors - see HTML::FormHandler license = Perl_5 copyright_holder = Gerda Shank copyright_year = 2014 version = 0.40064 [@Git] tag_format = %v [@Basic] [InstallGuide] [MetaJSON] [MetaResources] bugtracker.web = http://github.com/gshank/html-formhandler/issues ; If you have a repository... repository.url = git://github.com/gshank/html-formhandler.git repository.web = http://github.com/gshank/html-formhandler repository.type = git ; You have to have Dist::Zilla::Plugin:: for these to work [PodWeaver] [Test::NoTabs] [Test::EOL] [Signature] [CheckChangeLog] [Prereqs] Class::Load = 0.06 Carp = 0 ; raised Moose prereq because 2.0604 fails Moose = 2.1403 Locale::Maketext = 1.09 DateTime = 0 DateTime::Format::Strptime = 0 MooseX::Getopt = 0.16 MooseX::Types = 0.20 MooseX::Types::Common = 0 MooseX::Types::LoadableClass = 0.006 aliased = 0 File::Spec = 0 File::ShareDir = 0 Try::Tiny = 0 namespace::autoclean = 0.09 Email::Valid = 0 Sub::Exporter = 0 HTML::TreeBuilder = 3.23 Sub::Name = 0 Data::Clone = 0 JSON = 0 List::Util = 1.33 HTML::Entities = 0 [Prereqs / TestRequires] Test::More = 0.94 Test::Differences = 0 Test::Exception = 0 Test::Memory::Cycle = 1.04 Test::Warn = 0 PadWalker = 0 xt000755000770000024 012576552253 14755 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064dfv.t100644000770000024 146012576552253 16062 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use Data::FormValidator::Constraints ('match_state'); has_field 'my_state' => ( apply => [ { check => \&match_state, message => 'Invalid State' } ] ); has_field 'two'; has_field 'three'; } my $form = MyApp::Form::Test->new; ok( $form ); my $params = { my_state => 'XX', two => 1, three => 2 }; $form->process( params => $params ); ok( ! $form->validated, 'form did not validate' ); my @errors = $form->errors; is( $errors[0], 'Invalid State', 'correct error message' ); $params->{my_state} = 'NY'; ok( $form->process( params => $params ), 'correct State validated' ); done_testing; eol.t100644000770000024 30712576552253 16041 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; eval 'use Test::EOL'; plan skip_all => 'Test::EOL required' if $@; all_perl_files_ok({ trailing_whitespace => 1, all_reasons => 1 }, ('lib', 't', 'xt') ); META.yml100644000770000024 222212576552253 15731 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064--- abstract: 'HTML forms using Moose' author: - 'FormHandler Contributors - see HTML::FormHandler' build_requires: PadWalker: 0 Test::Differences: 0 Test::Exception: 0 Test::Memory::Cycle: 1.04 Test::More: 0.94 Test::Warn: 0 configure_requires: ExtUtils::MakeMaker: 6.30 File::ShareDir::Install: 0.03 dynamic_config: 0 generated_by: 'Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: HTML-FormHandler requires: Carp: 0 Class::Load: 0.06 Data::Clone: 0 DateTime: 0 DateTime::Format::Strptime: 0 Email::Valid: 0 File::ShareDir: 0 File::Spec: 0 HTML::Entities: 0 HTML::TreeBuilder: 3.23 JSON: 0 List::Util: 1.33 Locale::Maketext: 1.09 Moose: 2.1403 MooseX::Getopt: 0.16 MooseX::Types: 0.20 MooseX::Types::Common: 0 MooseX::Types::LoadableClass: 0.006 Sub::Exporter: 0 Sub::Name: 0 Try::Tiny: 0 aliased: 0 namespace::autoclean: 0.09 resources: bugtracker: http://github.com/gshank/html-formhandler/issues repository: git://github.com/gshank/html-formhandler.git version: 0.40064 MANIFEST100644000770000024 2635212576552253 15643 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064Changes INSTALL LICENSE MANIFEST META.json META.yml Makefile.PL README SIGNATURE TODO dist.ini lib/HTML/FormHandler.pm lib/HTML/FormHandler/Base.pm lib/HTML/FormHandler/Blocks.pm lib/HTML/FormHandler/BuildFields.pm lib/HTML/FormHandler/BuildPages.pm lib/HTML/FormHandler/Field.pm lib/HTML/FormHandler/Field/AddElement.pm lib/HTML/FormHandler/Field/BoolSelect.pm lib/HTML/FormHandler/Field/Boolean.pm lib/HTML/FormHandler/Field/Button.pm lib/HTML/FormHandler/Field/Captcha.pm lib/HTML/FormHandler/Field/Checkbox.pm lib/HTML/FormHandler/Field/Compound.pm lib/HTML/FormHandler/Field/Date.pm lib/HTML/FormHandler/Field/DateMDY.pm lib/HTML/FormHandler/Field/DateTime.pm lib/HTML/FormHandler/Field/Display.pm lib/HTML/FormHandler/Field/Duration.pm lib/HTML/FormHandler/Field/Email.pm lib/HTML/FormHandler/Field/File.pm lib/HTML/FormHandler/Field/Float.pm lib/HTML/FormHandler/Field/Hidden.pm lib/HTML/FormHandler/Field/Hour.pm lib/HTML/FormHandler/Field/IntRange.pm lib/HTML/FormHandler/Field/Integer.pm lib/HTML/FormHandler/Field/Minute.pm lib/HTML/FormHandler/Field/Money.pm lib/HTML/FormHandler/Field/Month.pm lib/HTML/FormHandler/Field/MonthDay.pm lib/HTML/FormHandler/Field/MonthName.pm lib/HTML/FormHandler/Field/Multiple.pm lib/HTML/FormHandler/Field/Nested.pm lib/HTML/FormHandler/Field/NoValue.pm lib/HTML/FormHandler/Field/NonEditable.pm lib/HTML/FormHandler/Field/Password.pm lib/HTML/FormHandler/Field/PasswordConf.pm lib/HTML/FormHandler/Field/PosInteger.pm lib/HTML/FormHandler/Field/PrimaryKey.pm lib/HTML/FormHandler/Field/Repeatable.pm lib/HTML/FormHandler/Field/Repeatable/Instance.pm lib/HTML/FormHandler/Field/Reset.pm lib/HTML/FormHandler/Field/Result.pm lib/HTML/FormHandler/Field/RmElement.pm lib/HTML/FormHandler/Field/Second.pm lib/HTML/FormHandler/Field/Select.pm lib/HTML/FormHandler/Field/SelectCSV.pm lib/HTML/FormHandler/Field/Submit.pm lib/HTML/FormHandler/Field/Text.pm lib/HTML/FormHandler/Field/TextArea.pm lib/HTML/FormHandler/Field/TextCSV.pm lib/HTML/FormHandler/Field/Upload.pm lib/HTML/FormHandler/Field/Weekday.pm lib/HTML/FormHandler/Field/Year.pm lib/HTML/FormHandler/Fields.pm lib/HTML/FormHandler/Foo.pm lib/HTML/FormHandler/I18N.pm lib/HTML/FormHandler/I18N/ar_kw.pm lib/HTML/FormHandler/I18N/bg_bg.pm lib/HTML/FormHandler/I18N/ca_es.pm lib/HTML/FormHandler/I18N/cs_cz.pm lib/HTML/FormHandler/I18N/de_de.pm lib/HTML/FormHandler/I18N/en_us.pm lib/HTML/FormHandler/I18N/es_es.pm lib/HTML/FormHandler/I18N/hu_hu.pm lib/HTML/FormHandler/I18N/it_it.pm lib/HTML/FormHandler/I18N/ja_jp.pm lib/HTML/FormHandler/I18N/pt_br.pm lib/HTML/FormHandler/I18N/ru_ru.pm lib/HTML/FormHandler/I18N/sv_se.pm lib/HTML/FormHandler/I18N/tr_tr.pm lib/HTML/FormHandler/I18N/ua_ua.pm lib/HTML/FormHandler/InitResult.pm lib/HTML/FormHandler/Manual.pod lib/HTML/FormHandler/Manual/Catalyst.pod lib/HTML/FormHandler/Manual/Cookbook.pod lib/HTML/FormHandler/Manual/Database.pod lib/HTML/FormHandler/Manual/Defaults.pod lib/HTML/FormHandler/Manual/Errors.pod lib/HTML/FormHandler/Manual/Fields.pod lib/HTML/FormHandler/Manual/FromDFV.pod lib/HTML/FormHandler/Manual/FromFF.pod lib/HTML/FormHandler/Manual/InflationDeflation.pod lib/HTML/FormHandler/Manual/Intro.pod lib/HTML/FormHandler/Manual/Reference.pod lib/HTML/FormHandler/Manual/Rendering.pod lib/HTML/FormHandler/Manual/RenderingCookbook.pod lib/HTML/FormHandler/Manual/Templates.pod lib/HTML/FormHandler/Manual/Testing.pod lib/HTML/FormHandler/Manual/Tutorial.pod lib/HTML/FormHandler/Manual/Validation.pod lib/HTML/FormHandler/Merge.pm lib/HTML/FormHandler/Meta/Role.pm lib/HTML/FormHandler/Model.pm lib/HTML/FormHandler/Model/CDBI.pm lib/HTML/FormHandler/Model/Object.pm lib/HTML/FormHandler/Moose.pm lib/HTML/FormHandler/Moose/Role.pm lib/HTML/FormHandler/Page.pm lib/HTML/FormHandler/Page/Simple.pm lib/HTML/FormHandler/Pages.pm lib/HTML/FormHandler/Params.pm lib/HTML/FormHandler/Render/RepeatableJs.pm lib/HTML/FormHandler/Render/Simple.pm lib/HTML/FormHandler/Render/Table.pm lib/HTML/FormHandler/Render/Util.pm lib/HTML/FormHandler/Render/WithTT.pm lib/HTML/FormHandler/Result.pm lib/HTML/FormHandler/Result/Role.pm lib/HTML/FormHandler/Test.pm lib/HTML/FormHandler/TraitFor/Captcha.pm lib/HTML/FormHandler/TraitFor/I18N.pm lib/HTML/FormHandler/TraitFor/Types.pm lib/HTML/FormHandler/Traits.pm lib/HTML/FormHandler/Types.pm lib/HTML/FormHandler/Validate.pm lib/HTML/FormHandler/Widget/ApplyRole.pm lib/HTML/FormHandler/Widget/Block.pm lib/HTML/FormHandler/Widget/Block/Bootstrap.pm lib/HTML/FormHandler/Widget/Field/Button.pm lib/HTML/FormHandler/Widget/Field/ButtonTag.pm lib/HTML/FormHandler/Widget/Field/Captcha.pm lib/HTML/FormHandler/Widget/Field/Checkbox.pm lib/HTML/FormHandler/Widget/Field/CheckboxGroup.pm lib/HTML/FormHandler/Widget/Field/Compound.pm lib/HTML/FormHandler/Widget/Field/Hidden.pm lib/HTML/FormHandler/Widget/Field/HorizCheckboxGroup.pm lib/HTML/FormHandler/Widget/Field/NoRender.pm lib/HTML/FormHandler/Widget/Field/Password.pm lib/HTML/FormHandler/Widget/Field/RadioGroup.pm lib/HTML/FormHandler/Widget/Field/Repeatable.pm lib/HTML/FormHandler/Widget/Field/Reset.pm lib/HTML/FormHandler/Widget/Field/Role/HTMLAttributes.pm lib/HTML/FormHandler/Widget/Field/Role/SelectedOption.pm lib/HTML/FormHandler/Widget/Field/Select.pm lib/HTML/FormHandler/Widget/Field/Span.pm lib/HTML/FormHandler/Widget/Field/Submit.pm lib/HTML/FormHandler/Widget/Field/Text.pm lib/HTML/FormHandler/Widget/Field/Textarea.pm lib/HTML/FormHandler/Widget/Field/Upload.pm lib/HTML/FormHandler/Widget/Form/Role/HTMLAttributes.pm lib/HTML/FormHandler/Widget/Form/Simple.pm lib/HTML/FormHandler/Widget/Form/Table.pm lib/HTML/FormHandler/Widget/Theme/Bootstrap.pm lib/HTML/FormHandler/Widget/Theme/Bootstrap3.pm lib/HTML/FormHandler/Widget/Theme/BootstrapFormMessages.pm lib/HTML/FormHandler/Widget/Wrapper/Base.pm lib/HTML/FormHandler/Widget/Wrapper/Bootstrap.pm lib/HTML/FormHandler/Widget/Wrapper/Bootstrap3.pm lib/HTML/FormHandler/Widget/Wrapper/Fieldset.pm lib/HTML/FormHandler/Widget/Wrapper/None.pm lib/HTML/FormHandler/Widget/Wrapper/Simple.pm lib/HTML/FormHandler/Widget/Wrapper/SimpleInline.pm lib/HTML/FormHandler/Widget/Wrapper/Table.pm lib/HTML/FormHandler/Widget/Wrapper/TableInline.pm lib/HTML/FormHandler/Wizard.pm share/templates/field/button.tt share/templates/field/checkbox.tt share/templates/field/checkbox_group.tt share/templates/field/compound.tt share/templates/field/hidden.tt share/templates/field/password.tt share/templates/field/radio_group.tt share/templates/field/repeatable.tt share/templates/field/reset.tt share/templates/field/select.tt share/templates/field/submit.tt share/templates/field/text.tt share/templates/field/textarea.tt share/templates/field/upload.tt share/templates/foo/checkbox_tag.tt share/templates/foo/end_form.tt share/templates/foo/field.tt share/templates/foo/form.tt share/templates/foo/input.tt share/templates/foo/input_tag.tt share/templates/foo/label.tt share/templates/foo/start_form.tt share/templates/form/form.tt share/templates/form/form22.tt share/templates/form/form_end.tt share/templates/form/form_in_one.tt share/templates/form/form_start.tt share/templates/wrapper/fieldset.tt share/templates/wrapper/label.tt share/templates/wrapper/none.tt share/templates/wrapper/simple.tt share/templates/wrapper/wrap_label.tt t/01app.t t/author-eol.t t/basic.t t/blocks/basic.t t/blocks/block_list.t t/blocks/blocktags.t t/blocks/loading.t t/blocks/nested.t t/blocks/render_units.t t/bootstrap/basic.t t/bootstrap/control_states.t t/bootstrap/controls.t t/bootstrap/ext_controls.t t/bootstrap/inline.t t/bootstrap/other.t t/bootstrap/search.t t/bootstrap3/basic.t t/bootstrap3/controls.t t/bootstrap3/horiz.t t/bootstrap3/horiz_checkboxgroup.t t/bootstrap3/inlinecheckboxes.t t/bootstrap3/layout_classes.t t/compound/basic.t t/compound/default.t t/compound/empty.t t/compound/include.t t/compound/select.t t/errors/basic.t t/errors/compound.t t/errors/form_messages.t t/errors/messages.t t/errors/req_message.t t/field_setup/checkbox.t t/field_setup/compound_update_fields.t t/field_setup/defaults.t t/field_setup/disabled.t t/field_setup/id.t t/field_setup/inactive.t t/field_setup/init_object.t t/field_setup/input_param.t t/field_setup/missing.t t/field_setup/plus_field.t t/field_setup/update_fields.t t/field_setup/update_subfields.t t/fields/dates.t t/fields/display.t t/fields/fields.t t/fields/float.t t/fields/formhandlerx.t t/fields/novalue.t t/fields/password.t t/fields/repeatable.t t/fields/select.t t/fields/select2.t t/fields/selectcsv.t t/fields/textcsv.t t/form_setup/api.t t/form_setup/clone.t t/form_setup/compound_field_list.t t/form_setup/config.t t/form_setup/dynamic.t t/form_setup/include.t t/form_setup/init_obj.t t/form_setup/no_update.t t/form_setup/posted.t t/form_setup/render_roles.t t/infl_defl/comp_field.t t/infl_defl/default.t t/infl_defl/defl_lives.t t/infl_defl/infl_defl.t t/infl_defl/infl_transform.t t/infl_defl/variations.t t/lib/BookDB/Form/Upload.pm t/lib/Field/Address.pm t/lib/Field/AltText.pm t/lib/Field/MyField.pm t/lib/Form/Address.pm t/lib/Form/AddressRole.pm t/lib/Form/Multiple.pm t/lib/Form/MultipleRole.pm t/lib/Form/NoExtForm.pm t/lib/Form/Person.pm t/lib/Form/PersonRole.pm t/lib/Form/Test.pm t/lib/Form/Two.pm t/lib/MyApp/Component/Section.pm t/lib/MyApp/I18N/abc_de.pm t/lib/Widget/Block/Test.pm t/lib/Widget/Field/Omega.pm t/lib/Widget/Field/TestWidget.pm t/memory_cycles.t t/moose/build_id.t t/moose/composed.t t/moose/field_traits.t t/moose/no_extend.t t/moose/subclass_roles.t t/release-no-tabs.t t/render/actions.t t/render/array.t t/render/basic.t t/render/checkbox.t t/render/checkbox_group.t t/render/classes.t t/render/compound.t t/render/compound2.t t/render/display.t t/render/errors.t t/render/escaping.t t/render/ff.t t/render/filter.t t/render/form_errors.t t/render/get_tag.t t/render/html5_attributes.t t/render/html_attr.t t/render/html_attributes.t t/render/inline.t t/render/label.t t/render/noneditable.t t/render/optgroup.t t/render/radio_group.t t/render/rep_fieldset.t t/render/rep_wrapper.t t/render/repeatable.t t/render/result.t t/render/select.t t/render/simple.t t/render/submit.t t/render/table.t t/render/tags.t t/render/tt_render_elementx.t t/render/util.t t/render/widget_loading.t t/render/widget_tags.t t/render/widgets.t t/render/with_class.t t/render/withtt.t t/repeatable/defaults.t t/repeatable/empty.t t/repeatable/has_many.t t/repeatable/hash.t t/repeatable/js.t t/repeatable/list.t t/repeatable/nested.t t/repeatable/nested2.t t/repeatable/num_extra.t t/repeatable/reload.t t/repeatable/set_methods.t t/repeatable/subfield.t t/result/basic.t t/result/blocks.t t/result/compound.t t/result/errors.t t/result/repeatable.t t/structured.t t/template.t t/validation/apply.t t/validation/constraints.t t/validation/dependency.t t/validation/filters.t t/validation/reqwhen.t t/validation/type_tiny.t t/validation/types.t t/validation/validate_coderef.t t/validation/when.t t/var/form1.pl t/var/form1.yml t/wizard/basic.t util/check_I18N.pl util/get_messages.pl util/messages xt/02pod.t xt/add_field.t xt/captcha.t xt/captcha2.t xt/chbox_group.t xt/check_selected_option.t xt/custom_fields.t xt/cycles.t xt/dfv.t xt/display.t xt/email.t xt/eol.t xt/field_list.t xt/form_errors.t xt/init.t xt/lib/MyCatalystApp.pm xt/lib/MyCatalystApp/Controller/Captcha.pm xt/lib/MyCatalystApp/Controller/Root.pm xt/load_field.t xt/locale.t xt/locale_data_localize.t xt/mb_form.t xt/model_cdbi.t xt/multiple_forms.t xt/order.t xt/params.t xt/posted.t xt/repeatable_clone.t xt/submit.t xt/upload.t t000755000770000024 012576552253 14565 5ustar00gshankstaff000000000000HTML-FormHandler-0.4006401app.t100644000770000024 51012576552253 16007 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tuse Test::More; use_ok( 'HTML::FormHandler::Model' ); use_ok( 'HTML::FormHandler' ); use_ok( 'HTML::FormHandler::Field' ); use_ok( 'HTML::FormHandler::Field::Select' ); use_ok( 'HTML::FormHandler::Field::Compound' ); use_ok( 'HTML::FormHandler::Field::Repeatable' ); use_ok( 'HTML::FormHandler::Model::CDBI' ); done_testing; basic.t100644000770000024 1421712576552253 16220 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tuse strict; use warnings; use Test::More; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; use_ok('HTML::FormHandler'); { package My::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform_' ); has '+no_preload' => ( default => 1 ); has_field 'optname' => ( temp => 'First' ); has_field 'reqname' => ( required => 1 ); has_field 'somename'; has_field 'my_selected' => ( type => 'Checkbox' ); has_field 'must_select' => ( type => 'Checkbox', required => 1 ); sub field_list { return [ fruit => 'Select', optname => { temp => 'Second' } ]; } sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } } my $form = My::Form->new; is( $form->field('optname')->temp, 'Second', 'got second optname field' ); ok( !$form->process, 'Empty data' ); is_deeply( $form->value, {}, 'no values returns hashref'); my $good = { reqname => 'hello', optname => 'not req', fruit => 2, must_select => 1, }; ok( $form->process($good), 'Good data' ); is( $form->field('somename')->value, undef, 'no value for somename' ); ok( !$form->field('somename')->has_value, 'predicate no value' ); $good->{somename} = 'testing'; $form->process($good); is( $form->field('somename')->value, 'testing', 'use input for extra data' ); is( $form->field('my_selected')->value, 0, 'correct value for unselected checkbox' ); ok( !$form->process( {} ), 'form doesn\'t validate with empty params' ); is( $form->num_errors, 0, 'form doesn\'t have errors with empty params' ); my $bad_1 = { reqname => '', optname => 'not req', fruit => 4, }; ok( !$form->process($bad_1), 'bad 1' ); ok( $form->field('fruit')->has_errors, 'fruit has error' ); ok( $form->field('reqname')->has_errors, 'reqname has error' ); ok( $form->field('must_select')->has_errors, 'must_select has error' ); ok( !$form->field('optname')->has_errors, 'optname has no error' ); is( $form->field('fruit')->id, "fruit", 'field has id' ); is( $form->field('fruit')->label, 'Fruit', 'field label' ); ok( !$form->process( {} ), 'no leftover params' ); is( $form->num_errors, 0, 'no leftover errors' ); ok( !$form->field('reqname')->has_errors, 'no leftover error in field' ); ok( !$form->field('optname')->fif, 'no lefover fif values' ); my $init_object = { reqname => 'Starting Perl', optname => 'Over Again' }; # if you're going to load something on new and expect it to work without # process, you need to have no_preload turned off $form = My::Form->new( init_object => $init_object, no_preload => 0 ); is( $form->field('optname')->value, 'Over Again', 'value with init_obj' ); # non-posted params $form->process( params => {} ); ok( !$form->validated, 'form validated' ); # it's not crystal clear what the behavior should be here, but I think # this is more correct than the previous behavior # it fills in the missing fields, which is what always happened for an # initial object (as opposed to hash), but it used to behave # differently for a hash, which seems wrong # TODO verify behavior is correct my $init_obj_plus_defaults = { 'fruit' => undef, 'must_select' => undef, 'my_selected' => undef, 'optname' => 'Over Again', 'reqname' => 'Starting Perl', 'somename' => undef, }; is_deeply( $form->value, $init_obj_plus_defaults, 'value with empty params' ); $init_object->{my_selected} = 0; # checkboxes must be forced to 0 $init_object->{must_select} = 0; my %fif = %$init_object; $fif{somename} = ''; $fif{fruit} = ''; $fif{must_select} = ''; $fif{my_selected} = ''; is_deeply( $form->fif, \%fif, 'get right fif with init_object' ); # make sure that checkbox is 0 in values $init_object->{must_select} = 1; $fif{must_select} = 1; ok( $form->process($init_object), 'form validates with params' ); #my %init_obj_value = (%$init_object, fruit => undef ); #is_deeply( $form->value, \%init_obj_value, 'value init obj' ); $init_object->{fruit} = undef; is_deeply( $form->value, $init_object, 'value init obj' ); $fif{must_select} = 1; $fif{my_selected} = 0; is_deeply( $form->fif, \%fif, 'get right fif with init_object' ); $form->clear; ok( !$form->has_value, 'Form value cleared' ); ok( !$form->has_input, 'Form input cleared' ); # check that form is cleared if fif is done before process $form->fif; $form->process($init_object); is_deeply( $form->fif, \%fif, 'get right fif when process preceded by fif'); $form = HTML::FormHandler->new( field_list => [ foo => { type => 'Text', required => 1 } ] ); if ( !$form->process( params => { bar => 1, } ) ) { # On some versions, the above process() returned false, but # error_fields did not return anything. my @fields = $form->error_fields; if ( is( scalar @fields, 1, "there is an error field" ) ) { my @errors = $fields[0]->all_errors; is( scalar @errors, 1, "there is an error" ); is( $errors[0], $fields[0]->label . " field is required", "error messages match" ); } else { fail("there is an error"); fail("error messages match"); } } # 'image' input produces { foo => bar, 'foo.x' => 42, 'foo.y' => 23 } $form = HTML::FormHandler->new( name => 'baz', html_prefix => 1, field_list => [ 'foo' ] ); eval{ $form->process( params => { 'baz.foo' => 'bar', 'baz.foo.x' => 42, 'baz.foo.y' => 23 } ) }; ok( !$@, 'image field processed' ) or diag $@; is_deeply( $form->field( 'foo' )->value, { '' => 'bar', x => 42, y => 23 }, 'image field' ); { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar'; sub validate { my $self = shift; if( $self->field('foo')->value eq 'cow' ) { $self->field('foo')->value('bovine'); } } } $form = Test::Form->new; $form->process( { foo => 'cow', bar => 'horse' } ); is_deeply( $form->value, { foo => 'bovine', bar => 'horse' }, 'correct value' ); # check for hashref constructor $form = HTML::FormHandler->new( { name => 'test_form', field_list => { one => 'Text', two => 'Text' } } ); ok( $form, 'form constructed ok' ); done_testing; init.t100644000770000024 333112576552253 16245 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; { package My::Default; use Moose::Role; sub build_default_over_obj { return 'From Method'; } } { package My::Other::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform_' ); has_field 'optname' => ( temp => 'First' ); has_field 'reqname' => ( required => 1, default_over_obj => 'From Attribute' ); has_field 'altname' => ( traits => ['My::Default'] ); has_field 'somename'; has_field 'extraname' => ( default_over_obj => '' ); sub default_somename { my $self = shift; return 'SN from meth'; } } my $init_object = { reqname => 'Starting Perl', optname => 'Over Again', altname => 'test', extraname => 'not_empty', }; my $form = My::Other::Form->new; ok( $form, 'get form' ); my $params = { reqname => 'Sweet', optname => 'Charity', somename => 'Exists' }; $form->process( init_object => $init_object, params => $params ); ok( $form->validated, 'form with init_obj & params validated' ); is( $form->field('reqname')->init_value, 'From Attribute', 'correct init_value'); is( $form->field('optname')->init_value, 'Over Again', 'correct init_value no meth'); is( $form->field('altname')->init_value, 'From Method', 'correct init_value from trait'); is( $form->field('somename')->init_value, 'SN from meth', 'correct for init_obj undef'); is( $form->field('somename')->value, 'Exists', 'correct value for init_obj undef'); is( $form->field('extraname')->init_value, '', 'correct value for empty string default'); $form = My::Other::Form->new( init_object => $init_object ); is( $form->field('somename')->init_value, 'SN from meth', 'correct init_value new w init_obj'); done_testing; META.json100644000770000024 437512576552253 16114 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064{ "abstract" : "HTML forms using Moose", "author" : [ "FormHandler Contributors - see HTML::FormHandler" ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "HTML-FormHandler", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "6.30", "File::ShareDir::Install" : "0.03" } }, "develop" : { "requires" : { "Test::EOL" : "0", "Test::More" : "0.88", "Test::NoTabs" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Class::Load" : "0.06", "Data::Clone" : "0", "DateTime" : "0", "DateTime::Format::Strptime" : "0", "Email::Valid" : "0", "File::ShareDir" : "0", "File::Spec" : "0", "HTML::Entities" : "0", "HTML::TreeBuilder" : "3.23", "JSON" : "0", "List::Util" : "1.33", "Locale::Maketext" : "1.09", "Moose" : "2.1403", "MooseX::Getopt" : "0.16", "MooseX::Types" : "0.20", "MooseX::Types::Common" : "0", "MooseX::Types::LoadableClass" : "0.006", "Sub::Exporter" : "0", "Sub::Name" : "0", "Try::Tiny" : "0", "aliased" : "0", "namespace::autoclean" : "0.09" } }, "test" : { "requires" : { "PadWalker" : "0", "Test::Differences" : "0", "Test::Exception" : "0", "Test::Memory::Cycle" : "1.04", "Test::More" : "0.94", "Test::Warn" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://github.com/gshank/html-formhandler/issues" }, "repository" : { "type" : "git", "url" : "git://github.com/gshank/html-formhandler.git", "web" : "http://github.com/gshank/html-formhandler" } }, "version" : "0.40064" } SIGNATURE100644000770000024 7347112576552253 16002 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064This file contains message digests of all files listed in MANIFEST, signed via the Module::Signature module, version 0.73. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 SHA1 cac04c2342f117700d15a9fff016f4516f2c4d82 Changes SHA1 2972c49b6d6e4d8bcc3360a734ee629ac16c6d8c INSTALL SHA1 b371bb7c182cf84dcc932ebdf50da8c1b810da89 LICENSE SHA1 ba72bfb734ba4059133d9d4d969087db44800d8d MANIFEST SHA1 08ecd5bf2d9bd7b1f30d1d60283c1a51bbf4311d META.json SHA1 40d318339189934adca2b196bce06bdb64a4199b META.yml SHA1 78420f99b82743267cf7a7c44efc2871168aecd4 Makefile.PL SHA1 8aa966ec5f9260fb05d066042be3d0a697192d1e README SHA1 d764cc72a4d6465a03e8d04bdbf58096068c619d TODO SHA1 ce60580e4dd6bb7c37c1d990fe9538b535917a01 dist.ini SHA1 61ae94fec036a15f55ca2ae5e82864f26244bc20 lib/HTML/FormHandler.pm SHA1 e36e0f556a678a5c118055f9c6cb03ee7a147f92 lib/HTML/FormHandler/Base.pm SHA1 bd42ace7583e98f11927de7d9fdc2a45a8b4938f lib/HTML/FormHandler/Blocks.pm SHA1 e59444511c98ea54196433bab55fffa8abaabfe0 lib/HTML/FormHandler/BuildFields.pm SHA1 61cf96b2476259930a8a21fede5fc76406cae76e lib/HTML/FormHandler/BuildPages.pm SHA1 2791b7fd559316751b57fd6f204d44990eb9e01b lib/HTML/FormHandler/Field.pm SHA1 aaf8d3b65c9e2608849bf82f774c367fa4789109 lib/HTML/FormHandler/Field/AddElement.pm SHA1 8061798449dec3289c1580eb0d471600043e56dd lib/HTML/FormHandler/Field/BoolSelect.pm SHA1 5a1fc911b6b400bbb9cfb7fa0b85389101ca7dc2 lib/HTML/FormHandler/Field/Boolean.pm SHA1 d7782623a63e37bb091d6026f725c10990d4a019 lib/HTML/FormHandler/Field/Button.pm SHA1 d22f5a23dba0fa4b3f5dd0ab052b633631bcc550 lib/HTML/FormHandler/Field/Captcha.pm SHA1 98bdcd811321b09be0792d884680ccd8ad8c98e4 lib/HTML/FormHandler/Field/Checkbox.pm SHA1 fce80090bd166cbf99411ffee401211e12912f73 lib/HTML/FormHandler/Field/Compound.pm SHA1 e2e2af2c7ef0b7cf61a2a50766fc35471eca9fd4 lib/HTML/FormHandler/Field/Date.pm SHA1 c0797006e83495eb69eecfad7394f0096ca22af7 lib/HTML/FormHandler/Field/DateMDY.pm SHA1 f01dd47c8544278ab87bc019a68b1b2169f16bcd lib/HTML/FormHandler/Field/DateTime.pm SHA1 10ad077784545979198cf264ff48780e7dcef80f lib/HTML/FormHandler/Field/Display.pm SHA1 da05b2f869f1e47df1ffed9041363cd50632c57c lib/HTML/FormHandler/Field/Duration.pm SHA1 ee6b54dcac206877dbc21a6873900b8cdc524214 lib/HTML/FormHandler/Field/Email.pm SHA1 978f16334572544daf65d675d2c0cb7c8bc411fa lib/HTML/FormHandler/Field/File.pm SHA1 92013314083e43e96a095c6b573f723547e4fb43 lib/HTML/FormHandler/Field/Float.pm SHA1 6f3d761cc9736f8436e7118c0be278d7b0000914 lib/HTML/FormHandler/Field/Hidden.pm SHA1 b14ba25e3d2d55e85b9527b5062ab8594c11d527 lib/HTML/FormHandler/Field/Hour.pm SHA1 837ca34e3c7971fe947b2b7319d823d587f02b75 lib/HTML/FormHandler/Field/IntRange.pm SHA1 dc92a6534ba03bec5fff5b1962f3378a850f11f1 lib/HTML/FormHandler/Field/Integer.pm SHA1 c5610b777daa22d97f6a2afbe256a76a100a88de lib/HTML/FormHandler/Field/Minute.pm SHA1 ebc5e77bd7d7fd3bd41e1264bee017dcabb85990 lib/HTML/FormHandler/Field/Money.pm SHA1 7fc47a1ecf6344c4b76fa6076ab8f93989ce027f lib/HTML/FormHandler/Field/Month.pm SHA1 f67206d5b7cb5aaaedb87a51dc6209d4ee52ed1c lib/HTML/FormHandler/Field/MonthDay.pm SHA1 41029ec8ec837cc41ceb636bc0574530e4b479dd lib/HTML/FormHandler/Field/MonthName.pm SHA1 a7d63156b7c32e54ddca01adbc94b53489483a71 lib/HTML/FormHandler/Field/Multiple.pm SHA1 188e2e92c203a2fc2f4f52c3aaa55470a0964129 lib/HTML/FormHandler/Field/Nested.pm SHA1 a8b4d4a71c1953b37014f917a04cf85509b42c8d lib/HTML/FormHandler/Field/NoValue.pm SHA1 c3b8218ab3bc17339c0e73b7f3335fe181c0107d lib/HTML/FormHandler/Field/NonEditable.pm SHA1 e7adca9553589b5db16424fbc1629132f6afe763 lib/HTML/FormHandler/Field/Password.pm SHA1 a03f4db698912006952e28479ddff62a8a76d5d0 lib/HTML/FormHandler/Field/PasswordConf.pm SHA1 995e7e1e748efb71cbeea3d31e3457cbd4da1dff lib/HTML/FormHandler/Field/PosInteger.pm SHA1 b98fba3ac68a037e18dc455819297da99d878d8a lib/HTML/FormHandler/Field/PrimaryKey.pm SHA1 f1a9b480fbe07f5ab3c48b7bb40a8d53977df1f2 lib/HTML/FormHandler/Field/Repeatable.pm SHA1 01442157b12521ea05e906db904d60e624c0ca0b lib/HTML/FormHandler/Field/Repeatable/Instance.pm SHA1 57c8f15771943acafe950073aad2eea89c7061b3 lib/HTML/FormHandler/Field/Reset.pm SHA1 6d075bf2fa9f4889b1c914f528cae26ecd58ffa0 lib/HTML/FormHandler/Field/Result.pm SHA1 07a3edbe072bc5f3510f0d6c50703b2d2e487821 lib/HTML/FormHandler/Field/RmElement.pm SHA1 131809ae75207db1cf676994586654580d8cf57d lib/HTML/FormHandler/Field/Second.pm SHA1 39e1083703bc3c4e4aecfbdb0394f238c9e75ea1 lib/HTML/FormHandler/Field/Select.pm SHA1 01928851f90442f914fd6b8a27985f22a7e858e0 lib/HTML/FormHandler/Field/SelectCSV.pm SHA1 b9e196da89a5f2d84f88bda4220f8d3ec6e59441 lib/HTML/FormHandler/Field/Submit.pm SHA1 8588ecd2f529eda7b878915473912262dee787e2 lib/HTML/FormHandler/Field/Text.pm SHA1 1e39377e70869b19b4fcd6c727f4b44de9819170 lib/HTML/FormHandler/Field/TextArea.pm SHA1 3388471c7a6b46d06e137cb6bc74898b87f73e71 lib/HTML/FormHandler/Field/TextCSV.pm SHA1 842ed8364d95048faae5b68fe7670a711c216c07 lib/HTML/FormHandler/Field/Upload.pm SHA1 0264ca056a7d89bd5b09725b3c5513202331638f lib/HTML/FormHandler/Field/Weekday.pm SHA1 5f733724391fdf60c4f4be1b6b8d9c66957b7497 lib/HTML/FormHandler/Field/Year.pm SHA1 76bad7258a43969742513ef192c2e057d74d95e2 lib/HTML/FormHandler/Fields.pm SHA1 9bb3d1064fff106efa60d5a1a45f25417a78d4d4 lib/HTML/FormHandler/Foo.pm SHA1 924e38a6203b5246d4a4148319d919379fd04b08 lib/HTML/FormHandler/I18N.pm SHA1 b0cd7d57e9e816c71c5ff9a531c200fed78a514c lib/HTML/FormHandler/I18N/ar_kw.pm SHA1 89a64cfde531f5a9c139a4971f23ef04b2d3e4d8 lib/HTML/FormHandler/I18N/bg_bg.pm SHA1 fd4e1e6fa3a3c0dc88812856a81d700c292cb947 lib/HTML/FormHandler/I18N/ca_es.pm SHA1 1f5d378815f185d4fc40d01ca794672b44526a4a lib/HTML/FormHandler/I18N/cs_cz.pm SHA1 a29a99bb069553d3213b85bafcc8c99c11e83078 lib/HTML/FormHandler/I18N/de_de.pm SHA1 fb7dc64824cb10064e5e712db20a41307054fce3 lib/HTML/FormHandler/I18N/en_us.pm SHA1 3ffae34de630b1d99f35f1f9ea2d5ee2cce7f042 lib/HTML/FormHandler/I18N/es_es.pm SHA1 3431a281ac1c8e208dc678b36522aa371ecf47b1 lib/HTML/FormHandler/I18N/hu_hu.pm SHA1 468bc8a0862c4397a393c260941ba80129980101 lib/HTML/FormHandler/I18N/it_it.pm SHA1 78e8ab8ebd8bdaed093980cf13a025b7903a874d lib/HTML/FormHandler/I18N/ja_jp.pm SHA1 fbaaf65c6b3e7ee6a47bc6fb8bd7aee4eb05a101 lib/HTML/FormHandler/I18N/pt_br.pm SHA1 c6d90e882741a938c715b131658ba182b4e16a72 lib/HTML/FormHandler/I18N/ru_ru.pm SHA1 114e508efd77e7ac1c4af0ba68901412b284c9db lib/HTML/FormHandler/I18N/sv_se.pm SHA1 5d06c9c3b31c7e9dccda973fe18840c7f5314bf0 lib/HTML/FormHandler/I18N/tr_tr.pm SHA1 7c6d529da64ceb4d1067ba7774af45510ccebb18 lib/HTML/FormHandler/I18N/ua_ua.pm SHA1 3e5c6a3669f4503b78f7a643deb851583b0cf5c1 lib/HTML/FormHandler/InitResult.pm SHA1 82dd401d265955378d9767fc98188d17ffa5f96d lib/HTML/FormHandler/Manual.pod SHA1 840719d0c3160d664bfd8e012b5337d96a774043 lib/HTML/FormHandler/Manual/Catalyst.pod SHA1 f4206eabefd0b8aa15e393a1c79b9cfab603eed7 lib/HTML/FormHandler/Manual/Cookbook.pod SHA1 2c10bd3851d4bd0d9b20050d2cff1d973ff33e2f lib/HTML/FormHandler/Manual/Database.pod SHA1 455e658e75e90ab4dd0f8b6e3ac0ec5a1ed7e8b4 lib/HTML/FormHandler/Manual/Defaults.pod SHA1 bc1dd7480e36e489538626aa20b50d257fc011d6 lib/HTML/FormHandler/Manual/Errors.pod SHA1 09a06eec5db80bfeba12bb7ae75e7bc727b7563f lib/HTML/FormHandler/Manual/Fields.pod SHA1 586f6f65cd48db4f8be66bace3c478670a77326b lib/HTML/FormHandler/Manual/FromDFV.pod SHA1 0b08a48531606337e59d0de5ae059d26bc2b6561 lib/HTML/FormHandler/Manual/FromFF.pod SHA1 d3cb5856148dddb388b9b4de9cafd08822b60542 lib/HTML/FormHandler/Manual/InflationDeflation.pod SHA1 0ce39aa42a3978fa0ddb78d184f4e3f70f31e057 lib/HTML/FormHandler/Manual/Intro.pod SHA1 53790bdbc39ee155897fc2d81888eab986baecfd lib/HTML/FormHandler/Manual/Reference.pod SHA1 32c65323001757194175d06e1c071849a6f9ede7 lib/HTML/FormHandler/Manual/Rendering.pod SHA1 35ee239c54cdd4f7d52a155a6738cc47bf4c4341 lib/HTML/FormHandler/Manual/RenderingCookbook.pod SHA1 d7143feb18c0e5b4fdd38cc2dc0f396d086ef427 lib/HTML/FormHandler/Manual/Templates.pod SHA1 51f7d8dcaecdfd6c5b7d70a40683498e47dd5113 lib/HTML/FormHandler/Manual/Testing.pod SHA1 af3c3493b2fb8758a03e0635f5e8d72dba597b8f lib/HTML/FormHandler/Manual/Tutorial.pod SHA1 8769cb2db66146cdc862c65dc3a80cc8c8064aba lib/HTML/FormHandler/Manual/Validation.pod SHA1 9e1d3bb99ef3d99b595a0686881790a53b722459 lib/HTML/FormHandler/Merge.pm SHA1 0fdd17b1f4eeb28afd9d2cf5634333f064e8f347 lib/HTML/FormHandler/Meta/Role.pm SHA1 5aac544dc81cc3c817bbd9d8eaeda0395ced0366 lib/HTML/FormHandler/Model.pm SHA1 7efcc781a37e622e9f61430f494c671751331c7a lib/HTML/FormHandler/Model/CDBI.pm SHA1 846bfa7a19ebafc69917c6c73f8829c709a8010c lib/HTML/FormHandler/Model/Object.pm SHA1 642273476c9fd6b7ce5891345e2a38c985859737 lib/HTML/FormHandler/Moose.pm SHA1 228a84bb1fca3f786e1ce08a94f597ae821a35a3 lib/HTML/FormHandler/Moose/Role.pm SHA1 8cd0a94a63b79f6411203aeda80a3c38d0611b38 lib/HTML/FormHandler/Page.pm SHA1 19936c5dab62e0d9b4709e337d2a20f5af166e42 lib/HTML/FormHandler/Page/Simple.pm SHA1 1d28f85f17d570b7bbe1e4d75ffc5b0e90f8526a lib/HTML/FormHandler/Pages.pm SHA1 3d97ef2dc65ec8efd6c0b46595e90a01105b484a lib/HTML/FormHandler/Params.pm SHA1 3689890c0a3a30c85a89f9b850ba11e26c94221a lib/HTML/FormHandler/Render/RepeatableJs.pm SHA1 f8061e091e1663fa416655f3ac7c5c9934ef42ef lib/HTML/FormHandler/Render/Simple.pm SHA1 faaf5fd36ad5923c01e87d383f76b92f76f52ac9 lib/HTML/FormHandler/Render/Table.pm SHA1 b8d3c8f806326bc3755578c17727d9358dcd80f6 lib/HTML/FormHandler/Render/Util.pm SHA1 d4ef46c39fd07b5a321d0eb2742ded252727fb9b lib/HTML/FormHandler/Render/WithTT.pm SHA1 35a7e17d73329dd334d829d2167bbcbc7f61fb5c lib/HTML/FormHandler/Result.pm SHA1 11d58b8ca882bc3d63f8a0655ce90b79477efac6 lib/HTML/FormHandler/Result/Role.pm SHA1 da3fc1ced14b943c5e09cb7cc01ee1aaac68ac1f lib/HTML/FormHandler/Test.pm SHA1 f4121774be5785f6c6fc2b4e993fbe78d9b8d8b2 lib/HTML/FormHandler/TraitFor/Captcha.pm SHA1 22dfb0bbf1a422aac3fd40920d44396ce4eb6253 lib/HTML/FormHandler/TraitFor/I18N.pm SHA1 369de94d2245cbe3423304d3bc3c29d11e24a1df lib/HTML/FormHandler/TraitFor/Types.pm SHA1 905176afe01a398d3272cfdb2819db6a6012bd99 lib/HTML/FormHandler/Traits.pm SHA1 3b1147b389c1ff15ac38b7fdc6a41f247cecc95f lib/HTML/FormHandler/Types.pm SHA1 89aa8095cb6d3e5da54e8b07b1418c00d011363d lib/HTML/FormHandler/Validate.pm SHA1 bbdbbe438e4ea9afd9b8a8b2f731f4c6c9b21ccc lib/HTML/FormHandler/Widget/ApplyRole.pm SHA1 d5a98fc5184526cb163c31887d1dfe85142f9134 lib/HTML/FormHandler/Widget/Block.pm SHA1 251374e3914a5fba9169813e1162356ae9cdbda9 lib/HTML/FormHandler/Widget/Block/Bootstrap.pm SHA1 8e81f440565a2cae100798048e46a5dea5f42407 lib/HTML/FormHandler/Widget/Field/Button.pm SHA1 e84fb8be92ff744160973b39d2830ea4391020dd lib/HTML/FormHandler/Widget/Field/ButtonTag.pm SHA1 22364764fc96db988c9a6509026e2f76dc47571f lib/HTML/FormHandler/Widget/Field/Captcha.pm SHA1 a1756fd01ccf06c48b2fbd0524ccedb4a520b26a lib/HTML/FormHandler/Widget/Field/Checkbox.pm SHA1 b11e165f82da7f051d196f6ca9ef74a82d9d95de lib/HTML/FormHandler/Widget/Field/CheckboxGroup.pm SHA1 d96885ee9d7fbdc058fe870af43694acb5d16943 lib/HTML/FormHandler/Widget/Field/Compound.pm SHA1 4e0987af5cdb933d6906aa9176e583dbd71eec86 lib/HTML/FormHandler/Widget/Field/Hidden.pm SHA1 773e977c360298774a7d7057983b13d9c98f00c2 lib/HTML/FormHandler/Widget/Field/HorizCheckboxGroup.pm SHA1 bc04e9d132f0d124067b9d9aa4e44b52d8ac3eec lib/HTML/FormHandler/Widget/Field/NoRender.pm SHA1 ecf6cf901ad55689622e3c0173ee68d1f1287da2 lib/HTML/FormHandler/Widget/Field/Password.pm SHA1 3f5d4c31cc313eb8ab924bcaedfed89b2f149752 lib/HTML/FormHandler/Widget/Field/RadioGroup.pm SHA1 f42e14a6d8c50e6075cf250b4e9b9c32ed6c73a2 lib/HTML/FormHandler/Widget/Field/Repeatable.pm SHA1 198be2917de3c163169fec4a963076054cd2eff9 lib/HTML/FormHandler/Widget/Field/Reset.pm SHA1 8cb1de8af89010fa162046bb1d72a4c38f14fceb lib/HTML/FormHandler/Widget/Field/Role/HTMLAttributes.pm SHA1 0286f99eb83fc2f86475377ad4caae4443b53f42 lib/HTML/FormHandler/Widget/Field/Role/SelectedOption.pm SHA1 71df059772e8e30538fa25531acc8da1a8c41c2b lib/HTML/FormHandler/Widget/Field/Select.pm SHA1 b0030431d05bb660ecc52e887ef8c2bab90b6969 lib/HTML/FormHandler/Widget/Field/Span.pm SHA1 de84bf53492f01ce2a556ebf17252eb38a375592 lib/HTML/FormHandler/Widget/Field/Submit.pm SHA1 1c18fd146c99d7223c360df7e0093026efa34c54 lib/HTML/FormHandler/Widget/Field/Text.pm SHA1 a570aae30c2b83b50933e7de335a23192b34b16c lib/HTML/FormHandler/Widget/Field/Textarea.pm SHA1 4e5148aaba715555c35bf9809bcf501a35966750 lib/HTML/FormHandler/Widget/Field/Upload.pm SHA1 45719071268f8afff85920ff112d16d5bea7a5fb lib/HTML/FormHandler/Widget/Form/Role/HTMLAttributes.pm SHA1 c6c5d772002376ca95ecd324c1c40f254399941c lib/HTML/FormHandler/Widget/Form/Simple.pm SHA1 f10f6c1efb0ce00ae81d130b4c6bceb35de403ab lib/HTML/FormHandler/Widget/Form/Table.pm SHA1 5ac3513f597057c2367d4f2b52c3d8d64130a57e lib/HTML/FormHandler/Widget/Theme/Bootstrap.pm SHA1 44308d870686aed3e594a5606cbd0ff8e7a46968 lib/HTML/FormHandler/Widget/Theme/Bootstrap3.pm SHA1 3dd089e431093dc5223f721fc12d5c602a7ef57f lib/HTML/FormHandler/Widget/Theme/BootstrapFormMessages.pm SHA1 b17311df5babce4a086988fed5fe93ca67c9f3d1 lib/HTML/FormHandler/Widget/Wrapper/Base.pm SHA1 1c23982a3a373bcf5f3bccba7a63c01c18eea514 lib/HTML/FormHandler/Widget/Wrapper/Bootstrap.pm SHA1 ca2b192f076665d31ecc8eae8e9cb696cbf1cf26 lib/HTML/FormHandler/Widget/Wrapper/Bootstrap3.pm SHA1 bdfdb7829efb4b89ce84115d11a318bcffe02d70 lib/HTML/FormHandler/Widget/Wrapper/Fieldset.pm SHA1 8276f81bb28acd9aec9f1cff58a191761b1382c2 lib/HTML/FormHandler/Widget/Wrapper/None.pm SHA1 a0bb3a48af3d794abb1c65b07bdbb6a147fded67 lib/HTML/FormHandler/Widget/Wrapper/Simple.pm SHA1 893420fc04a0fa1df5e30795770eddb1aea18236 lib/HTML/FormHandler/Widget/Wrapper/SimpleInline.pm SHA1 013b3da4192fcf157c725079f66fa9e8cdf2182b lib/HTML/FormHandler/Widget/Wrapper/Table.pm SHA1 af8471b12bc7c1f52c7869f3aa0b08cab0612bdd lib/HTML/FormHandler/Widget/Wrapper/TableInline.pm SHA1 de98b4632bab65c91fec92d1f032f5a9d372c600 lib/HTML/FormHandler/Wizard.pm SHA1 794da1f2f7c41af8edd5fc53e766a33072c10c91 share/templates/field/button.tt SHA1 3681fc90aef0523ca43663e10a2e2798d7a413ab share/templates/field/checkbox.tt SHA1 acc9394577fdda7a1408ee052792c70f00340c34 share/templates/field/checkbox_group.tt SHA1 86d4b217c985f6a4f501b32f4c92a8e388285f1d share/templates/field/compound.tt SHA1 67db06d5868ee6bd9ef38350325436f4da3e19ac share/templates/field/hidden.tt SHA1 44ac0e6fc4db1bcfe561598258528e6f0000f37e share/templates/field/password.tt SHA1 c5c430236706e7bcbb2d88b43c3fdd10ea7b8fa5 share/templates/field/radio_group.tt SHA1 a660124b371ce25428bc1a9f9facaa31eca9d8cb share/templates/field/repeatable.tt SHA1 cb99bbd10c2067d02e0e9b7a898e7535a1108c59 share/templates/field/reset.tt SHA1 5de099392c362013ea3dc49c17be7f01cac987fc share/templates/field/select.tt SHA1 776c16b7c5744cd197bdeb8b7b2981ec631eab31 share/templates/field/submit.tt SHA1 f539376e39505417ed106c9a8239aad1102ee226 share/templates/field/text.tt SHA1 5ed10a483ec32dde1dbcd92a9c89e364ec75c401 share/templates/field/textarea.tt SHA1 d963677f9ec0d30e1abe3a604fbc6a80c8489498 share/templates/field/upload.tt SHA1 b2faa01201389f379517e3955f686b04c045793a share/templates/foo/checkbox_tag.tt SHA1 90d389dd6cd2ad7431f9172a225eea49975a3712 share/templates/foo/end_form.tt SHA1 b128ee5ab6181501a2a7675efa8d908845e545f7 share/templates/foo/field.tt SHA1 04b81260d43b3c7a4cd324556f6e9ab47f1e2644 share/templates/foo/form.tt SHA1 d21cd1dc150147d5688ae048dc0c1f3c5ae59283 share/templates/foo/input.tt SHA1 dbc5ab703565e950469a288390dfd94be437d7d2 share/templates/foo/input_tag.tt SHA1 5886e336a836a6ce4df0559dee82cfcd30ff35eb share/templates/foo/label.tt SHA1 63cb1701b6b97d8c092b5b5afd66cd03faaf5dfd share/templates/foo/start_form.tt SHA1 378ff945471b9b88de9a04cec914d900dc2dd06f share/templates/form/form.tt SHA1 78b7b8068756334ca53c8a7624076918c71fce40 share/templates/form/form22.tt SHA1 90d389dd6cd2ad7431f9172a225eea49975a3712 share/templates/form/form_end.tt SHA1 8b310b0206b7126daf1d7812a884df95e3751c70 share/templates/form/form_in_one.tt SHA1 63cb1701b6b97d8c092b5b5afd66cd03faaf5dfd share/templates/form/form_start.tt SHA1 27e0470ee115b9f96c9cef602703e71c0d71b725 share/templates/wrapper/fieldset.tt SHA1 a6f1dc7378d74c91fca73dd9cda322636c9f6dc8 share/templates/wrapper/label.tt SHA1 475346c385a4f2fdd668aab9f6b0e1f8d63522d0 share/templates/wrapper/none.tt SHA1 96b3d105205e2bde31af480ae3774c6c58c1589d share/templates/wrapper/simple.tt SHA1 edbdd55a879e452a4bbd0efad463c2be27dcb80d share/templates/wrapper/wrap_label.tt SHA1 d55b2da9ebb18c4da78ae398a555d19728397acd t/01app.t SHA1 488cbed50b454798db401dc8e2720ec601b6df68 t/author-eol.t SHA1 cd5f377bc07357aae0ddf592fdf97aef6ff60489 t/basic.t SHA1 9ccc83343d981613ac0c71f941a206b9d50223e4 t/blocks/basic.t SHA1 d164545e6a42ed3cc2e8323abe759ace1b2f8765 t/blocks/block_list.t SHA1 0ac8fde2c904dfb30544de720fbef9c9580c4bd7 t/blocks/blocktags.t SHA1 b1f78d867fcf6aa011d9286ab1d05e018a49eddf t/blocks/loading.t SHA1 1e8ec64e5640cfccfdfe2d0d2ab921d25891a917 t/blocks/nested.t SHA1 f09cd0aba1ed89940f4b3e75d6dbd8b7b6235ab6 t/blocks/render_units.t SHA1 733e77823d3d86ea38382d691397353b87ac26ab t/bootstrap/basic.t SHA1 7301ecf03852708029d8e59997e149590f596f60 t/bootstrap/control_states.t SHA1 ae16a51d2a268b80c575175904cd6795073636ae t/bootstrap/controls.t SHA1 6110d50ed54a4606e882494064c11d933bd766ae t/bootstrap/ext_controls.t SHA1 eaa1754ec21ec4fd417ba15d1cded0002169b36d t/bootstrap/inline.t SHA1 8e7d351b4f1b296106c6928785c02c69745c7338 t/bootstrap/other.t SHA1 125b1f1217851c8d468d33316a017b8756b63221 t/bootstrap/search.t SHA1 b7f3d404d5ae0aa94c1b5f61f7e5582beb983a45 t/bootstrap3/basic.t SHA1 3ba503de363c86bbe821e986455bad58f95976d7 t/bootstrap3/controls.t SHA1 fbac5e409e361615cd723635299cf7e06132b01c t/bootstrap3/horiz.t SHA1 cfc7b730c83305dd93946678c4289cb4e401de08 t/bootstrap3/horiz_checkboxgroup.t SHA1 0718779ad9787d39230aa12efdb0ecf3d0cee275 t/bootstrap3/inlinecheckboxes.t SHA1 aa4a34c0a641d66ca56140cbcc732b5942d34b79 t/bootstrap3/layout_classes.t SHA1 99db89ba2029b09d8aceebe7ca3a0d2a4bc3804e t/compound/basic.t SHA1 076f5508b176cc8df148e3c54f8c02506c61ebfc t/compound/default.t SHA1 5113d3260a143cbb4214c532b0267013485f9866 t/compound/empty.t SHA1 3484c409ef375e7c7a383fe1a21afdffa88bcb67 t/compound/include.t SHA1 e70e61d29017ca572169563f5bc5f04409d75223 t/compound/select.t SHA1 9b3346315f550ac726c9733c750ff26cf205789e t/errors/basic.t SHA1 45c2969b6e22b940d89c282f29cb12393320b5ce t/errors/compound.t SHA1 96b02b3f93ab1c096ab6e64d6cadfde6cfb887eb t/errors/form_messages.t SHA1 4da7ca25cadbdddd2c61f5fd43b8d46568e03c6a t/errors/messages.t SHA1 a98bd1e8013013d26ca7ecd2bdcac079969a255a t/errors/req_message.t SHA1 b34ec719574cc0bbad22b820a6ba617f8f7afcdc t/field_setup/checkbox.t SHA1 39c71d5c367b29a0ca4fc7a8b96ce19f226cb913 t/field_setup/compound_update_fields.t SHA1 d0e5f8d2b24883af8e1d835c7f777b0cc4dbcf80 t/field_setup/defaults.t SHA1 d48b9904cd8546c3fd23653628bb0aad999e7b51 t/field_setup/disabled.t SHA1 c9ce3ecb482109d83fdac934784d81f5c21ee743 t/field_setup/id.t SHA1 4867c2f3cfc14d5b82e3ce8177dc4b355771ec6c t/field_setup/inactive.t SHA1 97744c22607da7adacafa6a3952bc0568a817de8 t/field_setup/init_object.t SHA1 3963aec76768a163add932eb82d3700ef19c0820 t/field_setup/input_param.t SHA1 e5e246a2d74b0cf478c859fa7f5d59f26e4886ac t/field_setup/missing.t SHA1 99b4bed094f697439910d0106e1018a4688f209f t/field_setup/plus_field.t SHA1 5ef5f0dca7f29790083872ded07fbdaddba5b4b5 t/field_setup/update_fields.t SHA1 ee3294fdd0643d1a13fdf0f813f6b75b5c1762fa t/field_setup/update_subfields.t SHA1 c79522cffc29aa7a10f478a7a2cf206a8d5bdc98 t/fields/dates.t SHA1 b49610114fcca34d34b2d3a302efeb7a4499c8fe t/fields/display.t SHA1 4e7421c927b94f2c8a49f3cffbe20526a7ed26b5 t/fields/fields.t SHA1 32ffb3e7403b82fd033326ed8dfa1950330f8f99 t/fields/float.t SHA1 1c7e3714c63b6ca0f42bad837b9fde746bcfac2c t/fields/formhandlerx.t SHA1 eb62c3ad672f8697c0cf6eafd6a5474c904cee8d t/fields/novalue.t SHA1 03e8a04c7c3e5590deea887bb176e59dcea90472 t/fields/password.t SHA1 544f7a16def20df3347f502e3357b85a435d1671 t/fields/repeatable.t SHA1 8989c771bf86ea48804f9016aa8481aa7120711a t/fields/select.t SHA1 f233d0276585178953f92da2dbd51b8482676c0d t/fields/select2.t SHA1 267cb4dddb0fb7e7ba5c93b33c209fc95c50dbbf t/fields/selectcsv.t SHA1 62c3a4d7ef2aafbfe365d29244f8030b9db298e8 t/fields/textcsv.t SHA1 7846a6c8a3ab1463756f3cb97edd688e1431a8c6 t/form_setup/api.t SHA1 4e01795fb844699a5482d0429bf678d63002b94a t/form_setup/clone.t SHA1 76bef41216e5703501cbdc5e1524ad6d9e9693df t/form_setup/compound_field_list.t SHA1 f4bf6e023e39186b1fe371e41033c689ea0fcc84 t/form_setup/config.t SHA1 f6d1ddf31d2715bc0e0fae057905658bd9234cb1 t/form_setup/dynamic.t SHA1 3322e427487ebea857befbdde07f3ec404a7047e t/form_setup/include.t SHA1 d0eb67a45078195f6d4a3281f51cf66820ed31db t/form_setup/init_obj.t SHA1 93559f482788e583eb24d7bcb5fd1187b4e66a4b t/form_setup/no_update.t SHA1 4b95ce6100c2b052109ec965ac52c864a58f751b t/form_setup/posted.t SHA1 0972c2048c440a92020f7eba9473e09eac3105ea t/form_setup/render_roles.t SHA1 12375d16dfb7f3c00385c0834976e594172319d3 t/infl_defl/comp_field.t SHA1 8685c2e531341016ed61439c2ab9df7b50818266 t/infl_defl/default.t SHA1 e1cb08e56c1268ea619c5bf80731b90047f95735 t/infl_defl/defl_lives.t SHA1 458176d710595080122f1ee6d93adfc5938dc87d t/infl_defl/infl_defl.t SHA1 8e2043b8edf2a460282743a6edfb15859958426d t/infl_defl/infl_transform.t SHA1 cda457f835bc268a1d3c4e6d7b177ab4a4e2be51 t/infl_defl/variations.t SHA1 e330f72586852fb7f18c444008ab792c3e04b6c6 t/lib/BookDB/Form/Upload.pm SHA1 f5a80fcbc4f14894c274ea1e896067cc45143312 t/lib/Field/Address.pm SHA1 df80db13f94fe5044c995228ade46b8cd341045e t/lib/Field/AltText.pm SHA1 498e59d660a0b78b32565494484cb75ce9cad9c3 t/lib/Field/MyField.pm SHA1 3de5695a354809ff50f2900d257ec7eb195f9db7 t/lib/Form/Address.pm SHA1 3fa8edbecc482588a667d4ff0f938da4ab60b3c6 t/lib/Form/AddressRole.pm SHA1 37ae2600a3998048b253de1e96ee7b7d7597281c t/lib/Form/Multiple.pm SHA1 f01a56814525ff213d829b7499bbfef06fc90538 t/lib/Form/MultipleRole.pm SHA1 cf460b1f0a0106df286bffeae39cc321472d4e7b t/lib/Form/NoExtForm.pm SHA1 58469593246683e39a8fa3bdcf07b2669c9cb59a t/lib/Form/Person.pm SHA1 51ceda9acbd63d49a81a959adc27285a42e5ff27 t/lib/Form/PersonRole.pm SHA1 94cd172b90fd02eab01eb6e528c9e701eb914fd1 t/lib/Form/Test.pm SHA1 d6ce4712417f325870983a7e6f7d07e52c10974f t/lib/Form/Two.pm SHA1 d92e6eaa78b5fe830c108a1f91fb0aa6ea82cd39 t/lib/MyApp/Component/Section.pm SHA1 5239c744281b45b5ee49e4498fe5a04822ea1766 t/lib/MyApp/I18N/abc_de.pm SHA1 3b549a8c8d4fdc4e55ec323fac3eaf48111f8320 t/lib/Widget/Block/Test.pm SHA1 364e324607d74434dc26938a08fec784de110737 t/lib/Widget/Field/Omega.pm SHA1 7d6fdb503d9aee63eb6a79ec86d33997faf8b383 t/lib/Widget/Field/TestWidget.pm SHA1 eed8ac3446c4a13d80720503345cfb54395571b9 t/memory_cycles.t SHA1 725aeac4b9c347859d451fe700fd5988dab60055 t/moose/build_id.t SHA1 9489e970b3d3f5bd0ca82ba7704a0589546d278c t/moose/composed.t SHA1 7ad31d0a34a696fc1b05aca77302b050abeb189a t/moose/field_traits.t SHA1 1908e358a05fb889f1d3e76bc462df747766f5eb t/moose/no_extend.t SHA1 2fcb1cf1667bbf821cac0eba3389357dec953857 t/moose/subclass_roles.t SHA1 6af16b8f551ada3ee2e7c260d3573ca095bdf503 t/release-no-tabs.t SHA1 d69dcbcff41cd0df28bf36527ddb37d447754932 t/render/actions.t SHA1 c1191d24fc2785ef40103d2191e87dfe92ee71e9 t/render/array.t SHA1 5a953cb7108e91b26087649ce7aa7cf9d213b650 t/render/basic.t SHA1 07244bfe73f681547ed1f51fa6f9b81d17ce356a t/render/checkbox.t SHA1 8541c93eca5d0804ae369fd226022c2371193621 t/render/checkbox_group.t SHA1 a5df3850dc018534a798cb15ea6150c00e165753 t/render/classes.t SHA1 b3bb4fcdaf7528300f7d3853c768812d86fe0f78 t/render/compound.t SHA1 8e30bceab9974e70669803515b19ba17848877f2 t/render/compound2.t SHA1 9d74a680a8b8420ccf65fca01ed631c25ca8e724 t/render/display.t SHA1 4e2142b5f91f776af188e3edeea4b8530ed0f59f t/render/errors.t SHA1 e9779e6c5b64ac56a003e9ce4678b1f61149c5f3 t/render/escaping.t SHA1 34169ac2fd52733922c55e3b1371ac47d3d49d9c t/render/ff.t SHA1 ae10e2cea31a74caae799668c2742e9596dc2a85 t/render/filter.t SHA1 baee60bf749cdd64dbe05404b5fbb97f9246f07b t/render/form_errors.t SHA1 10c270e17ff97aebde06110159bb3662ccdfc7b5 t/render/get_tag.t SHA1 782a804a2ed9a197f983ef954a31babd316a35c7 t/render/html5_attributes.t SHA1 ae53d67a44b13e3c1da6fcc79bca8c9221c974f0 t/render/html_attr.t SHA1 93a47fa99029371cca018337acd5a56911a90064 t/render/html_attributes.t SHA1 429398d9de168ed3f03b6d4ce01ab1bdccc787e6 t/render/inline.t SHA1 f43bbd9c8aedd00c513e72a5748bce5355b188b3 t/render/label.t SHA1 055b6f61d8e45ddb9b2c6905680dcb70b256c63b t/render/noneditable.t SHA1 5b88d772b395d9f2876be4e8e1498ba6266842e2 t/render/optgroup.t SHA1 654948efd382323ce4bb0d267f4f9c168868204b t/render/radio_group.t SHA1 7175a9276b2f6cabcd4382ef846ec84157ba79d4 t/render/rep_fieldset.t SHA1 b6ef18105cb6d136f78217e38f42f09f93c7d2f6 t/render/rep_wrapper.t SHA1 406f852e54337b6b1888398e6042f399cbffb9fc t/render/repeatable.t SHA1 b9b3e4d218182714100a52561502c9c14e34bb1b t/render/result.t SHA1 90e802e12c26b25a7f88802cfdcc3eb6f1ae9198 t/render/select.t SHA1 17dc198e476104266c590d5dd8bc61c8f7934c1d t/render/simple.t SHA1 544a4a24dcb34fc50fc4c18ebc6aaa48f5cceb3a t/render/submit.t SHA1 7ac35647e2a90f8de10a0b8f5569ce2728c2972b t/render/table.t SHA1 17c04b46c520260fadf04cc4a7c5acdc0004dcb2 t/render/tags.t SHA1 aa807aff3acbda893ccbd6400c1c473fcf67189d t/render/tt_render_elementx.t SHA1 d977f8cecf28d424cde917093535cbfc6fb27ea3 t/render/util.t SHA1 f4e53913e5882a765e13e93d84d5a498a03569fa t/render/widget_loading.t SHA1 98dcba91ccb83597ef0170ad045291bded439c41 t/render/widget_tags.t SHA1 93033625a3a956991cfb3e5354141a3e924aab0d t/render/widgets.t SHA1 7d5d0825b48ea1047f5de81e696daebca856df32 t/render/with_class.t SHA1 23ea3683a53943fcba024599cbba28761cb5b8e4 t/render/withtt.t SHA1 fe4e8b94c36d1707101b3d329069172536e4aa6e t/repeatable/defaults.t SHA1 2778a516f22e0b0d8d14db468304821fa262e3ab t/repeatable/empty.t SHA1 0362d4289b5d7c15f31d0fc9aadc32738b894704 t/repeatable/has_many.t SHA1 388ed334251b9db9f096a6884c01ff00e3e3fe2b t/repeatable/hash.t SHA1 34075dacb6d838e9f9b88e1966678230efaf87fb t/repeatable/js.t SHA1 f50d0e2ed62e9a9a8e455aa4ccecc533801ee8ad t/repeatable/list.t SHA1 c875b3c645f32bb58ee195aae4042a6e4851dc94 t/repeatable/nested.t SHA1 4e0978924167cb79c7be49ffa104b9fffada8616 t/repeatable/nested2.t SHA1 bf316fc1f7fb0ab2e90b50244fae2f7d71b5872a t/repeatable/num_extra.t SHA1 f08e15a8370c204d16b4a4dd899f0b8c8f6f2773 t/repeatable/reload.t SHA1 fbe8ae9d5062acb07c81ac8c5d733ac2be22154a t/repeatable/set_methods.t SHA1 359087d5f8a029fabad7944fa3ff2af9c6a6ed79 t/repeatable/subfield.t SHA1 b771d6ebc02f44fbebd3868894022a0bd959b001 t/result/basic.t SHA1 e94436b6500a0e51fcfce7b217547775f65e58a5 t/result/blocks.t SHA1 24b760833e98e72c96a41ab615568f825b0c358b t/result/compound.t SHA1 14babbbd7dbbf7acf3e8a887066eb1b6a66b3259 t/result/errors.t SHA1 724bf07cbf1f65c22fdf7c211ed758874f6d2aef t/result/repeatable.t SHA1 b83f7770be71ea9e5b627f0323a207bf6e94efce t/structured.t SHA1 ed8a1b0d5f149f02df2dde44f58fc814516171c8 t/template.t SHA1 2c0584c0a616ec1f3ab7cef0b4310df844d45fce t/validation/apply.t SHA1 c8b2d029acdc6c58ff0e44a25404549ac6c6680f t/validation/constraints.t SHA1 a7469a1fb8a0e7b3e1af9e5dfd9674eae54e8d7f t/validation/dependency.t SHA1 fa54bae035104eac9559c449aa0d80ba8e2649d3 t/validation/filters.t SHA1 8bebaf81f0a777a646972ea49a0e07b0d700effe t/validation/reqwhen.t SHA1 8e379034c33ab1ee3d70c6e9db1b067777bf7f86 t/validation/type_tiny.t SHA1 9217945ea0f55aef934824ab82fb2f2c88dcd67e t/validation/types.t SHA1 60761cd04a6350433097c91e438bef74f5ca53b7 t/validation/validate_coderef.t SHA1 bc0b36210f8c7fcc56c9fb9b805cbc993c4394bf t/validation/when.t SHA1 8e040ebd13ce2e819310418baeca2b44c46eadf0 t/var/form1.pl SHA1 2d8d392a1c132b6c6f49fbf2c8eea327d89f1104 t/var/form1.yml SHA1 d23691c4eb64f6237f37959e18ac1d40b0d5c618 t/wizard/basic.t SHA1 6cbc9f61f49670b2211f2fa5157631246b65ebf5 util/check_I18N.pl SHA1 6df1c66c420e0f42840fa6d6c46daf4290630e7a util/get_messages.pl SHA1 e2f1f4a7bd5660f67237752e4b26c57fb08e3187 util/messages SHA1 86d255a7c9f065a13049108362c949b3e35a4c24 xt/02pod.t SHA1 65ca268d24f92823c6a33fcbe7640857315e0d0e xt/add_field.t SHA1 77fc699934e5885b083a8e4485ed3d20c76550b8 xt/captcha.t SHA1 84bae2a79191282ea96e987c00439d7c72bcdad6 xt/captcha2.t SHA1 a536583356d1f37258e77d8bae3491bd3b36793e xt/chbox_group.t SHA1 2148bb20efb65181d062d0906e4d10a904735e2f xt/check_selected_option.t SHA1 1edadbbec253933b48f5185dc9c367acb8472163 xt/custom_fields.t SHA1 4c47aa23f9cdaf64d628ff069666a1caca5c385a xt/cycles.t SHA1 6fe7330dcf9aeb70f6fb8f6f17d1a691df027f36 xt/dfv.t SHA1 4e292478d5ce0ba4b4dc98cfffd15d767e442378 xt/display.t SHA1 2a3193b807b6df2f6964d98a854b95b2bac12184 xt/email.t SHA1 88654c3432fbde212db1de54ba74478ded6c38cc xt/eol.t SHA1 0f80fc1a2dd60772c5ec83096af23b54398b63c1 xt/field_list.t SHA1 e0bae1206838fa9f79e11899182601e1ede46176 xt/form_errors.t SHA1 c08a4366a8d2aad7ac677541352d5ea3cd708043 xt/init.t SHA1 a4f3c6e37039a856f555e8923dcb7b09809b24cf xt/lib/MyCatalystApp.pm SHA1 b689a246cde895936371a1b33245a5c78e4eda68 xt/lib/MyCatalystApp/Controller/Captcha.pm SHA1 aefd98c4a4d10ca1063ebc43d0ee979c01c46154 xt/lib/MyCatalystApp/Controller/Root.pm SHA1 d02a4b95dfe88f5b748acdcd1efda6f4c53012d5 xt/load_field.t SHA1 fbada2c08ac6f80f03050d4af4b0b889b03146b9 xt/locale.t SHA1 183db3551cff148adc7d611af316f3739953afec xt/locale_data_localize.t SHA1 db6e66c79f25cdcf6435f021499473475fdb15a1 xt/mb_form.t SHA1 1ce3a2c875d974a0f81e1233be575386a1bc5612 xt/model_cdbi.t SHA1 a4127156e8dad3f81624bf6b5f5683931f76f88f xt/multiple_forms.t SHA1 94f2ae2ffc6b9e178bf144604b2b68d94af2ecb3 xt/order.t SHA1 b89aefcbbc7f6fbb350932bdedd031b15c66cb9f xt/params.t SHA1 1a18e8b9e12e2a35fe3e08a40547da667c047d3a xt/posted.t SHA1 5554a5710a78de48ea5e7e639eb2483a33e72e40 xt/repeatable_clone.t SHA1 0ad8d5fe3ee1aef6f9f78b7035cf7058ad0eb814 xt/submit.t SHA1 11cfd9ee49b356722fc0b09c75b5110fed8759c2 xt/upload.t -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.22 (Darwin) iF4EAREIAAYFAlX61KsACgkQlX0ZOkgCuch6FwD+JydfsldLCRQema/oPZl8vOvO GEXjMcAGyXjr/vTjbZkA/3dfScvCdq0H+lH4D4u8cod6wSg2KK6oFZwMqu12n0Un =sp87 -----END PGP SIGNATURE----- 02pod.t100644000770000024 27612576552253 16213 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More; eval "use Test::Pod 1.14"; plan skip_all => 'Test::Pod 1.14 required' if $@; plan skip_all => 'set TEST_POD to enable this test' unless $ENV{TEST_POD}; all_pod_files_ok(); email.t100644000770000024 212112576552253 16365 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; BEGIN { eval "use Email::Valid"; plan skip_all => 'Email::Valid required' if $@; plan tests => 7; } $ENV{LANG} = 'en_us'; # in case user has LANG set my $class = 'HTML::FormHandler::Field::Email'; use_ok($class); my $field = $class->new( name => 'test_field', ); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input('foo@bar.com'); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, 'foo@bar.com', 'value returned' ); $field->_set_input('foo@bar'); $field->validate_field; ok( $field->has_errors, 'Test for errors 2' ); is( $field->errors->[0], 'Email should be of the format someuser@example.com', 'Test error message' ); $field->_set_input('someuser@example.com'); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'email' => ( type => 'Email', email_valid_params => { -mxcheck => 1 }, ); } order.t100644000770000024 76712576552253 16407 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More tests => 3; use_ok( 'HTML::FormHandler' ); { package My::Form; use Moose; extends 'HTML::FormHandler'; sub field_list { [ field_one => 'Text', field_two => 'Text', field_three => 'Text', field_four => 'Text', field_five => 'Text', ] } } my $form = My::Form->new; is( $form->field('field_one')->order, 1, 'first field order'); is( $form->field('field_five')->order, 5, 'last field order'); cycles.t100644000770000024 71012576552253 16542 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More 0.88; use Devel::Cycle; { package FormHandlerMemLeak; use HTML::FormHandler::Moose; extends qw/HTML::FormHandler/; has_field test => ( type => "Text"); sub default_test { return "test"; } sub validate_test { return 1; } __PACKAGE__->meta->make_immutable; } my $i = FormHandlerMemLeak->new; find_cycle($i, sub { fail("Cycle found") }); ok $i; done_testing; locale.t100644000770000024 1120412576552253 16557 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use Test::Exception; use HTML::FormHandler::Field::Text; use lib ('t/lib'); # ensure $ENV is properly set up my @LH_VARS = ('LANGUAGE_HANDLE', 'HTTP_ACCEPT_LANGUAGE', 'LANG', 'LANGUAGE' ); my %LOC_ENV; $LOC_ENV{$_} = delete $ENV{$_} for @LH_VARS; # a primitive translation package { package HTML::FormHandler::I18N::xx_xx; use base 'HTML::FormHandler::I18N'; # Auto define lexicon our %Lexicon = ( '_AUTO' => 1, 'You lost, insert coin' => 'Not won, coin needed', 'Test field' => 'Grfg svryq', ); } # a simple demo form { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'test_field'; } my $form; ################ Locale -none- $ENV{LANGUAGE} = 'en-US'; # create form w/o locale must work lives_ok { $form = Test::Form->new } 'create form w/o locale lives'; ok($form, 'create form w/o locale'); is(ref($form->language_handle), 'HTML::FormHandler::I18N::en_us', 'locale en_us'); # ensure we know / don't know the translations $HTML::FormHandler::I18N::en_us::Lexicon{'You lost, insert coin'} = 'XX Dummy 42'; $HTML::FormHandler::I18N::en_us::Lexicon{'Must insert a [_1] coin'} = 'Want a [_1] coin'; delete $HTML::FormHandler::I18N::en_us::Lexicon{'Test field'}; delete $HTML::FormHandler::I18N::en_us::Lexicon{'You won'}; # translating a known error works $form->field('test_field')->clear_errors; $form->field('test_field')->add_error('You lost, insert coin'); is_deeply($form->field('test_field')->errors, ['XX Dummy 42'], 'error is translated into en_us'); # translating a known label is($form->field('test_field')->label, 'Test field', 'Label w/o translation = ok'); # translating a known error with a positional parameter $form->field('test_field')->clear_errors; $form->field('test_field')->add_error('Must insert a [_1] coin', 'cleaned'); is_deeply($form->field('test_field')->errors, ['Want a cleaned coin'], 'error w/parameter is translated into en_us'); # translating an unknown error also works $form->field('test_field')->clear_errors; $form->field('test_field')->add_error('You won'); is_deeply($form->field('test_field')->errors, ['You won'], 'error is translated into en_us'); # translating an error with bracket issues $form->field('test_field')->clear_errors; dies_ok( sub { $form->field('test_field')->add_error('You are not authorized for this archive. See: [more information], [request authorization]') }, 'dies on maketext error' ); lives_ok( sub { $form->field('test_field')->add_error('An error with ~[escaped brackets~]'); }, 'does not die when brackets are escaped with tilde' ); ################ Locale xx_xx set via ENV{LANGUAGE_HANDLE} $ENV{LANGUAGE_HANDLE} = 'xx_xx'; # create form w/ locale must work undef $form; lives_ok { $form = Test::Form->new } 'create form w/ locale lives'; ok($form, 'create form w/ locale'); is(ref($form->language_handle), 'HTML::FormHandler::I18N::xx_xx', 'locale xx_xx'); # translating a known error works $form->field('test_field')->clear_errors; $form->field('test_field')->add_error('You lost, insert coin'); is_deeply($form->field('test_field')->errors, ['Not won, coin needed'], 'error is translated into xx_xx'); # translating an unknown error also works $form->field('test_field')->clear_errors; $form->field('test_field')->add_error('You won'); is_deeply($form->field('test_field')->errors, ['You won'], 'error is translated into xx_xx'); # translating a known label is($form->field('test_field')->loc_label, 'Grfg svryq', 'label rot13 to xx_xx'); # remove from environment variable, so we can use builder delete $ENV{LANGUAGE_HANDLE}; { package MyApp::Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use MyApp::I18N::abc_de; sub _build_language_handle { MyApp::I18N::abc_de->new } has_field 'foo'; has_field 'bar'; sub validate_foo { my ( $self, $field ) = @_; $field->add_error('You lost, insert coin'); } } $form = MyApp::Test::Form->new; ok( $form, 'form built' ); $form->process( params => { foo => 'test' } ); is( $form->field('foo')->errors->[0], 'Loser! coin needed', 'right message' ); is( ref $form->language_handle, 'MyApp::I18N::abc_de', 'using right lh'); is( ref $form->field('foo')->language_handle, 'MyApp::I18N::abc_de', 'field uses form language handle' ); $form->process( language_handle => HTML::FormHandler::I18N->get_handle('en_us'), params => { foo => 'byebye' } ); my $field_lh = $form->field('bar')->language_handle; is( ref $field_lh, 'HTML::FormHandler::I18N::en_us', 'field uses form language handle' ); $ENV{$_} = 'en-US' for @LH_VARS; done_testing; params.t100644000770000024 403612576552253 16570 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More tests => 6; use_ok( 'HTML::FormHandler::Params' ); my $_params = HTML::FormHandler::Params->new; my $p1 = { 'book.author' => 'J.Doe', 'book.title' => 'Doing something', 'book.date' => '2002', }; my $p1_exp = $_params->expand_hash( $p1 ); is_deeply( $p1_exp, { book => { author => 'J.Doe', title => 'Doing something', date => '2002' } }, 'get expanded has' ); my $p2 = { 'books.0.author' => 'Jane Doe', 'books.0.title' => 'Janes Book', 'books.0.date' => '2003', 'books.1.author' => 'Miss Muffet', 'books.1.title' => 'Sitting on a Tuffet', 'books.1.date' => '2004' }; my $p_hash = { books => [ { author => 'Jane Doe', title => 'Janes Book', date => '2003', }, { author => 'Miss Muffet', title => 'Sitting on a Tuffet', date => '2004', } ] }; my $p2_exp = $_params->expand_hash( $p2 ); is_deeply( $p2_exp, $p_hash, 'get expanded hash for dot notation' ); my $p3 = { 'books+0+author' => 'Jane Doe', 'books+0+title' => 'Janes Book', 'books+0+date' => '2003', 'books+1+author' => 'Miss Muffet', 'books+1+title' => 'Sitting on a Tuffet', 'books+1+date' => '2004' }; my $p3_exp = $_params->expand_hash( $p3, '+' ); is_deeply( $p3_exp, $p_hash, 'get expanded hash for plus notation' ); my $p4 = { 'books[0]author' => 'Jane Doe', 'books[0]title' => 'Janes Book', 'books[0]date' => '2003', 'books[1]author' => 'Miss Muffet', 'books[1]title' => 'Sitting on a Tuffet', 'books[1]date' => '2004' }; my $p4_exp = $_params->expand_hash( $p4, '[]' ); is_deeply( $p4_exp, $p_hash, 'get expanded hash for bracket notation' ); my $p5 = { 'book.author' => 'Jane Doe', 'book.title' => 'Janes Book', 'book.date' => '2003', }; my $p5_hash = { book => { author => 'Jane Doe', title => 'Janes Book', date => '2003', }, }; my $p5_exp = $_params->expand_hash( $p5 ); is_deeply( $p5_exp, $p5_hash, 'get hash from single brackets'); posted.t100644000770000024 307312576552253 16603 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package Test::SingleBool; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'opt_in' => ( type => 'Boolean', required => 1 ); } { my $form = Test::SingleBool->new; ok( $form, 'form built' ); $form->process( params => {} ); ok( !$form->ran_validation, 'form did not run validation' ); my $test = 'POST'; $form->process( posted => ($test eq 'POST'), params => {} ); ok( $form->ran_validation, 'form did run validation' ); ok( $form->has_errors, 'form has errors' ); my @errors = $form->errors; is( scalar @errors, 1, 'form has an error' ); is( $errors[0], 'Opt in field is required', 'error message is correct' ); } { package Test::SingleBoolCompound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'a' => ( type => 'Compound', required => 1 ); has_field 'a.opt_in' => ( type => 'Boolean', required => 1 ); } { my $form = Test::SingleBoolCompound->new; ok( $form, 'form built' ); $form->process( params => {} ); ok( !$form->ran_validation, 'form did not run validation' ); my $test = 'POST'; $form->process( posted => ($test eq 'POST'), params => {} ); ok( $form->ran_validation, 'form did run validation' ); ok( $form->has_errors, 'form has errors' ); my @errors = $form->errors; is( scalar @errors, 1, 'form has an error' ); is( $errors[0], 'A field is required', 'error message is correct' ); } done_testing; submit.t100644000770000024 246312576552253 16612 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use_ok( 'HTML::FormHandler::Field::Submit' ); my $field = HTML::FormHandler::Field::Submit->new(name => 'submit'); $field->build_result; is( $field->value, 'Save', 'get right value'); ok( $field->result, 'returns result'); { package Test::Submit; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; has '+name' => (default => 'test_submit'); has_field 'some_field'; has_field 'submit' => ( type => 'Submit', value => 'Submit' ); } my $form = Test::Submit->new; ok( $form, 'get form'); my $params = { some_field => 'test' }; $form->process($params); my $result = $form->result; is( $result->num_results, 2, 'two results'); is( $form->field('submit')->input, undef, 'no input for submit field'); $form->process( { some_field => 'test', submit => 'Submit' } ); is( $form->field('submit')->input, 'Submit', 'input for submit field'); my $rendered = $form->render; is_html( $rendered, '
', 'form renders'); done_testing; upload.t100644000770000024 730412576552253 16572 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use_ok('HTML::FormHandler::Field::Upload'); use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package Mock::Upload; use Moose; use File::Copy (); use IO::File (); use File::Spec::Unix; has filename => ( is => 'rw' ); has size => ( is => 'rw' ); has tempname => ( is => 'rw', lazy_build => 1 ); has basename => ( is => 'ro', lazy_build => 1 ); has tmpdir => ( is => 'ro', default => '' ); has fh => ( is => 'rw', required => 1, lazy_build => 1 ); sub _build_fh { my $self = shift; my $fh = IO::File->new( $self->tempname, IO::File::O_RDONLY ); unless ( defined $fh ) { my $filename = $self->tempname; die "Can't open '$filename': '$!'"; } return $fh; } sub _build_tempname { my $self = shift; return $self->tmpdir . $self->basename; } sub _build_basename { my $self = shift; my $basename = $self->filename; $basename =~ s|\\|/|g; $basename = ( File::Spec::Unix->splitpath($basename) )[2]; $basename =~ s|[^\w\.-]+|_|g; return $basename; } sub copy_to { my $self = shift; return File::Copy::copy( $self->tempname, @_ ); } sub link_to { my ( $self, $target ) = @_; return CORE::link( $self->tempname, $target ); } sub slurp { my ( $self, $layer ) = @_; unless ($layer) { $layer = ':raw'; } my $content = undef; my $handle = $self->fh; binmode( $handle, $layer ); while ( $handle->sysread( my $buffer, 8192 ) ) { $content .= $buffer; } return $content; } } { package My::Form::Upload; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+enctype' => ( default => 'multipart/form-data'); has_field 'file' => ( type => 'Upload' ); has_field 'submit' => ( type => 'Submit', value => 'Upload' ); } my $form = My::Form::Upload->new; ok( $form, 'created form with upload field' ); is_html( $form->field('file')->render, '
', 'renders ok' ); my $upload = Mock::Upload->new( filename => 'test.txt', size => 1024 ); $form->process( params => { file => $upload } ); ok( $form->validated, 'form validated' ); $upload->size( 20000000 ); $form->process( params => { file => $upload } ); ok( !$form->validated, 'form did not validate' ); # file exists, is empty `touch temp.txt`; open ( my $fh, '>', 'temp.txt' ); $form->process( params => { file => $fh } ); my @errors = $form->errors; is( $errors[0], 'File uploaded is empty', 'empty file fails' ); # file exists, is not empty print {$fh} "testing\n"; close( $fh ); open ( $fh, '<', 'temp.txt' ); $form->process( params => { file => $fh } ); ok( $form->validated, 'form validated' ); # file doesn't exist $form->process( params => { file => 'not_there.txt' } ); @errors = $form->errors; is( $errors[0], 'File not found for upload field', 'error when file does not exist' ); unlink('temp.txt'); { package My::Form::Upload::NoSize; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+enctype' => ( default => 'multipart/form-data'); has_field 'file' => ( type => 'Upload', min_size => undef, max_size => undef ); has_field 'submit' => ( type => 'Submit', value => 'Upload' ); } $form = My::Form::Upload::NoSize->new; $upload = Mock::Upload->new( filename => 'test.txt', size => 4000000 ); $form->process( params => { file => $upload } ); ok( $form->validated, 'form validated with no size limit' ); done_testing; Makefile.PL100644000770000024 543612576552253 16444 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064 use strict; use warnings; use ExtUtils::MakeMaker 6.30; use File::ShareDir::Install; install_share dist => "share"; my %WriteMakefileArgs = ( "ABSTRACT" => "HTML forms using Moose", "AUTHOR" => "FormHandler Contributors - see HTML::FormHandler", "BUILD_REQUIRES" => {}, "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => "6.30", "File::ShareDir::Install" => "0.03" }, "DISTNAME" => "HTML-FormHandler", "EXE_FILES" => [], "LICENSE" => "perl", "NAME" => "HTML::FormHandler", "PREREQ_PM" => { "Carp" => 0, "Class::Load" => "0.06", "Data::Clone" => 0, "DateTime" => 0, "DateTime::Format::Strptime" => 0, "Email::Valid" => 0, "File::ShareDir" => 0, "File::Spec" => 0, "HTML::Entities" => 0, "HTML::TreeBuilder" => "3.23", "JSON" => 0, "List::Util" => "1.33", "Locale::Maketext" => "1.09", "Moose" => "2.1403", "MooseX::Getopt" => "0.16", "MooseX::Types" => "0.20", "MooseX::Types::Common" => 0, "MooseX::Types::LoadableClass" => "0.006", "Sub::Exporter" => 0, "Sub::Name" => 0, "Try::Tiny" => 0, "aliased" => 0, "namespace::autoclean" => "0.09" }, "TEST_REQUIRES" => { "PadWalker" => 0, "Test::Differences" => 0, "Test::Exception" => 0, "Test::Memory::Cycle" => "1.04", "Test::More" => "0.94", "Test::Warn" => 0 }, "VERSION" => "0.40064", "test" => { "TESTS" => "t/*.t t/blocks/*.t t/bootstrap/*.t t/bootstrap3/*.t t/compound/*.t t/errors/*.t t/field_setup/*.t t/fields/*.t t/form_setup/*.t t/infl_defl/*.t t/moose/*.t t/render/*.t t/repeatable/*.t t/result/*.t t/validation/*.t t/wizard/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Class::Load" => "0.06", "Data::Clone" => 0, "DateTime" => 0, "DateTime::Format::Strptime" => 0, "Email::Valid" => 0, "File::ShareDir" => 0, "File::Spec" => 0, "HTML::Entities" => 0, "HTML::TreeBuilder" => "3.23", "JSON" => 0, "List::Util" => "1.33", "Locale::Maketext" => "1.09", "Moose" => "2.1403", "MooseX::Getopt" => "0.16", "MooseX::Types" => "0.20", "MooseX::Types::Common" => 0, "MooseX::Types::LoadableClass" => "0.006", "PadWalker" => 0, "Sub::Exporter" => 0, "Sub::Name" => 0, "Test::Differences" => 0, "Test::Exception" => 0, "Test::Memory::Cycle" => "1.04", "Test::More" => "0.94", "Test::Warn" => 0, "Try::Tiny" => 0, "aliased" => 0, "namespace::autoclean" => "0.09" ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); { package MY; use File::ShareDir::Install qw(postamble); } template.t100644000770000024 37512576552253 16712 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tuse strict; use warnings; use Test::More; { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar'; } my $form = MyApp::Form::Test->new; ok( $form ); done_testing; captcha.t100644000770000024 464712576552253 16720 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; BEGIN { eval "use GD::SecurityImage"; plan skip_all => 'GD::SecurityImage required' if $@; } use_ok( 'HTML::FormHandler::Field::Captcha' ); { package Test::Captcha; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::TraitFor::Captcha'; with 'HTML::FormHandler::Render::Simple'; has_field 'some_field'; has_field 'subject'; has_field '+captcha' => ( id => 'captcha', wrapper_class => 'captcha' ); sub validate_subject { my ( $self, $field ) = @_; $field->add_error("Incorrect") unless $field->value eq 'Correct'; } } { package Mock::Ctx; use Moose; has '_session' => ( isa => 'HashRef', is => 'rw', builder => 'build_session' ); sub build_session {{}} sub session { my $self = shift; my $session = $self->_session; if (@_) { my $new_values = @_ > 1 ? { @_ } : $_[0]; croak('session takes a hash or hashref') unless ref $new_values; for my $key (keys %$new_values) { $session->{$key} = $new_values->{$key}; } } $session; } } my $ctx = Mock::Ctx->new; ok( $ctx, 'get mock ctx' ); my $form = Test::Captcha->new( ctx => $ctx ); ok( $form, 'get form' ); my $rnd = $ctx->session->{captcha}->{rnd}; ok( $rnd, 'captcha is in session' ); my $params = { some_field => 'test', subject => 'Correct', captcha => '1234' }; $form->process( ctx => $ctx, params => $params ); ok( !$form->validated, 'form did not validate with wrong captcha'); my $rnd2 = $ctx->session->{captcha}->{rnd}; ok( $rnd ne $rnd2, 'we now have a different captcha'); ok( !$form->field('captcha')->fif, 'no fif for captcha' ); $params->{captcha} = $rnd2; $params->{subject} = 'Incorrect'; $form->process( ctx => $ctx, params => $params ); # valid captcha, invalid subject ok( !$form->validated, 'form did not validate: valid captcha, invalid field' ); ok( $rnd2 == $ctx->session->{captcha}->{rnd}, 'captcha has not changed' ); $params->{subject} = 'Correct'; $form->process( ctx => $ctx, params => $params ); ok( $form->validated, 'form validated; old captcha, valid fields' ); my $render = $form->render_field('captcha'); is_html( $render, '
', 'captcha renders ok' ); done_testing; display.t100644000770000024 241412576552253 16750 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar' => ( type => 'Display' ); has_field 'baz' => ( type => 'Display' ); sub html_bar { my ( $self, $field ) = @_; my $html = '
My Bar:&nbps;' . $field->value . '
'; return $html; } sub html_baz { my ( $self, $field ) = @_; my $html = '
My Baz:&nbps;' . $field->value . '
'; return $html; } } my $form = Test::Form->new; my $init_obj = { foo => 'we have a foo', bar => '...and a bar...', baz => '...and a baz!!', }; $form->process( init_object => $init_obj, params => {} ); my $rendered = $form->render; like( $rendered, qr/and a bar/, 'value for display field renders' ); like( $rendered, qr/and a baz!!/, 'value for display field renders' ); # testing $form->process( init_object => $init_obj, params => { foo => 'new foo' } ); $rendered = $form->render; like( $rendered, qr/and a bar/, 'value for display field still renders' ); is_deeply( $form->value, { foo => 'new foo' }, 'value for form is correct' ); is_deeply( $form->fif, { foo => 'new foo' }, 'fif for form is correct' ); done_testing; mb_form.t100644000770000024 464412576552253 16733 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; { package Hello::Form::Page; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+html_prefix' => ( default => 0 ); has_field 'wizard_session_id' => ( type => 'Hidden' ); has_field 'cancel' => ( type => 'Submit', value => "Cancel" ); has_field 'prev' => ( type => 'Submit', value => "Prev" ); has_field 'next' => ( type => 'Submit', value => "Next" ); } { package Hello::Form::Page2; use HTML::FormHandler::Moose; extends 'Hello::Form::Page'; has_field 'organization' => ( type => 'Text' ); has_field 'mediums' => ( type => 'Repeatable', num_when_empty => 0 ); has_field 'mediums.id' => ( type => 'Integer' ); has_field 'mediums.tracklist' => ( type => 'Compound' ); has_field 'mediums.tracklist.id' => ( type => 'Integer' ); has_field 'mediums.tracklist.tracks' => ( type => 'Repeatable', num_when_empty => 0 ); has_field 'mediums.tracklist.tracks.id' => ( type => 'Integer' ); } my $form = Hello::Form::Page2->new; ok( $form, 'form builds ok' ); diag( $form->peek ); diag( $form->result->peek ); my $init_obj = { mediums => [ { id => 1, tracklist => { id => 10, tracks => [ { id => 100 }, { id => 200 }, ], }, }, { id => 2, tracklist => { id => 20, tracks => [ { id => 300 }, { id => 400 }, ], }, }, ] }; my $extra_values = { 'next' => 'Next', cancel => 'Cancel', organization => undef, prev => 'Prev', wizard_session_id => undef, }; $form->process( init_object => $init_obj ); diag( $form->peek ); diag( $form->result->peek ); my $value = $form->value; is_deeply( $value, { %$init_obj, %$extra_values}, 'right values' ); my $good_fif = { 'mediums.0.id' => 1, 'mediums.0.tracklist.id' => 10, 'mediums.0.tracklist.tracks.0.id' => 100, 'mediums.0.tracklist.tracks.1.id' => 200, 'mediums.1.id' => 2, 'mediums.1.tracklist.id' => 20, 'mediums.1.tracklist.tracks.0.id' => 300, 'mediums.1.tracklist.tracks.1.id' => 400, 'organization' => '', 'wizard_session_id' => '', }; my $fif = $form->fif; is_deeply( $fif, $good_fif, 'fif is right' ); $form->process( $fif ); done_testing; render000755000770000024 012576552253 16044 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tff.t100644000770000024 437412576552253 16774 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package HTML::FormHandler::Render::FFTheme; use Moose::Role; sub build_update_subfields {{ all => { tags => { no_wrapped_label => 1 } } }} sub html_attributes { my ( $self, $field, $type, $attr ) = @_; my $class = $attr->{class} || []; if( $type eq 'wrapper' ) { # this is not exactly like what FF does, but it's close push @$class, $field->type_attr; push @$class, 'label' if $field->do_label; $attr->{class} = $class; } return $attr; } } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::FFTheme'; has '+name' => ( default => 'test_form' ); has '+action' => ( default => '/form' ); has_field 'user' => ( label => 'Username' ); has_field 'pass' => ( type => 'Password', label => 'Password' ); has_field 'opt_in' => ( type => 'Checkbox', label => 'Opt in?', ); has_field 'choose' => ( type => 'Select', label => 'Choose some', options => [ { label => 'blue', value => 1 }, { label => 'red', value => 2 }] ); has_field 'submit' => ( type => 'Submit', value => "Save" ); } my $expected = '
'; my $form = Test::Form->new; $form->process; my $rendered = $form->render; is_html($rendered, $expected, 'renders ok' ); done_testing; util000755000770000024 012576552253 15277 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064messages100644000770000024 1237412576552253 17220 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/util[ { 'Field' => { 'range_too_high' => 'Value must be less than or equal to [_1]', 'range_incorrect' => 'Value must be between [_1] and [_2]', 'wrong_value' => 'Wrong value', 'error_occurred' => 'error occurred', 'range_too_low' => 'Value must be greater than or equal to [_1]', 'field_invalid' => 'field is invalid', 'required' => '[_1] field is required', 'not_allowed' => '[_1] not allowed', 'no_match' => '[_1] does not match' } }, { 'Types' => { 'NegativeNum' => 'Must be a negative number', 'NegativeInt' => 'Must be a negative integer', 'PositiveNum' => 'Must be a positive number', 'WordChars' => 'Must be made up of letters, digits, and underscores', 'IPAddress' => 'Not a valid IP address', 'PositiveInt' => 'Must be a positive integer', 'State' => 'Not a valid state', 'Printable' => 'Field contains non-printable characters', 'Password' => 'Must be between 4 and 255 chars', 'Zip' => 'Zip is not valid', 'SimpleStr' => 'Must be a single line of no more than 255 chars', 'Email' => 'Email is not valid', 'SingleDigit' => 'Must be a single digit', 'NonEmptySimpleStr' => 'Must be a non-empty single line of no more than 255 chars', 'NotAllDigits' => 'Must not be all digits', 'NoSpaces' => 'Must not contain spaces', 'SingleWord' => 'Field must contain a single word', 'NonEmptyStr' => 'Must not be empty', 'StrongPassword' => 'Must be between 8 and 255 chars, and contain a non-alpha char' } }, { 'Date' => { 'date_late' => 'Date is too late', 'date_early' => 'Date is too early' } }, { 'DateTime' => { 'datetime_invalid' => 'Not a valid DateTime' } }, { 'Duration' => { 'duration_invalid' => 'Invalid value for [_1]: [_2]' } }, { 'Email' => { 'email_format' => 'Email should be of the format [_1]' } }, { 'Float' => { 'float_needed' => 'Must be a number. May contain numbers, +, - and decimal separator \'[_1]\'', 'float_precision' => 'May have a maximum of [quant,_1,digit] after the decimal point, but has [_2]', 'float_size' => 'Total size of number must be less than or equal to [_1], but is [_2]' } }, { 'Integer' => { 'integer_needed' => 'Value must be an integer' } }, { 'Money' => { 'money_real' => 'Value must be a real number', 'money_convert' => 'Value cannot be converted to money' } }, { 'Password' => { 'required' => 'Please enter a password in this field', 'password_ne_username' => 'Password must not match [_1]' } }, { 'PasswordConf' => { 'required' => 'Please enter a password confirmation', 'pass_conf_not_matched' => 'The password confirmation does not match the password' } }, { 'PosInteger' => { 'integer_positive' => 'Value must be a positive integer' } }, { 'Select' => { 'select_not_multiple' => 'This field does not take multiple values', 'select_invalid_value' => '\'[_1]\' is not a valid value' } }, { 'Text' => { 'text_maxlength' => 'Field should not exceed [quant,_1,character]. You entered [_2]', 'text_minlength' => 'Field must be at least [quant,_1,character]. You entered [_2]' } }, { 'Upload' => { 'upload_file_too_small' => 'File is too small (< [_1] bytes)', 'upload_file_empty' => 'File uploaded is empty', 'upload_file_not_found' => 'File not found for upload field', 'upload_file_too_big' => 'File is too big (> [_1] bytes)' } } ] captcha2.t100644000770000024 275412576552253 16777 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use lib 'xt/lib/'; # HFH::TraitFor::Captcha and HFH::Field::Captcha do not work with current # versions of Catalyst. # # The reason seems to be that get_captcha and set_captcha use # $form->ctx->{session} directly, instead of using the accessor # $from->ctx->session. # # I am not sure if this works with older versions of Catalyst, but it is # definitely broken when using Catalyst 5.90007 # # I have attached a simple test. # # The patch makes get_captcha and set_captcha using the session-accessor # IF $form->ctx has one. (if it is a catalyst context). Otherwise, the old # behaviour will not change. The module should still work with # non-catalyst applications. use Test::More; my @missing; eval" use Test::WWW::Mechanize::Catalyst; "; if($@){ push @missing, "Test::WWW::Mechanize"; } eval" use GD::SecurityImage; "; if($@){ push @missing, "GD::SecurityImage"; } if(@missing){ plan skip_all => "The following Modules are required to run this test: " . join ", ", @missing; } else{ plan tests => 7; } my $mech = Test::WWW::Mechanize::Catalyst->new(catalyst_app => "MyCatalystApp"); $mech->get_ok("/captcha"); #diag explain $mech; $mech->content_contains(''); $mech->get_ok("/captcha/get_rnd"); my $rnd = $mech->content; $mech->get_ok("/captcha/image"); is $mech->res->content_type, "image/png"; $mech->get_ok("/captcha?captcha=$rnd"); $mech->content_is("verification succeeded"); done_testing; exit; structured.t100644000770000024 1057412576552253 17345 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tuse strict; use warnings; use Test::More; my $struct = { username => 'Joe Blow', occupation => 'Programmer', tags => ['Perl', 'programming', 'Moose' ], employer => { name => 'TechTronix', country => 'Utopia', }, options => { flags => { opt_in => 1, email => 0, }, cc_cards => [ { type => 'Visa', number => '4248999900001010', }, { type => 'MasterCard', number => '4335992034971010', }, ], }, addresses => [ { street => 'First Street', city => 'Prime City', country => 'Utopia', id => 0, }, { street => 'Second Street', city => 'Secondary City', country => 'Graustark', id => 1, }, { street => 'Third Street', city => 'Tertiary City', country => 'Atlantis', id => 2, } ] }; { package Structured::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'username'; has_field 'occupation'; has_field 'tags' => ( type => 'Repeatable' ); has_field 'tags.contains' => ( type => 'Text' ); has_field 'employer' => ( type => 'Compound' ); has_field 'employer.name'; has_field 'employer.country'; has_field 'options' => ( type => 'Compound' ); has_field 'options.flags' => ( type => 'Compound' ); has_field 'options.flags.opt_in' => ( type => 'Boolean' ); has_field 'options.flags.email' => ( type => 'Boolean' ); has_field 'options.cc_cards' => ( type => 'Repeatable' ); has_field 'options.cc_cards.type'; has_field 'options.cc_cards.number'; has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.street'; has_field 'addresses.city'; has_field 'addresses.country'; has_field 'addresses.id'; } #=========== # test structured params my $form = Structured::Form->new; ok( $form, 'form created' ); $form->process( params => $struct ); is( $form->result->num_results, 6, 'correct number of results' ); ok( $form->validated, 'form validated'); is_deeply( $form->field('tags')->value, ['Perl', 'programming', 'Moose' ], 'list field tags has right values' ); is( $form->field('addresses.0.city')->value, 'Prime City', 'get address field OK' ); is( $form->field('options.flags.opt_in')->value, 1, 'get opt_in flag'); #============ # test structured init_object/item my $form2 = Structured::Form->new; ok( $form2, 'form created' ); $form2->process( init_object => $struct, params => {} ); is( $form2->result->num_results, 6, 'correct number of results' ); ok( !$form2->validated, 'form validated'); is_deeply( $form2->field('employer')->item, { name => 'TechTronix', country => 'Utopia', }, 'has item'); is_deeply( $form2->field('addresses')->item, $struct->{addresses}, 'item for repeatable' ); #============= my $fif = { 'addresses.0.city' => 'Prime City', 'addresses.0.country' => 'Utopia', 'addresses.0.id' => 0, 'addresses.0.street' => 'First Street', 'addresses.1.city' => 'Secondary City', 'addresses.1.country' => 'Graustark', 'addresses.1.id' => 1, 'addresses.1.street' => 'Second Street', 'addresses.2.city' => 'Tertiary City', 'addresses.2.country' => 'Atlantis', 'addresses.2.id' => 2, 'addresses.2.street' => 'Third Street', 'employer.country' => 'Utopia', 'employer.name' => 'TechTronix', 'occupation' => 'Programmer', 'options.cc_cards.0.number' => '4248999900001010', 'options.cc_cards.0.type' => 'Visa', 'options.cc_cards.1.number' => '4335992034971010', 'options.cc_cards.1.type' => 'MasterCard', 'options.flags.email' => 0, 'options.flags.opt_in' => 1, 'tags.0' => 'Perl', 'tags.1' => 'programming', 'tags.2' => 'Moose', 'username' => 'Joe Blow' }; #========= is_deeply( $form->fif, $fif, 'fif is correct' ); $form->process( $fif ); ok( $form->validated, 'form processed from fif' ); is_deeply( $form->values, $struct, 'values round-tripped from fif'); #========= # works with item and params $form2->process( item => $struct, params => $fif ); ok( $form2->validated, 'form processed from fif' ); is( $form2->result->num_results, 6, 'correct number of results' ); is_deeply( $form2->field('employer')->item, { name => 'TechTronix', country => 'Utopia', }, 'has item'); is_deeply( $form2->field('addresses')->item, $struct->{addresses}, 'item for repeatable' ); done_testing; var000755000770000024 012576552253 15355 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tform1.pl100644000770000024 61012576552253 17053 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/var{ action => '/login', field_list => [ { type => 'Text', name => 'user', label => 'Username', required => 1, }, { type => 'Password', name => 'pass', label => 'Password', required => 1, }, { type => 'Submit', name => 'submit', value => 'Login', }, ], } add_field.t100644000770000024 135212576552253 17176 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More tests => 2; use HTML::FormHandler::Field::Text; use HTML::FormHandler::Field; { package My::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform' ); sub field_list { [ meat => 'Text', starch => { required => 1 }, fruit => 'Select', ] } sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } } my $form = My::Form->new; ok( $form, 'get form' ); my $field = HTML::FormHandler::Field::Text->new( name => 'Testfield' ); $form->push_field($field); ok( $form->field('Testfield'), 'form now has test field' ); author-eol.t100644000770000024 3020412576552253 17210 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t BEGIN { unless ($ENV{AUTHOR_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for testing by the author'); } } use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::EOL 0.18 use Test::More 0.88; use Test::EOL; my @files = ( 'lib/HTML/FormHandler.pm', 'lib/HTML/FormHandler/Base.pm', 'lib/HTML/FormHandler/Blocks.pm', 'lib/HTML/FormHandler/BuildFields.pm', 'lib/HTML/FormHandler/BuildPages.pm', 'lib/HTML/FormHandler/Field.pm', 'lib/HTML/FormHandler/Field/AddElement.pm', 'lib/HTML/FormHandler/Field/BoolSelect.pm', 'lib/HTML/FormHandler/Field/Boolean.pm', 'lib/HTML/FormHandler/Field/Button.pm', 'lib/HTML/FormHandler/Field/Captcha.pm', 'lib/HTML/FormHandler/Field/Checkbox.pm', 'lib/HTML/FormHandler/Field/Compound.pm', 'lib/HTML/FormHandler/Field/Date.pm', 'lib/HTML/FormHandler/Field/DateMDY.pm', 'lib/HTML/FormHandler/Field/DateTime.pm', 'lib/HTML/FormHandler/Field/Display.pm', 'lib/HTML/FormHandler/Field/Duration.pm', 'lib/HTML/FormHandler/Field/Email.pm', 'lib/HTML/FormHandler/Field/File.pm', 'lib/HTML/FormHandler/Field/Float.pm', 'lib/HTML/FormHandler/Field/Hidden.pm', 'lib/HTML/FormHandler/Field/Hour.pm', 'lib/HTML/FormHandler/Field/IntRange.pm', 'lib/HTML/FormHandler/Field/Integer.pm', 'lib/HTML/FormHandler/Field/Minute.pm', 'lib/HTML/FormHandler/Field/Money.pm', 'lib/HTML/FormHandler/Field/Month.pm', 'lib/HTML/FormHandler/Field/MonthDay.pm', 'lib/HTML/FormHandler/Field/MonthName.pm', 'lib/HTML/FormHandler/Field/Multiple.pm', 'lib/HTML/FormHandler/Field/Nested.pm', 'lib/HTML/FormHandler/Field/NoValue.pm', 'lib/HTML/FormHandler/Field/NonEditable.pm', 'lib/HTML/FormHandler/Field/Password.pm', 'lib/HTML/FormHandler/Field/PasswordConf.pm', 'lib/HTML/FormHandler/Field/PosInteger.pm', 'lib/HTML/FormHandler/Field/PrimaryKey.pm', 'lib/HTML/FormHandler/Field/Repeatable.pm', 'lib/HTML/FormHandler/Field/Repeatable/Instance.pm', 'lib/HTML/FormHandler/Field/Reset.pm', 'lib/HTML/FormHandler/Field/Result.pm', 'lib/HTML/FormHandler/Field/RmElement.pm', 'lib/HTML/FormHandler/Field/Second.pm', 'lib/HTML/FormHandler/Field/Select.pm', 'lib/HTML/FormHandler/Field/SelectCSV.pm', 'lib/HTML/FormHandler/Field/Submit.pm', 'lib/HTML/FormHandler/Field/Text.pm', 'lib/HTML/FormHandler/Field/TextArea.pm', 'lib/HTML/FormHandler/Field/TextCSV.pm', 'lib/HTML/FormHandler/Field/Upload.pm', 'lib/HTML/FormHandler/Field/Weekday.pm', 'lib/HTML/FormHandler/Field/Year.pm', 'lib/HTML/FormHandler/Fields.pm', 'lib/HTML/FormHandler/Foo.pm', 'lib/HTML/FormHandler/I18N.pm', 'lib/HTML/FormHandler/I18N/ar_kw.pm', 'lib/HTML/FormHandler/I18N/bg_bg.pm', 'lib/HTML/FormHandler/I18N/ca_es.pm', 'lib/HTML/FormHandler/I18N/cs_cz.pm', 'lib/HTML/FormHandler/I18N/de_de.pm', 'lib/HTML/FormHandler/I18N/en_us.pm', 'lib/HTML/FormHandler/I18N/es_es.pm', 'lib/HTML/FormHandler/I18N/hu_hu.pm', 'lib/HTML/FormHandler/I18N/it_it.pm', 'lib/HTML/FormHandler/I18N/ja_jp.pm', 'lib/HTML/FormHandler/I18N/pt_br.pm', 'lib/HTML/FormHandler/I18N/ru_ru.pm', 'lib/HTML/FormHandler/I18N/sv_se.pm', 'lib/HTML/FormHandler/I18N/tr_tr.pm', 'lib/HTML/FormHandler/I18N/ua_ua.pm', 'lib/HTML/FormHandler/InitResult.pm', 'lib/HTML/FormHandler/Manual.pod', 'lib/HTML/FormHandler/Manual/Catalyst.pod', 'lib/HTML/FormHandler/Manual/Cookbook.pod', 'lib/HTML/FormHandler/Manual/Database.pod', 'lib/HTML/FormHandler/Manual/Defaults.pod', 'lib/HTML/FormHandler/Manual/Errors.pod', 'lib/HTML/FormHandler/Manual/Fields.pod', 'lib/HTML/FormHandler/Manual/FromDFV.pod', 'lib/HTML/FormHandler/Manual/FromFF.pod', 'lib/HTML/FormHandler/Manual/InflationDeflation.pod', 'lib/HTML/FormHandler/Manual/Intro.pod', 'lib/HTML/FormHandler/Manual/Reference.pod', 'lib/HTML/FormHandler/Manual/Rendering.pod', 'lib/HTML/FormHandler/Manual/RenderingCookbook.pod', 'lib/HTML/FormHandler/Manual/Templates.pod', 'lib/HTML/FormHandler/Manual/Testing.pod', 'lib/HTML/FormHandler/Manual/Tutorial.pod', 'lib/HTML/FormHandler/Manual/Validation.pod', 'lib/HTML/FormHandler/Merge.pm', 'lib/HTML/FormHandler/Meta/Role.pm', 'lib/HTML/FormHandler/Model.pm', 'lib/HTML/FormHandler/Model/CDBI.pm', 'lib/HTML/FormHandler/Model/Object.pm', 'lib/HTML/FormHandler/Moose.pm', 'lib/HTML/FormHandler/Moose/Role.pm', 'lib/HTML/FormHandler/Page.pm', 'lib/HTML/FormHandler/Page/Simple.pm', 'lib/HTML/FormHandler/Pages.pm', 'lib/HTML/FormHandler/Params.pm', 'lib/HTML/FormHandler/Render/RepeatableJs.pm', 'lib/HTML/FormHandler/Render/Simple.pm', 'lib/HTML/FormHandler/Render/Table.pm', 'lib/HTML/FormHandler/Render/Util.pm', 'lib/HTML/FormHandler/Render/WithTT.pm', 'lib/HTML/FormHandler/Result.pm', 'lib/HTML/FormHandler/Result/Role.pm', 'lib/HTML/FormHandler/Test.pm', 'lib/HTML/FormHandler/TraitFor/Captcha.pm', 'lib/HTML/FormHandler/TraitFor/I18N.pm', 'lib/HTML/FormHandler/TraitFor/Types.pm', 'lib/HTML/FormHandler/Traits.pm', 'lib/HTML/FormHandler/Types.pm', 'lib/HTML/FormHandler/Validate.pm', 'lib/HTML/FormHandler/Widget/ApplyRole.pm', 'lib/HTML/FormHandler/Widget/Block.pm', 'lib/HTML/FormHandler/Widget/Block/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Field/Button.pm', 'lib/HTML/FormHandler/Widget/Field/ButtonTag.pm', 'lib/HTML/FormHandler/Widget/Field/Captcha.pm', 'lib/HTML/FormHandler/Widget/Field/Checkbox.pm', 'lib/HTML/FormHandler/Widget/Field/CheckboxGroup.pm', 'lib/HTML/FormHandler/Widget/Field/Compound.pm', 'lib/HTML/FormHandler/Widget/Field/Hidden.pm', 'lib/HTML/FormHandler/Widget/Field/HorizCheckboxGroup.pm', 'lib/HTML/FormHandler/Widget/Field/NoRender.pm', 'lib/HTML/FormHandler/Widget/Field/Password.pm', 'lib/HTML/FormHandler/Widget/Field/RadioGroup.pm', 'lib/HTML/FormHandler/Widget/Field/Repeatable.pm', 'lib/HTML/FormHandler/Widget/Field/Reset.pm', 'lib/HTML/FormHandler/Widget/Field/Role/HTMLAttributes.pm', 'lib/HTML/FormHandler/Widget/Field/Role/SelectedOption.pm', 'lib/HTML/FormHandler/Widget/Field/Select.pm', 'lib/HTML/FormHandler/Widget/Field/Span.pm', 'lib/HTML/FormHandler/Widget/Field/Submit.pm', 'lib/HTML/FormHandler/Widget/Field/Text.pm', 'lib/HTML/FormHandler/Widget/Field/Textarea.pm', 'lib/HTML/FormHandler/Widget/Field/Upload.pm', 'lib/HTML/FormHandler/Widget/Form/Role/HTMLAttributes.pm', 'lib/HTML/FormHandler/Widget/Form/Simple.pm', 'lib/HTML/FormHandler/Widget/Form/Table.pm', 'lib/HTML/FormHandler/Widget/Theme/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Theme/Bootstrap3.pm', 'lib/HTML/FormHandler/Widget/Theme/BootstrapFormMessages.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Base.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Bootstrap3.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Fieldset.pm', 'lib/HTML/FormHandler/Widget/Wrapper/None.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Simple.pm', 'lib/HTML/FormHandler/Widget/Wrapper/SimpleInline.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Table.pm', 'lib/HTML/FormHandler/Widget/Wrapper/TableInline.pm', 'lib/HTML/FormHandler/Wizard.pm', 't/01app.t', 't/author-eol.t', 't/basic.t', 't/blocks/basic.t', 't/blocks/block_list.t', 't/blocks/blocktags.t', 't/blocks/loading.t', 't/blocks/nested.t', 't/blocks/render_units.t', 't/bootstrap/basic.t', 't/bootstrap/control_states.t', 't/bootstrap/controls.t', 't/bootstrap/ext_controls.t', 't/bootstrap/inline.t', 't/bootstrap/other.t', 't/bootstrap/search.t', 't/bootstrap3/basic.t', 't/bootstrap3/controls.t', 't/bootstrap3/horiz.t', 't/bootstrap3/horiz_checkboxgroup.t', 't/bootstrap3/inlinecheckboxes.t', 't/bootstrap3/layout_classes.t', 't/compound/basic.t', 't/compound/default.t', 't/compound/empty.t', 't/compound/include.t', 't/compound/select.t', 't/errors/basic.t', 't/errors/compound.t', 't/errors/form_messages.t', 't/errors/messages.t', 't/errors/req_message.t', 't/field_setup/checkbox.t', 't/field_setup/compound_update_fields.t', 't/field_setup/defaults.t', 't/field_setup/disabled.t', 't/field_setup/id.t', 't/field_setup/inactive.t', 't/field_setup/init_object.t', 't/field_setup/input_param.t', 't/field_setup/missing.t', 't/field_setup/plus_field.t', 't/field_setup/update_fields.t', 't/field_setup/update_subfields.t', 't/fields/dates.t', 't/fields/display.t', 't/fields/fields.t', 't/fields/float.t', 't/fields/formhandlerx.t', 't/fields/novalue.t', 't/fields/password.t', 't/fields/repeatable.t', 't/fields/select.t', 't/fields/select2.t', 't/fields/selectcsv.t', 't/fields/textcsv.t', 't/form_setup/api.t', 't/form_setup/clone.t', 't/form_setup/compound_field_list.t', 't/form_setup/config.t', 't/form_setup/dynamic.t', 't/form_setup/include.t', 't/form_setup/init_obj.t', 't/form_setup/no_update.t', 't/form_setup/posted.t', 't/form_setup/render_roles.t', 't/infl_defl/comp_field.t', 't/infl_defl/default.t', 't/infl_defl/defl_lives.t', 't/infl_defl/infl_defl.t', 't/infl_defl/infl_transform.t', 't/infl_defl/variations.t', 't/lib/BookDB/Form/Upload.pm', 't/lib/Field/Address.pm', 't/lib/Field/AltText.pm', 't/lib/Field/MyField.pm', 't/lib/Form/Address.pm', 't/lib/Form/AddressRole.pm', 't/lib/Form/Multiple.pm', 't/lib/Form/MultipleRole.pm', 't/lib/Form/NoExtForm.pm', 't/lib/Form/Person.pm', 't/lib/Form/PersonRole.pm', 't/lib/Form/Test.pm', 't/lib/Form/Two.pm', 't/lib/MyApp/Component/Section.pm', 't/lib/MyApp/I18N/abc_de.pm', 't/lib/Widget/Block/Test.pm', 't/lib/Widget/Field/Omega.pm', 't/lib/Widget/Field/TestWidget.pm', 't/memory_cycles.t', 't/moose/build_id.t', 't/moose/composed.t', 't/moose/field_traits.t', 't/moose/no_extend.t', 't/moose/subclass_roles.t', 't/release-no-tabs.t', 't/render/actions.t', 't/render/array.t', 't/render/basic.t', 't/render/checkbox.t', 't/render/checkbox_group.t', 't/render/classes.t', 't/render/compound.t', 't/render/compound2.t', 't/render/display.t', 't/render/errors.t', 't/render/escaping.t', 't/render/ff.t', 't/render/filter.t', 't/render/form_errors.t', 't/render/get_tag.t', 't/render/html5_attributes.t', 't/render/html_attr.t', 't/render/html_attributes.t', 't/render/inline.t', 't/render/label.t', 't/render/noneditable.t', 't/render/optgroup.t', 't/render/radio_group.t', 't/render/rep_fieldset.t', 't/render/rep_wrapper.t', 't/render/repeatable.t', 't/render/result.t', 't/render/select.t', 't/render/simple.t', 't/render/submit.t', 't/render/table.t', 't/render/tags.t', 't/render/tt_render_elementx.t', 't/render/util.t', 't/render/widget_loading.t', 't/render/widget_tags.t', 't/render/widgets.t', 't/render/with_class.t', 't/render/withtt.t', 't/repeatable/defaults.t', 't/repeatable/empty.t', 't/repeatable/has_many.t', 't/repeatable/hash.t', 't/repeatable/js.t', 't/repeatable/list.t', 't/repeatable/nested.t', 't/repeatable/nested2.t', 't/repeatable/num_extra.t', 't/repeatable/reload.t', 't/repeatable/set_methods.t', 't/repeatable/subfield.t', 't/result/basic.t', 't/result/blocks.t', 't/result/compound.t', 't/result/errors.t', 't/result/repeatable.t', 't/structured.t', 't/template.t', 't/validation/apply.t', 't/validation/constraints.t', 't/validation/dependency.t', 't/validation/filters.t', 't/validation/reqwhen.t', 't/validation/type_tiny.t', 't/validation/types.t', 't/validation/validate_coderef.t', 't/validation/when.t', 't/var/form1.pl', 't/var/form1.yml', 't/wizard/basic.t' ); eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files; done_testing; tags.t100644000770000024 504412576552253 17332 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_form_tags {{ form_text => 'testing', }} sub build_update_subfields {{ all => { tags => { wrapper_tag => 'p', label_tag => 'span', } }, }} has_field 'foo'; has_field 'bar'; has_field 'vax'; has_field 'multi' => ( type => 'Compound' ); has_field 'multi.one'; has_field 'multi.two'; has_field 'records' => ( type => 'Repeatable' ); has_field 'records.one'; has_field 'records.two'; sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{class} = ['label'] if $type eq 'label'; return $attr; } } my $form = Test::Form->new; $form->process({}); my $rendered = $form->render; unlike( $rendered, qr/fieldset/, 'no fieldset rendered' ); unlike( $rendered, qr/Foo: /, 'no colon in label' ); like( $rendered, qr/

Multi<\/legend>/, 'no fieldset around compound' ); like( $rendered, qr/Bar<\/span>/, 'label formatted with span and class' ); ok( ! exists $form->field('foo')->tags->{form_text}, 'no form widgets tags in fields' ); my $exp_tags = { wrapper_tag => 'p', label_tag => 'span' }; my $got_tags = $form->field('records.0')->tags; is_deeply( $got_tags, $exp_tags, 'correct tags' ); { package Test::Tags; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; sub build_do_form_wrapper {1} sub build_update_subfields {{ all => { tags => { wrapper_tag => 'p' } } }} has_field 'bar' => ( tags => {wrapper_tag => 'span'}); has_field 'baz' => ( do_wrapper => 0 ); sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{class} = 'label' if $type eq 'label'; return $attr; } } $form = Test::Tags->new; $form->process( { foo => 'bar' } ); is_html( $form->field('foo')->render, '

', 'renders with different tags'); is_html( $form->field('bar')->render, ' ', 'field renders with custom tags' ); is_html( $form->field('baz')->render, ' ', 'field renders with false wrapper_tag' ); done_testing; util.t100644000770000024 103412576552253 17344 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Render::Util ('ucc_widget', 'cc_widget'); my @cc = ('MyApp', 'myApp', 'My_App', 'MyLongerApp'); my @ucc = ('my_app', 'my_app', 'my_app', 'my_longer_app'); my @cc_ucc = ('MyApp', 'MyApp', 'MyApp', 'MyLongerApp'); my $index = 0; foreach my $str ( @cc ) { is( ucc_widget($str), $ucc[$index], "$str uncamelcased ok" ); $index++; } $index = 0; foreach my $str ( @ucc ) { is( cc_widget($str), $cc_ucc[$index], "$str camelcased ok" ); $index++; } done_testing; form1.yml100644000770000024 105212576552253 17262 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/varaction: /login name: login_form tt_template: form.tt field_list: - name: user type: Text label: Username required: 1 wrapper_attr: class: 'text label' - name: pass type: Password label: Password required: 1 wrapper_attr: class: 'password label' - name: opt_in type: Checkbox label: Opt in? wrapper_attr: class: 'checkbox label' - name: submit type: Submit value: Login label: ~ wrapper_attr: class: 'submit' field_list.t100644000770000024 104012576552253 17413 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More tests => 4; use Data::Clone; use HTML::FormHandler; my $field_list = [ id => { type => 'Text', required => 1, }, submit => 'Submit', ]; my $form = HTML::FormHandler->new( field_list => $field_list ); ok( $form, 'created form OK the first time'); ok( $form->field('id'), 'id field exists' ); $form = HTML::FormHandler->new( field_list => [@{$field_list}, new_field => 'Text'] ); ok( $form, 'created form OK the second time' ); ok( $form->field('id'), 'id field exists' ); load_field.t100644000770000024 336012576552253 17366 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use lib 't/lib'; { package My::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; # this form specifies the form name has '+field_name_space' => ( default => 'Field' ); has_field 'field_one' => ( type => '+AltText', another_attribute => 'one' ); has_field 'field_two' => ( type => '+AltText', another_attribute => 'two' ); has_field 'field_three' => ( type => '+AltText', another_attribute => 'three' ); has_field 'field_four' => ( type => 'AltText', another_attribute => 'four' ); } my $form = My::Form->new; ok( $form, 'get form' ); my $params = { field_one => 'one two three four', field_two => 'one three four', field_three => 'one three four', field_four => 'four', }; $form->process( $params ); ok( !$form->validated, 'form validated' ); ok( !$form->field('field_one')->has_errors, 'field one has no error'); is( $form->field('field_two')->has_errors, 1, 'field two has one error'); is( $form->field('field_two')->errors->[0], 'Fails AltText validation', 'get error message' ); ok( !$form->field('field_three')->has_errors, 'field three has no error'); ok( !$form->field('field_four')->has_errors, 'field four has no error'); { package Field::Text; use Moose; extends 'HTML::FormHandler::Field::Text'; has 'my_attr' => ( is => 'rw' ); } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; # this form specifies the form name has '+field_name_space' => ( default => sub { ['Test', 'Field', 'FieldX']} ); has_field 'field_text' => ( type => '+Text', my_attr => 'test' ); } $form = Test::Form->new; is( $form->field('field_text')->my_attr, 'test', 'finds right field' ); done_testing; model_cdbi.t100644000770000024 34612576552253 17346 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More tests => 2; use_ok( 'HTML::FormHandler::Model::CDBI' ); { package Test::CDBI; use Moose; extends 'HTML::FormHandler::Model::CDBI'; } my $form = Test::CDBI->new; ok( $form, 'get form from CDBI model' ); blocks000755000770000024 012576552253 16042 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 373712576552253 17462 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/blocksuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use_ok('HTML::FormHandler::Blocks'); use_ok('HTML::FormHandler::Widget::Block'); use lib ('t/lib'); { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_form' ); has '+widget_name_space' => ( default => sub {'Widget'} ); sub build_render_list { ['header', 'foo', 'my_fieldset'] } has_field 'foo'; has_field 'bar'; has_block 'my_fieldset' => ( tag => 'fieldset', render_list => ['bar'], label => 'My Special Bar' ); has_block 'header' => ( type => 'Test' ); sub validate_bar { my ( $self, $field ) = @_; $field->add_error('Wrong foo'); } } my $form = Test::Form->new; ok( $form, 'form built' ); my $block = $form->block('my_fieldset'); is( ref $block, 'HTML::FormHandler::Widget::Block', 'got a block' ); is_deeply( $form->render_list, ['header', 'foo', 'my_fieldset'], 'got a render list' ); is_deeply( $block->render_list, ['bar'], 'got a render list from the block' ); $form->process; my $rendered = $form->render; my $expected = '

You got to the Block! Congratulations.

My Special Bar
'; is_html( $rendered, $expected, 'block rendered ok' ); $form->process( params => { foo => 'abc', bar => 'def' } ); ok( $form->has_errors, 'form has errors' ); $rendered = $form->field('bar')->render; $expected = '
Wrong foo
'; is_html( $rendered, $expected, 'error formatted ok' ); done_testing; errors000755000770000024 012576552253 16101 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 1057112576552253 17533 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/errorsuse strict; use warnings; use Test::More; use_ok( 'HTML::FormHandler' ); use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package My::Form; use Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform_' ); sub field_list { return [ reqname => { type => 'Text', required => 1, messages => { required => 'You must supply a reqname' }, }, fruit => 'Select', optname => 'Text', silly_name => { type =>'Text', set_validate => 'valid_silly' } ]; } sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } sub valid_silly { my ( $self, $field ) = @_; $field->add_error( 'Not a valid silly_name' ) unless $field->value eq 'TeStInG'; } } my $form = My::Form->new; my $bad_1 = { optname => 'not req', fruit => 4, silly_name => 'what??', }; ok( !$form->process( $bad_1 ), 'bad 1' ); ok( $form->has_errors, 'form has error' ); my $errors_by_id = { fruit => [q{'4' is not a valid value}], reqname => ['You must supply a reqname'], silly_name => ['Not a valid silly_name'], }; is_deeply( $form->errors_by_id, $errors_by_id, 'right errors' ); is_deeply( $form->errors_by_name, $errors_by_id, 'errors by name are the same as by id'); ok( $form->field('fruit')->has_errors, 'fruit has error' ); ok( $form->field('reqname')->has_errors, 'reqname has error' ); ok( !$form->field('optname')->has_errors, 'optname has no error' ); ok( $form->field('silly_name')->has_errors, 'silly_name has error' ); ok( $form->has_errors, 'form has errors' ); my @fields = $form->error_fields; ok( @fields, 'error fields' ); my @errors = $form->errors; is_deeply( \@errors, [ 'You must supply a reqname', '\'4\' is not a valid value', 'Not a valid silly_name' ], 'errors from form' ); is( $form->num_errors, 3, 'number of errors' ); my @field_names = $form->error_field_names; is_deeply( \@field_names, [ 'reqname', 'fruit', 'silly_name' ], 'error field names' ); is( $form->field('fruit')->id, "fruit", 'field has id' ); { package Repeatable::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'my_test'; has_field 'addresses' => ( type => 'Repeatable', auto_id => 1 ); has_field 'addresses.street'; has_field 'addresses.city'; has_field 'addresses.country'; sub validate_addresses_city { my ( $self, $field ) = @_; $field->add_error("Invalid City: " . $field->value) if( $field->value !~ /City/ ); } } my $init_object = { my_test => 'repeatable_errors', addresses => [ { street => 'First Street', city => 'Prime', country => 'Utopia', id => 0, }, { street => 'Second Street', city => 'Secondary', country => 'Graustark', id => 1, }, { street => 'Third Street', city => 'Tertiary City', country => 'Atlantis', id => 2, } ] }; $form = Repeatable::Form->new; ok( $form, 'form created'); $form->process( $init_object ); ok( !$form->validated, 'form did not validate' ); is( $form->num_errors, 2, 'form has two errors' ); my $rendered_field = $form->field('addresses')->render; ok( $rendered_field, 'rendered field with auto_id ok' ); { package Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => 'Repeatable', required => 1); has_field 'foo.bar' => ( type => 'Text', required => 1); has_field 'foo.optional' => ( type => 'Text', required => 0); } $form = Form->new; ok(!$form->process( params => { 'foo.0.bar' => '' , 'foo.1.bar' => '' }), 'Processing a form with empty fields should not validate'); ok(!$form->process( params => { 'foo.0.bar' => '' , 'foo.1.bar' => 'Test' }), 'Processing a form with some empty fields should not validate'); ok(!$form->process( params => { 'foo.0.bar' => 'Test' , 'foo.1.bar' => '' }), 'Processing a form with some empty fields should not validate'); ok($form->process( params => { 'foo.0.bar' => 'Test' , 'foo.1.bar' => 'Test' }), 'Processing a form with all inputs validates'); done_testing; fields000755000770000024 012576552253 16033 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tdates.t100644000770000024 1604712576552253 17510 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use Test::Warn; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; # # DateMDY # my $class = 'HTML::FormHandler::Field::DateMDY'; use_ok($class); my $field = $class->new( name => 'test_field', ); $field->build_result; ok( defined $field, 'new() called for DateMDY' ); $field->_set_input('10/02/2009'); $field->validate_field; ok( $field->validated, 'No errors 1' ); ok( $field->value->isa('DateTime'), 'isa DateTime' ); $field->reset_result; $field->_set_input('14/40/09'); $field->validate_field; ok( $field->has_errors, 'Has error 1' ); is( $field->fif, '14/40/09', 'Correct value' ); $field->reset_result; $field->_set_input('02/29/2009'); $field->validate_field; ok( $field->has_errors, 'Has error 2' ); is( $field->fif, '02/29/2009', 'isa DateTime' ); $field->reset_result; $field->_set_input('12/31/2008'); $field->validate_field; ok( $field->validated, 'No errors 2' ); is( $field->fif, $field->value->strftime("%m/%d/%Y", 'fif ok' ), 'fif ok'); $field->reset_result; $field->_set_input('07/07/09'); ok( $field->validated, 'No errors 3' ); $field->reset_result; $field->_deflate_and_set_value( DateTime->new( year => 2008, month => 12, day => 31 ) ); is( $field->fif, '12/31/2008', 'fif from value ok'); # # Date # $class = 'HTML::FormHandler::Field::Date'; use_ok($class); $field = $class->new( name => 'test_field', format => "mm/dd/yy" ); $field->build_result; ok( defined $field, 'new() called for DateMDY' ); $field->_set_input('02/10/2009'); $field->validate_field; ok( $field->validated, 'No errors 1' ); ok( $field->value->isa('DateTime'), 'isa DateTime' ); $field->reset_result; $field->date_start('2009-10-01'); $field->_set_input('08/01/2009'); $field->validate_field; ok( $field->has_errors, 'Date is too early' ); is( $field->fif, '08/01/2009', 'Correct value' ); $field->clear_date_start; $field->reset_result; $field->date_end('2010-01-01'); $field->_set_input('02/01/2010'); $field->validate_field; ok( $field->has_errors, 'date is too late'); $field->_set_input('02/29/2009'); $field->validate_field; ok( $field->has_errors, 'Not a valid date' ); is( $field->fif, '02/29/2009', 'isa DateTime' ); $field->reset_result; $field->_set_input('12/31/2008'); $field->validate_field; ok( $field->validated, 'No errors 2' ); is( $field->fif, $field->value->strftime("%m/%d/%Y", 'fif ok' ), 'fif ok'); $field->reset_result; $field->_deflate_and_set_value( DateTime->new( year => 2008, month => 12, day => 31 ) ); is( $field->fif, '12/31/2008', 'fif from deflated value ok'); $field->format("%d-%m-%Y"); $field->_set_input('07-07-09'); $field->validate_field; ok( $field->validated, 'No errors 3' ); is( $field->fif, '07-07-09', 'fif ok'); $field->reset_result; $field->format("%m/%d/%Y"); $field->_set_input('12/31/2008'); $field->time_zone('America/Los_Angeles'); $field->validate_field; ok( $field->validated, 'No errors 3a'); is( $field->value->time_zone->name, 'America/Los_Angeles' ); { package Test::Date; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; has_field 'start_date' => ( type => 'Date' ); has_field 'end_date' => ( type => 'Date', required => 1 ); has_field 'another_date' => ( type => 'Date' ); } { package My::Date; use base 'DateTime'; } my $form = Test::Date->new; ok( $form, 'form with date created' ); ok( $form->render_field('end_date'), 'date field renders' ); ok( !$form->process( params => { end_date => '' } ), "Didn't validate Test::Date with empty string for end_date" ); my $adate = My::Date->new( year => '2014', month => '05', day => '20' ); $form = Test::Date->new( item => { end_date => '1999-01-01', start_date => '', another_date => $adate } ); ok( !$form->process( params => { } ), "Didn't validate Test::Date with empty params" ); is( $form->field('another_date')->fif, '2014-05-20', 'date fif is correct' ); ok( $form->process( params => { end_date => '1999-12-31', another_date => '2014-05-20' } ), "validated ok" ); # # DateTime # $class = 'HTML::FormHandler::Field::DateTime'; use_ok($class); #$field = $class->new( name => 'test_field', format => "mm/dd/yy" ); $field = $class->new( name => 'test_field', field_list => [ year => 'Integer', month => 'Integer', day => 'Integer' ] ); ok( defined $field, 'new() called for DateTime' ); $field->build_result; $field->_set_input({ month => 2, day => 10, year => 2009 }); $field->test_validate_field; ok( $field->validated, 'No errors 1' ); ok( $field->value && $field->value->isa('DateTime'), 'isa DateTime' ); is( $field->value->ymd, '2009-02-10', 'correct DateTime' ); $field = $class->new( name => 'test_field', field_list => [ year => 'Integer', month => { type => 'Integer', range_start => 9, range_end => 12 }, day => 'Integer' ] ); ok( $field, 'field compiles and builds' ); $field->reset_result; my $date_hash = { month => 5, day => 10, year => 2009 }; $field->_set_input($date_hash); $field->test_validate_field; ok( $field->has_errors, 'Date is wrong month' ); is( $field->fif, $date_hash, 'Correct value' ); $field->reset_result; $date_hash = { month => 10, day => 32, year => 2009 }; $field->_set_input($date_hash); $field->test_validate_field; ok( $field->has_errors, 'Date is wrong month' ); like( $field->errors->[0], qr/Not a valid/, 'DateTime error message' ); is( $field->fif, $date_hash, 'Correct value' ); { package Test::DateTime; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'my_date' => ( type => 'DateTime' ); has_field 'my_date.month'; has_field 'my_date.year'; has_field 'my_date.day'; } $form = Test::DateTime->new; my $dt = DateTime->new( year => '2010', month => '02', day => '22' ); $form->process( init_object => { foo => 'abc', my_date => $dt } ); is_deeply( $form->field('my_date')->fif, { year => '2010', month => '2', day => '22' }, 'right fif from obj with date' ); my $fif = $form->fif; is( $fif->{'my_date.day'}, '22', 'right fif day'); $fif->{'my_date.day'} = '15'; $form->process( params => $fif ); ok( $form->validated, 'form validated' ); is( $form->field('my_date')->value->mdy, '02-15-2010', 'right value for my_date' ); # # HTML5 date-format restrictions # { package Test::Date::HTML5; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; has '+is_html5' => ( default => 1 ); has_field 'date' => ( type => 'Date', format => 'mm/dd/yy'); } $form = Test::Date::HTML5->new; warnings_like { $form->render } [qr/HTML5/, qr/HTML5/], "Warning when rendering an HTML5 form with a non-ISO date format"; { package Test::Date::HTML5; has_field '+date' => ( format => 'yy-mm-dd' ); } ok( sub { $form = Test::Date::HTML5->new; $form->render; }, "HTML5 renders fine with ISO date format", ); { package Test::Date::HTML5::WithDefault; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; has_field 'date' => ( type => 'Date' ); } ok( sub { $form = Test::Date::HTML5::WithDefault->new; $form->render; }, "HTML5 renders fine with default date format", ); done_testing; float.t100644000770000024 121012576552253 17457 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'float1' => ( type => 'Float', decimal_symbol_for_db => ',' ); has_field 'float2' => ( type => 'Float' ); has_field 'float3' => ( type => 'Float' ); } my $form = Test::Form->new; my $params = { float1 => '+1.00', float2 => '3.35', float3 => '44.0' }; $form->process( params => $params ); my $float1 = $form->field('float1')->value; is( $float1, '1,00', 'float has been deflated' ); my $float2 = $form->field('float2')->value; is( $float2, '3.35', 'correct float value' ); done_testing; array.t100644000770000024 740312576552253 17513 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Repeatable::Array; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'my_array' => ( type => 'Repeatable', num_when_empty => 2, do_wrapper => 1, do_label => 1 ); has_field 'my_array.contains' => ( type => 'Text', do_wrapper => 0, do_label => 0 ); has_field 'my_array2' => ( type => 'Repeatable', num_when_empty => 2, do_wrapper => 1, do_label => 1 ); has_field 'my_array2.contains' => ( type => 'Text', widget_wrapper => 'None' ); has_field 'my_rep' => ( type => 'Repeatable', 'num_when_empty' => 2 ); # we want a label but not a div wrapper has_field 'my_rep.foo' => ( do_wrapper => 0 ); has_field 'bar'; } my $form = Test::Repeatable::Array->new; my $expected = '
My array
'; my $rendered = $form->field('my_array')->render; is_html($rendered, $expected, 'repeatable array field renders correctly'); $expected = '
My array2
'; $rendered = $form->field('my_array2')->render; is_html($rendered, $expected, 'repeatable array field renders correctly'); $rendered = $form->field('my_rep')->render; $expected = '
'; is_html($rendered, $expected, 'simple repeatable renders correctly'); $form->process( params => {} ); my $rendered_form = $form->render; $rendered = $form->field('my_array')->render; $expected = '
My array
'; is_html($rendered, $expected, 'repeatable array renders after process' ); $rendered = $form->field('my_rep')->render; $expected = '
'; is_html($rendered, $expected, 'simple repeatable renders correctly after process'); $form->process( params => { foo => 'xxx', bar => 'yyy', 'my_array.0' => 'one', 'my_array.1' => 'two', 'my_rep.0.foo' => 'fee', 'my_rep.1.foo' => 'fie' } ); $rendered = $form->render; $rendered = $form->field('my_array')->render; $expected = '
My array
'; is_html($rendered, $expected, 'array renders ok after processing with params' ); $rendered = $form->field('my_rep')->render; $expected = '
'; is_html($rendered, $expected, 'repeatable renders ok after processing with params' ); done_testing; basic.t100644000770000024 551612576552253 17461 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_text' ); has_field 'foo'; has_field 'bar'; has_field 'save' => ( type => 'Submit' ); } my $form = Test::Form->new; ok( $form, 'form built' ); $form->process; my $rendered = $form->render; my $expected = '
'; is_html($rendered, $expected, 'simple form renders ok' ); } { { package Test::Form::Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_compound' ); has_field 'my_comp' => ( type => 'Compound' ); has_field 'my_comp.one'; has_field 'my_comp.two'; } my $form = Test::Form::Compound->new; ok( $form, 'form built' ); $form->process; my $rendered = $form->render; my $expected = '
'; is_html( $rendered, $expected, 'got expected rendering for compound' ); } { { package Test::Form::Repeatable; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_rep' ); has_field 'my_rep' => ( type => 'Repeatable' ); has_field 'my_rep.one'; has_field 'my_rep.two'; } my $form = Test::Form::Repeatable->new; $form->process; my $rendered = $form->render; # by default, repeatable instances are wrapped, with the class # 'hfh-repinst' my $expected = '
'; is_html( $rendered, $expected, 'got expected rendering for repeatable'); } done_testing; label.t100644000770000024 231712576552253 17453 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; our $labels = { foo => 'My Foo', bar => 'My Bar', }; has_field 'foo' => ( wrap_label_method => \&wrap_label, build_label_method => \&build_label, ); has_field 'bar'; sub build_label { my $self = shift; # self is field my $name = $self->name; return $labels->{$name}; } sub wrap_label { my ( $self, $label ) = @_; $label ||= $self->label; # so it can be used outside of rendering... my $name = $self->name; return qq{$label}; } } my $form = MyApp::Test::Form->new; ok( $form ); is( $form->field('foo')->label, 'My Foo', 'label is correct' ); is( $form->field('foo')->wrap_label, 'My Foo', 'wrapped label is correct' ); my $rendered = $form->field('foo')->render; my $expected = ''; is_html( $rendered, $expected, 'rendered ok' ); done_testing; table.t100644000770000024 464612576552253 17472 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Table'; has '+name' => ( default => 'renderform' ); has_field 'test_field' => ( type => 'Text', label => 'TEST', id => 'f99', ); has_field 'number'; has_field 'fruit' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple' ); has_field 'opt_in' => ( type => 'Select', widget => 'RadioGroup', options => [{ value => 0, label => 'No'}, { value => 1, label => 'Yes'} ] ); has_field 'active' => ( type => 'Checkbox' ); has_field 'comments' => ( type => 'TextArea' ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'selected' => ( type => 'Boolean' ); has_field 'start_date' => ( type => 'DateTime' ); has_field 'start_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'start_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); has_field 'start_date.year' => ( type => 'Integer', range_start => 2000, range_end => 2020 ); has_field 'two_errors' => ( apply => [ { check => [ ], message => 'First constraint error' }, { check => [ ], message => 'Second constraint error' } ] ); has_field 'submit' => ( type => 'Submit', value => 'Update' ); has '+dependency' => ( default => sub { [ ['start_date.month', 'start_date.day', 'start_date.year'] ] } ); has_field 'no_render' => ( widget => 'NoRender' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } } my $form = new_ok "Test::Form"; my $html ; ok( $html = $form->render, 'get table rendered output from form'); like $html, qr/
/, "form start is rendered"; like $html, qr/<\/table>\n<\/form>/, "form end is rendered"; my $rendered = $form->render_field('number'); my $expected = ''; is_html( $rendered, $expected, 'number field rendered ok' ); done_testing; result000755000770000024 012576552253 16103 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 1105412576552253 17532 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/resultuse strict; use warnings; use Test::More; use_ok('HTML::FormHandler'); { package My::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform_' ); has_field 'optname' => ( temp => 'First' ); has_field 'reqname' => ( required => 1 ); has_field 'somename'; has_field 'my_selected' => ( type => 'Checkbox' ); has_field 'must_select' => ( type => 'Checkbox', required => 1 ); has_field 'fruit' => ( type => 'Select' ); has_field 'optname' => ( temp => 'Second' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } } my $form = My::Form->new; is( $form->field('optname')->temp, 'Second', 'got second optname field' ); ok( !$form->process, 'Empty data' ); ok( $form->result, 'result exists' ); ok( $form->field('optname'), 'result field exists' ); my $good = { reqname => 'hello', optname => 'not req', fruit => 2, must_select => 1, }; $form->process($good); ok( $form->validated, 'Good data' ); my $result = $form->result; ok( $result, 'got result object' ); ok( $result->validated, 'result validated'); ok( $result->has_input, 'result still has input'); my $num_errors = $form->num_errors; $result = $form->run($good); ok( !$form->has_result, 'has result after been cleared'); ok( !$form->validated, 'form has been cleared' ); # field still points to existing result ok( !$form->field('reqname')->input, 'no input for field'); ok( !$form->field('reqname')->value, 'no value for field'); ok( $result->validated, 'result still has result' ); is( $result->num_errors, $num_errors, 'number of errors is correct'); is( $result->field('somename')->value, undef, 'no value for somename' ); ok( !$result->field('somename')->has_value, 'predicate no value' ); $good->{my_selected} = 0; $good->{somename} = ''; is_deeply( $result->fif, $good, 'fif is correct' ); delete $good->{my_selected}; $form->process({}); ok( !$form->field('reqname')->input, 'no input for field'); $good->{somename} = 'testing'; $result = $form->run($good); is( $result->field('somename')->value, 'testing', 'use input for extra data' ); is( $result->field('my_selected')->value, 0, 'correct value for unselected checkbox' ); $result = $form->run( {} ); ok( !$result->validated, 'form doesn\'t validate with empty params' ); is( $result->num_errors, 0, 'form doesn\'t have errors with empty params' ); my $bad_1 = { reqname => '', optname => 'not req', fruit => 4, }; $result = $form->run($bad_1); ok( !$result->validated, 'bad 1' ); ok( $result->field('fruit')->has_errors, 'fruit has error' ); ok( $result->field('reqname')->has_errors, 'reqname has error' ); ok( $result->field('must_select')->has_errors, 'must_select has error' ); ok( !$result->field('optname')->has_errors, 'optname has no error' ); $result = $form->run; ok( !$result->validated, 'no leftover params' ); is( $result->num_errors, 0, 'no leftover errors' ); ok( !$result->field('reqname')->has_errors, 'no leftover error in field' ); ok( !$result->field('optname')->fif, 'no lefover fif values' ); my $init_object = { reqname => 'Starting Perl', optname => 'Over Again' }; $form = My::Form->new( init_object => $init_object ); is( $form->field('optname')->value, 'Over Again', 'get right value from form' ); $result = $form->run( params => {} ); ok( !$result->validated, 'form did not validate' ); my $values = { 'fruit' => undef, 'must_select' => undef, 'my_selected' => undef, 'optname' => 'Over Again', 'reqname' => 'Starting Perl', 'somename' => undef, }; is_deeply( $result->value, $values, 'get right values from form' ); $init_object->{my_selected} = 0; $init_object->{must_select} = 1; $result = $form->run($init_object); ok( $result->validated, 'form validates with params' ); $init_object->{fruit} = undef; is_deeply( $result->value, $init_object, 'get right values from result' ); ok( !$form->has_value, 'Form value cleared' ); ok( !$form->has_input, 'Form input cleared' ); $form = HTML::FormHandler->new( field_list => [ foo => { type => 'Text', required => 1 } ] ); # 'image' input produces { foo => bar, 'foo.x' => 42, 'foo.y' => 23 } $form = HTML::FormHandler->new( name => 'baz', html_prefix => 1, field_list => [ 'foo' ] ); eval{ $result = $form->run( params => { 'baz.foo' => 'bar', 'baz.foo.x' => 42, 'baz.foo.y' => 23 } ) }; ok( !$@, 'image field processed' ) or diag $@; is_deeply( $result->field( 'foo' )->value, { '' => 'bar', x => 42, y => 23 }, 'image input value correct' ); done_testing; wizard000755000770000024 012576552253 16065 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 474212576552253 17502 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/wizarduse strict; use warnings; use Test::More; use_ok( 'HTML::FormHandler::Wizard' ); { package Test::Wizard; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Wizard'; has_field 'foo'; has_field 'bar'; has_field 'zed'; has_page 'one' => ( fields => ['foo'] ); has_page 'two' => ( fields => ['bar'] ); has_page 'three' => ( fields => ['zed'] ); } my $wizard = Test::Wizard->new; ok( $wizard, 'wizard built ok' ); is( $wizard->num_pages, 3, 'right number of pages' ); ok( $wizard->page('one')->has_fields, 'first page has a field' ); is( $wizard->page('one')->field('foo')->name, 'foo', 'field object from page' ); { package Test::Wizard::List; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Wizard'; has_field 'foo'; has_field 'bar'; has_field 'zed'; sub page_list { [ one => { fields => ['foo'] }, two => { fields => ['bar'] }, three => { fields => ['zed'] } ]} } my $stash = {}; $wizard = Test::Wizard::List->new( stash => $stash ); ok( $wizard, 'wizard built ok' ); is( $wizard->num_pages, 3, 'right number of pages' ); ok( $wizard->page('one')->has_fields, 'first page has a field' ); is( $wizard->page('one')->field('foo')->name, 'foo', 'field object from page' ); $wizard->process( params => {} ); like( $wizard->render, qr/\/, 'renders ok' ); is( $wizard->field('page_num')->value, 1, 'wizard is on first page' ); $wizard->process( params => { foo => 'test123', page_num => 1 } ); is( $wizard->field('page_num')->value, 2, 'wizard is on second page' ); like( $wizard->render, qr/\/, 'renders ok' ); is_deeply( $stash, { foo => 'test123', page_num => 1 }, 'values saved' ); $wizard->process( params => { bar => 'xxxxx', page_num => 2 } ); is( $wizard->field('page_num')->value, 3, 'wizard is on third page' ); like( $wizard->render, qr/\/, 'renders ok' ); is_deeply( $stash, { foo => 'test123', page_num => 2, bar => 'xxxxx' }, 'values saved' ); $wizard->process( params => { zed => 'omega', page_num => 3 } ); ok( $wizard->validated, 'wizard validated on last page' ); is_deeply( $stash, { foo => 'test123', page_num => 3, bar => 'xxxxx', zed => 'omega' }, 'values saved' ); is_deeply( $wizard->value, { foo => 'test123', page_num => 3, bar => 'xxxxx', zed => 'omega' }, 'value is correct' ); done_testing; chbox_group.t100644000770000024 145012576552253 17621 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; use_ok('HTML::FormHandler::Widget::Field::CheckboxGroup'); { package Test::CheckboxGroup; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo_list' => ( type => 'Multiple', widget => 'CheckboxGroup' ); sub options_foo_list { [ 1 => 'ShamWow', 2 => 'SliderStation', 3 => 'SlapChop', 4 => 'Zorbeez', 5 => 'OrangeGlow', ] } } my $form = Test::CheckboxGroup->new; ok( $form, 'form builds' ); $form->process( { foo_list => [ 2, 4 ] } ); ok( $form->validated, 'form validates' ); my $rendered = $form->field('foo_list')->render; ok( $rendered, 'field renders' ); my $rendered_form = $form->render; ok( $rendered_form, 'form renders' ); done_testing; form_errors.t100644000770000024 244112576552253 17642 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has 'secret' => ( is => 'rw', default => 'wrong' ); has_field 'foo'; has_field 'bar'; sub validate_foo { my ( $self, $field ) = @_; $field->add_error('Not a valid foo') if( $field->value eq 'test' ); } sub validate_bar { my ( $self, $field ) = @_; $field->add_error('Not a valid bar') if( $field->value eq 'bad_bar' ); } sub validate { my $self = shift; $self->add_form_error('Try again') if( $self->field('foo')->value ne $self->secret ); } } my $form = Test::Form->new; ok( $form, 'form builds' ); $form->process( params => {} ); my $params = { foo => 'test', bar => 'bad_bar', }; $form->process( secret => 'yikes', params => $params ); ok( !$form->validated, 'form did not validate' ); $form->process( secret => 'my_bar', params => { bar => 'my_bar', foo => 'my_foo' } ); my @errors = $form->errors; is( $errors[0], 'Try again', 'form error' ); $form->process( secret => 'my_foo', params => { bar => 'my_bar', foo => 'my_foo' } ); ok( $form->validated, 'form validated' ); ok( !$form->has_form_errors, 'form errors are gone' ); done_testing; memory_cycles.t100644000770000024 276612576552253 17777 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tuse strict; use warnings; use Test::More; use Test::Memory::Cycle; { package My::RepeatableForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform' ); has_field 'reqname' => ( required => 1 ); has_field 'vegetables' => ( type => 'Multiple' ); sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } has_field 'entries' => ( type => 'Repeatable', required => 1, required_message => 'Request without entries not accepted' ); has_field 'entries.rule_index' => ( type => 'PrimaryKey' ); has_field 'entries.foo' => ( type => 'Text', required => 1, ); has_field 'entries.bar' => ( type => 'Text', required => 1, ); has_field 'some_select' => ( type => 'Select', inactive => 1 ); sub update_model { my $self = shift; my $value = $self->field('some_select')->value; } } my $form = new_ok( 'My::RepeatableForm' ); my $params = { reqname => 'Testrequest', 'entries.1.foo' => 'test1', 'entries.1.bar' => 'test1', 'entries.2.foo' => 'test2', 'entries.2.bar' => 'test2', }; memory_cycle_ok( $form, 'form has no memory cycles before process' ); ok( $form->process( params => $params ), 'form processed ok' ); memory_cycle_ok( $form, 'form has no memory cycles after process' ); done_testing; nested.t100644000770000024 454212576552253 17656 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/blocksuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Nested::View; use HTML::FormHandler::Moose::Role; sub build_render_list { ['fset1'] } has_block 'fset1' => ( tag => 'fieldset', label => 'First Fieldset', render_list => ['foo', 'bar', 'pax', 'fset1.sub1', 'fset1.sub2'], ); has_block 'fset1.sub1' => ( tag => 'div', label => 'More Stuff', class => ['sub1'], render_list => ['fee', 'fie', 'fo'], ); has_block 'fset1.sub2' => ( tag => 'div', label => 'And Even More', class => ['sub2'], render_list => ['fum', 'man'], ); } { package MyApp::Form::Nested; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'MyApp::Form::Nested::View'; has '+name' => ( default => 'nested_form' ); has_field 'foo'; has_field 'bar'; has_field 'pax'; has_field 'fee'; has_field 'fie'; has_field 'fo'; has_field 'fum'; has_field 'man'; } my $form = MyApp::Form::Nested->new; ok( $form, 'form built' ); $form->process; my $rendered = $form->render; my $expected = '
First Fieldset
More Stuff
And Even More
'; is_html( $rendered, $expected, 'got expected rendering' ); done_testing; fields.t100644000770000024 4170112576552253 17651 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; # # Boolean # my $class = 'HTML::FormHandler::Field::Boolean'; use_ok($class); my $field = $class->new( name => 'test', ); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input(1); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, 1, 'Test true == 1' ); $field->_set_input(0); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); is( $field->value, 0, 'Test true == 0' ); $field->_set_input('checked'); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); is( $field->value, 1, 'Test true == 1' ); $field->_set_input('0'); $field->validate_field; ok( !$field->has_errors, 'Test for errors 4' ); is( $field->value, 0, 'Test true == 0' ); # email $class = 'HTML::FormHandler::Field::Email'; use_ok($class); $field = $class->new( name => 'test', ); $field->build_result; ok( defined $field, 'new() called' ); my $address = 'test@example.com'; $field->_set_input( $address ); $field->validate_field; ok( !$field->has_errors, 'Email Test for errors 1' ); is( $field->value, $address, 'is value input string' ); my $Address = 'Test@example.com'; $field->_set_input( $Address ); $field->validate_field; ok( !$field->has_errors, 'Email Test for errors 2' ); is( $field->value, lc($Address), 'is value input string' ); $field->preserve_case(1); $field->_set_input( $Address ); $field->validate_field; ok( !$field->has_errors, 'Email Test for errors 3' ); is( $field->value, $Address, 'field was not lowercased' ); $field->_set_input( 'test @ example . com' ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); is( $field->value, 'test@example.com', 'is email-valid corrected input string' ); # hidden $class = 'HTML::FormHandler::Field::Hidden'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); my $string = 'Some text'; $field->_set_input( $string ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, $string, 'is value input string'); $field->_set_input( '' ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); is( $field->value, undef, 'is value input string'); $field->required(1); $field->validate_field; ok( $field->has_errors, 'Test for errors 3' ); $field->_set_input('hello'); $field->required(1); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); is( $field->value, 'hello', 'Check again' ); $field->maxlength( 3 ); $field->validate_field; ok( $field->has_errors, 'Test for too long' ); $field->maxlength( 5 ); $field->validate_field; ok( !$field->has_errors, 'Test for right length' ); $field->minlength( 10 ); $field->validate_field; ok( $field->has_errors, 'Test not long enough' ); $field->minlength( 5 ); $field->validate_field; ok( !$field->has_errors, 'Test just long enough' ); $field->minlength( 4 ); $field->validate_field; ok( !$field->has_errors, 'Test plenty long enough' ); # integer $class = 'HTML::FormHandler::Field::Integer'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->reset_result; ok( defined $field, 'new() called' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, 1, 'Test value == 1' ); $field->_set_input( 0 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); is( $field->value, 0, 'Test value == 0' ); $field->_set_input( 'checked' ); $field->validate_field; ok( $field->has_errors, 'Test non integer' ); is( $field->errors->[0], 'Value must be an integer', 'correct error'); $field->_set_input( '+10' ); $field->validate_field; ok( !$field->has_errors, 'Test positive' ); is( $field->value, 10, 'Test value == 10' ); $field->_set_input( '-10' ); $field->validate_field; ok( !$field->has_errors, 'Test negative' ); is( $field->value, -10, 'Test value == -10' ); $field->_set_input( '-10.123' ); $field->validate_field; ok( $field->has_errors, 'Test real number' ); $field->range_start( 10 ); $field->_set_input( 9 ); $field->validate_field; ok( $field->has_errors, 'Test 9 < 10 fails' ); $field->_set_input( 100 ); $field->validate_field; ok( !$field->has_errors, 'Test 100 > 10 passes ' ); $field->range_end( 20 ); $field->_set_input( 100 ); $field->validate_field; ok( $field->has_errors, 'Test 10 <= 100 <= 20 fails' ); $field->range_end( 20 ); $field->_set_input( 15 ); $field->validate_field; ok( !$field->has_errors, 'Test 10 <= 15 <= 20 passes' ); $field->_set_input( 10 ); $field->validate_field; ok( !$field->has_errors, 'Test 10 <= 10 <= 20 passes' ); $field->_set_input( 20 ); $field->validate_field; ok( !$field->has_errors, 'Test 10 <= 20 <= 20 passes' ); $field->_set_input( 21 ); $field->validate_field; ok( $field->has_errors, 'Test 10 <= 21 <= 20 fails' ); $field->_set_input( 9 ); $field->validate_field; ok( $field->has_errors, 'Test 10 <= 9 <= 20 fails' ); # intrange.t $class = 'HTML::FormHandler::Field::IntRange'; use_ok( $class ); $field = $class->new( name => 'test_field', range_start => 30, range_end => 39, ); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 30 ); $field->validate_field; ok( !$field->has_errors, '30 in range' ); $field->_set_input( 39 ); $field->validate_field; ok( !$field->has_errors, '39 in range' ); $field->_set_input( 35 ); $field->validate_field; ok( !$field->has_errors, '35 in range' ); $field->_set_input( 29 ); $field->validate_field; ok( $field->has_errors, '29 out of range' ); $field->_set_input( 40 ); $field->validate_field; ok( $field->has_errors, '40 out of range' ); # minute $class = 'HTML::FormHandler::Field::Minute'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 0 ); $field->validate_field; ok( !$field->has_errors, '0 in range' ); $field->_set_input( 59 ); $field->validate_field; ok( !$field->has_errors, '59 in range' ); $field->_set_input( 12 ); $field->validate_field; ok( !$field->has_errors, '12 in range' ); $field->_set_input( -1 ); $field->validate_field; ok( $field->has_errors, '-1 out of range' ); $field->_set_input( 60 ); $field->validate_field; ok( $field->has_errors, '60 out of range' ); # money $class = 'HTML::FormHandler::Field::Money'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( ' $123.45 ' ); $field->validate_field; ok( !$field->has_errors, 'Test for errors " $123.00 "' ); is( $field->value, 123.45, 'Test value == 123.45' ); $field->_set_input( ' $12x3.45 ' ); $field->validate_field; ok( $field->has_errors, 'Test for errors " $12x3.45 "' ); is( $field->errors->[0], 'Value cannot be converted to money', 'get error' ); $field->_set_input( 2345 ); $field->validate_field; is( $field->value, '2345.00', 'transformation worked: 2345 => 2345.00' ); # monthday $class = 'HTML::FormHandler::Field::MonthDay'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, '1 in range' ); $field->_set_input( 31 ); $field->validate_field; ok( !$field->has_errors, '31 in range' ); $field->_set_input( 12 ); $field->validate_field; ok( !$field->has_errors, '12 in range' ); $field->_set_input( 0 ); $field->validate_field; ok( $field->has_errors, '0 out of range' ); $field->_set_input( 32 ); $field->validate_field; ok( $field->has_errors, '32 out of range' ); # monthname $class = 'HTML::FormHandler::Field::MonthName'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); for ( 1 .. 12 ) { $field->_set_input( $_ ); $field->validate_field; ok( !$field->has_errors, $_ . ' is valid' ); } $field->_set_input( 0 ); $field->validate_field; ok( $field->has_errors, '0 is not valid day of the week' ); $field->_set_input( 13 ); $field->validate_field; ok( $field->has_errors, '13 is not valid day of the week' ); #month $class = 'HTML::FormHandler::Field::Month'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, '1 in range' ); $field->_set_input( 12 ); $field->validate_field; ok( !$field->has_errors, '59 in range' ); $field->_set_input( 6 ); $field->validate_field; ok( !$field->has_errors, '6 in range' ); $field->_set_input( 0 ); $field->validate_field; ok( $field->has_errors, '0 out of range' ); $field->_set_input( 13 ); $field->validate_field; ok( $field->has_errors, '60 out of range' ); $field->_set_input( 'March' ); $field->validate_field; ok( $field->has_errors, 'March is not numeric' ); is( $field->errors->[0], "'March' is not a valid value", 'is error message' ); # multiple $class = 'HTML::FormHandler::Field::Multiple'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->options([ { value => 1, label => 'one' }, { value => 2, label => 'two' }, { value => 3, label => 'three' }, ]); ok( $field->options, 'options method called' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is_deeply( $field->value, [1], 'Test 1 => [1]' ); $field->_set_input( [1] ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); ok( eq_array( $field->value, [1], 'test array' ), 'Check [1]'); $field->_set_input( [1,2] ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); ok( eq_array( $field->value, [1,2], 'test array' ), 'Check [1,2]'); $field->_set_input( [1,2,4] ); $field->validate_field; ok( $field->has_errors, 'Test for errors 4' ); is( $field->errors->[0], "'4' is not a valid value", 'Error message' ); # password tested separately. requires a form. # posinteger $class = 'HTML::FormHandler::Field::PosInteger'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, 1, 'Test value == 1' ); $field->_set_input( 0 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); is( $field->value, 0, 'Test value == 0' ); $field->_set_input( 'checked' ); $field->validate_field; ok( $field->has_errors, 'Test non integer' ); $field->_set_input( '+10' ); $field->validate_field; ok( !$field->has_errors, 'Test positive' ); is( $field->value, 10, 'Test value == 10' ); $field->_set_input( '-10' ); $field->validate_field; ok( $field->has_errors, 'Test negative' ); $field->_set_input( '-10.123' ); $field->validate_field; ok( $field->has_errors, 'Test real number ' ); # second $class = 'HTML::FormHandler::Field::Second'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 0 ); $field->validate_field; ok( !$field->has_errors, '0 in range' ); $field->_set_input( 59 ); $field->validate_field; ok( !$field->has_errors, '59 in range' ); $field->_set_input( 12 ); $field->validate_field; ok( !$field->has_errors, '12 in range' ); $field->_set_input( -1 ); $field->validate_field; ok( $field->has_errors, '-1 out of range' ); $field->_set_input( 60 ); $field->validate_field; ok( $field->has_errors, '60 out of range' ); # select $class = 'HTML::FormHandler::Field::Select'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); ok( $field->options, 'Test for init_options failure in 0.09' ); my $options = [ { value => 1, label => 'one' }, { value => 2, label => 'two' }, { value => 3, label => 'three' }, ]; $field->options($options); ok( $field->options, 'Test for set options failure' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, 1, 'Test true == 1' ); $field->_set_input( [1] ); $field->validate_field; ok( $field->has_errors, 'Test for errors array' ); $field->_set_input( [1,4] ); $field->validate_field; ok( $field->has_errors, 'Test for errors 4' ); is( $field->errors->[0], 'This field does not take multiple values', 'Error message' ); $field = $class->new( name => 'test_prompt', 'empty_select' => "Choose a Number", options => $options, required => 1 ); is( $field->num_options, 3, 'right number of options'); # textarea $class = 'HTML::FormHandler::Field::TextArea'; use_ok( $class ); $field = $class->new( name => 'comments', cols => 40, rows => 3 ); $field->build_result; ok( $field, 'get TextArea field'); $field->_set_input("Testing, testing, testing... This is a test"); $field->validate_field; ok( !$field->has_errors, 'field has no errors'); $field->maxlength( 10 ); $field->validate_field; ok( $field->has_errors, 'field has errors'); is( $field->errors->[0], 'Field should not exceed 10 characters. You entered 43', 'Test for too long' ); # text $class = 'HTML::FormHandler::Field::Text'; use_ok( $class ); $field = $class->new( name => 'test',); $field->build_result; ok( defined $field, 'new() called' ); $string = 'Some text'; $field->_set_input( $string ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); is( $field->value, $string, 'is value input string'); $field->_set_input( '' ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 2' ); is( $field->value, undef, 'is value input string'); $field->required(1); $field->validate_field; ok( $field->has_errors, 'Test for errors 3' ); $field->_set_input('hello'); $field->required(1); $field->validate_field; ok( !$field->has_errors, 'Test for errors 3' ); is( $field->value, 'hello', 'Check again' ); $field->maxlength( 3 ); $field->validate_field; is( $field->errors->[0], 'Field should not exceed 3 characters. You entered 5', 'Test for too long' ); $field->maxlength( 5 ); $field->validate_field; ok( !$field->has_errors, 'Test for right length' ); $field->minlength( 10 ); $field->minlength_message('[_3] field must be at least [quant,_1,character]'); $field->validate_field; is( $field->errors->[0], 'Test field must be at least 10 characters', 'Test not long enough' ); $field->minlength( 5 ); $field->validate_field; ok( !$field->has_errors, 'Test just long enough' ); $field->minlength( 4 ); $field->validate_field; ok( !$field->has_errors, 'Test plenty long enough' ); $field = $class->new( name => 'test_not_nullable', not_nullable => 1); $field->build_result; $field->input(''); $field->validate_field; is( $field->value, '', 'empty string'); # weekday $class = 'HTML::FormHandler::Field::Weekday'; use_ok( $class ); $field = $class->new( name => 'test_field',); $field->build_result; ok( defined $field, 'new() called' ); for ( 0 .. 6 ) { $field->_set_input( $_ ); $field->validate_field; ok( !$field->has_errors, $_ . ' is valid' ); } $field->_set_input( -1 ); $field->validate_field; ok( $field->has_errors, '-1 is not valid day of the week' ); $field->_set_input( 7 ); $field->validate_field; ok( $field->has_errors, '7 is not valid day of the week' ); # year $class = 'HTML::FormHandler::Field::Year'; use_ok( $class ); $field = $class->new( name => 'test_field' ); $field->build_result; ok( defined $field, 'new() called' ); $field->_set_input( 0 ); $field->validate_field; ok( $field->has_errors, '0 is bad year' ); $field->_set_input( (localtime)[5] + 1900 ); $field->validate_field; ok ( !$field->has_errors, 'Now is just a fine year' ); $field->_set_input( 2100 ); $field->validate_field; ok( $field->has_errors, '2100 makes the author really old' ); # float $class = 'HTML::FormHandler::Field::Float'; use_ok( $class ); $field = $class->new( name => 'float_test' ); $field->build_result; ok( defined $field, 'field built' ); $field->_set_input( '2.0' ); $field->validate_field; ok( !$field->has_errors, 'accepted 2.0 value' ); $field->_set_input( '2.000' ); $field->validate_field; ok( $field->has_errors, 'error for 3 decimal places' ); is( $field->errors->[0], 'May have a maximum of 2 digits after the decimal point, but has 3', 'error message correct' ); $field->size(4); $field->_set_input( '12345.00' ); $field->validate_field; ok( $field->has_errors, 'error for size' ); is( $field->errors->[0], 'Total size of number must be less than or equal to 4, but is 7', 'error message correct' ); $field->_set_input( '12.30' ); $field->validate_field; ok( $field->validated, 'field validated' ); # Boolean select $class = 'HTML::FormHandler::Field::BoolSelect'; use_ok( $class ); $field = $class->new( name => 'boolselect' ); $field->build_result; ok( defined $field, 'field built' ); $field->_set_input( '' ); $field->validate_field; ok( !$field->has_errors, 'accepted null value' ); $field->_set_input( 1 ); $field->validate_field; ok( !$field->has_errors, 'accepted 1 value' ); $field->_set_input( 0 ); $field->validate_field; ok( !$field->has_errors, 'accepted 0 value' ); done_testing; select.t100644000770000024 1566712576552253 17676 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use HTML::FormHandler::Field::Text; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'options_form' ); has_field 'test_field' => ( type => 'Text', label => 'TEST', id => 'f99', ); has_field 'fruit' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple' ); has_field 'empty' => ( type => 'Multiple', no_option_validation => 1 ); has_field 'build_attr' => ( type => 'Select' ); sub default_fruit { 2 } # the following sometimes happens with db options sub options_empty { ([]) } has 'options_fruit' => ( is => 'rw', traits => ['Array'], default => sub { [1 => 'apples', 2 => 'oranges', 3 => 'kiwi'] } ); sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } has 'options_build_attr' => ( is => 'ro', traits => ['Array'], lazy_build => 1 ); sub _build_options_build_attr { return [ 1 => 'testing', 2 => 'moose', 3 => 'attr builder', ]; } } my $form = Test::Form->new; ok( $form, 'create form'); my $veg_options = [ {'label' => 'lettuce', 'value' => 1 }, {'label' => 'broccoli', 'value' => 2 }, {'label' => 'carrots', 'value' => 3 }, {'label' => 'peas', 'value' => 4 } ]; my $field_options = $form->field('vegetables')->options_ref; is_deeply( $field_options, $veg_options, 'get options for vegetables' ); my $fruit_options = [ {'label' => 'apples', 'value' => 1 }, {'label' => 'oranges', 'value' => 2 }, {'label' => 'kiwi', 'value' => 3 } ]; $field_options = $form->field('fruit')->options; is_deeply( $field_options, $fruit_options, 'get options for fruit' ); my $build_attr_options = [ {'label' => 'testing', 'value' => 1 }, {'label' => 'moose', 'value' => 2 }, {'label' => 'attr builder', 'value' => 3 } ]; $field_options = $form->field('build_attr')->options_ref; is_deeply( $field_options, $build_attr_options, 'get options for fruit' ); is( $form->field('fruit')->value, 2, 'initial value ok'); $form->process( params => {}, init_object => { vegetables => undef, fruit => undef, build_attr => undef } ); $field_options = $form->field('vegetables')->options; is_deeply( $field_options, $veg_options, 'get options for vegetables after process' ); $field_options = $form->field('fruit')->options; is_deeply( $field_options, $fruit_options, 'get options for fruit after process' ); $field_options = $form->field('build_attr')->options; is_deeply( $field_options, $build_attr_options, 'get options for fruit after process' ); my $params = { fruit => 2, vegetables => [2,4], empty => 'test', }; $form->process( $params ); ok( $form->validated, 'form validated' ); is( $form->field('fruit')->value, 2, 'fruit value is correct'); is_deeply( $form->field('vegetables')->value, [2,4], 'vegetables value is correct'); is_deeply( $form->fif, { fruit => 2, vegetables => [2, 4], empty => ['test'], test_field => '', build_attr => '' }, 'fif is correct'); is_deeply( $form->values, { fruit => 2, vegetables => [2, 4], empty => ['test'], build_attr => undef }, 'values are correct'); is( $form->field('vegetables')->as_label, 'broccoli, peas', 'multiple as_label works'); is( $form->field('vegetables')->as_label([3,4]), 'carrots, peas', 'pass in multiple as_label works'); $params = { fruit => 2, vegetables => 4, }; $form->process($params); is_deeply( $form->field('vegetables')->value, [4], 'value for vegetables correct' ); is_deeply( $form->field('vegetables')->fif, [4], 'fif for vegetables correct' ); { package Test::Form2; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'my_list' => ( type => 'Select' ); # this adds a 'selected' hash key to an option as an alternative # to setting the default for the field. sub options_my_list { return [ { value => 1, label => 'One', selected => 1, }, { value => 2, label => 'Two', }, { value => 3, label => 'Three', } ]; } } $form = Test::Form2->new; ok( $form, 'form built' ); my $rendered_field = $form->field('my_list')->render; like( $rendered_field, qr/ '; $rendered = $form->field('my_alt')->render; is_html( $rendered, $expected, 'compound field with table inline wrapper' ); done_testing; result.t100644000770000024 1126112576552253 17730 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use Test::Differences; use HTML::FormHandler::Test; use_ok('HTML::FormHandler::Result'); { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+widget_form' => ( default => 'Simple' ); has '+name' => ( default => 'testform' ); has_field 'test_field' => ( size => 20, label => 'TEST', id => 'f99', ); has_field 'number'; has_field 'fruit' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple' ); has_field 'opt_in' => ( type => 'Select', widget => 'RadioGroup', options => [{ value => 0, label => 'No'}, { value => 1, label => 'Yes'} ] ); has_field 'active' => ( type => 'Checkbox' ); has_field 'comments' => ( type => 'TextArea' ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'selected' => ( type => 'Boolean' ); has_field 'start_date' => ( type => 'DateTime' ); has_field 'start_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'start_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); has_field 'start_date.year' => ( type => 'Integer', range_start => 2000, range_end => 2020 ); has_field 'two_errors' => ( apply => [ { check => [ ], message => 'First constraint error' }, { check => [ ], message => 'Second constraint error' } ] ); has_field 'submit' => ( type => 'Submit', value => 'Update' ); has '+dependency' => ( default => sub { [ ['start_date.month', 'start_date.day', 'start_date.year'] ] } ); has_field 'no_render' => ( widget => 'NoRender' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } } my $form = Test::Form->new; ok( $form, 'create form'); my $params1 = { test_field => 'something', number => 0, fruit => 2, vegetables => [2,4], active => 'now', comments => 'Four score and seven years ago...', hidden => '1234', selected => '1', 'start_date.month' => '7', 'start_date.day' => '14', 'start_date.year' => '2006', two_errors => 'aaa', opt_in => 0, }; $form->process( $params1 ); my $outputf = $form->render; ok( $outputf, 'get rendered output from form'); my $result1 = $form->result; ok( $result1, 'get result' ); my $outputr = $result1->render; ok( $outputr, 'get render from result'); is_html( $outputf, $outputr, 'no diff form and result'); my $params2 = { test_field => 'anything', number => 2, fruit => 3, vegetables => [2,4], active => 'now', comments => 'Four centuries and seven years ago...', hidden => '5678', selected => '0', 'start_date.month' => '9', 'start_date.day' => '14', 'start_date.year' => '2008', two_errors => 'aaa', opt_in => 1, }; my $result2 = $form->run($params2); my $outputr2 = $result1->render; is_html( $outputr, $outputr2, 'no diff second execution'); #$outputr > io('first_result.txt'); #$outputr2 > io('second_result.txt'); #my $diff = `diff first_result.txt second_result.txt`; #diag( $diff ); $form->process($params1); is_html( $result1->field('test_field')->render, $form->field('test_field')->render, 'no diff test_field' ); is_html( $result1->field('number')->render, $form->field('number')->render, 'no diff number' ); is_html( $result1->field('fruit')->render, $form->field('fruit')->render, 'no diff fruit' ); is_html( $result1->field('vegetables')->render, $form->field('vegetables')->render, 'no diff vegetables' ); is_html( $result1->field('active')->render, $form->field('active')->render, 'no diff active' ); is_html( $result1->field('comments')->render, $form->field('comments')->render, 'no diff comments' ); is_html( $result1->field('hidden')->render, $form->field('hidden')->render, 'no diff hidden' ); is_html( $result1->field('selected')->render, $form->field('selected')->render, 'no diff selected' ); is_html( $result1->field('start_date.month')->render, $form->field('start_date.month')->render, 'no diff start_date.month' ); is_html( $result1->field('start_date.day')->render, $form->field('start_date.day')->render, 'no diff start_date.day' ); is_html( $result1->field('start_date.year')->render, $form->field('start_date.year')->render, 'no diff start_date.year' ); is_html( $result1->field('two_errors')->render, $form->field('two_errors')->render, 'no diff two_errors' ); is_html( $result1->field('opt_in')->render, $form->field('opt_in')->render, 'no diff opt_in' ); done_testing; select.t100644000770000024 470212576552253 17653 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_form' ); has_field 'fruit' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple', empty_select => '-- Pick One --' ); has_field 'my_option' => ( type => 'BoolSelect' ); sub options_fruit { return ( '"apples"' => '"apples"', '' => '', '&kiwi&' => '&kiwi&', ); } sub options_vegetables { return ( '' => '', 'broccoli' => 'broccoli', 'carrots' => 'carrots', '& peas' => '& peas', ); } } my $form = Test::Form->new; my $params = { fruit => '', vegetables => [ 'broccoli', '& peas' ], }; $form->process( $params ); my $rendered = $form->field('fruit')->render; my $expected = '
'; is_html( $rendered, $expected, 'output from select field'); $rendered = $form->field('vegetables')->render; $expected = '
'; is_html( $rendered, $expected, 'output from select multiple field'); $rendered = $form->field('my_option')->render; $expected = '
'; is_html( $rendered, $expected, 'output from BoolSelect field' ); done_testing; simple.t100644000770000024 2070212576552253 17703 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use HTML::FormHandler::Field::Text; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; sub build_do_form_wrapper { 1 } sub build_form_wrapper_class { 'form_wrapper' } has '+name' => ( default => 'testform' ); has_field 'test_field' => ( element_class => 'test123', size => 20, label => 'TEST', id => 'f99', ); has_field 'number'; has_field 'fruit' => ( type => 'Select' ); has_field 'cheese' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple' ); has_field 'grains' => ( type => 'Multiple' ); has_field 'opt_in' => ( type => 'Select', widget => 'RadioGroup', options => [{ value => 0, label => 'No'}, { value => 1, label => 'Yes'} ] ); has_field 'starch' => ( type => 'Multiple', widget => 'CheckboxGroup', options => [{ value => 1, label => 'One'}, { value => 2, label => 'Two'}, { value => 3, label => 'Three' }, ] ); has_field 'active' => ( type => 'Checkbox' ); has_field 'comments' => ( type => 'TextArea', cols => 40, rows => 3 ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'selected' => ( type => 'Boolean' ); has_field 'start_date' => ( type => 'DateTime', do_wrapper => 1, tags => { wrapper_tag => 'fieldset' }, wrapper_attr => { class => 'start_date' }, ); has_field 'start_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'start_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); has_field 'start_date.year' => ( type => 'Integer', range_start => 2000, range_end => 2020 ); has_field 'two_errors' => ( apply => [ { check => [ ], message => 'First constraint error' }, { check => [ ], message => 'Second constraint error' } ] ); has_field 'submit' => ( type => 'Submit', value => 'Update' ); has '+dependency' => ( default => sub { [ ['start_date.month', 'start_date.day', 'start_date.year'] ] } ); has_field 'no_render' => ( widget => 'NoRender' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } sub options_grains { return [ { value => 1, label => 'maize', disabled => 0 }, { value => 2, label => 'rice', disabled => 1 }, { value => 3, label => 'wheat' }, ]; } sub options_cheese { return [ { value => 1, label => 'canastra', disabled => 0 }, { value => 2, label => 'brie', disabled => 1 }, { value => 3, label => 'gorgonzola' }, ]; } sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{class} = 'label' if $type eq 'label'; return $attr; } } my $form = Test::Form->new; ok( $form, 'create form'); my $params = { test_field => 'something', number => 0, fruit => 2, vegetables => [2,4], active => 'now', comments => 'Four score and seven years ago...', hidden => '1234', selected => '1', 'start_date.month' => '7', 'start_date.day' => '14', 'start_date.year' => '2006', two_errors => 'aaa', opt_in => 0, }; $form->process( $params ); is_deeply( $form->field('starch')->input_without_param, [], 'checkbox group settings' ); is( $form->field('starch')->not_nullable, 1, 'checkbox group settings' ); is_deeply( $form->value->{starch}, [], 'checkbox group value' ); is_html( $form->render_field( $form->field('number') ), '
', "value '0' is rendered" ); my $output1 = $form->render_field( $form->field('test_field') ); is_html( $output1, '
', 'output from text field'); my $output2 = $form->render_field( $form->field('fruit') ); is_html( $output2, '
', 'output from select field'); my $output12 = $form->render_field( $form->field('cheese') ); is_html( $output12, '
', 'output from select field with disabled option'); my $output3 = $form->render_field( $form->field('vegetables') ); is_html( $output3, '
', 'output from select multiple field'); my $output13 = $form->render_field( $form->field('grains') ); is_html( $output13, '
', 'output from select multiple field with disabled option'); my $output4 = $form->render_field( $form->field('active') ); is_html( $output4, '
', 'output from checkbox field'); my $output5 = $form->render_field( $form->field('comments') ); is_html( $output5, '
', 'output from textarea' ); my $output6 = $form->render_field( $form->field('hidden') ); is_html( $output6, '
', 'output from hidden field' ); my $output7 = $form->render_field( $form->field('selected') ); is_html( $output7, '
', 'output from boolean' ); my $output8 = $form->render_field( $form->field('start_date') ); is_html( $output8, '
Start date
', 'output from DateTime' ); my $output9 = $form->render_field( $form->field('submit') ); is_html( $output9, '
', 'output from Submit'); my $output10 = $form->render_field( $form->field('opt_in') ); is_html( $output10, '



', 'output from radio group' ); my $output11 = $form->render_start; is_html( $output11, '
', 'Form start OK' ); my $output = $form->render; ok( $output, 'get rendered output from form'); is_html( $form->render_field( $form->field('no_render')), '', 'no_render' ); done_testing; submit.t100644000770000024 115112576552253 17672 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; { package MyApp::Form::SubmitType; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'submit' => ( type => 'Submit', widget => 'ButtonTag', ); } { my $form = MyApp::Form::SubmitType->new; ok( $form ); my $rendered = $form->render; like($rendered, qr/type="submit"/, 'Submit button has type "submit"'); } { my $form = MyApp::Form::SubmitType->new(is_html5 => 1); ok( $form ); my $rendered = $form->render; like($rendered, qr/type="submit"/, 'Submit button has type "submit" for html5'); } done_testing(); withtt.t100644000770000024 1143412576552253 17737 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use File::ShareDir; use HTML::TreeBuilder; use HTML::FormHandler::Test; BEGIN { plan skip_all => 'Install Template Toolkit to test Render::WithTT' unless eval { require Template }; } use_ok('HTML::FormHandler::Render::WithTT'); use_ok('HTML::FormHandler::Render::Simple'); my $dir = File::ShareDir::dist_dir('HTML-FormHandler') . '/templates/'; ok( $dir, 'found template dir' ); { package Test::Form::WithTT::Role; use Moose::Role; with 'HTML::FormHandler::Render::WithTT' => { -excludes => [ 'build_tt_template', 'build_tt_include_path' ] }; sub build_tt_template {'form/form.tt'} sub build_tt_include_path { ['share/templates'] } } { package Test::Form::WithTT::FormInOne::Role; use Moose::Role; with 'HTML::FormHandler::Render::WithTT' => { -excludes => [ 'build_tt_template', 'build_tt_include_path' ] }; sub build_tt_template {'form/form_in_one.tt'} sub build_tt_include_path { ['share/templates'] } } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'submit' => ( type => 'Submit', widget_wrapper => 'None' ); has_field 'foo'; =pod has_field 'bar'; has_field 'fubar' => ( type => 'Compound', widget_wrapper => 'Fieldset', do_wrapper => 1, wrapper_attr => { class => 'fubar' }, ); has_field 'fubar.name'; has_field 'fubar.country'; =cut has_field 'opt_in' => ( type => 'Checkbox', label => 'XXXX', default => 1, tags => { no_wrapped_label => 1 }, ); =pod has_field 'choose' => ( type => 'Select', default => 2 ); has_field 'picksome' => ( type => 'Multiple', default => [1,2] ); has_field 'click' => ( type => 'Button' ); has_field 'reset' => ( type => 'Reset' ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'mememe' => ( type => 'Multiple', widget => 'RadioGroup', default => [2] ); has_field 'notes' => ( type => 'TextArea', cols => 30, rows => 4 ); has_field 'addresses' => ( type => 'Repeatable', widget_wrapper => 'Fieldset', tags => { wrapper_tag => 'fieldset' }, ); has_field 'addresses.street' => ( type => 'Text' ); has_field 'addresses.city' => ( type => 'Text' ); has_field 'pw' => ( type => 'Password' ); =cut has_field 'categories' => ( type => 'Multiple', widget => 'CheckboxGroup', default => [1] ); sub options_choose { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } sub options_picksome { return ( 1 => 'blue', 2 => 'red', 3 => 'orange', ); } sub options_mememe { return ( 1 => 'me', 2 => 'my', 3 => 'mine', ); } sub options_categories { return ( 1 => 'fun', 2 => 'work', 3 => 'boring', ); } sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{id} = 'wr_' . $field->name if $type eq 'wrapper'; return $attr; } } my $rendered_via_tt; { my $form = Test::Form->new_with_traits( traits => ['Test::Form::WithTT::Role'], name => 'test_tt' ); ok( $form, 'form builds' ); ok( $form->tt_include_path, 'tt include path' ); $rendered_via_tt = $form->tt_render; ok($rendered_via_tt, 'form tt renders' ); } my $rendered_via_widget; { my $form = Test::Form->new(name => 'test_tt'); ok( $form, 'form builds' ); $rendered_via_widget = $form->render; ok($rendered_via_widget, 'form simple renders' ); } my $rendered_via_tt_in_one; { my $form = Test::Form->new_with_traits( traits => ['Test::Form::WithTT::FormInOne::Role'], name => 'test_tt' ); ok( $form, 'form builds' ); ok( $form->tt_include_path, 'tt include path' ); $rendered_via_tt_in_one = $form->tt_render; ok($rendered_via_tt_in_one, 'form tt renders' ); } is_html($rendered_via_tt, $rendered_via_widget, 'tt rendering matches widget rendering' ); is_html($rendered_via_tt, $rendered_via_tt_in_one, 'tt rendering matches tt-in-one rendering' ); done_testing; exit; my $tt = HTML::TreeBuilder->new_from_content($rendered_via_tt); my $widget = HTML::TreeBuilder->new_from_content($rendered_via_widget); my $tt_ele = $tt->find_by_attribute('name', 'submit'); my $wt_ele = $widget->find_by_attribute('name', 'submit'); is_html($tt_ele->as_HTML, $wt_ele->as_HTML, "submit matches" ); my @elements = ('foo', 'bar', 'opt_in', 'choose', 'picksome' ); check_elements( "wr_" . $_ ) for @elements; sub check_elements { my $ele = shift; my $tt_ele = $tt->find_by_attribute('id', $ele); my $wt_ele = $widget->find_by_attribute('id', $ele); is_html($tt_ele->as_HTML, $wt_ele->as_HTML, "$ele matches" ); } done_testing; repeatable000755000770000024 012576552253 16671 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tjs.t100644000770000024 466312576552253 17643 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/repeatableuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; # an example of how to setup a form for adding repeatable elements. { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::RepeatableJs'; # Note: if using RepeatableJs, repeatable elements must be # wrapped in a 'controls' div (like the Bootstrap wrapper) # set 'setup_for_js' flag # do_wrapper is turned on by 'setup_for_js' flag has_field 'foo' => ( type => 'Repeatable', setup_for_js => 1, do_wrapper => 1, tags => { controls_div => 1 }, ); # The 'remove' doesn't have to be a display field. It could be other html associated # with the repeatable element wrapper or label. has_field 'foo.remove' => ( type => 'RmElement', value => 'Remove', ); has_field 'foo.one'; has_field 'foo.two'; # 'AddElement' field is right after repeatable field # It also doesn't need to be a display field. Any way to get the correct HTML in is ok. # It requires the name of the repeatable (as accessed from AddElement parent) # The 'value' is the button text. See the AddElement field for requirements. has_field 'add_element' => ( type => 'AddElement', repeatable => 'foo', value => 'Add another foo', ); has_field 'bar'; } my $form = MyApp::Form::Test->new; ok( $form ); ok( $form->has_for_js, 'for_js data is built'); my $js = $form->render_repeatable_js; ok( $js, 'got some javascript' ); my $expected = '
Add another foo
'; my $rendered = $form->field('add_element')->render; is_html( $rendered, $expected, 'add_element rendered ok' ); $expected = '
Remove
'; $rendered = $form->field('foo')->render; is_html( $rendered, $expected, 'repeatable field renders ok' ); done_testing; blocks.t100644000770000024 373512576552253 17715 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/resultuse strict; use warnings; use Test::More; use Test::Exception; { package Test::Form::User; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Widget::Theme::Bootstrap'; has '+item_class' => ( default => 'User' ); sub build_render_list { ['details', 'protect','submit'] } has_field 'first_name' => ( type => 'Text', required => 1, required_message => 'Please enter your first name.', label => 'First name', wrapper_class => ['span5'], ); has_field 'last_name' => ( type => 'Text', required => 1, required_message => 'Please enter your last name.', label => 'First name', wrapper_class => ['span5'], ); has_field 'new_password' => ( type => 'Password', label => 'New Password', required => 1, minlength => 5, wrapper_class => ['span5'], ); has_field 'new_password_conf' => ( type => 'PasswordConf', label => 'New Password (again)', password_field => 'new_password', required => 1, minlength => 5, wrapper_class => ['span10'], ); has_field 'submit' => ( type => 'Submit', value => 'Proceed', element_class => ['btn btn-yellow'] ); has_block 'details' => ( tag => 'fieldset', render_list => ['first_name','last_name'], label => 'Register a new account' ); has_block 'protect' => ( tag => 'fieldset', label => 'Protect your information with a password', render_list => ['new_password', 'new_password_conf'] ); } my $form = Test::Form::User->new; ok( $form ); my $result = $form->run( params => {} ); lives_ok( sub { $result->render; }, 'renders ok' ); done_testing; errors.t100644000770000024 234512576552253 17750 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/resultuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'foo_required' => ( required => 1 ); } my $form = Test::Form->new; ok( $form, 'got form'); my $result = $form->run( params => { foo => 'bar' } ); ok( !$result->validated, 'did not validate' ); ok( $result->field('foo_required')->has_errors, 'foo has error' ); ok( $result->has_errors, 'result has errors' ); is( $result->num_errors, 1, 'number of errors is correct' ); is_deeply( $result->errors_by_name, { foo_required => ['Foo required field is required'] }, 'correct errors_by_name' ); is( $result->errors->[0], 'Foo required field is required', 'result field has error' ); is_html( $result->field('foo_required')->render, '
Foo required field is required
', 'error field has error' ); my @errors = $result->form_and_field_errors; is( scalar @errors, 1, 'one error' ); done_testing; loading.t100644000770000024 233312576552253 20005 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/blocksuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use lib ('t/lib'); use_ok('MyApp::Component::Section'); my $obj = MyApp::Component::Section->new; ok( $obj, 'created section' ); my $rendered = $obj->render; my $expected = '

Please enter the relevant details

'; is_html( $rendered, $expected, 'section rendered standalone' ); { package MyApp::Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform' ); has_block 'section1' => ( type => '+MyApp::Component::Section' ); has_field 'foo'; has_field 'bar'; sub build_render_list { ['section1', 'foo', 'bar'] } } my $form = MyApp::Test::Form->new; ok( $form, 'form built' ); $rendered = $form->render; $expected = '

Please enter the relevant details

'; is_html( $rendered, $expected, 'rendered ok' ); done_testing; compound000755000770000024 012576552253 16411 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 1134012576552253 20036 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/compounduse Test::More; use lib 't/lib'; use_ok( 'HTML::FormHandler::Field::Duration'); use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; my $field = HTML::FormHandler::Field::Duration->new( name => 'duration' ); $field->build_result; ok( $field, 'get compound field'); my $input = { hours => 1, minutes => 2, }; $field->_set_input($input); is_deeply( $field->input, $input, 'field input is correct'); is_deeply( $field->fif, $input, 'field fif is same'); { package Duration::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'name' => ( type => 'Text' ); has_field 'duration' => ( type => 'Duration' ); has_field 'duration.hours' => ( type => 'Nested' ); has_field 'duration.minutes' => ( type => 'Nested' ); } my $form = Duration::Form->new; ok( $form, 'get compound form' ); ok( $form->field('duration'), 'duration field' ); ok( $form->field('duration.hours'), 'duration.hours field' ); my $params = { name => 'Testing', 'duration.hours' => 2, 'duration.minutes' => 30 }; $form->process( params => $params ); ok( $form->validated, 'form validated' ); is_deeply($form->fif, $params, 'get fif with right value'); is( $form->field('duration')->value->hours, 2, 'duration value is correct'); $form->process( params => { name => 'Testing', 'duration.hours' => 'abc', 'duration.minutes' => 'xyz' } ); ok( $form->has_errors, 'form does not validate' ); my @errors = $form->errors; is( $errors[0], 'Invalid value for Duration: Hours', 'correct error message' ); { package Form::Start; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'name' => ( type => 'Text' ); has_field 'start_date' => ( type => 'DateTime' ); has_field 'start_date.month' => ( type => 'Month' ); has_field 'start_date.day' => ( type => 'MonthDay' ); has_field 'start_date.year' => ( type => 'Year' ); sub validate_start_date_month { my ( $self, $field ) = @_; $field->add_error("That month is not available") if( $field->value == 8 ); } } my $dtform = Form::Start->new; ok( $dtform, 'datetime form' ); my $year = (localtime)[5] + 1900; $params = { name => 'DT_testing', 'start_date.month' => '10', 'start_date.day' => '2', 'start_date.year' => $year }; $dtform->process( params => $params ); ok( $dtform->validated, 'form validated' ); is( $dtform->field('start_date')->value->mdy, "10-02-$year", 'datetime value'); $params->{'start_date.month'} = 8; $dtform->process( params => $params ); ok( !$dtform->validated, 'form did not validate' ); ok( $dtform->has_errors, 'form has error' ); @errors = $dtform->errors; is_deeply( $errors[0], 'That month is not available', 'correct error' ); { package Field::MyCompound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'aaa'; has_field 'bbb'; } { package Form::TestValues; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'compound' => ( type => '+Field::MyCompound', apply => [ { check => sub { $_[0]->{aaa} eq 'aaa'}, message => 'Must be "aaa"' } ] ); } $form = Form::TestValues->new; ok( $form, 'Compound form with separate fields declarations created' ); $params = { 'compound.aaa' => 'aaa', 'compound.bbb' => 'bbb', }; $form->process( params => $params ); is_deeply( $form->values, { compound => { aaa => 'aaa', bbb => 'bbb' } }, 'Compound with separate fields - values in hash' ); is_deeply( $form->fif, $params, 'get fif from compound field' ); $form->process( params => { 'compound.aaa' => undef } ); ok( !$form->field( 'compound' )->has_errors, 'Not required compound with empty sub values is not checked'); { package Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'year' => ( type => 'Integer', required => 1, ); has_field 'month' => ( type => 'Integer', range_start => 1, range_end => 12, ); has_field 'day' => ( type => 'Integer', range_start => 1, range_end => 31, ); sub default { return { year => undef, month => undef, day => undef }; } } { package Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'date' => ( type => '+Compound', required => 1 ); has_field 'foo'; } my $f = Form->new; $f->process( { 'date.day' => '18', 'date.month' => '2', 'date.year' => '2010' } ); is_deeply( $f->field('date')->value, { year => 2010, month => 2, day => 18 }, 'correct value' ); $f = Form->new; $f->process( { foo => 'testing' } ); is_deeply( $f->field('date')->value, { year => undef, month => undef, day => undef }, 'correct default' ); done_testing; empty.t100644000770000024 352712576552253 20103 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/compounduse strict; use warnings; use Test::More; # tests behavior for an empty compound field, where the compund field value # is undef { { package MyApp::Test::Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'comp_foo' => ( type => 'Compound', default => { one => 1, two => 2, three => 3 } ); has_field 'comp_foo.one'; has_field 'comp_foo.two'; has_field 'comp_foo.three'; has_field 'bar'; } my $form = MyApp::Test::Compound->new; ok( $form ); my $params = { 'comp_foo.one' => '', 'comp_foo.two' => '', 'comp_foo.three' => '', 'bar' => 'my_bar', }; $form->process( params => $params ); my $value = $form->value; my $exp_value = { comp_foo => undef, bar => 'my_bar', }; is_deeply( $value, $exp_value, 'got expected value' ); } # tests behavior for an empty compound field with 'not_nullable', where the # compund field contains empty values { { package MyApp::Test::Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'comp_foo' => ( type => 'Compound', not_nullable => 1 ); has_field 'comp_foo.one'; has_field 'comp_foo.two'; has_field 'comp_foo.three'; has_field 'bar'; } my $form = MyApp::Test::Compound->new; ok( $form ); my $params = { 'comp_foo.one' => '', 'comp_foo.two' => '', 'comp_foo.three' => '', 'bar' => 'my_bar', }; $form->process( params => $params ); my $value = $form->value; my $exp_value = { comp_foo => { one => undef, two => undef, three => undef, }, bar => 'my_bar', }; is_deeply( $value, $exp_value, 'got expected value' ); } done_testing; field_setup000755000770000024 012576552253 17070 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tid.t100644000770000024 252112576552253 20011 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/field_setupuse strict; use warnings; use Test::More; # test dynamic field ID { package My::DynamicFieldId; use Moose::Role; around 'id' => sub { my $orig = shift; my $self = shift; my $form_name = $self->form->name; return $form_name . "." . $self->full_name; }; } { package My::CustomIdForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'F123' ); has '+html_prefix' => ( default => 1 ); has '+field_traits' => ( default => sub { ['My::DynamicFieldId'] } ); has_field 'foo'; has_field 'bar'; } my $form = My::CustomIdForm->new; is( $form->field('foo')->id, 'F123.foo', 'got correct id' ); # test providing a coderef for field ID building { package MyApp::CustomId; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_update_subfields { { all => { build_id_method => \&custom_id } } } has_field 'foo' => ( type => 'Compound' ); has_field 'foo.one'; has_field 'foo.two'; has_field 'foo.three'; sub custom_id { my $self = shift; my $full_name = $self->full_name; $full_name =~ s/\./_/g; return $full_name; } } $form = MyApp::CustomId->new; ok( $form, 'form built' ); is( $form->field('foo.two')->id, 'foo_two', 'got correct id' ); done_testing; display.t100644000770000024 117612576552253 20032 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; # this tests to make sure that a display field can take a value { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => 'Display', label => undef, required => 0, noupdate => 1 ); has_field 'bar' => ( type => 'Text' ); } my $form = MyApp::Form::Test->new; ok( $form ); my $init_obj = { foo => 'some foo', bar => 'a bar', }; $form->process( init_object => $init_obj, params => {} ); is( $form->field('foo')->value, 'some foo', 'foo field has a value' ); my $rendered = $form->render; done_testing; novalue.t100644000770000024 131012576552253 20024 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar'; has_field 'sbmt' => ( type => 'Submit', value => 'Test', default_method => \&default_submit ); sub default_submit { my $self = shift; my $value = $self->value; $value .= "_from_method"; } } my $form = MyApp::Form::Test->new; ok( $form ); my $expected = '
'; my $rendered = $form->field('sbmt')->render; is_html( $rendered, $expected, 'submit button renders ok' ); done_testing; select2.t100644000770000024 150412576552253 17721 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; { package MyApp::Test; use Moose; with 'HTML::FormHandler::TraitFor::Types'; has 'foo' => ( is => 'rw', isa => 'HFH::SelectOptions', coerce => 1, ); } my $obj = MyApp::Test->new( foo => [ 1 => 'One', 2 => 'Two', 3 => 'Three' ] ); is_deeply( $obj->foo, [ { value => 1, label => 'One' }, { value => 2, label => 'Two' }, { value => 3, label => 'Three' } ], 'value of foo is correct' ); { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => 'Select', options => [ 1 => 'One', 2 => 'Two', 3 => 'Three', ], ); has_field 'bar'; } my $form = MyApp::Form::Test->new; ok( $form ); done_testing; textcsv.t100644000770000024 155312576552253 20064 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; # tests the TextCSV field { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => 'TextCSV' ); has_field 'bar' => ( type => 'TextCSV' ); } my $form = MyApp::Form::Test->new; ok( $form ); my $init_obj = { foo => [1,4,5], bar => ['1,2'] }; $form->process( init_object => $init_obj ); my $fif = $form->fif; is_deeply( $fif, { foo => '1,4,5', bar => '1,2' }, 'fif is correct' ); my $rendered = $form->render; ok( $rendered, 'rendering worked' ); my $params = { foo => '', bar => '1,2' }; $form->process( $params ); $fif = $form->fif; is_deeply( $fif, $params, 'fif ok' ); my $value = $form->value; is_deeply( $value, { foo => undef, bar => [1,2] }, 'right value' ); $rendered = $form->render; ok( $rendered, 'rendering worked' ); done_testing; form_setup000755000770000024 012576552253 16750 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tapi.t100644000770000024 247512576552253 20056 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/form_setupuse strict; use warnings; use Test::More; { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+use_fields_for_input_without_param' => ( default => 1 ); has_field 'foo'; has_field 'bar' => ( default => 2 ); has_field 'moxy'; has_field 'naffy' => ( type => 'Compound' ); has_field 'naffy.one'; has_field 'naffy.two' => ( default => 'two'); } my $form = MyApp::Form::Test->new; ok( $form ); # process with no params $form->process( {} ); my $fif = $form->fif; my $exp_fif = { foo => '', bar => 2, moxy => '', 'naffy.one' => '', 'naffy.two' => 'two', }; is_deeply( $fif, $exp_fif, 'expected fif for non-validated' ); # process with only one param, others from fields my $params = { foo => 1 }; $form->process( $params ); $fif = $form->fif; $exp_fif = { foo => 1, bar => 2, moxy => '', 'naffy.one' => '', 'naffy.two' => 'two', }; is_deeply( $fif, $exp_fif, 'got expected fill-in-form including defaults' ); # moxy && # naffy->{one} are missing because not validated, so not # moved to value. my $value = $form->value; my $val_exp = { foo => 1, bar => 2, moxy => undef, naffy => { one => undef, two => 'two', }, }; is_deeply( $value, $val_exp, 'got expected value' ); done_testing; Test.pm100644000770000024 64312576552253 17636 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/lib/Formpackage Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'TestForm'); has_field 'reqname' => ( type => 'Text', required => 1 ); has_field 'optname' => ( type => 'Text' ); has_field 'fruit' => ( type => 'Select' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } no HTML::FormHandler::Moose; 1; moose000755000770000024 012576552253 15707 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbuild_id.t100644000770000024 441212576552253 20010 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/mooseuse strict; use warnings; use Test::More; use HTML::FormHandler::Field; # This is an example of the different ways to change an attribute of a field. # It uses the 'id' field for demonstration purposes - most of these methods # can also be used against other attributes. { package Test::IDRole; use Moose::Role; sub build_id { my $self = shift; return "meth_role." . $self->html_name; }; } # can't use a simple method role in field_traits because # it's applied against the base field class which contains # the 'build_id' method. a method in a role won't override # a method in a class itself. It *will* override a method in # a superclass, so this kind of role can be applied against # the field subclasses # a method modifier can be used to override a field class # method { package Test::IDRoleMM; use Moose::Role; around 'build_id' => sub { my $orig = shift; my $self = shift; return "mm_role." . $self->html_name; }; } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; # function with lexical variable my $name = 'test_form'; my $create_id = sub { my $field_name = shift; return "$name.$field_name"; }; sub BUILD { my $self = shift; $self->field('tue')->id('my_build.tue'); } has "+name" => ( default => $name ); has_field 'foo' => ( id => 'form.foo' ); has_field 'bar' => ( id => &my_id ); has_field 'dux' => ( traits => ['Test::IDRole'] ); has_field 'pax'; has_field 'mon' => ( id => &$create_id('mon') ); has_field 'tue'; sub my_id { 'my_form.bar' } } HTML::FormHandler::Field->apply_traits('Test::IDRoleMM'); #my $form = Test::Form->new( field_traits => ['Test::IDRole'] ); my $form = Test::Form->new; ok( $form, 'form built' ); is( $form->field('foo')->id, 'form.foo', 'id attribute works' ); is( $form->field('bar')->id, 'my_form.bar', 'id function works' ); is( $form->field('dux')->id, 'meth_role.dux', 'build_id role works' ); is( $form->field('pax')->id, 'mm_role.pax', 'role with meth modifier around build_id works' ); is( $form->field('mon')->id, 'test_form.mon', 'build_id function with var' ); is( $form->field('tue')->id, 'my_build.tue', 'set id in BUILD' ); done_testing; composed.t100644000770000024 264312576552253 20052 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/mooseuse strict; use warnings; use Test::More; { package Test::Composed; use Moose; with 'HTML::FormHandler::Traits'; has 'test' => ( is => 'rw' ); has 'foo' => ( is => 'rw' ); } { package Test::Another; use Moose; with 'HTML::FormHandler::Traits'; has 'another_test' => ( is => 'rw' ); } { package Test::Trait::One; use Moose::Role; has 'test_one' => ( is => 'rw' ); } { package Test::Trait::Two; use Moose::Role; has 'test_two' => ( is => 'rw' ); } my $class = Test::Composed->with_traits( 'Test::Trait::One', 'Test::Trait::Two' ); is( $class, 'Test::Composed::1', 'got class' ); my $obj1 = $class->new( test_one => 1, test_two => 2 ); ok( $obj1, 'constructed an instance' ); is( $obj1->test_one, 1, 'right value' ); $class = Test::Composed->with_traits( 'Test::Trait::Two' ); is( $class, 'Test::Composed::2', 'got a class' ); my $obj2 = $class->new( test_two => 3 ); ok( $obj2, 'constructed an instance' ); is( $obj2->test_two, 3, 'right value' ); $class = Test::Another->with_traits( 'Test::Trait::One' ); is( $class, 'Test::Another::3', 'right class name' ); my $obj3 = $class->new( 'another_test' => 1 ); is( $obj3->another_test, 1, 'instance ok' ); my $obj4 = Test::Another->new_with_traits( traits => ['Test::Trait::Two'], test_two => 'foo' ); is( $obj4->test_two, 'foo', 'instantiated ok' ); is( $obj4->meta->name, 'Test::Another::4', 'named ok' ); done_testing; actions.t100644000770000024 207512576552253 20035 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'action_form' ); has_field 'foo'; has_field 'actions' => ( type => 'Compound', do_wrapper => 1 , do_label => 0, wrapper_class => 'form-actions' ); has_field 'actions.save' => ( type => 'Submit', widget_wrapper => 'None' ); has_field 'actions.cancel' => ( type => 'Reset', widget_wrapper => 'None' ); } my $form = Test::Form->new; $form->process; my $rendered = $form->render; my $expected = '
'; is_html($rendered, $expected, 'actions render ok' ); done_testing; classes.t100644000770000024 617312576552253 20035 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form::Theme; use Moose::Role; sub build_form_tags {{ form_tag => 1, }} sub build_update_subfields {{ all => { tags => { some_tag => 1, field_tag => 0 } }, foo => { element_class => ['interesting'] } }} } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'Test::Form::Theme'; has_field 'foo' => ( element_class => ['fld_def'] ); has_field 'bar' => ( tags => { field_tag => 1 } ); has_field 'rox' => ( wrapper_class => 'frmwrp' ); } my $form = Test::Form->new; ok( $form ); my $element_class = $form->field('foo')->element_class; is_deeply( $element_class, ['interesting', 'fld_def'], 'got both classes' ); is_deeply( $form->field('rox')->tags, { some_tag => 1, field_tag => 0 }, 'correct widget tags' ); is_deeply( $form->field('bar')->tags, { some_tag => 1, field_tag => 1 }, 'correct widget tags' ); { package Test::ClassForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'hfhform' ); sub build_update_subfields {{ all => { wrapper_class => 'hfh' } }} has_field 'foo'; has_field 'bar'; has_field 'nox'; } $form = Test::ClassForm->new; $form->process; is_deeply( $form->field('foo')->wrapper_class, ['hfh'], 'foo has class' ); is_deeply( $form->field('bar')->wrapper_class, ['hfh'], 'bar has class' ); is_deeply( $form->field('nox')->wrapper_class, ['hfh'], 'nox has class' ); my $rendered = $form->render; my $expected = '
'; is_html( $rendered, $expected, 'rendered correctly' ); { package Test::ElementClassField; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Text'; sub build_element_class { ['foo'] } } { package Test::ElementClassForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => '+Test::ElementClassField', element_class => 'bar', ); # Note: all => { element_class => 'baz' } does not # override the specific setting on the field. This is # deliberate. The idea is that the more specific setting # should override the general setting. Like all of these things, # sometimes people are going to want it one way and sometimes the # other. If you want to set the element_class for all elements # at once, don't put a specific element_class on the field. sub build_update_subfields { { foo => { element_class => 'baz' }, } }; } $form = Test::ElementClassForm->new; $form->process; is_deeply( $form->field('foo')->element_class, [qw( baz )], 'foo has correct classes' ); done_testing; display.t100644000770000024 401312576552253 20034 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Field::Rendering; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'my_html' => ( type => 'Display', html => '

You got here!

' ); has_field 'explanation' => ( type => 'Display' ); has_field 'between' => ( type => 'Display', set_html => 'between_html' ); has_field 'nolabel' => ( type => 'Text', do_label => 0 ); sub html_explanation { my ( $self, $field ) = @_; return "

I have an explanation somewhere around here...

"; } sub between_html { my ( $self, $field ) = @_; return "
Somewhere, over the rainbow...
"; } } my $form = Test::Field::Rendering->new; is_html( $form->field('my_html')->render, '

You got here!

', 'display field renders with html attribute' ); is_html( $form->field('explanation')->render, '

I have an explanation somewhere around here...

', 'display field renders with form method' ); is_html( $form->field('between')->render, '
Somewhere, over the rainbow...
', 'set_html field renders' ); is_html( $form->field('nolabel')->render, '
', 'do_label => 0 works'); # test render_method { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar' => ( type => 'Display', render_method => \&render_bar, ); sub render_bar { my $self = shift; # $self is field my $name = $self->name; return "

This is field $name!

"; } has_field 'moy' => ( type => 'Display', html => '

From the html attribute...

', ); } $form = MyApp::Form::Test->new; my $rendered = $form->render; ok( $rendered, 'it rendered' ); like( $rendered, qr/This is field bar/, 'rendered from render_method' ); like( $rendered, qr/From the html attribute/, 'rendered from html attribute' ); done_testing; get_tag.t100644000770000024 146712576552253 20013 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::MyTags; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'testform' ); has_field 'foo' => ( tags => { after_element => \&help_text } ); has_field 'bar'; sub help_text { my $self = shift; my $label = $self->label; return qq{$label is most important>}; } } my $form = MyApp::Form::MyTags->new; $form->process; my $rendered = $form->field('foo')->render; my $expected = '
Foo is most important>
'; is_html( $rendered, $expected, 'foo field rendered correctly' ); done_testing; widgets.t100644000770000024 2005612576552253 20062 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use lib 't/lib'; use HTML::FormHandler::Field::Text; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_do_form_wrapper {1} sub build_update_subfields {{ by_flag => { compound => { do_wrapper => 1, do_label => 1 }, repeatable => { do_wrapper => 1, do_label => 1 }, }, }} sub build_form_wrapper_class { 'form_wrapper' } has '+name' => ( default => 'testform' ); has_field 'test_field' => ( size => 20, label => 'TEST', id => 'f99', element_class => 'test123', ); has_field 'number'; has_field hobbies => ( type => 'Repeatable', num_when_empty => 1, ); has_field 'hobbies.contains' => ( type => 'Text', tabindex => 2, ); has_field 'active' => ( type => 'Checkbox' ); has_field 'comments' => ( type => 'TextArea', cols => 40, rows => 3 ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'selected' => ( type => 'Boolean' ); has_field 'start_date' => ( type => 'DateTime', tags => { wrapper_tag => 'fieldset' } ); has_field 'start_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'start_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); has_field 'start_date.year' => ( type => 'Integer', range_start => 2000, range_end => 2020 ); has_field 'two_errors' => ( apply => [ { check => [], message => 'First constraint error' }, { check => [], message => 'Second constraint error' } ] ); has_field 'submit' => ( type => 'Submit', value => '>>> Update' ); has_field 'reset' => ( type => 'Reset', value => '<<< Reset' ); has '+dependency' => ( default => sub { [ [ 'start_date.month', 'start_date.day', 'start_date.year' ] ]; } ); has_field 'no_render' => ( widget => 'NoRender' ); has_field 'plain' => ( widget_wrapper => 'None' ); has_field 'boxed' => ( widget_wrapper => 'Fieldset', wrapper_attr => { class => 'boxed' } ); has_field 'element_wrapper_field' => ( element_wrapper_class => 'large' ); sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{class} = 'label' if $type eq 'label'; return $attr; } } my $form = Test::Form->new; ok( $form, 'create form' ); my $expected = '
Hobbies
'; is_html( $form->field('hobbies')->render, $expected, 'output from repeatable with num_when_empty == 1' ); my $params = { test_field => 'something', number => 0, active => 'now', comments => 'Four score and seven years ago...', hidden => '1234', selected => '1', 'start_date.month' => '7', 'start_date.day' => '14', 'start_date.year' => '2006', two_errors => 'aaa', plain => 'No divs!!', hobbies => [ 'eating', 'sleeping', 'not chasing mice' ], boxed => 'Testing single fieldset', }; $form->process($params); is_html( $form->field('number')->render, '
', "value '0' is rendered" ); my $rendered = $form->field('test_field')->render; is_html( $rendered, '
', 'output from text field' ); $rendered = $form->field('test_field')->render_element; is_html( $rendered, '', 'output from render_element is correct' ); $expected = '
'; is_html( $form->field('active')->render, $expected, 'output from checkbox field'); $rendered = $form->field('comments')->render; is_html( $rendered, '
', 'output from textarea' ); $rendered = $form->field('hidden')->render; is_html( $rendered, '
', 'output from hidden field' ); $rendered = $form->field('selected')->render; is_html( $rendered, '
', 'output from boolean' ); $rendered = $form->field('start_date')->render; is_html( $rendered, '
Start date
', 'output from DateTime' ); $rendered = $form->field('submit')->render; is_html( $rendered, '
', 'output from Submit' ); $rendered = $form->field('reset')->render; is_html( $rendered, '
', 'output from Reset' ); $rendered = $form->render_start; is_html( $rendered, '
', 'Form start OK' ); $rendered = $form->field('hobbies')->render; is_html( $rendered, '
Hobbies
', 'output from repeatable after processing result with 3 items' ); is( $form->field('no_render')->render, '', 'no_render' ); is_html( $form->field('plain')->render, '', 'renders without wrapper'); is_html( $form->field('boxed')->render, '
Boxed
', 'fieldset wrapper renders' ); is_html( $form->field('element_wrapper_field')->render, '
', 'element wrapper renders ok' ); # table widget $form = Test::Form->new( widget_form => 'Table', widget_wrapper => 'Table' ); like( $form->render, qr/
field('number')->render, qr/'; } elsif ( $l_type eq 'legend' ) { $output .= ''; } if ( $l_type ne 'legend' ) { $output .= '\n"; } return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Render::Table - render a form with a table layout =head1 VERSION version 0.40064 =head1 SYNOPSIS Include this role in a form: package MyApp::Form::User; use Moose; with 'HTML::FormHandler::Render::Table'; Use in a template: [% form.render %] =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Widget000755000770000024 012576552253 21260 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandlerBlock.pm100644000770000024 1217612576552253 23037 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widgetpackage HTML::FormHandler::Widget::Block; # ABSTRACT: base block renderer use Moose; with 'HTML::FormHandler::TraitFor::Types'; use HTML::FormHandler::Render::Util ('process_attrs'); use HTML::FormHandler::Field; has 'name' => ( is => 'ro', isa => 'Str', required => 1 ); has 'form' => ( is => 'ro', isa => 'HTML::FormHandler', required => 1, weak_ref => 1, ); has 'class' => ( is => 'rw', isa => 'HFH::ArrayRefStr', traits => ['Array'], builder => 'build_class', handles => { has_class => 'count', add_class => 'push', } ); sub build_class { [] } has 'attr' => ( is => 'rw', traits => ['Hash'], builder => 'build_attr', handles => { has_attr => 'count', set__attr => 'set', delete__attr => 'delete' }, ); sub build_attr { {} } has 'wrapper' => ( is => 'rw', isa => 'Bool', default => 1 ); has 'tag' => ( is => 'rw', isa => 'Str', default => 'div' ); has 'label' => ( is => 'rw', isa => 'Str', predicate => 'has_label' ); has 'label_tag' => ( is => 'rw', isa => 'Str' ); has 'label_class' => ( is => 'rw', isa => 'HFH::ArrayRefStr', traits => ['Array'], builder => 'build_label_class', handles => { has_label_class => 'count', add_label_class => 'push', } ); sub build_label_class { [] } has 'render_list' => ( is => 'rw', isa => 'ArrayRef[Str]', traits => ['Array'], builder => 'build_render_list', handles => { has_render_list => 'count', add_to_render_list => 'push', all_render_list => 'elements', get_render_list => 'get', } ); sub build_render_list { [] } has 'content' => ( is => 'rw' ); has 'after_plist' => ( is => 'rw' ); sub render { my ( $self, $result ) = @_; $result ||= $self->form->result; my $start_wrapper = ''; my $end_wrapper = ''; if( $self->wrapper ) { my $tag = $self->tag; # create attribute string my $attr_str = $self->render_attribute_string; $start_wrapper = qq{<$tag$attr_str>}; $end_wrapper = qq{}; } # get rendering of contained fields, if any my $rendered_fb = $self->render_from_list($result); my $content = $self->content || ''; my $after_plist = $self->after_plist || ''; # create label my $label = $self->render_label; my $block = qq{\n$start_wrapper$label$content$rendered_fb$after_plist$end_wrapper}; } sub render_attribute_string { my $self = shift; my $attr = { %{ $self->attr } }; $attr->{class} = $self->class if $self->has_class; my $attr_str = process_attrs($attr); return $attr_str; } sub render_label { my $self = shift; my $label = ''; if ( $self->has_label ) { my $label_tag = $self->label_tag || 'span'; $label_tag = 'legend' if lc $self->tag eq 'fieldset'; my $label_str = $self->form->_localize( $self->label ); my $attr_str = ''; $attr_str = process_attrs( { class => $self->label_class } ) if $self->has_label_class; $label = qq{<$label_tag$attr_str>$label_str}; } return $label; } sub render_from_list { my ( $self, $result ) = @_; my $output = ''; if ( $self->has_render_list ) { foreach my $fb ( @{ $self->render_list } ) { # it's a Field if ( $self->form->field_in_index($fb) ) { # find field result and use that my $fld_result = $result->get_result($fb); # if no result, then we shouldn't be rendering this field next unless $fld_result; $output .= $fld_result->render; } # it's a Block else { # block can't be called from a field, so this should # always be the for result my $block = $self->form->block($fb); die "found no form field or block named '$fb'\n" unless $block; $output .= $block->render($result); } } } # else nothing to render from render_list return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Block - base block renderer =head1 VERSION version 0.40064 =head1 SYNOPSIS Base block renderer to be used with L. has_block 'my_fieldset' => ( tag => 'fieldset', render_list => ['bar'], label => 'My Special Bar' ); =head1 ATTRIBUTES =over 4 =item render_list List of names of objects to render (fields and blocks) =item tag HTML tag for this block. Default 'div'. =item class Arrayref of classes for the HTML element. =item attr Other attributes for the HTML element. =item label_tag Tag to use for the label. Default: 'span'; default for 'fieldset' is 'legend'. =item label_class Classes for the label. =item label Label string. Will be localized. =back =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut radio_group.tt100644000770000024 42012576552253 23504 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/share/templates/field[% FOR option IN f.options -%] [% END -%] Boolean.pm100644000770000024 161012576552253 23133 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Boolean; # ABSTRACT: a true or false field use Moose; extends 'HTML::FormHandler::Field::Checkbox'; our $VERSION = '0.03'; sub value { my $self = shift; my $v = $self->next::method(@_); return $v ? 1 : 0; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Boolean - a true or false field =head1 VERSION version 0.40064 =head1 DESCRIPTION This field returns 1 if true, 0 if false. The widget type is 'Checkbox'. Similar to Checkbox, except only returns values of 1 or 0. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Captcha.pm100644000770000024 664412576552253 23133 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Captcha; # ABSTRACT: captcha field with GD::SecurityImage use Moose; extends 'HTML::FormHandler::Field'; use HTTP::Date; has 'height' => ( isa => 'Int', is => 'rw', default => '20' ); has 'width' => ( isa => 'Int', is => 'rw', default => '80' ); has 'scramble' => ( isa => 'Int', is => 'rw', default => '0' ); has 'lines' => ( isa => 'Int', is => 'rw', default => '2' ); has 'gd_font' => ( isa => 'Str', is => 'rw', default => 'Large' ); has 'image' => ( is => 'rw' ); has '+wrapper_class' => ( default => 'captcha' ); has '+widget' => ( default => 'Captcha' ); has '+noupdate' => ( default => 1 ); our $class_messages = { 'captcha_verify_failed' => 'Verification incorrect. Try again.', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } sub get_default_value { my $self = shift; my $captcha = $self->form->get_captcha; # setting the widget after the field is instantiated # doesn't actually work. The Captcha widget checks for # this setting though. if ($captcha) { if ( $captcha->{validated} ) { $self->required(0); $self->widget('NoRender'); } else { $self->required(1); $self->widget('Captcha'); $self->image( $captcha->{image} ); } } else { $self->required(1); $self->widget('Captcha'); $self->gen_captcha; } return; } sub validate { my $self = shift; my $captcha = $self->form->get_captcha; unless ( $captcha->{rnd} eq $self->value ) { $self->add_error($self->get_message('captcha_verify_failed')); $self->gen_captcha; } else { $captcha->{validated} = 1; } return !$self->has_errors; } sub fif { } sub gen_captcha { my $self = shift; require GD::SecurityImage; my ( $image, $type, $rnd ) = GD::SecurityImage->new( height => $self->height, width => $self->width, scramble => $self->scramble, lines => $self->lines, gd_font => $self->gd_font, )->random->create->out; my $captcha = { image => $image, type => $type, rnd => $rnd, validated => 0, }; $self->image($image); $self->form->set_captcha($captcha); } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Captcha - captcha field with GD::SecurityImage =head1 VERSION version 0.40064 =head1 SYNOPSIS A Captcha class using GD::SecurityImage. Requires that three methods be available from a form object: $self->form->get_captcha; $self->form->set_captcha; Using Catalyst and the Catalyst session plugin this field can be used in a form by using L. package MyApp::Form::Post; use HTML::FormHandler::Moose; with 'HTML::FormHandler::TraitFor::Captcha'; You can set the following attributes on the 'captcha' field: height, width, scramble, lines, gd_font Example: has 'captcha' => ( height => '24', width => '70' ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DateMDY.pm100644000770000024 150112576552253 23002 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::DateMDY; # ABSTRACT: m/d/y date field use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Date'; has '+format' => ( default => '%m/%d/%Y' ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::DateMDY - m/d/y date field =head1 VERSION version 0.40064 =head1 SYNOPSIS For date fields in the format nn/nn/nnnn. This simply inherits from L and sets the format to "%m/%d/%Y". =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Display.pm100644000770000024 533012576552253 23164 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Display; # ABSTRACT: display only field use Moose; extends 'HTML::FormHandler::Field::NoValue'; use namespace::autoclean; has 'html' => ( is => 'rw', isa => 'Str', builder => 'build_html', lazy => 1 ); sub build_html {''} has 'set_html' => ( isa => 'Str', is => 'ro'); has '+do_label' => ( default => 0 ); has 'render_method' => ( traits => ['Code'], is => 'ro', isa => 'CodeRef', lazy => 1, predicate => 'does_render_method', handles => { 'render' => 'execute_method' }, builder => 'build_render_method', ); sub build_render_method { my $self = shift; my $set_html = $self->set_html; $set_html ||= "html_" . HTML::FormHandler::Field::convert_full_name($self->full_name); return sub { my $self = shift; $self->form->$set_html($self); } if ( $self->form && $self->form->can($set_html) ); return sub { my $self = shift; return $self->html; }; } sub _result_from_object { my ( $self, $result, $value ) = @_; $self->_set_result($result); $self->value($value); $result->_set_field_def($self); return $result; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Display - display only field =head1 VERSION version 0.40064 =head1 SYNOPSIS This class can be used for fields that are display only. It will render the value returned by a form's 'html_' method, or the field's 'html' attribute. has_field 'explanation' => ( type => 'Display', html => '

This is an explanation...

' ); or in a form: has_field 'explanation' => ( type => 'Display' ); sub html_explanation { my ( $self, $field ) = @_; if( $self->something ) { return '

This type of explanation...

'; } else { return '

Another type of explanation...

'; } } #---- has_field 'username' => ( type => 'Display' ); sub html_username { my ( $self, $field ) = @_; return '
User: ' . $field->value . '
'; } or set the name of the rendering method: has_field 'explanation' => ( type => 'Display', set_html => 'my_explanation' ); sub my_explanation { .... } or provide a 'render_method': has_field 'my_button' => ( type => 'Display', render_method => \&render_my_button ); sub render_my_button { my $self = shift; .... return '...'; } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Integer.pm100644000770000024 333212576552253 23154 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Integer; # ABSTRACT: validate an integer value use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Text'; our $VERSION = '0.02'; has '+size' => ( default => 8 ); has '+html5_type_attr' => ( default => 'number' ); our $class_messages = { 'integer_needed' => 'Value must be an integer', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } apply( [ { transform => sub { my $value = shift; $value =~ s/^\+//; return $value; } }, { check => sub { $_[0] =~ /^-?[0-9]+$/ }, message => sub { my ( $value, $field ) = @_; return $field->get_message('integer_needed'); }, } ] ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Integer - validate an integer value =head1 VERSION version 0.40064 =head1 DESCRIPTION This accepts a positive or negative integer. Negative integers may be prefixed with a dash. By default a max of eight digits are accepted. Widget type is 'text'. If form has 'is_html5' flag active it will render instead of type="text" The 'range_start' and 'range_end' attributes may be used to limit valid numbers. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut NoValue.pm100644000770000024 335612576552253 23136 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::NoValue; # ABSTRACT: base class for submit field use Moose; extends 'HTML::FormHandler::Field'; has 'html' => ( is => 'rw', isa => 'Str', default => '' ); has 'value' => ( is => 'rw', predicate => 'has_value', clearer => 'clear_value', ); sub _result_from_fields { my ( $self, $result ) = @_; my $value = $self->get_default_value; if ( $value ) { $self->value($value); } $self->_set_result($result); $result->_set_field_def($self); return $result; } sub _result_from_input { my ( $self, $result, $input, $exists ) = @_; $self->_set_result($result); $result->_set_field_def($self); return $result; } sub _result_from_object { my ( $self, $result, $value ) = @_; $self->_set_result($result); $result->_set_field_def($self); return $result; } sub fif { } has '+widget' => ( default => '' ); has '+noupdate' => ( default => 1 ); sub validate_field { } #sub clear_value { } sub render { my $self = shift; return $self->html; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::NoValue - base class for submit field =head1 VERSION version 0.40064 =head1 SYNOPSIS This is the base class for the Submit & Reset fields. It can be used for fields that do not produce valid 'values'. It should not be used for fields that produce a value or need validating. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut TextCSV.pm100644000770000024 335212576552253 23061 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::TextCSV; # ABSTRACT: CSV Text field from multiple use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Text'; has '+deflate_method' => ( default => sub { \&textcsv_deflate } ); has '+inflate_method' => ( default => sub { \&textcsv_inflate } ); has 'multiple' => ( isa => 'Bool', is => 'rw', default => '0' ); sub build_value_when_empty { [] } sub _inner_validate_field { my $self = shift; my $value = $self->value; return unless $value; if ( ref $value ne 'ARRAY' ) { $value = [$value]; $self->_set_value($value); } } sub textcsv_deflate { my ( $self, $value ) = @_; if( defined $value && length $value ) { my $value = ref $value eq 'ARRAY' ? $value : [$value]; my $new_value = join(',', @$value); return $new_value; } return $value; } sub textcsv_inflate { my ( $self, $value ) = @_; if ( defined $value && length $value ) { my @values = split(/,/, $value); return \@values; } return $value; } __PACKAGE__->meta->make_immutable; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::TextCSV - CSV Text field from multiple =head1 VERSION version 0.40064 =head1 SYNOPSIS A text field that takes multiple values from a database and converts them to comma-separated values. This is intended for javascript fields that require that, such as 'select2'. =head1 NAME HTML::FormHandler::Field::TextCSV =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Weekday.pm100644000770000024 173012576552253 23150 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Weekday; # ABSTRACT: select list day of week strings use Moose; extends 'HTML::FormHandler::Field::Select'; our $VERSION = '0.01'; sub build_options { my $i = 0; my @days = qw/ Sunday Monday Tuesday Wednesday Thursday Friday Saturday /; return [ map { { value => $i++, label => $_ } } @days ]; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Weekday - select list day of week strings =head1 VERSION version 0.40064 =head1 DESCRIPTION Creates an option list for the days of the week. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Manual000755000770000024 012576552253 21252 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandlerIntro.pod100644000770000024 2533412576552253 23240 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Intro; # ABSTRACT: introduction to using FormHandler __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Intro - introduction to using FormHandler =head1 VERSION version 0.40064 =head1 SYNOPSIS L HTML::FormHandler is a form handling package that validates HTML form data and, for database forms, saves it to the database on validation. It has field classes that match various data types and HTML form elements, and rendering roles that can be used to render forms in many different ways, from hand-built forms to totally automated rendering. It can, of course, be used to validate data even if you are not interested in the rendering capabilities. A FormHandler 'form' is a Perl subclass of L for non-database forms, or a subclass of L for database forms, and in it you define your fields and validation routines. Because it's a Perl class written in Moose, you have a lot of flexibility and control. You can validate with Perl methods or Moose type constraints; you can use your own validation libraries. You can define your own field classes that perform specialized validation. When the form is validated, you can get the validated values back with C<< $form->value >>. A working example of a Catalyst app using FormHandler forms is available on github at L. =head1 Basics =head2 Create a form class The most common way of using FormHandler is to create a form package. You must 'use' "HTML::FormHandler::Moose" and 'extend' FormHandler: package MyApp::Form::Sample; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; Then you add some fields with 'has_field', and a field 'type' (the short name of the field package). (Fields with no type have type 'Text'.) has_field 'foo'; has_field 'bar' => ( type => 'Select' ); Basic field types are Text, Select, Checkbox, Submit, Hidden, Reset, TextArea, Password, Upload. See L for more information. =head2 Or create a form class dynamically You can also create a form class 'dynamically', by creating a 'new' HTML::FormHandler object. Use a 'field_list' parameter to create the fields instead of 'has_field'. my $form = HTML::FormHandler->new( field_list => [ 'username' => { type => 'Text' }, 'selections' => { type => 'Select' }, ] ); Some features will not be available using this method (like the automatic use of 'validate_' methods) and it's not as easy to test, of course. =head2 Process the form The form's 'process' method should be run on each request, passing in the request parameters: $form->process( params => $c->request->body_parameters, action => $action, ); If the parameters are not empty, then validation will be performed. The corollary is that you should not pass in extra parameters when the form has not been posted. A special 'posted' flag can be used if the form consists entirely of fields like checkboxes that do not include names in params if unchecked, and also works to prevent validation from being performed if there are extra params: $form->process( posted => ( $c->req->method eq 'POST' ), params => $c->request->parameters, action => $action ); There is an alternative method for processing the form, which is sometimes preferred for persistent forms. It returns a 'result' object, and clears the form: my $result = $form->run( params => $c->request->body_parameters ); You can also set most other FormHandler attributes on the 'process' call., One useful feature is that you can activate or inactivate fields: $form->process( params => $params, active => ['field1', 'field2'] ); See also L. =head2 Or process a database form A database form inherits from L instead of L. You must either pass in the DBIC row object or give FormHandler information to retrieve the row object. $form->process( item => $row, params => $params ); -- or -- $form->process( item_id => $id, schema => $schema, item_class => 'MyRow', params => $params ); 'item_class' is often set in the form class. See also L and L. =head2 After processing the form A database form will have saved the data or created a new row, so often no more processing is necessary. You can get the structured field values from C<< $form->value >>, and do whatever you want with them. If the validation succeeded, you may want to redirect: $form->process( params => $params ); return unless $form->validated $c->res->redirect( .... ); -- or -- return unless $form->process( params => params ); $c->res->redirect; =head2 Rendering the form At its simplest, all you need to do is C<< $form->render >> in a template. [% form.render %] The automatic rendering is powerful and flexible -- you can do almost anything with the right settings. Or you can render the form with a template. The form object will give you a hashref of values suitable for filling in the form with C<< $form->fif >>. By default FormHandler structures fields (and renders them) in a way that matches the database. If you want to organize the rendering output in different ways, you can use blocks to organize your fields. has_block 'fieldset1' => ( render_list => ['foo', 'bar'] ); For more rendering info, see L. =head2 Defaults for form fields The simplest way to provide defaults is by setting the default attribute in a field definition: has_field 'my_foo' => ( default => 'my_foo' ); The database row ('item') that is passed in will provide initial values for the form, of course. You can also provide default values with an 'init_object', which acts kind of like a database object: $form->process( init_object => { foo => '...', bar => '...' } ); There are a number of other flags and methods for providing defaults. See L. =head2 Validation You can validate a field with a method in the form 'validate_': has_field 'foo'; sub validate_foo { my ( $self, $field ) = @_; # self is the form unless( $field->value == .... ) { $field->add_error( .... ); } } You can provide a validation coderef that will be a field method: has_field 'foo' => ( validate_method => \&check_foo ); sub check_foo { my $self = shift; # self is field unless( $self->value == ... ) { $self->add_error( ... ); } } You can use 'apply' to use Moose types for validation, from L or another Moose type collection: use HTML::FormHandler::Types ('NotAllDigits'); ... has_field 'my_field' => ( apply => [NotAllDigits] ); Or create validators with check: has_field 'quux' => ( apply => [ { check => qr/abc/, message => 'Not a valid quux' } ] ); Or use a validate coderef: has_field 'foo' => ( validate_method => \&check_foo ); sub check_foo { my $self = shift; if ( $self->value =~ s/..../ ) { $self->add_error('....'); } } You can also create custom fields with custom validation, or use an existing field that does the validation you need. See L for more information on validation or L for more information on fields. =head2 Organizing your form code You can use 'has_field' and 'has_block' in Moose roles: package MyApp::Form::Role::Address; use HTML::FormHandler::Moose::Role; has_field 'foo'; has_block 'bar'; Your forms can inherit from base classes that set common application defaults. You can override field definitions with '+'. You can create 'compound' fields and include them in a form: package MyApp::Form::Field::Complex; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'field1' => ( validate_method => \&validate_field1 ); has_field 'field2' => ( type => 'Select', options_method => \&options_field2 ); sub validate_field1 { ... } sub options_field2 { ... } ... package MyApp::Form::Complex; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+field_name_space' => ( sub => {['MyApp::Form::Field']} ); has_field 'compound1' => ( type => 'Complex' ); has_field 'compound2' => ( type => 'Complex' ); =head2 Testing It's much easier to write unit tests for FormHandler forms than for Catalyst controllers. The 't' directory of the downloaded distribution has lots of examples. See L for more information. =head1 Localization FormHandler's built-in errors are added to the form fields with C<< $field->add_error >>, and to the form with C<< $form->add_form_error >>. These methods call a C<< $self->_localize >> method which is a coderef set from the field's default_localize sub, the field's 'localize_meth' attribute with C<< localize_meth => sub {} >>, or a form's sub localize_meth. The default localize uses Locale::Maketext. You can also use duck_type classes for localization. See the documentation in L and the tests in xt/locale.t. If you wish to skip localization for a particular message (such as for system errors) you can use C<< $field->push_errors >> or C<< $form->push_form_errors >>. See also L. =head1 Performance FormHandler makes heavy use of Moose, so almost all of FormHandler's profiled time will actually be in Moose methods, mostly constructing form and field attributes. Some people prefer to use a persistent form class (in a Moose attribute) in order to skip the form building step on each call. Other people don't like that solution because state will remain in the form until the next process call. The 'clear' method is called at the beginning of each 'process', but additional Moose attributes in the form, etc, will have to cleared by the programmer. If you are loading options from the database and you don't need to have them refreshed each time, you can set the 'do_not_reload' flag in the Select/Multiple field. If you're not using the field widget roles, you can set the 'no_widgets' flag. If you always use 'process' on each call (recommended) then you can set the 'no_preload' flag in the form to skip building results in BUILD (new). =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Simple.pm100644000770000024 2767512576552253 23244 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Renderpackage HTML::FormHandler::Render::Simple; # ABSTRACT: simple rendering role use Moose::Role; requires( 'sorted_fields', 'field' ); use HTML::FormHandler::Render::Util ('process_attrs', 'ucc_widget'); our $VERSION = 0.01; sub render { my $self = shift; my $output = $self->render_start; $output .= $self->render_form_errors; foreach my $field ( $self->sorted_fields ) { $output .= $self->render_field($field); } $output .= $self->render_end; return $output; } sub render_form_errors { my $self = shift; return '' unless $self->has_form_errors; my $output = "\n
"; $output .= qq{\n$_} for $self->all_form_errors; $output .= "\n
"; return $output; } sub render_field { my ( $self, $field ) = @_; if ( ref( \$field ) eq 'SCALAR' ) { $field = $self->field($field); } die "must pass field to render_field" unless ( defined $field && $field->isa('HTML::FormHandler::Field') ); # widgets should be in camel case, since they are Perl package names my $widget = ucc_widget($field->widget); return '' if $widget eq 'no_render'; my $rendered_field; my $form_render = 'render_' . $widget; if ( $self->can($form_render) ) { $rendered_field = $self->$form_render($field); } elsif ( $field->can('render') ) { $rendered_field = $field->render; } else { die "No widget method found for '$widget' in H::F::Render::Simple"; } return $self->wrap_field( $field, $rendered_field ); } sub wrap_field { my ( $self, $field, $rendered_field ) = @_; return "\n$rendered_field" if $field->uwrapper eq 'none'; return "\n$rendered_field" if ! $field->do_wrapper; my $output = "\n"; my $wrapper_tag = $field->get_tag('wrapper_tag'); $wrapper_tag ||= $field->has_flag('is_repeatable') ? 'fieldset' : 'div'; my $attrs = process_attrs($field->wrapper_attributes); $output .= qq{<$wrapper_tag$attrs>}; if( $wrapper_tag eq 'fieldset' ) { $output .= '' . $field->loc_label . ''; } elsif ( ! $field->get_tag('label_none') && $field->do_label && length( $field->label ) > 0 ) { $output .= "\n" . $self->render_label($field); } $output .= "\n$rendered_field"; $output .= qq{\n$_} for $field->all_errors; $output .= "\n"; return "$output"; } sub render_text { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= ' size="' . $field->size . '"' if $field->size; $output .= ' maxlength="' . $field->maxlength . '"' if $field->maxlength; $output .= ' value="' . $field->html_filter($field->fif) . '"'; $output .= process_attrs($field->element_attributes); $output .= ' />'; return $output; } sub render_password { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= ' size="' . $field->size . '"' if $field->size; $output .= ' maxlength="' . $field->maxlength . '"' if $field->maxlength; $output .= ' value="' . $field->html_filter($field->fif) . '"'; $output .= process_attrs($field->element_attributes); $output .= ' />'; return $output; } sub render_hidden { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= ' value="' . $field->html_filter($field->fif) . '"'; $output .= process_attrs($field->element_attributes); $output .= ' />'; return $output; } sub render_select { my ( $self, $field ) = @_; my $multiple = $field->multiple; my $id = $field->id; my $output = ''; return $output; } sub render_checkbox { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= ' value="' . $field->html_filter($field->checkbox_value) . '"'; $output .= ' checked="checked"' if $field->fif eq $field->checkbox_value; $output .= process_attrs($field->element_attributes); $output .= ' />'; return $output; } sub render_radio_group { my ( $self, $field ) = @_; my $output = "
"; my $index = 0; foreach my $option ( @{ $field->options } ) { my $id = $field->id . ".$index"; $output .= qq{
'; $index++; } return $output; } sub render_textarea { my ( $self, $field ) = @_; my $fif = $field->fif || ''; my $id = $field->id; my $cols = $field->cols || 10; my $rows = $field->rows || 5; my $name = $field->html_name; my $output = qq(); return $output; } sub render_upload { my ( $self, $field ) = @_; my $output; $output = 'id . '"'; $output .= process_attrs($field->element_attributes); $output .= ' />'; return $output; } sub render_label { my ( $self, $field ) = @_; my $attrs = process_attrs( $field->label_attributes ); my $label = $field->html_filter($field->loc_label); $label .= $field->get_tag('label_after') if( $field->tag_exists('label_after') ); my $label_tag = $field->tag_exists('label_tag') ? $field->get_tag('label_tag') : 'label'; return qq{<$label_tag$attrs for="} . $field->id . qq{">$label}; } sub render_compound { my ( $self, $field ) = @_; my $output = ''; foreach my $subfield ( $field->sorted_fields ) { $output .= $self->render_field($subfield); } return $output; } sub render_submit { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= process_attrs($field->element_attributes); $output .= ' value="' . $field->html_filter($field->_localize($field->value)) . '" />'; return $output; } sub render_reset { my ( $self, $field ) = @_; my $output = 'id . '"'; $output .= process_attrs($field->element_attributes); $output .= ' value="' . $field->html_filter($field->value) . '" />'; return $output; } sub render_captcha { my ( $self, $field ) = @_; my $output .= ''; $output .= ''; return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Render::Simple - simple rendering role =head1 VERSION version 0.40064 =head1 SYNOPSIS This is a Moose role that is an example of a simple rendering routine for L. It's here as an example of how to write a custom renderer in one package, if you prefer that to using the widgets. It won't always be updated with improvements by default, because it was becoming a lot of work to update the rendering in multiple places. For a 'MyApp::Form::Renderer' which you've created and modified, in your Form class: package MyApp::Form::Silly; use Moose; extends 'HTML::FormHandler::Model::DBIC'; with 'MyApp::Form::Renderers'; In a template: [% form.render %] The widgets are rendered with C<< $field->render >>; rendering routines from a class like this use C<< $form->render_field('field_name') >> to render individual fields: [% form.render_field( 'title' ) %] =head1 DESCRIPTION This role provides HTML output routines for the 'widget' types defined in the provided FormHandler fields. Each 'widget' name has a 'widget_$name' method here. These widget routines output strings with HTML suitable for displaying form fields. The widget for a particular field can be defined in the form. You can create additional widget routines in your form for custom widgets. The fill-in-form values ('fif') are cleaned with the 'render_filter' method of the base field class. You can change the filter to suit your own needs: see L =head2 render To render all the fields in a form in sorted order (using 'sorted_fields' method). =head2 render_start, render_end These use the methods in L now. If you want to customize them, copy them to your own package. Will render the beginning and ending
tags and fieldsets. Allows for easy splitting up of the form if you want to hand-render some of the fields. [% form.render_start %] [% form.render_field('title') %] [% form.render_field('some_field') %] [% form.render_end %] =head2 render_field Render a field passing in a field object or a field name $form->render_field( $field ) $form->render_field( 'title' ) =head2 render_text Output an HTML string for a text widget =head2 render_password Output an HTML string for a password widget =head2 render_hidden Output an HTML string for a hidden input widget =head2 render_select Output an HTML string for a 'select' widget, single or multiple =head2 render_checkbox Output an HTML string for a 'checkbox' widget =head2 render_radio_group Output an HTML string for a 'radio_group' selection widget. This widget should be for a field that inherits from 'Select', since it requires the existence of an 'options' array. =head2 render_textarea Output an HTML string for a textarea widget =head2 render_compound Renders field with 'compound' widget =head2 render_submit Renders field with 'submit' widget =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut WithTT.pm100644000770000024 652112576552253 23141 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Renderpackage HTML::FormHandler::Render::WithTT; # ABSTRACT: tt rendering use Moose::Role; use File::ShareDir; use Template; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); has 'tt_include_path' => ( traits => ['Array'], is => 'rw', isa => 'ArrayRef', lazy => 1, builder => 'build_tt_include_path', handles => { add_tt_include_path => 'push', } ); sub build_tt_include_path {[]} has 'tt_config' => ( traits => ['Hash'], is => 'rw', lazy => 1, builder => 'build_tt_config', ); sub build_tt_config { my $self = shift; return { INCLUDE_PATH => [ @{ $self->tt_include_path }, File::ShareDir::dist_dir('HTML-FormHandler') . '/templates/' ] }; } # either file name string or string ref? has 'tt_template' => ( is => 'rw', isa => 'Str', lazy => 1, builder => 'build_tt_template' ); sub build_tt_template { 'form/form.tt' } has 'tt_engine' => ( is => 'rw', isa => 'Template', lazy => 1, builder => 'build_tt_engine' ); sub build_tt_engine { my $self = shift; my $tt_engine = Template->new( $self->tt_config ); return $tt_engine; } has 'tt_vars' => ( is => 'rw', traits => ['Hash'], builder => 'build_tt_vars'); sub build_tt_vars {{}} has 'default_tt_vars' => ( is => 'ro', isa => 'HashRef', lazy => 1, builder => 'build_default_tt_vars' ); sub build_default_tt_vars { my $self = shift; return { form => $self->form, process_attrs => \&process_attrs }; } has 'tt_default_options' => ( traits => ['Hash'], is => 'rw', isa => 'HashRef', lazy => 1, builder => 'build_tt_default_options', ); sub build_tt_default_options {{}} sub tt_render { my $self = shift; my $output; my $vars = { %{$self->default_tt_vars}, %{$self->tt_vars} }; $self->tt_engine->process( $self->tt_template, $vars, \$output ); if( my $exception = $self->tt_engine->{SERVICE}->{_ERROR} ) { die $exception->[0] . " " . $exception->[1] . ". So far => " . ${$exception->[2]} . "\n"; } return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Render::WithTT - tt rendering =head1 VERSION version 0.40064 =head1 SYNOPSIS A rendering role for HTML::FormHandler that allows rendering using Template::Toolkit package MyApp::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::WithTT'; sub build_tt_template { 'user_form.tt' } sub build_tt_include_path { ['root/templates'] } ....< define form >.... my $form = MyApp::Form->new( $form->tt_render; If you want to render with TT, you don't need this role. Just use one of the TT form templates provided, form.tt or form_in_one.tt. If you use this role to render, you are using two different TT engines, with different sets of variables, etc, which doesn't make much sense. This is mainly useful as a testing aid and an example of using the sample templates. =head1 DESCRIPTION Uses 'tt_render' instead of 'render' to allow using both TT templates and the built-in rendering. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut TraitFor000755000770000024 012576552253 21567 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandlerI18N.pm100644000770000024 623412576552253 22751 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/TraitForpackage HTML::FormHandler::TraitFor::I18N; # ABSTRACT: localization use HTML::FormHandler::I18N; use Moose::Role; use Moose::Util::TypeConstraints; has 'language_handle' => ( isa => duck_type( [ qw(maketext) ] ), is => 'rw', lazy_build => 1, required => 1, ); sub _build_language_handle { my ($self) = @_; if (!$self->isa('HTML::FormHandler') && $self->has_form) { return $self->form->language_handle(); } my $lh; if ( $ENV{LANGUAGE_HANDLE} ) { if ( blessed $ENV{LANGUAGE_HANDLE} ) { $lh = $ENV{LANGUAGE_HANDLE}; } else { $lh = HTML::FormHandler::I18N->get_handle( $ENV{LANGUAGE_HANDLE} ); } } else { $lh = HTML::FormHandler::I18N->get_handle; } return $lh; } sub _localize { my ($self, @message) = @_; my $message = $self->language_handle->maketext(@message); return $message; } no Moose::Role; no Moose::Util::TypeConstraints; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::TraitFor::I18N - localization =head1 VERSION version 0.40064 =head3 language_handle, _build_language_handle Holds a Locale::Maketext (or other duck_type class with a 'maketext' method) language handle. The language handle is used to localize the error messages in the field's 'add_error' method. It's also used in various places in rendering to localize labels and button values, etc. The builder for this attribute gets the Locale::Maketext language handle from the environment variable $ENV{LANGUAGE_HANDLE}: $ENV{LANGUAGE_HANDLE} = 'en_en'; ...or creates a default language handler using L. (Note that earlier versions required an actual object reference in ENV, which is a bad practice and no longer supported.) You can pass in an existing L subclass instance or create one in a builder. In a form class: sub _build_language_handle { MyApp::I18N::abc_de->new } Passed into new or process: my $lh = MyApp::I18N::abc_de->new; my $form = MyApp::Form->new( language_handle => $lh ); If you do not set the language_handle, then L and/or L may guess, with unexpected results. You can use non-Locale::Maketext language handles, such as L. There's an example of building a L language handle in t/xt/locale_data_localize.t in the distribution. If you don't want a particular error message to go through localization, you can use 'push_errors' and 'push_form_errors' instead of 'add_error' and 'add_form_errors'. Example of getting the language handle from the Catalyst context (where the Catalyst context is passed in with 'ctx'): has '+language_handle' => ( builder => 'get_language_handle_from_ctx' ); sub get_language_handle_from_ctx { my $self = shift; return MyApp::I18N->get_handle( @{ $self->ctx->languages } ); } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut wrap_label.tt100644000770000024 24012576552253 23677 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/share/templates/wrapper[%~ content ~%][%~ f.label %] Checkbox.pm100644000770000024 447512576552253 23316 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Checkbox; # ABSTRACT: a checkbox field type use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field'; our $VERSION = '0.02'; has '+widget' => ( default => 'Checkbox' ); has 'checkbox_value' => ( is => 'rw', default => 1 ); has '+input_without_param' => ( default => 0 ); has '+type_attr' => ( default => 'checkbox' ); has 'option_label' => ( is => 'rw' ); has 'option_wrapper' => ( is => 'rw' ); sub validate { my $self = shift; $self->add_error($self->get_message('required'), $self->loc_label) if( $self->required && !$self->value ); return; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Checkbox - a checkbox field type =head1 VERSION version 0.40064 =head1 DESCRIPTION This field is very similar to the Boolean Widget except that this field allows other positive values besides 1. Since unselected checkboxes do not return a parameter, fields with Checkbox type will always be set to the 'input_without_param' default if they do not appear in the form. =head2 widget checkbox =head2 checkbox_value In order to create the HTML for a checkbox, there must be a 'value="xx"'. This value is specified with the 'checkbox_value' attribute, which defaults to 1. =head2 input_without_param If the checkbox is not checked, it will be set to the value of this attribute (the unchecked value). Default = 0. Because unchecked checkboxes do not return anything in the HTTP parameters, the absence of a checkbox key in the parameters hash forces this field to this value. This means that Checkbox fields, unlike other fields, will not be ignored if there is no input. If a particular checkbox should not be processed for a particular form, you must set 'inactive' to 1 instead. Note that a checkbox is only 'checked' when the 'checkbox_value' is provided. The 'value' for a non-checked checkbox is only really useful for creating form values such as are stored in a database. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Compound.pm100644000770000024 773112576552253 23352 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Compound; # ABSTRACT: field consisting of subfields use Moose; extends 'HTML::FormHandler::Field'; with 'HTML::FormHandler::Fields'; with 'HTML::FormHandler::BuildFields'; with 'HTML::FormHandler::InitResult'; has '+widget' => ( default => 'Compound' ); has 'is_compound' => ( is => 'ro', isa => 'Bool', default => 1 ); has 'item' => ( is => 'rw', clearer => 'clear_item' ); has '+do_wrapper' => ( default => 0 ); has '+do_label' => ( default => 0 ); has 'primary_key' => ( is => 'rw', isa => 'ArrayRef', predicate => 'has_primary_key', ); has '+field_name_space' => ( default => sub { my $self = shift; return $self->form->field_name_space if $self->form && $self->form->field_name_space; return []; }, ); sub BUILD { my $self = shift; $self->_build_fields; } # this is for testing compound fields outside # of a form sub test_validate_field { my $self = shift; unless( $self->form ) { if( $self->has_input ) { $self->_result_from_input( $self->result, $self->input );; } else { $self->_result_from_fields( $self->result ); } } $self->validate_field; unless( $self->form ) { foreach my $err_res (@{$self->result->error_results}) { $self->result->_push_errors($err_res->all_errors); } } } around '_result_from_object' => sub { my $orig = shift; my $self = shift; my ( $self_result, $item ) = @_; $self->item($item) if $item; $self->$orig(@_); }; after 'clear_data' => sub { my $self = shift; $self->clear_item; }; around '_result_from_input' => sub { my $orig = shift; my $self = shift; my ( $self_result, $input, $exists ) = @_; if ( !$input && !$exists ) { return $self->_result_from_fields($self_result); } else { return $self->$orig(@_); } }; __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Compound - field consisting of subfields =head1 VERSION version 0.40064 =head1 SYNOPSIS This field class is designed as the base (parent) class for fields with multiple subfields. Examples are L and L. A compound parent class requires the use of sub-fields prepended with the parent class name plus a dot has_field 'birthdate' => ( type => 'DateTime' ); has_field 'birthdate.year' => ( type => 'Year' ); has_field 'birthdate.month' => ( type => 'Month' ); has_field 'birthdate.day' => ( type => 'MonthDay'); If all validation is performed in the parent class so that no validation is necessary in the child classes, then the field class 'Nested' may be used. The array of subfields is available in the 'fields' array in the compound field: $form->field('birthdate')->fields Error messages will be available in the field on which the error occurred. You can access 'error_fields' on the form or on Compound fields (and subclasses, like Repeatable). The process method of this field runs the process methods on the child fields and then builds a hash of these fields values. This hash is available for further processing by L and the validate method. =head2 widget Widget type is 'compound' =head2 build_update_subfields You can set 'defaults' or other settings in a 'build_update_subfields' method, which contains attribute settings that will be merged with field definitions when the fields are built. Use the 'by_flag' key with 'repeatable', 'compound', and 'contains' subkeys, or use the 'all' key for settings which apply to all subfields in the compound field. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DateTime.pm100644000770000024 527012576552253 23256 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::DateTime; # ABSTRACT: compound DateTime field use Moose; extends 'HTML::FormHandler::Field::Compound'; use DateTime; use Try::Tiny; our $VERSION = '0.04'; has '+widget' => ( default => 'Compound' ); has '+inflate_default_method' => ( default => sub { \&datetime_inflate } ); our $class_messages = { 'datetime_invalid' => 'Not a valid DateTime', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } sub datetime_inflate { my ( $self, $value ) = @_; return $value unless ref $value eq 'DateTime'; my %hash; foreach my $field ( $self->all_fields ) { my $meth = $field->name; $hash{$meth} = $value->$meth; } return \%hash; } sub validate { my ($self) = @_; my @dt_parms; foreach my $child ( $self->all_fields ) { next unless $child->value; push @dt_parms, ( $child->accessor => $child->value ); } # set the value my $dt; try { $dt = DateTime->new(@dt_parms); } catch { $self->add_error( $self->get_message('datetime_invalid') ); }; if( $dt ) { $self->_set_value($dt); } else { $self->_set_value( {@dt_parms} ); } } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::DateTime - compound DateTime field =head1 VERSION version 0.40064 =head1 DESCRIPTION This is a compound field that requires you to define the subfields for month/day/year/hour/minute. Widget type is 'compound'. If you want to use drop-down select boxes for your DateTime, you can select fields like: has_field 'my_date' => ( type => 'DateTime' ); has_field 'my_date.month' => ( type => 'Month' ); has_field 'my_date.day' => ( type => 'MonthDay' ); has_field 'my_date.year' => ( type => 'Year' ); has_field 'my_date.hour' => ( type => 'Hour' ); has_field 'my_date.minute' => ( type => 'Minute' ); If you want simple input fields: has_field 'my_date' => ( type => 'DateTime' ); has_field 'my_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'my_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); Customizable error: 'datetime_invalid' (default = "Not a valid DateTime") See the 'Date' field for a single input date field. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Duration.pm100644000770000024 337312576552253 23351 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Duration; # ABSTRACT: DateTime::Duration from HTML form values use Moose; extends 'HTML::FormHandler::Field::Compound'; use DateTime; our $VERSION = '0.01'; our $class_messages = { 'duration_invalid' => 'Invalid value for [_1]: [_2]', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } sub validate { my ($self) = @_; my @dur_parms; foreach my $child ( $self->all_fields ) { unless ( $child->has_value && $child->value =~ /^\d+$/ ) { $self->add_error( $self->get_message('duration_invalid'), $self->loc_label, $child->loc_label ); next; } push @dur_parms, ( $child->accessor => $child->value ); } # set the value my $duration = DateTime::Duration->new(@dur_parms); $self->_set_value($duration); } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Duration - DateTime::Duration from HTML form values =head1 VERSION version 0.40064 =head1 SubFields Subfield names: years, months, weeks, days, hours, minutes, seconds, nanoseconds For example: has_field 'duration' => ( type => 'Duration' ); has_field 'duration.hours' => ( type => 'Hour' ); has_field 'duration.minutes' => ( type => 'Minute' ); Customize error message 'duration_invalid' (default 'Invalid value for [_1]: [_2]') =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut IntRange.pm100644000770000024 320412576552253 23264 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::IntRange; # ABSTRACT: integer range in select list use Moose; extends 'HTML::FormHandler::Field::Select'; our $VERSION = '0.01'; has 'label_format' => ( isa => 'Str', is => 'rw', default => '%d' ); has '+range_start' => ( default => 1 ); has '+range_end' => ( default => 10 ); sub build_options { my $self = shift; my $start = $self->range_start; my $end = $self->range_end; for ( $start, $end ) { die "Both range_start and range_end must be defined" unless defined $_; die "Integer ranges must be integers" unless /^\d+$/; } die "range_start must be less than range_end" unless $start < $end; my $format = $self->label_format || die 'IntRange needs label_format'; return [ map { { value => $_, label => sprintf( $format, $_ ) } } $self->range_start .. $self->range_end ]; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::IntRange - integer range in select list =head1 VERSION version 0.40064 =head1 DESCRIPTION This field generates a select list of numbers from 1 to 10. Override the range_start and range_end for a select list with a different range. has_field 'age' => ( type => 'IntRange', range_start => 0, range_end => 100 ); Widget type is 'select'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MonthDay.pm100644000770000024 143612576552253 23305 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::MonthDay; # ABSTRACT: select list 1 to 31 use Moose; extends 'HTML::FormHandler::Field::IntRange'; our $VERSION = '0.01'; has '+range_start' => ( default => 1 ); has '+range_end' => ( default => 31 ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::MonthDay - select list 1 to 31 =head1 VERSION version 0.40064 =head1 DESCRIPTION Generates a select list for integers 1 to 31. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Multiple.pm100644000770000024 310212576552253 23345 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Multiple; # ABSTRACT: multiple select list use Moose; extends 'HTML::FormHandler::Field::Select'; our $VERSION = '0.01'; has '+multiple' => ( default => 1 ); has '+size' => ( default => 5 ); has '+sort_options_method' => ( default => sub { \&default_sort_options } ); sub default_sort_options { my ( $self, $options ) = @_; return $options unless scalar @$options && defined $self->value; my $value = $self->deflate($self->value); return $options unless scalar @$value; # This places the currently selected options at the top of the list # Makes the drop down lists a bit nicer my %selected = map { $_ => 1 } @$value; my @out = grep { $selected{ $_->{value} } } @$options; push @out, grep { !$selected{ $_->{value} } } @$options; return \@out; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Multiple - multiple select list =head1 VERSION version 0.40064 =head1 DESCRIPTION This is a convenience field that inherits from the Select field and pre-sets some attributes. It sets the 'multiple' flag, sets the 'size' attribute to 5, and sets the 'sort_options_method' to move the currently selected options to the top of the options list. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Password.pm100644000770000024 570012576552253 23362 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Password; # ABSTRACT: password field use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Text'; our $VERSION = '0.04'; has '+widget' => ( default => 'Password' ); has '+password' => ( default => 1 ); has 'ne_username' => ( isa => 'Str', is => 'rw' ); has '+type_attr' => ( default => 'password' ); has '+html5_type_attr' => ( default => 'password' ); our $class_messages = { 'required' => 'Please enter a password in this field', 'password_ne_username' => 'Password must not match [_1]', }; sub get_class_messages { my $self = shift; my $messages = { %{ $self->next::method }, %$class_messages, }; $messages->{required} = $self->required_message if $self->required_message; return $messages; } after 'validate_field' => sub { my $self = shift; if ( !$self->required && !( defined( $self->value ) && length( $self->value ) ) ) { $self->noupdate(1); $self->clear_errors; } }; sub validate { my $self = shift; $self->noupdate(0); return unless $self->next::method; my $value = $self->value; if ( $self->form && $self->ne_username ) { my $username = $self->form->get_param( $self->ne_username ); return $self->add_error( $self->get_message('password_ne_username'), $self->ne_username ) if $username && $username eq $value; } return 1; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Password - password field =head1 VERSION version 0.40064 =head1 DESCRIPTION The password field has a default minimum length of 6, which can be easily changed: has_field 'password' => ( type => 'Password', minlength => 7 ); It does not come with additional default checks, since password requirements vary so widely. There are a few constraints in the L modules which could be used with this field: NoSpaces, WordChars, NotAllDigits. These constraints can be used in the field definitions 'apply': use HTML::FormHandler::Types ('NoSpaces', 'WordChars', 'NotAllDigits' ); ... has_field 'password' => ( type => 'Password', apply => [ NoSpaces, WordChars, NotAllDigits ], ); You can add your own constraints in addition, of course. If a password field is not required, then the field will be marked 'noupdate', to prevent a null from being saved into the database. =head2 ne_username Set this attribute to the name of your username field (default 'username') if you want to check that the password is not the same as the username. Does not check by default. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut TextArea.pm100644000770000024 161412576552253 23275 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::TextArea; # ABSTRACT: textarea input use Moose; extends 'HTML::FormHandler::Field::Text'; our $VERSION = '0.02'; has '+widget' => ( default => 'Textarea' ); has 'cols' => ( isa => 'Int', is => 'rw' ); has 'rows' => ( isa => 'Int', is => 'rw' ); sub html_element { 'textarea' } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::TextArea - textarea input =head1 VERSION version 0.40064 =head1 Summary For HTML textarea. Uses 'textarea' widget. Set cols/row/minlength/maxlength. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Errors.pod100644000770000024 1055112576552253 23414 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Errors; # ABSTRACT: FormHandler error methods __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Errors - FormHandler error methods =head1 VERSION version 0.40064 =head1 SYNOPSIS L Errors and error messages for L. =head1 DESCRIPTION Errors are added to field or form objects by the field 'add_error' method or the form 'add_form_error' method. FormHandler will perform the 'add_error' for you for built-in validation or 'apply' actions. When performing your own validation in a validation method, you must do the 'add_error' yourself. Errors, along with 'input' and 'value' attributes, are collected in the FormHandler 'result' objects. A number of error retrieving methods are delegated to the field and form classes. The existence (or not) of errors determines whether or not the form has been 'validated'. =head1 Form methods =over 4 =item errors Returns an array of localized error strings (both field and form errors): my @errors = $form->errors; Note: this is a form method, not a result method. For the same thing from a result object, use C<< $result->form_and_field_errors >>. =item has_errors Both 'form' errors and errors from the tree of subfields if( $form->has_errors ) { } =item form_errors, all_form_errors Returns an arrayref / array of error strings on the form (not including field errors). foreach my $err ( $self->all_form_errors ) { $output .= "$err"; } =item has_form_errors Does the form have form_errors? =item add_form_error Add an error to the form which is not associated with a specific field. sub validate { my $self = shift; unless( ) { $self->add_form_error('....'); } } =item push_form_errors Add a non-localized error to the form. =back =head1 Field methods The most common error method is probably 'add_error', which you use in the validation process. sub validate_foo { my ( $self, $field ) = @_; unless ( ) { $field->add_error('Error condition'); } } =over 4 =item errors Returns an array of error strings. =item has_errors Does the field have errors? Note that a compound field that contains subfields with errors will not return true for this method. If you want to know if there are errors in the subfields, do 'has_error_fields'. =item num_errors =item add_error Add an error to the field. Localization is performed. =item push_errors Add an error without localization. =item error_fields In a compound field (and its subclasses, like 'Repeatable'), the list of fields with errors. =back =head1 Result methods The input, value, and error attributes are actually stored in the result objects. Although most of the methods are delegated to the form and field classes, there are times, such as when rendering (because you might be rendering a result that's been peeled off of the form object), that you may need to use result methods. These are the main methods that you might need to use. =over 4 =item has_errors =item errors =item error_results The results with errors; 'error_fields' is a wrapper around this. =back =head1 Messages The base field class and the field subclasses have some 'built-in' error messages. These can be modified by setting the 'messages' hashref in the form or the individual fields. When a message is retrieved in a field with C<< $field->get_message('upload_file_') >> for example, the 'get_message' method will look first in user-set field specific messages, then in user-supplied form messages, finally in messages provided by the field classes. package MyApp::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_messages { return { required => '....', my_message => '....' }; } ... my $form = MyApp::Form->new( messages => { required => '...', ...} ); ... has_field 'my_field' => ( messages => { required => 'Please provide a my_field' }, required => 1 ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Fields.pod100644000770000024 3710712576552253 23354 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Fields; # ABSTRACT: brief documentation of available fields __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Fields - brief documentation of available fields =head1 VERSION version 0.40064 =head1 SYNOPSIS L See also L for a description of the base field attributes. The inheritance hierarchy of HTML::FormHandler Fields Text Money Password Hidden Integer PosInteger Float Date DateMDY Email TextCSV TextArea Select Multiple SelectCSV BoolSelect IntRange Hour Minute MonthDay Month Second Year MonthName Weekday Checkbox Boolean Compound Repeatable Duration DateTime NoValue Submit Reset Button Display AddElement RmElement NonEditable PrimaryKey Upload File =head1 DESCRIPTION A form's fields are created from the 'has_field' and 'field_list' definitions. FormHandler processes the field lists and creates an array of L objects. The "type" of a field determines which field class to use. The field class determines which attributes are valid for a particular field. A number of field classes are provided by FormHandler. You can customize the validation in your form on a per field basis, but validation that will be used for more than one field might be more easily handled in a custom field class. Fields are accessed with C<< form->field('name') >>. Field errors are in C<< $field->errors >>. If the 'field_name_space' is not set, fields will be loaded from the HTML::FormHandler::Field name space. If you provide a 'field_name_space' it will be searched before FormHandler. If you want to explicitly list the field's package, prefix it with a plus sign. The field_name_space plus the default name spaces 'HTML::FormHandler::Field' and 'HTML::FormHandlerX::Field' will be searched for fields. has '+field_name_space' => ( default => 'MyApp::Form::Field' ); has_field 'name' => ( type => 'Text' ); # HTML::FormHandler::Field::Text has_field 'name' => ( type => '+My::FieldType' ); # My::Fieldtype has_field 'foo' => ( type => '+Foo' ); # MyApp::Form::Field::Foo or has_field 'foo' => ( type => 'Foo' ); # MyApp::Form::Field::Foo The most basic type is "Text", which is usually a 'text' HTML element and a string data type. (If the type of a field is not specified, it will be set to 'Text'.) A "Select" field type is a HTML select element, and validates against the list of values provided in the 'options'. A "Multiple" type is like "Select" but it allows selecting more than one value at a time. Many field classes contain only a list of constraints and transformations to apply. Some use the 'validate' method, which is called after the actions are applied. Some build a custom select list using 'build_options'. There are two rough categories of Field classes: those that do extra processing and those that are simple validators. The 'Compound', 'Repeatable', and 'Select' fields are fields that are functional. =head1 Field names The standard way to use FormHandler is with field names that match your database accessors. If you want to prepend the HTML field names with a name plus dot, you can set the form 'name' and use the 'html_prefix' flag. "$name." will be stripped from the beginning of the HTML fields before processing by HFH, and will be added back in 'fif'. The field's 'html_name' convenience attribute will return this name for use in templates. If you want the FormHandler field name to be different than the database accessor, set 'accessor' on your fields. (It defaults to the field name.) You could then use any name that you want for your field. There are a number of name-related field attributes. The 'name' is the name used to identify this particular field in this fields array. The 'full_name' includes the names of all parents of this field, like 'address.street.streetname'. The 'html_name' is the same as the 'full_name' unless you have set the 'html_prefix' flag, in which case it includes the form name: 'myform.address.street.streetname'. To retrieve a field by name, you can use either the full_name or a chain: C<< $form->field('address')->field('street')->field('streetname') >> or: C<< $form->field('address.street.streetname') >>. =head1 Creating custom fields Subclass a custom field from L, or one of the existing subclasses. Almost everything that is done in a custom field class can also be done in a form. The advantage of a field class is that it can simplify declaration of often-repeated sets of attributes. The simplest subclasses contain only a 'validate' routine or an 'apply' attribute, which is called by the base Field class from 'process'. Look at L, for example. If the field's value will be an object instead of a simple scalar, such as a DateTime, and you want to use the transformed value to fill in the form, then you will also need a deflation or field class 'deflate' method to reformat the object into a form suitable for an HTML form field. See L for more info. Some custom fields might only require setting certain attributes to defaults, such as the L field, which set 'range_start' to 0 and 'range_end' to 23. A 'select' field might override the 'build_options' builder for the 'options' array, like L. A field may add additional attributes, such as 'label_format' in L, or set the 'required' message. An alternative to new field classes for many field validations might be roles with collections of validations. =head1 Other field packages Some custom fields are supplied as CPAN packages, in the HTML::FormHandlerX name space. L L L =head1 Fields supplied by FormHandler =head2 Basic Fields Although there are a lot of fields provided (probably too many) a lot of them are "convenience" fields or "name" fields, where the main benefit is that the field type is a name that gives the main purpose of the field. Most of these fields could be replaced by a basic field with a bit of validation or some select options. A few of the fields are special purpose fields that won't be used very often. The fields in this section are the basic fields, the commonly used fields that will be most often used in a form. =head3 Text A string data type that will be formatted as an HTML text field. Has 'minlength' and 'maxlength' attributes. L =head3 Select A field formatted as a select element. L =head3 Checkbox A field formatted as a checkbox. If not in params, will be forced to 'false' value by 'input_without_param' attribute (0 by default). L =head3 Hidden A hidden field. L =head3 Password A password field. The value is not re-displayed. L =head3 TextArea A textarea field. Has 'cols' and 'rows' attributes. L =head3 Upload A file upload field that takes a filehandle or a Catalyst upload object (an object with a 'size' method). L =head3 Submit A submit field. L =head3 Reset A reset field. L =head2 Complex Fields (Compound and Repeatable) These fields are complex fields which contain a fair amount of special code. They do not map to a single HTML element; they contain multiple subfields. =head3 Compound A compound field is a field that has sub-fields. Compound fields can be created in two ways: 1) using a field class, 2) by declaration. To create a compound field class, you must extend L and use L to allow declaring fields: package MyApp::Field::Duration; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'month' => (type => 'Integer'); has_field 'day' => ( type => 'Integer' ); has_field 'minutes' => ( type => 'Integer' ); Then in the form: has_field 'my_duration' => ( type => '+Duration' ); To create a compound field by declaration, declare the containing compound field and subfields, prefixing the subfield names with the name of the containing compound field plus a dot: package MyApp::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'duration' => ( type => 'Compound' ); has_field 'duration.month' => ( type => 'Integer' ); has_field 'duration.day' => ( type => 'Integer' ); has_field 'duration.year' => ( type => 'Integer' ); In an HTML form the name of the field must be the complete name with dots. The 'html_name' field attribute can be used to get this name, C<< $field->html_name >>. A compound field can be used for a database relation that will have only one row (belongs_to or has_one). If the relation has a compound primary key, you may need to provide the primary key columns, either through hidden fields or by setting them in the C<< $form->value >> hash before 'update_model' is called. See also L. =head3 Repeatable Repeatable fields are used for arrays of compound fields. has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.address_id' => ( type => 'PrimaryKey' ); has_field 'addresses.street'; has_field 'addresses.city'; has_field 'addresses.country' => ( type => 'Select' ); The arrays will be built from arrays passed in the params, or from related ('has_many') rows in the database. It is also used for arrays of single fields using the 'contains' keyword: has_field 'tags' => ( type => 'Repeatable' ); has_field 'tags.contains' => ( type => '+Tag' ); See L for more information. =head2 Text Fields Fields subclassed from the Text field. =head3 Text Text field. L =head3 Money Positive or negative real value, formatted to two decimal places. L =head3 Date Date field that can be used by jQuery datepicker plugin. L =head3 DateMDY A subclass of 'Date' with the "%m/%d/%Y" format. L =head3 Email Uses Email::Valid for validation. L =head3 Integer Positive and negative integers. Can use range_start and range_end. L =head3 PosInteger A positive integer field. L =head3 Float Float field that allows you to set size, precision, decimal_symbol, and decimal_symbol_for_db. L =head3 TextCSV A text field that takes multiple values from a database and converts them to comma-separated values. This is intended for javascript fields that require that, such as 'select2'. This is the only 'multiple' text field. This text field would be a select-type field for the user. L =head2 Compound Fields Fields subclassed from 'Compound'. =head3 Compound L =head3 Repeatable L =head3 Duration Compound field with possible subfields: years, months, weeks, days, hours, minutes, seconds, nanoseconds. L =head3 DateTime A compound field that requires you to provide the subfields that you want. (month/day/year/hour/minutes) L =head2 Checkbox Fields Fields that inherit from 'Checkbox'. =head3 Checkbox L =head3 Boolean Checkbox that return 1 or 0. L =head2 Select Fields Fields that inherit from 'Select'. =head3 Select L =head3 Multiple Multiple select. Also sorts the selected options to the top of the select list. L =head2 SelectCSV A multiple select field for comma-separated values in the database. It expects database values like: '1,5,7'. The string will be inflated into an arrayref for validation and form filling, and will be deflated into a comma-separated string in the output value. L =head3 BoolSelect A field with three possible values: empty/0/1. L =head3 Hour Integer select range field from 0-23. L =head3 Second Select field with range from 0-59. L =head3 IntRange An integer select field. Can set label format with 'label_format'. L =head3 Month Select field with range from 1 - 12. L =head3 MonthDay Select field with range from 1 - 31. L =head3 MonthName Select field with month name labels, value 1-12. L =head3 Minute Select field with range from 0-59. L =head3 Weekday A select field where the labels are the names of the week, and the values are 0-6. L =head3 Year Select field providing year list 5 years back and 10 years forward. L =head2 NoValue fields Fields that inherit from 'NoValue'. None of these fields will provide a 'value' in the C<< $form->value >> hashref. =head3 NoValue Base class for fields that don't produce a 'value'. L =head3 Submit L =head3 Reset L =head3 Button Button field that is rendered by the Button widget. L =head3 Display Non-data field used for inserting HTML into the form. Probably now better handled by a Block or a rendering tag. L =head3 AddElement Example field for adding a repeatable element. L =head3 RmElement Example field for removing a repeatable element L =head3 NonEditable For Bootstrap-style non-editable fields. =head2 TextArea fields Fields that inherit from 'TextArea'. =head3 TextArea L =head2 Password fields =head3 Password Password field. Sets 'noupdate' flag if empty and not required. L =head3 PasswordConf Password confirmation field. L =head2 Other fields These fields inherit just from 'Field'. =head3 File A file field that does no processing. Most people probably want to use 'Upload' instead. L =head3 PrimaryKey Hidden field that provides the primary key for Repeatable fields. L =head3 Captcha A Captcha field using GD::SecurityImage. Requires the use of the L role, or similar code. L =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut FromFF.pod100644000770000024 1400112576552253 23251 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::FromFF; # ABSTRACT: converting from HTML::FormFu __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::FromFF - converting from HTML::FormFu =head1 VERSION version 0.40064 =head1 SYNOPSIS L Cheatsheet for converting from L. =head1 DESCRIPTION Information that may be useful when converting to FormHandler from FormFu. =head2 Inside/Outside FormFu forms look to me like "inside-out" objects. The attributes and code are all set outside of the object. FormHandler forms are the opposite. Almost all attributes and settings are set *inside* the form class, although settings can be passed in on 'new' and 'process', of course. FormHandler fields are built as part of the object construction process, so you do not create or add new fields after the form instance has been constructed. There are many facilities for setting fields active/inactive or changing the various field attributes, so this is not limiting in what you can do. One of the big advantages of having form fields and validations, etc, inside the object is that it makes it a lot easier to test exactly what you're using in your controllers. =head2 Config files There are so many drawbacks to using config files to specify your forms that I don't see why anybody would voluntarily do it. However it takes all kinds, so if you really want to use config files, you can...mostly. There are a lot of things you can't do in config files, but FormHandler provides so many ways of doing things, that you can probably get it to work. And sometimes it's easier to update forms piecemeal, or there may be policies in place, so if you really want/need config files for building forms, see L and the test in t/form_setup/config.t. =head2 Rendering You should be able to make your FormHandler forms automatically render very close to FormFu's rendering. There's an example of simple FormFu-like rendering in t/render/ff.t. Set up a base class with the necessary code, and your forms could be practically drop-in replacements from a rendering perspective. =head1 Filters, Constraints, Inflators, Validators, Transformers FormHandler doesn't distinguish between these categories in the same way that FormFu does. FormHandler has inflation/deflation, validation methods, and apply actions. The distinguishing factor is mostly where it happens in the process. =head2 Filters A 'trim' filter is installed by default in FormHandler; it's a special version of an apply action, and can be set to a transform or Moose type. See the documentation in L. An HTML filter is applied by default in certain places in the rendering. You can change it with the 'render_filter' attribute. See L. You can change the form of the field's value using a number of inflation/deflation methods, or a transform, or a Moose type. See L and L. Transforms and inflations/deflations do not change what is presented in the form unless you set the 'fif_from_value' flag on the field (the rough equivalent of FormFu's 'render_processed_value'). =head3 FormatNumber Use an inflation: has_field 'foo' => ( type => 'PosInteger', inflate_method => \&format_number ); sub format_number { my ( $self, $value ) = @_; return unformat_number( $value ); } =head2 Constraints A lot of these are simple regexes or functions. If they're things you're going to use often, you probably want to put them in a type library or validator class. =over 4 =item AllOrNone Not implemented. Do this in a form 'validate' sub. =item ASCII A simple regex: has foo => ( apply => [ { check => qr/^\p{IsASCII}*\z/, message => 'Not a valid string' } ] ); =item AutoSet Not necessary. This is done automatically by FormHandler. You'd have to go to some work to avoid it. =item Bool A simple regex: qr/^[01]?\z/ Or you can use the Boolean field. =item Callback, CallbackOnce This is just validation done in code. Use one of the many places you can put validation in methods in FormHandler. See L. =item DateTime Use Date or DateTime field or make your own. =item DependOn Use 'dependency' attribute in the form. Or do more complicated things in the form's 'validate' sub. =item Email Use the 'Email' field type, or use the FH Moose Type, 'email'. has_field 'email' => ( type => 'Email' ); -- or -- use HTML::FormHandler::Types ('Email'); has_field 'email' => ( apply => [ Email ] ); =item Equal No equivalent. Perform this check in the form's 'validate' sub. =item File Use 'Upload' field. =item Integer Use 'Integer' field. =item Length, MaxLength, MinLength Use 'minlength' and 'maxlength' on the Text field and its subclasses. =item Range, MaxRange, MinRange Use 'range_start' and 'range_end'. =item MinMaxFields No equivalent. =item Number Use Moose type 'Num'. =item Printable Use FormHandler Moose type 'Printable'. =item reCAPTCHA Use Captcha field or L. =item Regex Use 'check' action with regex. =item Required Set 'required' flag on the field. =item Set Use 'check' action with arrayref of strings. =item SingleValue Not necessary. =item Word This is a simple regex: qr/^\w*\z/ Substitute FormHandler Moose type 'SingleWord'. =back =head2 Inflators Use one of the inflation/deflation methods. See L. =head2 Validators See L. =head2 Transformers See L and L. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Types.pm100644000770000024 236112576552253 23373 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/TraitForpackage HTML::FormHandler::TraitFor::Types; # ABSTRACT: types used internally in FormHandler use Moose::Role; use Moose::Util::TypeConstraints; subtype 'HFH::ArrayRefStr' => as 'ArrayRef[Str]'; coerce 'HFH::ArrayRefStr' => from 'Str' => via { if( length $_ ) { return [$_] }; return []; }; coerce 'HFH::ArrayRefStr' => from 'Undef' => via { return []; }; subtype 'HFH::SelectOptions' => as 'ArrayRef[HashRef]'; coerce 'HFH::SelectOptions' => from 'ArrayRef[Str]' => via { my @options = @$_; die "Options array must contain an even number of elements" if @options % 2; my $opts; push @{$opts}, { value => shift @options, label => shift @options } while @options; return $opts; }; no Moose::Util::TypeConstraints; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::TraitFor::Types - types used internally in FormHandler =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut compound_update_fields.t100644000770000024 315712576552253 24137 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/field_setupuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Field::Record; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; sub build_update_subfields {{ all => { wrapper_class => 'wrap', tags => { 'before_element' => '

A comment

' } }, 'sam' => { label_class => 'sam_label' }, }} has_field 'flot'; has_field 'jet'; has_field 'sam'; } { package MyApp::Form::Complex; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_form' ); has '+field_name_space' => ( default => sub{ ['MyApp::Form::Field'] } ); has_field 'foo'; has_field 'bar' => ( type => 'Record' ); } my $form = MyApp::Form::Complex->new; ok( $form, 'form built' ); $form->process; my $rendered = $form->render; my $expected = '

A comment

A comment

A comment

'; is_html( $rendered, $expected, 'rendered as expected' ); done_testing; MonthName.pm100644000770000024 203112576552253 23440 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::MonthName; # ABSTRACT: select list with month names use Moose; extends 'HTML::FormHandler::Field::Select'; our $VERSION = '0.01'; sub build_options { my $i = 1; my @months = qw/ January February March April May June July August September October November December /; return [ map { { value => $i++, label => $_ } } @months ]; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::MonthName - select list with month names =head1 VERSION version 0.40064 =head1 DESCRIPTION Generates a list of English month names. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut RmElement.pm100644000770000024 406312576552253 23451 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::RmElement; # ABSTRACT: field to support repeatable javascript remove use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Display'; use HTML::FormHandler::Render::Util ('process_attrs'); has '+do_wrapper' => ( default => 1 ); has '+value' => ( default => 'Remove' ); sub build_render_method { return sub { my ( $self, $result ) = @_; $result ||= $self->result; my $value = $self->html || $self->html_filter($self->_localize($self->value)); my $attrs = $self->element_attributes($result); push @{$attrs->{class}}, ( 'rm_element', 'btn' ); $attrs->{'data-rep-elem-id'} = $self->parent->id; $attrs->{id} = $self->id; my $attr_str = process_attrs($attrs); my $wrapper_tag = $self->get_tag('wrapper_tag') || 'div'; my $output = qq{<$wrapper_tag$attr_str>$value}; $output = $self->wrap_field($self->result, $output); return $output; }; } __PACKAGE__->meta->make_immutable; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::RmElement - field to support repeatable javascript remove =head1 VERSION version 0.40064 =head1 SYNOPSIS EXAMPLE field for rendering an RmElement field for doing javascript removals of repeatable elements. You probably want to make your own. The main requirements are that the button have 1) the 'rm_element' class, 2) a 'data-rep-elem-id' attribute that contains the id of the repeatable instance that you want to remove (C<< $self->parent->id >>). This field should be a subfield of the Repeatable, probably either first or last. =head1 NAME HTML::FormHandler::Field::RmElement =head1 ATTRIBUTES has_field 'rm_element' => ( type => 'RmElement', value => 'Remove', ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut SelectCSV.pm100644000770000024 324612576552253 23356 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::SelectCSV; # ABSTRACT: Multiple select field from CSV value use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Select'; has '+inflate_default_method' => ( default => sub { \&selectcsv_inflate_default } ); has '+deflate_value_method' => ( default => sub { \&selectcsv_deflate_value } ); has '+multiple' => ( default => 1 ); sub build_value_when_empty { undef } sub selectcsv_inflate_default { my ( $self, $value ) = @_; if( defined $value ) { my @values = split (/,/, $value); return @values; } return; } sub selectcsv_deflate_value { my ( $self, $value ) = @_; if ( defined $value ) { my $str = join( ',', sort @$value ); return $str; } return; } sub fif { my $self = shift; my $fif = $self->next::method; $fif = [] if $fif eq ''; return $fif; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::SelectCSV - Multiple select field from CSV value =head1 VERSION version 0.40064 =head1 SYNOPSIS A multiple select field for comma-separated values in the database. It expects database values like: '1,5,7'. The string will be inflated into an arrayref for validation and form filling, and will be deflated into a comma-separated string in the output value. This field is useful for MySQL 'set' columns. =head1 NAME HTML::FormHandler::Field::SelectCSV =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut FromDFV.pod100644000770000024 542412576552253 23366 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::FromDFV; # ABSTRACT: converting from Data::FormValidator __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::FromDFV - converting from Data::FormValidator =head1 VERSION version 0.40064 =head1 SYNOPSIS L Cheatsheet for converting from L. =head1 DESCRIPTION Information that's useful when switching from Data::FormValidator to HTML::FormHandler. There's not a lot here yet, so if you have something to add, patches are welcome. In a general way, FormHandler doesn't have nearly so many "special" checks as Data::FormValidator. It would be possible to implement many of them, but there hasn't been much demand for them. So far FormHandler users seem to be satisfied with the "do your own checks in a Perl method" solution. Because of the greater complexity of FormHandler's data model - with Repeatable arrays and nested compounds, etc - it's somewhat harder to do some of them automatically. =head1 Differences/conversions =over 4 =item dependencies In FormHandler, 'dependency' is the equivalent of 'dependency_group', without the key names. The other variations of dependencies in DFV are not implemented in FormHandler, and would normally be done in a form's 'validate' sub. =item trim, filters A 'trim' filter is installed by default in FormHandler; it's a special version of an apply action, and can be set to a transform or Moose type. See the documentation in L. Transforms and inflations/deflations do not change what is presented in the form unless you set the 'fif_from_value' flag on the field. =item FV_length_between, FV_max_length, FV_min_length Use text fields with 'minlength' and 'maxlength' attributes. =item FV_eq_with Perform your own checks in the form 'validate' sub. sub validate { my $self = shift; if( $self->field('one')->value eq $self->field('two')->value ) { } } =back =head1 Constraints The simple constraints from L can be used directly in a FormHandler form: use Data::FormValidator::Constraints ('match_state'); has_field 'my_state' => ( apply => [ { check => \&match_state, message => 'Invalid State' } ] ); =over 4 =item email Use the 'Email' field type, or use the FH Moose Type, 'email'. has_field 'email' => ( type => 'Email' ); -- or -- use HTML::FormHandler::Types ('Email'); has_field 'email' => ( apply => [ Email ] ); =back =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Testing.pod100644000770000024 727412576552253 23545 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Testing # ABSTRACT: testing forms __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Testing - testing forms =head1 VERSION version 0.40064 =head1 SYNOPSIS L One of the big advantages of FormHandler compared to many other form packages is that you can test the same form that you use in your controller. =head1 DESCRIPTION It's difficult to test forms that are instantiated in controllers with 'add_element' calls and from YAML, and that have no form class. It's one of the reasons that 'dynamic' forms generated with a field_list aren't a good idea for anything except the simplest forms. If you have a form class that contains everything that is needed for processing the form, it's really really easy to create tests for forms. Look in the FormHandler 't' directory. It's full of tests for forms. You can test that the validations work, that the database is getting updated correctly, even that the HTML that's being rendered is correct. If something isn't working correctly, it's ten times easier to debug in a test case than sitting in a controller somewhere. And when you finally start up your application and use the form, there should be very few surprises. FormHandler provides a simple function to test whether the HTML output is correct, 'is_html' in L, which uses L. If you need to build forms that use the rendering code to produce particular output, it can be helpful. =head1 Example Here's an example of a test, originally copied from one of the DBIC model tests. But you should download the tar.gz or checkout the distribution from github and browse through the tests. use Test::More; use lib 't/lib'; use_ok( 'BookDB::Form::Book'); use_ok( 'BookDB::Schema::DB'); my $schema = BookDB::Schema::DB->connect('dbi:SQLite:t/db/book.db'); ok($schema, 'get db schema'); my $form = BookDB::Form::Book->new(schema => $schema); # This is munging up the equivalent of param data from a form my $good = { 'title' => 'How to Test Perl Form Processors', 'author' => 'I.M. Author', 'genres' => [2, 4], 'format' => 2, 'isbn' => '123-02345-0502-2' , 'publisher' => 'EreWhon Publishing', }; ok( $form->process( params => $good ), 'Good data' ); my $book = $form->item; END { $book->delete }; ok ($book, 'get book object from form'); my $num_genres = $book->genres->count; is( $num_genres, 2, 'multiple select list updated ok'); is( $form->field('format')->value, 2, 'get value for format' ); my $bad_1 = { notitle => 'not req', silly_field => 4, }; ok( !$form->process( $bad_1 ), 'bad 1' ); my $bad_2 = { 'title' => "Another Silly Test Book", 'author' => "C. Foolish", 'year' => '1590', 'pages' => 'too few', 'format' => '22', }; ok( !$form->process( $bad_2 ), 'bad 2'); ok( $form->field('year')->has_errors, 'year has error' ); ok( $form->field('pages')->has_errors, 'pages has error' ); ok( !$form->field('author')->has_errors, 'author has no error' ); ok( $form->field('format')->has_errors, 'format has error' ); my $good = { title => "Another Silly Test Book", author => "C. Foolish", year => 1999, pages => 101, format => 2 }; ok( $form->process($good), 'now form validates' ); done_testing; =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut checkbox_group.tt100644000770000024 52712576552253 24204 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/share/templates/field[% FOR option IN f.options -%] [% END -%] Controller000755000770000024 012576552253 22401 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xt/lib/MyCatalystAppRoot.pm100644000770000024 210612576552253 24021 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xt/lib/MyCatalystApp/Controllerpackage MyCatalystApp::Controller::Root; use Moose; use namespace::autoclean; BEGIN { extends 'Catalyst::Controller' } # # Sets the actions in this controller to be registered with no prefix # so they function identically to actions created in MyApp.pm # __PACKAGE__->config(namespace => ''); =head1 NAME MyCatalystApp::Controller::Root - Root Controller for MyCatalystApp =head1 DESCRIPTION [enter your description here] =head1 METHODS =head2 index The root page (/) =cut sub index :Path :Args(0) { my ( $self, $c ) = @_; # Hello World $c->response->body( $c->welcome_message ); } =head2 default Standard 404 error page =cut sub default :Path { my ( $self, $c ) = @_; $c->response->body( 'Page not found' ); $c->response->status(404); } =head2 end Attempt to render a view, if needed. =cut sub end : ActionClass('RenderView') {} =head1 AUTHOR Lukas Thiemeier,1R/18,7289,none =head1 LICENSE This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself. =cut __PACKAGE__->meta->make_immutable; 1; AddElement.pm100644000770000024 443112576552253 23562 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::AddElement; # ABSTRACT: Field to support repeatable javascript add use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Display'; use HTML::FormHandler::Render::Util ('process_attrs'); has 'repeatable' => ( is => 'rw', isa => 'Str', required => 1 ); has '+do_wrapper' => ( default => 1 ); has '+value' => ( default => 'Add Element' ); sub build_render_method { return sub { my ( $self, $result ) = @_; $result ||= $self->result; my $rep_field = $self->parent->field($self->repeatable); die "Invalid repeatable name in field " . $self->name unless $rep_field; my $value = $self->html_filter($self->_localize($self->value)); my $attrs = $self->element_attributes($result); push @{$attrs->{class}}, ( 'add_element', 'btn' ); $attrs->{'data-rep-id'} = $rep_field->id; $attrs->{id} = $self->id; my $attr_str = process_attrs($attrs); my $wrapper_tag = $self->get_tag('wrapper_tag') || 'div'; my $output = qq{<$wrapper_tag$attr_str>$value}; $output = $self->wrap_field($self->result, $output); return $output; }; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::AddElement - Field to support repeatable javascript add =head1 VERSION version 0.40064 =head1 SYNOPSIS EXAMPLE field for rendering an AddElement field for doing javascript additions of repeatable elements. You probably want to make your own. The main requirements are that the button have 1) the 'add_element' class, 2) a 'data-rep-id' attribute that contains the id of the repeatable to which you want to add an element. =head1 NAME HTML::FormHandler::Field::AddElement =head1 ATTRIBUTES has_field 'add_element' => ( type => 'AddElement', repeatable => 'foo', value => 'Add another foo', ); =head2 repeatable Requires the name of a Repeatable sibling field. =head2 value The value of the button that's rendered, 'Add Element' by default. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut BoolSelect.pm100644000770000024 156612576552253 23621 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::BoolSelect; # ABSTRACT: Boolean select field use Moose; extends 'HTML::FormHandler::Field::Select'; has '+empty_select' => ( default => 'Select One' ); sub build_options { [ { value => 1, label => 'True'}, { value => 0, label => 'False' } ]}; __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::BoolSelect - Boolean select field =head1 VERSION version 0.40064 =head1 SYNOPSIS A Boolean select field with three states: null, 1, 0. Empty select is 'Select One'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut PosInteger.pm100644000770000024 235612576552253 23643 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::PosInteger; # ABSTRACT: positive integer field use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Integer'; our $VERSION = '0.02'; our $class_messages = { 'integer_positive' => 'Value must be a positive integer', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } apply( [ { check => sub { $_[0] >= 0 }, message => sub { my ( $value, $field ) = @_; return $field->get_message('integer_positive'); }, } ] ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::PosInteger - positive integer field =head1 VERSION version 0.40064 =head1 DESCRIPTION Tests that the input is an integer and has a positive value. Customize error message 'integer_positive'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut PrimaryKey.pm100644000770000024 261112576552253 23652 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::PrimaryKey; # ABSTRACT: primary key field use Moose; extends 'HTML::FormHandler::Field'; has 'is_primary_key' => ( isa => 'Bool', is => 'ro', default => '1' ); has '+widget' => ( default => 'Hidden' ); has '+do_label' => ( default => 0 ); has '+no_value_if_empty' => ( default => 1 ); sub BUILD { my $self = shift; if ( $self->has_parent ) { if ( $self->parent->has_primary_key ) { push @{ $self->parent->primary_key }, $self; } else { $self->parent->primary_key( [ $self ] ); } } } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::PrimaryKey - primary key field =head1 VERSION version 0.40064 =head1 SYNOPSIS This field is for providing the primary key for Repeatable fields: has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.address_id' => ( type => 'PrimaryKey' ); Do not use this field to hold the primary key of the form's main db object (item). That primary key is in the 'item_id' attribute. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Repeatable.pm100644000770000024 3343212576552253 23647 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Repeatable; # ABSTRACT: repeatable (array) field use Moose; extends 'HTML::FormHandler::Field::Compound'; use aliased 'HTML::FormHandler::Field::Repeatable::Instance'; use HTML::FormHandler::Field::PrimaryKey; use HTML::FormHandler::Merge ('merge'); use Data::Clone ('data_clone'); has 'contains' => ( isa => 'HTML::FormHandler::Field', is => 'rw', predicate => 'has_contains', ); has 'init_contains' => ( is => 'rw', isa => 'HashRef', traits => ['Hash'], default => sub {{}}, handles => { has_init_contains => 'count' }, ); has 'num_when_empty' => ( isa => 'Int', is => 'rw', default => 1 ); has 'num_extra' => ( isa => 'Int', is => 'rw', default => 0 ); has 'setup_for_js' => ( isa => 'Bool', is => 'rw' ); has 'index' => ( isa => 'Int', is => 'rw', default => 0 ); has 'auto_id' => ( isa => 'Bool', is => 'rw', default => 0 ); has 'is_repeatable' => ( isa => 'Bool', is => 'ro', default => 1 ); has '+widget' => ( default => 'Repeatable' ); sub _fields_validate { my $self = shift; # loop through array of fields and validate my @value_array; foreach my $field ( $self->all_fields ) { next if ( $field->is_inactive ); # Validate each field and "inflate" input -> value. $field->validate_field; # this calls the field's 'validate' routine push @value_array, $field->value if $field->has_value; } $self->_set_value( \@value_array ); } sub init_state { my $self = shift; # must clear out instances built last time unless ( $self->has_contains ) { if ( $self->num_fields == 1 && $self->field('contains') ) { $self->field('contains')->is_contains(1); $self->contains( $self->field('contains') ); } else { $self->contains( $self->create_element ); } } $self->clear_fields; } sub create_element { my ($self) = @_; my $instance; my $instance_attr = { name => 'contains', parent => $self, type => 'Repeatable::Instance', is_contains => 1, }; # primary_key array is used for reloading after database update $instance_attr->{primary_key} = $self->primary_key if $self->has_primary_key; if( $self->has_init_contains ) { $instance_attr = merge( $self->init_contains, $instance_attr ); } if( $self->form ) { $instance_attr->{form} = $self->form; $instance = $self->form->_make_adhoc_field( 'HTML::FormHandler::Field::Repeatable::Instance', $instance_attr ); } else { $instance = Instance->new( %$instance_attr ); } # copy the fields from this field into the instance $instance->add_field( $self->all_fields ); foreach my $fld ( $instance->all_fields ) { $fld->parent($instance); } # set required flag $instance->required( $self->required ); # auto_id has no way to change widgets...deprecate this? if ( $self->auto_id ) { unless ( grep $_->can('is_primary_key') && $_->is_primary_key, $instance->all_fields ) { my $field; my $field_attr = { name => 'id', parent => $instance }; if ( $self->form ) { # this will pull in the widget role $field_attr->{form} = $self->form; $field = $self->form->_make_adhoc_field( 'HTML::FormHandler::Field::PrimaryKey', $field_attr ); } else { # the following won't have a widget role applied $field = HTML::FormHandler::Field::PrimaryKey->new( %$field_attr ); } $instance->add_field($field); } } $_->parent($instance) for $instance->all_fields; return $instance; } sub clone_element { my ( $self, $index ) = @_; my $field = $self->contains->clone( errors => [], error_fields => [] ); $field->name($index); $field->parent($self); if ( $field->has_fields ) { $self->clone_fields( $field, [ $field->all_fields ] ); } return $field; } sub clone_fields { my ( $self, $parent, $fields ) = @_; my @field_array; $parent->fields( [] ); foreach my $field ( @{$fields} ) { my $new_field = $field->clone( errors => [], error_fields => [] ); if ( $new_field->has_fields ) { $self->clone_fields( $new_field, [ $new_field->all_fields ] ); } $new_field->parent($parent); $parent->add_field($new_field); } } # params exist and validation will be performed (later) sub _result_from_input { my ( $self, $result, $input ) = @_; $self->init_state; $result->_set_input($input); $self->_set_result($result); # if Repeatable has array input, need to build instances $self->fields( [] ); my $index = 0; if ( ref $input eq 'ARRAY' ) { # build appropriate instance array foreach my $element ( @{$input} ) { next if not defined $element; # skip empty slots my $field = $self->clone_element($index); my $result = HTML::FormHandler::Field::Result->new( name => $index, parent => $self->result ); $result = $field->_result_from_input( $result, $element, 1 ); $self->result->add_result($result); $self->add_field($field); $index++; } } $self->index($index); $self->_setup_for_js if $self->setup_for_js; $self->result->_set_field_def($self); return $self->result; } sub _setup_for_js { my $self = shift; return unless $self->form; my $full_name = $self->full_name; my $index_level =()= $full_name =~ /{index\d+}/g; $index_level++; my $field_name = "{index-$index_level}"; my $field = $self->_add_extra($field_name); my $rendered = $field->render; # remove extra result & field, now that it's rendered $self->result->_pop_result; $self->_pop_field; # set the information in the form # $self->index is the index of the next instance $self->form->set_for_js( $self->full_name, { index => $self->index, html => $rendered, level => $index_level } ); } # this is called when there is an init_object or a db item with values sub _result_from_object { my ( $self, $result, $values ) = @_; return $self->_result_from_fields($result) if ( $self->num_when_empty > 0 && !$values ); $self->item($values); $self->init_state; $self->_set_result($result); # Create field instances and fill with values my $index = 0; my @new_values; $self->fields( [] ); $values = [$values] if ( $values && ref $values ne 'ARRAY' ); foreach my $element ( @{$values} ) { next unless $element; my $field = $self->clone_element($index); my $result = HTML::FormHandler::Field::Result->new( name => $index, parent => $self->result ); if( $field->has_inflate_default_method ) { $element = $field->inflate_default($element); } $result = $field->_result_from_object( $result, $element ); push @new_values, $result->value; $self->add_field($field); $self->result->add_result( $field->result ); $index++; } if( my $num_extra = $self->num_extra ) { while ($num_extra ) { $self->_add_extra($index); $num_extra--; $index++; } } $self->index($index); $self->_setup_for_js if $self->setup_for_js; $values = \@new_values if scalar @new_values; $self->_set_value($values); $self->result->_set_field_def($self); return $self->result; } sub _add_extra { my ($self, $index) = @_; my $field = $self->clone_element($index); my $result = HTML::FormHandler::Field::Result->new( name => $index, parent => $self->result ); $result = $field->_result_from_fields($result); $self->result->add_result($result) if $result; $self->add_field($field); return $field; } sub add_extra { my ( $self, $count ) = @_; $count = 1 if not defined $count; my $index = $self->index; while ( $count ) { $self->_add_extra($index); $count--; $index++; } $self->index($index); } # create an empty field sub _result_from_fields { my ( $self, $result ) = @_; # check for defaults if ( my @values = $self->get_default_value ) { return $self->_result_from_object( $result, \@values ); } $self->init_state; $self->_set_result($result); my $count = $self->num_when_empty; my $index = 0; # build empty instance $self->fields( [] ); while ( $count > 0 ) { my $field = $self->clone_element($index); my $result = HTML::FormHandler::Field::Result->new( name => $index, parent => $self->result ); $result = $field->_result_from_fields($result); $self->result->add_result($result) if $result; $self->add_field($field); $index++; $count--; } $self->index($index); $self->_setup_for_js if $self->setup_for_js; $self->result->_set_field_def($self); return $result; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Repeatable - repeatable (array) field =head1 VERSION version 0.40064 =head1 SYNOPSIS In a form, for an array of hashrefs, equivalent to a 'has_many' database relationship. has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.address_id' => ( type => 'PrimaryKey' ); has_field 'addresses.street'; has_field 'addresses.city'; has_field 'addresses.state'; In a form, for an array of single fields (not directly equivalent to a database relationship) use the 'contains' pseudo field name: has_field 'tags' => ( type => 'Repeatable' ); has_field 'tags.contains' => ( type => 'Text', apply => [ { check => ['perl', 'programming', 'linux', 'internet'], message => 'Not a valid tag' } ] ); or use 'contains' with single fields which are compound fields: has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.contains' => ( type => '+MyAddress' ); If the MyAddress field contains fields 'address_id', 'street', 'city', and 'state', then this syntax is functionally equivalent to the first method where the fields are declared with dots ('addresses.city'); You can pass attributes to the 'contains' field by supplying an 'init_contains' hashref. has_field 'addresses' => ( type => 'Repeatable, init_contains => { wrapper_attr => { class => ['hfh', 'repinst'] } }, ); =head1 DESCRIPTION This class represents an array. It can either be an array of hashrefs (compound fields) or an array of single fields. The 'contains' keyword is used for elements that do not have names because they are not hash elements. This field node will build arrays of fields from the parameters or an initial object, or empty fields for an empty form. The name of the element fields will be an array index, starting with 0. Therefore the first array element can be accessed with: $form->field('tags')->field('0') $form->field('addresses')->field('0')->field('city') or using the shortcut form: $form->field('tags.0') $form->field('addresses.0.city') The array of elements will be in C<< $form->field('addresses')->fields >>. The subfields of the elements will be in a fields array in each element. foreach my $element ( $form->field('addresses')->fields ) { foreach my $field ( $element->fields ) { # do something } } Every field that has a 'fields' array will also have an 'error_fields' array containing references to the fields that contain errors. =head2 Complications When new elements are created by a Repeatable field in a database form an attempt is made to re-load the Repeatable field from the database, because otherwise the repeatable elements will not have primary keys. Although this works, if you have included other fields in your repeatable elements that do *not* come from the database, the defaults/values must be able to be loaded in a way that works when the form is initialized from the database item. This is only an issue if you re-present the form after the database update succeeds. =head1 ATTRIBUTES =over =item index This attribute contains the next index number available to create an additional array element. =item num_when_empty This attribute (default 1) indicates how many empty fields to present in an empty form which hasn't been filled from parameters or database rows. =item num_extra When the field results are built from an existing object (item or init_object) an additional number of repeatable elements will be created equal to this number. Default is 0. =item add_extra When a form is submitted and the field results are built from the input parameters, it's not clear when or if an additional repeatable element might be wanted. The method 'add_extra' will add an empty repeatable element. $form->process( params => {....} ); $form->field('my_repeatable')->add_extra(1); This might be useful if the form is being re-presented to the user. =item setup_for_js setup_for_js => 1 Saves information in the form for javascript to use when adding repeatable elements. If using the example javascript, you also must set 'do_wrapper' in the Repeatable field and use the Bootstrap widget wrapper (or wrap the repeatable elements in a 'controls' div by setting tags => { controls_div => 1 }. See t/repeatable/js.t for an example. See also L and L. =back =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Catalyst.pod100644000770000024 1437412576552253 23733 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Catalyst; # ABSTRACT: using HFH forms in Catalyst __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Catalyst - using HFH forms in Catalyst =head1 VERSION version 0.40064 =head1 SYNOPSIS L This part of the FormHandler Manual describes the use of the L package in Catalyst controllers. See the other FormHandler documentation at L, or the base class at L. =head1 DESCRIPTION Although L can be used in any Perl web application, module, or script, one of its most common uses is in L applications. Using a form takes only a few lines of code, so it's not necessary to have a L base controller, although you could make a base controller for FormHandler if you're doing more than the basics. =head2 A Controller Example The following example uses chained dispatching. The 'form' method is called by both the create and edit actions. package BookDB::Controller::Borrower; use Moose; BEGIN { extends 'Catalyst::Controller' } use BookDB::Form::Borrower; sub borrower_base : Chained PathPart('borrower') CaptureArgs(0) { } sub list : Chained('borrower_base') PathPart('list') Args(0) { my ( $self, $c ) = @_; my $borrowers = [ $c->model('DB::Borrower')->all ]; my @columns = ( 'name', 'email' ); $c->stash( borrowers => $borrowers, columns => \@columns, template => 'borrower/list.tt' ); } sub add : Chained('borrower_base') PathPart('add') Args(0) { my ( $self, $c ) = @_; # Create the empty borrower row for the form $c->stash( borrower => $c->model('DB::Borrower')->new_result({}) ); return $self->form($c); } sub item : Chained('borrower_base') PathPart('') CaptureArgs(1) { my ( $self, $c, $borrower_id ) = @_; $c->stash( borrower => $c->model('DB::Borrower')->find($borrower_id) ); } sub edit : Chained('item') PathPart('edit') Args(0) { my ( $self, $c ) = @_; return $self->form($c); } sub form { my ( $self, $c ) = @_; my $form = BookDB::Form::Borrower->new; $c->stash( form => $form, template => 'borrower/form.tt' ); return unless $form->process( item => $c->stash->{borrower}, params => $c->req->parameters ); $c->res->redirect( $c->uri_for($self->action_for('list')) ); } sub delete : Chained('item') PathPart('delete') Args(0) { my ( $self, $c ) = @_; $c->stash->{borrower}->delete; $c->res->redirect( $c->uri_for($c->action_for('list')) ); } 1; =head2 Another way to set up your form If you are setting the schema or other form attributes (such as the user_id, or other attributes) on your form you could create a base controller that would set these in the form on each call using L, or set them in a base Chained method. sub book_base : Chained PathPart('book') CaptureArgs(0) { my ( $self, $c ) = @_; my $form = MyApp::Form->new; $form->schema( $c->model('DB')->schema ); $form->params( $c->req->parameters ); $form->user_id( $c->user->id ); $c->stash( form => $form ); } Then you could just pass in the item_id when the form is processed. return unless $c->stash->{form}->process( item_id => $id ); =head2 Putting a form in a Moose attribute You can also put your form in a Moose attribute in the controller. package MyApp::Controller::Book; use Moose; BEGIN { extends 'Catalyst::Controller'; } use MyApp::Form::Book; has 'edit_form' => ( isa => 'MyApp::Form::Book', is => 'rw', lazy => 1, default => sub { MyApp::Form::Book->new } ); Then you can process the form in your actions with C<< $self->edit_form->process( params => $c->req->body_parameters ); >> or C<< my $result = $self->edit_form->run( params => $c->req->body_parameters ); >>. =head2 Using HTML::FillInForm If you want to use L to fill in values instead of doing it in directly in a template using either the field or the form 'fif' methods, you can use L on your view class: package MyApp::View::TT; use Moose; with 'Catalyst::View::FillInForm'; .... 1; and set the 'fif' hash in the 'fillinform' stash variable: $self->form->process( ... ); $c->stash( fillinform => $self->form->fif ); return unless $form->validated; When the 'fillinform' stash variable is set, HTML::FillInForm will automatically be used by your view to fill in the form values. This can be very helpful when you want to build your forms by hand, or when you have legacy forms that you're just trying to hook up to FormHandler. =head2 The Catalyst context FormHandler has a 'ctx' attribute that can be used to set the Catalyst context (or anything you want, really). But if you can avoid passing in the context, you should do so, because you're mixing up your MVC and it makes it much more difficult to test your forms. But if you need to do it, you can: my $form = MyApp::Form->new( ctx => $c ); Usually you should prefer to add new attributes to your form: package MyApp::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has 'user_id' => ( is => 'rw' ); has 'hostname' => ( is => 'rw' ); has 'captcha_store' => ( is => 'rw' ); .... 1; Then just pass the attributes in on new: my $form => MyApp::Form->new( user_id => $c->user->id, hostname => $c->req->host, captcha_store => $c->{session}->{captcha} ); Or set them using accessors: $form->user_id( $c->user->id ); $form->hostname( $c->req->host ); $form->captcha_store( $c->{session}->{captcha} ); Then you can access these attributes in your form validation methods: sub validate_selection { my ( $self, $field ) = @_; if( $field->value eq 'something' && $self->hostname eq 'something_else' ) { $field->add_error("some error message" ); } } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Cookbook.pod100644000770000024 6565112576552253 23721 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Cookbook; # ABSTRACT: FormHandler use recipes __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Cookbook - FormHandler use recipes =head1 VERSION version 0.40064 =head1 SYNOPSIS L Collection of use recipes for L =head2 No form file, no template file... I had to create a tiny little form this week for admins to enter a comment, and it seemed silly to have to create a form file and a template file. I remembered that you can set the TT 'template' to a string reference and not use a template at all, which is nice when FormHandler will create the form HTML for you anyway. sub comment : Chained('base_sub') PathPart('comment') Args(0) { my ( $self, $c ) = @_; my $form = HTML::FormHandler->new( field_list => [ comment => { type => 'Text', size => 60 }, submit => {type => 'Submit'} ] ); $form->process($c->req->params); if ( $form->validated ) { $self->admin_log( $c, "Admin::Queue", "admin comment", $form->field('comment')->value ); $c->flash( message => 'Comment added' ); $c->res->redirect( $c->stash->{urilist}->{view} ); } my $rendered_form = $form->render; $c->stash( template => \$rendered_form ); } This creates the form on the fly with a comment field and a submit button, renders it using the default TT wrappers, then logs the comment. No other files at all.... FormHandler isn't really necessary for validation here, but it does make it possible to have a simple, standalone method. =head2 Dynamically change the active fields A common use case is for forms with some fields that should be displayed in some circumstances and not in others. There are a number of ways to do this. One way is to use the 'field_list' method: sub field_list { my $self = shift; my @fields; return \@fields; } This only happens at form construction time, however. Another method that works is to define all of the possible fields in your form, and mark some of them 'inactive'; package MyApp::Variable::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar' => ( inactive => 1 ); 1; Set to 'active' or 'inactive' on the 'process' call: $form->process( params => $params, active => ['foo', 'bar'] ); ... $form->process( params => $params, inactive => ['bar'] ); If you need to check some other state to determine whether or not a field should be active, you can do that using a Moose method modifier on 'set_active': before 'set_active' => sub { my $self = shift; $self->active(['foo', bar']) if ( ); }; Fields set to active/inactive on the 'process' call are automatically set back to inactive when the form is cleared, so there's no need to reset. If you want the fields activated for the life of an object, set active on new: my $form = MyApp::Form::User->new( active => ['opt_in', 'active']); =head2 Add custom attributes to FormHandler fields If you want to add custom attributes to the FormHandler fields but don't want to subclass all the fields, you can apply a role containing the new attributes to an L in your form. Use 'traits' on the individual fields to apply a role to field instances. Use the form attribute 'field_traits' to apply a role to all field instances in the form. package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( traits => ['MyApp::TraitFor::Test'] ); has '+field_traits' => ( default => sub { ['Some::Trait', 'Another::Trait'] } ); Or set the traits on new: my $form = MyApp::Form::User->new( field_traits => ['MyApp::TraitFor::Test'] ); my $form = MyApp::Form::User->new( field_list => [ '+foo' => { traits => [...] } ]); To apply the role to a field base class, use 'apply_traits' on that class: HTML::FormHandler::Field->apply_traits( 'Some::Test' ); HTML::FormHandler::Field::Text->apply_traits( 'Another::Trait' ); =head2 Select lists If you want to set the default value of a select field to 0, you can just use 'default' on the field: has_field 'license' => ( default => 0 ); If there is logic involved, you can use a 'default_' method: sub default_license { my ( $self, $field, $item ) = @_; return 0 unless $item && $item->license_id; return $item->license_id; } If the table defining the choices for a select list doesn't include a 'no choice' choice, you can set 'empty_select' in your field if you are using FormHandler rendering: has_field 'subject_class' => ( type => 'Select', empty_select => '--- Choose Subject Class ---' ); Or you can do in a template: [% f = form.field('subject_class') %] You can create a custom select list in an 'options_' method: sub options_country { my $self = shift; return unless $self->schema; my @rows = $self->schema->resultset( 'Country' )-> search( {}, { order_by => ['rank', 'country_name'] } )->all; return [ map { $_->digraph, $_->country_name } @rows ]; } =head2 The database and FormHandler forms If you have to process the input data before saving to the database, and this is something that would be useful in other places besides your form, you should do that processing in the DBIx::Class result class. If the pre-processing is only relevant to HTML form input, you might want to do it in the form by setting a flag to prevent database updates, performing the pre-processing, and then updating the database yourself. has_field 'my_complex_field' => ( type => 'Text', noupdate => 1 ); The 'noupdate' flag is set in order to skip an attempt to update the database for this field (it would not be necessary if the field doesn't actually exist in the database...). You can process the input for the non-updatable field field in a number of different places, depending on what is most logical. Some of the choices are: 1) validate (for the form or field) 2) validate_model 3) update_model When the field is flagged 'writeonly', the value from the database will not be used to fill in the form (put in the C<< $form->fif >> hash, or the field C<< $field->fif >>), but a value entered in the form WILL be used to update the database. If you want to enter fields from an additional table that is related to this one in a 'single' relationship, you can use the DBIx::Class 'proxy' feature to create accessors for those fields. =head2 Set up form base classes or roles for your application You can add whatever attributes you want to your form classes. Maybe you want to save a title, or a particular navigation widget. You could even save bits of text, or retrieve them from the database. package MyApp::Form::Base; use Moose; extends 'HTML::FormHandler::Model::DBIC'; has 'title' => ( isa => 'Str', is => 'rw' ); has 'nav_bar' => ( isa => 'Str', is => 'rw' ); has_block 'reg_header' => ( tag => 'fieldset', label => 'Registration form', content => 'We take your membership seriously...' ); sub summary { my $self = shift; my $schema = $self->schema; my $text = $schema->resultset('Summary')->find( ... )->text; return $text; } 1; Then: package MyApp::Form::Whatsup; use Moose; extends 'MyApp::Form::Base'; has '+title' => ( default => 'This page is an example of what to expect...' ); has '+nav_bar' => ( default => ... ); ... 1; And in the template:

[% form.title %]

[% form.nav_bar %] [% form.block('reg_header')->render %]

Summary: [% form.summary %]

Or you can make these customizations Moose roles. package MyApp::Form::Role::Base; use Moose::Role; ... package MyApp::Form::Whatsup; use Moose; with 'MyApp::Form::Role::Base'; ... =head2 Split up your forms into reusable pieces An address field: package Form::Field::Address; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'street'; has_field 'city'; has_field 'state' => ( type => 'Select', options_method => \&options_state ); has_field 'zip' => ( type => '+Zip' ); sub options_state { ... } no HTML::FormHandler::Moose; 1; A person form that includes an address field: package Form::Person; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+widget_name_space' => ( default => sub {['Form::Field']} ); has_field 'name'; has_field 'telephone'; has_field 'email' => ( type => 'Email' ); has_field 'address' => ( type => 'Address' ); sub validate_name { .... } no HTML::FormHandler::Moose; 1; Or you can use roles; package Form::Role::Address; use HTML::FormHandler::Moose::Role; has_field 'street'; has_field 'city'; has_field 'state' => ( type => 'Select' ); has_field 'zip' => ( type => '+Zip' ); sub options_state { ... } no HTML::FormHandler::Moose::Role; 1; You could make roles that are collections of validations: package Form::Role::Member; use Moose::Role; sub check_zip { ... } sub check_email { ... } 1; And if the validations apply to fields with different names, specify the 'validate_method' on the fields: with 'Form::Role::Member'; has_field 'zip' => ( type => 'Integer', validate_method => \&check_zip ); =head2 Access a user record in the form You might need the user_id to create specialized select lists, or do other form processing. Add a user_id attribute to your form: has 'user_id' => ( isa => 'Int', is => 'rw' ); Then pass it in when you process the form: $form->process( item => $item, params => $c->req->parameters, user_id => $c->user->user_id ); =head2 Handle extra database fields If there is another database field that needs to be updated when a row is created, add an attribute to the form, and then process it with C< before 'update_model' >. In the form: has 'hostname' => ( isa => 'Int', is => 'rw' ); before 'update_model' => sub { my $self = shift; $self->item->hostname( $self->hostname ); }; Then just use an additional parameter when you create/process your form: $form->process( item => $item, params => $params, hostname => $c->req->host ); Some kinds of DB relationships need to have primary keys which might be more easily set in the update_model method; sub update_model { my $self = shift; my $values = $self->values; $values->{some_field}->{some_key} = 'some_value'; $self->_set_value($values); $self->next::method; } If you need to access a database field in order to create the value for a form field you can use a C< default_* > method. sub default_myformfield { my ($self, $field, $item) = @_; return unless defined $item; my $databasefield = $item->databasefield; my $value = ... # do stuff return $value; } =head2 Additional changes to the database If you want to do additional database updates besides the ones that FormHandler does for you, the best solution would generally be to add the functionality to your result source or resultset classes, but if you want to do additional updates in a form you should use an 'around' method modifier and a transaction: around 'update_model' => sub { my $orig = shift; my $self = shift; my $item = $self->item; $self->schema->txn_do( sub { $self->$orig(@_); }); }; =head2 Doing cross validation in roles In a role that handles a number of different fields, you may want to perform cross validation after the individual fields are validated. In the form you could use the 'validate' method, but that doesn't help if you want to keep the functionality packaged in a role. Instead you can use the 'after' method modifier on the 'validate' method: package MyApp::Form::Roles::DateFromTo; use HTML::FormHandler::Moose::Role; has_field 'date_from' => ( type => 'Date' ); has_field 'date_to' => ( type => 'Date' ); after 'validate' => sub { my $self = shift; $self->field('date_from')->add_error('From date must be before To date') if $self->field('date_from')->value gt $self->field('date_to')->value; }; =head2 Changing required flag Sometimes a field is required in one situation and not required in another. You can use a method modifier before 'validate_form': before 'validate_form' => sub { my $self = shift; my $required = 0; $required = 1 if( $self->params->{field_name} eq 'something' ); $self->field('some_field')->required($required); }; This happens before the fields contain input or values, so you would need to look at the param value. If you need the validated value, it might be better to do these sort of checks in the form's 'validate' routine. sub validate { my $self = shift; $self->field('dependent_field')->add_error("Field is required") if( $self->field('some_field')->value eq 'something' && !$self->field('dependent_field')->has_value); } In a Moose role you would need to use a method modifier instead. after 'validate' => sub { ... }; Don't forget the dependency list, which is used for cases where if any of one of a group of fields has a value, all of the fields are required. =head2 Supply an external coderef for validation There are situations in which you need to use a subroutine for validation which is not logically part of the form. It's possible to pass in a context or other sort of pointer and call the routine in the form's validation routine, but that makes the architecture muddy and is not a clear separation of concerns. This is an example of how to supply a coderef when constructing the form that performs validation and can be used to set an appropriate error using L. (Thanks to Florian Ragwitz for this excellent idea...) Here's the form: package SignupForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has check_name_availability => ( traits => ['Code'], isa => 'CodeRef', required => 1, handles => { name_available => 'execute', }, ); has_field 'name'; has_field 'email'; sub validate { my $self = shift; my $name = $self->value->{name}; if ( defined $name && length $name && !$self->name_available($name) ) { $self->field('name')->add_error('That name is taken already'); } } 1; And here's where the coderef is passed in to the form. package MyApp::Signup; use Moose; has 'form' => ( is => 'ro', builder => 'build_form' ); sub build_form { my $self = shift; return SignupForm->new( { check_name_availability => sub { my $name = shift; return $self->username_available($name); }, } ); } sub username_available { my ( $self, $name ) = @_; # perform some sort of username availability checks } 1; =head2 Example of a form with custom database interface The default DBIC model requires that the form structure match the database structure. If that doesn't work - you need to present the form in a different way - you may need to fudge it by creating your own 'init_object' and doing the database updates in the 'update_model' method. Here is a working example for a 'family' object (equivalent to a 'user' record') that has a relationship to permission type roles in a relationship 'user_roles'. package My::Form::AdminRoles; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has 'schema' => ( is => 'ro', required => 1 ); # Note 1 has '+widget_wrapper' => ( default => 'None' ); # Note 2 has_field 'admin_roles' => ( type => 'Repeatable' ); # Note 3 has_field 'admin_roles.family' => ( type => 'Hidden' ); # Note 4 has_field 'admin_roles.family_id' => ( type => 'PrimaryKey' ); # Note 5 has_field 'admin_roles.admin_flag' => ( type => 'Boolean', label => 'Admin' ); # Note 6 sub init_object { my $self = shift; my @is_admin; my @is_not_admin; my $active_families = $self->schema->resultset('Family')->search( { active => 1 } ); while ( my $fam = $active_families->next ) { my $admin_flag = $fam->search_related('user_roles', { role_id => 2 } )->count > 0 ? 1 : 0; my $family_name = $fam->name1 . ", " . $fam->name2; my $elem = { family => $family_name, family_id => $fam->family_id, admin_flag => $admin_flag }; if( $admin_flag ) { push @is_admin, $elem; } else { push @is_not_admin, $elem; } } # Note 7 # sort into admin flag first, then family_name @is_admin = sort { $a->{family} cmp $b->{family} } @is_admin; @is_not_admin = sort { $a->{family} cmp $b->{family} } @is_not_admin; return { admin_roles => [@is_admin, @is_not_admin] }; } # Note 8 sub update_model { my $self = shift; my $families = $self->schema->resultset('Family'); my $family_roles = $self->value->{admin_roles}; foreach my $elem ( @{$family_roles} ) { my $fam = $families->find( $elem->{family_id} ); my $has_admin_flag = $fam->search_related('user_roles', { role_id => 2 } )->count > 0; if( $elem->{admin_flag} == 1 && !$has_admin_flag ) { $fam->create_related('user_roles', { role_id => 2 } ); } elsif( $elem->{admin_flag} == 0 && $has_admin_flag ) { $fam->delete_related('user_roles', { role_id => 2 } ); } } } Note 1: This form creates its own 'schema' attribute. You could inherit from L, but you won't be using its update code, so it wouldn't add much. Note 2: The form will be displayed with a template that uses 'bare' form input fields, so 'widget_wrapper' is set to 'None' to skip wrapping the form inputs with divs or table elements. Note 3: This form consists of an array of elements, so there will be a single Repeatable form field with subfields. If you wanted to use automatic rendering, you would also need to create a 'submit' field, but in this case it will just be done in the template. Note 4: This field is actually going to be used for display purposes only, but it's a hidden field because otherwise the information would be lost when displaying the form from parameters. For this case there is no real 'validation' so it might not be necessary, but it would be required if the form needed to be re-displayed with error messages. Note 5: The 'family_id' is the primary key field, necessary for updating the correct records. Note 6: 'init_object' method: This is where the initial object is created, which takes the place of a database row for form creation. Note 7: The entries with the admin flag turned on are sorted into the beginning of the list. This is entirely a user interface choice. Note 8: 'update_model' method: This is where the database updates are performed. The Template Toolkit template for this form:

Update admin status for members

/, 'field has table wrapper'); $form->process($params); my $outputT = $form->render; ok( $outputT, 'output from table rendering' ); done_testing; check_I18N.pl100755000770000024 300612576552253 17612 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/util#!/usr/bin/env perl #============================================================ # util/check_I18N.pl # # pull messages file, and check the I18N lexicons for # coverage #============================================================ use strict; use warnings; use utf8; use Encode; use Cwd; use File::Find; use Class::Load ':all'; use Data::Dumper; use lib ( getcwd() . '/lib'); use HTML::FormHandler::I18N; my @directories = ( getcwd() . "/lib/HTML/FormHandler/I18N" ); my @lexicons; find(\&wanted, @directories); my $infile = getcwd() . '/util/messages'; open( my $fh, '<:utf8', $infile ) or die "Unable to open $infile"; my $line = 1; my @lines = <$fh>; my $msgs_from_file = join( ' ', @lines ); my $messages = eval $msgs_from_file; my @builtin_messages = map { values %{$_} } (map { values %{$_}} @$messages); binmode STDOUT, ":utf8"; foreach my $lexicon (@lexicons) { print "\n\n========== $lexicon ================\n"; my $lh = HTML::FormHandler::I18N->get_handle($lexicon); foreach my $msg (@builtin_messages) { my $translated = $lh->maketext($msg, '[_1]', '[_2]'); print $msg, " ==> ", $translated, "\n"; } } # you can pull in the arrayref of hashrefs that's written out #my $recovered = eval $output; sub wanted { my $type = $_; return if $type eq '.'; $type =~ s/\.pm$//; my $class = "HTML::FormHandler::I18N::$type"; if( try_load_class( $class ) ) { push @lexicons, $type; print "$type\n"; } else { print "did not load $type\n"; } } custom_fields.t100644000770000024 432612576552253 20147 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse strict; use warnings; use Test::More; { package Test::MonthYear; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'my_date' => ( type => 'DateTime' ); has_field 'my_date.month' => ( type => 'Month' ); has_field 'my_date.year' => ( type => 'Year' ); has_field 'submit' => ( type => 'Submit' ); } my $form = Test::MonthYear->new; ok( $form, 'form builds' ); my $rendered_form = $form->render; { package Test::Field::MonthYear; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::DateTime'; has_field 'month' => ( type => 'Month' ); has_field 'year' => ( type => 'Year' ); } { package Test::Widget::Field::MonthYear; use Moose::Role; sub render { my $self = shift; return '

Create your rendering here...

'; } } { package Test::Form::MonthYearField; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+field_name_space' => ( default => 'Test::Field' ); has '+widget_name_space' => ( default => sub { ['Test::Widget'] } ); has_field 'my_date' => ( type => '+MonthYear', widget => 'MonthYear' ); } $form = Test::Form::MonthYearField->new; ok( $form, 'form builds' ); ok( $form->field('my_date'), 'the field is there' ); is( $form->field('my_date')->render, '

Create your rendering here...

', 'renders ok' ); { package Test2::Widget::Field::SimpleWidget; use Moose::Role; sub render { "I'am simple widget" } } { package Test2::Field::CustomWidgetCompoundField; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'my_text' => ( type => 'Text', widget => 'SimpleWidget' ); } { package Test2::Form::Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+field_name_space' => ( default => sub { 'Test2::Field' } ); has '+widget_name_space' => ( default => sub { ['Test2::Widget'] } ); has_field 'test' => ( type => '+CustomWidgetCompoundField' ); } { my $form = Test2::Form::Compound->new; ok( $form, 'form builds' ); ok( $form->field('test.my_text'), 'the field is there' ); is( $form->field('test.my_text')->render, "I'am simple widget", 'renders ok'); } done_testing; bootstrap000755000770000024 012576552253 16602 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 700712576552253 20214 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrapuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Basic::Theme; use Moose::Role; # make a wrapper around the form sub build_do_form_wrapper {1} # set the class for the form wrapper sub build_form_wrapper_class { ['span9'] } # set the class for the form element sub build_form_element_class { ['well'] } # set various rendering tags sub build_form_tags { { wrapper_tag => 'div', before => qq{

With v2.0, we have lighter and smarter defaults for form styles. No extra markup, just form controls.

\n}, after => '
', } } # the settings in 'build_update_subfields' are merged with the field # definitions before they are constructed sub build_update_subfields {{ # all fields have a label but no wrapper all => { do_wrapper => 0, do_label => 1 }, # set the element class, a placeholder in element_attr foo => { element_class => ['span3'], element_attr => { placeholder => 'Type something…' }, tags => { after_element => qq{\nAssociated help text!} } }, bar => { option_label => 'Check me out', label_class => ['checkbox'], do_label => 0 }, submit_btn => { element_class => ['btn'] }, }} } { package MyApp::Form::Basic; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'MyApp::Form::Basic::Theme'; with 'HTML::FormHandler::Widget::Theme::BootstrapFormMessages'; has '+name' => ( default => 'basic_form' ); has_field 'foo' => ( type => 'Text' ); has_field 'bar' => ( type => 'Checkbox' ); has_field 'submit_btn' => ( type => 'Submit', value => 'Submit', widget => 'ButtonTag' ); } my $form = MyApp::Form::Basic->new; ok( $form, 'form built' ); $form->process({}); my $rendered = $form->render; my $expected = '

With v2.0, we have lighter and smarter defaults for form styles. No extra markup, just form controls.

Associated help text!
'; is_html($rendered, $expected, 'rendered correctly'); # check foo $rendered = $form->field('foo')->render; $expected = ' Associated help text!'; is_html($rendered, $expected, 'foo field is correct' ); # check bar $rendered = $form->field('bar')->render; $expected = ''; is_html($rendered, $expected, 'bar field is correct' ); $form->process( params => {}, info_message => 'Fill in the form!' ); $rendered = $form->render_form_messages; $expected = '
Fill in the form!'; is_html($rendered, $expected, 'info message rendered ok' ); done_testing; other.t100644000770000024 176112576552253 20255 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrapuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+widget_wrapper' => ( default => 'Bootstrap' ); has_field 'foo' => ( type => 'Hidden' ); has_field 'bar' => ( tags => { before_element_inside_div => '

Start

', after_element => '

End

', } ); } my $form = MyApp::Form::Test->new; ok( $form ); my $rendered = $form->field('foo')->render; my $expected = '
'; is_html( $rendered, $expected, 'rendered ok' ); $rendered = $form->field('bar')->render; $expected = '

Start

End

'; is_html( $rendered, $expected, 'tags rendered ok' ); done_testing; select.t100644000770000024 223212576552253 20214 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/compounduse strict; use warnings; use Test::More; { package Test::Field::MyComp; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'flim' => ( type => 'Select', options_method => \&options_flim ); has_field 'flam' => ( type => 'Multiple', options_method => \&options_flam ); has_field 'flot'; sub options_flim { my $self = shift; return [ { value => 1, label => 'one' }, { value => 2, label => 'two' } ]; } sub options_flam { my $self = shift; return [ { value => 1, label => 'red' }, { value => 2, label => 'blue' } ]; } } { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+field_name_space' => ( default => sub { [ 'Test::Field' ] } ); has_field 'floo' => ( type => 'MyComp' ); has_field 'ploot'; } my $form = Test::Form->new; ok( $form, 'form built' ); my $flim_options = $form->field('floo.flim')->options; is( scalar @$flim_options, 2, 'right number of flim options' ); my $flam_options = $form->field('floo.flam')->options; is( scalar @$flam_options, 2, 'right number of flam options' ); done_testing; compound.t100644000770000024 364412576552253 20261 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/errorsuse strict; use warnings; use Test::More; # shows behavior of required flag in compound fields { package MyApp::Form::User; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'userform' ); has_field 'name'; has_field 'email'; has_field 'address' => ( type => 'Compound' ); has_field 'address.city' => ( required => 1 ); has_field 'address.state' => ( required => 1 ); } my $form = MyApp::Form::User->new; my $params = { name => 'John Doe', email => 'jdoe@gmail.com', }; # no errors if compound subfields are required but missing # and compound field is not required $form->process( params => $params ); ok( $form->validated, 'no errors in form' ); # error if one field is entered and not the other # and compound field is not required $form->process( params => { %$params, 'address.city' => 'New York' } ); ok( $form->has_errors, 'error with one field filled' ); # errors if compound subfields are required & compound is required $form->process( update_field_list => { address => { required => 1 } }, params => $params ); ok( $form->has_errors, 'errors in form' ); # tests that errors are propagated up the tree, and aren't duplicated { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'name'; has_field 'comp1' => ( type => 'Compound' ); has_field 'comp1.comment'; has_field 'comp1.comp2' => ( type => 'Compound' ); has_field 'comp1.comp2.one'; has_field 'comp1.comp2.two' => ( type => 'PosInteger' ); } $form = MyApp::Form::Test->new; ok( $form ); $form->process; $params = { name => 'test', 'comp1.comment' => 'This is a test', 'comp1.comp2.one' => 1, 'comp1.comp2.two' => 'abc', }; $form->process( params => $params ); ok( $form->has_errors, 'form has errors' ); my @errors = $form->errors; is( scalar @errors, 2, 'right number of errors' ); done_testing; messages.t100644000770000024 102112576552253 20227 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/errorsuse strict; use warnings; use Test::More; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_messages { { required => 'You must supply this field', } } has_field 'foo' => ( type => 'Text', required => 1 ); has_field 'bar'; } my $form = Test::Form->new; ok( $form, 'form built'); $form->process( params => { bar => 1} ); my @errors = $form->errors; is( $errors[0], 'You must supply this field', 'form has errors' ); done_testing; password.t100644000770000024 621012576552253 20221 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use lib 't/lib'; use_ok( 'HTML::FormHandler::Field::Text' ); my $field = HTML::FormHandler::Field::Text->new( name => 'password', type => 'Text', required => 1, password => 1, ); $field->build_result; is( $field->password, 1, 'password is set'); $field->_set_value('abcdef'); is( $field->value, 'abcdef', 'set and get value' ); is( $field->fif, '', 'no fif for password'); $field = HTML::FormHandler::Field::Text->new( name => 'not_password', type => 'Text', required => 1, ); $field->build_result; is( $field->password, undef, 'password is not set'); $field->_set_value('abcdef'); is( $field->value, 'abcdef', 'set and get value' ); is( $field->fif, 'abcdef', 'get fif'); use HTML::FormHandler; use_ok( 'HTML::FormHandler::Field::Password' ); { package My::Form; use Moose; extends 'HTML::FormHandler'; sub field_list { return [ login => 'Text', username => 'Text', password => { type => 'Password', ne_username => 'username', minlength => 6, }, ]; } } my $form = My::Form->new; $field = $form->field('password'); my $params = { username => 'my4username', password => 'something' }; $form->process( $params ); ok( $field, 'got password field' ); $field->_set_input( '2192ab201def' ); $field->validate_field; ok( !$field->has_errors, 'Test for errors 1' ); $field->_set_input( 'ab1' ); $field->validate_field; ok( $field->has_errors, 'too short' ); $field->_set_input( 'my4username' ); $field->validate_field; ok( $field->has_errors, 'matches username' ); $field->_set_input( '' ); $field->validate_field; ok( !$field->has_errors, 'empty password accepted' ); is($field->noupdate, 1, 'noupdate has been set on password field' ); my $pass = 'my4user5name'; $field->_set_input( $pass ); $field->validate_field; ok( !$field->has_errors, 'just right' ); is ( $field->value, $pass, 'Input and value match' ); { package Password::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+field_name_space' => ( default => 'Field' ); has_field 'password' => ( type => 'Password', required => 1 ); has_field '_password' => ( type => 'PasswordConf', messages => { required => 'You must enter the password a second time' }, ); } $form = Password::Form->new; ok( $form, 'form created' ); $params = { password => '', _password => '', }; $form->process( params => $params ); ok( !$form->validated, 'form validated' ); ok( !$form->field('password')->noupdate, q[noupdate is 'false' on password field] ); ok( $form->field('_password')->has_errors, 'Password confirmation has errors' ); is( $form->field('_password')->errors->[0], 'You must enter the password a second time' ); $form->process( params => { password => 'aaaaaa', _password => 'bbbb' } ); ok( $form->field('_password')->has_errors, 'Password confirmation has errors' ); $form->process( params => { password => 'aaaaaa', _password => 'aaaaaa' } ); ok( $form->validated, 'password confirmation validated' ); done_testing; no_extend.t100644000770000024 133312576552253 20217 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/mooseuse strict; use warnings; use Test::More; use Test::Exception; use lib 't/lib'; { package Test::ExtForm; use Moose; extends 'HTML::FormHandler'; use HTML::FormHandler::Moose; has_field 'foo'; has_field 'bar'; } { package Test::SubExtForm; use Moose; extends 'Test::ExtForm'; use HTML::FormHandler::Moose; has_field 'fubar'; } dies_ok( sub { require Form::NoExtForm; }, 'dies when not extending' ); my $form = Test::ExtForm->new; ok($form, 'got a HFH object'); $form = Test::NoExtForm->new; ok($form, 'got a no-HFH object'); $form = Test::SubExtForm->new; ok($form, 'got an subclassed form'); $form = Test::SubExtForm->new; ok($form, 'got a second subclassed form'); done_testing; checkbox.t100644000770000024 515112576552253 20161 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'option1' => ( type => 'Checkbox', do_label => 0 ); has_field 'option2' => ( type => 'Checkbox', do_label => 0, tags => { label_left => 1 } ); has_field 'option3' => ( type => 'Checkbox', option_label => 'Try this one' ); has_field 'option4' => ( type => 'Checkbox', tags => { no_wrapped_label => 1 } ); has_field 'option5' => ( type => 'Checkbox', widget_wrapper => 'None' ); has_field 'option6' => ( type => 'Checkbox', do_label => 0, do_wrapper => 0, label => 'Simple Checkbox' ); } my $form = Test::Form->new; $form->process; # single_label: label wraps input, label to right my $expected = '
'; my $rendered = $form->field('option1')->render; is_html( $rendered, $expected, 'standard Checkbox render ok' ); # single_label: label wraps input, label to left $expected = '
'; $rendered = $form->field('option2')->render; is_html( $rendered, $expected, 'Checkbox with label to left' ); # standard: checkbox with additional label (like Bootstrap) $expected = '
'; $rendered = $form->field('option3')->render; is_html( $rendered, $expected, 'Checkbox with two labels' ); # no wrapped label $expected = '
'; $rendered = $form->field('option4')->render; is_html( $rendered, $expected, 'Checkbox with no wrapped label'); # wrapper = 'None', input element only $expected = ''; $rendered = $form->field('option5')->render; is_html( $rendered, $expected, 'Checkbox with no wrapper and no label' ); # no wrapper $expected = ''; $rendered = $form->field('option6')->render; is_html( $rendered, $expected, 'checkbox with no wrapper, wrapped label' ); } done_testing; compound.t100644000770000024 571712576552253 20227 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Theme::Basic; use Moose::Role; sub build_do_form_wrapper {1} sub build_form_tags {{ wrapper_tag => 'div' }} sub build_update_subfields {{ all => { tags => { label_tag => 'span' } }, by_flag => { 'compound' => { do_wrapper => 1, do_label => 1, tags => { wrapper_tag => 'span' }}}, }} sub html_attributes { my ( $self, $field, $type, $attr ) = @_; $attr->{class} = ['frm', 'ele'] if $type eq 'element'; $attr->{class} = ['frm', 'lbl'] if $type eq 'label'; $attr->{class} = ['frm', 'wrp'] if $type eq 'wrapper'; return $attr; } } { package MyApp::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'MyApp::Form::Theme::Basic'; has_field 'my_comp' => ( type => 'Compound' ); has_field 'my_comp.one'; has_field 'my_comp.two'; has_field 'my_text' => ( type => 'Text' ); } my $form = MyApp::Form->new; my $rendered = $form->field('my_comp')->render; my $expected = ' My comp
One
Two
'; is_html( $rendered, $expected, 'compound rendered ok' ); { package Test::DT; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_update_subfields {{ all => { tags => { label_after => ': ' }}}} has_field 'start_date' => ( type => 'DateTime', do_wrapper => 1, do_label => 1, tags => { wrapper_tag => 'fieldset' }, wrapper_class => 'start_date' ); has_field 'start_date.month' => ( type => 'Integer', range_start => 1, range_end => 12 ); has_field 'start_date.day' => ( type => 'Integer', range_start => 1, range_end => 31 ); has_field 'start_date.year' => ( type => 'Integer', range_start => 2000, range_end => 2020 ); } $form = Test::DT->new; my $params = { 'start_date.month' => 7, 'start_date.day' => 14, 'start_date.year' => '2006' }; $form->process( $params ); $rendered = $form->field('start_date')->render; is_html( $rendered, '
Start date
', 'output from DateTime' ); done_testing; escaping.t100644000770000024 1302112576552253 20177 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use HTML::FormHandler::Field::Text; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::Simple'; sub build_update_subfields {{ all => { do_wrapper => 1, tags => { label_after => ': ' }}, by_flag => { compound => { do_wrapper => 1 }}, }} sub build_do_form_wrapper {1} sub build_form_wrapper_class { 'form_wrapper' } has '+name' => ( default => 'testform' ); has_field 'test_field' => ( size => 20, label => '"TEST"', id => 'f99', ); has_field 'number'; has_field 'fruit' => ( type => 'Select' ); has_field 'vegetables' => ( type => 'Multiple' ); has_field 'opt_in' => ( type => 'Select', widget => 'RadioGroup', options => [{ value => 0, label => ''}, { value => 1, label => ''} ] ); has_field 'active' => ( type => 'Checkbox' ); has_field 'comments' => ( type => 'TextArea' ); has_field 'hidden' => ( type => 'Hidden' ); has_field 'selected' => ( type => 'Boolean' ); has_field 'two_errors' => ( apply => [ { check => [ ], message => 'First constraint error' }, { check => [ ], message => 'Second constraint error' } ] ); has_field 'submit' => ( type => 'Submit', value => 'Update' ); has '+dependency' => ( default => sub { [ ['start_date.month', 'start_date.day', 'start_date.year'] ] } ); has_field 'no_render' => ( widget => 'NoRender' ); sub options_fruit { return ( 1 => '"apples"', 2 => '', 3 => '&kiwi&', ); } sub options_vegetables { return ( 1 => '', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } } my $form = Test::Form->new; ok( $form, 'create form'); my $params = { test_field => 'something
', number => 0, fruit => 2, vegetables => [2,4], active => 'now', comments => 'Four score and seven years ago...', hidden => '<1234>', selected => '1', two_errors => 'aaa', opt_in => 0, }; $form->process( $params ); is_html( $form->render_field( $form->field('number') ), '
', "value '0' is rendered" ); my $rendered = $form->render_field( $form->field('test_field') ); my $expected = '
'; is_html( $rendered, $expected, 'output from text field'); is_html( $form->field('test_field')->render, $rendered, 'text field with widgets' ); $rendered = $form->render_field( $form->field('fruit') ); $expected = '
'; is_html( $rendered, $expected, 'output from select field'); $rendered = $form->render_field( $form->field('vegetables') ); is_html( $rendered, '
', 'output from select multiple field'); $rendered = $form->render_field( $form->field('active') ); is_html( $rendered, '
', 'output from checkbox field'); $rendered = $form->render_field( $form->field('comments') ); is_html( $rendered, '
', 'output from textarea' ); $rendered = $form->render_field( $form->field('hidden') ); is_html( $rendered, '
', 'output from hidden field' ); $rendered = $form->render_field( $form->field('selected') ); is_html( $rendered, '
', 'output from boolean' ); $rendered = $form->render_field( $form->field('submit') ); is_html( $rendered, q{
}, 'output from Submit'); $rendered = $form->render_field( $form->field('opt_in') ); is_html( $rendered, q{



}, 'output from radio group' ); $rendered = $form->render_start; is_html( $rendered, '
', 'Form start OK' ); my $output = $form->render; ok( $output, 'get rendered output from form'); is_html( $form->render_field( $form->field('no_render')), '', 'no_render' ); done_testing; optgroup.t100644000770000024 1303712576552253 20274 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; # tests rendering an optgroup { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'testop' => ( type => 'Select', multiple => 1, empty_select => '-- Choose --' ); sub options_testop { ( { group => 'First Group', options => [ { value => 1, label => 'One' }, { value => 2, label => 'Two' }, { value => 3, label => 'Three' }, ], }, { group => 'Second Group', options => [ { value => 4, label => 'Four' }, { value => 5, label => 'Five' }, { value => 6, label => 'Six' }, ], }, { value => '6a', label => 'SixA' }, { group => 'Third Group', options => [ { value => 7, label => 'Seven' }, { value => 8, label => 'Eight' }, { value => 9, label => 'Nine' }, ], }, ) } } my $form = MyApp::Form::Test->new; ok( $form, 'form built' ); $form->process ( { foo => 'my_foo', testop => 12 } ); ok( ! $form->validated, 'form validated' ); my $params = { foo => 'my_foo', testop => 8 }; $form->process( $params ); ok( $form->validated, 'form validated' ); my $rendered = $form->field('testop')->render; my $expected = '
'; is_html( $rendered, $expected, 'select rendered ok' ); $form = MyApp::Form::Test->new( update_subfields => { 'testop' => { widget => 'CheckboxGroup' } } ); $form->process( $params ); $rendered = $form->field('testop')->render; $expected = '
'; is_html( $rendered, $expected, 'checkboxgroup renders ok' ); $form = MyApp::Form::Test->new( update_subfields => { 'testop' => { widget => 'RadioGroup', multiple => 0 } } ); $form->process( $params ); $rendered = $form->field('testop')->render; $expected = '
'; is_html( $rendered, $expected, 'radiogroup renders ok' ); done_testing; hash.t100644000770000024 314412576552253 20143 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/repeatable use strict; use warnings; use Test::More; { package MyApp::Form::RepHash; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'lookup' => ( type => 'Repeatable', inflate_default_method => \&inflate_default, deflate_value_method => \&deflate_value, ); has_field 'lookup.key'; has_field 'lookup.value'; sub inflate_default { my ($self, $value) = @_; # convert hash to array of hashes # { k1 => v1, k2 => v2 } becomes # [ { key => k1, value => v1 }, { key => k2, value => v2 } ] return [map +{key => $_, value => $value->{$_}}, sort keys %$value]; } sub deflate_value { my ($self, $value) = @_; # convert array of hashes to hash # [ { key => k1, value => v1 }, { key => k2, value => v2 } ] becomes # { k1 => v1, k2 => v2 } return { map { ($_->{'key'} => $_->{'value'}) } @$value }; } no HTML::FormHandler::Moose; 1; } my $form = MyApp::Form::RepHash->new; ok( $form ); my $item = { 'lookup' => { 'k1' => 'v1', 'k2' => 'v2', } }; my $params = { 'lookup.0.key' => 'k1', 'lookup.0.value' => 'v1', 'lookup.1.key' => 'k2', 'lookup.1.value' => 'v2', }; my $inflated = { 'lookup' => [ { key => 'k1', value => 'v1' }, { key => 'k2', value => 'v2' }, ], }; { $form->process(item => $item); my $fif = $form->fif; my $value = $form->value; is_deeply( $fif, $params, 'fif is correct' ); is_deeply( $value, $inflated, 'value from item is correct' ); } { $form->process(params => $params); my $value = $form->value; is_deeply( $value, $item, 'value from params is correct' ); } done_testing; list.t100644000770000024 270712576552253 20177 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/repeatableuse strict; use warnings; use Test::More; use_ok('HTML::FormHandler::Field::Repeatable'); { package List::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'name'; has_field 'tags' => ( type => 'Repeatable' ); has_field 'tags.contains'; sub validate_tags_contains { my ( $self, $field ) = @_; if ( $field->value eq 'busybee' ) { $field->add_error('That tag is not allowed'); } } } my $form = List::Form->new; ok( $form, 'form created' ); # check for single empty repeatable $form->process; my $fif = { 'name' => '', 'tags.0' => '', }; is_deeply( $form->fif, $fif, 'fif ok' ); is_deeply( $form->value, {}, 'value ok' ); # empty arrayref for repeatable $fif->{name} = 'mary'; $form->process( $fif ); is_deeply( $form->value, { name => 'mary', tags => [] }, 'value is ok' ); my $params = { name => 'joe', tags => ['linux', 'algorithms', 'loops'], }; $form->process($params); ok( $form->validated, 'form validated' ); is( $form->field('tags')->field('0')->value, 'linux', 'get correct value' ); $fif = { 'name' => 'joe', 'tags.0' => 'linux', 'tags.1' => 'algorithms', 'tags.2' => 'loops', }; is_deeply( $form->fif, $fif, 'fif is correct' ); is_deeply( $form->values, $params, 'values are correct' ); $params = { name => 'sally', tags => ['busybee', 'sillysally', 'missymim'] }; $form->process($params); ok( $form->has_errors, 'form has errors' ); done_testing; compound.t100644000770000024 344512576552253 20262 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/resultuse strict; use warnings; use Test::More; my $struct = { username => 'Joe Blow', occupation => 'Programmer', tags => ['Perl', 'programming', 'Moose' ], employer => { name => 'TechTronix', country => 'Utopia', }, }; { package Structured::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'username'; has_field 'occupation'; has_field 'tags' => ( type => 'Repeatable' ); has_field 'tags.contains' => ( type => 'Text' ); has_field 'employer' => ( type => 'Compound' ); has_field 'employer.name'; has_field 'employer.country'; } my $form = Structured::Form->new; ok( $form, 'form created' ); $form->process( params => $struct ); ok( $form->validated, 'form validated'); is_deeply( $form->field('tags')->value, ['Perl', 'programming', 'Moose' ], 'list field tags has right values' ); my $result = $form->result; is( $result->num_results, 4, 'right number of results'); my $first_tag = $result->field('tags.0'); is( ref $first_tag, 'HTML::FormHandler::Field::Result', 'get result object'); is( $first_tag->value, 'Perl', 'result has right value' ); is( $first_tag->parent, $result->field('tags'), 'correct parent for '); my $employer = $result->field('employer'); my $employer_name = $result->field('employer.name'); is( $employer_name->parent, $employer, 'correct parent for compound field'); my $fif = { 'employer.country' => 'Utopia', 'employer.name' => 'TechTronix', 'occupation' => 'Programmer', 'tags.0' => 'Perl', 'tags.1' => 'programming', 'tags.2' => 'Moose', 'username' => 'Joe Blow' }; is_deeply( $form->fif, $fif, 'fif is correct' ); $result = $form->run( $fif ); ok( $result->validated, 'form processed from fif' ); is_deeply( $result->value, $struct, 'values round-tripped from fif'); done_testing; validation000755000770000024 012576552253 16717 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/twhen.t100644000770000024 207612576552253 20212 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/validationuse strict; use warnings; use Test::More; { package MyApp::Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'fee'; has_field 'fie' => ( apply => [ { when => { fee => 1 }, check => qr/when/, message => 'Wrong fie' }, ]); has_field 'fo'; has_field 'fum_comp' => ( type => 'Compound' ); has_field 'fum_comp.one' => ( apply => [ { when => { '+fee' => sub { $_[0] == 1 } }, check => qr/when/, message => 'Wrong one' }, ]); has_field 'fum_comp.two' => ( apply => [ { when => { '+fee' => [1,2,3] }, check => qr/when/, message => 'Wrong two' }, ]); } my $form = MyApp::Test::Form->new; ok( $form ); my $params = { fee => '', fie => 'where', fo => 'my_fo', 'fum_comp.one' => 2, 'fum_comp.two' => 'where', }; $form->process( $params ); ok( $form->validated ); $params->{fee} = 1; $form->process( $params ); ok( !$form->validated, 'validation failed for fie when fee is 1' ); my @errors = $form->errors; is( scalar @errors, 3, 'right number of errors' ); done_testing; multiple_forms.t100644000770000024 422212576552253 20343 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xtuse Test::More tests => 9; use_ok( 'HTML::FormHandler' ); { package My::Form::One; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; # this form specifies the form name has '+name' => ( default => 'One' ); has '+html_prefix' => ( default => 1 ); has_field 'field_one'; has_field 'field_two'; has_field 'field_three'; } my $form1 = My::Form::One->new; ok( $form1, 'get first form' ); { package My::Form::Two; use Moose; extends 'HTML::FormHandler'; # this form uses the default random form name generation has '+html_prefix' => ( default => 1 ); sub field_list { [ field_one => 'Text', field_two => 'Text', field_three => 'Text', ] } } my $form2 = My::Form::Two->new; ok( $form2, 'get second form' ); my $params = { 'One.field_one' => 'First field in first form', 'One.field_two' => 'Second field in first form', 'One.field_three' => 'Third field in first form', $form2->field('field_one')->html_name => 'First field in second form', $form2->field('field_two')->html_name => 'Second field in second form', $form2->field('field_three')->html_name => 'Third field in second form', }; $form1->process( $params ); ok( $form1->validated, 'validated first form' ); is( $form1->field('field_one')->value, 'First field in first form', 'value of field in first form is correct' ); my $fif_params = $form1->fif; is_deeply( $fif_params, { 'One.field_one' => 'First field in first form', 'One.field_two' => 'Second field in first form', 'One.field_three' => 'Third field in first form', }, 'fif params correct'); $form2->process( $params ); ok( $form2->validated, 'validated second form' ); is( $form2->field('field_three')->value, 'Third field in second form', 'value of field in second form is correct' ); $params = { 'One.field_one' => 'First field in first form', 'One.field_two' => 'Second field in first form', 'One.field_three' => 'Third field in first form', }; $form2 = My::Form::Two->new( params => $params ); ok( !$form2->has_params, 'has_params checks only params intented for the form'); release-no-tabs.t100644000770000024 1657012576552253 20124 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.05 use Test::More 0.88; use Test::NoTabs; my @files = ( 'lib/HTML/FormHandler.pm', 'lib/HTML/FormHandler/Base.pm', 'lib/HTML/FormHandler/Blocks.pm', 'lib/HTML/FormHandler/BuildFields.pm', 'lib/HTML/FormHandler/BuildPages.pm', 'lib/HTML/FormHandler/Field.pm', 'lib/HTML/FormHandler/Field/AddElement.pm', 'lib/HTML/FormHandler/Field/BoolSelect.pm', 'lib/HTML/FormHandler/Field/Boolean.pm', 'lib/HTML/FormHandler/Field/Button.pm', 'lib/HTML/FormHandler/Field/Captcha.pm', 'lib/HTML/FormHandler/Field/Checkbox.pm', 'lib/HTML/FormHandler/Field/Compound.pm', 'lib/HTML/FormHandler/Field/Date.pm', 'lib/HTML/FormHandler/Field/DateMDY.pm', 'lib/HTML/FormHandler/Field/DateTime.pm', 'lib/HTML/FormHandler/Field/Display.pm', 'lib/HTML/FormHandler/Field/Duration.pm', 'lib/HTML/FormHandler/Field/Email.pm', 'lib/HTML/FormHandler/Field/File.pm', 'lib/HTML/FormHandler/Field/Float.pm', 'lib/HTML/FormHandler/Field/Hidden.pm', 'lib/HTML/FormHandler/Field/Hour.pm', 'lib/HTML/FormHandler/Field/IntRange.pm', 'lib/HTML/FormHandler/Field/Integer.pm', 'lib/HTML/FormHandler/Field/Minute.pm', 'lib/HTML/FormHandler/Field/Money.pm', 'lib/HTML/FormHandler/Field/Month.pm', 'lib/HTML/FormHandler/Field/MonthDay.pm', 'lib/HTML/FormHandler/Field/MonthName.pm', 'lib/HTML/FormHandler/Field/Multiple.pm', 'lib/HTML/FormHandler/Field/Nested.pm', 'lib/HTML/FormHandler/Field/NoValue.pm', 'lib/HTML/FormHandler/Field/NonEditable.pm', 'lib/HTML/FormHandler/Field/Password.pm', 'lib/HTML/FormHandler/Field/PasswordConf.pm', 'lib/HTML/FormHandler/Field/PosInteger.pm', 'lib/HTML/FormHandler/Field/PrimaryKey.pm', 'lib/HTML/FormHandler/Field/Repeatable.pm', 'lib/HTML/FormHandler/Field/Repeatable/Instance.pm', 'lib/HTML/FormHandler/Field/Reset.pm', 'lib/HTML/FormHandler/Field/Result.pm', 'lib/HTML/FormHandler/Field/RmElement.pm', 'lib/HTML/FormHandler/Field/Second.pm', 'lib/HTML/FormHandler/Field/Select.pm', 'lib/HTML/FormHandler/Field/SelectCSV.pm', 'lib/HTML/FormHandler/Field/Submit.pm', 'lib/HTML/FormHandler/Field/Text.pm', 'lib/HTML/FormHandler/Field/TextArea.pm', 'lib/HTML/FormHandler/Field/TextCSV.pm', 'lib/HTML/FormHandler/Field/Upload.pm', 'lib/HTML/FormHandler/Field/Weekday.pm', 'lib/HTML/FormHandler/Field/Year.pm', 'lib/HTML/FormHandler/Fields.pm', 'lib/HTML/FormHandler/Foo.pm', 'lib/HTML/FormHandler/I18N.pm', 'lib/HTML/FormHandler/I18N/ar_kw.pm', 'lib/HTML/FormHandler/I18N/bg_bg.pm', 'lib/HTML/FormHandler/I18N/ca_es.pm', 'lib/HTML/FormHandler/I18N/cs_cz.pm', 'lib/HTML/FormHandler/I18N/de_de.pm', 'lib/HTML/FormHandler/I18N/en_us.pm', 'lib/HTML/FormHandler/I18N/es_es.pm', 'lib/HTML/FormHandler/I18N/hu_hu.pm', 'lib/HTML/FormHandler/I18N/it_it.pm', 'lib/HTML/FormHandler/I18N/ja_jp.pm', 'lib/HTML/FormHandler/I18N/pt_br.pm', 'lib/HTML/FormHandler/I18N/ru_ru.pm', 'lib/HTML/FormHandler/I18N/sv_se.pm', 'lib/HTML/FormHandler/I18N/tr_tr.pm', 'lib/HTML/FormHandler/I18N/ua_ua.pm', 'lib/HTML/FormHandler/InitResult.pm', 'lib/HTML/FormHandler/Manual.pod', 'lib/HTML/FormHandler/Manual/Catalyst.pod', 'lib/HTML/FormHandler/Manual/Cookbook.pod', 'lib/HTML/FormHandler/Manual/Database.pod', 'lib/HTML/FormHandler/Manual/Defaults.pod', 'lib/HTML/FormHandler/Manual/Errors.pod', 'lib/HTML/FormHandler/Manual/Fields.pod', 'lib/HTML/FormHandler/Manual/FromDFV.pod', 'lib/HTML/FormHandler/Manual/FromFF.pod', 'lib/HTML/FormHandler/Manual/InflationDeflation.pod', 'lib/HTML/FormHandler/Manual/Intro.pod', 'lib/HTML/FormHandler/Manual/Reference.pod', 'lib/HTML/FormHandler/Manual/Rendering.pod', 'lib/HTML/FormHandler/Manual/RenderingCookbook.pod', 'lib/HTML/FormHandler/Manual/Templates.pod', 'lib/HTML/FormHandler/Manual/Testing.pod', 'lib/HTML/FormHandler/Manual/Tutorial.pod', 'lib/HTML/FormHandler/Manual/Validation.pod', 'lib/HTML/FormHandler/Merge.pm', 'lib/HTML/FormHandler/Meta/Role.pm', 'lib/HTML/FormHandler/Model.pm', 'lib/HTML/FormHandler/Model/CDBI.pm', 'lib/HTML/FormHandler/Model/Object.pm', 'lib/HTML/FormHandler/Moose.pm', 'lib/HTML/FormHandler/Moose/Role.pm', 'lib/HTML/FormHandler/Page.pm', 'lib/HTML/FormHandler/Page/Simple.pm', 'lib/HTML/FormHandler/Pages.pm', 'lib/HTML/FormHandler/Params.pm', 'lib/HTML/FormHandler/Render/RepeatableJs.pm', 'lib/HTML/FormHandler/Render/Simple.pm', 'lib/HTML/FormHandler/Render/Table.pm', 'lib/HTML/FormHandler/Render/Util.pm', 'lib/HTML/FormHandler/Render/WithTT.pm', 'lib/HTML/FormHandler/Result.pm', 'lib/HTML/FormHandler/Result/Role.pm', 'lib/HTML/FormHandler/Test.pm', 'lib/HTML/FormHandler/TraitFor/Captcha.pm', 'lib/HTML/FormHandler/TraitFor/I18N.pm', 'lib/HTML/FormHandler/TraitFor/Types.pm', 'lib/HTML/FormHandler/Traits.pm', 'lib/HTML/FormHandler/Types.pm', 'lib/HTML/FormHandler/Validate.pm', 'lib/HTML/FormHandler/Widget/ApplyRole.pm', 'lib/HTML/FormHandler/Widget/Block.pm', 'lib/HTML/FormHandler/Widget/Block/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Field/Button.pm', 'lib/HTML/FormHandler/Widget/Field/ButtonTag.pm', 'lib/HTML/FormHandler/Widget/Field/Captcha.pm', 'lib/HTML/FormHandler/Widget/Field/Checkbox.pm', 'lib/HTML/FormHandler/Widget/Field/CheckboxGroup.pm', 'lib/HTML/FormHandler/Widget/Field/Compound.pm', 'lib/HTML/FormHandler/Widget/Field/Hidden.pm', 'lib/HTML/FormHandler/Widget/Field/HorizCheckboxGroup.pm', 'lib/HTML/FormHandler/Widget/Field/NoRender.pm', 'lib/HTML/FormHandler/Widget/Field/Password.pm', 'lib/HTML/FormHandler/Widget/Field/RadioGroup.pm', 'lib/HTML/FormHandler/Widget/Field/Repeatable.pm', 'lib/HTML/FormHandler/Widget/Field/Reset.pm', 'lib/HTML/FormHandler/Widget/Field/Role/HTMLAttributes.pm', 'lib/HTML/FormHandler/Widget/Field/Role/SelectedOption.pm', 'lib/HTML/FormHandler/Widget/Field/Select.pm', 'lib/HTML/FormHandler/Widget/Field/Span.pm', 'lib/HTML/FormHandler/Widget/Field/Submit.pm', 'lib/HTML/FormHandler/Widget/Field/Text.pm', 'lib/HTML/FormHandler/Widget/Field/Textarea.pm', 'lib/HTML/FormHandler/Widget/Field/Upload.pm', 'lib/HTML/FormHandler/Widget/Form/Role/HTMLAttributes.pm', 'lib/HTML/FormHandler/Widget/Form/Simple.pm', 'lib/HTML/FormHandler/Widget/Form/Table.pm', 'lib/HTML/FormHandler/Widget/Theme/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Theme/Bootstrap3.pm', 'lib/HTML/FormHandler/Widget/Theme/BootstrapFormMessages.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Base.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Bootstrap.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Bootstrap3.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Fieldset.pm', 'lib/HTML/FormHandler/Widget/Wrapper/None.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Simple.pm', 'lib/HTML/FormHandler/Widget/Wrapper/SimpleInline.pm', 'lib/HTML/FormHandler/Widget/Wrapper/Table.pm', 'lib/HTML/FormHandler/Widget/Wrapper/TableInline.pm', 'lib/HTML/FormHandler/Wizard.pm' ); notabs_ok($_) foreach @files; done_testing; blocktags.t100644000770000024 221312576552253 20336 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/blocksuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::BlockComment; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+name' => ( default => 'test_form' ); has_block 'comment' => ( tag => 'a', content => 'This is a comment from a block', class => ['comment' ] ); has_field 'foo' => ( tags => { before_element => '%comment' } ); has_field 'bar' => ( tags => { before_element => \&bar_element } ); sub bar_element { my $self = shift; return '
In a Sub
'; } } my $form = MyApp::Form::BlockComment->new; ok( $form, 'form built' ); $form->process; my $rendered = $form->render; my $expected = '
In a Sub
'; is_html( $rendered, $expected, 'rendered as expected' ); done_testing; inline.t100644000770000024 443512576552253 20413 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrapuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::InLine::Theme; use Moose::Role; # form tag classes sub build_form_element_class { ['well', 'form-search'] } # form wrapper class sub build_form_wrapper_class { ['span9'] } # turn on form wrapper, set the tag to 'div' (default is fieldset) sub build_do_form_wrapper {1} sub build_form_tags {{ wrapper_tag => 'div', before => '

Inline form

Inputs are block level to start. For .form-inline and .form-horizontal, we use inline-block.

', after => '
', no_form_message_div => 1, }} # update individual fields sub build_update_subfields {{ email => { element_class => ['input-small'], element_attr => { placeholder => 'Email' } }, password => { element_class => ['input-small'], element_attr => { placeholder => 'Password' }, tags => { wrapper_tag => 0 } }, go => { element_class => ['btn'] }, }} } { package MyApp::Form::InLine; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'MyApp::Form::InLine::Theme'; has '+name' => ( default => 'inline_form' ); has '+widget_wrapper' => ( default => 'None' ); has_field 'email' => ( type => 'Email' ); has_field 'password' => ( type => 'Password' ); has_field 'go' => ( type => 'Submit', widget => 'ButtonTag', value => 'Go' ) } my $form = MyApp::Form::InLine->new; $form->process; my $rendered = $form->render; my $expected = '

Inline form

Inputs are block level to start. For .form-inline and .form-horizontal, we use inline-block.

'; is_html( $rendered, $expected, 'form renders correctly' ); done_testing; search.t100644000770000024 352612576552253 20402 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrapuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package MyApp::Form::Search::Theme; use Moose::Role; sub build_form_tags {{ before => '

Search form

Reflecting default WebKit styles, just add .form-search for extra rounded search fields.

', after => '
', no_form_message_div => 1, }} # classes for form element sub build_form_element_class { ['well', 'form-search'] } # field updates sub build_update_subfields {{ searchterm => { widget_wrapper => 'None', element_attr => { class => ['input-medium', 'search-query'] }}, submitbtn => { widget => 'ButtonTag', widget_wrapper => 'None', element_attr => { class => ['btn'] } }, }} } { package MyApp::Form::Search; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'MyApp::Form::Search::Theme'; has '+name' => ( default => 'search_form' ); has '+http_method' => ( default => 'get' ); has_field 'searchterm' => ( type => 'Text' ); has_field 'submitbtn' => ( type => 'Submit', value => 'Search' ); } my $expected = '

Search form

Reflecting default WebKit styles, just add .form-search for extra rounded search fields.

'; my $form = MyApp::Form::Search->new; $form->process; my $rendered = $form->render; is_html($rendered, $expected, 'renders correctly' ); done_testing; bootstrap3000755000770000024 012576552253 16665 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/tbasic.t100644000770000024 621212576552253 20274 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrap3use strict; use warnings; use Test::More; use HTML::FormHandler::Test; $ENV{LANGUAGE_HANDLE} = 'en_en'; use_ok('HTML::FormHandler::Widget::Wrapper::Bootstrap3'); { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+widget_wrapper' => ( default => 'Bootstrap3' ); has_field 'foo' => ( required => 1 ); has_field 'bar'; has_field 'active' => ( type => 'Checkbox' ); has_field 'vegetables' => ( type => 'Multiple', widget => 'RadioGroup' ); sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } has_field 'save' => ( type => 'Submit', element_wrapper_class => ['col-lg-offset-2', 'col-lg-10'] ); } my $form = MyApp::Form::Test->new; ok( $form, 'form builds' ); my $expected = '
'; my $rendered = $form->field('foo')->render; is_html( $rendered, $expected, 'foo renders ok' ); $expected = '
'; $rendered = $form->field('active')->render; is_html( $rendered, $expected, 'checkbox renders ok' ); $expected = '
'; $rendered = $form->field('save')->render; is_html( $rendered, $expected, 'submit button renders ok' ); $expected = '
'; $rendered = $form->field('vegetables')->render; is_html( $rendered, $expected, 'radio group renders' ); # after processing $form->process( params => { bar => 'bar' } ); $expected = '
Foo field is required
'; $rendered = $form->field('foo')->render; is_html( $rendered, $expected, 'foo renders ok with error' ); done_testing; horiz.t100644000770000024 724412576552253 20354 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/bootstrap3use strict; use warnings; use Test::More; use HTML::FormHandler::Test; $ENV{LANGUAGE_HANDLE} = 'en_en'; use_ok('HTML::FormHandler::Widget::Wrapper::Bootstrap3'); { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Widget::Theme::Bootstrap3'; sub build_form_tags {{ 'layout_classes' => { label_class => ['col-lg-2'], element_wrapper_class => ['col-lg-10'], no_label_element_wrapper_class => ['col-lg-offset-2'], }, }} has_field 'foo' => ( required => 1 ); has_field 'bar'; has_field 'active' => ( type => 'Checkbox' ); has_field 'vegetables' => ( type => 'Multiple', widget => 'RadioGroup' ); sub options_vegetables { return ( 1 => 'lettuce', 2 => 'broccoli', 3 => 'carrots', 4 => 'peas', ); } has_field 'save' => ( type => 'Submit' ); } my $form = MyApp::Form::Test->new; ok( $form, 'form builds' ); is_deeply( $form->form_element_class, [ 'form-horizontal' ], 'form has "form-horizontal" in form_element_class', ); like( $form->render, qr/class="form-horizontal"/, 'form has form-horizontal class in rendered output', ); my $expected = '
'; my $rendered = $form->field('foo')->render; is_html( $rendered, $expected, 'foo renders ok' ); $expected = '
'; $rendered = $form->field('active')->render; is_html( $rendered, $expected, 'checkbox renders ok' ); $expected = '
'; $rendered = $form->field('save')->render; is_html( $rendered, $expected, 'submit button renders ok' ); $expected = '
'; $rendered = $form->field('vegetables')->render; is_html( $rendered, $expected, 'radio group renders' ); # after processing $form->process( params => { bar => 'bar' } ); $expected = '
Foo field is required
'; $rendered = $form->field('foo')->render; is_html( $rendered, $expected, 'foo renders ok with error' ); done_testing; default.t100644000770000024 315412576552253 20365 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/compounduse strict; use warnings; use Test::More; # tests that a 'default' hashref on a compound field works { { package MyApp::Test::Compound; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'comp_foo' => ( type => 'Compound', default => { one => 1, two => 2, three => 3 } ); has_field 'comp_foo.one'; has_field 'comp_foo.two'; has_field 'comp_foo.three'; } my $form = MyApp::Test::Compound->new; ok( $form ); $form->process; is( $form->field('comp_foo.one')->value, 1, 'value is one' ); is_deeply( $form->field('comp_foo')->value, { one => 1, two => 2, three => 3 }, 'value for compound is correct' ); } # tests that default object for a compound field works # object provided by default_method { { package MyApp::Foo; use Moose; has 'one' => ( is => 'ro', default => 1 ); has 'two' => ( is => 'ro', default => 2 ); has 'three' => ( is => 'ro', default => 3 ); } { package MyApp::Test::Compound2; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'comp_foo' => ( type => 'Compound', default_method => \&default_comp_foo ); has_field 'comp_foo.one'; has_field 'comp_foo.two'; has_field 'comp_foo.three'; sub default_comp_foo { return MyApp::Foo->new; } } my $form = MyApp::Test::Compound2->new; ok( $form ); is( $form->field('comp_foo.one')->value, 1, 'value is one' ); is( ref $form->field('comp_foo')->item, 'MyApp::Foo', 'item saved' ); } done_testing; include.t100644000770000024 222612576552253 20363 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/compounduse strict; use warnings; use Test::More; # Test using the 'include' attribute on a compound field # to limit the fields that are built. # alternative to active/inactive. Created for a situation # in which there are a very large number of fields in a # field/role and you don't want the overhead of building them # and then setting them activie/inactive. { package Test::FooField; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Compound'; has_field 'foo'; has_field 'bar'; has_field 'box'; has_field 'mix'; has_field 'nix'; } my $field = Test::FooField->new( name => 'muddly' ); ok( $field ); { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'fiddly'; has_field 'muddly' => ( type => '+Test::FooField', include => ['foo', 'mix', 'nix'] ); # no subfields. kinda weird... has_field 'middly' => ( type => '+Test::FooField', include => [ 'empty' ] ); } my $form = Test::Form->new; ok( $form ); is( $form->field('muddly')->num_fields, 3, 'right number of fields' ); is( $form->field('middly')->num_fields, 0, 'right number of fields' ); done_testing; selectcsv.t100644000770000024 265312576552253 20361 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/fieldsuse strict; use warnings; use Test::More; use Test::Exception; # tests the SelectCSV field { package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( type => 'SelectCSV' ); sub options_foo { ( 1 => 'One', 2 => 'Two', ) } has_field 'bar' => ( type => 'SelectCSV' ); sub options_bar { ( 1 => 'One', 2 => 'Two', ) } has_field 'box' => ( type => 'Select', multiple => 1 ); sub options_box { ( 1 => 'One', 2 => 'Two', 3 => 'Three', ) } } my $form = MyApp::Form::Test->new; ok( $form ); my $init_obj = { foo => '1', bar => '1,2', box => [2] }; $form->process( init_object => $init_obj ); my $fif = $form->fif; is_deeply( $fif, { foo => [1], bar => [1,2], box => [2] }, 'fif is correct' ); lives_ok( sub { $form->field('bar')->as_label }, 'as_label works with SelectCSV field' ); my $rendered = $form->render; ok( $rendered, 'rendering worked' ); my $params = { bar => [2,1] }; $form->process( $params ); lives_ok( sub { $form->field('bar')->as_label }, 'as_label works with SelectCSV field' ); $fif = $form->fif; is_deeply( $fif, $params, 'fif ok' ); my $value = $form->value; is_deeply( $value, { foo => undef, bar => '1,2', box => [] }, 'right value' ); $rendered = $form->render; ok( $rendered, 'rendering worked' ); done_testing; clone.t100644000770000024 257012576552253 20401 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/form_setupuse strict; use warnings; use Test::More; use Data::Dumper; # tests that hashref attributes are not shared between instances # of a form { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo' => ( tags => { one => 1, two => 2, three => 3 } ); has_field 'bar'; } my $form1 = Test::Form->new; my $form2 = Test::Form->new; my $form3 = Test::Form->new; $form2->field('foo')->delete_tag('two'); # no cloning necessary for field_list is( scalar keys %{$form1->field('foo')->tags}, 3, 'right number of tags keys' ); is( scalar keys %{$form2->field('foo')->tags}, 2, 'right number of tags keys' ); is( scalar keys %{$form1->field('foo')->tags}, 3, 'right number of tags keys' ); my $form4 = new_form(); my $form5 = new_form(); my $form6 = new_form(); $form5->field('foo')->delete_tag('two'); is( scalar keys %{$form4->field('foo')->tags}, 3, 'right number of tags keys' ); is( scalar keys %{$form5->field('foo')->tags}, 2, 'right number of tags keys' ); is( scalar keys %{$form6->field('foo')->tags}, 3, 'right number of tags keys' ); sub new_form { my $form = HTML::FormHandler->new( field_list => [ { name => 'foo', type => 'Text', tags => { one => 1, two => 2, three => 3 } }, { name => 'bar' }, { name => 'save', type => 'Submit' }, ], ); return $form; } done_testing; Person.pm100644000770000024 26012576552253 20160 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/lib/Formpackage Form::Person; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'name'; has_field 'telephone'; has_field 'email'; no HTML::FormHandler::Moose; 1; compound2.t100644000770000024 522012576552253 20276 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; use HTML::FormHandler::I18N; $ENV{LANGUAGE_HANDLE} = 'en_en'; { package MyApp::Form::Password; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use HTML::FormHandler::Types ('NotAllDigits'); has '+name' => ( default => 'testform' ); has '+widget_wrapper' => ( default => 'Bootstrap' ); # Email & compound definition in form: has_field 'email' => ( type => 'Email', label => 'Register.Email', element_attr => { placeholder => 'Register.Email', class => 'span3', }, wrapper_attr => { class => 'clearfix' }, required => 1, ); has_field 'password' => ( type => 'Compound', required => 1, do_wrapper => 1, do_label => 1, label => 'Register.Password', ); has_field 'password.password' => ( type => 'Password', do_wrapper => 0, do_label => 0, element_attr => { placeholder => 'Register.Password', class => 'span2', }, required => 1, minlength => 5, apply => [NotAllDigits], ); has_field 'password.again' => ( type => 'PasswordConf', password_field => 'password', do_wrapper => 0, do_label => 0, element_attr => { placeholder => 'Register.PasswordAgain', class => 'span2', }, ); } my $form = MyApp::Form::Password->new; ok( $form, 'form built' ); $form->process( params => { email => 'joe@nowhere.com', 'password.password' => '12345', 'password.again' => '54321' } ); my $rendered = $form->render; my $expected = '
Must not be all digits The password confirmation does not match the password
'; is_html( $rendered, $expected, 'got expected html' ); done_testing; html_attr.t100644000770000024 571312576552253 20375 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/t/renderuse strict; use warnings; use Test::More; use HTML::FormHandler::Test; { package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; sub build_form_element_attr { { method => 'GET', class => 'hfh test_form', target => '_blank' } } has_field 'foo' => ( element_attr => { arbitrary => 'something' } ); has_field 'bar' => ( element_attr => { writeonly => 1 }, label_attr => { title => 'Bar Field' } ); has_field 'mox' => ( wrapper_class => ['minx', 'finx'] ); has_field 'my_text' => ( type => 'TextArea', element_attr => { required => "required" } ); } my $form = Test::Form->new; $form->process( params => {} ); my $rendered = $form->render; like( $rendered, qr/class="hfh test_form"/, 'form has class' ); like( $rendered, qr/method="GET"/, 'form has html method' ); like( $rendered, qr/arbitrary="something"/, 'field has arbitrary attribute' ); like( $rendered, qr/writeonly="1"/, 'field has writeonly attribute' ); like( $rendered, qr/target="_blank"/, 'form has target attribute'); like( $rendered, qr{}, 'textarea rendered ok'); like( $rendered, qr{
[% END -%] fieldset.tt100644000770000024 15412576552253 23372 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/share/templates/wrapper[% f.label %] [% content -%] Button.pm100644000770000024 153612576552253 23036 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Button; # ABSTRACT: button field use Moose; extends 'HTML::FormHandler::Field::NoValue'; has '+widget' => ( default => 'Button' ); has '+value' => ( default => 'Button' ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Button - button field =head1 VERSION version 0.40064 =head1 SYNOPSIS Use this field to declare a button field in your form. has_field 'button' => ( type => 'Button', value => 'Press Me!' ); Uses the 'button' widget. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Hidden.pm100644000770000024 153712576552253 22757 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Hidden; # ABSTRACT: hidden field use Moose; extends 'HTML::FormHandler::Field::Text'; our $VERSION = '0.01'; has '+widget' => ( default => 'Hidden' ); has '+do_label' => ( default => 0 ); has '+html5_type_attr' => ( default => 'hidden' ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Hidden - hidden field =head1 VERSION version 0.40064 =head1 DESCRIPTION This is a text field that uses the 'hidden' widget type, for HTML of type 'hidden'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Minute.pm100644000770000024 156312576552253 23024 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Minute; # ABSTRACT: input range from 0 to 59 use Moose; extends 'HTML::FormHandler::Field::IntRange'; our $VERSION = '0.01'; has '+range_start' => ( default => 0 ); has '+range_end' => ( default => 59 ); has '+label_format' => ( default => '%02d' ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Minute - input range from 0 to 59 =head1 VERSION version 0.40064 =head1 DESCRIPTION Generate a select list for entering a minute value. Widget type is 'select'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Nested.pm100644000770000024 147012576552253 23002 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Nested; # ABSTRACT: for nested elements of compound fields use Moose; extends 'HTML::FormHandler::Field::Text'; __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Nested - for nested elements of compound fields =head1 VERSION version 0.40064 =head1 SYNOPSIS This field class is intended for nested elements of compound fields. It does no particular validation, since the compound field should handle that. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Result.pm100644000770000024 343212576552253 23036 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Result; # ABSTRACT: result class for fields use Moose; with 'HTML::FormHandler::Result::Role'; has 'value' => ( is => 'ro', writer => '_set_value', clearer => '_clear_value', predicate => 'has_value', ); has 'field_def' => ( is => 'ro', isa => 'HTML::FormHandler::Field', writer => '_set_field_def', ); has 'missing' => ( is => 'rw', isa => 'Bool' ); sub fif { my $self = shift; return $self->field_def->fif($self); } sub fields_fif { my ( $self, $prefix ) = @_; return $self->field_def->fields_fif( $self, $prefix ); } sub render { my $self = shift; return $self->field_def->render($self); } sub peek { my ( $self, $indent ) = @_; $indent ||= ''; my $name = $self->field_def ? $self->field_def->full_name : $self->name; my $type = $self->field_def ? $self->field_def->type : 'unknown'; my $string = $indent . "result " . $name . " type: " . $type . "\n"; $string .= $indent . "....value => " . $self->value . "\n" if $self->has_value; if( $self->has_results ) { $indent .= ' '; foreach my $res ( $self->results ) { $string .= $res->peek( $indent ); } } return $string; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Result - result class for fields =head1 VERSION version 0.40064 =head1 SYNOPSIS Result class for L =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Second.pm100644000770000024 144012576552253 22770 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Second; # ABSTRACT: select list 0 to 59 use Moose; extends 'HTML::FormHandler::Field::IntRange'; our $VERSION = '0.01'; has '+range_start' => ( default => 0 ); has '+range_end' => ( default => 59 ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Second - select list 0 to 59 =head1 VERSION version 0.40064 =head1 DESCRIPTION A select field for seconds in the range of 0 to 59. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Select.pm100644000770000024 5136212576552253 23024 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Select; # ABSTRACT: select fields use Moose; extends 'HTML::FormHandler::Field'; use Carp; our $VERSION = '0.03'; use HTML::Entities; has 'options' => ( isa => 'HFH::SelectOptions', is => 'rw', coerce => 1, traits => ['Array'], auto_deref => 1, handles => { all_options => 'elements', reset_options => 'clear', clear_options => 'clear', has_options => 'count', num_options => 'count', }, lazy => 1, builder => 'build_options' ); sub options_ref { [shift->options] } # this is used for rendering has 'options_index' => ( traits => ['Counter'], isa => 'Num', is => 'rw', default => 0, handles => { inc_options_index => 'inc', dec_options_index => 'dec', reset_options_index => 'reset' }, ); sub clear_data { my $self = shift; $self->next::method(); $self->reset_options_index; } sub build_options { [] } has 'options_from' => ( isa => 'Str', is => 'rw', default => 'none' ); has 'do_not_reload' => ( isa => 'Bool', is => 'ro' ); has 'no_option_validation' => ( isa => 'Bool', is => 'rw' ); has 'option_wrapper' => ( is => 'rw' ); sub BUILD { my $self = shift; $self->build_options_method; if( $self->options && $self->has_options ) { $self->options_from('build'); $self->default_from_options([$self->options]); } $self->input_without_param; # vivify } has 'options_method' => ( traits => ['Code'], is => 'ro', isa => 'CodeRef', writer => '_set_options_method', predicate => 'has_options_method', handles => { 'get_options' => 'execute_method' }, ); sub build_options_method { my $self = shift; my $set_options = $self->set_options; $set_options ||= "options_" . HTML::FormHandler::Field::convert_full_name($self->full_name); if ( $self->form && $self->form->can($set_options) ) { my $attr = $self->form->meta->find_method_by_name( $set_options ); if ( $attr and $attr->isa('Moose::Meta::Method::Accessor') ) { $self->_set_options_method( sub { my $self = shift; $self->form->$set_options; } ); } else { $self->_set_options_method( sub { my $self = shift; $self->form->$set_options($self); } ); } } } has 'sort_options_method' => ( traits => ['Code'], is => 'rw', isa => 'CodeRef', predicate => 'has_sort_options_method', handles => { sort_options => 'execute_method', }, ); has 'set_options' => ( isa => 'Str', is => 'ro'); has 'multiple' => ( isa => 'Bool', is => 'rw', default => '0' ); # following is for unusual case where a multiple select is a has_many type relation has 'has_many' => ( isa => 'Str', is => 'rw' ); has 'size' => ( isa => 'Int|Undef', is => 'rw' ); has 'label_column' => ( isa => 'Str', is => 'rw', default => 'name' ); has 'localize_labels' => ( isa => 'Bool', is => 'rw' ); has 'active_column' => ( isa => 'Str', is => 'rw', default => 'active' ); has 'auto_widget_size' => ( isa => 'Int', is => 'rw', default => '0' ); has 'sort_column' => ( isa => 'Str|ArrayRef[Str]', is => 'rw' ); has '+widget' => ( default => 'Select' ); sub html_element { 'select' } has '+type_attr' => ( default => 'select' ); has 'empty_select' => ( isa => 'Str', is => 'rw' ); has '+deflate_method' => ( default => sub { \&select_deflate } ); has '+input_without_param' => ( lazy => 1, builder => 'build_input_without_param' ); sub build_input_without_param { my $self = shift; if( $self->multiple ) { $self->not_nullable(1); return []; } else { return ''; } } has 'value_when_empty' => ( is => 'ro', lazy => 1, builder => 'build_value_when_empty' ); sub build_value_when_empty { my $self = shift; return [] if $self->multiple; return undef; } our $class_messages = { 'select_not_multiple' => 'This field does not take multiple values', 'select_invalid_value' => '\'[_1]\' is not a valid value', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } sub select_widget { my $field = shift; my $size = $field->auto_widget_size; return $field->widget unless $field->widget eq 'Select' && $size; my $options = $field->options || []; return 'Select' if @$options > $size; return $field->multiple ? 'checkbox_group' : 'radio_group'; } sub as_label { my ( $self, $value ) = @_; $value = $self->value unless defined $value; return unless defined $value; if ( $self->multiple ) { unless ( ref($value) eq 'ARRAY' ) { if( $self->has_inflate_default_method ) { my @values = $self->inflate_default($value); $value = \@values; } else { # not sure under what circumstances this would happen, but # just in case return $value; } } my @labels; my %value_hash; @value_hash{@$value} = (); for ( $self->options ) { if ( exists $value_hash{$_->{value}} ) { push @labels, $_->{label}; delete $value_hash{$_->{value}}; last unless keys %value_hash; } } my $str = join(', ', @labels); return $str; } else { for ( $self->options ) { return $_->{label} if $_->{value} eq $value; } } return; } sub _inner_validate_field { my ($self) = @_; my $value = $self->value; return unless defined $value; # nothing to check if ( ref $value eq 'ARRAY' && !( $self->can('multiple') && $self->multiple ) ) { $self->add_error( $self->get_message('select_not_multiple') ); return; } elsif ( ref $value ne 'ARRAY' && $self->multiple ) { $value = [$value]; $self->_set_value($value); } return if $self->no_option_validation; # create a lookup hash my %options; foreach my $opt ( @{ $self->options } ) { if ( exists $opt->{group} ) { foreach my $group_opt ( @{ $opt->{options} } ) { $options{$group_opt->{value}} = 1; } } else { $options{$opt->{value}} = 1; } } if( $self->has_many ) { $value = [map { $_->{$self->has_many} } @$value]; } for my $value ( ref $value eq 'ARRAY' ? @$value : ($value) ) { unless ( $options{$value} ) { my $opt_value = encode_entities($value); $self->add_error($self->get_message('select_invalid_value'), $opt_value); return; } } return 1; } sub _result_from_object { my ( $self, $result, $item ) = @_; $result = $self->next::method( $result, $item ); $self->_load_options; $result->_set_value($self->default) if( defined $self->default && not $result->has_value ); return $result; } sub _result_from_fields { my ( $self, $result ) = @_; $result = $self->next::method($result); $self->_load_options; $result->_set_value($self->default) if( defined $self->default && not $result->has_value ); return $result; } sub _result_from_input { my ( $self, $result, $input, $exists ) = @_; $input = ref $input eq 'ARRAY' ? $input : [$input] if $self->multiple; $result = $self->next::method( $result, $input, $exists ); $self->_load_options; $result->_set_value($self->default) if( defined $self->default && not $result->has_value ); return $result; } sub _load_options { my $self = shift; return if ( $self->options_from eq 'build' || ( $self->has_options && $self->do_not_reload ) ); my @options; if( $self->has_options_method ) { @options = $self->get_options; $self->options_from('method'); } elsif ( $self->form ) { my $full_accessor; $full_accessor = $self->parent->full_accessor if $self->parent; @options = $self->form->lookup_options( $self, $full_accessor ); $self->options_from('model') if scalar @options; } return unless @options; # so if there isn't an options method and no options # from a table, already set options attributes stays put # allow returning arrayref if ( ref $options[0] eq 'ARRAY' ) { @options = @{ $options[0] }; } return unless @options; my $opts; # if options_ is returning an already constructed array of hashrefs if ( ref $options[0] eq 'HASH' ) { $opts = \@options; $self->default_from_options($opts); } else { croak "Options array must contain an even number of elements for field " . $self->name if @options % 2; push @{$opts}, { value => shift @options, label => shift @options } while @options; } if ($opts) { # sort options if sort method exists $opts = $self->sort_options($opts) if $self->has_sort_options_method; $self->options($opts); } } # This is because setting 'checked => 1' or 'selected => 1' in an options # hashref is the equivalent of setting a default on the field. Originally # that was handled only in rendering, but it moved knowledge about where # the 'fif' value came from into the renderer, which was bad. So instead # we're setting the defaults from the options. # It's probably better to use 'defaults' to start with, but since there are # people using this method, this at least normalizes it. sub default_from_options { my ( $self, $options ) = @_; my @defaults = map { $_->{value} } grep { $_->{checked} || $_->{selected} } @$options; if( scalar @defaults ) { if( $self->multiple ) { $self->default(\@defaults); } else { $self->default($defaults[0]); } } } before 'value' => sub { my $self = shift; return undef unless $self->has_result; my $value = $self->result->value; if( $self->multiple ) { if ( !defined $value || $value eq '' || ( ref $value eq 'ARRAY' && scalar @$value == 0 ) ) { $self->_set_value( $self->value_when_empty ); } elsif ( $self->has_many && scalar @$value && ref($value->[0]) ne 'HASH' ) { my @new_values; foreach my $ele (@$value) { push @new_values, { $self->has_many => $ele }; } $self->_set_value( \@new_values ); } } }; sub select_deflate { my ( $self, $value ) = @_; return $value unless ( $self->has_many && $self->multiple ); # the following is for the edge case of a has_many select return $value unless ref($value) eq 'ARRAY' && scalar @$value && ref($value->[0]) eq 'HASH'; return [map { $_->{$self->has_many} } @$value]; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Select - select fields =head1 VERSION version 0.40064 =head1 DESCRIPTION This is a field that includes a list of possible valid options. This can be used for select and multiple-select fields. Widget type is 'select'. Because select lists and checkbox_groups do not return an HTTP parameter when the entire list is unselected, the Select field must assume that the lack of a param means unselection. So to avoid setting a Select field, it must be set to inactive, not merely not included in the HTML for a form. This field type can also be used for fields that use the 'radio_group' widget, and the 'checkbox_group' widget (for selects with multiple flag turned on, or that use the Multiple field). =head2 options The 'options' array can come from a number of different places: =over 4 =item From a field declaration In a field declaration: has_field 'opt_in' => ( type => 'Select', widget => 'RadioGroup', options => [{ value => 0, label => 'No'}, { value => 1, label => 'Yes'} ] ); =item From a field class 'build_options' method In a custom field class: package MyApp::Field::WeekDay; use Moose; extends 'HTML::FormHandler::Field::Select'; .... sub build_options { my $i = 0; my @days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ); return [ map { { value => $i++, label => $_ } } @days ]; } =item From a coderef supplied to the field definition has_field 'flim' => ( type => 'Select', options_method => \&flim_options ); sub flim_options { } =item From a form 'options_' method or attribute has_field 'fruit' => ( type => 'Select' ); sub options_fruit { return ( 1 => 'apples', 2 => 'oranges', 3 => 'kiwi', ); } -- or -- has 'options_fruit' => ( is => 'rw', traits => ['Array'], default => sub { [1 => 'apples', 2 => 'oranges', 3 => 'kiwi'] } ); Notice that, as a convenience, you can return a simple array (or arrayref) for the options array in the 'options_field_name' method. The hashrefs with 'value' and 'label' keys will be constructed for you by FormHandler. =item From the database The final source of the options array is a database when the name of the accessor is a relation to the table holding the information used to construct the select list. The primary key is used as the value. The other columns used are: label_column -- Used for the labels in the options (default 'name') active_column -- The name of the column to be used in the query (default 'active') that allows the rows retrieved to be restricted sort_column -- The name or arrayref of names of the column(s) used to sort the options See also L, the 'lookup_options' method. =back =head2 Customizing options Additional attributes can be added in the options array hashref, by using the 'attributes' key. If you have custom rendering code, you can add any additional key that you want, of course. Note that you should *not* set 'checked' or 'selected' attributes in options. That is handled by setting a field default. An options array with an extra 'note' key: sub options_license { my $self = shift; return unless $self->schema; my $licenses = $self->schema->resultset('License')->search({active => 1}, {order_by => 'sequence'}); my @selections; while ( my $license = $licenses->next ) { push @selections, { value => $license->id, label => $license->label, note => $license->note }; } return @selections; } Setting the select element to disabled: sub options_license { my $self = shift; return unless $self->schema; my $licenses = $self->schema->resultset('License')->search(undef, {order_by => 'sequence'}); my @selections; while ( my $license = $licenses->next ) { push @selections, { value => $license->id, label => $license->label, attributes => { disabled => ($license->active == 0) ? 1 : 0 } }; } return @selections; } You can also divide the options up into option groups. See the section on rendering. =head2 Reloading options If the options come from the options_ method or the database, they will be reloaded every time the form is reloaded because the available options may have changed. To prevent this from happening when the available options are known to be static, set the 'do_not_reload' flag, and the options will not be reloaded after the first time =head2 Sorting options The sorting of the options may be changed using a 'sort_options' method in a custom field class. The 'Multiple' field uses this method to put the already selected options at the top of the list. Note that this won't work with option groups. =head1 Attributes and Methods =head2 options This is an array of hashes for this field. Each has must have a label and value keys. =head2 options_method Coderef of method to return options =head2 multiple If true allows multiple input values =head2 size This can be used to store how many items should be offered in the UI at a given time. Defaults to 0. =head2 empty_select Set to the string value of the select label if you want the renderer to create an empty select value. This only affects rendering - it does not add an entry to the list of options. has_field 'fruit' => ( type => 'Select', empty_select => '---Choose a Fruit---' ); =head2 value_when_empty Usually the empty value is an empty arrayref. This attribute allows changing that. Used by SelectCSV field. =head2 label_column Sets or returns the name of the method to call on the foreign class to fetch the text to use for the select list. Refers to the method (or column) name to use in a related object class for the label for select lists. Defaults to "name". =head2 localize_labels For the renderers: whether or not to call the localize method on the select labels. Default is off. =head2 active_column Sets or returns the name of a boolean column that is used as a flag to indicate that a row is active or not. Rows that are not active are ignored. The default is "active". If this column exists on the class then the list of options will included only rows that are marked "active". The exception is any columns that are marked inactive, but are also part of the input data will be included with brackets around the label. This allows updating records that might have data that is now considered inactive. =head2 auto_widget_size This is a way to provide a hint as to when to automatically select the widget to display for fields with a small number of options. For example, this can be used to decided to display a radio select for select lists smaller than the size specified. See L below. =head2 sort_column Sets or returns the column or arrayref of columns used in the foreign class for sorting the options labels. Default is undefined. If not defined the label_column is used as the sort condition. =head2 select_widget If the widget is 'select' for the field then will look if the field also has a L. If the options list is less than or equal to the L then will return C if L is false, otherwise will return C. =head2 as_label Returns the option label for the option value that matches the field's current value. Can be helpful for displaying information about the field in a more friendly format. =head2 no_option_validation Set this flag to true if you don't want to validate the options that are submitted. This would generally only happen if the options are generated via javascript. =head2 error messages Customize 'select_invalid_value' and 'select_not_multiple'. Though neither of these messages should really be seen by users in a properly constructed select. =head1 Rendering The 'select' field can be rendered by the 'Select', 'RadioGroup', and 'CheckboxGroup' widgets. 'RadioGroup' is for a single select, and 'CheckboxGroup' is for a multiple select. Option groups can be rendered by providing an options arrays with 'group' elements containing options: sub options_testop { ( { group => 'First Group', options => [ { value => 1, label => 'One' }, { value => 2, label => 'Two' }, { value => 3, label => 'Three' }, ], }, { group => 'Second Group', options => [ { value => 4, label => 'Four' }, { value => 5, label => 'Five' }, { value => 6, label => 'Six' }, ], }, ) } The select rendering widgets all have a 'render_option' method, which may be useful for situations when you want to split up the rendering of a radio group or checkbox group. =head1 Database relations Also see L. The single select is for a DBIC 'belongs_to' relation. The multiple select is for a 'many_to_many' relation. There is very limited ability to do multiple select with 'has_many' relations. It will only work in very specific circumstances, and requires setting the 'has_many' attribute to the name of the primary key of the related table. This is a somewhat peculiar data structure for a relational database, and may not be what you really want. A 'has_many' is usually represented with a Repeatable field, and may require custom code if the form structure doesn't match the database structure. See L. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Submit.pm100644000770000024 266512576552253 23032 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Submit; # ABSTRACT: submit field use Moose; extends 'HTML::FormHandler::Field::NoValue'; has '+value' => ( default => 'Save' ); has '+widget' => ( default => 'Submit' ); has '+type_attr' => ( default => 'submit' ); has '+html5_type_attr' => ( default => 'submit' ); sub do_label {0} sub _result_from_input { my ( $self, $result, $input, $exists ) = @_; $self->_set_result($result); $result->_set_input($input); $result->_set_field_def($self); return $result; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Submit - submit field =head1 VERSION version 0.40064 =head1 SYNOPSIS Use this field to declare a submit field in your form. has_field 'submit' => ( type => 'Submit', value => 'Save' ); It will be used by L to construct a form with C<< $form->render >>. Uses the 'submit' widget. If you have multiple submit buttons, currently the only way to test which one has been clicked is with C<< $field->input >>. The 'value' attribute is used for the HTML input field 'value'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Upload.pm100644000770000024 703512576552253 23007 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::Upload; # ABSTRACT: file upload field use Moose; use Moose::Util::TypeConstraints; extends 'HTML::FormHandler::Field'; our $VERSION = '0.02'; has '+widget' => ( default => 'Upload', ); has min_size => ( is => 'rw', isa => 'Maybe[Int]', default => 1 ); has max_size => ( is => 'rw', isa => 'Maybe[Int]', default => 1048576 ); has '+type_attr' => ( default => 'file' ); our $class_messages = { 'upload_file_not_found' => 'File not found for upload field', 'upload_file_empty' => 'File uploaded is empty', 'upload_file_too_small' => 'File is too small (< [_1] bytes)', 'upload_file_too_big' => 'File is too big (> [_1] bytes)', }; sub get_class_messages { my $self = shift; return { %{ $self->next::method }, %$class_messages, } } sub validate { my $self = shift; my $upload = $self->value; my $size = 0; if( blessed $upload && $upload->can('size') ) { $size = $upload->size; } elsif( is_real_fh( $upload ) ) { $size = -s $upload; } else { return $self->add_error($self->get_message('upload_file_not_found')); } return $self->add_error($self->get_message('upload_file_empty')) unless $size > 0; if( defined $self->min_size && $size < $self->min_size ) { $self->add_error( $self->get_message('upload_file_too_small'), $self->min_size ); } if( defined $self->max_size && $size > $self->max_size ) { $self->add_error( $self->get_message('upload_file_too_big'), $self->max_size ); } return; } # stolen from Plack::Util::is_real_fh sub is_real_fh { my $fh = shift; my $reftype = Scalar::Util::reftype($fh) or return; if( $reftype eq 'IO' or $reftype eq 'GLOB' && *{$fh}{IO} ){ my $m_fileno = $fh->fileno; return unless defined $m_fileno; return unless $m_fileno >= 0; my $f_fileno = fileno($fh); return unless defined $f_fileno; return unless $f_fileno >= 0; return 1; } else { return; } } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Upload - file upload field =head1 VERSION version 0.40064 =head1 DESCRIPTION This field is designed to be used with a blessed object with a 'size' method, such as L, or a filehandle. Validates that the file is not empty and is within the 'min_size' and 'max_size' limits (limits are in bytes). A form containing this field must have the enctype set. package My::Form::Upload; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+enctype' => ( default => 'multipart/form-data'); has_field 'file' => ( type => 'Upload', max_size => '2000000' ); has_field 'submit' => ( type => 'Submit', value => 'Upload' ); In your controller: my $form = My::Form::Upload->new; my @params = ( file => $c->req->upload('file') ) if $c->req->method eq 'POST'; $form->process( params => { @params } ); return unless ( $form->validated ); You can set the min_size and max_size limits to undef if you don't want them to be validated. =head1 DEPENDENCIES =head2 widget Widget type is 'upload' =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Object.pm100644000770000024 145312576552253 23004 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Modelpackage HTML::FormHandler::Model::Object; # ABSTRACT: stub for Object model use Moose::Role; sub update_model { my $self = shift; my $item = $self->item; return unless $item; foreach my $field ( $self->all_fields ) { my $name = $field->name; next unless $item->can($name); $item->$name( $field->value ); } } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Model::Object - stub for Object model =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Table.pm100644000770000024 470112576552253 23003 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Renderpackage HTML::FormHandler::Render::Table; # ABSTRACT: render a form with a table layout use Moose::Role; with 'HTML::FormHandler::Render::Simple' => { -excludes => [ 'render', 'wrap_field', 'render_end', 'render_start' ] }; use HTML::FormHandler::Render::Util ('process_attrs'); sub render { my $self = shift; my $output = $self->render_start; $output .= $self->render_form_errors; foreach my $field ( $self->sorted_fields ) { $output .= $self->render_field($field); } $output .= $self->render_end; return $output; } sub render_start { my $self = shift; my $attrs = process_attrs($self->attributes); return qq{}; } sub render_form_errors { my $self = shift; return '' unless $self->has_form_errors; my $output = "\n"; return $output; } sub render_end { my $self = shift; my $output .= "
"; $output .= qq{\n$_} for $self->all_form_errors; $output .= "\n
\n"; $output .= "\n"; return $output; } sub wrap_field { my ( $self, $field, $rendered_field ) = @_; my $attrs = process_attrs($field->wrapper_attributes); my $output = qq{\n}; my $l_type = $field->widget eq 'Compound' ? 'legend' : 'label'; if ( $l_type eq 'label' ) { $output .= '
' . $self->render_label($field) . '' . $self->render_label($field) . '
'; } $output .= $rendered_field; $output .= qq{\n$_} for $field->all_errors; if ( $l_type ne 'legend' ) { $output .= "
[% FOREACH f IN form.field('admin_roles').sorted_fields %] [% END %]
FamilyAdmin
[% f.field('family').fif %][% f.field('family').render %] [% f.field('family_id').render %] [% f.field('admin_flag').render %]
'None'). There are two hidden fields here, so what is actually seen is two columns, one with the user (family) name, the other with a checkbox showing whether the user has admin status. Notice that the 'family' field information is rendered twice: once as a hidden field that will allow it to be preserved in params, once as a label. The Catalyst controller action to execute the form: sub admin_roles : Local { my ( $self, $c ) = @_; my $schema = $c->model('DB')->schema; my $form = My::Form::AdminRoles->new( schema => $schema ); $form->process( params => $c->req->params ); # re-process if form validated to reload from db and re-sort $form->process( params => {}) if $form->validated; $c->stash( form => $form, template => 'admin/admin_roles.tt' ); return; } Rather than redirect to some other page after saving the form, the form is redisplayed. If the form has been validated (i.e. the 'update_model' method has been run), the 'process' call is run again in order to re-sort the displayed list with admin users at the top. That could have also been done in the 'update_model' method. =head2 A form that takes a resultset, with custom update_model For updating a Repeatable field that is filled from a Resultset, and not a relationship on a single row. Creates a 'resultset' attribute to pass in a resultset. Massages the data into an array that's pointed to by an 'employers' hash key, and does the reverse in the 'update_model' method. Yes, it's a kludge, but it could be worse. If you want to implement a more general solution, patches welcome. package Test::Resultset; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Model::DBIC'; has '+item_class' => ( default => 'Employer' ); has 'resultset' => ( isa => 'DBIx::Class::ResultSet', is => 'rw', trigger => sub { shift->set_resultset(@_) } ); sub set_resultset { my ( $self, $resultset ) = @_; $self->schema( $resultset->result_source->schema ); } sub init_object { my $self = shift; my $rows = [$self->resultset->all]; return { employers => $rows }; } has_field 'employers' => ( type => 'Repeatable' ); has_field 'employers.employer_id' => ( type => 'PrimaryKey' ); has_field 'employers.name'; has_field 'employers.category'; has_field 'employers.country'; sub update_model { my $self = shift; my $values = $self->values->{employers}; foreach my $row (@$values) { delete $row->{employer_id} unless defined $row->{employer_id}; $self->resultset->update_or_create( $row ); } } =head2 Server-provided dynamic value for field There are many different ways to provide values for fields. Default values can be statically provided in the form with the 'default' attribute on the field, with a default_ method in the form, with an init_object/item, and with 'default_over_obj' if you have both an item/init_object and want to provide a default. has_field 'foo' => ( default => 'my_default' ); has_field 'foo' => ( default_over_obj => 'my_default' ); sub default_foo { 'my_default' } .. $form->process( init_object => { foo => 'my_default } ); $form->process( item => foo method to provide default> ); If you want to change the default for the field at run time, there are a number of options. You can set the value in the init_object or item before doing process: my $foo_value = 'some calculated value'; $form->process( init_object => { foo => $foo_value } ); You can use 'update_field_list' or 'defaults' on the 'process' call: $form->process( update_field_list => { foo => { default => $foo_value } } ); -- or -- $form->process( defaults => { foo => $foo_value } ); You can set a Moose attribute in the form class, and set the default in a default_ method: package My::Form; use HTML::FormHandler::Moose; extends 'HTML::Formhandler'; has 'form_id' => ( isa => 'Str', is => 'rw' ); has_field 'foo'; sub default_foo { my $self = shift; return $self->form_id; } .... $form->process( form_id => 'my_form', params => $params ); You can set a Moose attribute in the form class and set it in an update_fields method: sub update_fields { my $self = shift; $self->field('foo')->default('my_form'); } =head2 Static form, dynamic field IDs The problem: you have a form that will be used in multiple places on a page, but you want to use a static form instead of doing 'new' for each. You can pass a form name in on the process call and use 'html_prefix' in the form: $form->process( name => '...', params => {} ); But the field 'id' attribute has already been constructed and doesn't change. Solution: apply a role to the base field class to replace the 'id' getter for the 'id' attribute with a method which constructs the 'id' dynamically. Since the role is being applied to the base field class, you can't just use 'sub id', because the 'id' method defined by the 'id' attribute has precedence. So create an 'around' method modifier that replaces it in the role. package My::DynamicFieldId; use Moose::Role; around 'id' => sub { my $orig = shift; my $self = shift; my $form_name = $self->form->name; return $form_name . "." . $self->full_name; }; package My::CustomIdForm; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+html_prefix' => ( default => 1 ); has '+field_traits' => ( default => sub { ['My::DynamicFieldId'] } ); has_field 'foo'; has_field 'bar'; =head2 Create different field IDs Use 'build_id_method' to give your fields a different format 'id': package MyApp::CustomId; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has '+update_field_list' => ( default => sub { { all => { build_id_method => \&custom_id } } } ); has_field 'foo' => ( type => 'Compound' ); has_field 'foo.one'; has_field 'foo.two'; has_field 'foo.three'; sub custom_id { my $self = shift; my $full_name = $self->full_name; $full_name =~ s/\./_/g; return $full_name; } The above method provides IDs of "foo_two" and "foo_three" instead of "foo.two" and "foo.three". =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Database.pod100644000770000024 1225712576552253 23651 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Database; # ABSTRACT: FormHandler use recipes __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Database - FormHandler use recipes =head1 VERSION version 0.40064 =head1 SYNOPSIS L Information on interfacing FormHandler forms and fields with a database. Also see L. =head1 Form Models For a database form, use a model base class that interfaces with the database, such as L, which needs to be installed as a separate package. There's also a sample 'object' model in L, which will update a simple object. When using a database model, form field values for the row are retrieved from the database using the field 'accessor' attributes (defaults to field name) as database class accessors. FormHandler will use relationships to populate single and multiple selection lists, and validate input. A 'single' relationship is processed by L. A 'has_many' relationship is processed by L. Do not use database row method names, such as 'delete', as field names in a database form. You can pass in either the primary key or a row object to the form. If a primary key (item_id) is passed in, you must also provide the schema. The model will use the item_class (DBIC source name) to fetch the row from the database. If you pass in a row object (item), the schema, item_class, and item_id will be set from the row. Executing C<< $form->process( item => $row, params => $params ); >> will validate the parameters and then update or create the database row object. =head1 Fields that map to database relationships =head2 Select A select field will automatically retrieve a select list from the database, if the proper column names are provided. Single selects handle 'belongs_to' relationships, where the related table is used to construct a selection list from the database. See also L and 'lookup_options' in L. =head2 Multiple Select A multiple select is either a 'Select' with multiple => 1 set, or a field of the 'Multiple' type. The name of a Multiple select which pulls options from the database automatically should be the name of the 'many_to_many' relationship. The 'value' of the field is derived from the 'has_many' part of the relationship. The primary key is used for the 'id' of the select. The 'label' column of the select is assumed to be 'name'. If the label column has a different name, it must be specified with 'label_column'. Pertinent attributes: label_column active_column sort_column See also L and L. =head2 Compound fields A compound field represents a single relationship to another table. Although most compound relations can be handled without providing a primary key, in some circumstances you may need to provide a PrimaryKey field, or add extra values in update_model. See also L. The default for compound fields is that if all subfields are empty, the value of the compound field is set to undef (null). For some types of relations, you may want to set the 'not_nullable' flag to force the field to contain all subfields anyway, such as when the related rows are not deleted when empty. See test t/compound/empty.t for a demonstration of the difference in output. =head2 Repeatable fields The 'Repeatable' field type allows you to update arrays of columns from related tables easily. You will need to provide a 'PrimaryKey' hidden field in the compound field contained in the Repeatable. has_field 'addresses' => ( type => 'Repeatable' ); has_field 'addresses.address_id' => ( type => 'PrimaryKey' ); has_field 'addresses.street'; has_field 'addresses.city'; has_field 'addresses.state'; There are some complications with creating Repeatable elements (with the PrimaryKey field set to undef) in a database and re-presenting the form. See L for more info. =head1 Flags =head2 writeonly Do not read the value from the 'item' when populating the form. =head2 noupdate Do not update the database with this field, i.e. do not include it in C<< $form->value >>. =head1 Form generator A DBIC form generator is installed with the L package. See L. There's also a role, L, that allows simple form fields to be auto-generated from a DBIC result class. my $form = HTML::FormHandler::Model::DBIC->new_with_traits( traits => ['HTML::FormHandler::TraitFor::DBICFields'], includes => ['title', 'author' ], field_list => [ 'submit' => { type => 'Submit', value => 'Save', order => 99 } ], item => $book ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Defaults.pod100644000770000024 1421712576552253 23712 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Defaults; # ABSTRACT: form defaults documentation __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Defaults - form defaults documentation =head1 VERSION version 0.40064 =head1 SYNOPSIS L How to set defaults for your fields. =head1 Defaults Defaults for form fields come from a number of different places. The simplest way to set a field's default is on the field definition: has_field 'foo' => ( type => 'Text', default => 'my_foo' ); has_field 'select_many' => ( type => 'Multiple', default => [1, 2, 3] ); You can also set the default for a field with a method in the form with the name 'default_', where any periods in the field name are replaced with underscores. has_field 'foo'; sub default_foo { 'my_default' } Like other field attributes, the 'default' attribute can be modified on new with the 'field_list' attribute, or on 'process' with the 'update_field_list' parameter (or the shorthand form 'defaults'). my $form => MyApp::Form->new( field_list => { '+foo' => { default => 'my_foo' } } ); $form->process( update_field_list => { foo => { default => 'my_foo' } } ); $form->process( defaults => { foo => 'my_foo' }, params => $params ); For forms where you pass in an 'item' (usually a database row object), the values in that object will be used preferentially; if an accessor exists in the 'item' object, then the defaults won't be used. (If an accessor doesn't exist, the defaults *will* be used.) $form->process( item => $row, params => {} ); For the above call the 'default' on the field will not be used, which is usually what you want. When creating a new database record with your form, if you don't pass in an empty row, then the field defaults will be used, or you can provide defaults in an 'init_object'. note: the form class has 'item_class' set already. $form->process( schema => $schema, init_object => $obj ... ); If you provide an empty row object for 'create' type actions, however, you might want some defaults filled in. This can be done by filling the values into the row object or by turning on the form flag 'use_defaults_over_obj'. $form->process( item => $empty_row, use_defaults_over_obj => 1 ); If you always want new DBIC results to be ignored, you could set the flag in a base form method: sub set_active { my $self = shift; $self->next::method; if ( $self->item and ! $self->item->in_storage ) { $self->use_defaults_over_obj(1); } } You could also pass in another object or hashref in the 'init_object' attribute, and set the 'use_init_obj_over_item' flag: $form->process( item => $empty_row, init_object => $example, use_init_obj_over_item => 1 ); Note that the 'use_init_obj_over_item' and 'use_defaults_over_obj' flags are automatically cleared (if you're using persistent forms). For forms where some defaults come from a database row, and some defaults come from some other dynamic source (so that putting them into the field definitions doesn't make sense), you can use the 'use_init_obj_when_no_accessor_in_item' flag to provide two different sets of defaults, one set in the 'item' (usually a db row) and one set in the init_obj. If the 'item' is undefined, the values in the init_object are used. in form: has '+use_init_obj_when_no_accessor_in_item' => ( default => 1 ); $form->process( item => $item, init_object => { foo => '...' }, .. ); There is a convenience method for setting 'defaults' on a number of fields at once, the form's 'defaults' attribute, which uses the same mechanism as 'update_field_list' but only sets defaults. Note that this hashref is structured like the update_field_list with regard to field names, while the 'init_object' uses "structured" data: my $defaults = { model => 'standard', 'opts.color' => 'Red', 'opts.size' => 'Big', }; my $init_object => { model => 'standard', opts => { color => 'Red', size => 'Big' } }; $form->process( defaults => $defaults, ... ); $form->process( init_object => $init_object ... ); In addition, the 'defaults' actually changes the 'default' stored in the field definitions, while the init_object does not. There is also an alternative attribute in the fields, 'default_over_obj', but the new 'use_defaults_over_obj' and 'use_init_obj_over_item' flags, make it less necessary. Note that the 'default_over_obj' attribute only provides a default if an item/init_object and accessor exists. =head2 Defaults when processing params Normally when a form is posted, the params will contain all the values that are necessary to fill in the form. However, when a form is used in an API-like fashion, such as complex search forms, sometimes it is convenient to only provide particular params and let the others use defaults. However when the results are built from input, fields with no input are skipped unless the field has a value for 'input_without_param'. There is an additional form-level flag, 'use_fields_for_input_without_param' which will cause fields with no param entry to be built from the fields. This means that 'defaults' on the field will be used to provide a value and an input for the field. =head2 Query parameters for defaults You can use either the 'defaults' hashref or the 'init_object' to provide query parameter 'defaults'. They should not be provided in the 'params' hash, because then FormHandler will assume that the form has been posted and attempt to validate, which you don't want to do until the form has been submitted. Or you can use the 'posted' flag, to indicate whether or not to perform validation: $form->process( posted => ( $c->req->method eq 'POST' ), params => $c->req->params ); Note that in Catalyst, there are 'query_parameters' and 'body_parameters'. The 'parameters' contains both 'query_parameters' and 'body_parameters'. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Tutorial.pod100644000770000024 2467312576552253 23755 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Tutorial; # ABSTRACT: how to use FormHandler with Catalyst __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Tutorial - how to use FormHandler with Catalyst =head1 VERSION version 0.40064 =head1 SYNOPSIS L A tutorial for beginners to L =head1 Using HTML::FormHandler with Catalyst This tutorial demonstrates how you can use L to manage forms, validate form input, and interface your forms with the database. =head1 Installation Use CPAN to install L =head1 Use the Tutorial application We'll use the files that were created in the L, in order to concentrate on just the bits where HTML::FormHandler is useful. You can download a tar file of the tutorial files from the Catalyst code repository. (See L.) =head2 Create an HTML::FormHandler form Untar the tutorial and make a lib/MyApp/Form directory. In that directory create the file Book.pm. package MyApp::Form::Book; use utf8; # if using non-latin1 languages use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Model::DBIC'; has '+item_class' => ( default => 'Book' ); has_field 'title' => ( type => 'Text' ); has_field 'rating' => ( type => 'Integer' ); has_field 'authors' => ( type => 'Multiple', label_column => 'last_name' ); has_field 'submit' => ( type => 'Submit', value => 'Submit' ); no HTML::FormHandler::Moose; 1; This is your Form class. The form initializes the 'item_class' to the source name of your DBIx::Class result class. The form's fields are defined with the 'has_field' sugar, or in a 'field_list'. The names of the fields should match a column, relationship, or other accessor in your DBIx::Class result class. The basic fields have only a 'type', such as 'Text', or 'Integer'. These types are actually the names of L classes. 'Text' and 'Integer' are types that are provided by HTML::FormHandler, in L and L. The 'Multiple' type will allow you to easily create a multiple select list from the 'authors' relationship. The 'label_column' attribute must be defined because the column in the 'authors' table which is used to create the select list does not have the default column name ('name'). The 'submit' field is necessary if you are going to use FormHandler to render your form. It wouldn't be necessary for hand-built templates or HTML. Eventually you will want to create your own field classes, but for this simple form the default types are adequate. =head2 Connect HTML::FormHandler to your controller Edit lib/MyApp/Controller/Books.pm. Add use Moose: use Moose; BEGIN { extends 'Catalyst::Controller' } use MyApp::Form::Book; Create an attribute to hold your form: has 'form' => ( isa => 'MyApp::Form::Book', is => 'rw', lazy => 1, default => sub { MyApp::Form::Book->new } ); =head2 Add Action to Display and Save the Form In C add the following method: sub edit : Local { my ( $self, $c, $book_id ) = @_; $c->stash( template => 'books/edit.tt2', form => $self->form ); # Validate and insert/update database return unless $self->form->process( item_id => $book_id, params => $c->req->parameters, schema => $c->model('DB')->schema ); # Form validated, return to the books list $c->flash->{status_msg} = 'Book saved'; $c->res->redirect($c->uri_for('list')); } This will handle both creating new books, and updating old books. If $book_id is undefined, then HTML::FormHandler will create a new book from your form. If you pass in a DBIx::Class row object instead of a primary key, you don't need to specify the schema. =head2 Render the form Save a copy of C and create a new file that contains only: [% form.render %] =head2 Alternative hand-built Template for the form (optional) Although the automatic rendering works well, sometimes it's necessary to hand build HTML. This section contains an example of a Template Toolkit template that may be used to display a FormHandler form. In some cases, you might want to use the rendering for just the field and build custom divs or tables or whatever around it:
[% form.render_field('book') %]
If you don't want to play with HTML at this point, you can skip ahead to the next section. You could also use TT macros to do pretty sophisticated template generation. But for now, we'll stick to a straightforward TT template: Delete the single statement in C, and enter or copy the following: [% META title = 'Book Form' %] [% FOR field IN form.error_fields %] [% FOR error IN field.errors %]

[% field.label _ ': ' _ error %]

[% END %] [% END %]

[% f = form.field('title') %]

[% f = form.field('rating') %]

[% f = form.field('authors') %]

Return to book list

=head2 Add links to access create and update actions Add a link to root/src/books/list.tt2 to allow you to edit an existing book, by changing the last cell in the book list: Delete| Edit Change the link to create a book at the bottom of the file:

Create book

=head2 Test the L Create Form Start up the server for MyApp: $ script/myapp_server.pl (You'll need to login with test01/mypass if you're using the packaged tutorial.) Click the new "Create book" link at the bottom to display the form. Fill in the fields and click submit. You should be returned to the Book List page with a "Book saved" message. Magic! A new book has been created and saved to the database with very little code in your controller. Click on the 'edit' links, and edit the existing books. Changes should be saved and displayed properly. Try to add an alphabetic character to the rating field. You should get an error message. =head2 Add additional attributes to your form's fields We'll add a couple of 'label' attributes to the fields: has_field 'title' => ( type => 'Text', label => 'Title of a Book' ); has_field 'rating' => ( type => 'Integer', label => 'Rating (1-5)' ); has_field 'authors' => ( type => 'Multiple', label_column => 'last_name' ); If you want a new attribute in your fields, it's very easy to add it to your custom Field classes. package MyApp::Form::Field::Extra; use Moose; extends 'HTML::FormHandler::Field'; has 'my_attribute' => ( isa => Str, is => 'ro' ); 1; Now if your Field classes inherit from this, you can have a 'my_attribute' attribute for all your fields. Or use a Moose role instead of inheritance. You can also add attributes to the base FormHandler field class using Moose. This technique is described in L. =head1 L Validation Now we'll add more validation to ensure that users are entering correct data. Update the fields in the form file: has_field 'title' => ( type => 'Text', label => 'Title of a Book', required => 1, size => 40, minlength => 5 ); has_field 'rating' => ( type => 'Integer', label => 'Rating (1-5)', required => 1, messages => { required => 'You must rate the book' }, range_start => 1, range_end => 5 ); has_field 'authors' => ( type => 'Multiple', label_column => 'last_name', required => 1 ); We've made all the fields required. We added 'size' and 'minlength' attributes to the 'title' field. These are attributes of the 'Text' Field, which will use them to validate. We've added 'range_start' and 'range_end' attributes to the 'rating' field. Numbers entered in the form will be checked to make sure they fall within the defined range. (Another option would have been to use the 'IntRange' field type, which makes it easy to create a select list of numbers.) =head2 Add customized validation You can create a Field class for validation that will be performed on more than one field, but it is easy to perform custom validation on a per-field basis. This form doesn't really require any customized validation, so we'll add a silly field constraint. Add the following to the form: sub validate_title { my ( $self, $field ) = @_; $field->add_error("The word \'Rainbows\' is not allowed in titles") if ( $field->value =~ /Rainbows/ ); } You can also apply Moose constraints and transforms. Validation can also be performed in a form 'validate_ ( type => 'Captcha', label => 'Verification' ); sub get_captcha { my $self = shift; return unless $self->ctx; my $captcha; $captcha = $self->ctx->session->{captcha}; return $captcha; } sub set_captcha { my ( $self, $captcha ) = @_; return unless $self->ctx; $self->ctx->session( captcha => $captcha ); } sub captcha_image_url { return '/captcha/image'; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::TraitFor::Captcha - generate and validate captchas =head1 VERSION version 0.40064 =head1 SYNOPSIS A role to use in a form to implement a captcha field. package MyApp::Form; use HTML::FormHandler::Moose; with 'HTML::FormHandler::TraitFor::Captcha'; or my $form = MyApp::Form->new( traits => ['HTML::FormHandler::TraitFor::Captcha'], ctx => $c ); Needs a context object set in the form's 'ctx' attribute which has a session hashref in which to store a 'captcha' hashref, such as is provided by Catalyst session plugin. =head1 METHODS =head2 get_captcha Get a captcha stored in C<< $form->ctx->{session} >> =head1 set_captcha Set a captcha in C<< $self->ctx->{session} >> =head2 captcha_image_url Default is '/captcha/image'. Override in a form to change. sub captcha_image_url { '/my/image/url/' } Example of a Catalyst action to handle the image: sub image : Local { my ( $self, $c ) = @_; my $captcha = $c->session->{captcha}; $c->response->body($captcha->{image}); $c->response->content_type('image/'. $captcha->{type}); $c->res->headers->expires( time() ); $c->res->headers->header( 'Last-Modified' => HTTP::Date::time2str ); $c->res->headers->header( 'Pragma' => 'no-cache' ); $c->res->headers->header( 'Cache-Control' => 'no-cache' ); } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut ApplyRole.pm100644000770000024 362112576552253 23667 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widgetpackage HTML::FormHandler::Widget::ApplyRole; # ABSTRACT: role to apply widgets use Moose::Role; use File::Spec; use Class::MOP; use Try::Tiny; use Class::Load qw/ load_optional_class /; use namespace::autoclean; our $ERROR; sub apply_widget_role { my ( $self, $target, $widget_name, $dir ) = @_; my $render_role = $self->get_widget_role( $widget_name, $dir ); $render_role->meta->apply($target) if $render_role; } sub get_widget_role { my ( $self, $widget_name, $dir ) = @_; my $widget_class = $self->widget_class($widget_name); my $ldir = $dir ? '::' . $dir . '::' : '::'; my $widget_ns = $self->widget_name_space; my @name_spaces = @$widget_ns; push @name_spaces, ('HTML::FormHandler::Widget', 'HTML::FormHandlerX::Widget'); my @classes; if ( $widget_class =~ s/^\+// ) { push @classes, $widget_class; } foreach my $ns (@name_spaces) { push @classes, $ns . $ldir . $widget_class; } foreach my $try (@classes) { return $try if load_optional_class($try); } die "Can't find $dir widget $widget_class from " . join(", ", @name_spaces); } # this is for compatibility with widget names like 'radio_group' # RadioGroup, Textarea, etc. also work sub widget_class { my ( $self, $widget ) = @_; return unless $widget; if($widget eq lc $widget) { $widget =~ s/^(\w{1})/\u$1/g; $widget =~ s/_(\w{1})/\u$1/g; } return $widget; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::ApplyRole - role to apply widgets =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut NonEditable.pm100644000770000024 172412576552253 23746 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::NonEditable; # ABSTRACT: reset field use Moose; extends 'HTML::FormHandler::Field::NoValue'; has '+widget' => ( default => 'Span' ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::NonEditable - reset field =head1 VERSION version 0.40064 =head1 SYNOPSIS Another flavor of a display field, but unlike L it's intended to be rendered somewhat more like a "real" field, like the 'non-editable' "fields" in Bootstrap. has_field 'source' => ( type => 'NonEditable', value => 'Outsourced' ); By default uses the 'Span' widget. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Reference.pod100644000770000024 2243312576552253 24040 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Reference; # ABSTRACT: concise reference __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Reference - concise reference =head1 VERSION version 0.40064 =head1 DESCRIPTION L This is a concise reference of HTML::FormHandler. HTML::FormHandler has a lot of options and many ways to customize your forms. More complete documentation can be found in the rest of the manual as L and in L, L, L, L, and in the individual field classes. =head1 Form =head2 Form Attributes params HTTP parameters; if present validation will be attempted name Form name. Used in 'id' of form element field_name_space Where to search for fields widget_name_space Where to search for widgets language handle For MakeText ctx Application context for your use init_object For default values instead of $item dependency Array of arrays of field names. If one name has a value, all fields in the list are set to 'required' fields Field array sorted_fields The sorted array of fields field( $name ) Returns a field object has_field Moose-y sugar for declaring fields field_list Non-moose-y way to define fields clear Resets state. Used in persistent forms. value Returns a hashref of values (with accessor keys) fif Returns a hashref for filling in form =head2 Form database attributes item DB row object item_class Class of db item item_id Primary key of db item schema Schema of item Also 'update_model' sub =head2 Form processing process Sets up form, validates, updates model run Returns a result object and clears form update_field_list Updates to fields on process posted Flag to say whether or not to validate, instead of depending on presence of params =head3 Validation validate Sub for validation after individual fields are validated validate_model Sub for additional database type validation validated Flag that form has validated is_valid Synonym of 'validated' ran_validation Flag that validation has already been run dependency Set groups of fields that are set to required if one is present validate_$fieldname Validation routine for field (also 'validate_method') =head3 Errors has_errors True if any field has errors num_errors The number of errors (field errors + form errors) error_fields An array of fields with errors errors Returns an array of all errors error_field_names Returns an array of field names with errors =head3 Form Methods and process hooks update_model To perform additional database actions on update update_fields Sub providing convenient place to update fields on 'process' update_subfields Sub providing place to update fields on Build (useful for roles and compound field classes) init_object can be a method instead of an attribute =head3 Form Rendering html_prefix Flag to prefix html field names with the form name. Useful for multiple instances of the same form do_form_wrapper flag to wrap form. (build_do_form_wrapper) form_tags Various strings and flags used by rendering form_element_attr For arbitrary html attributes in the 'form' tag form_element_class Arrayref of classes for 'class="..."' in form element form_wrapper_attr For arbitrary html attributes on the form wrapper form_wrapper_class Arrayref of classes for 'class="..."' in form wrapper http_method For storing 'post' or 'get' action Store the form 'action' on submission. No default value. enctype Request enctype uuid generates a string containing an HTML field with UUID style adds a 'style' attribute to the form tag id the form tag 'id' attribute is set to the form name html_attributes hook that allows customizing html attributes (form & field) =head2 Field specific form methods options_$fieldname Sub returning options array (also 'options_method') validate_$fieldname Validation routine for field (also 'validate_method') default_$fieldname Set default for field (also 'default_method') =head1 Fields =head2 Field attributes name Field name. Must be the same as database column name or rel type Field type. From a Field class: 'Text', 'Select', etc order Set the order for fields. Default order is set by FH. dump For debugging active Arrayref of fields to set active is_active inactive Arrayref of fields to set inactive is_inactive input_without_param The value of the field if there is no input from the submitted form default Default value for the field default_method Coderef to set default or 'default_$fieldname' (by default) not_nullable Don't convert an empty field ('', etc) to undef trim Transform to trim the field deflation Function to deflate the field (in 'apply') (opposite of transform) deflate_method Coderef to deflate the field (for filling in the form) inflate_method Coderef to inflate the field (before validation) inflate_default_method Coderef to inflate value from item/init_object deflate_value_method Coderef to deflate value after validation fif_from_value Flag to use 'value' of field for 'fif'. password Remove from params and do not display in forms. =head2 Select fields options Sorted array of hashes; keys: "value", "label" options_method label_column Column to use for labels (default: name) active_column Which values to list in options sort_column Column to use for sorting (default: label_column) =head2 Field errors errors Errors associated with this field (also num_errors, clear_errors, has_errors, add_error) messages Hashref of message identifiers and text =head2 Field validation apply Array of constraint/coercion/transformation actions ( type, check, transform, message, when ) validate_method Validation coderef, or 'validate_$fieldname' in form (default) required Field is required required_when Takes a hashref of field name keys and values missing Flag set when a 'required' or 'required_when' fails maxlength Text fields. Validated. minlength Text fields. Used in validation range_start Range start for number fields range_end Range end for number fields =head2 Field attributes for DB accessor Database accessor name if different than field name unique Field should be unique in the database noupdate Don't update this field in the database writeonly Do not retrieve initial values Also see the select field _columns attributes =head2 Field rendering widget Determines which rendering widget to use for the field widget_wrapper Which wrapper widget to apply to the field element_attr Hashref to store arbitrary html attributes. label_attr Hashref for html attributes for the label wrapper_attr Hashref for html attributes for the wrapping element (div, etc) element_class Arrayref for classes for the form element wrapper_class Arrayref for classes for the form element wrapper label_class Arrayref for classes for the form element label label Text label for this field. Defaults to ucfirst field name. build_label_method provide a builder for 'label' attribute wrap_label_method provide a coderef to wrap the label id Useful for javascript (default is html_name. to prefix with form name, use 'html_prefix' in your form) build_id_method Provide a builder for 'id' attribute do_wrapper Flag to render wrapper do_label Flag to render label size Text & select fields. render Widget method to render the field ($field->render) renderx "" plus set attributes ($field->render( element_class => '...' )) render_element Widget method to render unwrapped field ($field->render_element) render_elementx "" plus set attributes ($field->render_elementx( element_class => '...')) =head2 Field attributes managed by FormHandler These attributes are usually accessed in a subroutine or in a template, but are usually set only by FormHandler. ('value' may be changed as a transform _in a validation routine_.) init_value Initial value from the database value The value of your field. input Input value from parameter or initial value from database fif Retrieve (do not set) values for filling in a form =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Rendering.pod100644000770000024 7003212576552253 24055 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Rendering; # ABSTRACT: how to render with FormHandler __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Rendering - how to render with FormHandler =head1 VERSION version 0.40064 =head1 SYNOPSIS L Rendering can be done in many different ways, from forms rendered entirely in templates with no information from FormHandler (except possibly the fill-in-the-form values) to forms that are completely rendered by FormHandler. =head1 DESCRIPTION For most situations, something in between hand-built and completely generated will probably be the best solution. For admin forms that don't need a lot of styling or special HTML, FormHandler's automatic rendering may be appropriate. FormHandler rendering may also be a good solution if you have enough forms that putting time into creating rendering widgets and themes is worthwhile. The automatic rendering is also useful when developing a new form. You can get an idea of what it looks like, and then customize it. Another situation in which FormHandler rendering may be useful is when the form is complex enough that working in Perl is a better idea than putting lots of logic into templates. All of the rendering is designed to be easily replaced with elements of your own, or to be replaced entirely. You can create your own rendering 'widgets' and load them into the fields by designating the directory in the 'widget_name_space'. You could also create a completely separate renderer that's a separate object or class that takes a form object, or a role that is applied to your form. Note that unless you set 'no_widgets' in the form, the rendering roles are automatically applied. You don't need to include anything else, unless you want to use a different renderer. =head2 Mostly templates The names of your fields must match the names of your FormHandler fields. If you use compound fields, you must use the FormHandler naming convention. Form used in examples: package MyApp::Form::Example; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; has_field 'foo'; has_field 'bar'; has_field 'save' => ( type => 'Submit' ); If you have existing forms in templates or just prefer them, you can use the 'fill-in-form' values provided with the form's 'fif' function. my $form = MyApp::Form::Example->new; $form->process( params => $params ); $c->stash( fif => $form->fif ); ...
If you are looking for an easy way to get your fields to line up in an evenly spaced manner, all uniformly aligned, and to do so without using templates or tables, you can externally style the default FormHandler output with the following CSS rule (not supported in internet explorer 6). *I *I form#id_of_your_form div div label, form#id_of_your_form div div input { float: left; display: inline-block; width: 40% } /* make sure the parent element is sized appropriately. 700px is a good width */ Going a little bit farther in using FormHandler rendering, you can render each of the fields individually, using 'render' or 'renderx':
My Foo [% form.field('foo').render %]
[% form.field('bar').renderx(element_class => 'cb33') %] [% form.field('save').render %]
If you don't want the wrappers, use a widget_wrapper of 'None'. has '+widget_wrapper' => ( default => 'None' ); Then you can provide the HTML in which the form elements are embedded:
[% form.field('foo').render %]
[% form.field('bar').renderx(element_class => 'cb33') %]
You can also use the 'render_element' or 'render_elementx' methodx, if you want to leave the wrapper in place, but sometimes render 'bare' html elements:
[% form.field('foo').render_element %]
[% form.field('foo').render_elementx(element_class => 'cb33') %]
If you wish to loop through the fields yourself, use the 'sorted_fields' method, since it skips inactive fields and handles the 'order' attribute. A set of Template Toolkit templates is also provided in the 'share' directory. There are individual templates for each 'widget', such as a checkbox, and there is also an all-in-one template that includes blocks for the various 'widgets'. If you want to use these templates you can just copy them to your template directory and specify the form template in your controller. See also L. =head2 Automatic rendering If you take all the defaults, you can simply render a form with C<< $form->render >>. [% form.render %] or [% form.renderx( form_element_class => ['xxx'] ) %] This uses the L role, which is applied to the form by default. You can use a different form rendering role by including it using 'with': with 'HTML::FormHandler::Widget::Form::Table'; has '+widget_wrapper' => ( default => 'Table' ); For the 'Table' form widget, you will also need to set the matching Table widget_wrapper. A widget role, providing the 'render' method, and a widget wrapper role, providing the 'wrap_field' method, are applied to each field when the form is built. Each field has a default widget, but you can change that by setting 'widget' to a different widget role: has_field 'foxy' => ( widget => 'MyWidget', widget_wrapper => 'MyWrapper' ); Often if you need custom rendering what you need to provide is a custom widget_wrapper. The 'widgets' render only the input elements, and that often doesn't need to be changed. If you have standard HTML that is used when rendering forms, making custom widget_wrappers is often the way to go. Default widget roles are found in the HTML::FormHandler::Widget directory, in the 'Field', 'Form', and 'Wrapper subdirectories. The name space used to look for the widget roles can be specified on a form or field basis by setting 'widget_name_space' to an arrayref of name spaces: has '+widget_name_space' => ( default => sub { ['MyApp::Form::Widget' ] } ); For the above widget ('MyWidget') and widget_name_space, you need to have a package named 'MyApp::Form::Widget::Field::MyWidget'. The HTML::FormHandler::Widget name space is always searched as the last name space. This means that you can set up an application or form specific set of widgets. Widgets in a widget directory (specified in widget_name_space) are located in either a 'Field', 'Wrapper', or 'Form' subdirectory. (Blocks are in a 'Blocks' subdirectory.) You can also create an 'all-in-one' type rendering role, using L as a basis. It used the method name 'render_field' on the form ( C<< $form->render_field('field_name') >> ) instead of the 'render' method on the field. In addition to the 'Simple' wrapper, there is a 'Bootstrap' wrapper which creates HTML formatted to use the Twitter Bootstrap 2.0 CSS. There's also a sample "theme", L, which is a role that sets the widget_wrapper to 'Bootstrap', and provides Bootstrap-type formatting of the form error message. There are a lot of different settings that control the rendering. Some of them are attributes in the form or field, and some of them are set using the 'tags' hashref in the field or the 'form_tags' hashref in the form. You can make your own copy of an existing wrapper and add features to it. However, there are so many different ways to render the HTML around a field, that it's very difficult to handle more than a short list of standard presentations in one 'wrapper'. It may be better to make a number of more atomic widget wrappers and use those rather than complicate the already fairly complicated "Simple" and "Bootstrap" wrappers more. =head2 HTML attributes Arbitrary HTML attributes on form elements (such as 'input' elements) can be specified with 'element_attr' on the field. You can also set attributes for the label with 'label_attr' and attributes for the wrapper with 'wrapper_attr'. The 'class' attributes are handled separately, and are arrayrefs (element_class, wrapper_class, label_class): has_field 'foo' => ( wrapper_class => ['form', 'special' ] ); See the documentation on L. =head2 Form settings =over 4 =item widget_wrapper The short name of the rendering wrapper widget to be applied to the fields. When the fields are constructed this is merged into fields that do not already set a widget wrapper. =item do_form_wrapper Flag set with 'sub build_do_form_wrapper{ 1 }'. Default is no form wrapper. =item form_tags Hashref of various tags used in rendering code. See the documentation for L. =item form_element_attr Hashref of arbitrary HTML attributes to be included in the form element. sub build_form_element_attr { [ ... ] } =item form_element_class Arrayref of classes to be included in the form element. form_element_class => ['hfh', 'admin'] -- or in your class -- sub build_form_element_class { ['hfh', 'admin'] } The above class would produce a form element:
=item form_wrapper_attr Hashref of arbitrary HTML attributes to be included in the form wrapper sub build_form_wrapper_attr { { name => 'formname' } } =back =head2 Form messages Some messages are rendered at the top of the form (inside the form tag) by the 'render_form_messages' method, which is implemented in L and L (which is included by the Bootstrap theme). There are three types of form messages: 'error_message', 'success_message', and 'info_message'. The 'error_message' and 'success_message' are set inside the form: has '+success_message' => ( default => 'Form successfully submitted' ); has '+error_message' => ( default => 'There were errors in your form.' ); And then are displayed after the form is validated. The 'info_message' is cleared out when a form is re-processed, and so would normally be set on the process call, or between new & process. $form->process( params => {}, info_message => 'Fill in the form' ); =head2 Field settings has_field 'foo' => ( widget => 'MyWidget', widget_wrapper => 'SpecialWrapper', element_attr => { placeholder => 'enter a foo' }, element_class => 'important', wrapper_class => ['label'], label_class => ['major'], tags => { wrapper_tag => 'fieldset' } ); =over 4 =item widget Short name of the rendering widget for this field. =item widget_wrapper Short name of the wrapping widget for this field. =item do_wrapper Flag that indicates whether or not the 'wrapper' should be rendered. =item do_label Flag that indicates whether or not a label should be rendered. =item element_attr Hashref of arbitrary HTML attributes to include in the element. Note that this does not include the 'id' and 'type' attributes, which are handled separately. The 'id' can be changed with the field's 'id' attribute. =item element_class Arrayref of classes to include in the element. =item wrapper_attr Hashref of arbitrary HTML attributes to include in the wrapper. =item wrapper_class Arrayref of classes to include in the wrapper. =item label_attr Hashref of arbitrary HTML attributes to include in the label. =item label_class Arrayref of classes to include in the label. =item build_id_method Coderef to construct the 'id'. Useful if your javascript needs a different format for the 'id'. =item build_label_method Coderef to construct the label. =item wrap_label_method Coderef to wrap the label. Used by the Simple and Bootstrap wrappers. Useful if your label contains HTML or a link. You must do your own localization and filtering if you use a 'wrap_label' method. =back =head2 html_attributes callback The form has an 'html_attributes' callback which can be used to customize, localize, or modify the various attributes when used. Types: element, wrapper, label, form_element, form_wrapper, checkbox_label sub html_attributes { my ( $self, $obj, $type, $attrs, $result ) = @_; # obj is either form or field $attrs->{class} = 'label' if $type eq 'label'; $attrs->{placeholder} = $self->_localize($attrs->{placeholder}) if exists $attrs->{placeholder}; return $attrs; } This callback is called in the methods that wrap the various '_attr' attributes, i.e. element_attributes, label_attributes, wrapper_attributes, form_element_attributes, form_wrapper_attributes. =head2 Field tags The 'tags' are settings and strings which may vary by the particular widget that implements them. The best place to look for documentation on them is in the field widget, field wrapper, and form widgets that you are using. The 'tags' allow customizing rendering behavior on a per-field basis. FormHandler has a number of flags/settings that it uses; you can add your own for your custom rendering code. wrapper_tag -- the tag to use in the wrapper, default 'div' label_tag -- tag to use for label (default 'label') label_after -- string to append to label, for example ': ' to append a colon Tags can be used to switch the Simple wrapper from divs to using paragraphs instead, or to add a colon in label formatting: has_field 'my_field' => ( tags => {wrapper_tag => 'p', label_after => ': ' } ); Most of the tags are implemented by the 'wrapper' widget, so see that documentation for more details: L, L. =head3 Tag types The 'get_tag' method will check for these three types of tags and perform the appropriate action. =over 4 =item String Standard, most common type of value for a tag. has_field 'bar' => ( tags => { before_element => '...' } ); Some tags are true/false also: has_field 'foo' => ( type => 'CheckBox', tags => { no_wrapped_label => 1 } ); =item CodeRef You can supply a coderef to a tag, and it will be executed as a method on the field. This is useful for localization or other sorts of runtime changes. has_field 'bar' => ( tags => { before_element => \&bar_element } ); sub bar_element { my $self = shift; # $self is the 'bar' field return '
In a Sub
'; } =item Block You can supply a block by giving a string that consists of a '%' followed by the block name: has_block 'comment' => ( tag => 'a', content => 'This is a comment from a block', class => ['comment' ] ); has_field 'foo' => ( tags => { before_element => '%comment' } ); =back =head3 Tags and other settings for all fields Tags can be set for all fields in the form by using a 'build_update_subfields' sub, or 'widget_tags'. The 'update_subfields' hashref takes general-purpose keys 'all', 'by_flag' (compound, repeatable, contains), and 'by_type'. You can also set specific field attributes by using the field name as a key. For example, if you don't want errors to be displayed next to the fields, you need to set the 'no_errors' tag: sub build_update_subfields {{ all => { tags => { no_errors => 1 }, wrapper_class => ['myapp'] }, by_type => { Text => { element_class => ['text'] } }, by_flag => { compound => { do_wrapper => 1 } }, foo => { label => 'My Foo' }, }} -- or -- '+widget_tags' => ( default => sub { { no_errors => 1 } } ); The 'widget_tags' attribute only handles the 'tags' hashref, so if you also want to set classes or attributes, then build_update_subfields is more useful. You can also use 'build_update_subfields' in a custom compound field class. If you have defaults that are set in 'build_update_subfields' in a base class, in order to use hashrefs from both base and current classes, you will need to merge the hashes: use HTML::FormHandler::Merge ('merge'); sub build_update_subfields { my $self = shift; my $new = { all => { tags => { wrapper_tag => 'p' } } }; return merge( $new, $self->next::method(@_) ); } In a role you would have to do the equivalent with an 'around' method modifier. =head3 Repeatable field instances The repeatable field instances are constructed internally, so it's trickier to set things like wrapper tags. There are two ways to do it, using the 'init_contains' attribute on the repeatable field, and using the 'update_subfields' builder: has_field 'records' => ( type => 'Repeatable', num_when_empty => 2, init_contains => { tags => { wrapper_tag => 'fieldset' } } ); -- or -- sub build_update_subfields { { by_flag => { contains => { tags => { wrapper_tag => 'fieldset' }}}}} The 'build_update_subfields' option is mainly useful if you have multiple repeatable fields that you want to set, or if you want defaults in a base class. =head3 widget and widget_wrapper set to 'None' If you want to implement the 'render' method in a custom field, you can set 'widget' to 'None' and no widget will be applied. Setting the 'widget_wrapper' to 'None' will apply the 'None' wrapper, which simply returns the widget rendering. =head3 Error messages The default is currently to display error messages next to the rendered fields, if you're doing C<< $form->render >>. If you don't want messages next to fields, you can set the 'no_errors' tag, as discussed in the section on 'Tags and other settings...'. Note that the 'None' widget wrapper, since it doesn't render anything except the form element (input, select, etc), will not render errors next to the field. Setting the 'do_wrapper' and 'do_label' flags to 0 will still render errors. =head2 Blocks When rendering, FormHandler loops through the sorted fields in the form and executes the 'render' method on each field. Fields in FormHandler forms, particularly those that interface with a database, are usually structured in a way that matches the data structure. This doesn't always fit with the way that you want to display the form. 'Blocks' provide an alternative way of structuring the display. A 'block' is a fairly basic object that contains a 'render' method. The standard block class, L, has Moose attributes to set the HTML tag, the label, the classes, etc, plus a 'render_list' which contains the names of a list of fields or other blocks to render. Here is the definition of a fieldset block that contains two fields: has_field 'foo'; has_field 'bar'; has_block 'first_fset' => ( tag => 'fieldset, label => 'Two Fields', render_list => ['foo', 'bar'] ); The 'first_fset' block will render like this:
Two Fields
In order to actually get this block to be used when you render with C<< $form->render >>, you need to supply a 'render_list' on the form level: sub build_render_list { ['first_fset', 'submit_btn'] } You could also render it with C<< $form->block('first_fset')->render >>. Blocks should be located in a widget name space, in a 'Block' directory, or else the name should be prefixed with a '+'. has '+widget_name_space' => ( default => sub { ['MyApp::Form::Widget'] }; has_block 'first' => ( type => 'MyBlock', ... ); The 'MyBlock' above will be found in 'MyApp::Form::Widget::Block::MyBlock'. has_block 'intro' => ( type => '+MyApp::Form::Component::Intro' ); A block can inherit from L, but it doesn't have to. At a minimum it must provide 'new' and 'render' methods. If no 'type' is specified, the block is created from the L package. The following package provides a functional block: package MyApp::Component::Section; sub new { my ( $class, %args ) = @_; return bless \%args, $class; } sub form { my $self = shift; return $self->{form}; } sub render { return '

Please enter the relevant details

'; } 1; When a form is rendered, it will either loop through all of the sorted_fields OR loop through the fields and blocks listed in the 'render_list'. A render_list can contain a mix of fields and blocks. Note that you must be rendering with widgets to use block rendering. =head2 Twitter Bootstrap 2.0 rendering The main component of Bootstrap rendering is L. It produces the standard Bootstrap-style HTML such as:
These are the standard 'control' blocks for Bootstrap vertical and horizontal forms. You can apply this wrapper to all of your fields by setting the widget_wrapper in the form: has '+widget_wrapper' => ( default => 'Bootstrap' ); There is also a sample "theme": L. It sets the widget_wrapper for you and provides a 'render_form_messages' method to render a success/error messages section. There are a couple of examples in the t/bootstrap directory of Bootstrap inline and search forms, which don't use exactly the same kind of control HTML. You can always copy the existing wrapper and add your own features, with settings provided by the 'tags' hashref. =head2 Rendering themes Many of the flags and settings necessary for rendering can now be moved out into a role. Whether you want to do that or not is a matter of style and preference. The advantage is that it leaves the form class itself cleaner and easier to read. The disadvantage is that your settings come from more different places. Here's an example of a form rendering 'theme', taken from the t/bootstrap/basic.t test: package MyApp::Form::Basic::Theme; use Moose::Role; # make a wrapper around the form sub build_do_form_wrapper {1} # set the class for the form wrapper sub build_form_wrapper_class { ['span9'] } # set the class for the form element sub build_form_element_class { ['well'] } # set various rendering tags sub build_form_tags { { wrapper_tag => 'div', before => qq{

With v2.0, we have lighter and smarter defaults for form styles. No extra markup, just form controls.

\n}, after => '
', } } # the settings in 'build_update_subfields' are merged with the field # definitions before they are constructed sub build_update_subfields {{ # all fields have a label but no wrapper all => { do_wrapper => 0, do_label => 1 }, # set the element class, a placeholder in element_attr foo => { element_class => ['span3'], element_attr => { placeholder => 'Type something…' }, tags => { after_element => qq{\nAssociated help text!} } }, bar => { option_label => 'Check me out', label_class => ['checkbox'], do_label => 0 }, submit_btn => { element_class => ['btn'] }, }} Note that the value 'all' key in the update_subfields hashref will be merged into the attributes used when building all of the fields. =head2 Rendering fields The default for most fields is a 'div' wrapper and a label. If you don't want the wrapper, set C<< do_wrapper => 0 >>. If you don't want the label, set C<< do_label => 0 >>. Checkboxes are most complicated, in that the default is to have two labels. The outer label, the one that's in the same place as the label for other input elements, is set with C<< label => '...' >>. The inner label, which is the equivalent of the C<< label => '...' >> in the options array used for selects and checkbox groups, is set with C<< option_label => '...' >>. There are a number of other 'tags' to control the presentation. See L for more information, and t/render/checkbox.t for examples. Some fields by default do not render a label: Button, Submit, Reset, ButtonTag. If you do want a label with these fields, you must set the 'do_label' flag to 1: has_field 'foo' ( type => 'Button', do_label => 1 ); Select fields are also fairly complicated. They can be rendered with the 'Select', 'RadioGroup', and 'CheckboxGroup' widgets. Option groups are also supported. See L; =head2 Rendering labels A 'standard' label is built in the field if you don't supply one. The label can be provided in the field definition: has_field 'foo' => ( label => 'My Foo' ); You can also provide a method to 'build' the label: has_field 'foo' => ( build_label_method => \&build_label ); sub build_label { my $self = shift; # field method return '...'; } And a method to 'wrap' the label (used by the Simple and Bootstrap wrappers): has_field 'foo' => ( label => 'My Foo', wrap_label_method => \&wrap_label ); sub wrap_label { my ( $self, $label ) = @_; # or: my $label = $self->label; return qq{$label}; } This is particularly useful for creating labels that have links or other HTML. The 'wrap_label_method' does no filtering or localization, so you must do that yourself in the method if you need it. =head2 Rendering filter The base field class has a 'render_filter' attribute which is a coderef used to clean the values used to fill in the form for Render::Simple and the Widgets, and for some of the labels.. The default filter changes quote, ampersand, <, and > to the equivalent html entities. If you wish to use some other sort of filtering, you can use the 'render_filter' method in your form, or set a coderef on individual field objects. A 'render_filter' function in your form will be used by all fields. Setting it for a field will just be for that field. sub render_filter { my $string = shift; $string =~ s/my/MY/g; # perform some kind of transformation return $string; } -- or -- has_field 'foo' => ( render_filter => sub { ... } ); The filter is called in Render::Simple and in the widgets with C<< $self->html_filter( $fif ) >> or C<< $field->html_filter( $fif ) >>. If you want to turn off the filter for a particular field, you can set it to a sub that just returns the value: has_field 'bar' => ( render_filter => sub { shift } ); If you want a label that is unfiltered, see 'wrap_label_method'. =head1 Special rendering pseudo-fields Also see L. Blocks may be a better solution than pseudo-fields (i.e. fields that aren't actual form elements). Various 'tags' used for rendering can also be used for similar purposes. =head2 NonEditable Like a Bootstrap 'non_editable' field. Displays the field's value as a span. has_field 'non_edit' => ( type => 'NonEditable', value => 'This is a Test' ); =head2 Display L You can supply an HTML string to this field, to be displayed directly. There is no 'value' associated with this field; it's a field for rendering only. The HTML string can be built with a form or field method. Blocks or tags will often be a better solution. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Templates.pod100644000770000024 2210712576552253 24076 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Templates; # ABSTRACT: using templates __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Templates - using templates =head1 VERSION version 0.40064 =head1 SYNOPSIS L Documentation on templates to use with L =head1 Using templates There is a FormHandler Template Toolkit rendering role at L, with a testcase in t/render_withtt.t. Normally, however, it probably won't make much sense to use both a TT parser in FormHandler, and a separate one for the "complete" templates, so the TT renderer is mainly useful for tests, or as an example of how to do TT rendering with HFH. You should create a template to render your form and then pass the template name and a template variable containing your form object to your templating or view engine, in whatever way you normally do that. If you want to use the 'process_attrs' function, you need to set that in your template variables too. A common way of using FormHandler with templates is to use the template for layout, specifying the divs and spans and wrappers, and then use the form object to render just the input fields. In your form: has '+widget_wrapper' => ( default => 'None' ); In your Catalyst controller: $c->stash( form => $form, template => 'form.tt' ); ..or do the equivalent for your web framework/view. In a form template (form.tt in the previous controller example):
My Foo [% form.field('foo').render %]
[% form.field('bar').render %]
[% form.field('save').render %] However, you can also render entirely with templates. There are lots of different ways to set up templates. There are sample templates installed in FormHandler's 'share' directory. These templates are now organized more-or-less similarly to the widget roles, with 'field', 'wrapper', and 'form' directories, but many other organizations are possible. There is also a template which combines the template rendering code into one file, 'share/templates/form/form_in_one.tt'. You can copy this template into your own TT directories, perhaps as form.tt, and then specify it as the template for your Catalyst actions. You can customize it by adding additional widget and widget_wrapper blocks, and then setting those in your field definitions. Note that widget names usually are camelcased, like the Moose roles that implement them in the Widget directory. You may want to use the non-camelcased widget/wrapper names in your TT templates, using the C<< $field->uwidget >> (un-camelcased widget name) and C<< $field->twidget >> (un-camelcased widget name + '.tt') convenience methods. ('MySpecialWidget' is the equivalent of 'my_special_widget') has_field 'my_field' => ( widget => 'MySpecialWidget' ); has_field 'another_field' => ( widget => 'YetAnotherWidget' ); And include them in a generic template: [% PROCESS widget/form_start.tt %] [% FOREACH f IN form.sorted_fields %] [% PROCESS widget/${f.twidget} %] [% END %] [% PROCESS widget/form_end.tt %] =head1 Field attributes If you want to use the 'process_attrs' function to pull in HTML attributes for the input elements, wrappers, and labels, you would need to pass that function into your TT setup. See L for an example: use HTML::FormHandler::Render::Util ('process_attrs'); $c->stash( process_attrs => &process_attrs ); # or add to TT vars in your view =head1 Sample templates The following is copied from the provided share/templates/form/form_in_one.tt file, as an example. Note that some fields, like form actions of 'submit' & 'reset', don't use the 'fif' value, but just the plain field value. [% PROCESS form_start -%]
[% FOREACH err IN form.form_errors -%] [% err %] [% END -%]
[% FOREACH f IN form.sorted_fields -%] [% WRAPPER "wrapper_${f.uwrapper}" -%][% PROCESS "${f.uwidget}" -%][% END -%] [% END -%] [% PROCESS form_end -%] [% BLOCK form_start -%] [% END -%] [% BLOCK form_end -%] [% END -%] [% BLOCK button -%] [% END -%] [% BLOCK checkbox -%] [%~ ~%] [% END -%] [% BLOCK checkbox_group -%] [% FOR option IN f.options -%] [% END -%] [% END -%] [% BLOCK compound -%] [% FOREACH sf IN f.sorted_fields -%] [% outerf = f; f = sf; -%] [% WRAPPER "wrapper_${f.uwrapper}" %][% PROCESS "${f.uwidget}" -%][% END -%] [% f = outerf -%] [% END -%] [% END -%] [% BLOCK hidden -%] [% END -%] [% BLOCK password -%] [% END -%] [% BLOCK radio_group -%] [% FOR option IN f.options -%] [% END -%] [% END -%] [% BLOCK repeatable -%] [% FOREACH rf IN f.sorted_fields -%] [% outerrf = f; f = rf; -%] [% WRAPPER "wrapper_${f.uwrapper}" %][% PROCESS "${f.uwidget}" -%][% END -%] [% f = outerrf -%] [% END -%] [% END -%] [% BLOCK reset -%] [% END -%] [% BLOCK select -%] [% END -%] [% BLOCK submit -%] [% END -%] [% BLOCK text -%] [% END -%] [% BLOCK textarea -%] [% END -%] [% BLOCK upload -%] [% END -%] [% BLOCK wrapper_simple -%] [% IF f.do_label %][% PROCESS label %][% END -%] [% content -%] [% END -%] [% BLOCK label -%] [% END -%] [% BLOCK wrapper_wrap_label -%] [%~ content ~%][%~ f.label %] [% END -%] [% BLOCK wrapper_none -%] [% content %] [% END -%] [% BLOCK wrapper_fieldset -%] [% f.label %] [% content -%] [% END -%] =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Field000755000770000024 012576552253 22303 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/WidgetSpan.pm100644000770000024 251712576552253 23707 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Span; # ABSTRACT: button field rendering widget use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); use namespace::autoclean; sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = 'id . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= '>'; $output .= $self->value; $output .= ''; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Span - button field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders the NonEditable pseudo-field as a span. The Field Value =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Text.pm100644000770000024 275112576552253 23732 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Text; # ABSTRACT: text field rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my $self = shift; my $result = shift || $self->result; my $t; my $rendered = $self->html_filter($result->fif); my $output = 'size; $output .= qq{ maxlength="$t"} if $t = $self->maxlength; $output .= ' value="' . $self->html_filter($result->fif) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Text - text field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a text field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Form000755000770000024 012576552253 22163 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/WidgetTable.pm100644000770000024 310612576552253 23710 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Formpackage HTML::FormHandler::Widget::Form::Table; # ABSTRACT: render a form with a table layout use Moose::Role; with 'HTML::FormHandler::Widget::Form::Simple' => { -excludes => [ 'render_start', 'render_end', 'render_form_errors' ] }; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_start { my ( $self, $result ) = @_; $result ||= $self->result; my $fattrs = process_attrs($self->attributes($result)); my $wattrs = process_attrs($self->form_wrapper_attributes($result)); return qq{\n}; } sub render_form_errors { my ( $self, $result ) = @_; return '' unless $result->has_form_errors; my $output = "\n"; $output .= qq{\n$_} for $result->all_form_errors; $output .= "\n"; return $output; } sub render_end { my $self = shift; my $output .= "\n"; $output .= "\n"; return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Form::Table - render a form with a table layout =head1 VERSION version 0.40064 =head1 SYNOPSIS Set in your form: has '+widget_form' => ( default => 'Table' ); Use in a template: [% form.render %] =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut PasswordConf.pm100644000770000024 426012576552253 24170 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Fieldpackage HTML::FormHandler::Field::PasswordConf; # ABSTRACT: password confirmation use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field::Text'; our $VERSION = '0.03'; has '+widget' => ( default => 'Password' ); has '+password' => ( default => 1 ); has '+required' => ( default => 1 ); has 'password_field' => ( isa => 'Str', is => 'rw', default => 'password' ); has 'pass_conf_message' => ( isa => 'Str', is => 'rw' ); our $class_messages = { required => 'Please enter a password confirmation', pass_conf_not_matched => 'The password confirmation does not match the password', }; sub get_class_messages { my $self = shift; my $messages = { %{ $self->next::method }, %$class_messages, }; $messages->{pass_conf_not_matched} = $self->pass_conf_message if $self->pass_conf_message; return $messages; } sub validate { my $self = shift; my $value = $self->value; my $password = $self->form->field( $self->password_field )->value || ''; if ( $password ne $self->value ) { $self->add_error( $self->get_message('pass_conf_not_matched') ); return; } return 1; } __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::PasswordConf - password confirmation =head1 VERSION version 0.40064 =head1 DESCRIPTION This field needs to be declared after the related Password field (or more precisely it needs to come after the Password field in the list returned by the L method). =head2 password_field Set this attribute to the name of your password field (default 'password') Customize error message 'pass_conf_not_matched' or 'required' has_field '_password' => ( type => 'PasswordConf', messages => { required => 'You must enter the password a second time' }, ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Validation.pod100644000770000024 2542012576552253 24233 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::Validation; # ABSTRACT: validating fields __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::Validation - validating fields =head1 VERSION version 0.40064 =head1 SYNOPSIS L There are many options for validating fields in FormHandler. Some validation is from field attributes, some from form or field methods, some from 'apply' actions on the fields. =head1 Field attributes for validation Each individual field may have additional attributes that relate to validation, which are not documented here. See the individual field documentation, linked from L. =head2 required, required_when Setting the 'required' flag on a field initiates a check for the existence of some value. If the field does not have a value, the 'required' error message is issued. has_field 'section' => ( required => 1, messages => { required => 'Please provide a section' } ); Note that a required flag on a subfield -- a field inside a compound field or repeatable field -- does not cause the containing field to be required. You need to set 'required' all the way up, if that's the behavior that you want. If a field is empty and *not* required, no other field validation will be performed unless the 'validate_when_empty' flag (see below) is set. The form's 'validate' method, however, will always be called. There is also the 'required_when' attribute, which works the same way as the 'when' key on the apply actions. has_field 'fee' => ( required_when => { 'fie' => 2 } ); When a 'required' or 'required_when' check fails, a 'missing' flag is set in the result: if ( $field->missing ) { ... } =head2 range_start, range_end Starting and ending range for number fields. =head2 unique Attribute used by the DBIC model to check for uniqueness. =head2 validate_when_empty If its 'validate_when_empty' flag is set to a true value, then a field will always undergo validation when its form is processed, even when that field is empty. =head1 Validation methods =head2 validate_method You can provide a validation method for a field by setting a coderef with 'validate_method'. has_field 'fox' => ( validate_method => \&check_fox ); sub check_fox { my $self = shift; # self is the fox field unless( $self->value eq .... ) { $self->add_error('....'); } } =head2 validate_ If you provide a 'validate_' method it will be automatically used. has_field 'cat'; sub validate_cat { my ( $self, $field ) = @_; # self is the form unless ( $field->value eq ... ) { $field->add_error( '...' ); } } If the field name has periods in it, they should be replaced with underscores. =head2 form validate method A form validation method can be used to do cross-validation or validation checks that need information from more than one field. sub validate { my $self = shift; $self->field('foo')->add_error('....') if( $self->field('foo')->value eq '..' && $self->field('bar')->value eq '..' ); } =head2 field validate method You can create a custom field to contain a commonly used validation. The validation in a custom field can be done with 'apply' or by using a 'validate' method. package MyApp::Form::Field::Custom; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field'; # or a subclass of Field sub validate { .... } =head1 Apply Actions: Filters, transformations, and constraints The actions in the 'apply' array (stored in the 'actions' attribute) will be performed in the order they are specified, allowing fine-grained control over inflation and validation. You can check constraints after transformations and vice versa. You can weave all three types of actions in any order you need. The two valid 'apply' array elements are 1) Moose types and 2) hashrefs with one of three keys: 'check', 'transform', and 'type'. The hashrefs will usually also have an additional key, 'message', with a string, array or coderef providing an error message, which is localized. The 'check' key can point to a regex, arrayref of strings, or coderef. The value of the 'transform' key should be a coderef. The value of the 'type' key is a Moose type. In addition to the check and type keys, you can provide a 'when' key to only perform this validation when a particular field is a particular value: has_field 'fee'; has_field 'fie' => ( apply => [ { when => { fee => 1 }, check => qr/when/, message => 'Wrong fie' }, ]); has_field 'fo'; has_field 'fum_comp' => ( type => 'Compound' ); has_field 'fum_comp.one'; has_field 'fum_comp.two' => ( apply => [ { when => { '+fee' => [1,2,3] }, check => qr/when/, message => 'Wrong two' }, ]); The field name key in the 'when' hashref is assumed to be a field at the same "level" as this field (i.e. a sibling field in a compound). If you want to specify a field name from the form, prepend the name with a '+'. The 'when' hashref can contain multiple key/value pairs. This simply extends its test across multiple fields; all fields named in the hashref's keys must match their respective values in order for the overall 'when' test to pass. when => { foo => 3 } # when the foo field value is 3 when => { foo => [1,2,3]} # when foo is 1, 2, or 3 when => { foo => sub { $_[0] > 0 }} # when foo is greater than 0 when => { foo => sub { $_[0] ne ''}} # when foo is the empty string Transformations and coercions are called in an eval to catch the errors. Warnings are trapped in a sigwarn handler. If the conditions get too complicated to easily fit into a when condition, you can always create a validation method instead. See also L and L. See L for information on inflation and deflation. =head2 Moose types Moose types can be used to do both constraints and transformations. If a coercion exists it will be applied, resulting in a transformation. After coercing, the result is checked. You can use type constraints from L libraries or defined using L. FormHandler supplies a library of Moose types in L. use HTML::FormHandler::Types ('NotAllDigits'); has_field 'foo' => ( apply => [ NotAllDigits ] ); You can create your own library of types, too. Or you can create a type constraint in the form: use Moose::Util::TypeConstraints; subtype 'GreaterThan10' => as 'Int' => where { $_ > 10 } => message { "This number ($_) is not greater than 10" }; has_field 'text_gt' => ( apply=> [ 'GreaterThan10' ] ); Moose types can also be used for their coercions to do transformations. subtype 'MyInt' => as 'Int'; coerce 'MyInt' => from 'MyStr' => via { return $1 if /(\d+)/ }; You can also use the 'type' keyword with a Moose type if you want to change the message: has_field 'text_gt' => ( apply => [ { type => 'GreaterThan10', message => 'Number is too small' } ] ); =head2 transform A 'transform' changes the format of a field's value, and does not need a message. It takes a coderef. has_field 'another_field' => ( apply => [ { transform => sub{ sprintf '<%.1g>', $_[0] } } ] ); Note that transformed values are not displayed in the HTML form unless the 'fif_from_value' flag is set. The transformed values are saved to the database or returned in C<< $form->value >>. =head2 'check' regex Checks that field value matches the regex. has_field 'some_field' => ( apply => [ { check => qr/aaa/, message => 'Must contain aaa' } ], ); You can use regex libraries like L too: use Regexp::Common ('URI'); ... has_field 'my_url' => ( apply => [ { check => qr/$RE{URI}{HTTP}/, message => 'Invalid URL' } ] ); =head2 'check' arrayref (matches) Provide an arrayref of strings to match against. has_field 'set_error' => ( apply => [ { check => [ 'abc', 'bbb' ], message => 'Must be "aaa" or "bbb"' } ] ); =head2 'check' coderef Provide a validation function to check. A 'check' coderef will be passed the current value of the field and should return true or false. Note that the field is passed in as the second argument, to allow simple functions to work properly. has_field 'callback_pass' => ( apply => [ { check => \&check_callback_pass, message => 'Must contain number greater than 10', } ] ); sub check_callback_pass { my ( $value, $field ) = @_; if( $value =~ /(\d+)/ ) { return $1 > 10; } } =head2 message The message for the above checks can also be an arrayref or coderef. The arrayref is useful for localized messages. You can also provide error messages for Moose types. has_field 'message_sub' => ( apply => [ { check => [ 'abc' ], message => \&err_message } ] ); sub err_message { my ($value, $field ) = @_; return $field->name . ': Must be "abc"'; } has_field 'message_arrayref' => ( apply => [ { check => qr/aaa/, message => ['Must contain [_1]', 'aaa'] } ], ); has_field 'my_moose_type_field' => ( apply => [ { type => SomeType, message => 'Invalid ...' } ] ); =head2 actions in a field class To declare actions inside a field class use L and 'apply' sugar: package MyApp::Field::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler::Field; apply [ 'SomeConstraint', { check => ..., message => .... } ]; 1; Actions specified with apply are cumulative. Actions may be specified in field classes and additional actions added in the 'has_field' declaration. You can see examples of field classes with 'apply' actions in the source for L and L, and in t/constraints.t. =head1 Dependency The 'dependency' attribute is an array of arrays of field names. During validation, if any field in a given group has a value that matches the pattern /\S/ (non-blank), the 'required' flag is set for all of the fields in the group. has '+dependency' => ( default => sub { [ ['address', 'city', 'state', 'zip'], ['cc_no', 'cc_expires'], ], }, ); You can also use the 'required_when' flag to do something similar. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Reset.pm100644000770000024 252512576552253 24067 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Reset; # ABSTRACT: reset field rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = 'id . '"'; $output .= ' value="' . $self->html_filter($self->_localize($self->value)) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Reset - reset field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a reset field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Simple.pm100644000770000024 1444612576552253 24143 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Formpackage HTML::FormHandler::Widget::Form::Simple; # ABSTRACT: widget to render a form with divs use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); with 'HTML::FormHandler::Widget::Form::Role::HTMLAttributes'; our $VERSION = 0.01; sub renderx { my ($self, %args) = @_; if ( keys %args > 0 ) { while ( my ( $key, $value ) = each %args ) { confess "invalid attribute '$key' passed to renderx" unless $self->can($key); $self->$key($value); } } $self->render; } sub render { my ($self) = @_; my $result; my $form; # NOTE: do not use $self in this method; use $result or $form if ( $self->DOES('HTML::FormHandler::Result') ) { $result = $self; $form = $self->form; } else { $result = $self->result; $form = $self; } my $output = $form->render_start($result); $output .= $form->render_form_messages($result); if ( $form->has_render_list ) { foreach my $fb ( @{ $form->render_list } ) { # it's a Field if ( $form->field_in_index($fb) ) { # find field result and use that my $fld_result = $result->get_result($fb); # if no result, then we shouldn't be rendering this field next unless $fld_result; $output .= $fld_result->render; } # it's a Block else { # always use form level result for blocks my $block = $form->block($fb); die "found no form field or block named '$fb'\n" unless $block; $output .= $block->render($result); } } } else { foreach my $fld_result ( $result->results ) { $output .= $fld_result->render; } } $output .= $form->render_end($result); return $output; } sub render_start { my ( $self, $result ) = @_; $result ||= $self->result; my $output = ''; $output = $self->get_tag('before'); my $wtag = $self->get_tag('wrapper_tag') || 'fieldset'; # render wrapper start if not fieldset $output .= $self->render_wrapper_start($wtag, $result) if $wtag ne 'fieldset'; # render form tag my $attrs = process_attrs($self->attributes($result)); $output .= qq{}; # render wrapper start if fieldset (not legal outside form tag) $output .= $self->render_wrapper_start($wtag) if $wtag eq 'fieldset'; $output .= $self->get_tag('after_start'); return $output } sub render_wrapper_start { my ( $self, $wrapper_tag, $result ) = @_; return '' unless $self->do_form_wrapper; $result ||= $self->result; my $attrs = process_attrs($self->form_wrapper_attributes($result)); return qq{<$wrapper_tag$attrs>}; } sub render_form_errors { shift->render_form_messages(@_) } sub render_form_messages { my ( $self, $result ) = @_; $result ||= $self->result; return '' if $self->get_tag('no_form_message_div'); my $messages_wrapper_class = $self->get_tag('messages_wrapper_class') || 'form_messages'; my $output = qq{\n
}; my $error_class = $self->get_tag('error_class') || 'error_message'; if( $self->has_error_message && ( $result->has_errors || $result->has_form_errors ) ) { my $msg = $self->error_message; $msg = $self->_localize($msg); $output .= qq{\n$msg}; } if ( $result->has_form_errors ) { $output .= qq{\n$_} for $result->all_form_errors; } if( $self->has_success_message && $result->validated ) { my $msg = $self->success_message; $msg = $self->_localize($msg); my $success_class = $self->get_tag('success_class') || 'success_message'; $output .= qq{\n$msg}; } if( $self->has_info_message && $self->info_message ) { my $msg = $self->info_message; $msg = $self->_localize($msg); my $info_class = $self->get_tag('info_class') || 'info_message'; $output .= qq{\n$msg}; } $output .= "\n
"; return $output; } sub render_end { my $self = shift; my $output = $self->get_tag('before_end'); my $wtag = $self->get_tag('wrapper_tag') || 'fieldset'; $output .= $self->render_wrapper_end($wtag) if $wtag eq 'fieldset'; $output .= "\n"; $output .= $self->render_wrapper_end($wtag) if $wtag ne 'fieldset'; $output .= $self->get_tag('after'); $output .= "\n"; return $output; } sub render_wrapper_end { my ( $self, $wrapper_tag ) = @_; return '' unless $self->do_form_wrapper; return qq{\n}; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Form::Simple - widget to render a form with divs =head1 VERSION version 0.40064 =head1 SYNOPSIS Role to apply to form objects to allow rendering. This rendering role is applied to HTML::FormHandler by default. It supports block rendering. (L, L) Relevant flags: do_form_wrapper - put a wrapper around the form If the wrapper_tag is a 'fieldset' (default if not specified) the wrapper goes inside the form tags (because it's not valid to put it outside of them). If the wrapper_tag is something else, it will go around the form tags. If you're doing one kind of wrapper and want another one, you can achieve that result by using the 'before'/'after' tags or the 'after_start'/'before_end' tags. Supported tags: wrapper_tag -- tag for form wrapper; default 'fieldset' before after after_start before_end messages_wrapper_class -- default 'form_messages' error_class -- default 'error_message' error_message -- message to issue when form contains errors success_class -- default 'success_message' success_message -- message to issue when form was submitted successfully =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Captcha.pm100644000770000024 344212576552253 24445 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/xt/lib/MyCatalystApp/Controllerpackage MyCatalystApp::Controller::Captcha; use HTML::FormHandler; use Moose; use namespace::autoclean; BEGIN {extends 'Catalyst::Controller'; } =head1 NAME MyCatalystApp::Controller::Captcha - Catalyst Controller =head1 DESCRIPTION Catalyst Controller. =head1 METHODS =cut =head2 index =cut sub index :Path :Args(0) { my ( $self, $c ) = @_; my $form = MyCatalystApp::Controller::Captcha::Form->new( ctx => $c, ); if($form->process($c->req->params)){ $c->res->body("verification succeeded"); return; } $c->res->body($form->render); } =head2 test returns the image belonging to the current captcha =cut sub image : Local { my ( $self, $c ) = @_; my $captcha = $c->session->{captcha}; $c->response->body($captcha->{image}); $c->response->content_type('image/'. $captcha->{type}); $c->res->headers->expires( time() ); $c->res->headers->header( 'Last-Modified' => HTTP::Date::time2str ); $c->res->headers->header( 'Pragma' => 'no-cache' ); $c->res->headers->header( 'Cache-Control' => 'no-cache' ); } sub get_rnd :Local{ my ( $self, $c ) = @_; my $captcha = $c->session->{captcha}; die "no captcha in session" unless $captcha; $c->res->body($captcha->{rnd}); } =head1 AUTHOR Lukas Thiemeier,1R/18,7289,none =head1 LICENSE This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself. =cut __PACKAGE__->meta->make_immutable; { package MyCatalystApp::Controller::Captcha::Form; use HTML::FormHandler::Moose; extends qw/HTML::FormHandler/; with qw/ HTML::FormHandler::Render::Simple HTML::FormHandler::TraitFor::Captcha /; has_field submit => ( type => "Submit" ); __PACKAGE__->meta->make_immutable; 1; } 1; RepeatableJs.pm100644000770000024 1131712576552253 24336 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Renderpackage HTML::FormHandler::Render::RepeatableJs; # ABSTRACT: role providing method to construct repeatable javascript use Moose::Role; use JSON ('encode_json'); sub render_repeatable_js { my $self = shift; return '' unless $self->has_for_js; my $for_js = $self->for_js; my %index; my %html; my %level; foreach my $key ( keys %$for_js ) { $index{$key} = $for_js->{$key}->{index}; $html{$key} = $for_js->{$key}->{html}; $level{$key} = $for_js->{$key}->{level}; } my $index_str = encode_json( \%index ); my $html_str = encode_json( \%html ); my $level_str = encode_json( \%level ); my $js = < \$(document).ready(function() { var rep_index = $index_str; var rep_html = $html_str; var rep_level = $level_str; \$('.add_element').click(function() { // get the repeatable id var data_rep_id = \$(this).attr('data-rep-id'); // create a regex out of index placeholder var level = rep_level[data_rep_id] var re = new RegExp('\{index-' + level + '\}',"g"); // replace the placeholder in the html with the index var index = rep_index[data_rep_id]; var html = rep_html[data_rep_id]; html = html.replace(re, index); // escape dots in element id var esc_rep_id = data_rep_id.replace(/[.]/g, '\\\\.'); // append new element in the 'controls' div of the repeatable var rep_controls = \$('#' + esc_rep_id + ' > .controls'); rep_controls.append(html); // increment index of repeatable fields index++; rep_index[data_rep_id] = index; }); \$(document).on('click', '.rm_element', function(event) { cont = confirm('Remove?'); if (cont) { var id = \$(this).attr('data-rep-elem-id'); var esc_id = id.replace(/[.]/g, '\\\\.'); var rm_elem = \$('#' + esc_id); rm_elem.remove(); } event.preventDefault(); }); }); EOS return $js; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Render::RepeatableJs - role providing method to construct repeatable javascript =head1 VERSION version 0.40064 =head1 SYNOPSIS Creates jQuery javascript to add and delete repeatable elements. Note: This is still EXPERIMENTAL. This is an EXAMPLE. Changes are very likely to occur. Javascript is not guaranteed to be best practice. It will not work on all rendered repeatables (requires wrapper with id). It is strongly suggested that you make your own role if you use it. Then you can modify it as needed. Or just write out the rep_ data to javascript variables, and write the function in javascript. This function uses a plain javascript confirmation dialog. You almost certainly want to do something else. This javascript depends on the Repeatable field having a 'controls' div class in order to position the new elements. Use the Bootstrap wrapper or the 'controls_div' tag on the Simple wrapper. A role to be used in a Form Class: package MyApp::Form::Test; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; with 'HTML::FormHandler::Render::RepeatableJs'; ... =head2 DESCRIPTION This contains one method, 'render_repeatable_js'. It's designed to be used in a template, something like: [% WRAPPER "wrapper.tt" %] [% form.render_repeatable_js %]

Editing Object ....

[% form.render %] [% END -%] It will render javascript which can be used with the AddElement field, and setting the 'setup_for_js' flag in the Repeatable field to add the ability to dynamically add a new repeatable element in a form. Note: this code is provided as an example. You may need to write your own javascript function if your situation is different. Some of the extra information (level) in this function is in preparation for handling nested repeatables, but it's not supported yet. This function operates on HTML elements that have the id of the repeatable element. That requires that the wrapper have the repeatable instance ID (now rendered by default). If you don't have wrappers around your repeatable elements, this won't work. See L for an example of rendering an HTML element that can be used to provide the AddElement button. See that field for the requirements for the add HTML. See L for an example of rendering an HTML element that can be used to provide a 'remove' button. See that field for the requirements for the remove HTML. =head1 NAME HTML::FormHandler::Render::RepeatableJs =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Button.pm100644000770000024 252412576552253 24257 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Button; # ABSTRACT: button field rendering widget use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); use namespace::autoclean; sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = 'id . '"'; $output .= ' value="' . $self->html_filter($self->_localize($self->value)) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Button - button field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Render a button =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Hidden.pm100644000770000024 274312576552253 24202 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Hidden; # ABSTRACT: hidden field rendering widget use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output .= 'id . '"'; $output .= ' value="' . $self->html_filter($result->fif) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= " />"; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); # wrap field unless do_label is set, which would cause unwanted # labels to be displayed return $self->wrap_field( $result, $output ) if !$self->do_label; return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Hidden - hidden field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Widget for rendering a hidden field. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Select.pm100644000770000024 767512576552253 24237 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Select; # ABSTRACT: select field rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; # create select element my $output = $self->render_select_start( $result ); # create empty select if( defined $self->empty_select ) { $output .= $self->render_empty_select; } # loop through options foreach my $option ( @{ $self->{options} } ) { if ( my $label = $option->{group} ) { $label = $self->_localize( $label ) if $self->localize_labels; $output .= qq{\n}; foreach my $group_opt ( @{ $option->{options} } ) { $output .= $self->render_option( $group_opt, $result ); } $output .= qq{\n}; } else { $output .= $self->render_option( $option, $result ); } } $self->reset_options_index; $output .= ''; return $output; } sub render_select_start { my ( $self, $result ) = @_; $result ||= $self->result; my $id = $self->id; my $output = 'id . '"'; $output .= ' value="' . $self->html_filter($self->_localize($self->value)) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Submit - submit field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a submit field. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Upload.pm100644000770000024 242112576552253 24224 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Upload; # ABSTRACT: update field rendering widget use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output; $output = 'id . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Upload - update field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders an Upload field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Wrapper000755000770000024 012576552253 22700 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/WidgetBase.pm100644000770000024 1434712576552253 24301 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Base; # ABSTRACT: common methods for widget wrappers use Moose::Role; use HTML::FormHandler::Render::Util ('process_attrs'); sub do_render_label { my ( $self, $result, $label_tag, $class ) = @_; $label_tag ||= $self->get_tag('label_tag') || 'label'; my $attr = $self->label_attributes( $result ); push @{ $attr->{class} }, @$class if $class; my $attrs = process_attrs($attr); my $label; if( $self->does_wrap_label ) { $label = $self->wrap_label( $self->label ); } else { $label = $self->get_tag('label_no_filter') ? $self->loc_label : $self->html_filter($self->loc_label); } $label .= $self->get_tag('label_after') if $label_tag ne 'legend'; my $id = $self->id; my $for = $label_tag eq 'label' ? qq{ for="$id"} : ''; return qq{<$label_tag$attrs$for>$label}; } sub wrap_checkbox { my ( $self, $result, $rendered_widget, $default_wrapper ) = @_; my $option_wrapper = $self->option_wrapper || $default_wrapper; if ( $option_wrapper && $option_wrapper ne 'standard' && $option_wrapper ne 'label' ) { unless ( $self->can($option_wrapper) ) { die "HFH: no option_wrapper method '$option_wrapper'"; } return $self->$option_wrapper($result, $rendered_widget); } else { return $self->standard_wrap_checkbox($result, $rendered_widget); } } sub standard_wrap_checkbox { my ( $self, $result, $rendered_widget ) = @_; return $rendered_widget if( $self->get_tag('no_wrapped_label' ) ); my $label = $self->get_checkbox_label; my $id = $self->id; my $for = qq{ for="$id"}; # use "simple" label attributes for inner label my @label_class = ('checkbox'); push @label_class, 'inline' if $self->get_tag('inline'); my $lattrs = process_attrs( { class => \@label_class } ); # return wrapped checkbox, either on left or right my $output = ''; if ( $self->get_tag('label_left') ) { $output = qq{\n$label\n$rendered_widget}; } else { $output = qq{$rendered_widget\n$label\n}; } if ( $self->get_tag('checkbox_element_wrapper') ) { $output = qq{
$output
}; } return $output; } sub get_checkbox_label { my $self = shift; my $label = $self->option_label || ''; if( $label eq '' && ! $self->do_label ) { $label = $self->get_tag('label_no_filter') ? $self->loc_label : $self->html_filter($self->loc_label); } elsif( $label ne '' ) { $label = $self->get_tag('label_no_filter') ? $self->_localize($label) : $self->html_filter($self->_localize($label)); } return $label; } sub b3_label_left { my ( $self, $result, $rendered_widget ) = @_; my $label = $self->get_checkbox_label; my $id = $self->id; my $output = qq{
}; $output .= qq{}; $output .= qq{
}; return $output; } sub b3_label_left_inline { my ( $self, $result, $rendered_widget ) = @_; my $label = $self->get_checkbox_label; my $id = $self->id; my $output .= qq{}; return $output; } sub b3_label_right { my ( $self, $result, $rendered_widget ) = @_; my $label = $self->get_checkbox_label; my $id = $self->id; my $output = qq{
}; $output .= qq{}; $output .= qq{
}; return $output; } sub label_left { my ( $self, $result, $rendered_widget ) = @_; my $label = $self->get_checkbox_label; my $id = $self->id; my $output .= qq{}; return $output; } sub label_right { my ( $self, $result, $rendered_widget ) = @_; my $label = $self->get_checkbox_label; my $id = $self->id; my $output .= qq{}; return $output; } sub no_wrapped_label { my ( $self, $result, $rendered_widget ) = @_; return $rendered_widget; } # for compatibility with older code sub render_label { my $self = shift; my $attrs = process_attrs($self->label_attributes); my $label = $self->html_filter($self->loc_label); $label .= ": " unless $self->get_tag('label_no_colon'); return qq{$label}; } # this is not actually used any more, but is left here for compatibility # with user created widgets sub render_class { my ( $self, $result ) = @_; $result ||= $self->result; return process_attrs($self->wrapper_attributes($result)); } sub render_elementx { my ($self, %args) = @_; my $result ||= $self->result; if ( keys %args > 0 ) { while ( my ( $key, $value ) = each %args ) { confess "invalid attribute '$key' passed to render_elementx" unless $self->can($key); $self->$key($value); } } $self->render_element($result); } sub renderx { my ($self, %args) = @_; my $result ||= $self->result; if ( keys %args > 0 ) { while ( my ( $key, $value ) = each %args ) { confess "invalid attribute '$key' passed to renderx" unless $self->can($key); $self->$key($value); } } $self->render($result); } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Base - common methods for widget wrappers =head1 VERSION version 0.40064 =head1 DESCRIPTION Provides several common methods for wrapper widgets, including 'do_render_label' and 'wrap_checkbox'. Implements the checkbox 'option_wrapper' rendering: b3_label_left b3_label_right b3_label_left_inline label_left label_right no_wrapped_label =head1 NAME HTML::FormHandler::Widget::Wrapper::Base =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut None.pm100644000770000024 140512576552253 24275 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::None; # ABSTRACT: wrapper that doesn't wrap use Moose::Role; sub wrap_field { "\n" . $_[2] } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::None - wrapper that doesn't wrap =head1 VERSION version 0.40064 =head1 DESCRIPTION This wrapper does nothing except return the 'bare' rendered form element, as returned by the 'widget'. It does not add errors or anything else. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Captcha.pm100644000770000024 253012576552253 24344 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Captcha; # ABSTRACT: Captcha field rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; return '' if $self->widget eq 'no_widget'; my $output .= ''; $output .= 'element_attributes); $output .= '/>'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Captcha - Captcha field rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renderer for Captcha field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Table.pm100644000770000024 276012576552253 24432 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Table; # ABSTRACT: wrapper class for table layout use Moose::Role; with 'HTML::FormHandler::Widget::Wrapper::Base'; use HTML::FormHandler::Render::Util ('process_attrs'); sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; return $rendered_widget if ( $self->has_flag('is_compound') && $self->get_tag('no_compound_wrapper') ); my $output = "\nwrapper_attributes($result)) . ">"; if ( $self->has_flag('is_compound') ) { $output .= '' . $self->do_render_label($result) . ''; } elsif ( $self->do_label && length( $self->label ) > 0 ) { $output .= '' . $self->do_render_label($result) . ''; } if ( !$self->has_flag('is_compound') ) { $output .= ''; } $output .= $rendered_widget; $output .= qq{\n$_} for $result->all_errors; if ( !$self->has_flag('is_compound') ) { $output .= "\n"; } return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Table - wrapper class for table layout =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Checkbox.pm100644000770000024 265112576552253 24533 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Checkbox; # ABSTRACT: HTML attributes field role use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $checkbox_value = $self->checkbox_value; my $output = 'fif eq $checkbox_value; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Checkbox - HTML attributes field role =head1 VERSION version 0.40064 =head1 SYNOPSIS Checkbox field renderer =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Compound.pm100644000770000024 262612576552253 24573 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Compound; # ABSTRACT: compound field widget use Moose::Role; sub render_subfield { my ( $self, $result, $subfield ) = @_; my $subresult = $result->field( $subfield->name ); return "" unless $subresult; return $subfield->render( $subresult ); } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = ''; foreach my $subfield ( $self->sorted_fields ) { $output .= $self->render_subfield( $result, $subfield ); } $output =~ s/^\n//; # remove newlines so they're not duplicated return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Compound - compound field widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Widget for rendering a compound field. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut NoRender.pm100644000770000024 120012576552253 24506 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::NoRender; # ABSTRACT: no rendering widget use Moose::Role; sub render { '' } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::NoRender - no rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a field as the empty string. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Password.pm100644000770000024 265312576552253 24611 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Password; # ABSTRACT: password rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my $self = shift; my $result = shift || $self->result; my $t; my $output = 'size; $output .= qq{ maxlength="$t"} if $t = $self->maxlength; $output .= ' value="' . $self->html_filter($result->fif) . '"'; $output .= process_attrs($self->element_attributes($result)); $output .= ' />'; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Password - password rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a password field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Textarea.pm100644000770000024 254112576552253 24560 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Textarea; # ABSTRACT: textarea rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render_element { my $self = shift; my $result = shift || $self->result; my $fif = $self->html_filter($result->fif); my $id = $self->id; my $cols = $self->cols || 10; my $rows = $self->rows || 5; my $name = $self->html_name; my $output = qq(); return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Textarea - textarea rendering widget =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Simple.pm100644000770000024 1007212576552253 24647 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Simple; # ABSTRACT: simple field wrapper use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); with 'HTML::FormHandler::Widget::Wrapper::Base'; sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; my $output; # get wrapper tag if set my $label_tag = $self->label_tag || ''; my $wrapper_tag; if( $self->do_wrapper ) { $output .= $self->get_tag('before_wrapper'); $wrapper_tag = $self->get_tag('wrapper_tag'); # default wrapper tags $wrapper_tag ||= $self->has_flag('is_repeatable') ? 'fieldset' : 'div'; # get attribute string my $attrs = process_attrs( $self->wrapper_attributes($result) ); # write wrapper tag $output .= qq{\n<$wrapper_tag$attrs>}; $label_tag = 'legend' if $wrapper_tag eq 'fieldset'; } # write label; special processing for checkboxes $rendered_widget = $self->wrap_checkbox($result, $rendered_widget) if ( lc $self->widget eq 'checkbox' ); $output .= "\n" . $self->do_render_label($result, $label_tag) if $self->do_label; # append 'before_element' $output .= $self->get_tag('before_element'); # start controls div if ( $self->get_tag('controls_div') ) { $output .= qq{\n
}; } elsif ( $self->has_element_wrapper_class ) { my $ew_attr = $self->element_wrapper_attributes($result); my $element_wrapper_attrs = process_attrs( $ew_attr ); $output .= qq{\n}; } # the input element itself $output .= "\n$rendered_widget"; # close controls div if ( $self->get_tag('controls_div') || $self->has_element_wrapper_class ) { # end control div $output .= "\n
"; } # the 'after_element' $output .= $self->get_tag('after_element'); # the error messages unless( $self->get_tag('no_errors') ) { my $error_class = $self->get_tag('error_class') || 'error_message'; $output .= qq{\n$_} for $result->all_errors; # warnings (incompletely implemented - only on field itself) my $warning_class = $self->get_tag('warning_class') || 'warning_message'; $output .= qq{\n$_} for $result->all_warnings; } if( $self->do_wrapper ) { $output .= "\n"; $output .= $self->get_tag('after_wrapper'); } return "$output"; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Simple - simple field wrapper =head1 VERSION version 0.40064 =head1 SYNOPSIS This is the default wrapper role. It will be installed if no other wrapper is specified and widget_wrapper is not set to 'none'. Relevant field flags: do_wrapper do_label If 'do_label' is set and not 'do_wrapper', only the label plus the form element will be rendered. Supported 'tags', all set via the 'tags' hashref on the field: wrapper_tag -- the tag to use in the wrapper, default 'div' label_tag -- tag to use for label (default 'label') label_after -- string to append to label, for example ': ' to append a colon before_element -- string that goes right before the element after_element -- string that goes right after the element no_errors -- don't issue error messages on the field error_class -- class for error messages (default 'error_message') warning_class -- class for warning messages (default 'warning_message' ) no_wrapped_label -- for checkboxes. Don't provide an inner wrapped label (from Base wrapper) Example: has_field 'foo' => ( tags => { wrapper_tag => 'span', no_errors => 1 } ); =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Block000755000770000024 012576552253 22312 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/WidgetBootstrap.pm100644000770000024 211512576552253 24764 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Blockpackage HTML::FormHandler::Widget::Block::Bootstrap; # ABSTRACT: block to format bare form element like bootstrap use Moose; extends 'HTML::FormHandler::Widget::Block'; has 'after_controls' => ( is => 'rw' ); sub BUILD { my $self = shift; $self->add_class('control-group'); $self->add_label_class('control-label'); $self->label_tag('label'); } sub render_from_list { my ( $self, $result ) = @_; $result ||= $self->form->result; my $output = $self->next::method($result); my $after_controls = $self->after_controls || ''; return qq{
\n$output\n$after_controls\n
\n}; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Block::Bootstrap - block to format bare form element like bootstrap =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut ButtonTag.pm100644000770000024 255212576552253 24714 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::ButtonTag; # ABSTRACT: button field rendering widget, using button tag use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub html_element { 'button' } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = '"; return $output; } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::ButtonTag - button field rendering widget, using button tag =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Theme000755000770000024 012576552253 22322 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/WidgetBootstrap.pm100644000770000024 346412576552253 25004 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Themepackage HTML::FormHandler::Widget::Theme::Bootstrap; # ABSTRACT: sample bootstrap theme use Moose::Role; with 'HTML::FormHandler::Widget::Theme::BootstrapFormMessages'; after 'before_build' => sub { my $self = shift; $self->set_widget_wrapper('Bootstrap') if $self->widget_wrapper eq 'Simple'; }; sub build_form_element_class { ['form-horizontal'] } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Theme::Bootstrap - sample bootstrap theme =head1 VERSION version 0.40064 =head1 SYNOPSIS Also see L. Sample Bootstrap theme role. Can be applied to your subclass of HTML::FormHandler. Sets the widget wrapper to 'Bootstrap' and renders form messages using Bootstrap formatting and classes. There is an example app using Bootstrap at http://github.com:gshank/formhandler-example. This is a lightweight example of what you could do in your own custom Bootstrap theme. The heavy lifting is done by the Bootstrap wrapper, L, which you can use by itself in your form with: has '+widget_wrapper' => ( default => 'Bootstrap' ); It also uses L to render the form messages in a Bootstrap style:
....
By default this does 'form-horizontal' with 'build_form_element_class'. Implement your own sub to use 'form-vertical': sub build_form_element_class { ['form-vertical'] } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut RadioGroup.pm100644000770000024 1001012576552253 25064 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::RadioGroup; # ABSTRACT: radio group rendering widget use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub type_attr { 'radio' } sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; my $output = ''; $output .= "
" if $self->get_tag('radio_br_after'); foreach my $option ( @{ $self->{options} } ) { if ( my $label = $option->{group} ) { $label = $self->_localize( $label ) if $self->localize_labels; my $attr = $option->{attributes} || {}; my $attr_str = process_attrs($attr); my $lattr = $option->{label_attributes} || {}; my $lattr_str= process_attrs($lattr); $output .= qq{\n$label}; foreach my $group_opt ( @{ $option->{options} } ) { $output .= $self->render_option( $group_opt, $result ); } $output .= qq{\n}; } else { $output .= $self->render_option( $option, $result ); } $output .= '
' if $self->get_tag('radio_br_after'); } $self->reset_options_index; return $output; } sub render_option { my ( $self, $option, $result ) = @_; $result ||= $result; my $rendered_widget = $self->render_radio( $result, $option ); my $output = $self->wrap_radio( $rendered_widget, $option->{label} ); $self->inc_options_index; return $output; } sub render_wrapped_option { my ( $self, $option, $result ) = @_; $result ||= $self->result; my $output = $self->render_option( $option, $result ); return $self->wrap_field( $result, $output ); } sub render_radio { my ( $self, $result, $option ) = @_; $result ||= $self->result; my $value = $option->{value}; my $id = $self->id . "." . $self->options_index; my $output = 'fif eq $value; $output .= process_attrs($option->{attributes}); $output .= ' />'; return $output; } sub wrap_radio { my ( $self, $rendered_widget, $option_label ) = @_; my $id = $self->id . "." . $self->options_index; my $for = qq{ for="$id"}; # use "simple" label attributes for inner label my @label_class = ('radio'); if ( $self->get_tag('inline') ) { my $class = 'inline'; $class = 'radio-inline' if $self->has_flag('is_b3'); push @label_class, $class; } my $lattrs = process_attrs( { class => \@label_class } ); # return wrapped radio, either on left or right my $label = $self->_localize($option_label); my $output = ''; if ( $self->get_tag('label_left') ) { $output = qq{\n$label\n$rendered_widget}; } else { $output = qq{$rendered_widget\n$label\n}; } if ( $self->get_tag('radio_element_wrapper') ) { $output = qq{
$output
}; } return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::RadioGroup - radio group rendering widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a radio group (from a 'Select' field); Tags: radio_br_after See L for documentation on select fields and options. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Repeatable.pm100644000770000024 246412576552253 25053 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::Repeatable; # ABSTRACT: repeatable field widget use Moose::Role; with 'HTML::FormHandler::Widget::Field::Compound'; has 'wrap_repeatable_element_method' => ( traits => ['Code'], is => 'ro', isa => 'CodeRef', handles => { 'wrap_repeatable_element' => 'execute_method' }, ); sub render_subfield { my ( $self, $result, $subfield ) = @_; my $subresult = $result->field( $subfield->name ); return "" unless $subresult or ( $self->has_flag( "is_repeatable") and $subfield->name < $self->num_when_empty ); my $output = $subfield->render($subresult); if ( $self->wrap_repeatable_element_method ) { $output = $self->wrap_repeatable_element($output, $subfield->name); } return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Repeatable - repeatable field widget =head1 VERSION version 0.40064 =head1 SYNOPSIS Renders a repeatable field =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Bootstrap3.pm100644000770000024 357212576552253 25067 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Themepackage HTML::FormHandler::Widget::Theme::Bootstrap3; # ABSTRACT: sample Bootstrap3 theme use Moose::Role; with 'HTML::FormHandler::Widget::Theme::BootstrapFormMessages'; after 'before_build' => sub { my $self = shift; $self->set_widget_wrapper('Bootstrap3') if $self->widget_wrapper eq 'Simple'; }; sub build_form_element_class { ['form-horizontal'] } sub form_messages_alert_error_class { 'alert-danger' } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Theme::Bootstrap3 - sample Bootstrap3 theme =head1 VERSION version 0.40064 =head1 SYNOPSIS Also see L. Sample Bootstrap3 theme role. Can be applied to your subclass of HTML::FormHandler. Sets the widget wrapper to 'Bootstrap3' and renders form messages using Bootstrap3 formatting and classes. There is an example app using Bootstrap3 at http://github.com/gshank/formhandler-example. This is a lightweight example of what you could do in your own custom Bootstrap3 theme. The heavy lifting is done by the Bootstrap3 wrapper, L, which you can use by itself in your form with: has '+widget_wrapper' => ( default => 'Bootstrap3' ); It also uses L to render the form messages in a Bootstrap style:
....
By default this does 'form-horizontal' with 'build_form_element_class'. Implement your own sub to use 'form-vertical': sub build_form_element_class { ['form-vertical'] } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Fieldset.pm100644000770000024 233112576552253 25134 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Fieldset; # ABSTRACT: fieldset field wrapper use Moose::Role; use namespace::autoclean; with 'HTML::FormHandler::Widget::Wrapper::Base'; use HTML::FormHandler::Render::Util ('process_attrs'); sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; my $wattrs = process_attrs($self->wrapper_attributes); my $output .= qq{\n}; $output .= qq{\n} . $self->loc_label . ''; $output .= "\n$rendered_widget"; $output .= qq{\n$_} for $result->all_errors; $output .= "\n"; return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Fieldset - fieldset field wrapper =head1 VERSION version 0.40064 =head1 SYNOPSIS Wraps a single field in a fieldset. =head1 NAME HTML::FormHandler::Widget::Wrapper::Fieldset - fieldset field wrapper =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Bootstrap.pm100644000770000024 1162212576552253 25375 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Bootstrap; # ABSTRACT: Twitter Bootstrap 2.0 field wrapper use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); with 'HTML::FormHandler::Widget::Wrapper::Base'; sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; my $output; # is this a control group or a form action? my $form_actions = 1 if ( $self->name eq 'form_actions' || $self->type_attr eq 'submit' || $self->type_attr eq 'reset' ); # create attribute string for wrapper my $attr = $self->wrapper_attributes($result); # no 'control-group' class for Hidden fields, 'form-actions' for submit/reset my $div_class = $self->type eq 'Hidden' ? undef : $form_actions ? "form-actions" : "control-group"; unshift @{$attr->{class}}, $div_class if $div_class; my $attr_str = process_attrs( $attr ); # wrapper is always a div if ( $self->do_wrapper ) { $output .= $self->get_tag('before_wrapper'); $output .= qq{\n}; } # render the label $output .= "\n" . $self->do_render_label($result, undef, ['control-label'] ) if $self->do_label; $output .= $self->get_tag('before_element'); # the controls div for ... controls $output .= qq{\n
} unless $form_actions || !$self->do_wrapper; # yet another tag $output .= $self->get_tag('before_element_inside_div'); # handle input-prepend and input-append if( $self->get_tag('input_prepend') || $self->get_tag('input_append') || $self->get_tag('input_append_button') ) { $rendered_widget = $self->do_prepend_append($rendered_widget); } elsif( lc $self->widget eq 'checkbox' ) { $rendered_widget = $self->wrap_checkbox($result, $rendered_widget) } $output .= "\n$rendered_widget"; # various 'help-inline' bits: errors, warnings unless( $self->get_tag('no_errors') ) { $output .= qq{\n$_} for $result->all_errors; $output .= qq{\n$_} for $result->all_warnings; } # extra after element stuff $output .= $self->get_tag('after_element'); # close 'control' div $output .= '
' unless $form_actions || !$self->do_wrapper; # close wrapper if ( $self->do_wrapper ) { $output .= "\n"; $output .= $self->get_tag('after_wrapper'); } return "$output"; } sub do_prepend_append { my ( $self, $rendered_widget ) = @_; my @class; if( my $ip_tag = $self->get_tag('input_prepend' ) ) { $rendered_widget = qq{$ip_tag$rendered_widget}; push @class, 'input-prepend'; } if ( my $ia_tag = $self->get_tag('input_append' ) ) { $rendered_widget = qq{$rendered_widget$ia_tag}; push @class, 'input-append'; } if ( my $iab_tag = $self->get_tag('input_append_button') ) { my @buttons = ref $iab_tag eq 'ARRAY' ? @$iab_tag : ($iab_tag); foreach my $btn ( @buttons ) { $rendered_widget = qq{$rendered_widget}; } push @class, 'input-append'; } my $attr = process_attrs( { class => \@class } ); $rendered_widget = qq{ $rendered_widget }; return $rendered_widget; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Bootstrap - Twitter Bootstrap 2.0 field wrapper =head1 VERSION version 0.40064 =head1 SYNOPSIS Wrapper to implement Bootstrap 2.0 style form element rendering. This wrapper does some very specific Bootstrap things, like wrap the form elements in divs with non-changeable classes. It is not as flexible as the 'Simple' wrapper, but means that you don't have to specify those classes in your form code. It wraps form elements with 'control-group' divs, and form 'actions' with 'form-actions' divs. It adds special additional wrappers for checkboxes and radio buttons, with wrapped labels. =head1 DESCRIPTION Tags supported: label_no_filter -- don't html filter the label label_after -- useful for putting a colon, or other trailing formatting before_element -- insert tag before input, outside element's control div before_element_inside_div -- insert tag before input element, inside control div input_prepend -- for Bootstrap 'input-prepend' class input_append -- for Bootstrap 'input-append' class input_append_button -- 'input-append' with button instead of span no_errors -- don't append error to field rendering after_element -- insert tag after input element =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Repeatable000755000770000024 012576552253 23124 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/FieldInstance.pm100644000770000024 221112576552253 25362 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Field/Repeatablepackage # hide from Pause HTML::FormHandler::Field::Repeatable::Instance; # ABSTRACT: used internally by repeatable fields use Moose; extends 'HTML::FormHandler::Field::Compound'; sub BUILD { my $self = shift; $self->add_wrapper_class('hfh-repinst') unless $self->has_wrapper_class; } sub build_tags {{ wrapper => 1 }} has '+do_label' => ( default => 0 ); has '+do_wrapper' => ( default => 1 ); has '+no_value_if_empty' => ( default => 1 ); __PACKAGE__->meta->make_immutable; use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Field::Repeatable::Instance - used internally by repeatable fields =head1 VERSION version 0.40064 =head1 SYNOPSIS This is a simple container class to hold an instance of a Repeatable field. It will have a name like '0', '1'... Users should not need to use this class. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut RenderingCookbook.pod100644000770000024 422412576552253 25524 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::RenderingCookbook; # ABSTRACT: rendering recipes __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::RenderingCookbook - rendering recipes =head1 VERSION version 0.40064 =head1 SYNOPSIS Collection of rendering recipes =head1 NAME HTML::FormHandler::Manual::Rendering::Cookbook =head1 Recipes =head2 Custom renderer, custom attributes You want to be able to specify the attributes that are rendered in the 'td' tag of the table renderer... First make your own copy of 'HTML::FormHandler::Widget::Wrapper::Table, in your own name space, and specify that name space in the 'widget_name_space' for the form. Change this line in the Table wrapper: $output .= '' . $self->do_render_label($result) . ''; to this: my $td_attr = process_attrs($self->get_tag('td_attr') || {} ); $output .= "" . $self->do_render_label($result) . ''; Now you can specify the attributes for the 'td' tag on a field: has_field 'foo' => ( tags => { td_attr => { class => ['emph', 'label'] } } ); =head2 Render a collection of checkboxes like a checkbox group =head2 Add a 'required' class to labels Create a custom widget wrapper: package MyApp::Form::Widget::Wrapper::CustomLabel; use Moose::Role; with 'HTML::FormHandler::Widget::Wrapper::Simple'; sub render_label { my ($self) = @_; return ''; } Or enable html5 output which adds a 'required' attribute. Or use the 'html_attributes' callback: sub html_attributes { my ( $self, $field, $type, $attr ) = @_; push @{$attr->{class}}, 'required' if ( $type eq 'label' && $field->required ); } =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Bootstrap3.pm100644000770000024 1716112576552253 25464 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::Bootstrap3; # ABSTRACT: Twitter Bootstrap 3.0 field wrapper use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); use List::Util 1.33 ('any'); with 'HTML::FormHandler::Widget::Wrapper::Base'; sub is_b3 {1} sub build_wrapper_tags { { radio_element_wrapper => 1, checkbox_element_wrapper => 1, } } sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; my $output; # create attribute string for wrapper if ( $self->do_wrapper ) { my $attr = $self->wrapper_attributes($result); # no 'control-group' class for Hidden fields, 'form-actions' for submit/reset my $div_class = 'form-group'; unshift @{$attr->{class}}, $div_class; my $attr_str = process_attrs( $attr ); # wrapper is always a div $output .= $self->get_tag('before_wrapper'); $output .= qq{\n}; } # render the label $output .= "\n" . $self->do_render_label($result, undef, ['control-label'] ) if $self->do_label; $output .= $self->get_tag('before_element'); # the controls div; used to have 'controls' class. Now it comes from # the 'element_wrapper_class'. Used for column layout. my $ew_attr = $self->element_wrapper_attributes($result); my $element_wrapper_attrs = process_attrs( $ew_attr ); $output .= qq{\n} unless !$self->do_wrapper; # yet another tag $output .= $self->get_tag('before_element_inside_div'); # handle input-prepend and input-append if( $self->get_tag('input_prepend') || $self->get_tag('input_append') || $self->get_tag('input_append_button') ) { $rendered_widget = $self->do_prepend_append($rendered_widget); } elsif( lc $self->widget eq 'checkbox' ) { $rendered_widget = $self->wrap_checkbox($result, $rendered_widget, 'b3_label_left') } $output .= "\n$rendered_widget"; # various 'help-inline' bits: errors, warnings unless( $self->get_tag('no_errors') ) { $output .= qq{\n$_} for $result->all_errors; $output .= qq{\n$_} for $result->all_warnings; } # extra after element stuff $output .= $self->get_tag('after_element'); # close element_wrapper 'control' div $output .= '' unless !$self->do_wrapper; # close wrapper if ( $self->do_wrapper ) { $output .= "\n"; $output .= $self->get_tag('after_wrapper'); } return "$output"; } # don't render label for checkboxes sub do_render_label { my ( $self ) = @_; return '' if $self->type_attr eq 'checkbox'; HTML::FormHandler::Widget::Wrapper::Base::do_render_label(@_); } sub add_standard_element_classes { my ( $self, $result, $class ) = @_; push @$class, 'has-error' if $result->has_errors; push @$class, 'has-warning' if $result->has_warnings; push @$class, 'disabled' if $self->disabled; push @$class, 'form-control' if $self->html_element eq 'select' || $self->html_element eq 'textarea' || $self->type_attr eq 'text' || $self->type_attr eq 'password'; } sub add_standard_wrapper_classes { my ( $self, $result, $class ) = @_; push @$class, 'has-error' if ( $result->has_error_results || $result->has_errors ); push @$class, 'has-warning' if $result->has_warnings; # TODO: has-success? } sub add_standard_label_classes { my ( $self, $result, $class ) = @_; if ( my $classes = $self->form->get_tag('layout_classes') ) { my $label_class = $classes->{label_class}; if ( $label_class && not any { $_ =~ /^col\-/ } @$class ) { push @$class, @{$classes->{label_class}}; } } } sub add_standard_element_wrapper_classes { my ( $self, $result, $class ) = @_; if ( my $classes = $self->form->get_tag('layout_classes') ) { if ( exists $classes->{element_wrapper_class} && not any { $_ =~ /^col\-/ } @$class ) { push @$class, @{$classes->{element_wrapper_class}}; } if ( exists $classes->{no_label_element_wrapper_class} && ( ! $self->do_label || $self->type_attr eq 'checkbox' ) && not any { $_ =~ /^col\-.*offset/ } @$class ) { push @$class, @{$classes->{no_label_element_wrapper_class}}; } } } sub wrap_checkbox { my ( $self, $result, $rendered_widget ) = @_; # use the regular label my $label = $self->option_label || $self->label; $label = $self->get_tag('label_no_filter') ? $self->_localize($label) : $self->html_filter($self->_localize($label)); my $id = $self->id; my $for = qq{ for="$id"}; # return unwrapped checkbox with 'checkbox-inline' return qq{} if( $self->get_tag('inline') ); # return wrapped checkbox, either on left or right return qq{
\n$label\n$rendered_widget
} if( $self->get_tag('label_left') ); return qq{
$rendered_widget\n$label\n
}; } sub do_prepend_append { my ( $self, $rendered_widget ) = @_; my @class; if( my $ip_tag = $self->get_tag('input_prepend' ) ) { $rendered_widget = qq{$ip_tag$rendered_widget}; push @class, 'input-group'; } if ( my $ia_tag = $self->get_tag('input_append' ) ) { $rendered_widget = qq{$rendered_widget$ia_tag}; push @class, 'input-group'; } if ( my $iab_tag = $self->get_tag('input_append_button') ) { my @buttons = ref $iab_tag eq 'ARRAY' ? @$iab_tag : ($iab_tag); my $group = qq{}; foreach my $btn ( @buttons ) { $group .= qq{}; } $group .= qq{}; $rendered_widget = qq{$rendered_widget$group}; push @class, 'input-group'; } my $attr = process_attrs( { class => \@class } ); $rendered_widget = qq{ $rendered_widget }; return $rendered_widget; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::Bootstrap3 - Twitter Bootstrap 3.0 field wrapper =head1 VERSION version 0.40064 =head1 SYNOPSIS Wrapper to implement Bootstrap 3.0 style form element rendering. =head1 DESCRIPTION Differences from the Bootstrap 2.0 wrapper: The wrapper class is 'form-group' instead of 'control-group' The div wrapping the form element does not have the 'controls' class. Used for sizing css classes. Input prepend & append use different classes The input elements have a 'form-control' class Tags supported: label_no_filter -- don't html filter the label label_after -- useful for putting a colon, or other trailing formatting before_element -- insert tag before input, outside element's control div before_element_inside_div -- insert tag before input element, inside control div input_prepend -- for Bootstrap 'input-prepend' class input_append -- for Bootstrap 'input-append' class input_append_button -- 'input-append' with button instead of span no_errors -- don't append error to field rendering after_element -- insert tag after input element =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut InflationDeflation.pod100644000770000024 1255712576552253 25721 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Manualpackage HTML::FormHandler::Manual::InflationDeflation; # ABSTRACT: inflation and deflation of field values __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Manual::InflationDeflation - inflation and deflation of field values =head1 VERSION version 0.40064 =head1 SYNOPSIS L How to inflate and deflate field values. =head2 DESCRIPTION When working with the various ways that data can be transformed, in and out, the meaning of the terms 'inflate' and 'deflate' starts to feel kind of slippery. The one constant is that values presented in an HTML form must be in a string format, or presented with select elements or checkboxes. There are two general types of inflation/deflation provided by FormHandler. The first, 'standard' type inflates values in order to validate them, and deflates them in order to present them in string format via HTML. The other ('DB') type takes values provided by defaults (usually a DB row, or item, but could also be a field default or an init_object) and munges the values coming in and changes them back going out. =head2 Standard inflation/deflation The standard type of inflation/deflation is implemented by using some of the following options for inflation: inflate_method transform (using 'apply') ..and the following options for deflation: deflate_method deflation (field attribute) When validation starts, the param input will be inflated by the inflate method, allowing validation to be performed on the inflated object. When the 'fif' fill-in-form value is returned for HTML generation, the deflation is used to flatten the object, usually into a string format. =head2 DB inflation/deflation The 'DB' type of inflation/deflation uses 'inflate_default_method' for inflation, and 'deflate_value_method' for deflation. Deflation could also be handled by changing the value in one of the various validation methods. This type of inflation/deflation is, logically, just a different way of providing data munging around the defaults (item/init_object/default) and 'value' output. The same effect could be achieved by performing a transformation outside of FormHandler - if you were handling the database updates yourself. Since the DBIC model enables automatic database updates, this kind of inflation/deflation makes that easier. One circumstance in which this type of inflation/deflation is useful is when there's a single field in the database row object which you want to expand into a compound field in the form. =head2 Attributes used in deflation/inflation =head3 Inflation methods The field 'input' comes from the params that are passed in from the submission of the form, so the input will always be in string format if it comes from an HTTP request. It's also possible to pass in params in other formats, of course. Or the params could be pre-processed before passing in to FormHandler. You should not normally be changing the 'input' attribute of a field. If you want the changed field value to be used when re-presenting the form, such as when you're adopting a standard format for the field, you should set C<< fif_from_value => 1 >>. There are three options for standard inflation, or transforming the field's 'input' to the field's 'value': =over 4 =item inflate_method Provide a method on the field which inflates the field 'input' (from params): has_field 'futility' => ( inflate_method => \&inflate_field ); sub inflate_field { my ( $self, $value ) = @_; .... return $value; } =item transform In a sequence of 'apply' actions, changes the format of the 'value' that is being validated. This might be useful if there are some validations that work on one format of the value, and some that work on another. =item set the value in validation methods In a validate method, you can change the format of the value, with $field->value(...); =back =head3 Deflation methods =over 4 =item deflate_method Most general purpose deflation method. Provide a coderef which is a method on the field: has_field => 'foo' => ( deflate_method => \&deflate_foo ); sub deflate_foo { my ( $self, $value ) = @_; # $self is the 'foo' field return $value; } =item deflation This is a coderef that performs deflation. has_field => 'bar' => ( deflation => sub { shift $value; ... return $value } ); =item set the value in validation methods Just like for inflation, you can change the value in a validation method; however, it won't be used for fill-in-form unless you set the 'fif_from_value' flag to true. =back =head3 fif_from_value Normally the fill-in-form value will be the param value that was submitted. If you want to change the format of the input when re-presenting the form, you can set 'fif_from_value'. =head3 deflate_to Earlier versions of FormHandler provided a 'deflate_to' attribute which allowed the deflation methods to be used for multiple, confusing purposes. This flag has been removed, since it made the process hard to understand and was mixing apples and oranges. The new inflation/deflation methods can handle all of the previous situations. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut CheckboxGroup.pm100644000770000024 770412576552253 25554 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::CheckboxGroup; # ABSTRACT: checkbox group field role use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; # loop through options my $output = ''; foreach my $option ( @{ $self->{options} } ) { if ( my $label = $option->{group} ) { $label = $self->_localize( $label ) if $self->localize_labels; my $attr = $option->{attributes} || {}; my $attr_str = process_attrs($attr); my $lattr = $option->{label_attributes} || {}; my $lattr_str= process_attrs($lattr); $output .= qq{\n$label}; foreach my $group_opt ( @{ $option->{options} } ) { $output .= $self->render_option( $group_opt, $result ); } $output .= qq{\n}; } else { $output .= $self->render_option( $option, $result ); } } $self->reset_options_index; return $output; } sub render_option { my ( $self, $option, $result ) = @_; $result ||= $self->result; # get existing values my $fif = $result->fif; my %fif_lookup; @fif_lookup{@$fif} = () if $self->multiple; # create option label attributes my $lattr = $option->{label_attributes} || {}; push @{ $lattr->{class} }, 'checkbox'; if ( $self->get_tag('inline') ) { my $class = 'inline'; $class = 'checkbox-inline' if $self->has_flag('is_b3'); push @{ $lattr->{class} }, $class; } my $lattr_str = process_attrs( $lattr ); my $id = $self->id . '.' . $self->options_index; my $output .= qq{\n}; my $value = $option->{value}; $output .= qq{\n{attributes} || {}; if( defined $option->{disabled} && $option->{disabled} ) { $attr->{disabled} = 'disabled'; } if ( defined $fif && ( ( $self->multiple && exists $fif_lookup{$value} ) || ( $fif eq $value ) ) ) { $attr->{checked} = 'checked'; } $output .= process_attrs($attr); $output .= " />\n"; # handle label my $label = $option->{label}; $label = $self->_localize($label) if $self->localize_labels; $output .= $self->html_filter($label); $output .= "\n"; $self->inc_options_index; if ($self->get_tag('checkbox_element_wrapper')) { $output = qq{
$output
}; } return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::CheckboxGroup - checkbox group field role =head1 VERSION version 0.40064 =head1 SYNOPSIS Checkbox group widget for rendering multiple selects. Checkbox element label class is 'checkbox', plus 'inline' if the 'inline' tag is set. Options hashrefs must have the keys 'value', and 'label'. They may have an 'attributes' hashref key. The 'checked' attribute should not be set in the options hashref. It should be set by supplying a default value or from params input. See L for documentation on select fields and options. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut TableInline.pm100644000770000024 244512576552253 25571 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::TableInline; # ABSTRACT: wrapper class for table layout that doesn't wrap compound fields use Moose::Role; with 'HTML::FormHandler::Widget::Wrapper::Base'; use HTML::FormHandler::Render::Util ('process_attrs'); sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; return $rendered_widget if $self->has_flag('is_compound'); my $output = "\nwrapper_attributes($result)) . ">"; if ( $self->do_label && length( $self->label ) > 0 ) { $output .= '' . $self->do_render_label($result) . ''; } $output .= ''; $output .= $rendered_widget; $output .= qq{\n$_} for $result->all_errors; $output .= "\n"; return $output; } use namespace::autoclean; 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::TableInline - wrapper class for table layout that doesn't wrap compound fields =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut SimpleInline.pm100644000770000024 275612576552253 26000 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Wrapperpackage HTML::FormHandler::Widget::Wrapper::SimpleInline; # ABSTRACT: simple field wrapper use Moose::Role; use namespace::autoclean; with 'HTML::FormHandler::Widget::Wrapper::Base'; sub wrap_field { my ( $self, $result, $rendered_widget ) = @_; return $rendered_widget if $self->has_flag('is_compound'); my $output = "\n"; my $tag = $self->wrapper_tag; my $start_tag = $self->get_tag('wrapper_start'); if( defined $start_tag ) { $output .= $start_tag; } else { $output .= "<$tag" . process_attrs( $self->wrapper_attributes($result) ) . ">"; } if ( $self->do_label && length( $self->label ) > 0 ) { $output .= $self->do_render_label($result); } $output .= $rendered_widget; $output .= qq{\n$_} for $result->all_errors; my $end_tag = $self->get_tag('wrapper_end'); $output .= defined $end_tag ? $end_tag : ""; return "$output\n"; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Wrapper::SimpleInline - simple field wrapper =head1 VERSION version 0.40064 =head1 SYNOPSIS This works like the Simple Wrapper, except it doesn't wrap Compound fields. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut HorizCheckboxGroup.pm100644000770000024 656512576552253 26574 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Fieldpackage HTML::FormHandler::Widget::Field::HorizCheckboxGroup; # ABSTRACT: checkbox group field role use Moose::Role; use namespace::autoclean; use HTML::FormHandler::Render::Util ('process_attrs'); sub render { my ( $self, $result ) = @_; $result ||= $self->result; die "No result for form field '" . $self->full_name . "'. Field may be inactive." unless $result; my $output = $self->render_element( $result ); return $self->wrap_field( $result, $output ); } sub render_element { my ( $self, $result ) = @_; $result ||= $self->result; # loop through options my $output = ''; foreach my $option ( @{ $self->{options} } ) { if ( my $label = $option->{group} ) { $label = $self->_localize( $label ) if $self->localize_labels; my $attr = $option->{attributes} || {}; my $attr_str = process_attrs($attr); my $lattr = $option->{label_attributes} || {}; my $lattr_str= process_attrs($lattr); $output .= qq{\n$label}; foreach my $group_opt ( @{ $option->{options} } ) { $output .= $self->render_option( $group_opt, $result ); } $output .= qq{\n}; } else { $output .= $self->render_option( $option, $result ); } } $self->reset_options_index; return $output; } sub render_option { my ( $self, $option, $result ) = @_; $result ||= $self->result; # get existing values my $fif = $result->fif; my %fif_lookup; @fif_lookup{@$fif} = () if $self->multiple; # create option label attributes my $lattr = $option->{label_attributes} || {}; my $lattr_str = process_attrs( $lattr ); my $id = $self->id . '.' . $self->options_index; # start wrapping div my $output = qq{
}; $output .= qq{\n}; my $value = $option->{value}; $output .= qq{\n{attributes} || {}; if( defined $option->{disabled} && $option->{disabled} ) { $attr->{disabled} = 'disabled'; } if ( defined $fif && ( ( $self->multiple && exists $fif_lookup{$value} ) || ( $fif eq $value ) ) ) { $attr->{checked} = 'checked'; } $output .= process_attrs($attr); $output .= " />\n"; # handle label my $label = $option->{label}; $label = $self->_localize($label) if $self->localize_labels; $output .= $self->html_filter($label); $output .= "\n"; # close wrapping div $output .= "\n
"; $self->inc_options_index; return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::HorizCheckboxGroup - checkbox group field role =head1 VERSION version 0.40064 =head1 SYNOPSIS Checkbox group widget for rendering multiple selects. Wraps each checkbox in a div. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Role000755000770000024 012576552253 23064 5ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/FormHTMLAttributes.pm100644000770000024 317212576552253 26400 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Form/Rolepackage HTML::FormHandler::Widget::Form::Role::HTMLAttributes; # ABSTRACT: set HTML attributes on the form tag use Moose::Role; sub html_form_tag { my $self = shift; my @attr_accessors = ( [ action => 'action' ], [ id => 'name' ], [ method => 'http_method' ], [ enctype => 'enctype' ], [ style => 'style' ], ); # make the element_attr a safe default my $element_attr = {}; # Assuming that self is a form $element_attr = { %{$self->form_element_attr} } if ( $self->can( 'form_element_attr' ) ); # Assuming that self is a field $element_attr = { %{$self->element_attr} } if ( $self->can( 'element_attr' ) ); foreach my $attr_pair (@attr_accessors) { my $attr = $attr_pair->[0]; my $accessor = $attr_pair->[1]; if ( !exists $element_attr->{$attr} && defined( my $value = $self->$accessor ) ) { $element_attr->{$attr} = $self->$accessor; } } my $output = 'attributes ); return $output; } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Role::HTMLAttributes - apply HTML attributes =head1 VERSION version 0.40064 =head1 SYNOPSIS Deprecated. Only here for interim compatibility, to provide '_add_html_attributes' method. Will be removed in the future. =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut SelectedOption.pm100644000770000024 173712576552253 26633 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Field/Rolepackage HTML::FormHandler::Widget::Field::Role::SelectedOption; # ABSTRACT: allow setting options from options keys use Moose::Role; use namespace::autoclean; sub check_selected_option { my ( $self, $option, $fif ) = @_; my $selected_key = defined($option->{'selected'}) ? $option->{'selected'} : $option->{'checked'}; if ( defined $selected_key ) { return $selected_key; } elsif ( defined $fif ) { return $fif eq $option->{'value'}; } else { return; } } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Field::Role::SelectedOption - allow setting options from options keys =head1 VERSION version 0.40064 =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut BootstrapFormMessages.pm100644000770000024 414412576552253 27314 0ustar00gshankstaff000000000000HTML-FormHandler-0.40064/lib/HTML/FormHandler/Widget/Themepackage HTML::FormHandler::Widget::Theme::BootstrapFormMessages; # ABSTRACT: role to render form messages using Bootstrap styling use Moose::Role; sub render_form_messages { my ( $self, $result ) = @_; return '' if $self->get_tag('no_form_message_div'); $result ||= $self->result; my $output = ''; if ( $result->has_form_errors || $result->has_errors ) { my $alert_error_class = $self->form_messages_alert_error_class; $output = qq{\n
}; my $msg = $self->error_message; $msg ||= 'There were errors in your form'; $msg = $self->_localize($msg); $output .= qq{\n$msg}; $output .= qq{\n$_} for $result->all_form_errors; $output .= "\n
"; } elsif ( $result->validated ) { my $msg = $self->success_message; $msg ||= "Your form was successfully submitted"; $msg = $self->_localize($msg); $output = qq{\n
}; $output .= qq{\n$msg}; $output .= "\n
"; } if ( $self->has_info_message && $self->info_message ) { my $msg = $self->info_message; $msg = $self->_localize($msg); $output = qq{\n
}; $output .= qq{\n$msg}; $output .= "\n
"; } return $output; } sub form_messages_alert_error_class { 'alert-error' } 1; __END__ =pod =encoding UTF-8 =head1 NAME HTML::FormHandler::Widget::Theme::BootstrapFormMessages - role to render form messages using Bootstrap styling =head1 VERSION version 0.40064 =head1 DESCRIPTION Role to render form messages using Bootstrap styling. =head1 NAME HTML::FormHandler::Widget::Theme::BootstrapFormMessages =head1 AUTHOR FormHandler Contributors - see HTML::FormHandler =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Gerda Shank. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut