Fixing bug 68215. Adding support for the onbeforeunload event. r=peterv@propagandism.org, sr=brendan@mozilla.org

This commit is contained in:
jst%mozilla.jstenback.com 2004-02-11 06:09:51 +00:00
Родитель 6cca3beefc
Коммит 6ca4c1a78e
35 изменённых файлов: 630 добавлений и 330 удалений

Просмотреть файл

@ -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
@ -414,9 +418,11 @@ protected:
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
@ -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()
{
@ -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;
}
@ -1121,6 +1225,8 @@ DocumentViewerImpl::Destroy()
mPresShell = nsnull;
}
mContainer = nsnull;
return NS_OK;
}

Просмотреть файл

@ -117,6 +117,7 @@ public:
// 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);
@ -157,6 +158,7 @@ public:
// 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);
@ -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)
{
@ -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)
{

Просмотреть файл

@ -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",
@ -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;
}

Просмотреть файл

@ -86,6 +86,7 @@ public:
eDOMEvents_focus,
eDOMEvents_blur,
eDOMEvents_load,
eDOMEvents_beforeunload,
eDOMEvents_unload,
eDOMEvents_abort,
eDOMEvents_error,

Просмотреть файл

@ -229,7 +229,8 @@ static const EventDispatchData sLoadEvents[] = {
{NS_SCRIPT_LOAD, HANDLER(&nsIDOMLoadListener::Load), NS_EVENT_BITS_LOAD_LOAD},
{NS_PAGE_UNLOAD, HANDLER(&nsIDOMLoadListener::Unload),NS_EVENT_BITS_LOAD_UNLOAD},
{NS_IMAGE_ERROR, HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR},
{NS_SCRIPT_ERROR,HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR}
{NS_SCRIPT_ERROR,HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR},
{NS_BEFORE_PAGE_UNLOAD,HANDLER(&nsIDOMLoadListener::BeforeUnload), NS_EVENT_BITS_LOAD_BEFORE_UNLOAD}
};
static const EventDispatchData sPaintEvents[] = {
@ -842,6 +843,10 @@ nsEventListenerManager::GetIdentifiersForType(nsIAtom* aType,
*aArrayType = eEventArrayType_Load;
*aFlags = NS_EVENT_BITS_LOAD_LOAD;
}
else if (aType == nsLayoutAtoms::onbeforeunload) {
*aArrayType = eEventArrayType_Load;
*aFlags = NS_EVENT_BITS_LOAD_BEFORE_UNLOAD;
}
else if (aType == nsLayoutAtoms::onunload) {
*aArrayType = eEventArrayType_Load;
*aFlags = NS_EVENT_BITS_LOAD_UNLOAD;
@ -1465,7 +1470,6 @@ nsresult nsEventListenerManager::HandleEvent(nsIPresContext* aPresContext,
keys which cause window deletion, can destroy this object
before we're ready. */
nsCOMPtr<nsIEventListenerManager> kungFuDeathGrip(this);
nsString empty;
nsVoidArray *listeners = nsnull;
if (aEvent->message == NS_CONTEXTMENU || aEvent->message == NS_CONTEXTMENU_KEY) {
@ -1476,6 +1480,7 @@ nsresult nsEventListenerManager::HandleEvent(nsIPresContext* aPresContext,
}
}
const EventTypeData* typeData = nsnull;
const EventDispatchData* dispData = nsnull;
@ -1500,7 +1505,7 @@ nsresult nsEventListenerManager::HandleEvent(nsIPresContext* aPresContext,
if (aEvent->eventStructType == NS_MUTATION_EVENT)
ret = NS_NewDOMMutationEvent(aDOMEvent, aPresContext, aEvent);
else
ret = NS_NewDOMUIEvent(aDOMEvent, aPresContext, empty, aEvent);
ret = NS_NewDOMUIEvent(aDOMEvent, aPresContext, EmptyString(), aEvent);
}
if (NS_SUCCEEDED(ret)) {
@ -1590,225 +1595,119 @@ nsresult
nsEventListenerManager::FlipCaptureBit(PRInt32 aEventTypes,
PRBool aInitCapture)
{
EventArrayType arrayType;
nsListenerStruct *ls;
EventArrayType arrayType = eEventArrayType_None;
PRUint8 bits;
if (aEventTypes & nsIDOMNSEvent::MOUSEDOWN) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_MOUSEDOWN;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_MOUSEDOWN;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_MOUSEDOWN;
}
if (aEventTypes & nsIDOMNSEvent::MOUSEUP) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_MOUSEUP;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_MOUSEUP;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_MOUSEUP;
}
if (aEventTypes & nsIDOMNSEvent::MOUSEOVER) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_MOUSEOVER;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_MOUSEOVER;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_MOUSEOVER;
}
if (aEventTypes & nsIDOMNSEvent::MOUSEOUT) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_MOUSEOUT;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_MOUSEOUT;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_MOUSEOUT;
}
if (aEventTypes & nsIDOMNSEvent::MOUSEMOVE) {
arrayType = eEventArrayType_MouseMotion;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSEMOTION_MOUSEMOVE;
}
if (aEventTypes & nsIDOMNSEvent::CLICK) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_CLICK;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_CLICK;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_CLICK;
}
if (aEventTypes & nsIDOMNSEvent::DBLCLICK) {
arrayType = eEventArrayType_Mouse;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_DBLCLICK;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_DBLCLICK;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_DBLCLICK;
}
if (aEventTypes & nsIDOMNSEvent::KEYDOWN) {
arrayType = eEventArrayType_Key;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_KEY_KEYDOWN;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_KEY_KEYDOWN;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_KEY_KEYDOWN;
}
if (aEventTypes & nsIDOMNSEvent::KEYUP) {
arrayType = eEventArrayType_Key;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_KEY_KEYUP;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_KEY_KEYUP;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_KEY_KEYUP;
}
if (aEventTypes & nsIDOMNSEvent::KEYPRESS) {
arrayType = eEventArrayType_Key;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_KEY_KEYPRESS;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_KEY_KEYPRESS;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_KEY_KEYPRESS;
}
if (aEventTypes & nsIDOMNSEvent::DRAGDROP) {
arrayType = eEventArrayType_Drag;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_DRAG_ENTER;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_DRAG_ENTER;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_DRAG_ENTER;
}
/*if (aEventTypes & nsIDOMNSEvent::MOUSEDRAG) {
arrayType = kIDOMMouseListenerarrayType;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_MOUSE_MOUSEDOWN;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_MOUSE_MOUSEDOWN;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_MOUSE_MOUSEDOWN;
}*/
if (aEventTypes & nsIDOMNSEvent::FOCUS) {
arrayType = eEventArrayType_Focus;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FOCUS_FOCUS;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FOCUS_FOCUS;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FOCUS_FOCUS;
}
if (aEventTypes & nsIDOMNSEvent::BLUR) {
arrayType = eEventArrayType_Focus;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FOCUS_BLUR;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FOCUS_BLUR;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FOCUS_BLUR;
}
if (aEventTypes & nsIDOMNSEvent::SELECT) {
arrayType = eEventArrayType_Form;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FORM_SELECT;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FORM_SELECT;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FORM_SELECT;
}
if (aEventTypes & nsIDOMNSEvent::CHANGE) {
arrayType = eEventArrayType_Form;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FORM_CHANGE;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FORM_CHANGE;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FORM_CHANGE;
}
if (aEventTypes & nsIDOMNSEvent::RESET) {
arrayType = eEventArrayType_Form;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FORM_RESET;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FORM_RESET;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FORM_RESET;
}
if (aEventTypes & nsIDOMNSEvent::SUBMIT) {
arrayType = eEventArrayType_Form;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_FORM_SUBMIT;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_FORM_SUBMIT;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_FORM_SUBMIT;
}
if (aEventTypes & nsIDOMNSEvent::LOAD) {
arrayType = eEventArrayType_Load;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_LOAD_LOAD;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_LOAD_LOAD;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_LOAD_LOAD;
}
if (aEventTypes & nsIDOMNSEvent::UNLOAD) {
arrayType = eEventArrayType_Load;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_LOAD_UNLOAD;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_LOAD_UNLOAD;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_LOAD_UNLOAD;
}
if (aEventTypes & nsIDOMNSEvent::ABORT) {
arrayType = eEventArrayType_Load;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_LOAD_ABORT;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_LOAD_ABORT;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_LOAD_ABORT;
}
if (aEventTypes & nsIDOMNSEvent::ERROR) {
arrayType = eEventArrayType_Load;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_LOAD_ERROR;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_LOAD_ERROR;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_LOAD_ERROR;
}
if (aEventTypes & nsIDOMNSEvent::RESIZE) {
arrayType = eEventArrayType_Paint;
ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_PAINT_RESIZE;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_PAINT_RESIZE;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
bits = NS_EVENT_BITS_PAINT_RESIZE;
}
if (aEventTypes & nsIDOMNSEvent::SCROLL) {
arrayType = eEventArrayType_Scroll;
ls = FindJSEventListener(arrayType);
bits = NS_EVENT_BITS_PAINT_RESIZE;
}
if (arrayType != eEventArrayType_None) {
nsListenerStruct *ls = FindJSEventListener(arrayType);
if (ls) {
if (aInitCapture) ls->mSubTypeCapture |= NS_EVENT_BITS_PAINT_RESIZE;
else ls->mSubTypeCapture &= ~NS_EVENT_BITS_PAINT_RESIZE;
if (aInitCapture)
ls->mSubTypeCapture |= bits;
else
ls->mSubTypeCapture &= ~bits;
ls->mFlags |= NS_EVENT_FLAG_CAPTURE;
}
}
return NS_OK;
}
@ -2002,7 +1901,6 @@ nsEventListenerManager::FixContextMenuEvent(nsIPresContext* aPresContext,
nsCOMPtr<nsIDOMElement> currentFocus;
nsCOMPtr<nsIDocument> doc;
nsIPresShell* shell = aPresContext->PresShell();
nsString empty;
if (aEvent->message == NS_CONTEXTMENU_KEY) {
shell->GetDocument(getter_AddRefs(doc));
@ -2027,7 +1925,7 @@ nsEventListenerManager::FixContextMenuEvent(nsIPresContext* aPresContext,
// the client X/Y will be 0,0. We can make use of that if the widget is null.
if (aEvent->message == NS_CONTEXTMENU_KEY)
NS_IF_RELEASE(((nsGUIEvent*)aEvent)->widget); // nulls out widget
ret = NS_NewDOMUIEvent(aDOMEvent, aPresContext, empty, aEvent);
ret = NS_NewDOMUIEvent(aDOMEvent, aPresContext, EmptyString(), aEvent);
}
if (NS_SUCCEEDED(ret)) {

Просмотреть файл

@ -292,11 +292,12 @@ protected:
#define NS_EVENT_BITS_FORM_INPUT 0x10
//nsIDOMLoadListener
#define NS_EVENT_BITS_LOAD_NONE 0x00
#define NS_EVENT_BITS_LOAD_LOAD 0x01
#define NS_EVENT_BITS_LOAD_UNLOAD 0x02
#define NS_EVENT_BITS_LOAD_ABORT 0x04
#define NS_EVENT_BITS_LOAD_ERROR 0x08
#define NS_EVENT_BITS_LOAD_NONE 0x00
#define NS_EVENT_BITS_LOAD_LOAD 0x01
#define NS_EVENT_BITS_LOAD_UNLOAD 0x02
#define NS_EVENT_BITS_LOAD_ABORT 0x04
#define NS_EVENT_BITS_LOAD_ERROR 0x08
#define NS_EVENT_BITS_LOAD_BEFORE_UNLOAD 0x10
//nsIDOMXULListener
#define NS_EVENT_BITS_XUL_NONE 0x00

Просмотреть файл

@ -1809,6 +1809,7 @@ PRBool nsGenericHTMLElement::IsEventName(nsIAtom* aName)
aName == nsLayoutAtoms::onmousemove ||
aName == nsLayoutAtoms::onload ||
aName == nsLayoutAtoms::onunload ||
aName == nsLayoutAtoms::onbeforeunload ||
aName == nsLayoutAtoms::onabort ||
aName == nsLayoutAtoms::onerror ||
aName == nsLayoutAtoms::onfocus ||

Просмотреть файл

@ -301,9 +301,9 @@ nsHTMLScriptEventHandler::Invoke(nsISupports *aTargetObject,
}
// Invoke the event handler script...
PRBool dummy;
return scriptContext->CallEventHandler(scriptObject, funcObject, aArgCount,
aArgs, &dummy);
jsval dummy;
return scriptContext->CallEventHandler(scriptObject, (JSObject *)funcObject,
aArgCount, (jsval *)aArgs, &dummy);
}

Просмотреть файл

@ -2020,15 +2020,28 @@ nsHTMLDocument::OpenCommon(nsIURI* aSourceURI)
}
nsCOMPtr<nsIDocShell> docshell = do_QueryReferent(mDocumentContainer);
nsresult rv = NS_OK;
// Stop current loads targeted at the window this document is in.
if (mScriptGlobalObject && docshell) {
nsCOMPtr<nsIContentViewer> cv;
docshell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
PRBool okToUnload;
rv = cv->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// We don't want to unload, so stop here, but don't throw an
// exception.
return NS_OK;
}
}
nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(docshell));
webnav->Stop(nsIWebNavigation::STOP_NETWORK);
}
nsresult rv = NS_OK;
// The open occurred after the document finished loading.
// So we reset the document and create a new one.
nsCOMPtr<nsIChannel> channel;
@ -2242,7 +2255,11 @@ nsHTMLDocument::WriteCommon(const nsAString& aText,
if (!mParser) {
rv = Open();
if (NS_FAILED(rv)) {
// If Open() fails, or if it didn't create a parser (as it won't
// if the user chose to not discard the current document through
// onbeforeunload), don't write anything.
if (NS_FAILED(rv) || !mParser) {
return rv;
}
} else if (IsXHTML()) {

Просмотреть файл

@ -147,6 +147,7 @@ LAYOUT_ATOM(viewProperty, "ViewProperty")
// Alphabetical list of event handler names
LAYOUT_ATOM(onabort, "onabort")
LAYOUT_ATOM(onbeforeunload, "onbeforeunload")
LAYOUT_ATOM(onblur, "onblur")
LAYOUT_ATOM(onbroadcast, "onbroadcast")
LAYOUT_ATOM(onchange, "onchange")

Просмотреть файл

@ -232,6 +232,7 @@ public:
NS_DECL_NSIREQUESTOBSERVER
NS_IMETHOD Load(nsIDOMEvent* aEvent);
NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; };
NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; };
NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; };
NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; };

Просмотреть файл

@ -228,6 +228,7 @@ nsDocShell::nsDocShell():
mAllowMetaRedirects(PR_TRUE),
mAllowImages(PR_TRUE),
mFocusDocFirst(PR_FALSE),
mHasFocus(PR_FALSE),
mCreatingDocument(PR_FALSE),
mUseErrorPages(PR_FALSE),
mAllowAuth(PR_TRUE),
@ -236,15 +237,15 @@ nsDocShell::nsDocShell():
mFiredUnloadEvent(PR_FALSE),
mEODForCurrentDocument(PR_FALSE),
mURIResultedInDocument(PR_FALSE),
mUseExternalProtocolHandler(PR_FALSE),
mDisallowPopupWindows(PR_FALSE),
mUseExternalProtocolHandler(PR_FALSE),
mIsBeingDestroyed(PR_FALSE),
mIsExecutingOnLoadHandler(PR_FALSE),
mIsPrintingOrPP(PR_FALSE),
mEditorData(nsnull),
mParent(nsnull),
mTreeOwner(nsnull),
mChromeEventHandler(nsnull),
mIsPrintingOrPP(PR_FALSE)
mChromeEventHandler(nsnull)
{
#ifdef PR_LOGGING
if (! gDocShellLog)
@ -816,21 +817,18 @@ nsDocShell::PrepareForNewContentModel()
NS_IMETHODIMP
nsDocShell::FireUnloadNotification()
{
nsresult rv;
if (mContentViewer && !mFiredUnloadEvent) {
mFiredUnloadEvent = PR_TRUE;
rv = mContentViewer->Unload();
mContentViewer->Unload();
PRInt32 i, n = mChildren.Count();
for (i = 0; i < n; i++) {
nsIDocShellTreeItem* item = (nsIDocShellTreeItem*) mChildren.ElementAt(i);
if(item) {
nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
if (shell) {
rv = shell->FireUnloadNotification();
}
nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item));
if (shell) {
shell->FireUnloadNotification();
}
}
}
@ -2996,20 +2994,27 @@ nsDocShell::Create()
mPrefs = do_GetService(NS_PREF_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRBool tmpbool;
// i don't want to read this pref in every time we load a url
// so read it in once here and be done with it...
mPrefs->GetBoolPref("network.protocols.useSystemDefaults",
&mUseExternalProtocolHandler);
mPrefs->GetBoolPref("browser.block.target_new_window", &mDisallowPopupWindows);
mPrefs->GetBoolPref("browser.frames.enabled", &mAllowSubframes);
&tmpbool);
mUseExternalProtocolHandler = tmpbool;
mPrefs->GetBoolPref("browser.block.target_new_window", &tmpbool);
mDisallowPopupWindows = tmpbool;
mPrefs->GetBoolPref("browser.frames.enabled", &tmpbool);
mAllowSubframes = tmpbool;
// Check pref to see if we should prevent frameset spoofing
mPrefs->GetBoolPref("browser.frame.validate_origin", &mValidateOrigin);
mPrefs->GetBoolPref("browser.frame.validate_origin", &tmpbool);
mValidateOrigin = tmpbool;
// Should we use XUL error pages instead of alerts if possible?
PRBool useErrorPages = PR_FALSE;
mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &useErrorPages);
mUseErrorPages = useErrorPages;
mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool);
mUseErrorPages = tmpbool;
return NS_OK;
}
@ -4464,6 +4469,8 @@ nsDocShell::CreateContentViewer(const char *aContentType,
nsIRequest * request,
nsIStreamListener ** aContentHandler)
{
*aContentHandler = nsnull;
// Can we check the content type of the current content viewer
// and reuse it without destroying it and re-creating it?
@ -5095,6 +5102,19 @@ nsDocShell::InternalLoad(nsIURI * aURI,
return rv;
}
// Check if the page doesn't want to be unloaded. The javascript:
// protocol handler deals with this for javascript: URLs.
if (!bIsJavascript && mContentViewer) {
PRBool okToUnload;
rv = mContentViewer->PermitUnload(&okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
// The user chose not to unload the page, interrupt the
// load.
return NS_OK;
}
}
//
// Load is being targetted at this docshell so return an error if the
// docshell is in the process of being destroyed.
@ -6867,8 +6887,8 @@ nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState *aLayoutHistoryState)
//*** nsRefreshTimer: Object Management
//*****************************************************************************
nsRefreshTimer::nsRefreshTimer():mRepeat(PR_FALSE), mDelay(0),
mMetaRefresh(PR_FALSE)
nsRefreshTimer::nsRefreshTimer()
: mDelay(0), mRepeat(PR_FALSE), mMetaRefresh(PR_FALSE)
{
}

Просмотреть файл

@ -149,10 +149,9 @@ public:
nsCOMPtr<nsIDocShell> mDocShell;
nsCOMPtr<nsIURI> mURI;
PRBool mRepeat;
PRInt32 mDelay;
PRBool mMetaRefresh;
PRPackedBool mRepeat;
PRPackedBool mMetaRefresh;
protected:
virtual ~nsRefreshTimer();
@ -359,31 +358,34 @@ protected:
// Somebody give me better name
nsCOMPtr<nsISHEntry> mLSHE;
PRBool mFiredUnloadEvent;
PRPackedBool mFiredUnloadEvent;
// this flag is for bug #21358. a docshell may load many urls
// which don't result in new documents being created (i.e. a new content viewer)
// we want to make sure we don't call a on load event more than once for a given
// content viewer.
PRBool mEODForCurrentDocument;
PRBool mURIResultedInDocument;
PRPackedBool mEODForCurrentDocument;
PRPackedBool mURIResultedInDocument;
PRPackedBool mIsBeingDestroyed;
// used to keep track of whether user click links should be handle by us
// or immediately kicked out to an external application. mscott: eventually
// i'm going to try to fold this up into the uriloader where it belongs but i haven't
// figured out how to do that yet.
PRBool mUseExternalProtocolHandler;
PRPackedBool mUseExternalProtocolHandler;
// Disallow popping up new windows with target=
PRBool mDisallowPopupWindows;
PRPackedBool mDisallowPopupWindows;
// Validate window targets to prevent frameset spoofing
PRBool mValidateOrigin;
PRBool mIsBeingDestroyed;
PRPackedBool mValidateOrigin;
PRPackedBool mIsExecutingOnLoadHandler;
// Indicates that a DocShell in this "docshell tree" is printing
PRPackedBool mIsPrintingOrPP;
// Editor stuff
nsDocShellEditorData* mEditorData; // editor data, if any
@ -398,8 +400,6 @@ protected:
nsIDocShellTreeOwner * mTreeOwner; // Weak Reference
nsIChromeEventHandler * mChromeEventHandler; //Weak Reference
// Indicates that a DocShell in this "docshell tree" is printing
PRBool mIsPrintingOrPP;
public:
class InterfaceRequestorProxy : public nsIInterfaceRequestor {

Просмотреть файл

@ -25,6 +25,7 @@ interface nsIContentViewer : nsISupports
void loadStart(in nsISupports aDoc);
void loadComplete(in unsigned long aStatus);
boolean permitUnload();
void unload();
/**

Просмотреть файл

@ -63,6 +63,13 @@ public:
*/
NS_IMETHOD Load(nsIDOMEvent* aEvent) = 0;
/**
* Processes a page beforeUnload event
* @param aMouseEvent @see nsIDOMEvent.h
* @returns whether the event was consumed or ignored. @see nsresult
*/
NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) = 0;
/**
* Processes a page unload event
* @param aMouseEvent @see nsIDOMEvent.h

Просмотреть файл

@ -195,9 +195,9 @@ public:
* @param aBoolResult out parameter returning boolean function result, or
* true if the result was not boolean.
**/
virtual nsresult CallEventHandler(void* aTarget, void* aHandler,
PRUint32 argc, void* argv,
PRBool* aBoolResult) = 0;
virtual nsresult CallEventHandler(JSObject* aTarget, JSObject* aHandler,
uintN argc, jsval* argv,
jsval* rval) = 0;
/**
* Bind an already-compiled event handler function to a name in the given

Просмотреть файл

@ -1,2 +1,4 @@
JSURLLoadBlockedWarning=Attempt to load a javascript: URL from one host\nin a window displaying content from another host\nwas blocked by the security manager.
WindowCloseBlockedWarning=Scripts may not close windows that were not opened by script.
WindowCloseBlockedWarning=Scripts may not close windows that were not opened by script.
OnBeforeUnloadPreMessage=Are you sure you want to navigate away from this page?
OnBeforeUnloadPostMessage=Press OK to continue, or Cancel to stay on the current page.

Просмотреть файл

@ -240,6 +240,7 @@ protected:
static jsval sOnchange_id;
static jsval sOnselect_id;
static jsval sOnload_id;
static jsval sOnbeforeunload_id;
static jsval sOnunload_id;
static jsval sOnabort_id;
static jsval sOnerror_id;

Просмотреть файл

@ -3563,6 +3563,7 @@ GlobalWindowImpl::Close()
}
}
}
return NS_OK;
}
}
@ -3578,8 +3579,13 @@ GlobalWindowImpl::Close()
mDocShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
PRBool canClose;
cv->RequestWindowClose(&canClose);
if (!canClose)
rv = cv->PermitUnload(&canClose);
if (NS_SUCCEEDED(rv) && !canClose)
return NS_OK;
rv = cv->RequestWindowClose(&canClose);
if (NS_SUCCEEDED(rv) && !canClose)
return NS_OK;
}
@ -5133,7 +5139,7 @@ GlobalWindowImpl::RunTimeout(nsTimeoutImpl *aTimeout)
lateness = PR_IntervalToMilliseconds(lateness);
timeout->mArgv[timeout->mArgc] = INT_TO_JSVAL((jsint) lateness);
PRBool dummy;
jsval dummy;
rv = mContext->CallEventHandler(mJSObject, timeout->mFunObj,
timeout->mArgc + 1, timeout->mArgv,
&dummy);

Просмотреть файл

@ -1195,10 +1195,10 @@ nsJSContext::CompileFunction(void* aTarget,
}
nsresult
nsJSContext::CallEventHandler(void *aTarget, void *aHandler, PRUint32 argc,
void *argv, PRBool *aBoolResult)
nsJSContext::CallEventHandler(JSObject *aTarget, JSObject *aHandler,
uintN argc, jsval *argv, jsval *rval)
{
*aBoolResult = PR_TRUE;
*rval = JSVAL_VOID;
if (!mScriptsEnabled) {
return NS_OK;
@ -1226,21 +1226,21 @@ nsJSContext::CallEventHandler(void *aTarget, void *aHandler, PRUint32 argc,
rv = sSecurityManager->CheckFunctionAccess(mContext, aHandler, aTarget);
if (NS_SUCCEEDED(rv)) {
jsval val;
jsval funval = OBJECT_TO_JSVAL(aHandler);
PRBool ok = ::JS_CallFunctionValue(mContext, (JSObject *)aTarget, funval,
argc, (jsval *)argv, &val);
PRBool ok = ::JS_CallFunctionValue(mContext, aTarget, funval, argc, argv,
rval);
ScriptEvaluated(PR_TRUE);
if (ok) {
*aBoolResult = !JSVAL_IS_BOOLEAN(val) || JSVAL_TO_BOOLEAN(val);
} else {
if (!ok) {
// Tell XPConnect about any pending exceptions. This is needed
// to avoid dropping JS exceptions in case we got here through
// nested calls through XPConnect.
NotifyXPCIfExceptionPending(mContext);
// Don't pass back results from failed calls.
*rval = JSVAL_VOID;
}
}

Просмотреть файл

@ -94,9 +94,8 @@ public:
PRUint32 aLineNo,
PRBool aShared,
void** aHandler);
virtual nsresult CallEventHandler(void *aTarget, void *aHandler,
PRUint32 argc, void *argv,
PRBool *aBoolResult);
virtual nsresult CallEventHandler(JSObject *aTarget, JSObject *aHandler,
uintN argc, jsval *argv, jsval* rval);
virtual nsresult BindCompiledEventHandler(void *aTarget,
nsIAtom *aName,
void *aHandler);

Просмотреть файл

@ -36,6 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsJSEventListener.h"
#include "nsJSUtils.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsIServiceManager.h"
@ -52,9 +53,9 @@
*/
nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
nsISupports *aObject)
: nsIJSEventListener(aContext, aObject)
: nsIJSEventListener(aContext, aObject),
mReturnResult(nsReturnResult_eNotSet)
{
mReturnResult = nsReturnResult_eNotSet;
}
nsJSEventListener::~nsJSEventListener()
@ -168,21 +169,46 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
argc = 1;
}
PRBool jsBoolResult;
jsval rval;
rv = mContext->CallEventHandler(obj, JSVAL_TO_OBJECT(funval), argc, argv,
&jsBoolResult);
&rval);
if (argv != &arg) {
::JS_PopArguments(cx, stackPtr);
}
if (NS_SUCCEEDED(rv)) {
// if the handler returned false and its sense is not reversed, or
// the handler returned true and its sense is reversed from the
// usual (false means cancel), then prevent default.
if (eventString.Equals(NS_LITERAL_STRING("onbeforeunload"))) {
nsCOMPtr<nsIPrivateDOMEvent> priv(do_QueryInterface(aEvent));
NS_ENSURE_TRUE(priv, NS_ERROR_UNEXPECTED);
if (!(jsBoolResult ^ (mReturnResult == nsReturnResult_eReverseReturnResult)))
aEvent->PreventDefault();
nsEvent* event;
priv->GetInternalNSEvent(&event);
NS_ENSURE_TRUE(event && event->message == NS_BEFORE_PAGE_UNLOAD,
NS_ERROR_UNEXPECTED);
nsBeforePageUnloadEvent *beforeUnload =
NS_STATIC_CAST(nsBeforePageUnloadEvent *, event);
if (!JSVAL_IS_VOID(rval)) {
aEvent->PreventDefault();
if (JSVAL_IS_STRING(rval)) {
beforeUnload->text = nsDependentJSString(JSVAL_TO_STRING(rval));
}
}
} else {
// if the handler returned false and its sense is not reversed,
// or the handler returned true and its sense is reversed from
// the usual (false means cancel), then prevent default.
PRBool jsBoolResult = !JSVAL_IS_BOOLEAN(rval) || JSVAL_TO_BOOLEAN(rval);
if (jsBoolResult ==
(mReturnResult == nsReturnResult_eReverseReturnResult)) {
aEvent->PreventDefault();
}
}
}
return rv;

Просмотреть файл

@ -68,6 +68,8 @@
#include "nsEscape.h"
#include "nsIJSContextStack.h"
#include "nsIWebNavigation.h"
#include "nsIDocShell.h"
#include "nsIContentViewer.h"
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
@ -534,10 +536,34 @@ nsJSChannel::InternalOpen(PRBool aIsAsync, nsIStreamListener *aListener,
mStreamChannel->GetLoadFlags(&loadFlags);
if (loadFlags & LOAD_DOCUMENT_URI) {
// We're loaded as the document channel. Stop all pending
// network loads.
// We're loaded as the document channel. If we go on,
// we'll blow away the current document. Make sure that's
// ok. If so, stop all pending network loads.
rv = StopAll();
nsCOMPtr<nsIInterfaceRequestor> cb;
mStreamChannel->GetNotificationCallbacks(getter_AddRefs(cb));
nsCOMPtr<nsIDocShell> docShell(do_GetInterface(cb));
if (docShell) {
nsCOMPtr<nsIContentViewer> cv;
docShell->GetContentViewer(getter_AddRefs(cv));
if (cv) {
PRBool okToUnload;
if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) &&
!okToUnload) {
// The user didn't want to unload the current
// page, translate this into an undefined
// return from the javascript: URL...
rv = NS_ERROR_DOM_RETVAL_UNDEFINED;
}
}
}
if (NS_SUCCEEDED(rv)) {
rv = StopAll();
}
}
if (NS_SUCCEEDED(rv)) {
@ -549,7 +575,9 @@ nsJSChannel::InternalOpen(PRBool aIsAsync, nsIStreamListener *aListener,
rv = mStreamChannel->Open(aResult);
}
}
} else {
}
if (NS_FAILED(rv)) {
// Propagate the failure down to the underlying channel...
mStreamChannel->Cancel(rv);
}

Просмотреть файл

@ -301,6 +301,12 @@ nsDOMParser::Load(nsIDOMEvent* aEvent)
return NS_OK;
}
nsresult
nsDOMParser::BeforeUnload(nsIDOMEvent* aEvent)
{
return NS_OK;
}
nsresult
nsDOMParser::Unload(nsIDOMEvent* aEvent)
{

Просмотреть файл

@ -64,6 +64,7 @@ public:
// 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);

Просмотреть файл

@ -74,6 +74,18 @@ nsLoadListenerProxy::Load(nsIDOMEvent* aEvent)
return NS_OK;
}
NS_IMETHODIMP
nsLoadListenerProxy::BeforeUnload(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener(do_QueryReferent(mParent));
if (listener) {
return listener->BeforeUnload(aEvent);
}
return NS_OK;
}
NS_IMETHODIMP
nsLoadListenerProxy::Unload(nsIDOMEvent* aEvent)
{

Просмотреть файл

@ -66,6 +66,7 @@ public:
// 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);

Просмотреть файл

@ -1435,6 +1435,12 @@ nsXMLHttpRequest::Unload(nsIDOMEvent* aEvent)
return NS_OK;
}
nsresult
nsXMLHttpRequest::BeforeUnload(nsIDOMEvent* aEvent)
{
return NS_OK;
}
nsresult
nsXMLHttpRequest::Abort(nsIDOMEvent* aEvent)
{

Просмотреть файл

@ -89,6 +89,7 @@ public:
// 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);

Просмотреть файл

@ -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
@ -414,9 +418,11 @@ protected:
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
@ -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()
{
@ -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;
}
@ -1121,6 +1225,8 @@ DocumentViewerImpl::Destroy()
mPresShell = nsnull;
}
mContainer = nsnull;
return NS_OK;
}

Просмотреть файл

@ -147,6 +147,7 @@ LAYOUT_ATOM(viewProperty, "ViewProperty")
// Alphabetical list of event handler names
LAYOUT_ATOM(onabort, "onabort")
LAYOUT_ATOM(onbeforeunload, "onbeforeunload")
LAYOUT_ATOM(onblur, "onblur")
LAYOUT_ATOM(onbroadcast, "onbroadcast")
LAYOUT_ATOM(onchange, "onchange")

Просмотреть файл

@ -44,6 +44,7 @@
#include "nsRect.h"
#include "nsEvent.h"
#include "nsHashtable.h"
#include "nsString.h"
// nsIDOMEvent contains a long enum which includes a member called ERROR,
// which conflicts with something that Windows defines somewhere.
@ -60,33 +61,34 @@ class nsIMenuItem;
class nsIAccessible;
class nsIContent;
class nsIURI;
/**
* Event Struct Types
*/
#define NS_EVENT 1
#define NS_GUI_EVENT 2
#define NS_SIZE_EVENT 3
#define NS_SIZEMODE_EVENT 4
#define NS_ZLEVEL_EVENT 5
#define NS_PAINT_EVENT 6
#define NS_SCROLLBAR_EVENT 7
#define NS_INPUT_EVENT 8
#define NS_KEY_EVENT 9
#define NS_MOUSE_EVENT 10
#define NS_MENU_EVENT 11
#define NS_SCRIPT_ERROR_EVENT 12
#define NS_TEXT_EVENT 13
#define NS_COMPOSITION_EVENT 14
#define NS_RECONVERSION_EVENT 15
#define NS_MOUSE_SCROLL_EVENT 16
#define NS_SCROLLPORT_EVENT 18
#define NS_ACCESSIBLE_EVENT 20
#define NS_FORM_EVENT 21
#define NS_FOCUS_EVENT 22
#define NS_POPUP_EVENT 23
#define NS_APPCOMMAND_EVENT 24
#define NS_POPUPBLOCKED_EVENT 25
#define NS_EVENT 1
#define NS_GUI_EVENT 2
#define NS_SIZE_EVENT 3
#define NS_SIZEMODE_EVENT 4
#define NS_ZLEVEL_EVENT 5
#define NS_PAINT_EVENT 6
#define NS_SCROLLBAR_EVENT 7
#define NS_INPUT_EVENT 8
#define NS_KEY_EVENT 9
#define NS_MOUSE_EVENT 10
#define NS_MENU_EVENT 11
#define NS_SCRIPT_ERROR_EVENT 12
#define NS_TEXT_EVENT 13
#define NS_COMPOSITION_EVENT 14
#define NS_RECONVERSION_EVENT 15
#define NS_MOUSE_SCROLL_EVENT 16
#define NS_SCROLLPORT_EVENT 18
#define NS_ACCESSIBLE_EVENT 20
#define NS_FORM_EVENT 21
#define NS_FOCUS_EVENT 22
#define NS_POPUP_EVENT 23
#define NS_APPCOMMAND_EVENT 24
#define NS_POPUPBLOCKED_EVENT 25
#define NS_BEFORE_PAGE_UNLOAD_EVENT 26
#define NS_EVENT_FLAG_NONE 0x0000
@ -205,6 +207,16 @@ struct nsScriptErrorEvent : public nsEvent
const PRUnichar* fileName;
};
struct nsBeforePageUnloadEvent : public nsEvent
{
nsBeforePageUnloadEvent(PRUint32 msg)
: nsEvent(msg, NS_BEFORE_PAGE_UNLOAD_EVENT)
{
}
nsString text;
};
/**
* Window resize event
*/
@ -723,6 +735,7 @@ enum nsDragDropEventStatus {
#define NS_IMAGE_ABORT (NS_STREAM_EVENT_START + 3)
#define NS_IMAGE_ERROR (NS_STREAM_EVENT_START + 4)
#define NS_SCRIPT_LOAD (NS_STREAM_EVENT_START + 5)
#define NS_BEFORE_PAGE_UNLOAD (NS_STREAM_EVENT_START + 6)
#define NS_FORM_EVENT_START 1200
#define NS_FORM_SUBMIT (NS_FORM_EVENT_START)

Просмотреть файл

@ -1489,26 +1489,25 @@ PRBool nsWebShellWindow::ExecuteCloseHandler()
than it otherwise would.) */
nsCOMPtr<nsIWebShellWindow> kungFuDeathGrip(this);
nsresult rv;
nsCOMPtr<nsIScriptGlobalObjectOwner> globalObjectOwner(do_QueryInterface(mWebShell));
nsCOMPtr<nsIScriptGlobalObject> globalObject;
nsCOMPtr<nsIScriptGlobalObject> globalObject(do_GetInterface(mWebShell));
if (globalObjectOwner) {
if (NS_SUCCEEDED(globalObjectOwner->GetScriptGlobalObject(getter_AddRefs(globalObject))) && globalObject) {
nsCOMPtr<nsIContentViewer> contentViewer;
if (NS_SUCCEEDED(mDocShell->GetContentViewer(getter_AddRefs(contentViewer)))) {
nsCOMPtr<nsIDocumentViewer> docViewer;
nsCOMPtr<nsIPresContext> presContext;
docViewer = do_QueryInterface(contentViewer);
if (docViewer && NS_SUCCEEDED(docViewer->GetPresContext(getter_AddRefs(presContext)))) {
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event(NS_XUL_CLOSE);
rv = globalObject->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
if (NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault)
return PR_TRUE;
// else fall through and return PR_FALSE
}
}
if (globalObject) {
nsCOMPtr<nsIContentViewer> contentViewer;
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
nsCOMPtr<nsIDocumentViewer> docViewer(do_QueryInterface(contentViewer));
if (docViewer) {
nsCOMPtr<nsIPresContext> presContext;
docViewer->GetPresContext(getter_AddRefs(presContext));
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event(NS_XUL_CLOSE);
nsresult rv = globalObject->HandleDOMEvent(presContext, &event, nsnull,
NS_EVENT_FLAG_INIT, &status);
if (NS_SUCCEEDED(rv) && status == nsEventStatus_eConsumeNoDefault)
return PR_TRUE;
// else fall through and return PR_FALSE
}
}

Просмотреть файл

@ -2279,7 +2279,8 @@ function maybeInitPopupContext()
function WindowIsClosing()
{
var browser = getBrowser();
var numtabs = browser.mTabContainer.childNodes.length;
var cn = browser.mTabContainer.childNodes;
var numtabs = cn.length;
var reallyClose = true;
if (numtabs > 1) {
@ -2307,5 +2308,13 @@ function WindowIsClosing()
}
} //if the warn-me pref was true
} //if multiple tabs are open
for (var i = 0; reallyClose && i < numtabs; ++i) {
var ds = browser.getBrowserForTab(cn[i]).docShell;
if (ds.contentViewer && !ds.contentViewer.permitUnload())
reallyClose = false;
}
return reallyClose;
}

Просмотреть файл

@ -852,11 +852,11 @@
else
this.mTabContainer.selectedItem = aTab;
while (this.mTabContainer.lastChild != aTab)
this.removeTab(this.mTabContainer.lastChild);
while (aTab.previousSibling)
this.removeTab(aTab.previousSibling);
var childNodes = this.mTabContainer.childNodes;
for (var i = childNodes.length - 1; i >= 0; --i) {
if (childNodes[i] != aTab)
this.removeTab(childNodes[i]);
}
]]>
</body>
</method>
@ -884,6 +884,11 @@
return;
}
var ds = this.getBrowserForTab(aTab).docShell;
if (ds.contentViewer && !ds.contentViewer.permitUnload())
return;
if (l == 2) {
var autohide = this.mPrefs.getBoolPref("browser.tabs.autoHide");
if (autohide)