mbraak/django-file-form

Customize frontend UI

BoPeng opened this issue · 9 comments

Right now the UI consists of a button and a drop area. What is the best way to customize this, say, if I want to have something like the following? Perhaps a event handler could be defined and allows users to draw its own UI?

image

One solution that I can think of:

If no files are uploaded, the class dff-empty is added to the .dff-files div. This allows you to customize the drop area with css.

I can add an option to change the 'Drop your files here' message. The only thing missing is the 'click to upload' link. I don't know how that would work.

click to upload would replace the "browse" button. This layout is a bit cleaner than the default one because it has a single widget, although the "click to upload" link would be gone (?) once files are added (or the file list should be put elsewhere).

I am not saying that I like this layout, just curious what is the best way to customize the frontend widget.

Actually I do not quite understand why the widget should be dynamically created in JS. Why cannot it be put into upload_widget.html ?

The widget should also work without javascript. Without javascript there is only an upload input.

I guess it's possible to add a custom handler for the ui. But it's difficult to define what it should do. It's a lot easier to add a very specific handler, like: draw the message for the empty dropbox.

To cover up the default upload button, I had to do something like the following in upload_widget.html

<div class="dff-uploader">
    <div class="dff-container" {% if uploaded_files %} data-files='{{ uploaded_files }}' {% endif %}
        data-translations="{{ translations }}">

        <div class="custom_upload">
            <label for="{{ input | get_id }}">
                {{ input }}
                <span class="btn btn--round btn--sm">Choose File</span>
            </label>
        </div>
    </div>
</div>

The problem is that input is not passed in as a widget, but as a rendered string

upload_input = super().render(name, value, attrs, renderer)
return mark_safe(
render_to_string(
"django_file_form/upload_widget.html",
dict(
input=upload_input,
translations=json.dumps(TRANSLATIONS),
uploaded_files=json.dumps(get_uploaded_files(value)),
),
)

so I had to define a customized template tag to extract the id. Perhaps input should be passed directly?

Anyway, with more css and fake translation of delete and cancel button, the result is

image

image

I will have a look

I think the rendered input has to be included, because I don't see how it can be rendered in upload_widget.html.

An alternative solution could be to add attrs to the upload_widget.html. Then the id can be accessed in the template:

{{ attrs.id }}

Please let me know if this is a solution in your case.

A proper way seems to extend get_context which would allow me to use widget.attrs.id in the template. I just proposed an PR for this change.