Search code examples
javajavascriptgwtjsni

Wrapping/decorating GWT FileUpload


GWT FileUpload comes as a widget that produces so that one can upload a file during form submit (at least it's how I understand it :) ) What I want to do is to make it a better-looking and get rid of standard "Browse..." button.

Since I don't have good GWT experience (and no JavaScript), I looked for existing solutions and found quite a good project - gwtupload. It's good, but I realized I'd love to have my own miniature version (and also, I was curious about how it works). So I browsed through code and tried to extract the magic part. I realized that GWT FileInput is used, but it's not shown, and Button clicks are delegated to this FileInput. The code I tried to extract (only the part that delegates the click) after reviewing sources of gwtupload contains this tricky elem.click() JSNI:

class MyUpload extends Composite {
    private static native void clickOnInputFile(Element elem) /*-{
        elem.click();
    }-*/;

    public MyUpload() {
        final FileUpload upload = new FileUpload();
        AbsolutePanel container = new AbsolutePanel();
        // container.add(upload);
        Button btn = new Button("My Browse..");
        btn.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                clickOnInputFile(upload.getElement());
            }
        });
        container.add(btn);
        initWidget(container);
    }
}

But this seems not to work: clicking on 'My Browse..' results in no effect (just in case I also tried running with un-commented container.add(upload) line) . Could you please help me in understanding what's wrong/missing in this code sample?

Thank you in advance.

P.S. I know that I have to place it on the FormPanel, and I know the rest about how to perform the actual submit/handling in Servlet; the only thing I want to do is this kind of decoration.


Solution

  • Since I have not received any answers, I had to have more investigation of this issue, so I performed a deeper code analysis of gwtupload project in order to understand how GWT FileUpload (which gets transformed into ) can be decorated.

    It turned out that element.click() will only work in browsers which support #click() method (IE, Chrome, Safari). Actually, Manuel Carrasco Moñino - project author - mentions it within comments. There's second approach (for Firefox & Opera) that uses hack when FileInput is placed on transparent panel, which however is placed over some decorated button (using absolute positioning); comment by Manuel:

    When the user puts his mouse over the button and clicks on it, what really happens is that the user clicks on the transparent file input showing the choose file dialog.

    After that, the main work is correctly applying style attributes to elements.

    Thus, there are two implementations of custom file upload component, and GWT deferred binding is used to instantiate them depending on Browser.

    As for example I mention in my question, there're few fixes ("upload" has to be added to to the container, and it can be set to #setVisible(false)):

    class MyUpload extends Composite {
        private static native void clickOnInputFile(Element elem) /*-{
            elem.click();
        }-*/;
    
        public MyUpload() {
            final FileUploadWithMouseEvents upload = new FileUploadWithMouseEvents();
            AbsolutePanel container = new AbsolutePanel();
            container.add(upload);
            upload.setVisible(false);
            Button btn = new Button("My Browse..");
            btn.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    clickOnInputFile(upload.getElement());
                }
            });
            container.add(btn);
            initWidget(container);
        }
    }
    

    This example works fine in IE8.

    P.S. Thanks to Manuel for his great library :)