/* MyMAM - Open Source Digital Media Asset Management. * http://www.mymam.net * * Copyright 2013, MyMAM contributors as indicated by the @author tag. * * Licensed 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 net.mymam.ui; import net.mymam.upload.UploadMultipartRequestWrapper; import org.apache.commons.fileupload.FileItem; import javax.faces.component.EditableValueHolder; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.FacesRenderer; import javax.faces.render.Renderer; import javax.servlet.ServletRequestWrapper; import java.io.IOException; import java.nio.charset.Charset; /** * Renderer for the {@link Upload} component. * * <p/> * Most of the HTML rendered here is initially invisible, using <tt>style="display: none"</tt>. * The invisible tags are templates that are used by <tt>mymam-upload.js</tt>. * * @see Upload * @author fstab */ @FacesRenderer(componentFamily = UIInput.COMPONENT_FAMILY, rendererType = "net.mymam.ui.UploadRenderer") public class UploadRenderer extends Renderer { @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { if ( component.isRendered() ) { ResponseWriter writer = context.getResponseWriter(); String clientId = component.getClientId(context); renderMainButtons(clientId, writer, (Upload) component); renderStatusMessageTemplates(writer, (Upload) component); renderGlobalStatusLineTemplate(writer, (Upload) component); renderUploadInfoTable(writer, (Upload) component); } } private void renderMainButtons(String clientId, ResponseWriter writer, Upload component) throws IOException { writer.startElement("div", component); writer.writeAttribute("class", "main-buttons", null); renderAddFilesButton(clientId, writer, component); renderClearButton(writer, component); renderSubmitButton(writer, component); writer.endElement("div"); } private void renderAddFilesButton(String clientId, ResponseWriter writer, Upload component) throws IOException { writer.startElement("span", component); writer.writeAttribute("class", "btn fileinput-button btn-primary", null); writer.startElement("i", component); writer.writeAttribute("class", "icon-plus", null); writer.endElement("i"); writer.startElement("span", component); writer.write(component.getAddFilesButtonLabel()); writer.endElement("span"); writer.startElement("input", component); writer.writeAttribute("type", "file", null); writer.writeAttribute("name", clientId, null); writer.writeAttribute("multiple", "multiple", null); writer.endElement("input"); writer.endElement("span"); } private void renderClearButton(ResponseWriter writer, Upload component) throws IOException { writer.startElement("input", component); writer.writeAttribute("type", "button", null); writer.writeAttribute("value", component.getClearButtonLabel(), null); writer.writeAttribute("class", "btn clear-button", null); writer.endElement("input"); } private void renderSubmitButton(ResponseWriter writer, Upload component) throws IOException { writer.startElement("input", component); writer.writeAttribute("type", "button", null); writer.writeAttribute("value", component.getSubmitButtonLabel(), null); writer.writeAttribute("class", "btn submit-button", null); writer.endElement("input"); } private void renderStatusMessageTemplates(ResponseWriter writer, Upload component) throws IOException { renderStatusMessageTemplate(writer, component, "alert alert-success upload-info-all-done", component.getSuccessMsgTemplate()); renderStatusMessageTemplate(writer, component, "alert alert-block upload-info-all-warn", component.getWarnMsgTemplate()); renderStatusMessageTemplate(writer, component, "alert alert-error upload-info-all-error", component.getErrorMsgTemplate()); } private void renderStatusMessageTemplate(ResponseWriter writer, Upload component, String styleClass, String msg) throws IOException { writer.startElement("div", component); writer.writeAttribute("class", styleClass, null); writer.writeAttribute("style", "display: none", null); writer.startElement("button", component); writer.writeAttribute("type", "button", null); writer.writeAttribute("class", "close", null); writer.writeAttribute("data-dismiss", "alert", null); writer.write("×"); writer.endElement("button"); writer.write(msg); writer.endElement("div"); } private void renderGlobalStatusLineTemplate(ResponseWriter writer, Upload component) throws IOException { writer.startElement("p", component); writer.writeAttribute("class", "upload-info-status lead", null); writer.startElement("span", component); writer.writeAttribute("style", "display: none;", null); writer.write(component.getGlobalStatusTemplate()); writer.endElement("span"); writer.endElement("p"); } private void renderUploadInfoTable(ResponseWriter writer, Upload component) throws IOException { writer.startElement("table", component); writer.writeAttribute("class", "table table-striped", null); writer.startElement("tbody", component); writer.startElement("tr", component); writer.writeAttribute("style", "display: none", null); renderColumnOne(writer, component); renderColumnTwo(writer, component); renderColumnThree(writer, component); renderColumnFour(writer, component); writer.endElement("tr"); writer.endElement("tbody"); writer.endElement("table"); } private void renderColumnOne(ResponseWriter writer, Upload component) throws IOException { writer.startElement("td", component); writer.writeAttribute("class", "upload-info-line-number", null); writer.write("1"); writer.endElement("td"); } private void renderColumnTwo(ResponseWriter writer, Upload component) throws IOException { writer.startElement("td", component); writer.writeAttribute("class", "upload-info-file-name", null); writer.startElement("div", component); writer.write("video.mov"); writer.endElement("div"); writer.startElement("div", component); writer.writeAttribute("class", "progress progress-striped", null); writer.startElement("div", component); writer.writeAttribute("class", "bar", null); writer.writeAttribute("style", "width: 0%;", null); writer.endElement("div"); writer.endElement("div"); writer.endElement("td"); } private void renderColumnThree(ResponseWriter writer, Upload component) throws IOException { writer.startElement("td", component); writer.writeAttribute("class", "upload-info-file-size", null); writer.write("1.5M"); writer.endElement("td"); } private void renderColumnFour(ResponseWriter writer, Upload component) throws IOException { writer.startElement("td", component); writer.writeAttribute("class", "upload-info-status-column", null); renderRemoveButton(writer, component); renderLabel(writer, component, "label label-info upload-info-status-uploading", "icon-arrow-up", component.getUploadingLabel()); renderLabel(writer, component, "label label-success upload-info-status-done", "icon-ok-sign", component.getDoneLabel()); renderLabel(writer, component, "label label-important upload-info-status-failed", "icon-warning-sign", component.getFailedLabel()); writer.endElement("td"); } private void renderRemoveButton(ResponseWriter writer, Upload component) throws IOException { writer.startElement("button", component); writer.writeAttribute("class", "btn upload-info-status-remove", null); writer.startElement("i", component); writer.writeAttribute("class", "icon-remove-circle", null); writer.endElement("i"); writer.startElement("span", component); writer.write(" " + component.getRemoveButtonLabel()); writer.endElement("span"); writer.endElement("button"); } private void renderLabel(ResponseWriter writer, Upload component, String styleClass, String icon, String msg) throws IOException { writer.startElement("span", component); writer.writeAttribute("class", styleClass, null); writer.writeAttribute("style", "display: none;", null); writer.startElement("i", component); writer.writeAttribute("class", icon, null); writer.endElement("i"); writer.startElement("span", component); writer.write(" " + msg); writer.endElement("span"); writer.endElement("span"); } /** * Handle the postback of a form containing an {@link Upload} component. * * <p/> * If the request contains a {@link FileItem}, set the corresponding * value in the backing bean. * * @param context {@link FacesContext} for the request we are processing. * @param component {@link UIComponent} to be decoded. */ @Override public void decode(FacesContext context, UIComponent component) { UploadMultipartRequestWrapper requestWrapper = getMultiPartRequestInChain(context); if (requestWrapper != null) { // if we are processing a multipart request String clientId = component.getClientId(context); FileItem fileItem = requestWrapper.getFileItem(clientId); if (fileItem != null) { // if the multipart request has a file item String encoding = findEncoding(requestWrapper); UploadedFile uploadedFile = new UploadedFile(fileItem, encoding); ((EditableValueHolder) component).setSubmittedValue(uploadedFile); ((EditableValueHolder) component).setValid(true); } } } // Either the encoding is sent in the request, or we take the JVM's default encoding. private String findEncoding(UploadMultipartRequestWrapper request) { String encoding = request.getCharacterEncoding(); if ( encoding == null ) { encoding = System.getProperty("file.encoding"); } if ( encoding == null ) { encoding = Charset.defaultCharset().toString(); } return encoding; } // Finds our MultipartRequestServletWrapper in case application contains other RequestWrappers. // This method is taken from PrimeFaces' implementation. private UploadMultipartRequestWrapper getMultiPartRequestInChain(FacesContext facesContext) { Object request = facesContext.getExternalContext().getRequest(); while (request instanceof ServletRequestWrapper) { if (request instanceof UploadMultipartRequestWrapper) { return (UploadMultipartRequestWrapper) request; } else { request = ((ServletRequestWrapper) request).getRequest(); } } return null; } }