📄 kjs_events.cpp
字号:
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003 Apple Computer, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "khtml_part.h"
#include "kjs_window.h"
#include "kjs_events.h"
#include "kjs_events.lut.h"
#include "kjs_views.h"
#include "kjs_proxy.h"
#include "xml/dom_nodeimpl.h"
#include "xml/dom_docimpl.h"
#include "xml/dom2_eventsimpl.h"
#include "rendering/render_object.h"
#include "misc/loader.h"
#include <kdebug.h>
using namespace KJS;
using DOM::KeyboardEvent;
using DOM::EventImpl;
using DOM::NodeImpl;
// -------------------------------------------------------------------------
JSAbstractEventListener::JSAbstractEventListener(bool _html)
: html(_html)
{
}
JSAbstractEventListener::~JSAbstractEventListener()
{
}
void JSAbstractEventListener::handleEvent(DOM::Event &evt, bool isWindowEvent)
{
#ifdef KJS_DEBUGGER
if (KJSDebugWin::instance() && KJSDebugWin::instance()->inSession())
return;
#endif
Object listener = listenerObj();
Object win = windowObj();
KHTMLPart *part = static_cast<Window*>(win.imp())->part();
KJSProxy *proxy = 0;
if (part)
proxy = KJSProxy::proxy( part );
if (proxy && listener.implementsCall()) {
ref();
KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter());
ExecState *exec = interpreter->globalExec();
List args;
args.append(getDOMEvent(exec,evt));
Window *window = static_cast<Window*>(win.imp());
// Set the event we're handling in the Window object
window->setCurrentEvent( &evt );
// ... and in the interpreter
interpreter->setCurrentEvent( &evt );
#ifdef NOKIA_CHANGES
interpreter->resetStatementCount();
#endif
Object thisObj;
if (isWindowEvent) {
thisObj = win;
} else {
KJS::Interpreter::lock();
thisObj = Object::dynamicCast(getDOMNode(exec,evt.currentTarget()));
KJS::Interpreter::unlock();
}
KJS::Interpreter::lock();
Value retval = listener.call(exec, thisObj, args);
KJS::Interpreter::unlock();
window->setCurrentEvent( 0 );
interpreter->setCurrentEvent( 0 );
#if APPLE_CHANGES
if ( exec->hadException() ) {
KJS::Interpreter::lock();
char *message = exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii();
int lineNumber = exec->exception().toObject(exec).get(exec, "line").toInt32(exec);
UString sourceURL = exec->exception().toObject(exec).get(exec, "sourceURL").toString(exec);
KJS::Interpreter::unlock();
if (Interpreter::shouldPrintExceptions()) {
printf("(event handler):%s\n", message);
}
KWQ(part)->addMessageToConsole(message, lineNumber, sourceURL.qstring());
exec->clearException();
}
#else
if ( exec->hadException() )
exec->clearException();
#endif
else if (html)
{
QVariant ret = ValueToVariant(exec, retval);
if (ret.type() == QVariant::Bool && ret.toBool() == false)
evt.preventDefault();
}
DOM::DocumentImpl::updateDocumentsRendering();
deref();
}
}
DOM::DOMString JSAbstractEventListener::eventListenerType()
{
if (html)
return "_khtml_HTMLEventListener";
else
return "_khtml_JSEventListener";
}
// -------------------------------------------------------------------------
JSUnprotectedEventListener::JSUnprotectedEventListener(Object _listener, const Object &_win, bool _html)
: JSAbstractEventListener(_html)
, listener(_listener)
, win(_win)
{
if (_listener.imp()) {
static_cast<Window*>(win.imp())->jsUnprotectedEventListeners.insert(_listener.imp(), this);
}
}
JSUnprotectedEventListener::~JSUnprotectedEventListener()
{
if (listener.imp()) {
static_cast<Window*>(win.imp())->jsUnprotectedEventListeners.remove(listener.imp());
}
}
Object JSUnprotectedEventListener::listenerObj() const
{
return listener;
}
Object JSUnprotectedEventListener::windowObj() const
{
return win;
}
void JSUnprotectedEventListener::mark()
{
ObjectImp *listenerImp = listener.imp();
if (listenerImp && !listenerImp->marked())
listenerImp->mark();
}
// -------------------------------------------------------------------------
JSEventListener::JSEventListener(Object _listener, const Object &_win, bool _html)
: JSAbstractEventListener(_html)
, listener(_listener)
, win(_win)
{
//fprintf(stderr,"JSEventListener::JSEventListener this=%p listener=%p\n",this,listener.imp());
if (_listener.imp()) {
static_cast<Window*>(win.imp())->jsEventListeners.insert(_listener.imp(), this);
}
}
JSEventListener::~JSEventListener()
{
if (listener.imp()) {
static_cast<Window*>(win.imp())->jsEventListeners.remove(listener.imp());
}
//fprintf(stderr,"JSEventListener::~JSEventListener this=%p listener=%p\n",this,listener.imp());
}
Object JSEventListener::listenerObj() const
{
return listener;
}
Object JSEventListener::windowObj() const
{
return win;
}
// -------------------------------------------------------------------------
JSLazyEventListener::JSLazyEventListener(QString _code, const Object &_win, NodeImpl *_originalNode, int lineno)
: JSEventListener(Object(), _win, true),
code(_code),
parsed(false)
{
lineNumber = lineno;
// We don't retain the original node, because we assume it
// will stay alive as long as this handler object is around
// and we need to avoid a reference cycle. If JS transfers
// this handler to another node, parseCode will be called and
// then originalNode is no longer needed.
originalNode = _originalNode;
}
void JSLazyEventListener::handleEvent(DOM::Event &evt, bool isWindowEvent)
{
parseCode();
if (!listener.isNull()) {
JSEventListener::handleEvent(evt, isWindowEvent);
}
}
Object JSLazyEventListener::listenerObj() const
{
parseCode();
return listener;
}
void JSLazyEventListener::parseCode() const
{
if (!parsed) {
KHTMLPart *part = static_cast<Window*>(win.imp())->part();
KJSProxy *proxy = 0L;
if (part)
proxy = KJSProxy::proxy( part );
if (proxy) {
KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter());
ExecState *exec = interpreter->globalExec();
KJS::Interpreter::lock();
//KJS::Constructor constr(KJS::Global::current().get("Function").imp());
KJS::Object constr = interpreter->builtinFunction();
KJS::List args;
static ProtectedValue eventString = KJS::String("event");
UString sourceURL(part->m_url.url());
args.append(eventString);
args.append(KJS::String(code));
listener = constr.construct(exec, args, sourceURL, lineNumber); // ### is globalExec ok ?
KJS::Interpreter::unlock();
if (exec->hadException()) {
exec->clearException();
// failed to parse, so let's just make this listener a no-op
listener = Object();
} else if (originalNode) {
// Add the event's home element to the scope
// (and the document, and the form - see KJS::HTMLElement::eventHandlerScope)
ScopeChain scope = listener.scope();
KJS::Interpreter::lock();
Object thisObj = Object::dynamicCast(getDOMNode(exec, originalNode));
KJS::Interpreter::unlock();
if (!thisObj.isNull()) {
KJS::Interpreter::lock();
static_cast<DOMNode*>(thisObj.imp())->pushEventHandlerScope(exec, scope);
KJS::Interpreter::unlock();
listener.setScope(scope);
}
}
}
// no more need to keep the unparsed code around
code = QString();
if (!listener.isNull()) {
static_cast<Window*>(win.imp())->jsEventListeners.insert(listener.imp(),
(KJS::JSEventListener *)(this));
}
parsed = true;
}
}
Value KJS::getNodeEventListener(DOM::Node n, int eventId)
{
DOM::EventListener *listener = n.handle()->getHTMLEventListener(eventId);
JSEventListener *jsListener = static_cast<JSEventListener*>(listener);
if ( jsListener && jsListener->listenerObjImp() )
return jsListener->listenerObj();
else
return Null();
}
// -------------------------------------------------------------------------
const ClassInfo EventConstructor::info = { "EventConstructor", 0, &EventConstructorTable, 0 };
/*
@begin EventConstructorTable 3
CAPTURING_PHASE DOM::Event::CAPTURING_PHASE DontDelete|ReadOnly
AT_TARGET DOM::Event::AT_TARGET DontDelete|ReadOnly
BUBBLING_PHASE DOM::Event::BUBBLING_PHASE DontDelete|ReadOnly
# Reverse-engineered from Netscape
MOUSEDOWN 1 DontDelete|ReadOnly
MOUSEUP 2 DontDelete|ReadOnly
MOUSEOVER 4 DontDelete|ReadOnly
MOUSEOUT 8 DontDelete|ReadOnly
MOUSEMOVE 16 DontDelete|ReadOnly
MOUSEDRAG 32 DontDelete|ReadOnly
CLICK 64 DontDelete|ReadOnly
DBLCLICK 128 DontDelete|ReadOnly
KEYDOWN 256 DontDelete|ReadOnly
KEYUP 512 DontDelete|ReadOnly
KEYPRESS 1024 DontDelete|ReadOnly
DRAGDROP 2048 DontDelete|ReadOnly
FOCUS 4096 DontDelete|ReadOnly
BLUR 8192 DontDelete|ReadOnly
SELECT 16384 DontDelete|ReadOnly
CHANGE 32768 DontDelete|ReadOnly
@end
*/
Value EventConstructor::tryGet(ExecState *exec, const Identifier &p) const
{
return DOMObjectLookupGetValue<EventConstructor, DOMObject>(exec,p,&EventConstructorTable,this);
}
Value EventConstructor::getValueProperty(ExecState *, int token) const
{
// We use the token as the value to return directly
return Number(token);
}
Value KJS::getEventConstructor(ExecState *exec)
{
return cacheGlobalObject<EventConstructor>(exec, "[[event.constructor]]");
}
// -------------------------------------------------------------------------
const ClassInfo DOMEvent::info = { "Event", 0, &DOMEventTable, 0 };
/*
@begin DOMEventTable 12
type DOMEvent::Type DontDelete|ReadOnly
target DOMEvent::Target DontDelete|ReadOnly
currentTarget DOMEvent::CurrentTarget DontDelete|ReadOnly
srcElement DOMEvent::SrcElement DontDelete|ReadOnly
eventPhase DOMEvent::EventPhase DontDelete|ReadOnly
bubbles DOMEvent::Bubbles DontDelete|ReadOnly
cancelable DOMEvent::Cancelable DontDelete|ReadOnly
timeStamp DOMEvent::TimeStamp DontDelete|ReadOnly
returnValue DOMEvent::ReturnValue DontDelete
cancelBubble DOMEvent::CancelBubble DontDelete
dataTransfer DOMMouseEvent::DataTransfer DontDelete|ReadOnly
clipboardData DOMEvent::ClipboardData DontDelete|ReadOnly
@end
@begin DOMEventProtoTable 3
stopPropagation DOMEvent::StopPropagation DontDelete|Function 0
preventDefault DOMEvent::PreventDefault DontDelete|Function 0
initEvent DOMEvent::InitEvent DontDelete|Function 3
@end
*/
DEFINE_PROTOTYPE("DOMEvent", DOMEventProto)
IMPLEMENT_PROTOFUNC(DOMEventProtoFunc)
IMPLEMENT_PROTOTYPE(DOMEventProto, DOMEventProtoFunc)
DOMEvent::DOMEvent(ExecState *exec, DOM::Event e)
: DOMObject(DOMEventProto::self(exec)), event(e), clipboard(0) { }
DOMEvent::~DOMEvent()
{
ScriptInterpreter::forgetDOMObject(event.handle());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -