diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/DocumentLoadEvent.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/DocumentLoadEvent.java index bf7c5356d97..d5a4f0b50c6 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/DocumentLoadEvent.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/DocumentLoadEvent.java @@ -84,6 +84,27 @@ public class DocumentLoadEvent extends WebclientEvent { public static final long FETCH_INTERRUPT_EVENT_MASK = 1 << 8; + /** + *

This event indicates the current fetch is the start of an Ajax + * transaction.

+ */ + + public static final long START_AJAX_EVENT_MASK = 1 << 9; + + /** + *

This event indicates the current fetch is an Ajax + * transaction in an error state.

+ */ + + public static final long ERROR_AJAX_EVENT_MASK = 1 << 10; + + /** + *

This event indicates the current fetch is an Ajax + * transaction in that has completed.

+ */ + + public static final long END_AJAX_EVENT_MASK = 1 << 11; + // // Constructors // diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/PageInfoListener.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/PageInfoListener.java index 9cd15ce22c9..3295f8e0479 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/PageInfoListener.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/PageInfoListener.java @@ -59,6 +59,65 @@ package org.mozilla.webclient; * This entry will be a java.util.Map of all the response * headers.

* + *
For START_AJAX_EVENT_MASK type
+ + *

The map will contain the following keys and values:

+ + *
+ + *
headers
+ + *
a java.util.Map of all the request headers.
+ + *
method
+ + *
the request method for this event.
+ + *
readyState
+ + *
a String of the numerical value of the XMLHTTPRequest readyState
+ + *
+ + *
+ + *
For END_AJAX_EVENT_MASK type
+ * + *

The map will contain the following keys and values:

+ + *
+ + *
method
+ + *
the request method for this event.
+ + *
responseXML
+ + *
a org.w3c.dom.Document instance of the response XML.
+ + *
responseText
+ + *
a String instance of the response Text.
+ + *
status
+ + *
the response status string from the server, such as "200 + * OK".
+ + *
headers
+ + *
a java.util.Map of all the response headers.
+ + *
method
+ + *
the request method for this event.
+ + *
readyState
+ + *
a String of the numerical value of the XMLHTTPRequest readyState
+ + *
+ * * * diff --git a/mozilla/java/webclient/src_moz/AjaxListener.cpp b/mozilla/java/webclient/src_moz/AjaxListener.cpp index 45d8200c75e..f16b0d91a61 100755 --- a/mozilla/java/webclient/src_moz/AjaxListener.cpp +++ b/mozilla/java/webclient/src_moz/AjaxListener.cpp @@ -19,19 +19,34 @@ * Ed Burns */ +#include + #include "AjaxListener.h" #include "EmbedProgress.h" +#include "nsXPIDLString.h" +#include "nsString.h" + #include "nsServiceManagerUtils.h" #include "nsIObserverService.h" #include "nsIHttpChannel.h" #include "nsIRequest.h" #include "nsIXMLHTTPRequest.h" #include "nsIInterfaceRequestor.h" +#include "nsIDOMEvent.h" + +#include "NativeBrowserControl.h" +#include "NativeWrapperFactory.h" +#include "HttpHeaderVisitorImpl.h" #include "jni_util.h" -NS_IMPL_ISUPPORTS1(AjaxListener, nsIObserver) +#define LOADSTR NS_LITERAL_STRING("load") +#define ERRORSTR NS_LITERAL_STRING("error") + +NS_IMPL_ISUPPORTS2(AjaxListener, + nsIObserver, + nsIDOMEventListener) AjaxListener::AjaxListener(EmbedProgress *owner, JNIEnv *env, @@ -77,7 +92,23 @@ AjaxListener::Observe(nsISupports *aSubject, if (NS_SUCCEEDED(rv) && iface) { ajax = do_QueryInterface(iface, &rv); if (NS_SUCCEEDED(rv) && ajax) { - loadFlags = 0; + rv = ObserveAjax(request, channel, ajax, + AJAX_START); + if (NS_SUCCEEDED(rv)) { + // Hook ourselves up as a DOMEventListener + nsCOMPtr domTarget = + do_QueryInterface(ajax, &rv); + if (NS_SUCCEEDED(rv) && domTarget) { + rv = domTarget->AddEventListener(LOADSTR, + this, + PR_TRUE); + if (NS_SUCCEEDED(rv)) { + rv = domTarget->AddEventListener(ERRORSTR, + this, + PR_FALSE); + } + } + } } else { // It's ok if we don't have an xmlhttprequest @@ -95,6 +126,47 @@ AjaxListener::Observe(nsISupports *aSubject, return rv; } +// +// Methods from nsIDOMEventListener +// + +NS_IMETHODIMP +AjaxListener::HandleEvent(nsIDOMEvent *event) +{ + nsresult rv = NS_OK; + nsCOMPtr ajax; + nsCOMPtr eventTarget; + if (NS_SUCCEEDED(rv = event->GetTarget(getter_AddRefs(eventTarget)))) { + ajax = do_QueryInterface(eventTarget); + if (ajax) { + nsCOMPtr channel; + nsCOMPtr httpChannel; + nsCOMPtr request = nsnull; + nsAutoString type; + AJAX_STATE state; + + rv = ajax->GetChannel(getter_AddRefs(channel)); + if (NS_SUCCEEDED(rv) && channel) { + httpChannel = do_QueryInterface(channel); + if (httpChannel) { + request = do_QueryInterface(channel); + if (request) { + rv = event->GetType(type); + if (NS_SUCCEEDED(rv)) { + state = type.EqualsIgnoreCase("load", 4) ? + AJAX_END : AJAX_ERROR; + rv = ObserveAjax(request, httpChannel, ajax, + state); + } + } + } + } + } + } + return rv; +} + + // // Webclient private methods // @@ -125,3 +197,140 @@ AjaxListener::StopObserving() return rv; } +NS_IMETHODIMP +AjaxListener::ObserveAjax(nsIRequest *request, + nsIHttpChannel *channel, + nsIXMLHttpRequest *ajax, + AJAX_STATE state) +{ + nsresult rv = NS_OK; + NativeBrowserControl *browserControl = mOwner->GetOwner(); + NativeWrapperFactory *wrapperFactory = + browserControl->GetWrapperFactory(); + ShareInitContext *pShareContext = &(wrapperFactory->shareContext); + jobject properties = ::util_NewGlobalRef(mJNIEnv, + ::util_CreatePropertiesObject(mJNIEnv, (jobject)pShareContext)); + PRUint32 responseStatus = 0; + PRInt32 readyState = 0; + char buf[20]; + jstring jStr = nsnull; + + browserControl->ContentStateChange(); + + nsXPIDLCString uriString; + nsCAutoString cstr; + EmbedProgress::RequestToURIString(request, getter_Copies(uriString)); + const char * uriCStr = (const char *) uriString; + // don't report "about:" URL events. + if (uriString && 5 < uriString.Length() && + 0 == strncmp("about:", uriCStr, 6)) { + return NS_OK; + } + + // store the request URI + jStr = (jstring) ::util_NewGlobalRef(mJNIEnv, + ::util_NewStringUTF(mJNIEnv, + (nsnull != uriCStr ? uriCStr : ""))); + ::util_StoreIntoPropertiesObject(mJNIEnv, properties, URI_VALUE, jStr, + (jobject) pShareContext); + + + // store the headers + HttpHeaderVisitorImpl *visitor = + new HttpHeaderVisitorImpl(mJNIEnv, properties, + (jobject) pShareContext); + if (AJAX_START == state) { + channel->VisitRequestHeaders(visitor); + } + else { + channel->VisitResponseHeaders(visitor); + } + delete visitor; + + // store the request method + if (NS_SUCCEEDED(rv = channel->GetRequestMethod(cstr))) { + jStr = + (jstring) ::util_NewGlobalRef(mJNIEnv, + ::util_NewStringUTF(mJNIEnv, cstr.get())); + + ::util_StoreIntoPropertiesObject(mJNIEnv, properties, + METHOD_VALUE, jStr, + (jobject) pShareContext); + } + + // store the ready state + if (NS_SUCCEEDED(rv = ajax->GetReadyState(&readyState))) { + WC_ITOA(readyState, buf, 10); + jStr = ::util_NewStringUTF(mJNIEnv, buf); + ::util_StoreIntoPropertiesObject(mJNIEnv, properties, READY_STATE_KEY, + (jobject) jStr, + (jobject) pShareContext); + } + + if (AJAX_END == state || AJAX_ERROR == state) { + nsAutoString autoString; + // store the response status + if (NS_SUCCEEDED(rv = ajax->GetStatus(&responseStatus))){ + if (NS_SUCCEEDED(rv = ajax->GetStatusText(cstr))) { + autoString.AppendInt(responseStatus); + autoString.AppendWithConversion(" "); + autoString.AppendWithConversion(cstr.get()); + + jStr = (jstring) ::util_NewGlobalRef(mJNIEnv, + ::util_NewString(mJNIEnv, + autoString.get(), + autoString.Length())); + + ::util_StoreIntoPropertiesObject(mJNIEnv, properties, + STATUS_VALUE, jStr, + (jobject) pShareContext); + + } + } + + // store the response text + if (NS_SUCCEEDED(rv = ajax->GetResponseText(autoString))) { + jStr = (jstring) ::util_NewGlobalRef(mJNIEnv, + ::util_NewString(mJNIEnv, + autoString.get(), + autoString.Length())); + + ::util_StoreIntoPropertiesObject(mJNIEnv, properties, + RESPONSE_TEXT_KEY, jStr, + (jobject) pShareContext); + + } + } + + DOCUMENT_LOADER_EVENT_MASK_NAMES maskValue = END_AJAX_EVENT_MASK; + switch (state) { + case AJAX_START: + maskValue = START_AJAX_EVENT_MASK; + break; + case AJAX_END: + maskValue = END_AJAX_EVENT_MASK; + break; + case AJAX_ERROR: + maskValue = ERROR_AJAX_EVENT_MASK; + break; + default: + PR_ASSERT(PR_FALSE); + break; + } + + ::util_SendEventToJava(nsnull, + mEventRegistration, + DOCUMENT_LOAD_LISTENER_CLASSNAME, + DocumentLoader_maskValues[maskValue], + properties); + + return NS_OK; +} + + +/******************* + + + + +**********/ diff --git a/mozilla/java/webclient/src_moz/AjaxListener.h b/mozilla/java/webclient/src_moz/AjaxListener.h index eebff88e05d..cd3d97c0a26 100755 --- a/mozilla/java/webclient/src_moz/AjaxListener.h +++ b/mozilla/java/webclient/src_moz/AjaxListener.h @@ -24,16 +24,27 @@ #include "nsIObserver.h" +#include "nsIDOMEventListener.h" #include "jni.h" class EmbedProgress; +class nsIXMLHttpRequest; +class nsIHttpChannel; +class nsIRequest; -class AjaxListener : public nsIObserver +class AjaxListener : public nsIObserver, public nsIDOMEventListener { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER + NS_DECL_NSIDOMEVENTLISTENER + + enum AJAX_STATE { + AJAX_START, + AJAX_END, + AJAX_ERROR + }; AjaxListener(EmbedProgress *owner, JNIEnv *env, jobject eventRegistration); @@ -43,6 +54,12 @@ public: NS_IMETHOD StopObserving(void); private: + + NS_IMETHOD ObserveAjax(nsIRequest *request, + nsIHttpChannel *channel, + nsIXMLHttpRequest *ajax, + AJAX_STATE state); + EmbedProgress* mOwner; JNIEnv *mJNIEnv; jobject mEventRegistration; diff --git a/mozilla/java/webclient/src_moz/EmbedProgress.cpp b/mozilla/java/webclient/src_moz/EmbedProgress.cpp index e028288ac5e..3daf9e388e1 100644 --- a/mozilla/java/webclient/src_moz/EmbedProgress.cpp +++ b/mozilla/java/webclient/src_moz/EmbedProgress.cpp @@ -90,15 +90,6 @@ EmbedProgress::SetEventRegistration(jobject yourEventRegistration) ::util_ThrowExceptionToJava(env, "Exception: EmbedProgress->SetEventRegistration(): can't create NewGlobalRef\n\tfor eventRegistration"); rv = NS_ERROR_FAILURE; } - - return rv; -} - -nsresult -EmbedProgress::SetCapturePageInfo(jboolean newState) -{ - mCapturePageInfo = newState; - nsresult rv = NS_OK; AjaxListener *observer = nsnull; rv = GetAjaxListener(&observer); if (observer && NS_SUCCEEDED(rv)) { @@ -109,6 +100,14 @@ EmbedProgress::SetCapturePageInfo(jboolean newState) observer->StopObserving(); } } + + return rv; +} + +nsresult +EmbedProgress::SetCapturePageInfo(jboolean newState) +{ + mCapturePageInfo = newState; return NS_OK; } @@ -479,6 +478,11 @@ EmbedProgress::OnSecurityChange(nsIWebProgress *aWebProgress, return NS_OK; } +NativeBrowserControl* EmbedProgress::GetOwner() +{ + return mOwner; +} + NS_IMETHODIMP EmbedProgress::GetAjaxListener(AjaxListener* *result) { diff --git a/mozilla/java/webclient/src_moz/EmbedProgress.h b/mozilla/java/webclient/src_moz/EmbedProgress.h index d10b93e649a..9c58d862758 100644 --- a/mozilla/java/webclient/src_moz/EmbedProgress.h +++ b/mozilla/java/webclient/src_moz/EmbedProgress.h @@ -47,13 +47,14 @@ class EmbedProgress : public nsIWebProgressListener, NS_DECL_NSIWEBPROGRESSLISTENER + NativeBrowserControl *GetOwner(); + static void RequestToURIString (nsIRequest *aRequest, char **aString); + private: NS_IMETHOD GetAjaxListener(AjaxListener** result); NS_IMETHOD RemoveAjaxListener(void); - static void RequestToURIString (nsIRequest *aRequest, char **aString); - NativeBrowserControl *mOwner; AjaxListener *mAjaxListener; diff --git a/mozilla/java/webclient/src_share/jni_util.cpp b/mozilla/java/webclient/src_share/jni_util.cpp index 6843280a6e6..b053efd7d76 100644 --- a/mozilla/java/webclient/src_share/jni_util.cpp +++ b/mozilla/java/webclient/src_share/jni_util.cpp @@ -55,6 +55,9 @@ jobject SCREEN_X_KEY; jobject SCREEN_Y_KEY; jobject CLIENT_X_KEY; jobject CLIENT_Y_KEY; +jobject READY_STATE_KEY; +jobject RESPONSE_TEXT_KEY; +jobject RESPONSE_XML_KEY; jobject CHAR_CODE; jobject KEY_CODE; jobject ALT_KEY; @@ -104,6 +107,9 @@ char * DocumentLoader_maskNames[] = { STATUS_URL_LOAD_EVENT_MASK_VALUE, UNKNOWN_CONTENT_EVENT_MASK_VALUE, FETCH_INTERRUPT_EVENT_MASK_VALUE, + START_AJAX_EVENT_MASK_VALUE, + ERROR_AJAX_EVENT_MASK_VALUE, + END_AJAX_EVENT_MASK_VALUE, nsnull }; @@ -167,6 +173,21 @@ jboolean util_InitStringConstants() ::util_NewStringUTF(env, "ClientY")))) { return JNI_FALSE; } + if (nsnull == (READY_STATE_KEY = + ::util_NewGlobalRef(env, (jobject) + ::util_NewStringUTF(env, "readyState")))) { + return JNI_FALSE; + } + if (nsnull == (RESPONSE_TEXT_KEY = + ::util_NewGlobalRef(env, (jobject) + ::util_NewStringUTF(env, "responseText")))) { + return JNI_FALSE; + } + if (nsnull == (RESPONSE_XML_KEY = + ::util_NewGlobalRef(env, (jobject) + ::util_NewStringUTF(env, "responseXML")))) { + return JNI_FALSE; + } if (nsnull == (CHAR_CODE = ::util_NewGlobalRef(env, (jobject) ::util_NewStringUTF(env, "KeyChar")))) { diff --git a/mozilla/java/webclient/src_share/jni_util.h b/mozilla/java/webclient/src_share/jni_util.h index 8fdfb4f51a2..dd41241a7d1 100644 --- a/mozilla/java/webclient/src_share/jni_util.h +++ b/mozilla/java/webclient/src_share/jni_util.h @@ -70,6 +70,9 @@ extern jobject SCREEN_X_KEY; extern jobject SCREEN_Y_KEY; extern jobject CLIENT_X_KEY; extern jobject CLIENT_Y_KEY; +extern jobject READY_STATE_KEY; +extern jobject RESPONSE_TEXT_KEY; +extern jobject RESPONSE_XML_KEY; extern jobject CHAR_CODE; extern jobject KEY_CODE; extern jobject ALT_KEY; @@ -164,6 +167,9 @@ typedef enum { #define STATUS_URL_LOAD_EVENT_MASK_VALUE "STATUS_URL_LOAD_EVENT_MASK" #define UNKNOWN_CONTENT_EVENT_MASK_VALUE "UNKNOWN_CONTENT_EVENT_MASK" #define FETCH_INTERRUPT_EVENT_MASK_VALUE "FETCH_INTERRUPT_EVENT_MASK" +#define START_AJAX_EVENT_MASK_VALUE "START_AJAX_EVENT_MASK" +#define ERROR_AJAX_EVENT_MASK_VALUE "ERROR_AJAX_EVENT_MASK" +#define END_AJAX_EVENT_MASK_VALUE "END_AJAX_EVENT_MASK" #define MOUSE_DOWN_EVENT_MASK_VALUE "MOUSE_DOWN_EVENT_MASK" #define MOUSE_UP_EVENT_MASK_VALUE "MOUSE_UP_EVENT_MASK" @@ -186,6 +192,9 @@ typedef enum { STATUS_URL_LOAD_EVENT_MASK, UNKNOWN_CONTENT_EVENT_MASK, FETCH_INTERRUPT_EVENT_MASK, + START_AJAX_EVENT_MASK, + ERROR_AJAX_EVENT_MASK, + END_AJAX_EVENT_MASK, NUMBER_OF_DOCUMENT_LOADER_MASK_NAMES } DOCUMENT_LOADER_EVENT_MASK_NAMES; diff --git a/mozilla/java/webclient/test/manual/src/classes/org/mozilla/webclient/test/TestBrowser.java b/mozilla/java/webclient/test/manual/src/classes/org/mozilla/webclient/test/TestBrowser.java index a4ccc4106cb..19fbf18a6b4 100644 --- a/mozilla/java/webclient/test/manual/src/classes/org/mozilla/webclient/test/TestBrowser.java +++ b/mozilla/java/webclient/test/manual/src/classes/org/mozilla/webclient/test/TestBrowser.java @@ -241,6 +241,17 @@ public class TestBrowser extends JPanel { if (event instanceof DocumentLoadEvent) { System.out.println("URI: " + map.get("URI")); switch ((int) event.getType()) { + case ((int) DocumentLoadEvent.END_AJAX_EVENT_MASK): + System.out.println("status: " + + map.get("status")); + System.out.println("responseText: " + + map.get("responseText")); + // INTENTIONAL FALL THROUGH + case ((int) DocumentLoadEvent.START_AJAX_EVENT_MASK): + System.out.println("requestMethod: " + + map.get("method")); + // INTENTIONAL FALL THROUGH + case ((int) DocumentLoadEvent.START_URL_LOAD_EVENT_MASK): System.out.println("requestMethod: " + map.get("method"));