Repository: wicket Updated Branches: refs/heads/WICKET-6517-multipart-ajax dfccba1f9 -> 9ba43c592
WICKET-6517 dep could be multipart too Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/9ba43c59 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/9ba43c59 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/9ba43c59 Branch: refs/heads/WICKET-6517-multipart-ajax Commit: 9ba43c5925358de8be47ef7a93184b4ecf6c0a50 Parents: dfccba1 Author: Sven Meier <svenme...@apache.org> Authored: Wed Jan 17 00:32:29 2018 +0100 Committer: Sven Meier <svenme...@apache.org> Committed: Wed Jan 17 00:32:29 2018 +0100 ---------------------------------------------------------------------- .../wicket/ajax/res/js/wicket-ajax-jquery.js | 49 ++---- .../examples/ajax/builtin/FileUploadPage.html | 10 +- .../examples/ajax/builtin/FileUploadPage.java | 26 ++++ .../markup/html/AjaxFileUploadBehavior.java | 156 +++++++++++++++++++ .../extensions/ajax/markup/html/datatransfer.js | 54 +++++++ 5 files changed, 261 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/9ba43c59/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js index 801a47d..b2ad3a0 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/res/js/wicket-ajax-jquery.js @@ -49,8 +49,7 @@ }; } - var createIFrame, - getAjaxBaseUrl, + var getAjaxBaseUrl, isUndef, replaceAll, htmlToDomDocument, @@ -66,19 +65,6 @@ }; /** - * Creates an iframe that can be used to load data asynchronously or as a - * target for Ajax form submit. - * - * @param iframeName {String} the value of the iframe's name attribute - */ - createIFrame = function (iframeName) { - // WICKET-6340 properly close tag for XHTML markup - var $iframe = jQuery('<iframe name="'+iframeName+'" id="'+iframeName+ - '" src="about:blank" style="position: absolute; top: -9999px; left: -9999px;"></iframe>'); - return $iframe[0]; - }; - - /** * A safe getter for Wicket's Ajax base URL. * If the value is not defined or is empty string then * return '.' (current folder) as base URL. @@ -553,7 +539,7 @@ extraParam = this._asParamArray(extraParam); params = params.concat(extraParam); } - return jQuery.param(params); + return params; }, /** @@ -583,6 +569,8 @@ 'Wicket-Ajax': 'true', 'Wicket-Ajax-BaseURL': getAjaxBaseUrl() }, + + url = attrs.u, // the request (extra) parameters data = this._asParamArray(attrs.ep), @@ -658,6 +646,17 @@ var el = Wicket.$(attrs.c); data = data.concat(Wicket.Form.serializeElement(el, attrs.sr)); } + + // collect the dynamic extra parameters + if (jQuery.isArray(attrs.dep)) { + var dynamicData = this._calculateDynamicParameters(attrs); + if (attrs.m.toLowerCase() === 'post') { + data = data.concat(dynamicData); + } else { + var separator = url.indexOf('?') > -1 ? '&' : '?'; + url = url + separator + jQuery.param(dynamicData); + } + } var wwwFormUrlEncoded = undefined; // default if (attrs.mp) { @@ -676,29 +675,13 @@ // execute the request var jqXHR = jQuery.ajax({ - url: attrs.u, + url: url, type: attrs.m, context: self, processData: wwwFormUrlEncoded, contentType: wwwFormUrlEncoded, beforeSend: function (jqXHR, settings) { - // collect the dynamic extra parameters - if (jQuery.isArray(attrs.dep)) { - var queryString, - separator; - - queryString = this._calculateDynamicParameters(attrs); - if (settings.type.toLowerCase() === 'post') { - separator = settings.data.length > 0 ? '&' : ''; - settings.data = settings.data + separator + queryString; - jqXHR.setRequestHeader("Content-Type", settings.contentType); - } else { - separator = settings.url.indexOf('?') > -1 ? '&' : '?'; - settings.url = settings.url + separator + queryString; - } - } - self._executeHandlers(attrs.bsh, attrs, jqXHR, settings); we.publish(topic.AJAX_CALL_BEFORE_SEND, attrs, jqXHR, settings); http://git-wip-us.apache.org/repos/asf/wicket/blob/9ba43c59/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.html b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.html index 9351d4c..4642ae3 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.html @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="UTF-8" ?> +<html> +<body> <wicket:extend xmlns:wicket="http://wicket.apache.org"> Demonstrates Wicket's ability to transparently handle multipart forms via AJAX.<br/><br/>The only difference between this example and other non-AJAX upload examples is the option to trigger the form submit via an AjaxButton, everything else is handled transparently by Wicket.<br/><br/> @@ -13,4 +15,10 @@ Demonstrates Wicket's ability to transparently handle multipart forms via AJAX.< <input type="submit" value="Regular Submit"/> <input wicket:id="ajaxSubmit" type="button" value="Ajax Submit"/> </form> -</wicket:extend> \ No newline at end of file +<div wicket:id="drop" style="border: 1px dotted black; width:200px; height:200px;"> + Drop file here. +</div> + +</wicket:extend> +</body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/9ba43c59/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.java index e2eda2e..ca6dc70 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/FileUploadPage.java @@ -16,10 +16,14 @@ */ package org.apache.wicket.examples.ajax.builtin; +import java.util.List; + import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.extensions.ajax.markup.html.AjaxFileUploadBehavior; import org.apache.wicket.extensions.ajax.markup.html.form.upload.UploadProgressBar; +import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; @@ -110,5 +114,27 @@ public class FileUploadPage extends BasePage } }); + + WebMarkupContainer drop = new WebMarkupContainer("drop"); + drop.add(new AjaxFileUploadBehavior() { + protected void onFileUpload(AjaxRequestTarget target, List<FileUpload> files) { + + // display uploaded info + if (files == null || files.isEmpty()) + { + info("No file uploaded"); + } + else + { + for (FileUpload file : files) { + info("File-Name: " + file.getClientFileName() + " File-Size: " + + Bytes.bytes(file.getSize()).toString()); + } + } + + target.add(feedback); + } + }); + add(drop); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/9ba43c59/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxFileUploadBehavior.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxFileUploadBehavior.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxFileUploadBehavior.java new file mode 100644 index 0000000..3801c62 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxFileUploadBehavior.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.ajax.markup.html; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; +import org.apache.wicket.ajax.attributes.AjaxRequestAttributes.Method; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.JavaScriptHeaderItem; +import org.apache.wicket.markup.head.OnDomReadyHeaderItem; +import org.apache.wicket.markup.html.form.upload.FileUpload; +import org.apache.wicket.protocol.http.servlet.MultipartServletWebRequest; +import org.apache.wicket.protocol.http.servlet.ServletWebRequest; +import org.apache.wicket.request.resource.PackageResourceReference; +import org.apache.wicket.request.resource.ResourceReference; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.lang.Bytes; + +/** + * Uploads files from a drop event. + * + * @author svenmeier + */ +public class AjaxFileUploadBehavior extends AjaxEventBehavior +{ + + private static final ResourceReference JS = new PackageResourceReference(AjaxFileUploadBehavior.class, "datatransfer.js"); + + /** + * Maximum size of all uploaded files in bytes in a request. + */ + private Bytes maxSize; + + /** + * Maximum size of file of upload in bytes (if there are more than one) in a request. + */ + private Bytes fileMaxSize; + + private String parameterName = "f"; + + public AjaxFileUploadBehavior() + { + super("drop"); + } + + @Override + public void renderHead(Component component, IHeaderResponse response) + { + super.renderHead(component, response); + + response.render(JavaScriptHeaderItem.forReference(JS)); + + // default must be prevented for dragover event, otherwise browser will consume the dataTransfer + response.render(OnDomReadyHeaderItem.forScript(String.format("jQuery('#%s').on('dragover', function(e) { e.preventDefault(); });", component.getMarkupId()))); + } + + @Override + protected void updateAjaxAttributes(AjaxRequestAttributes attributes) + { + super.updateAjaxAttributes(attributes); + + attributes.setMultipart(true); + attributes.setMethod(Method.POST); + // default must be prevented, otherwise browser will consume the dataTransfer + attributes.setPreventDefault(true); + + attributes.getDynamicExtraParameters().add( + String.format("return Wicket.DataTransfer.getFilesAsParamArray(attrs.event.originalEvent, '%s');", parameterName) + ); + } + + @Override + protected void onEvent(AjaxRequestTarget target) + { + try + { + ServletWebRequest request = (ServletWebRequest)getComponent().getRequest(); + final MultipartServletWebRequest multipartWebRequest = request.newMultipartWebRequest( + getMaxSize(), getComponent().getPage().getId()); + multipartWebRequest.setFileMaxSize(getFileMaxSize()); + multipartWebRequest.parseFileParts(); + + // TODO: Can't this be detected from header? + getComponent().getRequestCycle().setRequest(multipartWebRequest); + + ArrayList<FileUpload> fileUploads = new ArrayList<>(); + + // Get the item for the path + final List<FileItem> fileItems = multipartWebRequest.getFile(parameterName); + + if (fileItems != null) + { + for (FileItem item : fileItems) + { + fileUploads.add(new FileUpload(item)); + } + } + + onFileUpload(target, fileUploads); + } + catch (final FileUploadException fux) + { + onError(fux); + } + } + + public Bytes getMaxSize() + { + return maxSize; + } + + public void setMaxSize(Bytes maxSize) + { + Args.notNull(maxSize, "maxSize"); + this.maxSize = maxSize; + } + + public Bytes getFileMaxSize() + { + return fileMaxSize; + } + + public void setFileMaxSize(Bytes fileMaxSize) + { + this.fileMaxSize = fileMaxSize; + } + + protected void onFileUpload(AjaxRequestTarget target, List<FileUpload> files) + { + } + + protected void onError(FileUploadException fux) + { + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/9ba43c59/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/datatransfer.js ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/datatransfer.js b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/datatransfer.js new file mode 100644 index 0000000..05ff68a --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/datatransfer.js @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +;(function (undefined) { + 'use strict'; + + if (typeof(Wicket) === "undefined") { + window.Wicket = {}; + } + + if (Wicket.DataTransfer) { + return; + } + + Wicket.DataTransfer = { + getFilesAsParamArray : function(ev, name) { + var files = []; + + function pushFile(file) { + files.push({'name' : name, 'value' : file}); + }; + + var dataTransfer = ev.dataTransfer; + var i; + if (dataTransfer.items) { + for (i = 0; i < dataTransfer.items.length; i++) { + if (dataTransfer.items[i].kind == 'file') { + pushFile(dataTransfer.items[i].getAsFile()); + } + } + } else { + for (i = 0; i < dataTransfer.files.length; i++) { + pushFile(dataTransfer.files[i]); + } + } + + return files; + } + }; +})();