package org.webcat.ui;
import org.apache.log4j.Logger;
import org.webcat.ui._base.DojoActionFormElement;
import org.webcat.ui.util.DojoRemoteHelper;
import org.webcat.ui.util.JSHash;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOAssociation;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOElement;
import com.webobjects.appserver.WOPageNotFoundException;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.appserver._private.WOCGIFormValues;
import com.webobjects.appserver._private.WODynamicElementCreationException;
import com.webobjects.appserver._private.WOHTMLDynamicElement;
import com.webobjects.appserver._private.WONoContentElement;
import com.webobjects.appserver._private.WOStaticURLUtilities;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation._NSDictionaryUtilities;
import er.ajax.AjaxUtils;
import er.extensions.components.ERXComponentUtilities;
import er.extensions.components._private.ERXWOForm;
//-------------------------------------------------------------------------
/**
* An element whose tag name can be anything you want (using an
* {@code elementName} binding similar to {@code WOGenericElement}), but which
* can also execute actions (standard and remote) when clicked. This is useful
* when you want to perform an action through the {@code onClick} handler of an
* element but you don't want to use a button or a link, and you don't want to
* deal with the hassle of creating a {@code WCActionFunction} and binding it
* manually to the {@code onClick} handler of an element.
*
* @author Tony Allevato
* @author Last changed by $Author: aallowat $
* @version $Revision: 1.1 $, $Date: 2011/05/02 16:18:29 $
*/
public class WCActionElement extends WOHTMLDynamicElement
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
@SuppressWarnings("unchecked")
public WCActionElement(String name,
NSDictionary<String, WOAssociation> someAssociations,
WOElement template)
{
super(name, someAssociations, template);
_otherQueryAssociations = _NSDictionaryUtilities
.extractObjectsForKeysWithPrefix(_associations, "?", true);
if (_otherQueryAssociations == null
|| _otherQueryAssociations.count() <= 0)
{
_otherQueryAssociations = null;
}
_elementName = _associations.removeObjectForKey("elementName");
_action = _associations.removeObjectForKey("action");
_disabled = _associations.removeObjectForKey("disabled");
_actionClass = _associations.removeObjectForKey("actionClass");
_directActionName = _associations
.removeObjectForKey("directActionName");
_pageName = _associations.removeObjectForKey("pageName");
_onClick = _associations.removeObjectForKey("onClick");
_ignoreForm = _associations.removeObjectForKey("ignoreForm");
_remoteHelper = new DojoRemoteHelper(_associations);
if (_action == null && _pageName == null && _directActionName == null
&& _actionClass == null)
{
throw new WODynamicElementCreationException("<"
+ getClass().getName()
+ "> Missing required attribute: 'action' or or "
+ "'pageName' or 'directActionName' or 'actionClass'");
}
if ((_action != null && _pageName != null)
|| (_action != null && _directActionName != null)
|| (_pageName != null && _directActionName != null)
|| (_action != null && _actionClass != null))
{
throw new WODynamicElementCreationException("<"
+ getClass().getName()
+ "> At least two of these conflicting attributes are "
+ "present: 'action', 'pageName', "
+ "'directActionName', 'actionClass'.");
}
if (_action != null && _action.isValueConstant())
{
throw new WODynamicElementCreationException("<"
+ getClass().getName() + "> 'action' is a constant.");
}
}
//~ Methods ...............................................................
// ----------------------------------------------------------
protected void _appendOpenTagToResponse(WOResponse response,
WOContext context)
{
response.appendContentCharacter('<');
response.appendContentString(elementNameInContext(context));
appendAttributesToResponse(response, context);
if (!(hasContent()))
{
response.appendContentString(" /");
}
response.appendContentCharacter('>');
}
// ----------------------------------------------------------
protected void _appendCloseTagToResponse(WOResponse response,
WOContext context)
{
if (hasContent())
{
response.appendContentString("</");
response.appendContentString(elementNameInContext(context));
response.appendContentCharacter('>');
}
}
// ----------------------------------------------------------
protected void _appendCGIActionURLToResponse(WOResponse response,
WOContext context, boolean htmlEscapeURL)
{
String actionPath = computeActionStringInContext(_actionClass,
_directActionName, context);
NSDictionary<String, Object> queryDict = computeQueryDictionaryInContext(
actionPath, null /* FIXME */, _otherQueryAssociations, true,
context);
response.appendContentString(context._directActionURL(actionPath,
queryDict, secureInContext(context), 0, htmlEscapeURL));
}
// ----------------------------------------------------------
protected void _appendComponentActionURLToResponse(WOResponse response,
WOContext context, boolean escapeHTML)
{
String actionURL = context.componentActionURL(WOApplication
.application().componentRequestHandlerKey(),
secureInContext(context));
response.appendContentString(actionURL);
}
// ----------------------------------------------------------
protected void _appendOpeningHrefToResponse(WOResponse response,
WOContext context)
{
response.appendContentCharacter(' ');
response.appendContentString("href");
response.appendContentCharacter('=');
response.appendContentCharacter('"');
}
// ----------------------------------------------------------
protected void _appendClosingHrefToResponse(WOResponse response,
WOContext context)
{
response.appendContentCharacter('"');
}
// ----------------------------------------------------------
@Override
public void appendAttributesToResponse(WOResponse response,
WOContext context)
{
super.appendAttributesToResponse(response, context);
if (isDisabledInContext(context))
{
return;
}
if (_remoteHelper.isRemoteInContext(context))
{
response.appendContentString(" href=\"javascript:void(0);\"");
}
else
{
String formName = ERXWOForm.formName(context, null);
if (!isIgnoreFormInContext(context) && formName != null)
{
response.appendContentString(" href=\"javascript:void(0);\"");
}
/*else
{
_appendOpeningHrefToResponse(response, context);
if (_actionClass != null || _directActionName != null)
{
_appendCGIActionURLToResponse(response, context, true);
}
else if (_action != null || _pageName != null)
{
_appendComponentActionURLToResponse(response, context, true);
}
_appendClosingHrefToResponse(response, context);
}*/
}
appendOnClickAttributeToResponse(response, context);
}
// ----------------------------------------------------------
protected String elementNameInContext(WOContext context)
{
if (_elementName != null)
{
Object elementName = _elementName.valueInComponent(context
.component());
return (elementName == null) ? null : elementName.toString();
}
else
{
return null;
}
}
// ----------------------------------------------------------
protected boolean isDisabledInContext(WOContext context)
{
if (!isRenderedInContext(context))
{
return true;
}
if (_disabled != null)
{
return _disabled.booleanValueInComponent(context.component());
}
else
{
return false;
}
}
// ----------------------------------------------------------
protected boolean isIgnoreFormInContext(WOContext context)
{
if (_ignoreForm != null)
{
return _ignoreForm.booleanValueInComponent(context.component());
}
else
{
return false;
}
}
// ----------------------------------------------------------
protected void appendOnClickAttributeToResponse(WOResponse response,
WOContext context)
{
String onClick = null;
if (_onClick != null)
{
onClick = _onClick.valueInComponent(context.component()).toString();
}
if (_remoteHelper.isRemoteInContext(context))
{
response.appendContentString(" onclick=\"");
if (onClick != null)
{
response.appendContentString(onClick);
if (!onClick.endsWith(";"))
{
response.appendContentCharacter(';');
}
}
appendXhrGetToResponse(response, context);
response.appendContentString("\"");
}
else
{
String formName = ERXWOForm.formName(context, null);
if (formName == null)
{
log.warn("Rendered a WCActionElement with a non-remote action "
+ "that isn't in a form; the action will not execute.");
}
if (!isIgnoreFormInContext(context) && formName != null)
{
String senderID = context.elementID();
if (onClick == null)
{
onClick = "";
}
onClick += "; webcat.fullSubmit('" + formName + "','"
+ senderID + "');";
}
if (onClick != null)
{
response.appendContentString(" onclick=\"");
response.appendContentString(onClick);
response.appendContentString("\"");
}
}
}
// ----------------------------------------------------------
@SuppressWarnings("unchecked")
protected void appendXhrGetToResponse(WOResponse response, WOContext context)
{
WOComponent component = context.component();
String actionUrl = null;
if (_directActionName != null)
{
actionUrl = context.directActionURLForActionNamed(
(String) _directActionName.valueInComponent(component),
ERXComponentUtilities.queryParametersInComponent(
_associations, component)).replaceAll("&", "&");
}
else
{
actionUrl = AjaxUtils.ajaxComponentActionUrl(context);
}
JSHash requestOptions = new JSHash();
requestOptions.put("url", actionUrl);
// If we're inside a form, include the name of the element as the
// sender. This is unnecessary for buttons, but required for other
// types of action elements, like WCMenuItem.
String formName = ERXWOForm.formName(context, null);
if (!isIgnoreFormInContext(context) && formName != null)
{
requestOptions.put("sender", context.elementID());
}
response.appendContentString(_remoteHelper.remoteSubmitCall("this",
requestOptions, context));
}
// ----------------------------------------------------------
public WOActionResults invokeAction(WORequest request, WOContext context)
{
if (AjaxUtils.isAjaxRequest(request)
&& AjaxUtils.shouldHandleRequest(request, context, null))
{
return invokeRemoteAction(request, context);
}
else
{
return invokeStandardAction(request, context);
}
}
// ----------------------------------------------------------
protected boolean shouldHandleAction(WORequest request, WOContext context)
{
return (context.elementID().equals(context.senderID()))
|| (context.wasFormSubmitted()
&& context.isMultipleSubmitForm() && request
.formValueForKey(context.elementID()) != null);
}
// ----------------------------------------------------------
public WOActionResults invokeStandardAction(WORequest aRequest,
WOContext context)
{
String nextPageName = null;
WOActionResults invokedElement = null;
WOComponent component = context.component();
if (shouldHandleAction(aRequest, context))
{
if (_disabled == null
|| !_disabled.booleanValueInComponent(component))
{
context.setActionInvoked(true);
if (_pageName != null)
{
Object nextPageValue = _pageName
.valueInComponent(component);
if (nextPageValue != null)
{
nextPageName = nextPageValue.toString();
}
}
if (_action != null)
{
invokedElement = (WOActionResults) _action
.valueInComponent(component);
}
else
{
if (_pageName == null)
{
throw new IllegalStateException("<"
+ getClass().getName()
+ "> : Missing page name.");
}
if (nextPageName != null)
{
invokedElement = WOApplication.application()
.pageWithName(nextPageName, context);
}
else
{
throw new WOPageNotFoundException("<"
+ getClass().getName()
+ "> : cannot find page.");
}
}
}
else
{
invokedElement = new WONoContentElement();
}
if (invokedElement == null)
{
invokedElement = context.page();
}
}
return invokedElement;
}
// ----------------------------------------------------------
protected WOActionResults invokeRemoteAction(WORequest request,
WOContext context)
{
WOActionResults result = null;
WOComponent component = context.component();
AjaxUtils.createResponse(request, context);
AjaxUtils.mutableUserInfo(request);
context.setActionInvoked(true);
if (_action != null)
{
result = (WOActionResults) _action.valueInComponent(component);
}
AjaxUtils.updateMutableUserInfoWithAjaxInfo(context);
if (result == context.page())
{
log.warn("An Ajax request attempted to return the page, which "
+ "is almost certainly an error.");
result = null;
}
if (result == null)
{
result = AjaxUtils.createResponse(request, context);
}
return result;
}
//~ Static/instance variables .............................................
protected WOAssociation _elementName;
protected WOAssociation _action;
protected WOAssociation _pageName;
protected WOAssociation _disabled;
protected WOAssociation _actionClass;
protected WOAssociation _directActionName;
protected WOAssociation _onClick;
protected WOAssociation _ignoreForm;
protected NSDictionary<String, WOAssociation> _otherQueryAssociations;
protected DojoRemoteHelper _remoteHelper;
private static final Logger log = Logger.getLogger(WCActionElement.class);
}