001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup.html.form.upload; 018 019import java.util.ArrayList; 020import java.util.List; 021import org.apache.wicket.Component; 022import org.apache.wicket.WicketRuntimeException; 023import org.apache.wicket.ajax.AjaxRequestTarget; 024import org.apache.wicket.ajax.attributes.AjaxRequestAttributes; 025import org.apache.wicket.ajax.attributes.IAjaxCallListener; 026import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; 027import org.apache.wicket.markup.head.IHeaderResponse; 028import org.apache.wicket.markup.head.JavaScriptHeaderItem; 029import org.apache.wicket.request.IRequestParameters; 030import org.apache.wicket.request.Request; 031import org.apache.wicket.request.cycle.RequestCycle; 032import org.apache.wicket.request.resource.JavaScriptResourceReference; 033import org.apache.wicket.request.resource.ResourceReference; 034import org.apache.wicket.util.lang.Args; 035import org.apache.wicket.util.string.StringValue; 036import org.danekja.java.util.function.serializable.SerializableBiConsumer; 037import com.github.openjson.JSONArray; 038import com.github.openjson.JSONObject; 039 040/** 041 * {@link org.apache.wicket.ajax.form.OnChangeAjaxBehavior} that streams back to server properties 042 * of the selected file(s) (at client side), before uploading it (them). 043 * 044 * @author Ernesto Reinaldo Barreiro (reiern70@gmail.com). 045 */ 046public abstract class FilesSelectedBehavior extends OnChangeAjaxBehavior { 047 048 private static final long serialVersionUID = 1L; 049 050 private static final ResourceReference JS = new JavaScriptResourceReference(FilesSelectedBehavior.class, "FilesSelectedBehavior.js"); 051 052 @Override 053 protected void onBind() { 054 super.onBind(); 055 Component component = getComponent(); 056 if (!(component instanceof FileUploadField)) { 057 throw new WicketRuntimeException("Behavior " + getClass().getName() 058 + " can only be added to an instance of a FileUploadField"); 059 } 060 } 061 062 @Override 063 protected void onUpdate(AjaxRequestTarget target) { 064 Request request = RequestCycle.get().getRequest(); 065 List<FileDescription> fileDescriptions = new ArrayList<>(); 066 IRequestParameters parameters = request.getRequestParameters(); 067 // data is streamed as JSON. 068 StringValue fileInfos = parameters.getParameterValue("fileInfos"); 069 JSONArray jsonArray = new JSONArray(fileInfos.toString()); 070 for (int i = 0; i < jsonArray.length(); i++) 071 { 072 fileDescriptions.add(new FileDescription((JSONObject)jsonArray.get(i))); 073 } 074 onSelected(target, fileDescriptions); 075 } 076 077 078 /** 079 * Called when a file, at client side is selected. 080 * 081 * @param target The {@link org.apache.wicket.ajax.AjaxRequestTarget} 082 * @param fileDescriptions A list of FileDescription 083 */ 084 protected abstract void onSelected(AjaxRequestTarget target, List<FileDescription> fileDescriptions); 085 086 @Override 087 protected void updateAjaxAttributes(AjaxRequestAttributes attributes) 088 { 089 super.updateAjaxAttributes(attributes); 090 attributes.getAjaxCallListeners().add(new IAjaxCallListener() 091 { 092 @Override 093 public CharSequence getPrecondition(Component component) 094 { 095 return "return Wicket.FilesSelected.precondition(this);"; 096 } 097 }); 098 attributes.getDynamicExtraParameters().add("return Wicket.FilesSelected.collectFilesDetails('" + getComponent().getMarkupId() + "');"); 099 } 100 101 @Override 102 public void renderHead(Component component, IHeaderResponse response) 103 { 104 super.renderHead(component, response); 105 response.render(JavaScriptHeaderItem.forReference(JS)); 106 } 107 108 /** 109 * Creates an {@link FilesSelectedBehavior} based on lambda expressions 110 * 111 * @param select {@link SerializableBiConsumer} 112 * 113 * @return the {@link FilesSelectedBehavior} behavior 114 */ 115 public static FilesSelectedBehavior onSelected( 116 SerializableBiConsumer<AjaxRequestTarget, List<FileDescription>> select) 117 { 118 Args.notNull(select, "select"); 119 120 return new FilesSelectedBehavior() 121 { 122 private static final long serialVersionUID = 1L; 123 124 @Override 125 protected void onSelected(AjaxRequestTarget target, List<FileDescription> fileDescriptions) { 126 select.accept(target, fileDescriptions); 127 } 128 }; 129 } 130}