com.github.gilbertotorrezan.gwtcloudinary.client.CloudinaryUploadWidget.java Source code

Java tutorial

Introduction

Here is the source code for com.github.gilbertotorrezan.gwtcloudinary.client.CloudinaryUploadWidget.java

Source

/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2015 Gilberto Torrezan Filho
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * 
 */
package com.github.gilbertotorrezan.gwtcloudinary.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.safehtml.client.HasSafeHtml;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.HasText;

/**
 * The GWT wrapper for the Cloudinary's Upload Widget. It is a {@link Composite} built around a GWT {@link Button}. 
 * 
 * @author Gilberto Torrezan Filho
 *
 * @since v.1.0.0
 * 
 * @see http://cloudinary.com/documentation/upload_widget
 */
public class CloudinaryUploadWidget extends Composite
        implements HasCloudinaryUploadFinishedHandlers, HasText, HasHTML, HasSafeHtml, HasEnabled {

    protected Button button;
    protected JSONObject options;

    public CloudinaryUploadWidget() {
        button = new Button();
        initialize();
    }

    public CloudinaryUploadWidget(String html) {
        button = new Button(html);
        initialize();
    }

    public CloudinaryUploadWidget(SafeHtml html) {
        button = new Button(html);
        initialize();
    }

    protected CloudinaryUploadWidget(Element elem) {
        button = Button.wrap(elem);
        initialize();
    }

    // executed after any constructor
    protected void initialize() {
        initWidget(button);
        options = new JSONObject();
        button.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                openUploadWidget(options.getJavaScriptObject());
            }
        });
    }

    /**
     * Opens the Cloudinary's Upload Widget in a IFrame. This methos is called automatically by the click handler on the button.
     */
    public native void openUploadWidget(JavaScriptObject options)/*-{
                                                                 var widget = this;
                                                                 $wnd.cloudinary.openUploadWidget(options, 
                                                                 function(error, result) {
                                                                 console.log(error, result);
                                                                 widget.@com.github.gilbertotorrezan.gwtcloudinary.client.CloudinaryUploadWidget::fireUploadFinished(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(error, result);
                                                                 });
                                                                 }-*/;

    /**
     * Fires the {@link CloudinaryUploadFinishedEvent} by using the native objects, converting them to {@link CloudinaryUploadInfo} objects.
     */
    protected void fireUploadFinished(JavaScriptObject error, JavaScriptObject result) {
        String message = null;
        List<CloudinaryUploadInfo> infos = new ArrayList<>();

        if (error != null) {
            JSONObject obj = new JSONObject(error);
            message = getSafeString(obj.get("message"));
        }

        if (result != null) {
            JSONArray resultArray = new JSONArray(result);
            int size = resultArray.size();
            for (int i = 0; i < size; i++) {
                JSONObject object = resultArray.get(i).isObject();

                CloudinaryUploadInfo info = new CloudinaryUploadInfo();
                info.setPublicId(getSafeString(object.get("public_id")));
                info.setSecureUrl(getSafeString(object.get("secure_url")));
                info.setThumbnailUrl(getSafeString(object.get("thumbnail_url")));
                info.setUrl(getSafeString(object.get("url")));
                info.setType(getSafeString(object.get("type")));
                info.setVersion(getSafeString(object.get("version")));
                info.setWidth(getSafeInteger(object.get("width")));
                info.setHeight(getSafeInteger(object.get("height")));
                info.setFormat(getSafeString(object.get("format")));
                info.setResourceType(getSafeString(object.get("resource_type")));
                info.setSignature(getSafeString(object.get("signature")));
                info.setBytes(getSafeInteger(object.get("bytes")));
                info.setOriginalFilename(getSafeString(object.get("original_filename")));
                info.setEtag(getSafeString(object.get("etag")));
                info.setPath(getSafeString(object.get("path")));
                info.setCreatedAt(getSafeString(object.get("created_at")));

                JSONValue tagsValue = object.get("tags");
                if (tagsValue != null && tagsValue.isArray() != null) {
                    JSONArray array = tagsValue.isArray();
                    String[] tags = new String[array.size()];
                    for (int j = 0; j < tags.length; j++) {
                        JSONValue v = array.get(j);
                        tags[j] = getSafeString(v);
                    }
                    info.setTags(tags);
                }

                JSONValue coordinatesValue = object.get("coordinates");
                if (coordinatesValue != null && coordinatesValue.isObject() != null) {
                    JSONObject obj = coordinatesValue.isObject();

                    JSONValue customValue = obj.get("custom");
                    if (customValue != null && customValue.isArray() != null) {
                        JSONArray array = customValue.isArray();
                        CloudinaryCoordinates[] coordinatesArray = new CloudinaryCoordinates[array.size()];
                        for (int j = 0; j < coordinatesArray.length; j++) {
                            JSONValue value = array.get(j);
                            if (value != null && value.isArray() != null && value.isArray().size() >= 4) {
                                JSONArray valueArray = value.isArray();
                                coordinatesArray[j] = new CloudinaryCoordinates();
                                coordinatesArray[j].setX(getSafeInteger(valueArray.get(0)));
                                coordinatesArray[j].setY(getSafeInteger(valueArray.get(1)));
                                coordinatesArray[j].setWidth(getSafeInteger(valueArray.get(2)));
                                coordinatesArray[j].setHeight(getSafeInteger(valueArray.get(3)));
                            }
                        }
                        info.setCustomCoordinates(coordinatesArray);
                    }

                    JSONValue facesValue = obj.get("faces");
                    if (facesValue == null || facesValue.isArray() == null) {
                        facesValue = obj.get("face");
                    }
                    if (facesValue != null && facesValue.isArray() != null) {
                        JSONArray array = facesValue.isArray();
                        CloudinaryCoordinates[] coordinatesArray = new CloudinaryCoordinates[array.size()];
                        for (int j = 0; j < coordinatesArray.length; j++) {
                            JSONValue value = array.get(j);
                            if (value != null && value.isArray() != null && value.isArray().size() >= 4) {
                                JSONArray valueArray = value.isArray();
                                coordinatesArray[j] = new CloudinaryCoordinates();
                                coordinatesArray[j].setX(getSafeInteger(valueArray.get(0)));
                                coordinatesArray[j].setY(getSafeInteger(valueArray.get(1)));
                                coordinatesArray[j].setWidth(getSafeInteger(valueArray.get(2)));
                                coordinatesArray[j].setHeight(getSafeInteger(valueArray.get(3)));
                            }
                        }
                        info.setFaceCoordinates(coordinatesArray);
                    }
                }

                infos.add(info);
            }
        }

        CloudinaryUploadFinishedEvent.fireUploadFinished(this, infos, message, result, error);
    }

    private String getSafeString(JSONValue value) {
        if (value == null) {
            return null;
        }
        JSONString string = value.isString();
        if (string == null) {
            return null;
        }
        return string.stringValue();
    }

    private Integer getSafeInteger(JSONValue value) {
        if (value == null) {
            return null;
        }
        JSONNumber number = value.isNumber();
        if (number == null) {
            return null;
        }
        return (int) number.doubleValue();
    }

    /**
     * Directly set the upload options.
     */
    public CloudinaryUploadWidget setOptions(JSONObject options) {
        if (options == null) {
            clearOptions();
        } else {
            this.options = options;
        }
        return this;
    }

    /**
     * @return The options set so far, never <code>null</code>.
     */
    public JSONObject getOptions() {
        return options;
    }

    /**
     * Clears all the options set so far, by creating a new {@link JSONObject} internally.
     */
    public CloudinaryUploadWidget clearOptions() {
        options = new JSONObject();
        return this;
    }

    /**
     * The cloud name of your Cloudinary's account. Can be set either globally using setCloudName or explicitly for each widget creation call.
     * 
     * @param cloudName Mandatory string. Example: 'demo'
     */
    public CloudinaryUploadWidget setCloudName(String cloudName) {
        options.put("cloud_name", cloudName == null ? null : new JSONString(cloudName));
        return this;
    }

    /**
     * The name of an unsigned upload preset defined for your Cloudinary account either through the Settings page or using the Admin API.
     * 
     * @param uploadPreset Mandatory string. Example: 'a5vxnzbp'
     */
    public CloudinaryUploadWidget setUploadPreset(String uploadPreset) {
        options.put("upload_preset", uploadPreset == null ? null : new JSONString(uploadPreset));
        return this;
    }

    /**
     * List of file sources that should be available as tabs of the widget's helper.
     * Supported sources are: local files using selection or drag & drop, remote HTTP URL and webcam capturing. 
     * Note: Camera is currently supported in all modern browsers, not including Internet Explorer and Desktop Safari.
     * 
     * @param sources Array of strings: local, url, camera. Default: ['local', 'url', 'camera']
     */
    public CloudinaryUploadWidget setSources(String[] sources) {
        if (sources != null) {
            JSONArray array = new JSONArray();
            for (int i = 0; i < sources.length; i++) {
                array.set(i, new JSONString(sources[i]));
            }
            options.put("sources", array);
        } else {
            options.put("sources", null);
        }
        return this;
    }

    /**
     * The default selected source tab when the widget is opened.
     * 
     * @param defaultSource String. Default: local
     */
    public CloudinaryUploadWidget setDefaultSource(String defaultSource) {
        options.put("default_source", defaultSource == null ? null : new JSONString(defaultSource));
        return this;
    }

    /**
     *  Whether selecting and uploading multiple images is allowed. Completion callback is called only when all images complete uploading. 
     *  Multiple hidden fields of image identifiers are created if set to true. If set to false, only a single image is allowed in any source.
     *  
     *  @param multiple Boolean. Default: true
     */
    public CloudinaryUploadWidget setMultiple(Boolean multiple) {
        options.put("multiple", multiple == null ? null : JSONBoolean.getInstance(multiple));
        return this;
    }

    /**
     * The maximum number of files allowed in multiple upload mode. If selecting or dragging more files, only the first max_images files will be uploaded.
     * 
     * @param maxFiles Integer. Default: null. Unlimited. Example: 10
     */
    public CloudinaryUploadWidget setMaxFiles(Integer maxFiles) {
        options.put("max_files", maxFiles == null ? null : new JSONNumber(maxFiles));
        return this;
    }

    /**
     * Whether to enable interactive cropping of images before uploading to Cloudinary. Interactive cropping allows users to mark the interesting part of images.
     * The selected dimensions are sent as the custom_coordinates upload parameter of Cloudinary. 
     * Setting gravity to custom when generating delivery URLs will focus on the marked region.
     * Incoming cropping on the server-side can be applied by applying the crop mode with the custom gravity of in your upload preset.
     * Enabling cropping forces single file uploading.
     * 
     *  @param cropping String. Cropping modes: 'server' Default: null. No cropping. Example: 'server' 
     */
    public CloudinaryUploadWidget setCropping(String cropping) {
        options.put("cropping", cropping == null ? null : new JSONString(cropping));
        return this;
    }

    /**
     * If specified, enforce the given aspect ratio on selected region when performing interactive cropping. Relevant only if cropping is enabled.
     * The aspect ratio is defined as width/height. For example, 0.5 for portrait oriented rectangle or 1 for square.
     * 
     * @param croppingAspectRatio Decimal. Default: null. No constraint. Example: 0.5
     */
    public CloudinaryUploadWidget setCroppingAspectRatio(Double croppingAspectRatio) {
        options.put("cropping_aspect_ratio",
                croppingAspectRatio == null ? null : new JSONNumber(croppingAspectRatio));
        return this;
    }

    /**
     * Initialize the size of the cropping selection box to a different value than the default (0.9). Relevant only if the cropping feature is enabled.
     * The cropping_default_selection_ratio value is calculated as a proportion of the image's size.
     * 
     * @param croppingDefaultSelectionRatio Decimal. Default: 0.9. Range: 0.1 to 1.0. Example: 0.75
     */
    public CloudinaryUploadWidget setCroppingDefaultSelectionRatio(Double croppingDefaultSelectionRatio) {
        options.put("cropping_default_selection_ratio",
                croppingDefaultSelectionRatio == null ? null : new JSONNumber(croppingDefaultSelectionRatio));
        return this;
    }

    /**
     * Custom public ID to assign to a single uploaded image.
     * If not specified, either a randomly generated string or the original file-name is used as the public ID according to the unsigned upload preset.
     * To ensure secure usage, overwriting previously uploaded images sharing the same public ID is prevented.
     * 
     * @param publicId String. Default: null. Example: 'profile_11002'
     */
    public CloudinaryUploadWidget setPublicId(String publicId) {
        options.put("public_id", publicId == null ? null : new JSONString(publicId));
        return this;
    }

    /**
     * Folder name for all uploaded images. Acts as the prefix of assigned public IDs.
     * 
     * @param folder String. Default: null. Example: 'user_photos'
     */
    public CloudinaryUploadWidget setFolder(String folder) {
        options.put("folder", folder == null ? null : new JSONString(folder));
        return this;
    }

    /**
     *  One or more tags to assign to the uploaded images.
     *  
     *  @param tags String or array of strings. Default: null. Example: '['users' 'content']
     */
    public CloudinaryUploadWidget setTags(String[] tags) {
        if (tags != null) {
            JSONArray array = new JSONArray();
            for (int i = 0; i < tags.length; i++) {
                array.set(i, new JSONString(tags[i]));
            }
            options.put("tags", array);
        } else {
            options.put("tags", null);
        }
        return this;
    }

    /**
     * The resource type of the uploaded files. In default, both images and raw files are allowed.
     * Setting to either 'raw' or 'image' forces only raw files or only images respectively.
     * 
     * @param resourceType String: 'auto', 'image', 'raw'. Default: 'auto' Example: 'image'
     */
    public CloudinaryUploadWidget setResourceType(String resourceType) {
        options.put("resource_type", resourceType == null ? null : new JSONString(resourceType));
        return this;
    }

    /**
     * Additional context metadata to attach to the uploaded images.
     * 
     * @param context Map of key-value pairs. Example: { alt: "my_alt", caption: "my_caption"}
     */
    public CloudinaryUploadWidget setContext(JSONObject context) {
        options.put("context", context);
        return this;
    }

    /**
     * Allows client-side validation of the uploaded files based on their file extensions. You can specify one or more image or raw file extensions.
     * 
     * @param clientAllowedFormats Array of file formats: png, jpg, gif, doc, xls, etc. Default: null. All formats allowed. Example: ["png","gif", "jpeg"]
     */
    public CloudinaryUploadWidget setClientAllowedFormats(String[] clientAllowedFormats) {
        if (clientAllowedFormats != null) {
            JSONArray array = new JSONArray();
            for (int i = 0; i < clientAllowedFormats.length; i++) {
                array.set(i, new JSONString(clientAllowedFormats[i]));
            }
            options.put("client_allowed_formats", array);
        } else {
            options.put("client_allowed_formats", null);
        }
        return this;
    }

    /**
     * If specified, perform client side validation that prevents uploading files bigger than the given bytes size.
     * 
     * @param maxFileSize Integer. Number of bytes. Default: null. No size limit. Example: 130000
     */
    public CloudinaryUploadWidget setMaxFileSize(Integer maxFileSize) {
        options.put("max_file_size", maxFileSize == null ? null : new JSONNumber(maxFileSize));
        return this;
    }

    /**
     * If specified, client-side scale-down resizing takes place before uploading if the width of the selected file is bigger than the specified value.
     * 
     * @param maxImageWidth Integer. Number of pixels. Default: null. No resizing. Example: 2000
     */
    public CloudinaryUploadWidget setMaxImageWidth(Integer maxImageWidth) {
        options.put("max_image_width", maxImageWidth == null ? null : new JSONNumber(maxImageWidth));
        return this;
    }

    /**
     * If specified, client-side scale-down resizing takes place before uploading if the height of the selected file is bigger than the specified value.
     * 
     * @param maxImageHeight Integer. Number of pixels. Default: null. No resizing. Example: 2000
     */
    public CloudinaryUploadWidget setMaxImageHeight(Integer maxImageHeight) {
        options.put("max_image_height", maxImageHeight == null ? null : new JSONNumber(maxImageHeight));
        return this;
    }

    /**
     * The selector (CSS path) of the form, to which you would like to append hidden fields with the identifiers of the uploaded images.
     * Implicitly set by default to the containing form of the given element when the widget is created using applyUploadWidget or $.fn.cloudinary_upload_widget.
     * Note: Supported only if jQuery is loaded in your site.
     * 
     * @param form String. jQuery-style selector. Default: null Example: '#my_form'
     */
    public CloudinaryUploadWidget setForm(String form) {
        options.put("form", form == null ? null : new JSONString(form));
        return this;
    }

    /**
     * The name of the hidden field added to your form when image uploading is completed.
     * Multiple hidden fields with the same name are created for multiple uploaded images.
     * The name may include '[]' for supporting web frameworks such as Ruby on Rails.
     * Note: Supported only if jQuery is loaded in your site.
     * 
     * @param fieldName String. Form field name. Default: 'image' Example: 'photo[]'
     */
    public CloudinaryUploadWidget setFieldName(String fieldName) {
        options.put("field_name", fieldName == null ? null : new JSONString(fieldName));
        return this;
    }

    /**
     * Selector (CSS path) of an HTML element that acts as the container for appending uploaded images thumbnails to.
     * Implicitly set by default to the containing form of the given element when the widget is created using applyUploadWidget or $.fn.cloudinary_upload_widget.
     * Note: Supported only if jQuery is loaded in your site.
     * 
     * @param thumbnails String. jQuery-style selector. Default: null Example: '.content .uploaded'
     */
    public CloudinaryUploadWidget setThumbnails(String thumbnails) {
        options.put("thumbnails", thumbnails == null ? null : new JSONString(thumbnails));
        return this;
    }

    /**
     * The Cloudinary transformation (image manipulation) to apply on uploaded images for embedding thumbnails in your site.
     * Any resizing, cropping, effects and other Cloudinary transformation options can be applied by specifying a transformation string, a map of transformations parameters or an array of chained transformations.
     * Thumbnails transformations can be eagerly generated during upload by defining a set of eager transformations in your defined upload preset.
     * 
     * @param thumbnailTransformation String, Map or Array of maps. Default: { width: 90, height: 60, crop: 'limit' } 
     * Examples: { width: 200, height: 200, crop: 'fill' }[ {width: 200, height: 200, crop: 'fill'}, {effect: 'sepia'} ]
     * "w_200"
     */
    public CloudinaryUploadWidget setThumbnailTransformation(JSONObject thumbnailTransformation) {
        options.put("thumbnail_transformation", thumbnailTransformation);
        return this;
    }

    /**
     * Allows overriding the default CSS class name of the upload button added to your site.
     * Default CSS style is applied to the cloudinary-button class, that you can override using CSS directives.
     * Alternatively, you can specify any class name that matches your website design.
     * 
     * @param buttonClass String. Default: 'cloudinary-button' Example: 'my_button'
     */
    public CloudinaryUploadWidget setButtonClass(String buttonClass) {
        options.put("button_class", buttonClass == null ? null : new JSONString(buttonClass));
        return this;
    }

    /**
     * Allows overriding the default caption of the upload button added to your site.
     * 
     * @param buttonCaption String. Default: 'Upload image' Example: 'Pick photo...'
     */
    public CloudinaryUploadWidget setButtonCaption(String buttonCaption) {
        options.put("button_caption", buttonCaption == null ? null : new JSONString(buttonCaption));
        return this;
    }

    /**
     * The name of a predefined widget theme. Widget behavior is the same for all themes, while look & feel changes.
     * 
     * @param theme String. Supported themes: 'default', 'white', 'minimal', 'purple'. Default: 'default' Example: 'white'
     */
    public CloudinaryUploadWidget setTheme(String theme) {
        options.put("theme", theme == null ? null : new JSONString(theme));
        return this;
    }

    /**
     * Advanced customization of the widget's look & feel.
     * Allows overriding the widget theme's colors, fonts, icons and other elements by providing custom style definition.
     * See the white and minimal themes as reference implementations.
     * 
     * @param stylesheet String. Either a URL of a CSS file or inline CSS styles. Default: null 
     * Examples: 
     * 'http://mydomain/widget_style.css'
     * '//mydomain/widget_style.css'
     * '#cloudinary-overlay { background-color: #a7a7a7; } #cloudinary-widget { background: #f0f0f0; }'
     * 
     */
    public CloudinaryUploadWidget setStylesheet(String stylesheet) {
        options.put("stylesheet", stylesheet == null ? null : new JSONString(stylesheet));
        return this;
    }

    /**
     * Mainly for debug purposes. If set to true, the upload widget remains open when uploading is completed.
     * 
     * @param keepWidgetOpen Boolean. Default: false
     */
    public CloudinaryUploadWidget setKeepWidgetOpen(Boolean keepWidgetOpen) {
        options.put("keep_widget_open", keepWidgetOpen == null ? null : JSONBoolean.getInstance(keepWidgetOpen));
        return this;
    }

    /**
     * If set to false, the Powered By Cloudinary icon is not displayed.
     * Note: Supported only for paid Cloudinary accounts and requires some time for cache expiration.
     * 
     * @param showPoweredBy Boolean. Default: true
     */
    public CloudinaryUploadWidget setShowPoweredBy(Boolean showPoweredBy) {
        options.put("show_powered_by", showPoweredBy == null ? null : JSONBoolean.getInstance(showPoweredBy));
        return this;
    }

    @Override
    public HandlerRegistration addCloudinaryUploadFinishedHandler(CloudinaryUploadFinishedHandler handler) {
        return addHandler(handler, CloudinaryUploadFinishedEvent.getType());
    }

    @Override
    public String getHTML() {
        return button.getHTML();
    }

    @Override
    public void setHTML(String html) {
        button.setHTML(html);
    }

    @Override
    public void setText(String text) {
        button.setText(text);
    }

    @Override
    public String getText() {
        return button.getText();
    }

    @Override
    public boolean isEnabled() {
        return button.isEnabled();
    }

    @Override
    public void setEnabled(boolean enabled) {
        button.setEnabled(enabled);
    }

    @Override
    public void setHTML(SafeHtml html) {
        button.setHTML(html);
    }
}