weve used this before: http://www.tehnrd.com/visualforce-pop-up/ but that aside.
If you are using a lookup window to find a contact, what about creating a custom lookup window to which you add a "create contact" button. Use the create button to replace the lookup content with new contact fields right in that window, simple as re-rendering the page using render flags. That way its in keeping with standard salesforce UX and your users will possibly embrace the custom functionality more easily.
The only moderately difficult part is getting the selection back from the child lookup window to the parent.
These functions go on the parent VF page:
function openPopupFocus(a, b, c, d, e, f, g, k) {
closePopup();
if (f) {
if (lastMouseX - c < 0)
lastMouseX = c;
if (lastMouseY + d > screen.height)
lastMouseY -= lastMouseY + d + 50 - screen.height;
lastMouseX -= c;
lastMouseY += 10;
e += ",screenX=" + lastMouseX + ",left=" + lastMouseX + ",screenY=" + lastMouseY + ",top=" + lastMouseY
}
curPopupWindow = window.open(a, b, e, false);
curPopupWindow.focus()
if (k)
closeOnParentUnloadWindow = win
}
function closePopup() {
if (closetimer) {
clearTimeout(closetimer);
closetimer = null
}
if (curPopupWindow != null) {
try {
if (curPopupWindow.confirmOnClose) if (curPopupWindow.confirm(curPopupWindow.confirmOnCloseLabel)) {
curPopupWindow.confirmOnClose = false;
curPopupWindow.focus();
return false
}
curPopupWindow.close()
} catch (a) {}
curPopupWindow = null
}
}
function doLookupPick(a,b,c,d){
$(a).val(b);
$(c).val(d);
closePopup();
}
the link to open the window
openPopupFocus(%27/apex/<VF PAGE NAME>?filter=item%27, %27CCBCCLookup%27, 420, 490, %27width=420,height=490,toolbar=no,status=no,directories=no,menubar=no,resizable=yes,scrollable=no%27, true);
This function goes on the custom lookup page:
function sendToParent(selectedId,selectedName){
top.window.opener.doLookupPick(<hidden field dom id>,
<selected sfObject ID>,
<text input field dom id>',
<text input contact name>);
}
Unfortunately there isn't currently a way to assign an action to a button. sforce.one.createRecord() uses the standard page layout for the profile/record type, not an action layout.
You could fake it out by creating a Visualforce page that dynamically generates the form based on the action layout, something like this (this is a lead because it's code I had on hand, you can do something similar for your New Event action):
public class QuickCreateController{
public final ApexPages.StandardController stdController;
public Lead newLead = new Lead();
public Map<string, boolean> requiredMap {get;set;}
public QuickCreateController() {}
public QuickCreateController(ApexPages.StandardController stdController)
{
this.stdController = stdController;
this.newLead = (Lead) stdController.getRecord();
// Workaround for DescribeLayoutItem.required attribute apparently not
// accessible in VF page (bug?): storing the required flags in a map.
requiredMap = new Map<string, boolean>();
}
// Get the list of fields in the NewLead global action.
public List<QuickAction.DescribeLayoutItem> getActionFieldList()
{
List<QuickAction.DescribeLayoutItem> fieldList = new List<QuickAction.DescribeLayoutItem>();
QuickAction.DescribeQuickActionResult[] results = QuickAction.describeQuickActions(new String[]{ QuickAction.NewLead });
for (QuickAction.DescribeQuickActionResult res : results)
{
for (QuickAction.DescribeLayoutRow row : res.getLayout().getLayoutRows())
{
for (QuickAction.DescribeLayoutItem col : row.getLayoutItems())
{
// Ignore placeholders.
if (!col.placeholder)
{
fieldList.add(col);
// Hack to get DescribeLayoutItem.required flag in the VF page:
// store it in a map, request it from the page.
requiredMap.put(col.label, col.required);
}
}
}
}
return fieldList;
}
public PageReference submitQuickAction()
{
PageReference p = new PageReference('/apex/QuickCreate');
QuickAction.QuickActionRequest req = new QuickAction.QuickActionRequest();
req.quickActionName = QuickAction.NewLead;
req.record = newLead;
try
{
QuickAction.QuickActionResult res = QuickAction.performQuickAction(req);
p = new PageReference('/apex/Page_To_Go_To_After_Completion);
p.setRedirect(true);
}
catch (Exception ex)
{
ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.ERROR, ex.getMessage());
ApexPages.addMessage(myMsg);
}
return p;
}
}
Then your Visualforce page looks something like this:
<apex:page standardController="Lead" extensions="QuickCreateController">
<apex:form >
<apex:pageMessages />
<apex:repeat value="{!actionFieldList}" var="layoutItem">
<apex:outputPanel layout="none" rendered="{!requiredMap[layoutItem.label]}"><span style="font-weight: bold; color: red">*</span> </apex:outputPanel>
<apex:outputLabel value="{!layoutItem.label}"></apex:outputLabel><br />
<apex:repeat value="{!layoutItem.layoutComponents}" var="layoutComponent">
<apex:inputField value="{!Lead[layoutComponent.value]}" required="{!requiredMap[layoutItem.label]}"/>
</apex:repeat>
</apex:repeat>
<apex:commandButton action="{!submitQuickAction}" value="Save" />
</apex:form>
</apex:page>
It's a hack and I don't recommend it as a solution, but I thought it was interesting to know it could be done. :-)
Best Answer
As of Summer '15 you can hide the header in Visualforce custom actions by setting the showQuickActionVfHeader attribute to false (see the Summer '15 Release Notes).
So you could hide the buttons and then add a "back" button in your VF page that basically does the same thing as cancelling. Not perfect, but at least less confusing for the end user.