U
    }Ha7                     @   s   d dl Z d dlmZmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZmZmZmZ G dd	 d	ZG d
d deZdS )    N)NoReverseMatchreverse)	mark_safe)FormHelpersException)Layout)LayoutSlice)TEMPLATE_PACKflatattlist_differencerender_fieldc                   @   s\   e Zd Zdd Zdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd ZdS )DynamicLayoutHandlerc                 C   s   | j d krtdd S )Nz+You need to set a layout in your FormHelper)layoutr   self r   7/tmp/pip-unpacked-wheel-rp2i33ek/crispy_forms/helper.py_check_layout   s    
z"DynamicLayoutHandler._check_layoutc                 C   s   |    | jd krtdd S )Nz3You need to pass a form instance to your FormHelper)r   formr   r   r   r   r   _check_layout_and_form   s    
z+DynamicLayoutHandler._check_layout_and_formc                 C   s$   |    t| jtdt| jjdS )zD
        Returns all layout objects of first level of depth
        r      )r   r   r   slicelenfieldsr   r   r   r   all   s    zDynamicLayoutHandler.allc                 O   s>   |    |dd}|dd}| jj|||d}t| j|S )zX
        Returns a LayoutSlice pointing to layout objects of type `LayoutClass`
        	max_levelr   greedyF)r   r   )r   popr   Zget_layout_objectsr   )r   ZLayoutClasseskwargsr   r   Zfiltered_layout_objectsr   r   r   filter   s
    zDynamicLayoutHandler.filterc                 C   sN   |    | j }g }|D ]&}t| jj|d  j|r|| qt| j|S )zX
        Returns a LayoutSlice pointing to fields with widgets of `widget_type`
        r   	r   r   get_field_names
isinstancer   r   widgetappendr   r   Zwidget_typelayout_field_namesZfiltered_fieldspointerr   r   r   filter_by_widget(   s    
z%DynamicLayoutHandler.filter_by_widgetc                 C   sN   |    | j }g }|D ]&}t| jj|d  j|s|| qt| j|S )zb
        Returns a LayoutSlice pointing to fields with widgets NOT matching `widget_type`
        r   r   r$   r   r   r   exclude_by_widget7   s    
z&DynamicLayoutHandler.exclude_by_widgetc                 C   sx   t |trlt| |rt| |S |   | j }g }|D ]&}t|dkr8|d |kr8|| q8t	| j|S t	| j|S )z{
        Return a LayoutSlice that makes changes affect the current instance of the layout
        and not a copy.
           r   )
r!   strhasattrgetattrr   r   r    r   r#   r   )r   keyr%   Zfiltered_fieldr&   r   r   r   __getitem__F   s    



z DynamicLayoutHandler.__getitem__c                 C   s   || j |< d S Nr   )r   r-   valuer   r   r   __setitem___   s    z DynamicLayoutHandler.__setitem__c                 C   s   | j j|= d S r/   )r   r   )r   r-   r   r   r   __delitem__b   s    z DynamicLayoutHandler.__delitem__c                 C   s   | j d k	rt| j jS dS d S )Nr   )r   r   r   r   r   r   r   __len__e   s    
zDynamicLayoutHandler.__len__N)__name__
__module____qualname__r   r   r   r   r'   r(   r.   r2   r3   r4   r   r   r   r   r      s   r   c                   @   s4  e Zd ZdZdZdZdZdZdZdZ	dZ
dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZd#dd	Zd
d Ze dd Z!e!j"dd Z!e dd Z#e#j"dd Z#e dd Z$e$j"dd Z$e dd Z%e%j"dd Z%e dd Z&e&j"dd Z&dd Z'dd Z(e)fdd Z*e)fd!d"Z+dS )$
FormHelperah  
    This class controls the form rendering behavior of the form passed to
    the `{% crispy %}` tag. For doing so you will need to set its attributes
    and pass the corresponding helper object to the tag::

        {% crispy form form.helper %}

    Let's see what attributes you can set and what form behaviors they apply to:

        **form_method**: Specifies form method attribute.
            You can set it to 'POST' or 'GET'. Defaults to 'POST'

        **form_action**: Applied to the form action attribute:
            - Can be a named url in your URLconf that can be executed via the `{% url %}` template tag.             Example: 'show_my_profile'. In your URLconf you could have something like::

                path('show/profile/', 'show_my_profile_view', name = 'show_my_profile')

            - It can simply point to a URL '/whatever/blabla/'.

        **form_id**: Generates a form id for dom identification.
            If no id provided then no id attribute is created on the form.

        **form_class**: String containing separated CSS classes to be applied
            to form class attribute. The form will always have by default
            'uniForm' class.

        **form_group_wrapper_class**: String containing separated CSS classes to be applied
            to each row of inputs.

        **form_tag**: It specifies if <form></form> tags should be rendered when using a Layout.
            If set to False it renders the form without the <form></form> tags. Defaults to True.

        **form_error_title**: If a form has `non_field_errors` to display, they
            are rendered in a div. You can set title's div with this attribute.
            Example: "Oooops!" or "Form Errors"

        **formset_error_title**: If a formset has `non_form_errors` to display, they
            are rendered in a div. You can set title's div with this attribute.

        **form_style**: Uni-form has two built in different form styles. You can choose
            your favorite. This can be set to "default" or "inline". Defaults to "default".

        **include_media**: Whether to automatically include form media. Set to False if
            you want to manually include form media outside the form. Defaults to True.

    Public Methods:

        **add_input(input)**: You can add input buttons using this method. Inputs
            added using this method will be rendered at the end of the form/formset.

        **add_layout(layout)**: You can add a `Layout` object to `FormHelper`. The Layout
            specifies in a simple, clean and DRY way how the form fields should be rendered.
            You can wrap fields, order them, customize pretty much anything in the form.

    Best way to add a helper to a form is adding a property named helper to the form
    that returns customized `FormHelper` object::

        from crispy_forms.helper import FormHelper
        from crispy_forms.layout import Submit

        class MyForm(forms.Form):
            title = forms.CharField(_("Title"))

            @property
            def helper(self):
                helper = FormHelper()
                helper.form_id = 'this-form-rocks'
                helper.form_class = 'search'
                helper.add_input(Submit('save', 'save'))
                [...]
                return helper

    You can use it in a template doing::

        {% load crispy_forms_tags %}
        {% crispy form %}
    post defaultNTFc                 C   s*   i | _ g | _|d k	r&|| _| || _d S r/   )attrsinputsr   build_default_layoutr   r   r   r   r   r   __init__   s
    zFormHelper.__init__c                 C   s   t |j  S r/   )r   r   keysr?   r   r   r   r>      s    zFormHelper.build_default_layoutc                 C   s   | j S r/   )_form_methodr   r   r   r   form_method   s    zFormHelper.form_methodc                 C   s"   |  dkrtd|  | _d S )N)getr9   zSOnly GET and POST are valid in the                     form_method helper attribute)lowerr   rB   )r   methodr   r   r   rC      s
    c                 C   s,   zt | jW S  tk
r&   | j Y S X d S r/   )r   _form_actionr   r   r   r   r   form_action   s    zFormHelper.form_actionc                 C   s
   || _ d S r/   )rG   )r   actionr   r   r   rH      s    c                 C   s    | j dkrdS | j dkrdS d S )Nr;   r:   inlineZinlineLabels)_form_styler   r   r   r   
form_style   s    

zFormHelper.form_stylec                 C   s"   |  dkrtd|  | _d S )N)r;   rJ   zXOnly default and inline are valid in the                     form_style helper attribute)rE   r   rK   )r   styler   r   r   rL     s
    c                 C   s   | j S r/   )_help_text_inliner   r   r   r   help_text_inline  s    zFormHelper.help_text_inlinec                 C   s   || _ | | _d S r/   )rN   _error_text_inliner   flagr   r   r   rO     s    c                 C   s   | j S r/   )rP   r   r   r   r   error_text_inline  s    zFormHelper.error_text_inlinec                 C   s   || _ | | _d S r/   )rP   rN   rQ   r   r   r   rS     s    c                 C   s   | j | d S r/   )r=   r#   )r   Zinput_objectr   r   r   	add_input  s    zFormHelper.add_inputc                 C   s
   || _ d S r/   r0   )r   r   r   r   r   
add_layout"  s    zFormHelper.add_layoutc              	   C   s   t  |_| j|_| jj|| j||d}| js8| js8| j	rt
|j }t||j}|D ]J}| js| jrt|j| jjs| j	rV|j| jjrV|t||| j||d7 }qVt|S )zB
        Returns safe html of the rendering of the layout
        )template_pack)setZrendered_fieldsfield_templateZcrispy_field_templater   renderrL   render_unmentioned_fieldsrender_hidden_fieldsrender_required_fieldstupler   rA   r
   r"   Z	is_hiddenZis_requiredr   r   )r   r   contextrV   htmlr   Zleft_fields_to_renderfieldr   r   r   render_layout%  s&    zFormHelper.render_layoutc                    s  | j | j| j| jpd| | j | j| j| j | j	| j
| j| j| j| jd}|dkrd| j krtd| j}|rd  fdd|D |d	< n,td
| j}|rd  fdd|D |d	< i |d< | jr| j |d< | jr| j |d d< | jr| j |d d< | jrJ|dkr6d| j  |d d< n| j |d d< n$|dkrn| jddd |d d< | jr| j|d d< t|d |d< | jr| j|d< | jr| j |d< | jr| j |d< | j D ]2\}}||kr|dkr|ds|||< q|S )zD
        Used by crispy_forms_tags to get helper attributes
        z%s/field.html)disable_csrfrS   field_classrX   rC   form_show_errorsform_show_labelsrL   form_tagrO   html5_requiredinclude_medialabel_classuse_custom_controlZ
bootstrap4zform-horizontalzcol(-(xl|lg|md|sm))?-(\d+)zoffset%s-%sc                    s    g | ]} |d  |d f qS )r   r   .0mZoffset_patternr   r   
<listcomp>W  s    z-FormHelper.get_attributes.<locals>.<listcomp>Zbootstrap_checkbox_offsetszcol-(lg|md|sm|xs)-(\d+)zcol-%s-offset-%sc                    s   g | ]} | qS r   r   rl   ro   r   r   rp   ^  s     r<   rI   idZuni_formz
uniForm %sclassr:   z uniFormform_group_wrapper_classZ
flat_attrsr=   form_error_titleformset_error_title)r   r=   _) rb   rS   rc   rX   rC   striprd   re   rL   rf   rO   rg   rh   ri   rj   
form_classsplitrefindallr<   copyrH   form_idrD   rs   r	   r=   rt   ru   __dict__items
startswith)r   rV   r   Zbootstrap_size_matchZattribute_namer1   r   ro   r   get_attributes=  st    



zFormHelper.get_attributes)N),r5   r6   r7   __doc__rB   rG   rK   r   r}   rx   rs   r   rf   rt   ru   rd   rZ   r[   r\   rN   rP   rg   re   templaterX   rb   rj   ri   rc   rh   r@   r>   propertyrC   setterrH   rL   rO   rS   rT   rU   r   ra   r   r   r   r   r   r8   l   sj   O


	



	



r8   )rz   Zdjango.urlsr   r   Zdjango.utils.safestringr   Zcrispy_forms.exceptionsr   Zcrispy_forms.layoutr   Zcrispy_forms.layout_slicer   Zcrispy_forms.utilsr   r	   r
   r   r   r8   r   r   r   r   <module>   s   `