package er.attachment.components;
import org.apache.log4j.Logger;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOResponse;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import er.ajax.AjaxUtils;
import er.attachment.model.ERAttachment;
import er.extensions.appserver.ERXWOContext;
import er.extensions.components.ERXComponentUtilities;
import er.extensions.components.ERXNonSynchronizingComponent;
/**
* ERAttachmentFlexibleEditor is a wrapper around {@link ERAttachmentFlexibleUpload} and {@link ERAttachmentViewer}
* It provides a one stop shop for editing a to-one relationship between a masterObject and
* an ERAttachment. Switching back and forth between edit and view modes is handled by ajax updates.
* <p>
* There is one scenario where there is the potential for an orphaned ERAttachment and associated file.
* <ol>
* <li>User lands on an edit page for the masterObject</li>
* <li>User selects and successfully uploads a file for the attachment</li>
* <li>User leaves the masterObject edit page without saving changes</li>
* </ol>
*
* @binding masterObject (required) - Parent object owning the relationship to this attachment
* @binding relationshipKey (required) - Name of the to-one relationship to the attachment
* @binding injectDefaultCSS - inject the default stylesheet from the Ajax framework (defaults to true);
* @binding id - unique identifier for this component (generated if null)
* @binding editorEditLabel - label for the edit button (defaults to "Edit")
* @binding editorEditButtonClass - css class for the edit button (defaults to "Button ObjButton EditObjButton")
* @binding editorCancelLabel - label for the cancel button (defaults to "Cancel")
* @binding editorCancelButtonClass - css class for the cancel button (defaults to "Button ObjButton CancelObjButton")
* @binding configurationName - configuration name for configuring ERAttachment
* @binding storageType - storage type for configuring ERAttachment
* @binding viewShowFileName - show the attachment file name in the view mode (defaults to true)
* @binding viewShowAttachmentLink - if viewShowFilename is true, wrap it with an ERAttachmentLink (defaults to true)
* @binding uploadDialogHeaderText - the text of the upload header (defaults to "Edit Attachment")
*
* @binding viewHeight - see: {@link ERAttachmentViewer}
* @binding viewWidth - see: {@link ERAttachmentViewer}
*
* @binding viewAllowDownload - see: {@link ERAttachmentLink}
*
* @binding uploadAllowCancel - for the following see: {@link ERAttachmentFlexibleUpload}
* @binding uploadFinishedFunction
* @binding uploadCancelButtonClass
* @binding uploadCancelLabel
* @binding uploadCanceledAction
* @binding uploadCanceledFunction
* @binding uploadCancelingText
* @binding uploadClearClass
* @binding uploadFailedAction
* @binding uploadFailedFunction
* @binding uploadHeight
* @binding uploadWidth
* @binding uploadMimeType
* @binding uploadOwnerID
* @binding uploadRefreshTime
* @binding uploadSelectFileButtonClass
* @binding uploadSelectFileLabel
* @binding uploadStartedFunction
*
* @property er.attachment.[configurationName].tempFolder (optional) the temp folder to use for WOFileUploads
* @property er.attachment.tempFolder (optional) the temp folder to use for WOFileUploads
* @property er.attachment.[configurationName].storageType
* @property er.attachment.storageType
* @property er.attachment.[configurationName].width
* @property er.attachment.width
* @property er.attachment.[configurationName].height
* @property er.attachment.height
*
* @author david
*/
public class ERAttachmentFlexibleEditor extends ERXNonSynchronizingComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
protected final Logger log = Logger.getLogger(getClass());
public static interface Keys {
public static final String masterObject = "masterObject";
public static final String relationshipKey = "relationshipKey";
public static final String viewAllowDownload = "viewAllowDownload";
public static final String viewShowFileName = "viewShowFileName";
public static final String viewShowAttachmentLink = "viewShowAttachmentLink";
public static final String uploadStartedFunction = "uploadStartedFunction";
public static final String uploadFinishedFunction = "uploadFinishedFunction";
public static final String uploadSucceededAction = "uploadSucceededAction";
public static final String uploadAllowCancel = "uploadAllowCancel";
public static final String uploadCancelLabel = "uploadCancelLabel";
public static final String injectDefaultCSS = "injectDefaultCSS";
public static final String editorEditButtonClass = "editorEditButtonClass";
public static final String editorCancelButtonClass = "editorCancelButtonClass";
public static final String editorEditLabel = "editorEditLabel";
public static final String editorCancelLabel = "editorCancelLabel";
public static final String uploadDialogHeaderText = "uploadDialogHeaderText";
}
private String _id;
private ERAttachment _newAttachment;
private String _uploadCancelLabel;
private String _editorCancelButtonClass;
private String _editorEditButtonClass;
private String _editorEditLabel;
private String _editorCancelLabel;
private String _uploadDialogHeaderText;
private boolean _showUpload;
public ERAttachmentFlexibleEditor(WOContext context) {
super(context);
}
@Override
public void appendToResponse(WOResponse response, WOContext context) {
super.appendToResponse(response, context);
if (ERXComponentUtilities.booleanValueForBinding(this, Keys.injectDefaultCSS, true)) {
AjaxUtils.addStylesheetResourceInHead(context, response, "default_ajaxupload.css");
}
AjaxUtils.addScriptResourceInHead(context, response, "prototype.js");
AjaxUtils.addScriptResourceInHead(context, response, "effects.js");
AjaxUtils.addScriptResourceInHead(context, response, "wonder.js");
AjaxUtils.addScriptResourceInHead(context, response, "ajaxupload.js");
}
// ACTIONS
/**
* Action bound to the edit button
*
* @return null
*/
public WOActionResults editAttachment() {
_showUpload = true;
return null;
}
/**
* Action bound to the cancel button
*
* @return null
*/
public WOActionResults cancelEdit() {
_showUpload = false;
return null;
}
/**
* Action called when an upload succeeds
*
* @return results of the
*/
public WOActionResults uploadSucceededAction() {
EOEditingContext workingEC = masterObject().editingContext();
ERAttachment existing = (ERAttachment)masterObject().valueForKey(relationshipKey());
if (existing != null) {
workingEC.deleteObject(existing.localInstanceIn(workingEC));
}
masterObject().addObjectToBothSidesOfRelationshipWithKey(newAttachment(), relationshipKey());
_showUpload = false;
return (WOActionResults)valueForBinding(Keys.uploadSucceededAction);
}
public WOActionResults finishedAction() {
return null;
}
// STATE
/**
* Controls whether the upload component is shown
*
* @return boolean
*/
public boolean showUpload() {
return viewerAttachment() == null || _showUpload;
}
// FOR UPLOADER
public ERAttachment newAttachment() {
return _newAttachment;
}
public void setNewAttachment(ERAttachment a) {
_newAttachment = a;
}
/**
* EOEditingContext for the uploaded attachment
*
* @return EOEditingContext
*/
public EOEditingContext attachmentEC() {
return masterObject().editingContext();
}
public boolean allowCancel() {
return booleanValueForBinding(Keys.uploadAllowCancel, true);
}
/**
* The label to apply to the upload components cancel button
*
* Defaults to "Cancel Upload"
*
* @return String the uploadCancelLabel
*/
public String uploadCancelLabel() {
if (_uploadCancelLabel == null) {
_uploadCancelLabel = stringValueForBinding(Keys.uploadCancelLabel, "Cancel Upload");
}
return _uploadCancelLabel;
}
// FOR VIEWER
/**
* The masterObject's attachment
*
* @return ERAttachment
*/
public ERAttachment viewerAttachment() {
return (ERAttachment)masterObject().valueForKey(relationshipKey());
}
/**
* Controls whether the file name should be displayed
*
* Defaults to true
*
* @return boolean
*/
public boolean showFileName() {
return booleanValueForBinding(Keys.viewShowFileName, true);
}
/**
* Controls whether the file name should be shown as a link
*
* Defaults to true
*
* @return boolean
*/
public boolean showLink() {
boolean showAttachment = booleanValueForBinding(Keys.viewShowAttachmentLink, true);
boolean isNew = viewerAttachment().isNewObject();
return showAttachment && !isNew;
}
public boolean allowDownload() {
return booleanValueForBinding(Keys.viewAllowDownload, true);
}
// FOR EDITOR
/**
* The css class for the main edit button
*
* Defaults to "Button ObjButton EditObjButton"
*
* @return the editorEditButtonClass
*/
public String editorEditButtonClass() {
if (_editorEditButtonClass == null) {
_editorEditButtonClass = stringValueForBinding(Keys.editorEditButtonClass, "Button ObjButton EditObjButton");
}
return _editorEditButtonClass;
}
/**
* The css class for the main cancel button
*
* Defaults to "Button ObjButton CancelObjButton"
*
* @return the editorCancelButtonClass
*/
public String editorCancelButtonClass() {
if (_editorCancelButtonClass == null) {
_editorCancelButtonClass = stringValueForBinding(Keys.editorCancelButtonClass, "Button ObjButton CancelObjButton");
}
return _editorCancelButtonClass;
}
/**
* The label for the main edit button
*
* Defaults to "Edit"
*
* @return the editorEditLabel
*/
public String editorEditLabel() {
if (_editorEditLabel == null) {
_editorEditLabel = stringValueForBinding(Keys.editorEditLabel, "Edit");
}
return _editorEditLabel;
}
/**
* The label for the main cancel button
*
* Defaults to "Cancel"
*
* @return the _editorCancelLabel
*/
public String editorCancelLabel() {
if (_editorCancelLabel == null) {
_editorCancelLabel = stringValueForBinding(Keys.editorCancelLabel, "Cancel");
}
return _editorCancelLabel;
}
/**
* The text to display in the header of the edit box
*
* @return the uploadDialogHeaderText
*/
public String uploadDialogHeaderText() {
if (_uploadDialogHeaderText == null) {
_uploadDialogHeaderText = stringValueForBinding(Keys.uploadDialogHeaderText, "Edit Attachment");
}
return _uploadDialogHeaderText;
}
// GENERIC ACCESSORS
/**
* Getter for the masterObject
*
* @return the masterObject
*/
public EOEnterpriseObject masterObject() {
return (EOEnterpriseObject)valueForBinding(Keys.masterObject);
}
/**
* Getter for the relationhipKey
*
* @return the relationshipKey
*/
public String relationshipKey() {
return stringValueForBinding(Keys.relationshipKey);
}
/**
* Should the component inject the default css in the head of the page
*
* @return boolean
*/
public boolean injectDefaultCSS() {
return booleanValueForBinding(Keys.injectDefaultCSS, true);
}
// AJAX SUPPORT
/**
* Base unique identifier, used to create the other id's in the component
*
* @return String
*/
public String id() {
if (_id == null) {
_id = stringValueForBinding("id", ERXWOContext.safeIdentifierName(context(), true));
}
return _id;
}
/**
* Unique identifier for the main update container
*
* @return String
*/
public String updateContainerID() {
return "AFEUC" + id();
}
/**
* Unique identifier for the cancel button wrapper div
*
* @return String
*/
public String cancelButtonWrapperID() {
return "AECB" + id();
}
/**
* Function to update the main update container
*
* @return String
*/
public String refreshContainerFunction() {
return updateContainerID() + "Update();";
}
/**
* Function called when the upload finishes
*
* @return String
*/
public String uploadFinishedFunction() {
String finishedFunction = stringValueForBinding(Keys.uploadFinishedFunction, "");
String result = "function(e) { " + refreshContainerFunction() + " " + finishedFunction + " }";
if (log.isDebugEnabled()) log.debug(result);
return result;
}
/**
* Function called when the upload starts
*
* @return String
*/
public String startedFunction() {
String startedFunction = stringValueForBinding(Keys.uploadStartedFunction, "");
String result = "function(e) { $('" + cancelButtonWrapperID() + "').hide(); " + startedFunction + "}";
if (log.isDebugEnabled()) log.debug(result);
return result;
}
}