JS based multiupload component #PL-5638

This commit is contained in:
Yuriy Artamonov 2015-08-04 15:15:55 +00:00
parent bf442ac288
commit dae0cb6147
16 changed files with 492 additions and 273 deletions

View File

@ -12,9 +12,7 @@ import java.util.UUID;
* @author abramov
* @version $Id$
*/
public interface FileUploadField
extends Component, Component.HasCaption, Component.BelongToFrame
{
public interface FileUploadField extends Component, Component.HasCaption, Component.BelongToFrame {
String NAME = "upload";
interface Listener {
@ -47,7 +45,7 @@ public interface FileUploadField
void uploadFailed(Event event);
}
public class ListenerAdapter implements Listener {
class ListenerAdapter implements Listener {
@Override
public void uploadStarted(Event event) {
}

View File

@ -6,6 +6,7 @@
package com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload;
import com.haulmont.cuba.web.toolkit.ui.CubaFileUpload;
import com.haulmont.cuba.web.toolkit.ui.client.fileupload.CubaFileUploadServerRpc;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
@ -37,31 +38,43 @@ public class CubaFileUploadConnector extends AbstractComponentConnector implemen
return (CubaFileUploadState) super.getState();
}
@Override
protected void init() {
super.init();
getWidget().filePermissionsHandler = new CubaFileUploadWidget.FilePermissionsHandler() {
@Override
public void fileSizeLimitExceeded(String filename) {
getRpcProxy(CubaFileUploadServerRpc.class).fileSizeLimitExceeded(filename);
}
};
}
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
if (stateChangeEvent.hasPropertyChanged("caption")
|| stateChangeEvent.hasPropertyChanged("captionAsHtml")) {
VCaption.setCaptionText(getWidget().captionElement, getState());
VCaption.setCaptionText(getWidget().submitButton.captionElement, getState());
}
if (stateChangeEvent.hasPropertyChanged("resources")) {
if (getWidget().icon != null) {
getWidget().buttonWrap.removeChild(getWidget().icon.getElement());
getWidget().icon = null;
if (getWidget().submitButton.icon != null) {
getWidget().submitButton.wrapper.removeChild(getWidget().submitButton.icon.getElement());
getWidget().submitButton.icon = null;
}
Icon icon = getIcon();
if (icon != null) {
getWidget().icon = icon;
getWidget().submitButton.icon = icon;
if (getState().iconAltText != null) {
icon.setAlternateText(getState().iconAltText);
} else {
icon.setAlternateText("");
}
getWidget().buttonWrap.insertBefore(icon.getElement(),
getWidget().captionElement);
getWidget().submitButton.wrapper.insertBefore(icon.getElement(),
getWidget().submitButton.captionElement);
}
}
@ -70,8 +83,8 @@ public class CubaFileUploadConnector extends AbstractComponentConnector implemen
}
if (stateChangeEvent.hasPropertyChanged("iconAltText")) {
if (getWidget().icon != null) {
Icon icon = getWidget().icon;
if (getWidget().submitButton.icon != null) {
Icon icon = getWidget().submitButton.icon;
if (getState().iconAltText != null) {
icon.setAlternateText(getState().iconAltText);
} else {
@ -91,6 +104,20 @@ public class CubaFileUploadConnector extends AbstractComponentConnector implemen
if (stateChangeEvent.hasPropertyChanged("unableToUploadFileMessage")) {
getWidget().unableToUploadFileMessage = getState().unableToUploadFileMessage;
}
if (stateChangeEvent.hasPropertyChanged("accept")) {
getWidget().setAccept(getState().accept);
}
if (stateChangeEvent.hasPropertyChanged("fileSizeLimit")) {
getWidget().fileSizeLimit = getState().fileSizeLimit;
}
if (!isEnabled() || isReadOnly()) {
getWidget().disableUpload();
} else {
getWidget().enableUpload();
}
}
@Override

View File

@ -21,6 +21,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComputedStyle;
import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.*;
@ -39,7 +40,7 @@ public class CubaFileUploadProgressWindow extends VOverlay implements KeyDownHan
private static final String MODAL_WINDOW_OPEN_CLASSNAME = "v-modal-window-open";
public static final int Z_INDEX = 10000;
public static final int Z_INDEX = 15000;
protected Element contents;
@ -49,7 +50,7 @@ public class CubaFileUploadProgressWindow extends VOverlay implements KeyDownHan
protected Element resizeBox;
protected final FocusableScrollPanel contentPanel = new FocusableScrollPanel();
protected SimpleFocusablePanel contentPanel;
protected boolean dragging;
@ -114,9 +115,6 @@ public class CubaFileUploadProgressWindow extends VOverlay implements KeyDownHan
RelevantValue.ADDITIONS);
constructDOM();
contentPanel.addKeyDownHandler(this);
contentPanel.addKeyUpHandler(this);
}
@Override
@ -248,10 +246,18 @@ public class CubaFileUploadProgressWindow extends VOverlay implements KeyDownHan
}
});
contentPanel = new SimpleFocusablePanel();
contentPanel.setStyleName("content-pane");
contentPanel.addKeyDownHandler(this);
contentPanel.addKeyUpHandler(this);
setWidget(contentPanel);
final FlowPanel verticalPanel = new FlowPanel();
verticalPanel.setWidth("100%");
verticalPanel.setStyleName("vertical-panel");
verticalPanel.addStyleName("v-widget");
verticalPanel.addStyleName("v-has-width");
verticalPanel.addStyleName("v-has-height");
verticalPanel.add(currentFileLabel);
verticalPanel.add(progressBar);
@ -265,13 +271,15 @@ public class CubaFileUploadProgressWindow extends VOverlay implements KeyDownHan
public void execute() {
Style contentStyle = contents.getStyle();
int headerHeight = WidgetUtil.getRequiredHeight(header);
contentStyle.setPaddingTop(headerHeight, Style.Unit.PX);
contentStyle.setMarginTop(-headerHeight, Style.Unit.PX);
ComputedStyle headerCs = new ComputedStyle(header);
String headerHeight = headerCs.getProperty("height");
contentStyle.setProperty("paddingTop", headerHeight);
contentStyle.setProperty("marginTop", "-" + headerHeight);
int footerHeight = WidgetUtil.getRequiredHeight(footer);
contentStyle.setPaddingBottom(footerHeight, Style.Unit.PX);
contentStyle.setMarginBottom(-footerHeight, Style.Unit.PX);
ComputedStyle footerCs = new ComputedStyle(footer);
String footerHeight = footerCs.getProperty("height");
contentStyle.setProperty("paddingBottom", footerHeight);
contentStyle.setProperty("marginBottom", "-" + footerHeight);
}
});

View File

@ -5,71 +5,81 @@
package com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.ui.FocusWidget;
import com.vaadin.client.ui.Icon;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlowPanel;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.VButton;
import com.vaadin.client.ui.VNotification;
import com.vaadin.shared.Position;
/**
* todo artamonov support keyboard Enter/Space press
*
* todo artamonov compress js files
*
* @author artamonov
* @version $Id$
*/
public class CubaFileUploadWidget extends FocusWidget {
public class CubaFileUploadWidget extends FlowPanel {
public static final String DEFAULT_CLASSNAME = "cuba-fileupload";
protected Element rootElement;
protected Element inputElement;
protected Element captionElement;
protected Element buttonWrap;
protected Icon icon;
protected int tabIndex = 0;
protected boolean enabled = true;
protected VButton submitButton;
protected JQueryFileUploadOverlay fileUpload;
protected CubaFileUploadProgressWindow progressWindow;
protected String unableToUploadFileMessage;
protected String progressWindowCaption;
protected String cancelButtonCaption;
private CubaFileUploadProgressWindow progressWindow;
protected int fileSizeLimit = -1;
protected FilePermissionsHandler filePermissionsHandler;
protected boolean enabled;
public CubaFileUploadWidget() {
Document doc = Document.get();
rootElement = doc.createDivElement();
buttonWrap = doc.createSpanElement();
captionElement = doc.createSpanElement();
buttonWrap.appendChild(captionElement);
rootElement.appendChild(buttonWrap);
inputElement = doc.createFileInputElement();
inputElement.setAttribute("name", "files[]");
Style inputStyle = inputElement.getStyle();
inputStyle.setPosition(Style.Position.ABSOLUTE);
inputStyle.setTop(0, Unit.PX);
inputStyle.setRight(0, Unit.PX);
inputStyle.setFontSize(200, Unit.PX);
inputStyle.setMargin(0, Unit.PX);
inputStyle.setOpacity(0);
rootElement.appendChild(inputElement);
setElement(rootElement);
submitButton = new VButton();
submitButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
fireNativeClick(inputElement);
}
});
add(submitButton);
submitButton.setTabIndex(-1);
setStyleName(DEFAULT_CLASSNAME);
if (inputElement != null) {
getElement().removeChild(inputElement);
}
inputElement = Document.get().createFileInputElement();
inputElement.setAttribute("name", "files[]");
DOM.sinkEvents(inputElement, Event.ONFOCUS);
getElement().appendChild(inputElement);
fileUpload = new JQueryFileUploadOverlay(inputElement) {
protected boolean canceled = false;
@Override
protected boolean isValidFile(String name, double size) {
if (fileSizeLimit > 0 && size > fileSizeLimit) {
if (filePermissionsHandler != null) {
filePermissionsHandler.fileSizeLimitExceeded(name);
}
return false;
}
return true;
}
@Override
protected void queueUploadStart() {
progressWindow = new CubaFileUploadProgressWindow();
@ -87,7 +97,9 @@ public class CubaFileUploadWidget extends FocusWidget {
progressWindow.closeListener = new CubaFileUploadProgressWindow.CloseListener() {
@Override
public void onClose() {
// todo artamonov cancel uploading
canceled = true;
cancelUploading();
progressWindow = null;
}
};
@ -96,6 +108,8 @@ public class CubaFileUploadWidget extends FocusWidget {
progressWindow.show();
progressWindow.center();
progressWindow.setVisible(true);
canceled = false;
}
@Override
@ -120,9 +134,29 @@ public class CubaFileUploadWidget extends FocusWidget {
progressWindow = null;
}
}
@Override
protected void uploadFailed(String textStatus, String errorThrown) {
if (!canceled) {
if (unableToUploadFileMessage != null) {
// show notification without server round trip, server may be unreachable
VNotification notification = VNotification.createNotification(-1, CubaFileUploadWidget.this);
String message = "<h1>" + WidgetUtil.escapeHTML(unableToUploadFileMessage) + "</h1>";
notification.show(message, Position.MIDDLE_CENTER, "error");
}
canceled = true;
cancelUploading();
}
}
};
}
private static native void fireNativeClick(Element element)
/*-{
element.click();
}-*/;
public void setMultiSelect(boolean multiple) {
if (multiple) {
inputElement.setAttribute("multiple", "");
@ -135,61 +169,35 @@ public class CubaFileUploadWidget extends FocusWidget {
fileUpload.setUploadUrl(uploadUrl);
}
@Override
public final void setEnabled(boolean enabled) {
if (isEnabled() != enabled) {
this.enabled = enabled;
if (!enabled) {
Roles.getButtonRole().setAriaDisabledState(getElement(), true);
super.setTabIndex(-1);
} else {
Roles.getButtonRole().removeAriaDisabledState(getElement());
super.setTabIndex(tabIndex);
}
public void setAccept(String accept) {
if (accept != null) {
inputElement.setAttribute("accept", accept);
} else {
inputElement.removeAttribute("accept");
}
}
@Override
public final boolean isEnabled() {
return enabled;
public void disableUpload() {
setEnabledForSubmitButton(false);
// Cannot disable the fileupload while submitting or the file won't
// be submitted at all
inputElement.setAttribute("disabled", "disabled");
enabled = false;
}
@Override
public final void setTabIndex(int index) {
if (isEnabled()) {
super.setTabIndex(index);
}
tabIndex = index;
public void enableUpload() {
setEnabledForSubmitButton(true);
inputElement.removeAttribute("disabled");
enabled = true;
}
@Override
public int getTabIndex() {
return tabIndex;
protected void setEnabledForSubmitButton(boolean enabled) {
submitButton.setEnabled(enabled);
submitButton.setStyleName(StyleConstants.DISABLED, !enabled);
}
@Override
protected void onAttach() {
int tabIndex = this.tabIndex;
public interface FilePermissionsHandler {
super.onAttach();
// Small hack to restore tabIndex after attach
setTabIndex(tabIndex);
}
@Override
public void setStyleName(String style) {
super.setStyleName(style);
buttonWrap.setClassName(getStylePrimaryName() + "-wrap");
captionElement.setClassName(getStylePrimaryName() + "-caption");
}
@Override
public void setStylePrimaryName(String style) {
super.setStylePrimaryName(style);
buttonWrap.setClassName(getStylePrimaryName() + "-wrap");
captionElement.setClassName(getStylePrimaryName() + "-caption");
void fileSizeLimitExceeded(String filename);
}
}

View File

@ -5,8 +5,12 @@
package com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import java.util.ArrayList;
import java.util.List;
/**
* @author artamonov
* @version $Id$
@ -16,6 +20,8 @@ public class JQueryFileUploadOverlay {
protected Element fileInput;
protected String uploadUrl;
protected List<JavaScriptObject> currentXHRs = new ArrayList<JavaScriptObject>();
public JQueryFileUploadOverlay(Element fileInput) {
this.fileInput = fileInput;
@ -41,52 +47,82 @@ public class JQueryFileUploadOverlay {
var self = this;
upload.bind('fileuploadadd', function (e, data) {
console.log('Add file');
upload.bind('fileuploadadd', $entry(function (e, data) {
console.log(">> File add");
data.url = self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::uploadUrl;
data.submit();
});
upload.bind('fileuploadsend', function (e, data) {
$entry(
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::fileUploadStart(*)(data.files[0].name)
);
});
var file = data.files[0];
var valid = self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::isValidFile(*)(file.name, file.size);
upload.bind('fileuploadprogress', function (e, data) {
if (valid) {
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::addPendingUpload(*)(data);
data.submit();
}
}));
upload.bind('fileuploaddone', $entry(function (e, data) {
console.log(">> File done");
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::removePendingUpload(*)(data)
}));
upload.bind('fileuploadsend', $entry(function (e, data) {
console.log(">> File send");
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::fileUploadStart(*)(data.files[0].name)
}));
upload.bind('fileuploadprogress', $entry(function (e, data) {
console.log('Upload progress ' + data.loaded + ' / ' + data.total);
$entry(
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::uploadProgress(*)(data.loaded, data.total)
);
});
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::uploadProgress(*)(data.loaded, data.total)
}));
upload.bind('fileuploadstart', function (e, data) {
console.log('Start upload');
upload.bind('fileuploadstart', $entry(function (e, data) {
console.log(">> queue start");
$entry(
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::queueUploadStart()()
);
});
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::queueUploadStart()()
}));
upload.bind('fileuploadstop', function (e, data) {
console.log('Stop upload');
upload.bind('fileuploadstop', $entry(function (e, data) {
console.log(">> queue stop");
$entry(
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::queueUploadStop()()
);
});
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::queueUploadStop()()
}));
upload.bind('fileuploadfail', function (e, data) {
console.log('Failed upload ' + data.errorThrown + ' ' + data.textStatus);
upload.bind('fileuploadfail', $entry(function (e, data) {
console.log(">> fail");
$entry(
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::uploadFailed(*)(data.textStatus, data.errorThrown)
);
});
self.@com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.JQueryFileUploadOverlay::uploadFailed(*)(data.textStatus, data.errorThrown)
}));
}-*/;
protected native void cancelXHR(JavaScriptObject jqXHR) /*-{
jqXHR.abort();
}-*/;
protected void addPendingUpload(JavaScriptObject jqXHR) {
currentXHRs.add(jqXHR);
}
protected void removePendingUpload(JavaScriptObject jqXHR) {
currentXHRs.remove(jqXHR);
}
public void cancelUploading() {
for (int i = currentXHRs.size() - 1; i >= 0; i--) {
cancelXHR(currentXHRs.get(i));
}
currentXHRs.clear();
}
protected boolean isValidFile(String name, double size) {
// check if file has valid extension and size
return true;
}
protected void uploadProgress(double loaded, double total) {
// change progress bar value
}

View File

@ -14,6 +14,10 @@ import com.vaadin.client.ui.VUpload;
public class CubaUploadWidget extends VUpload {
public void setAccept(String accept) {
fu.getElement().setAttribute("accept", accept);
if (accept != null) {
fu.getElement().setAttribute("accept", accept);
} else {
fu.getElement().removeAttribute("accept");
}
}
}

View File

@ -12,6 +12,7 @@ import com.haulmont.cuba.web.WebConfig;
import com.haulmont.cuba.web.app.WebStatisticsAccumulator;
import com.haulmont.cuba.web.auth.RequestContext;
import com.vaadin.server.*;
import com.vaadin.shared.ApplicationConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -41,8 +42,7 @@ public class CubaApplicationServlet extends VaadinServlet {
protected WebConfig webConfig;
//private StatisticsCounter statisticsCounter;
private WebStatisticsAccumulator statisticsCounter;
protected WebStatisticsAccumulator statisticsCounter;
@Override
protected VaadinServletService createServletService(DeploymentConfiguration deploymentConfiguration)
@ -167,11 +167,26 @@ public class CubaApplicationServlet extends VaadinServlet {
AppContext.setSecurityContext(null);
}
long t = System.currentTimeMillis() - startTs;
if (t > (webConfig.getLogLongRequestsThresholdSec() * 1000)) {
// todo artamonov ignore file uploading requests here
log.warn(String.format("Too long request processing [%d ms]: ip=%s, url=%s",
t, request.getRemoteAddr(), request.getRequestURI()));
if (hasPathPrefix(request, ApplicationConstants.UIDL_PATH + '/')) {
long t = System.currentTimeMillis() - startTs;
if (t > (webConfig.getLogLongRequestsThresholdSec() * 1000)) {
log.warn(String.format("Too long request processing [%d ms]: ip=%s, url=%s",
t, request.getRemoteAddr(), request.getRequestURI()));
}
}
}
protected boolean hasPathPrefix(HttpServletRequest request, String prefix) {
String pathInfo = request.getPathInfo();
if (pathInfo == null) {
return false;
}
if (!prefix.startsWith("/")) {
prefix = '/' + prefix;
}
return pathInfo.startsWith(prefix);
}
}

View File

@ -5,6 +5,7 @@
package com.haulmont.cuba.web.toolkit.ui;
import com.haulmont.cuba.web.toolkit.ui.client.fileupload.CubaFileUploadServerRpc;
import com.haulmont.cuba.web.toolkit.ui.client.jqueryfileupload.CubaFileUploadState;
import com.vaadin.annotations.JavaScript;
import com.vaadin.server.*;
@ -13,6 +14,9 @@ import com.vaadin.ui.Component;
import com.vaadin.ui.LegacyComponent;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.OutputStream;
import java.io.Serializable;
@ -24,9 +28,9 @@ import java.util.*;
* @version $Id$
*/
@JavaScript({
"resources/jqueryfileupload/jquery.ui.widget-1.11.1.js",
"resources/jqueryfileupload/jquery.iframe-transport-9.10.5.js",
"resources/jqueryfileupload/jquery.fileupload-9.10.5.js"
"resources/jqueryfileupload/jquery.ui.widget-1.11.1.min.js",
"resources/jqueryfileupload/jquery.iframe-transport-9.10.5.min.js",
"resources/jqueryfileupload/jquery.fileupload-9.10.5.min.js"
})
public class CubaFileUpload extends AbstractComponent implements Component.Focusable, LegacyComponent {
@ -50,6 +54,26 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
protected Set<String> permittedExtensions;
public CubaFileUpload() {
registerRpc(new CubaFileUploadServerRpc() {
@Override
public void fileSizeLimitExceeded(String fileName) {
fireFileSizeLimitExceeded(fileName);
}
});
setErrorHandler(new ErrorHandler() {
@Override
public void error(com.vaadin.server.ErrorEvent event) {
Log log = LogFactory.getLog(CubaFileUpload.class);
//noinspection ThrowableResultOfMethodCallIgnored
Throwable ex = event.getThrowable();
if (StringUtils.contains(ExceptionUtils.getRootCauseMessage(ex), "The multipart stream ended unexpectedly")) {
log.warn("Unable to upload file, it seems upload canceled or network error occured");
} else {
log.warn("Unexpected error in CubaFileUpload", ex);
}
}
});
}
@Override
@ -212,6 +236,17 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
}
}
public double getFileSizeLimit() {
return getState(false).fileSizeLimit;
}
/**
* @param fileSizeLimit file size limit in bytes
*/
public void setFileSizeLimit(int fileSizeLimit) {
getState().fileSizeLimit = fileSizeLimit;
}
public Receiver getReceiver() {
return receiver;
}
@ -256,8 +291,19 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
public void streamingStarted(StreamingStartEvent event) {
startUpload();
contentLength = event.getContentLength();
fireStarted(event.getFileName(), event.getMimeType());
lastStartedEvent = event;
double fileSizeLimit = getFileSizeLimit();
if (fileSizeLimit >0 && event.getContentLength() > fileSizeLimit) {
Log log = LogFactory.getLog(CubaFileUpload.class);
log.warn("Unable to start upload. File size limit exceeded, but client-side checks ignored.");
interruptUpload();
return;
// here client sends file to us bypassing client-side checks, just stop uploading
}
fireStarted(event.getFileName(), event.getMimeType());
}
@Override
@ -366,6 +412,10 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
fireEvent(new SucceededEvent(this, filename, MIMEType, length));
}
protected void fireFileSizeLimitExceeded(String filename) {
fireEvent(new FileSizeLimitExceededEvent(this, filename));
}
/**
* Interface that must be implemented by the upload receivers to provide the
* Upload component an output stream to write the uploaded data.
@ -502,6 +552,21 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
}
}
public static class FileSizeLimitExceededEvent extends Component.Event {
private String filename;
/**
* @param source the source of the file.
* @param filename the received file name.
*/
public FileSizeLimitExceededEvent(CubaFileUpload source, String filename) {
super(source);
this.filename = filename;
}
}
/**
* FailedEvent that indicates that an output stream could not be obtained.
*/
@ -665,6 +730,11 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
void uploadSucceeded(SucceededEvent event);
}
public interface FileSizeLimitExceededListener extends Serializable {
void fileSizeLimitExceeded(FileSizeLimitExceededEvent e);
}
private static final Method UPLOAD_FINISHED_METHOD;
private static final Method UPLOAD_FAILED_METHOD;
@ -673,16 +743,19 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
private static final Method UPLOAD_STARTED_METHOD;
private static final Method FILESIZE_LIMIT_EXCEEDED_METHOD;
static {
try {
UPLOAD_FINISHED_METHOD = FinishedListener.class.getDeclaredMethod("uploadFinished", FinishedEvent.class);
UPLOAD_FAILED_METHOD = FailedListener.class.getDeclaredMethod("uploadFailed", FailedEvent.class);
UPLOAD_STARTED_METHOD = StartedListener.class.getDeclaredMethod("uploadStarted", StartedEvent.class);
UPLOAD_SUCCEEDED_METHOD = SucceededListener.class.getDeclaredMethod("uploadSucceeded", SucceededEvent.class);
FILESIZE_LIMIT_EXCEEDED_METHOD = FileSizeLimitExceededListener.class.getDeclaredMethod("fileSizeLimitExceeded", FileSizeLimitExceededEvent.class);
} catch (final java.lang.NoSuchMethodException e) {
// This should never happen
throw new java.lang.RuntimeException(
"Internal error finding methods in Upload");
"Internal error finding methods in CubaFileUpload");
}
}
@ -765,4 +838,12 @@ public class CubaFileUpload extends AbstractComponent implements Component.Focus
public void removeSucceededListener(SucceededListener listener) {
removeListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD);
}
public void addFileSizeLimitExceededListener(FileSizeLimitExceededListener listener) {
addListener(FileSizeLimitExceededEvent.class, listener, FILESIZE_LIMIT_EXCEEDED_METHOD);
}
public void removeFileSizeLimitExceededListener(FileSizeLimitExceededListener listener) {
removeListener(FileSizeLimitExceededEvent.class, listener, FILESIZE_LIMIT_EXCEEDED_METHOD);
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (c) 2008-2015 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
package com.haulmont.cuba.web.toolkit.ui.client.fileupload;
import com.vaadin.shared.communication.ServerRpc;
/**
* @author artamonov
* @version $Id$
*/
public interface CubaFileUploadServerRpc extends ServerRpc {
void fileSizeLimitExceeded(String fileName);
}

View File

@ -13,6 +13,7 @@ import com.vaadin.shared.ui.TabIndexState;
* @version $Id$
*/
public class CubaFileUploadState extends TabIndexState {
{
primaryStyleName = "cuba-fileupload";
}
@ -35,4 +36,7 @@ public class CubaFileUploadState extends TabIndexState {
@NoLayout
public String unableToUploadFileMessage;
@NoLayout
public int fileSizeLimit;
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2008-2015 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
// Version: $Id$
@mixin halo-cuba-fileupload($primary-stylename: cuba-fileupload) {
.#{$primary-stylename} {
position: relative;
}
.#{$primary-stylename}:hover .v-button {
&:after {
@if $v-background-color {
$bg: darken($v-background-color, 25%);
@if is-dark-color($v-background-color) {
$bg: lighten($v-background-color, 15%);
}
background-color: rgba($bg, .1);
}
}
}
.#{$primary-stylename} input {
display: block;
cursor: pointer;
position: absolute;
//z-index: -1;
opacity: 0;
text-align: right;
margin: 0;
top: 0;
right: 0;
font-size: 200px;
@include box-defaults;
}
.#{$primary-stylename}.v-has-width .v-button {
width: 100%;
}
.#{$primary-stylename}.v-has-height .v-button {
height: 100%;
}
.#{$primary-stylename}-progresswindow.v-window {
width: 500px;
.content-pane {
outline: 0;
}
.vertical-panel {
width: 100%;
@include box-defaults;
display: inline-block;
}
.v-label.upload-file-label {
font-family: $v-font-family;
font-size: $v-font-size;
line-height: $v-line-height;
}
.v-label.upload-file-label,
.upload-progressbar,
.v-button.upload-cancel-button {
margin-top: $v-layout-margin-top;
}
.upload-cancel-button {
float: right;
}
}
}

View File

@ -33,6 +33,7 @@
@import "components/splitpanel/splitpanel";
@import "components/twincolumn/twincolumn";
@import "components/flowlayout/flowlayout";
@import "components/fileupload/fileupload";
@import "components/pickerfield/pickerfield";
@import "components/contextmenu/contextmenu";
@import "components/maskedfield/maskedfield";
@ -94,6 +95,7 @@
@include halo-cuba-groupbox;
@include halo-cuba-tokenlist;
@include halo-cuba-grouptable;
@include halo-cuba-fileupload;
@include halo-cuba-flowlayout;
@include halo-cuba-fieldgroup;
@include halo-cuba-maskedfield;

View File

@ -7,137 +7,53 @@
@mixin havana-cuba-fileupload($primary-stylename: cuba-fileupload) {
.#{$primary-stylename} {
display: inline-block;
overflow: hidden;
position: relative;
zoom: 1;
text-align: center;
text-decoration: none;
border: $cuba-button-border-color 1px solid;
background: transparent url(../button/images/button.gif) repeat-x;
cursor: pointer;
white-space: nowrap;
margin: 0;
height: 25px;
padding: 0 5px;
color: inherit;
line-height: normal;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
outline: 0;
font-size: 12px;
.#{$primary-stylename}-wrap {
vertical-align: middle;
.#{$primary-stylename}-caption {
font: inherit;
font-size: 12px;
line-height: 18px;
font-family: $cuba-havana-fonts;
vertical-align: middle;
white-space: nowrap;
color: $cuba-button-caption-color;
}
}
overflow: hidden;
}
.#{$primary-stylename}:focus {
outline: none;
border-color: $cuba-button-focuced-border-color;
}
.v-disabled.#{$primary-stylename}:focus {
border-color: $cuba-button-border-color;
}
.#{$primary-stylename}-link:focus {
outline: none;
border: 1px dashed #4d7ab2;
}
.v-disabled.#{$primary-stylename}-link:focus {
border: 1px solid transparent;
}
.#{$primary-stylename}-empty-caption {
.#{$primary-stylename}-caption {
display: none;
}
.#{$primary-stylename}-wrap {
.v-icon {
margin-right: 0;
}
}
}
.#{$primary-stylename}:hover {
.#{$primary-stylename}:hover .v-button {
background: transparent url(../button/images/button-hover.gif) repeat-x;
}
.#{$primary-stylename}:active {
background: transparent url(../button/images/button-pressed.png) repeat-x;
}
.v-disabled.#{$primary-stylename}:hover,
.v-disabled.#{$primary-stylename}:active {
background: transparent url(../button/images/button.gif) repeat-x;
}
.#{$primary-stylename}-link {
border: 1px solid transparent;
text-align: left;
background: transparent;
padding: 0;
height: auto;
.#{$primary-stylename}-wrap {
background: transparent;
height: inherit;
padding: 0;
margin-top: 0;
.#{$primary-stylename}-caption {
text-decoration: underline;
color: $cuba-link-color;
text-align: left;
}
}
}
.v-disabled.#{$primary-stylename}.#{$primary-stylename}-link:hover {
background: transparent;
}
.v-disabled.#{$primary-stylename}.#{$primary-stylename}-link:focus {
outline: none;
border-color: transparent;
}
.#{$primary-stylename}-link:focus {
outline: none;
border: 1px dashed $cuba-link-color;
}
.#{$primary-stylename}-link:hover,
.#{$primary-stylename}-link:active {
background: transparent;
}
.#{$primary-stylename} input {
display: block;
cursor: pointer;
position: absolute;
//z-index: -1;
opacity: 0;
text-align: right;
margin: 0;
top: 0;
right: 0;
font-size: 200px;
@include box-defaults;
}
.#{$primary-stylename}.v-has-width .v-button {
width: 100%;
}
.#{$primary-stylename}.v-has-height .v-button {
height: 100%;
}
.#{$primary-stylename}-progresswindow.v-window {
width: 500px;
.content-pane {
outline: 0;
}
.vertical-panel {
width: 100%;
@include box-defaults;
display: inline-block;
}
.v-label.upload-file-label {
font-family: $cuba-havana-fonts;
font-size: 12px;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*
* Copyright (c) 2008-2015 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
/* global define, require, window, document */
!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):window.jQuery)}(function(e){"use strict";var t=0;e.ajaxTransport("iframe",function(r){if(r.async){var n,a,o,i=r.initialIframeSrc||"javascript:false;";return{send:function(p,m){n=e('<form style="display:none;"></form>'),n.attr("accept-charset",r.formAcceptCharset),o=/\?/.test(r.url)?"&":"?","DELETE"===r.type?(r.url=r.url+o+"_method=DELETE",r.type="POST"):"PUT"===r.type?(r.url=r.url+o+"_method=PUT",r.type="POST"):"PATCH"===r.type&&(r.url=r.url+o+"_method=PATCH",r.type="POST"),t+=1,a=e('<iframe src="'+i+'" name="iframe-transport-'+t+'"></iframe>').bind("load",function(){var t,o=e.isArray(r.paramName)?r.paramName:[r.paramName];a.unbind("load").bind("load",function(){var t;try{if(t=a.contents(),!t.length||!t[0].firstChild)throw new Error}catch(r){t=void 0}m(200,"success",{iframe:t}),e('<iframe src="'+i+'"></iframe>').appendTo(n),window.setTimeout(function(){n.remove()},0)}),n.prop("target",a.prop("name")).prop("action",r.url).prop("method",r.type),r.formData&&e.each(r.formData,function(t,r){e('<input type="hidden"/>').prop("name",r.name).val(r.value).appendTo(n)}),r.fileInput&&r.fileInput.length&&"POST"===r.type&&(t=r.fileInput.clone(),r.fileInput.after(function(e){return t[e]}),r.paramName&&r.fileInput.each(function(t){e(this).prop("name",o[t]||r.paramName)}),n.append(r.fileInput).prop("enctype","multipart/form-data").prop("encoding","multipart/form-data"),r.fileInput.removeAttr("form")),n.submit(),t&&t.length&&r.fileInput.each(function(r,n){var a=e(t[r]);e(n).prop("name",a.prop("name")).attr("form",a.attr("form")),a.replaceWith(n)})}),n.append(a).appendTo(document.body)},abort:function(){a&&a.unbind("load").prop("src",i),n&&n.remove()}}}}),e.ajaxSetup({converters:{"iframe text":function(t){return t&&e(t[0].body).text()},"iframe json":function(t){return t&&e.parseJSON(e(t[0].body).text())},"iframe html":function(t){return t&&e(t[0].body).html()},"iframe xml":function(t){var r=t&&t[0];return r&&e.isXMLDoc(r)?r:e.parseXML(r.XMLDocument&&r.XMLDocument.xml||e(r.body).html())},"iframe script":function(t){return t&&e.globalEval(e(t[0].body).text())}}})});

File diff suppressed because one or more lines are too long