Bug #251418 --> Expose progress notification events through nsIXMLHttpRequest. Allow consumers of nsIXMLHttpRequest to

set a progress event listener. Listen for the http channel's nsIProgressEventSink notification and fire our new progress event
to the consumer.

r/sr=jst
This commit is contained in:
scott%scott-macgregor.org 2006-04-20 03:39:16 +00:00
parent fb1bc6a924
commit c866840e10
3 changed files with 193 additions and 3 deletions

View File

@ -315,6 +315,20 @@ interface nsIJSXMLHttpRequest : nsISupports {
*/
attribute nsIDOMEventListener onerror;
/**
* Meant to be a script-only mechanism for setting a progress event listener.
* The attribute is expected to be JavaScript function object. When
* the error event occurs, the function is invoked.
* This attribute should not be used from native code!!
* This event listener may be called multiple times during the open request.
*
* After the initial response, all event listeners will be cleared.
* Call open() before setting new event listeners.
*
* Mozilla only.
*/
attribute nsIDOMEventListener onprogress;
/**
* Meant to be a script-only mechanism for setting a callback function.
* The attribute is expected to be JavaScript function object. When the

View File

@ -285,6 +285,7 @@ NS_INTERFACE_MAP_BEGIN(nsXMLHttpRequest)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIHttpEventSink)
NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(XMLHttpRequest)
@ -429,6 +430,28 @@ nsXMLHttpRequest::SetOnerror(nsIDOMEventListener * aOnerror)
return NS_OK;
}
/* attribute nsIDOMEventListener onprogress; */
NS_IMETHODIMP
nsXMLHttpRequest::GetOnprogress(nsIDOMEventListener * *aOnprogress)
{
NS_ENSURE_ARG_POINTER(aOnprogress);
*aOnprogress = mOnProgressListener;
NS_IF_ADDREF(*aOnprogress);
return NS_OK;
}
NS_IMETHODIMP
nsXMLHttpRequest::SetOnprogress(nsIDOMEventListener * aOnprogress)
{
mOnProgressListener = aOnprogress;
mScriptContext = GetCurrentContext();
return NS_OK;
}
/* readonly attribute nsIChannel channel; */
NS_IMETHODIMP
nsXMLHttpRequest::GetChannel(nsIChannel **aChannel)
@ -806,6 +829,8 @@ nsXMLHttpRequest::ClearEventListeners()
mOnLoadListener = nsnull;
mOnErrorListener = nsnull;
mOnReadystatechangeListener = nsnull;
mOnProgressListener = nsnull;
}
already_AddRefed<nsIHttpChannel>
@ -891,9 +916,11 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
GetLoadGroup(getter_AddRefs(loadGroup));
// nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active,
// which in turn keeps STOP button from becoming active
// which in turn keeps STOP button from becoming active.
// If the consumer passed in a progress event handler we must load with nsIRequest::LOAD_NORMAL
// or necko won't generate any progress notifications
rv = NS_NewChannel(getter_AddRefs(mChannel), uri, nsnull, loadGroup,
nsnull, nsIRequest::LOAD_BACKGROUND);
nsnull, mOnProgressListener ? nsIRequest::LOAD_NORMAL : nsIRequest::LOAD_BACKGROUND);
if (NS_FAILED(rv)) return rv;
//mChannel->SetAuthTriedWithPrehost(authp);
@ -1778,6 +1805,38 @@ nsXMLHttpRequest::OnRedirect(nsIHttpChannel *aHttpChannel,
return NS_OK;
}
/////////////////////////////////////////////////////
// nsIProgressEventSink methods:
//
NS_IMETHODIMP
nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint32 aProgress, PRUint32 aProgressMax)
{
if (mOnProgressListener)
{
nsCOMPtr<nsIDOMEvent> event;
nsEvent evt(NS_EVENT_NULL ); // what name do we make up here?
nsresult rv = CreateEvent(&evt, getter_AddRefs(event));
NS_ENSURE_SUCCESS(rv, rv);
nsXMLHttpProgressEvent * progressEvent = new nsXMLHttpProgressEvent(event, aProgress, aProgressMax);
if (!progressEvent)
return NS_ERROR_OUT_OF_MEMORY;
event = do_QueryInterface(progressEvent);
NotifyEventListeners(mOnProgressListener, nsnull, event);
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLHttpRequest::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, const PRUnichar *aStatusArg)
{
// nothing to do here...
return NS_OK;
}
/////////////////////////////////////////////////////
// nsIInterfaceRequestor methods:
//
@ -1807,7 +1866,6 @@ nsXMLHttpRequest::GetInterface(const nsIID & aIID, void **aResult)
return QueryInterface(aIID, aResult);
}
NS_IMPL_ISUPPORTS1(nsXMLHttpRequest::nsHeaderVisitor, nsIHttpHeaderVisitor)
NS_IMETHODIMP nsXMLHttpRequest::
@ -1819,3 +1877,93 @@ nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
mHeaders.Append('\n');
return NS_OK;
}
// DOM event class to handle progress notifications
nsXMLHttpProgressEvent::nsXMLHttpProgressEvent(nsIDOMEvent * aInner, PRUint32 aCurrentProgress, PRUint32 aMaxProgress)
{
mInner = aInner;
mCurProgress = aCurrentProgress;
mMaxProgress = aMaxProgress;
}
nsXMLHttpProgressEvent::~nsXMLHttpProgressEvent()
{}
// QueryInterface implementation for nsXMLHttpRequest
NS_INTERFACE_MAP_BEGIN(nsXMLHttpProgressEvent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLSProgressEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMLSProgressEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMEvent)
NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(XMLHttpProgressEvent)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsXMLHttpProgressEvent)
NS_IMPL_RELEASE(nsXMLHttpProgressEvent)
NS_IMETHODIMP nsXMLHttpProgressEvent::GetInput(nsIDOMLSInput * *aInput)
{
*aInput = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetPosition(PRUint32 *aPosition)
{
*aPosition = mCurProgress;
return NS_OK;
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetTotalSize(PRUint32 *aTotalSize)
{
*aTotalSize = mMaxProgress;
return NS_OK;
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetType(nsAString & aType)
{
return mInner->GetType(aType);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetTarget(nsIDOMEventTarget * *aTarget)
{
return mInner->GetTarget(aTarget);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetCurrentTarget(nsIDOMEventTarget * *aCurrentTarget)
{
return mInner->GetCurrentTarget(aCurrentTarget);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetEventPhase(PRUint16 *aEventPhase)
{
return mInner->GetEventPhase(aEventPhase);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetBubbles(PRBool *aBubbles)
{
return mInner->GetBubbles(aBubbles);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetCancelable(PRBool *aCancelable)
{
return mInner->GetCancelable(aCancelable);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::GetTimeStamp(DOMTimeStamp *aTimeStamp)
{
return mInner->GetTimeStamp(aTimeStamp);
}
NS_IMETHODIMP nsXMLHttpProgressEvent::StopPropagation()
{
return mInner->StopPropagation();
}
NS_IMETHODIMP nsXMLHttpProgressEvent::PreventDefault()
{
return mInner->PreventDefault();
}
NS_IMETHODIMP nsXMLHttpProgressEvent::InitEvent(const nsAString & eventTypeArg, PRBool canBubbleArg, PRBool cancelableArg)
{
return mInner->InitEvent(eventTypeArg, canBubbleArg, cancelableArg);
}

View File

@ -57,6 +57,10 @@
#include "nsIHttpEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsIProgressEventSink.h"
#include "nsIDOMLSProgressEvent.h"
class nsILoadGroup;
class nsXMLHttpRequest : public nsIXMLHttpRequest,
@ -66,6 +70,7 @@ class nsXMLHttpRequest : public nsIXMLHttpRequest,
public nsIStreamListener,
public nsIHttpEventSink,
public nsIInterfaceRequestor,
public nsIProgressEventSink,
public nsSupportsWeakReference
{
public:
@ -102,6 +107,9 @@ public:
// nsIHttpEventSink
NS_DECL_NSIHTTPEVENTSINK
// nsIProgressEventSink
NS_DECL_NSIPROGRESSEVENTSINK
// nsIInterfaceRequestor
NS_DECL_NSIINTERFACEREQUESTOR
protected:
@ -139,6 +147,7 @@ protected:
nsCOMPtr<nsIDOMEventListener> mOnLoadListener;
nsCOMPtr<nsIDOMEventListener> mOnErrorListener;
nsCOMPtr<nsIDOMEventListener> mOnProgressListener;
nsCOMPtr<nsIOnReadyStateChangeHandler> mOnReadystatechangeListener;
@ -164,4 +173,23 @@ protected:
PRUint32 mState;
};
// helper class to expose a progress DOM Event
class nsXMLHttpProgressEvent : public nsIDOMLSProgressEvent
{
public:
nsXMLHttpProgressEvent(nsIDOMEvent * aInner, PRUint32 aCurrentProgress, PRUint32 aMaxProgress);
virtual ~nsXMLHttpProgressEvent();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMLSPROGRESSEVENT
NS_DECL_NSIDOMEVENT
protected:
nsCOMPtr<nsIDOMEvent> mInner;
PRUint32 mCurProgress;
PRUint32 mMaxProgress;
};
#endif