package er.ajax;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import er.extensions.appserver.ERXWOContext;
/**
* <p>Generates an element to open a specific AjaxModalDialog. This is useful when you want to physically separate the modal dialog from what
* opens it, for example if you want a modal dialog containing a form to have an opener inside of another form. It is also useful if you
* want to use a dialog in a repetition. Using an AjaxModalDialogOpener in the repetition and moving the AjaxModalDialog outside of the
* repetition will result in only a single rendering of the AjaxModalDialog in the page. You can also move it before the repetition to
* speed up request handling when the dialog is open. Normally you will want to bind showOpener=false; on the AjaxModalDialog that this opens.
* </p>
*
* <p> If you need to do some preparation before the dialog opens, use the action
* method.This is called synchronously so make it quick! The action method is useful for things like copying the item from a repetition
* to use in a dialog that is not nested in the repetition. </p>
*
* <p>If you specify the <code>elementName</code> as <code>a</code> then the label binding can be used to specify the link, or you can use child elements.
* You can also specify the link's title using the title binding.</p>
*
* <p>As the opener functions on the client only, it is possible for it to be rendered when <code>enabled</code> evaluates to
* <code>true</code> and clicked later when <code>enabled</code> would evaluate to <code>false</code>. This condition is checked for
* when the opener is clicked. If <code>enabled</code> evaluates to <code>false</code> at that time: the action method
* is not called, the AjaxModalDialog is not opened, and the onFailure handler (if any) is run.
* </p>
*
* @binding dialogId required, ID of the AjaxModalDialog to open
* @binding elementName the element that you want the open rendered as
* @binding label only relevant if <code>elementName</code> is <code>a</code>: the text for the link that opens the dialog box, if this used the child elements are ignored.
* @binding linkTitle only relevant if <code>elementName</code> is <code>a</code>: used as title attribute of link opening dialog
* @binding title the Title to be displayed in the ModalBox window header, can override what the dialog was created with
* @binding action, optional action to call before opening the modal dialog.
* @binding enabled if false, nothing is rendered for this component. This can be used instead of wrapping this in a WOConditional.
* The default is true.
* @binding onFailure optional JavaScript (not a function()!) to run if the opener is clicked and enabled evaluates to false. This can remove the element, show
* an alert, etc. e.g. onFailure = "alert('This is no longer available');";
*
* @binding id HTML id for the link
* @binding class CSS class for the link
* @binding style CSS style for the link
*
* @see AjaxModalDialog
* @see <a href="http://www.wildbit.com/labs/modalbox"/>Modalbox Page</a>
* @see <a href="http://code.google.com/p/modalbox/">Google Group</a>
* @author chill
*/
public class AjaxModalDialogOpener extends AjaxComponent {
/**
* 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;
/**
* Call this, from the action method only, to prevent the dialog from opening. If there is an onFailure
* callback, it will get executed. This is also called internally if <code>enabled</code> is bound and
* evaluates to false. This method sets the response status code to an error code so that the onSuccess
* callback is not executed. The error status returned is 409 - "Conflict" which seemed like the best
* match for this.
*
* @param context WOContext to reject open in
*/
public static void rejectOpen(WOContext context) {
AjaxUtils.createResponse(context.request(), context).setStatus(409);
}
public AjaxModalDialogOpener(WOContext context) {
super(context);
}
@Override
public boolean isStateless() {
return true;
}
/**
* Generate a link that opens the indicated dialog.
*
* @see er.ajax.AjaxComponent#appendToResponse(com.webobjects.appserver.WOResponse, com.webobjects.appserver.WOContext)
*/
@Override
public void appendToResponse(WOResponse response, WOContext context) {
if( ! booleanValueForBinding("enabled", true)) {
return;
}
String elementName = (String) valueForBinding("elementName", "a", context.component());
response.appendContentString("<" + elementName + " ");
if (elementName.equals("a")) {
response.appendContentString("href=\"javascript:void(0)\"");
appendTagAttributeToResponse(response, "title", valueForBinding("linkTitle", null));
}
appendTagAttributeToResponse(response, "id", id());
appendTagAttributeToResponse(response, "class", valueForBinding("class", null));
appendTagAttributeToResponse(response, "style", valueForBinding("style", null));
// onclick calls the script that opens the AjaxModalDialog
response.appendContentString(" onclick=\"");
response.appendContentString("new Ajax.Request('");
response.appendContentString(AjaxUtils.ajaxComponentActionUrl(context()));
response.appendContentString("', ");
AjaxOptions.appendToResponse(ajaxRequestOptions(), response, context);
response.appendContentString("); ");
response.appendContentString("return false;\" >");
if (elementName.equals("a") && hasBinding("label")) {
response.appendContentString((String) valueForBinding("label"));
} else {
// This will append the contents inside of the link
super.appendToResponse(response, context);
}
response.appendContentString("</" + elementName + ">");
}
/**
* @return the value bound to id or an manufactured string if id is not bound
*/
public String id() {
return hasBinding("id") ? (String) valueForBinding("id") : ERXWOContext.safeIdentifierName(context(), false);
}
/**
* @return the value bound to dialogId
*/
public String modalDialogId() {
return (String) valueForBinding("dialogId");
}
@Override
protected void addRequiredWebResources(WOResponse res) {
}
/**
* Runs action and returns success status if enabled, otherwise returns failed status.
*/
@Override
public WOActionResults handleRequest(WORequest request, WOContext context) {
if( booleanValueForBinding("enabled", true)) {
valueForBinding("action");
}
else {
rejectOpen(context);
}
return null;
}
/**
* @return options for Ajax.Request that is made when the link is clicked
*/
protected NSMutableDictionary ajaxRequestOptions() {
NSMutableArray ajaxOptionsArray = new NSMutableArray();
ajaxOptionsArray.addObject(new AjaxConstantOption("asynchronous", Boolean.FALSE, AjaxOption.BOOLEAN));
ajaxOptionsArray.addObject(new AjaxConstantOption("evalScripts", Boolean.FALSE, AjaxOption.BOOLEAN));
ajaxOptionsArray.addObject(new AjaxOption("onFailure", AjaxOption.FUNCTION_1));
// onSuccess callback handler to open AMD
StringBuilder sb = new StringBuilder(500);
sb.append(AjaxModalDialog.openDialogFunctionName(modalDialogId()));
sb.append('(');
// Override for dialog name
if (hasBinding("title")) {
sb.append(AjaxValue.javaScriptEscaped(valueForBinding("title")));
}
sb.append(");");
ajaxOptionsArray.addObject(new AjaxConstantOption("onSuccess", sb.toString(), AjaxOption.FUNCTION_1));
return AjaxOption.createAjaxOptionsDictionary(ajaxOptionsArray, this);
}
}