350 lines
9.2 KiB
C++
350 lines
9.2 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "prtypes.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsITimer.h"
|
|
#include "nsITimerCallback.h"
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
#include "nsIScriptContextOwner.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIScriptGlobalObjectData.h"
|
|
#include "nsIScriptObjectOwner.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsINameSpaceManager.h"
|
|
#include "nsHTMLAtoms.h"
|
|
|
|
#include "nsGfxAutoTextControlFrame.h"
|
|
|
|
|
|
static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID);
|
|
static NS_DEFINE_IID(kIScriptObjectOwnerIID, NS_ISCRIPTOBJECTOWNER_IID);
|
|
static NS_DEFINE_IID(kIScriptGlobalObjectDataIID, NS_ISCRIPTGLOBALOBJECTDATA_IID);
|
|
|
|
extern nsresult NS_NewNativeTextControlFrame(nsIFrame** aNewFrame);
|
|
|
|
|
|
nsresult NS_NewGfxAutoTextControlFrame(nsIFrame** aNewFrame)
|
|
{
|
|
NS_PRECONDITION(aNewFrame, "null OUT ptr");
|
|
if (nsnull == aNewFrame)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*aNewFrame = new nsGfxAutoTextControlFrame;
|
|
if (nsnull == aNewFrame)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsresult result = ((nsGfxAutoTextControlFrame*)(*aNewFrame))->InitTextControl();
|
|
if (NS_FAILED(result))
|
|
{ // can't properly initialized ender, probably it isn't installed
|
|
delete *aNewFrame;
|
|
result = NS_NewNativeTextControlFrame(aNewFrame);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
char* nsGfxAutoTextControlFrame::eventName[] = {"onstartlookup", "onautocomplete"};
|
|
|
|
|
|
nsGfxAutoTextControlFrame::nsGfxAutoTextControlFrame()
|
|
: mUseBlurr(PR_FALSE),
|
|
mLookupTimer(nsnull),
|
|
mLookupInterval(300)
|
|
{
|
|
PRInt32 i;
|
|
for (i = 0; i < LAST_ID; i ++)
|
|
{
|
|
mEvtHdlrContext[i] = nsnull;
|
|
mEvtHdlrScript[i] = nsnull;
|
|
}
|
|
}
|
|
|
|
|
|
nsGfxAutoTextControlFrame::~nsGfxAutoTextControlFrame()
|
|
{
|
|
KillTimer();
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::Init(nsIPresContext& aPresContext,
|
|
nsIContent* aContent,
|
|
nsIFrame* aParent,
|
|
nsIStyleContext* aContext,
|
|
nsIFrame* aPrevInFlow)
|
|
{
|
|
ReadAttributes(aContent);
|
|
return(Inherited::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow));
|
|
}
|
|
|
|
nsresult nsGfxAutoTextControlFrame::HandleEvent(nsIPresContext& aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus& aEventStatus)
|
|
{
|
|
if (nsEventStatus_eConsumeNoDefault == aEventStatus)
|
|
return NS_OK;
|
|
|
|
switch(aEvent->message)
|
|
{
|
|
case NS_KEY_UP: //Set lookup timer only when user release the key and if the key isn't return or enter
|
|
if (NS_KEY_EVENT == aEvent->eventStructType)
|
|
{
|
|
KillTimer();
|
|
nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
|
|
switch (keyEvent->keyCode)
|
|
{
|
|
case NS_VK_ENTER : break;
|
|
case NS_VK_RETURN : break;
|
|
|
|
case NS_VK_DELETE :
|
|
case NS_VK_BACK :
|
|
if (mUseBlurr)
|
|
PrimeTimer();
|
|
break;
|
|
|
|
default :
|
|
if (mUseBlurr)
|
|
{
|
|
nsString emptyStr("");
|
|
SetAutoCompleteString(emptyStr);
|
|
}
|
|
PrimeTimer();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NS_KEY_DOWN: //If user press return or enter, fire onautocomplete
|
|
if (NS_KEY_EVENT == aEvent->eventStructType)
|
|
{
|
|
nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
|
|
switch (keyEvent->keyCode)
|
|
{
|
|
case NS_VK_ENTER : ExecuteScriptEventHandler(ONAUTOCOMPLETE_ID); break;
|
|
case NS_VK_RETURN : ExecuteScriptEventHandler(ONAUTOCOMPLETE_ID); break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(Inherited::HandleEvent(aPresContext, aEvent, aEventStatus));
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue)
|
|
{
|
|
if (nsHTMLAtoms::autocomplete == aName)
|
|
{
|
|
SetAutoCompleteString(aValue);
|
|
//return NS_OK;
|
|
}
|
|
|
|
return(Inherited::SetProperty(aName, aValue));
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::GetProperty(nsIAtom* aName, nsString& aValue)
|
|
{
|
|
if (nsHTMLAtoms::autocomplete == aName)
|
|
{
|
|
//GetAutoCompleteString(aValue);
|
|
//return NS_OK;
|
|
}
|
|
return(Inherited::GetProperty(aName, aValue));
|
|
}
|
|
|
|
|
|
void nsGfxAutoTextControlFrame::ReadAttributes(nsIContent* aContent)
|
|
{
|
|
nsString val;
|
|
|
|
if (NS_SUCCEEDED(aContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::autocompletetimeout, val)))
|
|
if (! val.IsEmpty())
|
|
{
|
|
PRInt32 aErrorCode;
|
|
mLookupInterval = val.ToInteger(&aErrorCode);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(aContent->GetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::autocompletetype, val)))
|
|
{
|
|
if (! val.IsEmpty())
|
|
mUseBlurr = (val == "blurr");
|
|
}
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::SetAutoCompleteString(const nsString& val)
|
|
{
|
|
if (mEditor)
|
|
{
|
|
//ducarroz: I need to add the given string at the end of the input field data and select it...
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
void nsGfxAutoTextControlFrame::KillTimer()
|
|
{
|
|
if (mLookupTimer)
|
|
{
|
|
mLookupTimer->Cancel();
|
|
NS_RELEASE(mLookupTimer);
|
|
}
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::PrimeTimer()
|
|
{
|
|
KillTimer();
|
|
|
|
nsresult err = NS_NewTimer(&mLookupTimer);
|
|
if (NS_FAILED(err))
|
|
return err;
|
|
|
|
mLookupTimer->Init(TimerCallback, this, mLookupInterval);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* static */ void nsGfxAutoTextControlFrame::TimerCallback(nsITimer *aTimer, void *aClosure)
|
|
{
|
|
nsGfxAutoTextControlFrame* theAutoText = NS_REINTERPRET_CAST(nsGfxAutoTextControlFrame*, aClosure);
|
|
if (!theAutoText)
|
|
return;
|
|
|
|
theAutoText->ExecuteScriptEventHandler(ONSTARTLOOKUP_ID);
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::SetEventHandlers(PRInt32 handlerID)
|
|
{
|
|
if (nsnull == mContent)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsIDOMHTMLInputElement* inputElem = nsnull;
|
|
nsresult result = mContent->QueryInterface(kIDOMHTMLInputElementIID, (void**)&inputElem);
|
|
if ((NS_OK == result) && inputElem)
|
|
{
|
|
nsString value;
|
|
|
|
inputElem->GetAttribute(eventName[handlerID], value);
|
|
if (mEvtHdlrProp[handlerID] != value)
|
|
{
|
|
mEvtHdlrProp[handlerID] = value;
|
|
|
|
nsIDocument* doc = nsnull;
|
|
mContent->GetDocument(doc);
|
|
AddScriptEventHandler(handlerID, eventName[handlerID], value, doc);
|
|
}
|
|
|
|
NS_RELEASE(inputElem);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::AddScriptEventHandler(PRInt32 handlerID, const char* handlerName, const nsString& aFunc, nsIDocument* aDocument)
|
|
{
|
|
nsresult ret = NS_OK;
|
|
nsIScriptContext* context;
|
|
nsIScriptContextOwner* owner;
|
|
|
|
if (nsnull != aDocument)
|
|
{
|
|
owner = aDocument->GetScriptContextOwner();
|
|
if (owner)
|
|
{
|
|
if (NS_OK == owner->GetScriptContext(&context))
|
|
{
|
|
nsIScriptObjectOwner* cowner;
|
|
if (NS_OK == mContent->QueryInterface(kIScriptObjectOwnerIID,
|
|
(void**) &cowner))
|
|
{
|
|
JSObject *mScriptObject;
|
|
ret = BuildScriptEventHandler(context, cowner, handlerName, aFunc, &mScriptObject);
|
|
if (NS_SUCCEEDED(ret))
|
|
{
|
|
mEvtHdlrContext[handlerID] = context;
|
|
mEvtHdlrScript[handlerID] = mScriptObject;
|
|
}
|
|
NS_RELEASE(cowner);
|
|
}
|
|
NS_RELEASE(context);
|
|
}
|
|
NS_RELEASE(owner);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
nsresult nsGfxAutoTextControlFrame::BuildScriptEventHandler(nsIScriptContext* aContext, nsIScriptObjectOwner *aScriptObjectOwner,
|
|
const char *aName, const nsString& aFunc, JSObject **mScriptObject)
|
|
{
|
|
nsIScriptGlobalObject *global;
|
|
nsIScriptGlobalObjectData *globalData;
|
|
nsIPrincipal * prin = nsnull;
|
|
*mScriptObject = nsnull;
|
|
global = aContext->GetGlobalObject();
|
|
if (global && NS_SUCCEEDED(global->QueryInterface(kIScriptGlobalObjectDataIID, (void**)&globalData)))
|
|
{
|
|
if (NS_FAILED(globalData->GetPrincipal(& prin)))
|
|
{
|
|
NS_RELEASE(global);
|
|
NS_RELEASE(globalData);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_RELEASE(globalData);
|
|
}
|
|
NS_IF_RELEASE(global);
|
|
JSPrincipals *jsprin;
|
|
prin->GetJSPrincipals(&jsprin);
|
|
JSContext* mJSContext = (JSContext*)aContext->GetNativeContext();
|
|
if (NS_OK == aScriptObjectOwner->GetScriptObject(aContext, (void**)mScriptObject))
|
|
{
|
|
if (nsnull != aName)
|
|
{
|
|
JS_CompileUCFunctionForPrincipals(mJSContext, *mScriptObject, jsprin, aName,
|
|
0, nsnull, (jschar*)aFunc.GetUnicode(), aFunc.Length(),
|
|
nsnull, 0);
|
|
JSPRINCIPALS_DROP(mJSContext, jsprin);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
JSPRINCIPALS_DROP(mJSContext, jsprin);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult nsGfxAutoTextControlFrame::ExecuteScriptEventHandler(PRInt32 handlerID)
|
|
{
|
|
jsval funval, result;
|
|
SetEventHandlers(handlerID);
|
|
if (mEvtHdlrContext[handlerID] && mEvtHdlrScript[handlerID])
|
|
{
|
|
JSContext* mJSContext = (JSContext*)mEvtHdlrContext[handlerID]->GetNativeContext();
|
|
if (!JS_LookupProperty(mJSContext, mEvtHdlrScript[handlerID], eventName[handlerID], &funval))
|
|
return NS_ERROR_FAILURE;
|
|
if (JS_TypeOfValue(mJSContext, funval) != JSTYPE_FUNCTION)
|
|
return NS_OK;
|
|
JS_CallFunctionValue(mJSContext, mEvtHdlrScript[handlerID], funval, 0, nsnull, &result);
|
|
}
|
|
return NS_OK;
|
|
}
|