This is an automated email from the ASF dual-hosted git repository.
reiern70 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/master by this push:
new fd890ccc7c [WICKET-7033] implementation of: 1) an upload field that
allows uploading files into to a mounted resource, 2) a reusable mounted
resource that process uploads and 3) adapting upload progress bar to work in
such use case
fd890ccc7c is described below
commit fd890ccc7c787c192f308e9b4c2a64844954ce86
Author: reiern70 <[email protected]>
AuthorDate: Thu Apr 6 10:20:25 2023 +0300
[WICKET-7033] implementation of: 1) an upload field that allows uploading
files into to a mounted resource, 2) a reusable mounted resource that process
uploads and 3) adapting upload progress bar to work in such use case
---
.../java/org/apache/wicket/ajax/AjaxUtils.java | 55 +++
.../org/apache/wicket/markup/html/form/Form.java | 8 +-
.../resource/AbstractFileUploadResource.java | 292 +++++++++++
.../resource/FileUploadResourceReference.java | 121 +++++
.../upload/resource/FileUploadToResourceField.java | 541 +++++++++++++++++++++
.../upload/resource/FileUploadToResourceField.js | 109 +++++
.../resource/FileUploadToResourceField.properties | 15 +
.../upload/resource/FolderUploadsFileManager.java | 83 ++++
.../form/upload/resource/IUploadsFileManager.java | 52 ++
.../wicket/examples/upload/UploadApplication.java | 19 +
.../apache/wicket/examples/upload/UploadPage.java | 2 +-
.../examples/upload/UploadToResourcePage.html | 44 ++
.../examples/upload/UploadToResourcePage.java | 266 ++++++++++
.../apache/wicket/examples/homepage/HomePage.html | 1 +
.../resources/org/apache/wicket/examples/style.css | 2 +-
.../markup/html/form/upload/UploadProgressBar.java | 73 ++-
.../ajax/markup/html/form/upload/progressbar.js | 50 +-
17 files changed, 1704 insertions(+), 29 deletions(-)
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxUtils.java
b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxUtils.java
new file mode 100644
index 0000000000..7ed0253e1a
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AjaxUtils.java
@@ -0,0 +1,55 @@
+/*
+ * 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.ajax;
+
+import java.util.Optional;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.danekja.java.util.function.serializable.SerializableConsumer;
+
+/**
+ * Some AJAX related utility functions.
+ */
+public class AjaxUtils
+{
+
+ /**
+ * Runs action if current request is of type "AJAX". Otherwise, nothing is
done.
+ *
+ * @param ajaxAction
+ * The action to run a {@link SerializableConsumer}
+ */
+ public static void executeIfAjax(SerializableConsumer<AjaxRequestTarget>
ajaxAction)
+ {
+ Optional<AjaxRequestTarget> target =
RequestCycle.get().find(AjaxRequestTarget.class);
+ target.ifPresent(ajaxAction);
+ }
+
+
+ /**
+ * Runs action if current request is of type "AJAX" or a Websockets
request. Otherwise, nothing is done.
+ *
+ * @param ajaxAction
+ * The action to run a {@link SerializableConsumer}
+ */
+ public static void
executeIfAjaxOrWebSockets(SerializableConsumer<IPartialPageRequestHandler>
ajaxAction)
+ {
+ Optional<IPartialPageRequestHandler> target =
RequestCycle.get().find(IPartialPageRequestHandler.class);
+ target.ifPresent(ajaxAction);
+ }
+
+}
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
index db195086ef..bc245a7f8a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/Form.java
@@ -256,11 +256,11 @@ public class Form<T> extends WebMarkupContainer
private static final long serialVersionUID = 1L;
- private static final String UPLOAD_FAILED_RESOURCE_KEY = "uploadFailed";
+ public static final String UPLOAD_FAILED_RESOURCE_KEY = "uploadFailed";
- private static final String UPLOAD_TOO_LARGE_RESOURCE_KEY =
"uploadTooLarge";
- private static final String UPLOAD_SINGLE_FILE_TOO_LARGE_RESOURCE_KEY =
"uploadSingleFileTooLarge";
- private static final String UPLOAD_TOO_MANY_FILES_RESOURCE_KEY =
"uploadTooManyFiles";
+ public static final String UPLOAD_TOO_LARGE_RESOURCE_KEY =
"uploadTooLarge";
+ public static final String UPLOAD_SINGLE_FILE_TOO_LARGE_RESOURCE_KEY =
"uploadSingleFileTooLarge";
+ public static final String UPLOAD_TOO_MANY_FILES_RESOURCE_KEY =
"uploadTooManyFiles";
/**
* Any default IFormSubmittingComponent. If set, a hidden submit
component will be rendered
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
new file mode 100644
index 0000000000..b00d7895c2
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/AbstractFileUploadResource.java
@@ -0,0 +1,292 @@
+/*
+ * 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.markup.html.form.upload.resource;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.fileupload2.FileItem;
+import org.apache.commons.fileupload2.FileUploadException;
+import org.apache.commons.fileupload2.pub.FileUploadByteCountLimitException;
+import org.apache.commons.fileupload2.pub.FileUploadFileCountLimitException;
+import org.apache.wicket.Application;
+import org.apache.wicket.markup.html.form.Form;
+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.cycle.RequestCycle;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.util.lang.Bytes;
+import org.apache.wicket.util.string.StringValueConversionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.github.openjson.JSONObject;
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * The resource that handles the file uploads.
+ * Reads the file items from the request parameters and uses {@link
IUploadsFileManager}
+ * to store them.
+ * Additionally, cares about the response's content type and body.
+ * <p>
+ * This code was adapted from
+ * <p>
+ * <a
href="https://github.com/martin-g/blogs/blob/master/file-upload/src/main/java/com/mycompany/fileupload/AbstractFileUploadResource.java">AbstractFileUploadResource.java</a>
+ * <p>
+ * The main difference is that there some JQuery plugin is used at client side
(and it supports multiple uploads +
+ * some UI allowing to delete/preview files and so on).
+ * Here we are just using plain jQuery code at client side to upload a single
file.
+ */
+public abstract class AbstractFileUploadResource extends AbstractResource
+{
+ private static final Logger LOG =
LoggerFactory.getLogger(AbstractFileUploadResource.class);
+
+ public static final String PARAM_NAME = "WICKET-FILE-UPLOAD";
+
+ /**
+ * This resource is usually an application singleton. Thus, client side
pass
+ * to the resource a unique ID identifying the upload field performing
the upload.
+ * The upload file makes sure this is a unique identifier at
application level, See
+ * {@link
FileUploadToResourceField#generateAUniqueApplicationWiseId()}. So that, there
are no clashes between
+ * different users/pages/sessions performing an upload.
+ */
+ public static final String UPLOAD_ID = "uploadId";
+ /**
+ * i18n key for case no files were selected.
+ */
+ public static final String NO_FILE_SELECTED =
"wicket.no.files.selected";
+
+ private final IUploadsFileManager fileManager;
+
+ public AbstractFileUploadResource(IUploadsFileManager fileManager)
+ {
+ this.fileManager = fileManager;
+ }
+
+ /**
+ * Reads and stores the uploaded files
+ *
+ * @param attributes
+ * Attributes
+ * @return ResourceResponse
+ */
+ @Override
+ protected ResourceResponse newResourceResponse(Attributes attributes)
+ {
+ final ResourceResponse resourceResponse = new
ResourceResponse();
+
+ final ServletWebRequest webRequest = (ServletWebRequest)
attributes.getRequest();
+
+ // get the ID of the upload field (it should be unique per
application)
+ String uploadId =
webRequest.getRequestParameters().getParameterValue(UPLOAD_ID).toString("resource");
+
+ Bytes maxSize = getMaxSize(webRequest);
+ Bytes fileMaxSize = getFileMaxSize(webRequest);
+ long fileCountMax = getFileCountMax(webRequest);
+ try
+ {
+ MultipartServletWebRequest multiPartRequest =
webRequest.newMultipartWebRequest(maxSize, uploadId);
+ multiPartRequest.setFileMaxSize(fileMaxSize);
+ multiPartRequest.setFileCountMax(fileCountMax);
+ multiPartRequest.parseFileParts();
+
+ RequestCycle.get().setRequest(multiPartRequest);
+
+ // retrieve the files.
+ Map<String, List<FileItem>> files =
multiPartRequest.getFiles();
+ List<FileItem> fileItems = files.get(PARAM_NAME);
+
+ if (fileItems != null)
+ {
+ List<FileUpload> fileUploads = new
ArrayList<>();
+ for (FileItem fileItem : fileItems)
+ {
+ fileUploads.add(new
FileUpload(fileItem));
+ }
+ saveFiles(fileUploads, uploadId);
+ prepareResponse(resourceResponse, webRequest,
fileUploads);
+ }
+ else
+ {
+
resourceResponse.setContentType("application/json");
+ resourceResponse.setWriteCallback(new
WriteCallback()
+ {
+ @Override
+ public void writeData(Attributes
attributes) throws IOException
+ {
+ JSONObject json = new
JSONObject();
+ json.put("error", true);
+ json.put("errorMessage",
NO_FILE_SELECTED);
+ String error = json.toString();
+
attributes.getResponse().write(error);
+ }
+ });
+ }
+ return resourceResponse;
+
+ }
+ catch (FileUploadException fux)
+ {
+ resourceResponse.setContentType("application/json");
+
resourceResponse.setStatusCode(HttpServletResponse.SC_OK);
+ JSONObject json = new JSONObject();
+ json.put("error", true);
+ String errorMessage = getFileUploadExceptionKey(fux);
+ json.put("errorMessage", errorMessage);
+ String error = json.toString();
+ resourceResponse.setWriteCallback(new WriteCallback()
+ {
+ @Override
+ public void writeData(Attributes attributes)
throws IOException
+ {
+ attributes.getResponse().write(error);
+ }
+ });
+ return resourceResponse;
+ }
+ catch (Exception fux)
+ {
+ resourceResponse.setContentType("application/json");
+ JSONObject json = new JSONObject();
+ json.put("error", true);
+ String errorMessage = LOG.isDebugEnabled() ?
fux.getMessage() : Form.UPLOAD_FAILED_RESOURCE_KEY;
+ json.put("errorMessage", errorMessage);
+ String error = json.toString();
+ resourceResponse.setWriteCallback(new WriteCallback()
+ {
+ @Override
+ public void writeData(Attributes attributes)
throws IOException
+ {
+ attributes.getResponse().write(error);
+ }
+ });
+ }
+
+ return resourceResponse;
+ }
+
+
+ protected String getFileUploadExceptionKey(final FileUploadException e)
+ {
+ if (e instanceof FileUploadByteCountLimitException)
+ {
+ return Form.UPLOAD_TOO_LARGE_RESOURCE_KEY;
+ }
+ else if (e instanceof FileUploadFileCountLimitException)
+ {
+ return Form.UPLOAD_TOO_MANY_FILES_RESOURCE_KEY;
+ }
+ else
+ {
+ return Form.UPLOAD_FAILED_RESOURCE_KEY;
+ }
+ }
+
+ /**
+ * Sets the response's content type and body
+ *
+ * @param resourceResponse
+ * ResourceResponse
+ * @param webRequest
+ * ServletWebRequest
+ * @param fileItems
+ * List<FileUpload>
+ */
+ protected void prepareResponse(ResourceResponse resourceResponse,
ServletWebRequest webRequest, List<FileUpload> fileItems)
+ {
+ resourceResponse.setContentType("application/json");
+ final String responseContent =
generateJsonResponse(resourceResponse, webRequest, fileItems);
+
+ resourceResponse.setWriteCallback(new WriteCallback()
+ {
+ @Override
+ public void writeData(Attributes attributes) throws
IOException
+ {
+ attributes.getResponse().write(responseContent);
+ }
+ });
+ }
+
+ /**
+ * Delegates to FileManager to store the uploaded files
+ *
+ * @param fileItems
+ * List<FileUpload>
+ */
+ protected void saveFiles(List<FileUpload> fileItems, String uploadId)
+ {
+ for (FileUpload fileItem : fileItems)
+ {
+ fileManager.save(fileItem, uploadId);
+ }
+ }
+
+ /**
+ * Defines what is the maximum (total) size of the uploaded files.
+ *
+ * @return Bytes
+ */
+ private Bytes getMaxSize(ServletWebRequest webRequest)
+ {
+ try
+ {
+ return
Bytes.bytes(webRequest.getRequestParameters().getParameterValue("maxSize").toLong());
+ }
+ catch (StringValueConversionException e)
+ {
+ return
Application.get().getApplicationSettings().getDefaultMaximumUploadSize();
+ }
+
+ }
+
+ /**
+ * Defines what is the maximum size of an uploaded file.
+ *
+ * @return Bytes
+ */
+ private Bytes getFileMaxSize(ServletWebRequest webRequest)
+ {
+ long fileMaxSize =
webRequest.getRequestParameters().getParameterValue("fileMaxSize").toLong(-1);
+ return fileMaxSize > 0 ? Bytes.bytes(fileMaxSize) : null;
+ }
+
+ /**
+ * Defines what is the maximum size of an uploaded file.
+ *
+ * @return Bytes
+ */
+ private long getFileCountMax(ServletWebRequest webRequest)
+ {
+ return
webRequest.getRequestParameters().getParameterValue("fileCountMax").toLong(-1);
+ }
+
+ /**
+ * Should generate the response's body in JSON format
+ *
+ * @param resourceResponse
+ * ResourceResponse
+ * @param webRequest
+ * ServletWebRequest
+ * @param files
+ * List<FileUpload>
+ * @return The generated JSON
+ */
+ protected abstract String generateJsonResponse(ResourceResponse
resourceResponse,
+ ServletWebRequest webRequest, List<FileUpload> files);
+
+}
\ No newline at end of file
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
new file mode 100644
index 0000000000..b57644503c
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadResourceReference.java
@@ -0,0 +1,121 @@
+/*
+ * 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.markup.html.form.upload.resource;
+
+import java.util.List;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.protocol.http.servlet.ServletWebRequest;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.util.lang.Args;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONException;
+import com.github.openjson.JSONObject;
+
+/**
+ * A resource reference that provides default implementation of
AbstractFileUploadResource.
+ * The implementation generates JSON response with data from the upload (this
data is
+ * re-routed to the page for things like getting the client file name and file
size).
+ */
+public class FileUploadResourceReference extends ResourceReference
+{
+
+ private final IUploadsFileManager uploadFileManager;
+
+ private static FileUploadResourceReference instance;
+
+ /**
+ * This method assumes {@link #createNewInstance(IUploadsFileManager)}
was called before
+ *
+ * @return FileUploadResourceReference
+ */
+ public static FileUploadResourceReference getInstance()
+ {
+ if (instance == null)
+ {
+ throw new IllegalStateException("An instance should be
created via the createNewInstance method");
+ }
+ return instance;
+ }
+
+ /**
+ * Use this method in order to create an instance to be mounted at
application level.
+ *
+ * @param fileManager The {@link IUploadsFileManager}
+ * @return FileUploadResourceReference
+ */
+ public static FileUploadResourceReference
createNewInstance(IUploadsFileManager fileManager)
+ {
+ if (instance == null)
+ {
+ instance = new FileUploadResourceReference(fileManager);
+ }
+ return instance;
+ }
+
+ protected FileUploadResourceReference(IUploadsFileManager
uploadFileManager)
+ {
+ super(FileUploadResourceReference.class, "file-uploads");
+
+ Args.notNull(uploadFileManager, "uploadFileManager");
+
+ this.uploadFileManager = uploadFileManager;
+ }
+
+ @Override
+ public IResource getResource()
+ {
+ return new AbstractFileUploadResource(uploadFileManager)
+ {
+
+ @Override
+ protected String generateJsonResponse(ResourceResponse
resourceResponse, ServletWebRequest webRequest, List<FileUpload> files)
+ {
+ JSONArray json = new JSONArray();
+
+ for (FileUpload fileItem : files)
+ {
+ JSONObject fileJson = new JSONObject();
+
+ try
+ {
+ generateFileInfo(fileJson,
fileItem);
+ json.put(fileJson);
+ }
+ catch (JSONException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ return json.toString();
+ }
+
+ };
+ }
+
+ public IUploadsFileManager getUploadFileManager() {
+ return uploadFileManager;
+ }
+
+ protected void generateFileInfo(JSONObject fileJson, FileUpload
fileItem)
+ {
+ fileJson.put("clientFileName", fileItem.getClientFileName());
+ fileJson.put("size", fileItem.getSize());
+ fileJson.put("contentType", fileItem.getContentType());
+ }
+
+}
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java
new file mode 100644
index 0000000000..fbff4d91e0
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.java
@@ -0,0 +1,541 @@
+/*
+ * 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.markup.html.form.upload.resource;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import org.apache.commons.io.IOUtils;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.AjaxUtils;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+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.markup.html.form.upload.FileUploadField;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+import org.apache.wicket.resource.CoreLibrariesContributor;
+import org.apache.wicket.util.lang.Bytes;
+import org.apache.wicket.util.string.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.github.openjson.JSONArray;
+import com.github.openjson.JSONObject;
+
+/**
+ * Implementation of FileUploadField capable to uploading a file into a wicket
mounted resource.
+ * This field does not require a {@link
org.apache.wicket.markup.html.form.Form}!
+ * The upload of the file id done via the {@link
#startUpload(IPartialPageRequestHandler)} method.
+ */
+public abstract class FileUploadToResourceField extends FileUploadField
+{
+ private static final Logger LOGGER =
LoggerFactory.getLogger(FileUploadToResourceField.class);
+
+ /**
+ * Info regarding an upload.
+ */
+ public static final class UploadInfo
+ {
+ private File file;
+ private final String clientFileName;
+
+ private final long size;
+
+ private final String contentType;
+
+ public UploadInfo(String clientFileName, long size, String contentType)
+ {
+ this.clientFileName = clientFileName;
+ this.size = size;
+ this.contentType = contentType;
+ }
+
+ public File getFile()
+ {
+ return file;
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ public String getClientFileName()
+ {
+ return clientFileName;
+ }
+
+ public long getSize()
+ {
+ return size;
+ }
+
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ UploadInfo fileInfo = (UploadInfo) o;
+ return Objects.equals(clientFileName, fileInfo.clientFileName);
+ }
+
+ /**
+ * @return the bytes associated with the upload. Return null in case
no file is present
+ * or some other error condition happens.
+ */
+ public byte[] get()
+ {
+ if (file == null)
+ {
+ return null;
+ }
+
+ byte[] fileData = new byte[(int) getSize()];
+ InputStream fis = null;
+
+ try
+ {
+ fis = new FileInputStream(file);
+ IOUtils.readFully(fis, fileData);
+ }
+ catch (IOException e)
+ {
+ LOGGER.debug("IOException at get", e);
+ fileData = null;
+ }
+ finally
+ {
+ IOUtils.closeQuietly(fis);
+ }
+
+ return fileData;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(clientFileName);
+ }
+
+ public static List<UploadInfo> fromJson(String json)
+ {
+ List<UploadInfo> infos = new ArrayList<>();
+ JSONArray jsonArray = new JSONArray(json);
+ for (int i = 0; i < jsonArray.length(); i++)
+ {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ infos.add(new
UploadInfo(jsonObject.getString("clientFileName"), jsonObject.getLong("size"),
jsonObject.getString("contentType")));
+ }
+ return infos;
+ }
+ }
+
+ private static final JavaScriptResourceReference JS = new
JavaScriptResourceReference(FileUploadToResourceField.class,
"FileUploadToResourceField.js");
+
+ public static String UPLOAD_CANCELED = "upload.canceled";
+
+
+ private static abstract class FileModel implements IModel<List<UploadInfo>>
+ {
+
+ @Override
+ public List<UploadInfo> getObject()
+ {
+ List<UploadInfo> fileInfos = getFileUploadInfos();
+ for (UploadInfo uploadInfo : fileInfos)
+ {
+ // at this point files were stored at the server side by
resource
+ // UploadFieldId acts as a discriminator at application level
+ // so that uploaded files are isolated.
+ uploadInfo.setFile(fileManager().getFile(getUploadFieldId(),
uploadInfo.clientFileName));
+ }
+ return fileInfos;
+ }
+
+ @Override
+ public void setObject(List<UploadInfo> object)
+ {
+ throw new UnsupportedOperationException("setObject not supported");
+ }
+
+ protected abstract IUploadsFileManager fileManager();
+
+ /*
+ This is an application unique ID assigned to upload field.
+ */
+ protected abstract String getUploadFieldId();
+
+ protected abstract List<UploadInfo> getFileUploadInfos();
+ }
+
+ private final AbstractDefaultAjaxBehavior ajaxBehavior;
+
+ private transient List<UploadInfo> fileUploadInfos;
+
+ /**
+ * Maximum size of file of upload in bytes (if there are more than one) in
request.
+ */
+ private Bytes fileMaxSize;
+
+ /**
+ * Maximum amount of files in request.
+ * A value of -1 indicates no maximum.
+ */
+ private long fileCountMax = -1L;
+
+ /**
+ * Maximum size of an upload in bytes. If null, the setting
+ * {@link
org.apache.wicket.settings.ApplicationSettings#getDefaultMaximumUploadSize()}
is used.
+ */
+ private Bytes maxSize = null;
+
+ public FileUploadToResourceField(String id)
+ {
+ super(id);
+ setOutputMarkupId(true);
+ // generate a unique ID
+ setMarkupId(generateAUniqueApplicationWiseId());
+ setDefaultModel(new FileModel() {
+ @Override
+ protected IUploadsFileManager fileManager() {
+ return FileUploadToResourceField.this.fileManager();
+ }
+
+ @Override
+ protected String getUploadFieldId()
+ {
+ return FileUploadToResourceField.this.getMarkupId();
+ }
+
+ @Override
+ protected List<UploadInfo> getFileUploadInfos()
+ {
+ return fileUploadInfos;
+ }
+ });
+ ajaxBehavior = new AbstractDefaultAjaxBehavior()
+ {
+ @Override
+ protected void respond(AjaxRequestTarget target)
+ {
+ Request request = RequestCycle.get().getRequest();
+ boolean error =
request.getRequestParameters().getParameterValue("error").toBoolean(true);
+ if (!error) {
+ String filesIfo =
request.getRequestParameters().getParameterValue("filesInfo").toString();
+ fileUploadInfos = UploadInfo.fromJson(filesIfo);
+ onUploadSuccess(target, getFileUploadInfos());
+ }
+ else
+ {
+ String errorMessage =
request.getRequestParameters().getParameterValue("errorMessage").toString(null);
+ if (UPLOAD_CANCELED.equals(errorMessage))
+ {
+ onUploadCanceled(target);
+ }
+ else
+ {
+ if
(AbstractFileUploadResource.NO_FILE_SELECTED.equals(errorMessage))
+ {
+ errorMessage =
getString(AbstractFileUploadResource.NO_FILE_SELECTED);
+ }
+ else
+ {
+ final Map<String, Object> model = new HashMap<>();
+ if (Strings.isEmpty(errorMessage)) {
+ errorMessage = "uploadTooLarge";
+ }
+ model.put("exception", errorMessage);
+ model.put("maxSize", getMaxSize());
+ model.put("fileMaxSize", getFileMaxSize());
+ model.put("fileCountMax", getFileCountMax());
+ errorMessage = getString(errorMessage,
Model.ofMap(model));
+ }
+ error(errorMessage);
+ onUploadFailure(target, errorMessage);
+ }
+ }
+ }
+ };
+ add(ajaxBehavior);
+ }
+
+ private List<UploadInfo> getFileUploadInfos()
+ {
+ // mind that this makes files to be added.
+ return (List<UploadInfo>)getDefaultModel().getObject();
+ }
+
+ @Override
+ public FileUpload getFileUpload()
+ {
+ throw new UnsupportedOperationException("FileUploadToResourceField
does not support working with FileUpload");
+ }
+
+ @Override
+ public List<FileUpload> getFileUploads()
+ {
+ throw new UnsupportedOperationException("FileUploadToResourceField
does not support working with FileUpload");
+ }
+
+ @Override
+ protected void onRemove()
+ {
+ super.onRemove();
+ // we clean any client side mess if component is removed via "partial"
page replacement
+ AjaxUtils.executeIfAjaxOrWebSockets(target ->
target.appendJavaScript("delete Wicket.Timer." + getMarkupId() + ";"));
+
+ }
+
+ /**
+ * Override to do something on a successful upload.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param fileInfos The List<FileInfo
+ */
+ protected abstract void onUploadSuccess(AjaxRequestTarget target,
List<UploadInfo> fileInfos);
+
+
+ /**
+ * Override to do something on a non successful upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ * @param errorInfo The cause of the failure
+ */
+ protected void onUploadFailure(AjaxRequestTarget target, String errorInfo)
+ {
+ // nothing by default
+ }
+
+ /**
+ * Override to do something in case user canceled upload
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ protected void onUploadCanceled(AjaxRequestTarget target)
+ {
+ // nothing by default
+ }
+
+ /**
+ * @return a unique application wise ID (it should be a valid HTML id).
+ */
+ protected String generateAUniqueApplicationWiseId()
+ {
+ return "WRFUF_" + UUID.randomUUID().toString().replace("-", "_");
+ }
+
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ CoreLibrariesContributor.contributeAjax(getApplication(), response);
+ response.render(JavaScriptHeaderItem.forReference(JS));
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("inputName", getMarkupId());
+ jsonObject.put("resourceUrl", urlFor(getFileUploadResourceReference(),
new PageParameters()).toString());
+ jsonObject.put("ajaxCallBackUrl", ajaxBehavior.getCallbackUrl());
+ jsonObject.put("maxSize", getMaxSize().bytes());
+ Bytes fileMaxSize = getFileMaxSize();
+ if (fileMaxSize != null)
+ {
+ jsonObject.put("fileMaxSize", fileMaxSize.bytes());
+ }
+ jsonObject.put("fileCountMax", getFileCountMax());
+ response.render(OnDomReadyHeaderItem.forScript("Wicket.Timer."
+ + getMarkupId() + " = new Wicket.FileUploadToResourceField("
+ + jsonObject + ","
+ + getClientBeforeSendCallBack() + ","
+ + getClientSideSuccessCallBack() + ","
+ + getClientSideCancelCallBack() + ","
+ + getClientSideUploadErrorCallBack() + ");"));
+ }
+
+ /**
+ * Sets maximum size of each file in upload request.
+ *
+ * @param fileMaxSize
+ */
+ public void setFileMaxSize(Bytes fileMaxSize)
+ {
+ this.fileMaxSize = fileMaxSize;
+ }
+
+ /**
+ * Sets maximum amount of files in upload request.
+ *
+ * @param fileCountMax
+ */
+ public void setFileCountMax(long fileCountMax)
+ {
+ this.fileCountMax = fileCountMax;
+ }
+
+ /**
+ * Sets the maximum size for uploads. If null, the setting
+ * {@link
org.apache.wicket.settings.ApplicationSettings#getDefaultMaximumUploadSize()}
is used.
+ *
+ * @param maxSize
+ * The maximum size
+ */
+ public void setMaxSize(final Bytes maxSize)
+ {
+ this.maxSize = maxSize;
+ }
+
+
+ /**
+ * Gets the maximum size for uploads. If null, the setting
+ * {@link
org.apache.wicket.settings.ApplicationSettings#getDefaultMaximumUploadSize()}
is used.
+ *
+ * @return the maximum size
+ */
+ public final Bytes getMaxSize()
+ {
+ if (maxSize == null)
+ {
+ return
getApplication().getApplicationSettings().getDefaultMaximumUploadSize();
+ }
+ return maxSize;
+ }
+
+ /**
+ *
+ * @return Gets maximum size for each file of an upload.
+ */
+ public Bytes getFileMaxSize()
+ {
+ return fileMaxSize;
+ }
+
+ /**
+ *
+ *
+ * @return Gets maximum count of files in the form
+ */
+ public long getFileCountMax()
+ {
+ return fileCountMax;
+ }
+
+ /**
+ * Override if you need to return a different instance of
FileUploadResourceReference
+ * @return FileUploadResourceReference
+ */
+ protected FileUploadResourceReference getFileUploadResourceReference()
+ {
+ return FileUploadResourceReference.getInstance();
+ }
+
+ /**
+ * @return The JavaScript expression starting the upload.
+ */
+ public String getTriggerUploadScript()
+ {
+ return "Wicket.Timer." + getMarkupId() + ".upload();";
+ }
+
+ /**
+ * Starts the upload via an AJAX request.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ public void startUpload(IPartialPageRequestHandler target)
+ {
+ target.appendJavaScript(getTriggerUploadScript());
+ }
+
+ /**
+ * @return The JavaScript expression canceling the upload.
+ */
+ public String getTriggerCancelUploadScript()
+ {
+ return "Wicket.Timer." + getMarkupId() + ".cancel();";
+ }
+ /**
+ * Cancels the upload via an AJAX request.
+ *
+ * @param target The {@link AjaxRequestTarget}
+ */
+ public void cancelUpload(IPartialPageRequestHandler target)
+ {
+ target.appendJavaScript(getTriggerCancelUploadScript());
+ }
+
+ /**
+ * See jQuery.ajax documentation.
+ *
+ * @return A JavaScript function to be executed on beforeSend the upload
request.
+ */
+ protected CharSequence getClientBeforeSendCallBack()
+ {
+ return "function (xhr, settings) { return true; }";
+ }
+
+ /**
+ * @return A JavaScript function to be executed on successful upload. This
is, besides the normal wicket
+ * AJAX request (see {@link #onUploadSuccess(AjaxRequestTarget, List)}).
+ */
+ protected CharSequence getClientSideSuccessCallBack()
+ {
+ return "function () {}";
+ }
+
+ /**
+ * @return A JavaScript function to be executed on upload canceled. This
is, besides the normal wicket
+ * AJAX request (see {@link #onUploadFailure(AjaxRequestTarget, String)}).
+ */
+ protected CharSequence getClientSideCancelCallBack()
+ {
+ return "function () {}";
+ }
+
+ /**
+ * @return A JavaScript function to be executed on upload canceled. This
is, besides the normal wicket
+ * AJAX request (see {@link #onUploadFailure(AjaxRequestTarget, String)}).
It receives as parameter a JSON object
+ * like <code>{'error': true, errorMessage: 'xxx'}</code>.
+ */
+ protected CharSequence getClientSideUploadErrorCallBack()
+ {
+ return "function (res) {}";
+ }
+
+ /**
+ * @return The IUploadsFileManager
+ */
+ protected IUploadsFileManager fileManager()
+ {
+ return getFileUploadResourceReference().getUploadFileManager();
+ }
+}
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js
new file mode 100644
index 0000000000..815e66912f
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.js
@@ -0,0 +1,109 @@
+/*
+ * 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.FileUploadToResourceField) === 'object') {
+ return;
+ }
+
+ Wicket.FileUploadToResourceField = function (settings,
clientBeforeSendCallBack, clientSideSuccessCallBack, clientSideCancelCallBack,
uploadErrorCallBack)
+ {
+ this.settings = settings;
+ this.inputName = settings.inputName;
+ this.input = document.getElementById(this.inputName);
+ this.resourceUrl = settings.resourceUrl + "?uploadId=" +
this.inputName + "&maxSize=" + this.settings.maxSize;
+ if (this.settings.fileMaxSize != null) {
+ this.resourceUrl = this.resourceUrl + "&fileMaxSize=" +
this.settings.fileMaxSize;
+ }
+ if (this.settings.fileCountMax != null) {
+ this.resourceUrl = this.resourceUrl + "&fileCountMax=" +
this.settings.fileCountMax;
+ }
+ this.ajaxCallBackUrl = settings.ajaxCallBackUrl;
+ this.clientBeforeSendCallBack = clientBeforeSendCallBack;
+ this.clientSideSuccessCallBack = clientSideSuccessCallBack;
+ this.clientSideCancelCallBack = clientSideCancelCallBack;
+ this.uploadErrorCallBack = uploadErrorCallBack;
+ }
+
+ Wicket.FileUploadToResourceField.prototype.upload = function()
+ {
+ // get a fresh reference to input
+ this.input = document.getElementById(this.inputName);
+ // we add the files to a FormData object.
+ var formData = new FormData();
+ var totalfiles = this.input.files.length;
+ for (var index = 0; index < totalfiles; index++) {
+ formData.append("WICKET-FILE-UPLOAD",this.input.files[index]);
+ }
+ var self = this;
+ // we use jQuery to post the files to the resource (this.resourceUrl)
+ // and we keep a reference to the request in order to be able
+ // to cancel the upload
+ this.xhr = $.ajax({
+ url: this.resourceUrl,
+ type: "POST",
+ data: formData,
+ processData: false,
+ contentType: false,
+ success: function (res) {
+ // do clean up on success
+ if (res.error) {
+ self.uploadErrorCallBack(res);
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": res});
+ } else {
+ self.clientSideSuccessCallBack();
+ var ep = {'error': false, 'filesInfo':
JSON.stringify(res)};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ }
+ },
+ beforeSend: function (xhr) {
+ self.clientBeforeSendCallBack(xhr);
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ if (textStatus === "abort") {
+ // user aborted the upload.
+ var ep = {'error': true, 'errorMessage':
'upload.canceled'};
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ } else if (textStatus === "error"){
+ var ep = {'error': true, "errorMessage": errorThrown};
+ self.uploadErrorCallBack(ep);
+ Wicket.Ajax.get({"u": self.ajaxCallBackUrl, "ep": ep});
+ } else if (textStatus === "parsererror"){
+ // this error will only happen is generated JSON at server
side is faulty
+ var data = jqXHR.responseText;
+ Wicket.Log.log(data);
+ }
+ }
+ });
+ }
+
+ // cancel the upload
+ Wicket.FileUploadToResourceField.prototype.cancel = function () {
+ // we have a reference to the request we can cancel it.
+ if (this.xhr) {
+ this.xhr.abort();
+ this.clientSideCancelCallBack();
+ Wicket.Log.log("The upload associated with field '" +
this.inputName + "' has been canceled!");
+ delete (this.xhr);
+ } else {
+ Wicket.Log.log("Too late to cancel upload for field '" +
this.inputName + "': the upload has already finished.");
+ }
+ }
+})();
\ No newline at end of file
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.properties
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.properties
new file mode 100644
index 0000000000..5c115a887c
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FileUploadToResourceField.properties
@@ -0,0 +1,15 @@
+# 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.
+wicket.no.files.selected = Nothing to upload: no files were selected.
\ No newline at end of file
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FolderUploadsFileManager.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FolderUploadsFileManager.java
new file mode 100644
index 0000000000..0146b82099
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/FolderUploadsFileManager.java
@@ -0,0 +1,83 @@
+/*
+ * 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.markup.html.form.upload.resource;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.util.file.File;
+import org.apache.wicket.util.io.IOUtils;
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * Implementation of {@link IUploadsFileManager} that stores files in
sub-folders of a given folder.
+ * Sub-folders are named using the input field ID (and those are unique per
application). Thus, there
+ * is no possibility that uploads get mixed up.
+ */
+public class FolderUploadsFileManager implements IUploadsFileManager
+{
+
+ private final File folder;
+
+ public FolderUploadsFileManager(File folder)
+ {
+ Args.notNull(folder, "folder");
+ if (!folder.exists())
+ {
+ try
+ {
+ Files.createDirectories(folder.toPath());
+ }
+ catch (IOException e)
+ {
+ throw new WicketRuntimeException(e);
+ }
+ }
+ else if (folder.exists() && !folder.isDirectory())
+ {
+ throw new IllegalArgumentException("Not a folder : " +
folder.getAbsolutePath());
+ }
+ this.folder = folder;
+ }
+
+ public File getFolder() {
+ return folder;
+ }
+
+ @Override
+ public void save(FileUpload fileItem, String uploadFieldId)
+ {
+ File uploadFieldFolder = new File(getFolder(), uploadFieldId);
+ uploadFieldFolder.mkdirs();
+ try
+ {
+ IOUtils.copy(fileItem.getInputStream(), new FileOutputStream(new
File(uploadFieldFolder, fileItem.getClientFileName())));
+ }
+ catch (IOException e)
+ {
+ throw new WicketRuntimeException(e);
+ }
+ }
+
+ @Override
+ public File getFile(String uploadFieldId, String clientFileName)
+ {
+ return new File(new File(getFolder(), uploadFieldId), clientFileName);
+ }
+}
diff --git
a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
new file mode 100644
index 0000000000..78a1208503
--- /dev/null
+++
b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/upload/resource/IUploadsFileManager.java
@@ -0,0 +1,52 @@
+/*
+ * 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.markup.html.form.upload.resource;
+
+import org.apache.wicket.markup.html.form.upload.FileUpload;
+import org.apache.wicket.util.file.File;
+
+/**
+ * This interface defines the bridge between a file uploaded to a resource and
the wicket component.
+ * Wicket component uses some identifier (passed as a request parameter) to
instruct the resource
+ * how to store file. Same identifier is used to retrieve the file, once
uploaded, from component in page.
+ * Mind that uploader resource is a singleton => identifier needs to be unique
among different sessions
+ * (and pages in a session).
+ */
+public interface IUploadsFileManager
+{
+
+ /**
+ * Saves an uploaded files into some persistent storage (e,g, disk).
+ *
+ * @param fileItem
+ * The {@link FileUpload}
+ * @param uploadFieldId
+ * The unique ID of the upload field.
+ */
+ void save(FileUpload fileItem, String uploadFieldId);
+
+ /**
+ * Retrieves the file based on an uploadFieldId and clientFileName.
+ *
+ * @param uploadFieldId
+ * The unique ID of the upload field.
+ * @param clientFileName
+ * The client file name
+ * @return File the file
+ */
+ File getFile(String uploadFieldId, String clientFileName);
+}
diff --git
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadApplication.java
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadApplication.java
index 0826393842..281e9e3fe9 100644
---
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadApplication.java
+++
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadApplication.java
@@ -18,7 +18,11 @@ package org.apache.wicket.examples.upload;
import org.apache.wicket.Page;
import org.apache.wicket.examples.WicketExampleApplication;
+import
org.apache.wicket.markup.html.form.upload.resource.FileUploadResourceReference;
+import
org.apache.wicket.markup.html.form.upload.resource.FolderUploadsFileManager;
+import org.apache.wicket.markup.html.form.upload.resource.IUploadsFileManager;
import org.apache.wicket.util.file.Folder;
+import org.apache.wicket.util.lang.Bytes;
/**
@@ -30,6 +34,8 @@ public class UploadApplication extends
WicketExampleApplication
{
private Folder uploadFolder = null;
+ private IUploadsFileManager uploadsFileManager;
+
@Override
public Class<? extends Page> getHomePage()
{
@@ -55,9 +61,22 @@ public class UploadApplication extends
WicketExampleApplication
// Ensure folder exists
uploadFolder.mkdirs();
+ uploadsFileManager = new FolderUploadsFileManager(uploadFolder);
+
+ mountResource("/uploads",
FileUploadResourceReference.createNewInstance(uploadsFileManager));
+
mountPage("/multi", MultiUploadPage.class);
mountPage("/single", UploadPage.class);
+ mountPage("/uploadToResource", UploadToResourcePage.class);
getApplicationSettings().setUploadProgressUpdatesEnabled(true);
}
+
+ public IUploadsFileManager getUploadsFileManager() {
+ return uploadsFileManager;
+ }
+
+ public static UploadApplication getInstance() {
+ return (UploadApplication)get();
+ }
}
diff --git
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadPage.java
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadPage.java
index 3fe09b7eef..6e98748d2c 100644
---
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadPage.java
+++
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadPage.java
@@ -216,6 +216,6 @@ public class UploadPage extends WicketExamplePage
private Folder getUploadFolder()
{
- return ((UploadApplication)Application.get()).getUploadFolder();
+ return UploadApplication.getInstance().getUploadFolder();
}
}
diff --git
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.html
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.html
new file mode 100644
index 0000000000..ba2097cddf
--- /dev/null
+++
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.html
@@ -0,0 +1,44 @@
+<html xmlns:wicket="http://wicket.apache.org">
+<head>
+ <title>Wicket Examples - upload</title>
+ <style>
+ legend { border: 1px solid #e9601a; background-color: #bbb;
color: #fff; padding: 4px;}
+ fieldset { border: 1px solid #e9601a; padding: 10px;
margin-top: 10px;}
+ </style>
+</head>
+<body>
+ <wicket:extend>
+ <p>Wicket can upload to a <em>mounted resource.</em></p>
+ <p>This upload is done via jQuery AJAX and <em>does not</em>
block Wicket AJAX</p>
+ <p><em>Upload progressbar</em> has been updated to work with
this component</p>
+ <br/>
+
+ <div>
+ <fieldset>
+ <legend>Upload a file(s) to a <em>mounted
resource</em></legend>
+ <p>
+ <label wicket:for="fileInput">File</label>
+ <input wicket:id="fileInput" type="file"
multiple="multiple"/>
+ </p>
+ <form wicket:id="form">
+ <p>
+ <input
wicket:id="allowToLeavePageWhileUploading" type="checkbox"/>
+ <label
wicket:for="allowToLeavePageWhileUploading">Block leaving page while upload is
happening?</label>
+ </p>
+ </form>
+ <div>
+ <span wicket:id="progress">[[upload
progressbar]]</span>
+ </div>
+ <input wicket:id="upload" type="button" value="Upload
to a resource"/>
+ <input wicket:id="cancelUpload" type="button"
value="Cancel upload via AJAX request"/>
+ <input wicket:id="cancelUploadClientSide"
type="button" value="Cancel upload at client side"/>
+ <button wicket:id="counter" type="button">Click
me</button>
+ </fieldset>
+ </div>
+ <br/>
+ <div>
+ <span wicket:id="uploadFeedback"/>
+ </div>
+ </wicket:extend>
+</body>
+</html>
diff --git
a/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.java
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.java
new file mode 100644
index 0000000000..0f5f0413b3
--- /dev/null
+++
b/wicket-examples/src/main/java/org/apache/wicket/examples/upload/UploadToResourcePage.java
@@ -0,0 +1,266 @@
+/*
+ * 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.examples.upload;
+
+import java.util.List;
+import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.examples.WicketExamplePage;
+import
org.apache.wicket.extensions.ajax.markup.html.form.upload.UploadProgressBar;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.markup.head.OnEventHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.upload.resource.IUploadsFileManager;
+import
org.apache.wicket.markup.html.form.upload.resource.FileUploadToResourceField;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.util.lang.Bytes;
+
+/**
+ * Upload example.
+ *
+ * @author reiern70
+ */
+public class UploadToResourcePage extends WicketExamplePage
+{
+ private static class UpdateInEachAjaxRequestBehavior extends Behavior
+ {
+
+ @Override
+ public void bind(Component component)
+ {
+ component.setOutputMarkupPlaceholderTag(true);
+ }
+
+ @Override
+ public void onEvent(Component component, IEvent<?> event)
+ {
+ if (event.getPayload() instanceof AjaxRequestTarget)
+ {
+
((AjaxRequestTarget)event.getPayload()).add(component);
+ }
+ }
+ }
+
+ private final FeedbackPanel uploadFeedback;
+
+ private final FileUploadToResourceField fileUploadToResourceField;
+
+ private boolean uploading;
+
+ private int counter;
+
+ private final IModel<Boolean> allowToLeavePageWhileUploading =
Model.of(true);
+
+ /**
+ * Constructor.
+ *
+ * @param parameters
+ * Page parameters
+ */
+ public UploadToResourcePage(final PageParameters parameters)
+ {
+ fileUploadToResourceField = new
FileUploadToResourceField("fileInput")
+ {
+
+ private void updateFeedback(AjaxRequestTarget target)
+ {
+ target.add(uploadFeedback);
+ uploading = false;
+ }
+
+ @Override
+ protected void onUploadSuccess(AjaxRequestTarget
target, List<UploadInfo> infos)
+ {
+ for (UploadInfo uploadInfo : infos) {
+ info("File " +
uploadInfo.getClientFileName() + " successfully uploaded. Size: " +
uploadInfo.getSize() + "bytes. ContentType: "
+ +
uploadInfo.getContentType() +". Stored at " +
uploadInfo.getFile().getAbsolutePath());
+ }
+ updateFeedback(target);
+ }
+
+ @Override
+ protected void onUploadFailure(AjaxRequestTarget
target, String errorInfo)
+ {
+ updateFeedback(target);
+ }
+
+ @Override
+ public void startUpload(IPartialPageRequestHandler
target) {
+ if (allowToLeavePageWhileUploading.getObject())
+ {
+
target.prependJavaScript("Wicket.CurrentUpload = {};");
+ }
+ super.startUpload(target);
+ }
+
+ @Override
+ protected void onUploadCanceled(AjaxRequestTarget
target)
+ {
+ info("You have canceled the upload!");
+ updateFeedback(target);
+ }
+
+ @Override
+ protected CharSequence getClientSideSuccessCallBack() {
+ return "function() {Wicket.CurrentUpload =
null}";
+ }
+
+ @Override
+ protected CharSequence
getClientSideUploadErrorCallBack()
+ {
+ return "function() {Wicket.CurrentUpload =
null}";
+ }
+
+ @Override
+ protected String getClientSideCancelCallBack()
+ {
+ return "function() {Wicket.CurrentUpload =
null}";
+ }
+
+ @Override
+ protected IUploadsFileManager fileManager()
+ {
+ return getUploadsFileManager();
+ }
+ };
+ fileUploadToResourceField.setMaxSize(Bytes.kilobytes(100));
+ fileUploadToResourceField.setFileMaxSize(Bytes.kilobytes(90));
+ fileUploadToResourceField.setFileCountMax(5L);
+ add(fileUploadToResourceField);
+
+ Form<Void> form = new Form<>("form");
+ add(form);
+ form.add(new AjaxCheckBox("allowToLeavePageWhileUploading",
allowToLeavePageWhileUploading) {
+ @Override
+ protected void onUpdate(AjaxRequestTarget target) {
+
+ }
+ });
+ final UploadProgressBar uploadProgressBar = new
UploadProgressBar("progress", fileUploadToResourceField)
+ {
+
+ @Override
+ protected String getOnProgressUpdatedCallBack()
+ {
+ return "function(percent) {
console.log(percent);}";
+ }
+ };
+ add(uploadProgressBar);
+ add(new AjaxLink<Void>("upload")
+ {
+ @Override
+ public void onClick(AjaxRequestTarget target)
+ {
+ uploading = true;
+ fileUploadToResourceField.startUpload(target);
+ uploadProgressBar.start(target);
+ target.add(uploadFeedback);
+ }
+
+ @Override
+ protected void onConfigure()
+ {
+ super.onConfigure();
+ setVisible(!uploading);
+ }
+ }.add(new UpdateInEachAjaxRequestBehavior()));
+
+ add(new AjaxLink<Void>("cancelUpload")
+ {
+ @Override
+ public void onClick(AjaxRequestTarget target)
+ {
+ fileUploadToResourceField.cancelUpload(target);
+ target.add(uploadFeedback);
+ }
+
+ @Override
+ protected void onConfigure()
+ {
+ super.onConfigure();
+ setVisible(uploading);
+ }
+ }.add(new UpdateInEachAjaxRequestBehavior()));
+
+
+ add(new WebMarkupContainer("cancelUploadClientSide")
+ {
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ super.renderHead(response);
+
response.render(OnEventHeaderItem.forComponent(this, "click",
fileUploadToResourceField.getTriggerCancelUploadScript()));
+ }
+
+ @Override
+ protected void onConfigure()
+ {
+ super.onConfigure();
+ setVisible(uploading);
+ }
+
+ }.add(new UpdateInEachAjaxRequestBehavior()));
+
+ add(new AjaxLink<Void>("counter")
+ {
+
+ @Override
+ public void onClick(AjaxRequestTarget target)
+ {
+ counter ++;
+ target.add(this);
+ }
+
+ }.setBody(()-> "Click me: upload does not blocks normal wicket
AJAX. I was clicked " + counter).setOutputMarkupId(true));
+ // Create feedback panels
+ uploadFeedback = new FeedbackPanel("uploadFeedback");
+ uploadFeedback.setOutputMarkupId(true);
+
+ // Add uploadFeedback to the page itself
+ add(uploadFeedback);
+
+ }
+
+ @Override
+ public void renderHead(IHeaderResponse response) {
+ super.renderHead(response);
+ response.render(
+
OnDomReadyHeaderItem.forScript("$(window).bind('beforeunload', function(){ if
(Wicket.CurrentUpload != null) { return 'leave?'; }});"));
+ }
+
+ @Override
+ protected void onBeforeRender()
+ {
+ super.onBeforeRender();
+ uploading = false;
+ }
+
+ private IUploadsFileManager getUploadsFileManager()
+ {
+ return UploadApplication.getInstance().getUploadsFileManager();
+ }
+}
diff --git
a/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
b/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
index 2199c03f50..708fefd64f 100644
---
a/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
+++
b/wicket-examples/src/main/resources/org/apache/wicket/examples/homepage/HomePage.html
@@ -23,6 +23,7 @@
<tr><td align="right"><a
href="authorization">authorization</a></td><td> - Demonstrates authorization
for pages and components.</td></tr>
<tr><td align="right"><a href="upload/single">upload</a></td><td> -
Single file upload.</td></tr>
<tr><td align="right"><a href="upload/multi">upload</a></td><td> -
Multiple file upload.</td></tr>
+ <tr><td align="right"><a
href="upload/uploadToResource">upload</a></td><td> - Multiple (AJAX) upload to
a resource.</td></tr>
<tr><td align="right"><a href="template">template</a></td><td> -
Templating example.</td></tr>
<tr><td align="right"><a href="mailtemplate">mail template</a></td><td>
- Generate mail templates out of Page, Panel or TextTemplate.</td></tr>
<tr><td align="right"><a href="stateless">stateless</a></td><td> -
Demonstrates stateless pages/sessions.</td></tr>
diff --git
a/wicket-examples/src/main/resources/org/apache/wicket/examples/style.css
b/wicket-examples/src/main/resources/org/apache/wicket/examples/style.css
index f27f2c2dac..81fcf9216f 100644
--- a/wicket-examples/src/main/resources/org/apache/wicket/examples/style.css
+++ b/wicket-examples/src/main/resources/org/apache/wicket/examples/style.css
@@ -305,7 +305,7 @@ button.button--alert {
input[type=submit],
input[type=reset],
input[type=button],
-button {
+button, a.button {
background: #FF9925;
color: #fff; }
.button:hover,
diff --git
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/UploadProgressBar.java
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/UploadProgressBar.java
index d938e370e3..52e4d29a55 100644
---
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/UploadProgressBar.java
+++
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/UploadProgressBar.java
@@ -21,6 +21,7 @@ import java.util.Formatter;
import org.apache.wicket.Application;
import org.apache.wicket.IInitializer;
import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@@ -29,7 +30,6 @@ import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.IModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
@@ -109,7 +109,7 @@ public class UploadProgressBar extends Panel
private static final long serialVersionUID = 1L;
- private final Form<?> form;
+ private Form<?> form;
private MarkupContainer statusDiv;
@@ -117,6 +117,30 @@ public class UploadProgressBar extends Panel
private final FileUploadField uploadField;
+ /**
+ * Constructor that will display the upload progress bar for every
submit of the given form.
+ *
+ * @param id
+ * component id (not null)
+ * @param uploadField
+ * the file upload field to check for a file upload, or null
to display the upload
+ * field for every submit of the given form
+ */
+ public UploadProgressBar(final String id, final FileUploadField
uploadField)
+ {
+ super(id);
+
+ this.uploadField = uploadField;
+ if (uploadField != null)
+ {
+ uploadField.setOutputMarkupId(true);
+ }
+
+ setRenderBodyOnly(true);
+ }
+
+
+
/**
* Constructor that will display the upload progress bar for every
submit of the given form.
*
@@ -163,7 +187,10 @@ public class UploadProgressBar extends Panel
protected void onInitialize()
{
super.onInitialize();
- getCallbackForm().setOutputMarkupId(true);
+ Form<?> form = getCallbackForm();
+ if (form != null) {
+ form.setOutputMarkupId(true);
+ }
barDiv = newBarComponent("bar");
add(barDiv);
@@ -228,22 +255,44 @@ public class UploadProgressBar extends Panel
ResourceReference ref = new
SharedResourceReference(RESOURCE_NAME);
- final String uploadFieldId = (uploadField == null) ? "" :
uploadField.getMarkupId();
+ final String uploadFieldId = (uploadField == null) ? "null" :
("'" + uploadField.getMarkupId() + "'");
- final String status = new
StringResourceModel(RESOURCE_STARTING, this, (IModel<?>)null).getString();
+ final String status = new
StringResourceModel(RESOURCE_STARTING, this, null).getString();
- CharSequence url = urlFor(ref,
UploadStatusResource.newParameter(getPage().getId()));
+ CharSequence url = form != null ? urlFor(ref,
UploadStatusResource.newParameter(getPage().getId())) :
+ urlFor(ref,
UploadStatusResource.newParameter(uploadField.getMarkupId()));
StringBuilder builder = new StringBuilder(128);
Formatter formatter = new Formatter(builder);
- formatter.format(
- "new Wicket.WUPB('%s', '%s', '%s', '%s', '%s', '%s');",
- getCallbackForm().getMarkupId(),
statusDiv.getMarkupId(), barDiv.getMarkupId(), url, uploadFieldId,
- status);
+ Form<?> form = getCallbackForm();
+
+ formatter.format(getVarName() + " = new Wicket.WUPB(%s, '%s',
'%s', '%s', %s, '%s', %s);",
+ form != null ? "'" + form.getMarkupId() + "'" :
"null", statusDiv.getMarkupId(), barDiv.getMarkupId(), url, uploadFieldId,
+ status, getOnProgressUpdatedCallBack());
response.render(OnDomReadyHeaderItem.forScript(builder.toString()));
}
+ /**
+ * Allows to pass a JavaScript function that is called when progress in
updated.
+ *
+ * @return A JavaScript function.
+ */
+ protected String getOnProgressUpdatedCallBack()
+ {
+ return "function(percent) {}";
+ }
+
+ private String getVarName() {
+ return "window.upb_" + barDiv.getMarkupId();
+ }
+
+
+ public void start(IPartialPageRequestHandler handler)
+ {
+ handler.appendJavaScript(getVarName() + ".start();");
+ }
+
/**
* Form on where will be installed the JavaScript callback to present
the progress bar.
*
@@ -251,6 +300,10 @@ public class UploadProgressBar extends Panel
*/
private Form<?> getCallbackForm()
{
+ if (form == null)
+ {
+ return null;
+ }
return form.getRootForm();
}
}
diff --git
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/progressbar.js
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/progressbar.js
index 6cd0ad930b..f540347786 100644
---
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/progressbar.js
+++
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/form/upload/progressbar.js
@@ -25,16 +25,19 @@
Wicket.WUPB = Wicket.Class.create();
Wicket.WUPB.prototype = {
- initialize : function(formid, statusid, barid, url, fileid,
initialStatus) {
+ initialize : function(formid, statusid, barid, url, fileid,
initialStatus, onProgressUpdated) {
this.statusid = statusid;
this.barid = barid;
this.url = url;
this.fileid = fileid;
this.initialStatus = initialStatus;
+ this.onProgressUpdated = onProgressUpdated;
- var formElement = Wicket.$(formid);
- this.originalCallback = formElement.onsubmit;
- formElement.onsubmit = Wicket.bind(this.submitCallback,
this);
+ if (formid) {
+ var formElement = Wicket.$(formid);
+ this.originalCallback = formElement.onsubmit;
+ formElement.onsubmit =
Wicket.bind(this.submitCallback, this);
+ }
},
submitCallback : function() {
@@ -55,8 +58,14 @@
if (displayprogress) {
this.setPercent(0);
this.setStatus(this.initialStatus);
-
Wicket.$(this.statusid).removeAttribute('hidden');
- Wicket.$(this.barid).removeAttribute('hidden');
+ var $statusId = Wicket.$(this.statusid);
+ if ($statusId != null) {
+ Wicket.DOM.show($statusId);
+ }
+ var $barid = Wicket.$(this.barid);
+ if ($barid != null) {
+ Wicket.DOM.show($barid);
+ }
this.scheduleUpdate();
}
},
@@ -64,15 +73,24 @@
setStatus : function(status) {
var label = document.createElement("label");
label.innerHTML = status;
- var oldLabel = Wicket.$(this.statusid).firstChild;
- if( oldLabel != null){
- Wicket.$(this.statusid).removeChild(oldLabel);
+ var $statusId = Wicket.$(this.statusid);
+ if ($statusId != null) {
+ var oldLabel = $statusId.firstChild;
+ if (oldLabel != null){
+ $statusId.removeChild(oldLabel);
+ }
+ $statusId.appendChild(label);
}
- Wicket.$(this.statusid).appendChild(label);
},
setPercent : function(progressPercent) {
- Wicket.$(this.barid).firstChild.firstChild.style.width
= progressPercent + '%';
+ var barId = Wicket.$(this.barid);
+ if (barId != null && barId.firstChild != null &&
barId.firstChild.firstChild != null) {
+ barId.firstChild.firstChild.style.width =
progressPercent + '%';
+ }
+ if (this.onProgressUpdated) {
+ this.onProgressUpdated(progressPercent);
+ }
},
scheduleUpdate : function(){
@@ -117,8 +135,14 @@
this.iframe = null;
if (progressPercent === '100') {
- Wicket.$(this.statusid).setAttribute('hidden',
'');
- Wicket.$(this.barid).setAttribute('hidden', '');
+ var $statusId = Wicket.$(this.statusid);
+ if ($statusId != null) {
+ Wicket.DOM.hide($statusId);
+ }
+ var $barid = Wicket.$(this.barid);
+ if ($barid != null) {
+ Wicket.DOM.hide($barid);
+ }
} else {
this.scheduleUpdate();
}