Skip to content

Commit

Permalink
Fixing bug 68215. Adding support for the onbeforeunload event. r=pete…
Browse files Browse the repository at this point in the history
…rv@propagandism.org, sr=brendan@mozilla.org
  • Loading branch information
jst%mozilla.jstenback.com committed Feb 11, 2004
1 parent 2703a27 commit 64ad19a
Show file tree
Hide file tree
Showing 35 changed files with 630 additions and 330 deletions.
112 changes: 109 additions & 3 deletions content/base/src/nsDocumentViewer.cpp
Expand Up @@ -199,6 +199,10 @@ static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printset

static NS_DEFINE_CID(kGalleyContextCID, NS_GALLEYCONTEXT_CID);

static const char kDOMStringBundleURL[] =
"chrome://communicator/locale/dom/dom.properties";


#ifdef NS_DEBUG

#undef NOISY_VIEWER
Expand Down Expand Up @@ -414,9 +418,11 @@ class DocumentViewerImpl : public nsIDocumentViewer,

nsIWidget* mParentWidget; // purposely won't be ref counted

PRPackedBool mInPermitUnload;

#ifdef NS_PRINTING
PRPackedBool mClosingWhilePrinting;
nsPrintEngine* mPrintEngine;
PRBool mClosingWhilePrinting;
nsCOMPtr<nsIDOMWindowInternal> mDialogParentWin;
#if NS_PRINT_PREVIEW
// These data member support delayed printing when the document is loading
Expand Down Expand Up @@ -961,6 +967,104 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus)
return rv;
}

NS_IMETHODIMP
DocumentViewerImpl::PermitUnload(PRBool *aPermitUnload)
{
*aPermitUnload = PR_TRUE;

if (!mDocument || mInPermitUnload) {
return NS_OK;
}

// First, get the script global object from the document...
nsIScriptGlobalObject *global = mDocument->GetScriptGlobalObject();

if (!global) {
// This is odd, but not fatal
NS_WARNING("nsIScriptGlobalObject not set for document!");
return NS_OK;
}

// Now, fire an BeforeUnload event to the document and see if it's ok
// to unload...
nsEventStatus status = nsEventStatus_eIgnore;
nsBeforePageUnloadEvent event(NS_BEFORE_PAGE_UNLOAD);

// In evil cases we might be destroyed while handling the
// onbeforeunload event, don't let that happen.
nsRefPtr<DocumentViewerImpl> kungFuDeathGrip(this);

mInPermitUnload = PR_TRUE;
nsresult rv = global->HandleDOMEvent(mPresContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
mInPermitUnload = PR_FALSE;

if (NS_SUCCEEDED(rv) && event.flags & NS_EVENT_FLAG_NO_DEFAULT) {
// Ask the user if it's ok to unload the current page

nsCOMPtr<nsIPrompt> prompt(do_GetInterface(mContainer));

if (prompt) {
nsCOMPtr<nsIStringBundleService>
stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
NS_ENSURE_TRUE(stringService, NS_OK);

nsCOMPtr<nsIStringBundle> bundle;
stringService->CreateBundle(kDOMStringBundleURL, getter_AddRefs(bundle));
NS_ENSURE_TRUE(bundle, NS_OK);

nsXPIDLString preMsg, postMsg;
nsresult rv;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("OnBeforeUnloadPreMessage").get(), getter_Copies(preMsg));
rv |= bundle->GetStringFromName(NS_LITERAL_STRING("OnBeforeUnloadPostMessage").get(), getter_Copies(postMsg));

// GetStringFromName can succeed, yet give NULL strings back.
if (NS_FAILED(rv) || !preMsg || !postMsg) {
NS_ERROR("Failed to get strings from dom.properties!");
return NS_OK;
}

// Limit the length of the text the page can inject into this
// dialogue to 1024 characters.
PRInt32 len = PR_MIN(event.text.Length(), 1024);

nsAutoString msg(preMsg + NS_LITERAL_STRING("\n\n") +
StringHead(event.text, len) +
NS_LITERAL_STRING("\n\n") + postMsg);

// This doesn't pass a title, which makes the title be
// "Confirm", is that ok, or do we want a localizable title for
// this dialogue?
if (NS_FAILED(prompt->Confirm(nsnull, msg.get(), aPermitUnload))) {
*aPermitUnload = PR_TRUE;
}
}
}

nsCOMPtr<nsIDocShellTreeNode> docShellNode(do_QueryInterface(mContainer));

if (docShellNode) {
PRInt32 childCount;
docShellNode->GetChildCount(&childCount);

for (PRInt32 i = 0; i < childCount && *aPermitUnload; ++i) {
nsCOMPtr<nsIDocShellTreeItem> item;
docShellNode->GetChildAt(i, getter_AddRefs(item));

nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(item));
nsCOMPtr<nsIContentViewer> cv;

docShell->GetContentViewer(getter_AddRefs(cv));

if (cv) {
cv->PermitUnload(aPermitUnload);
}
}
}

return NS_OK;
}

NS_IMETHODIMP
DocumentViewerImpl::Unload()
{
Expand All @@ -971,11 +1075,11 @@ DocumentViewerImpl::Unload()
}

// First, get the script global object from the document...
nsCOMPtr<nsIScriptGlobalObject> global = mDocument->GetScriptGlobalObject();
nsIScriptGlobalObject *global = mDocument->GetScriptGlobalObject();

if (!global) {
// Fail if no ScriptGlobalObject is available...
NS_ASSERTION(0, "nsIScriptGlobalObject not set for document!");
NS_ERROR("nsIScriptGlobalObject not set for document!");
return NS_ERROR_NULL_POINTER;
}

Expand Down Expand Up @@ -1121,6 +1225,8 @@ DocumentViewerImpl::Destroy()
mPresShell = nsnull;
}

mContainer = nsnull;

return NS_OK;
}

Expand Down
22 changes: 22 additions & 0 deletions content/base/src/nsSyncLoadService.cpp
Expand Up @@ -117,6 +117,7 @@ class nsSyncLoader : public nsIDOMLoadListener,

// nsIDOMLoadListener
NS_IMETHOD Load(nsIDOMEvent* aEvent);
NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent);
NS_IMETHOD Unload(nsIDOMEvent* aEvent);
NS_IMETHOD Abort(nsIDOMEvent* aEvent);
NS_IMETHOD Error(nsIDOMEvent* aEvent);
Expand Down Expand Up @@ -157,6 +158,7 @@ class txLoadListenerProxy : public nsIDOMLoadListener {

// nsIDOMLoadListener
NS_IMETHOD Load(nsIDOMEvent* aEvent);
NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent);
NS_IMETHOD Unload(nsIDOMEvent* aEvent);
NS_IMETHOD Abort(nsIDOMEvent* aEvent);
NS_IMETHOD Error(nsIDOMEvent* aEvent);
Expand Down Expand Up @@ -200,6 +202,18 @@ txLoadListenerProxy::Load(nsIDOMEvent* aEvent)
return NS_OK;
}

NS_IMETHODIMP
txLoadListenerProxy::BeforeUnload(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);

if (listener) {
return listener->BeforeUnload(aEvent);
}

return NS_OK;
}

NS_IMETHODIMP
txLoadListenerProxy::Unload(nsIDOMEvent* aEvent)
{
Expand Down Expand Up @@ -465,6 +479,14 @@ nsSyncLoader::Load(nsIDOMEvent* aEvent)
return NS_OK;
}

nsresult
nsSyncLoader::BeforeUnload(nsIDOMEvent* aEvent)
{
// Like, whatever.

return NS_OK;
}

nsresult
nsSyncLoader::Unload(nsIDOMEvent* aEvent)
{
Expand Down
104 changes: 53 additions & 51 deletions content/events/src/nsDOMEvent.cpp
Expand Up @@ -64,10 +64,10 @@
#include "nsIDOMMutationEvent.h"
#include "nsIURI.h"

static const char* const mEventNames[] = {
static const char* const sEventNames[] = {
"mousedown", "mouseup", "click", "dblclick", "mouseover",
"mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
"focus", "blur", "load", "unload", "abort", "error",
"focus", "blur", "load", "beforeunload", "unload", "abort", "error",
"submit", "reset", "change", "select", "input", "paint" ,"text",
"popupshowing", "popupshown", "popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
"dragenter", "dragover", "dragexit", "dragdrop", "draggesture", "resize",
Expand Down Expand Up @@ -1482,113 +1482,115 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
case NS_MOUSE_LEFT_BUTTON_DOWN:
case NS_MOUSE_MIDDLE_BUTTON_DOWN:
case NS_MOUSE_RIGHT_BUTTON_DOWN:
return mEventNames[eDOMEvents_mousedown];
return sEventNames[eDOMEvents_mousedown];
case NS_MOUSE_LEFT_BUTTON_UP:
case NS_MOUSE_MIDDLE_BUTTON_UP:
case NS_MOUSE_RIGHT_BUTTON_UP:
return mEventNames[eDOMEvents_mouseup];
return sEventNames[eDOMEvents_mouseup];
case NS_MOUSE_LEFT_CLICK:
case NS_MOUSE_MIDDLE_CLICK:
case NS_MOUSE_RIGHT_CLICK:
return mEventNames[eDOMEvents_click];
return sEventNames[eDOMEvents_click];
case NS_MOUSE_LEFT_DOUBLECLICK:
case NS_MOUSE_MIDDLE_DOUBLECLICK:
case NS_MOUSE_RIGHT_DOUBLECLICK:
return mEventNames[eDOMEvents_dblclick];
return sEventNames[eDOMEvents_dblclick];
case NS_MOUSE_ENTER_SYNTH:
return mEventNames[eDOMEvents_mouseover];
return sEventNames[eDOMEvents_mouseover];
case NS_MOUSE_EXIT_SYNTH:
return mEventNames[eDOMEvents_mouseout];
return sEventNames[eDOMEvents_mouseout];
case NS_MOUSE_MOVE:
return mEventNames[eDOMEvents_mousemove];
return sEventNames[eDOMEvents_mousemove];
case NS_KEY_UP:
return mEventNames[eDOMEvents_keyup];
return sEventNames[eDOMEvents_keyup];
case NS_KEY_DOWN:
return mEventNames[eDOMEvents_keydown];
return sEventNames[eDOMEvents_keydown];
case NS_KEY_PRESS:
return mEventNames[eDOMEvents_keypress];
return sEventNames[eDOMEvents_keypress];
case NS_FOCUS_CONTENT:
return mEventNames[eDOMEvents_focus];
return sEventNames[eDOMEvents_focus];
case NS_BLUR_CONTENT:
return mEventNames[eDOMEvents_blur];
return sEventNames[eDOMEvents_blur];
case NS_XUL_CLOSE:
return mEventNames[eDOMEvents_close];
return sEventNames[eDOMEvents_close];
case NS_PAGE_LOAD:
case NS_IMAGE_LOAD:
case NS_SCRIPT_LOAD:
return mEventNames[eDOMEvents_load];
return sEventNames[eDOMEvents_load];
case NS_BEFORE_PAGE_UNLOAD:
return sEventNames[eDOMEvents_beforeunload];
case NS_PAGE_UNLOAD:
return mEventNames[eDOMEvents_unload];
return sEventNames[eDOMEvents_unload];
case NS_IMAGE_ABORT:
return mEventNames[eDOMEvents_abort];
return sEventNames[eDOMEvents_abort];
case NS_IMAGE_ERROR:
case NS_SCRIPT_ERROR:
return mEventNames[eDOMEvents_error];
return sEventNames[eDOMEvents_error];
case NS_FORM_SUBMIT:
return mEventNames[eDOMEvents_submit];
return sEventNames[eDOMEvents_submit];
case NS_FORM_RESET:
return mEventNames[eDOMEvents_reset];
return sEventNames[eDOMEvents_reset];
case NS_FORM_CHANGE:
return mEventNames[eDOMEvents_change];
return sEventNames[eDOMEvents_change];
case NS_FORM_SELECTED:
return mEventNames[eDOMEvents_select];
return sEventNames[eDOMEvents_select];
case NS_FORM_INPUT:
return mEventNames[eDOMEvents_input];
return sEventNames[eDOMEvents_input];
case NS_PAINT:
return mEventNames[eDOMEvents_paint];
return sEventNames[eDOMEvents_paint];
case NS_RESIZE_EVENT:
return mEventNames[eDOMEvents_resize];
return sEventNames[eDOMEvents_resize];
case NS_SCROLL_EVENT:
return mEventNames[eDOMEvents_scroll];
return sEventNames[eDOMEvents_scroll];
case NS_TEXT_TEXT:
return mEventNames[eDOMEvents_text];
return sEventNames[eDOMEvents_text];
case NS_XUL_POPUP_SHOWING:
return mEventNames[eDOMEvents_popupShowing];
return sEventNames[eDOMEvents_popupShowing];
case NS_XUL_POPUP_SHOWN:
return mEventNames[eDOMEvents_popupShown];
return sEventNames[eDOMEvents_popupShown];
case NS_XUL_POPUP_HIDING:
return mEventNames[eDOMEvents_popupHiding];
return sEventNames[eDOMEvents_popupHiding];
case NS_XUL_POPUP_HIDDEN:
return mEventNames[eDOMEvents_popupHidden];
return sEventNames[eDOMEvents_popupHidden];
case NS_XUL_COMMAND:
return mEventNames[eDOMEvents_command];
return sEventNames[eDOMEvents_command];
case NS_XUL_BROADCAST:
return mEventNames[eDOMEvents_broadcast];
return sEventNames[eDOMEvents_broadcast];
case NS_XUL_COMMAND_UPDATE:
return mEventNames[eDOMEvents_commandupdate];
return sEventNames[eDOMEvents_commandupdate];
case NS_DRAGDROP_ENTER:
return mEventNames[eDOMEvents_dragenter];
return sEventNames[eDOMEvents_dragenter];
case NS_DRAGDROP_OVER_SYNTH:
return mEventNames[eDOMEvents_dragover];
return sEventNames[eDOMEvents_dragover];
case NS_DRAGDROP_EXIT_SYNTH:
return mEventNames[eDOMEvents_dragexit];
return sEventNames[eDOMEvents_dragexit];
case NS_DRAGDROP_DROP:
return mEventNames[eDOMEvents_dragdrop];
return sEventNames[eDOMEvents_dragdrop];
case NS_DRAGDROP_GESTURE:
return mEventNames[eDOMEvents_draggesture];
return sEventNames[eDOMEvents_draggesture];
case NS_SCROLLPORT_OVERFLOW:
return mEventNames[eDOMEvents_overflow];
return sEventNames[eDOMEvents_overflow];
case NS_SCROLLPORT_UNDERFLOW:
return mEventNames[eDOMEvents_underflow];
return sEventNames[eDOMEvents_underflow];
case NS_SCROLLPORT_OVERFLOWCHANGED:
return mEventNames[eDOMEvents_overflowchanged];
return sEventNames[eDOMEvents_overflowchanged];
case NS_MUTATION_SUBTREEMODIFIED:
return mEventNames[eDOMEvents_subtreemodified];
return sEventNames[eDOMEvents_subtreemodified];
case NS_MUTATION_NODEINSERTED:
return mEventNames[eDOMEvents_nodeinserted];
return sEventNames[eDOMEvents_nodeinserted];
case NS_MUTATION_NODEREMOVED:
return mEventNames[eDOMEvents_noderemoved];
return sEventNames[eDOMEvents_noderemoved];
case NS_MUTATION_NODEREMOVEDFROMDOCUMENT:
return mEventNames[eDOMEvents_noderemovedfromdocument];
return sEventNames[eDOMEvents_noderemovedfromdocument];
case NS_MUTATION_NODEINSERTEDINTODOCUMENT:
return mEventNames[eDOMEvents_nodeinsertedintodocument];
return sEventNames[eDOMEvents_nodeinsertedintodocument];
case NS_MUTATION_ATTRMODIFIED:
return mEventNames[eDOMEvents_attrmodified];
return sEventNames[eDOMEvents_attrmodified];
case NS_MUTATION_CHARACTERDATAMODIFIED:
return mEventNames[eDOMEvents_characterdatamodified];
return sEventNames[eDOMEvents_characterdatamodified];
case NS_CONTEXTMENU:
case NS_CONTEXTMENU_KEY:
return mEventNames[eDOMEvents_contextmenu];
return sEventNames[eDOMEvents_contextmenu];
default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions content/events/src/nsDOMEvent.h
Expand Up @@ -86,6 +86,7 @@ class nsDOMEvent : public nsIDOMKeyEvent,
eDOMEvents_focus,
eDOMEvents_blur,
eDOMEvents_load,
eDOMEvents_beforeunload,
eDOMEvents_unload,
eDOMEvents_abort,
eDOMEvents_error,
Expand Down

0 comments on commit 64ad19a

Please sign in to comment.