6b223379f2be6ddb051c7a9f08dcde92f61213a2
[WebKit-https.git] / WebCore / khtml / ecma / kjs_events.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include "khtml_part.h"
22 #include "kjs_window.h"
23 #include "kjs_events.h"
24 #include "kjs_events.lut.h"
25 #include "kjs_views.h"
26 #include "kjs_proxy.h"
27 #include "xml/dom_nodeimpl.h"
28 #include "xml/dom_docimpl.h"
29 #include "xml/dom2_eventsimpl.h"
30 #include "rendering/render_object.h"
31 #include "misc/loader.h"
32
33 #include <kdebug.h>
34
35 using namespace KJS;
36
37 using DOM::KeyboardEvent;
38 using DOM::EventImpl;
39
40 // -------------------------------------------------------------------------
41
42 JSEventListener::JSEventListener(Object _listener, const Object &_win, bool _html)
43 {
44     listener = _listener;
45     //fprintf(stderr,"JSEventListener::JSEventListener this=%p listener=%p\n",this,listener.imp());
46     html = _html;
47     win = _win;
48     if (_listener.imp()) {
49       static_cast<Window*>(win.imp())->jsEventListeners.insert(_listener.imp(), this);
50     }
51 }
52
53 JSEventListener::~JSEventListener()
54 {
55     if (listener.imp()) {
56       static_cast<Window*>(win.imp())->jsEventListeners.remove(listener.imp());
57     }
58     //fprintf(stderr,"JSEventListener::~JSEventListener this=%p listener=%p\n",this,listener.imp());
59 }
60
61 void JSEventListener::handleEvent(DOM::Event &evt, bool isWindowEvent)
62 {
63 #ifdef KJS_DEBUGGER
64   if (KJSDebugWin::instance() && KJSDebugWin::instance()->inSession())
65     return;
66 #endif
67   KHTMLPart *part = static_cast<Window*>(win.imp())->part();
68   KJSProxy *proxy = 0;
69   if (part)
70       proxy = KJSProxy::proxy( part );
71
72   if (proxy && listener.implementsCall()) {
73     ref();
74
75     KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter());
76     ExecState *exec = interpreter->globalExec();
77
78     List args;
79     args.append(getDOMEvent(exec,evt));
80
81     // Add the event's target element to the scope
82     // (and the document, and the form - see KJS::HTMLElement::eventHandlerScope)
83     ScopeChain oldScope = listener.scope();
84     Object thisObj;
85     if (isWindowEvent) {
86         thisObj = win;
87     } else {
88         KJS::Interpreter::lock();
89         thisObj = Object::dynamicCast(getDOMNode(exec,evt.currentTarget()));
90         KJS::Interpreter::unlock();
91         if ( !thisObj.isNull() ) {
92             ScopeChain scope;
93             KJS::Interpreter::lock();
94             static_cast<DOMNode*>(thisObj.imp())->pushEventHandlerScope(exec, scope);
95             KJS::Interpreter::unlock();
96             scope.push(oldScope);
97             listener.setScope( scope );
98         }
99     }
100
101     Window *window = static_cast<Window*>(win.imp());
102     // Set the event we're handling in the Window object
103     window->setCurrentEvent( &evt );
104     // ... and in the interpreter
105     interpreter->setCurrentEvent( &evt );
106
107     KJS::Interpreter::lock();
108     Value retval = listener.call(exec, thisObj, args);
109     KJS::Interpreter::unlock();
110
111     listener.setScope( oldScope );
112
113     window->setCurrentEvent( 0 );
114     interpreter->setCurrentEvent( 0 );
115 #if APPLE_CHANGES
116     if ( exec->hadException() ) {
117         KJS::Interpreter::lock();
118         char *message = exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii();
119         int lineNumber =  exec->exception().toObject(exec).get(exec, "line").toInt32(exec);
120         UString sourceURL = exec->exception().toObject(exec).get(exec, "sourceURL").toString(exec);
121         KJS::Interpreter::unlock();
122         if (Interpreter::shouldPrintExceptions()) {
123             printf("(event handler):%s\n", message);
124         }
125         KWQ(part)->addMessageToConsole(message, lineNumber, sourceURL.qstring());
126         exec->clearException();
127     }
128 #else
129     if ( exec->hadException() )
130         exec->clearException();
131 #endif
132
133     else if (html)
134     {
135         QVariant ret = ValueToVariant(exec, retval);
136         if (ret.type() == QVariant::Bool && ret.toBool() == false)
137             evt.preventDefault();
138     }
139     DOM::DocumentImpl::updateDocumentsRendering();
140     deref();
141   }
142 }
143
144 DOM::DOMString JSEventListener::eventListenerType()
145 {
146     if (html)
147         return "_khtml_HTMLEventListener";
148     else
149         return "_khtml_JSEventListener";
150 }
151
152
153 Object JSEventListener::listenerObj() const
154
155   return listener; 
156 }
157
158 JSLazyEventListener::JSLazyEventListener(QString _code, const Object &_win, bool _html, int lineno)
159   : JSEventListener(Object(), _win, _html),
160     code(_code),
161     parsed(false)
162 {
163         lineNumber = lineno;
164 }
165
166 void JSLazyEventListener::handleEvent(DOM::Event &evt, bool isWindowEvent)
167 {
168   parseCode();
169   if (!listener.isNull()) { 
170     JSEventListener::handleEvent(evt, isWindowEvent);
171   }
172 }
173
174
175 Object JSLazyEventListener::listenerObj() const
176 {
177   parseCode();
178   return listener;
179 }
180
181 void JSLazyEventListener::parseCode() const
182 {
183   if (!parsed) {
184     KHTMLPart *part = static_cast<Window*>(win.imp())->part();
185     KJSProxy *proxy = 0L;
186     if (part)
187       proxy = KJSProxy::proxy( part );
188
189     if (proxy) {
190       KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter());
191       ExecState *exec = interpreter->globalExec();
192
193       KJS::Interpreter::lock();
194       //KJS::Constructor constr(KJS::Global::current().get("Function").imp());
195       KJS::Object constr = interpreter->builtinFunction();
196       KJS::List args;
197
198       static ProtectedValue eventString = KJS::String("event");
199       UString sourceURL(part->m_url.url());
200       args.append(eventString);
201       args.append(KJS::String(code));
202       listener = constr.construct(exec, args, sourceURL, lineNumber); // ### is globalExec ok ?
203
204       KJS::Interpreter::unlock();
205       
206       if ( exec->hadException() ) {
207         exec->clearException();
208
209         // failed to parse, so let's just make this listener a no-op
210         listener = Object();
211       }
212     }
213
214     // no more need to keep the unparsed code around
215     code = QString();
216     
217     if (!listener.isNull()) {
218       static_cast<Window*>(win.imp())->jsEventListeners.insert(listener.imp(), 
219                                                                (KJS::JSEventListener *)(this));
220     }
221     
222     parsed = true;
223   }
224 }
225
226 Value KJS::getNodeEventListener(DOM::Node n, int eventId)
227 {
228     DOM::EventListener *listener = n.handle()->getHTMLEventListener(eventId);
229     JSEventListener *jsListener = static_cast<JSEventListener*>(listener);
230     if ( jsListener && jsListener->listenerObjImp() )
231         return jsListener->listenerObj();
232     else
233         return Null();
234 }
235
236
237
238 // -------------------------------------------------------------------------
239
240 const ClassInfo EventConstructor::info = { "EventConstructor", 0, &EventConstructorTable, 0 };
241 /*
242 @begin EventConstructorTable 3
243   CAPTURING_PHASE       DOM::Event::CAPTURING_PHASE     DontDelete|ReadOnly
244   AT_TARGET             DOM::Event::AT_TARGET           DontDelete|ReadOnly
245   BUBBLING_PHASE        DOM::Event::BUBBLING_PHASE      DontDelete|ReadOnly
246 # Reverse-engineered from Netscape
247   MOUSEDOWN             1                               DontDelete|ReadOnly
248   MOUSEUP               2                               DontDelete|ReadOnly
249   MOUSEOVER             4                               DontDelete|ReadOnly
250   MOUSEOUT              8                               DontDelete|ReadOnly
251   MOUSEMOVE             16                              DontDelete|ReadOnly
252   MOUSEDRAG             32                              DontDelete|ReadOnly
253   CLICK                 64                              DontDelete|ReadOnly
254   DBLCLICK              128                             DontDelete|ReadOnly
255   KEYDOWN               256                             DontDelete|ReadOnly
256   KEYUP                 512                             DontDelete|ReadOnly
257   KEYPRESS              1024                            DontDelete|ReadOnly
258   DRAGDROP              2048                            DontDelete|ReadOnly
259   FOCUS                 4096                            DontDelete|ReadOnly
260   BLUR                  8192                            DontDelete|ReadOnly
261   SELECT                16384                           DontDelete|ReadOnly
262   CHANGE                32768                           DontDelete|ReadOnly
263 @end
264 */
265
266 Value EventConstructor::tryGet(ExecState *exec, const Identifier &p) const
267 {
268   return DOMObjectLookupGetValue<EventConstructor, DOMObject>(exec,p,&EventConstructorTable,this);
269 }
270
271 Value EventConstructor::getValueProperty(ExecState *, int token) const
272 {
273   // We use the token as the value to return directly
274   return Number(token);
275 }
276
277 Value KJS::getEventConstructor(ExecState *exec)
278 {
279   return cacheGlobalObject<EventConstructor>(exec, "[[event.constructor]]");
280 }
281
282 // -------------------------------------------------------------------------
283
284 const ClassInfo DOMEvent::info = { "Event", 0, &DOMEventTable, 0 };
285 /*
286 @begin DOMEventTable 12
287   type          DOMEvent::Type          DontDelete|ReadOnly
288   target        DOMEvent::Target        DontDelete|ReadOnly
289   currentTarget DOMEvent::CurrentTarget DontDelete|ReadOnly
290   srcElement    DOMEvent::SrcElement    DontDelete|ReadOnly
291   eventPhase    DOMEvent::EventPhase    DontDelete|ReadOnly
292   bubbles       DOMEvent::Bubbles       DontDelete|ReadOnly
293   cancelable    DOMEvent::Cancelable    DontDelete|ReadOnly
294   timeStamp     DOMEvent::TimeStamp     DontDelete|ReadOnly
295   returnValue   DOMEvent::ReturnValue   DontDelete
296   cancelBubble  DOMEvent::CancelBubble  DontDelete
297   dataTransfer  DOMMouseEvent::DataTransfer DontDelete|ReadOnly
298   clipboardData  DOMEvent::ClipboardData  DontDelete|ReadOnly
299 @end
300 @begin DOMEventProtoTable 3
301   stopPropagation       DOMEvent::StopPropagation       DontDelete|Function 0
302   preventDefault        DOMEvent::PreventDefault        DontDelete|Function 0
303   initEvent             DOMEvent::InitEvent             DontDelete|Function 3
304 @end
305 */
306 DEFINE_PROTOTYPE("DOMEvent", DOMEventProto)
307 IMPLEMENT_PROTOFUNC(DOMEventProtoFunc)
308 IMPLEMENT_PROTOTYPE(DOMEventProto, DOMEventProtoFunc)
309
310 DOMEvent::DOMEvent(ExecState *exec, DOM::Event e)
311   : DOMObject(DOMEventProto::self(exec)), event(e), clipboard(0) { }
312
313 DOMEvent::~DOMEvent()
314 {
315   ScriptInterpreter::forgetDOMObject(event.handle());
316 }
317
318 // pass marks through to JS objects we hold during garbage collection
319 void DOMMouseEvent::mark()
320 {
321     ObjectImp::mark();
322     if (clipboard && !clipboard->marked())
323         clipboard->mark();
324 }
325
326 Value DOMEvent::tryGet(ExecState *exec, const Identifier &p) const
327 {
328 #ifdef KJS_VERBOSE
329   kdDebug() << "KJS::DOMEvent::tryGet " << p.qstring() << endl;
330 #endif
331   return DOMObjectLookupGetValue<DOMEvent,DOMObject>(exec, p, &DOMEventTable, this );
332 }
333
334 Value DOMEvent::getValueProperty(ExecState *exec, int token) const
335 {
336   switch (token) {
337   case Type:
338     return String(event.type());
339   case Target:
340   case SrcElement: /*MSIE extension - "the object that fired the event"*/
341     return getDOMNode(exec,event.target());
342   case CurrentTarget:
343     return getDOMNode(exec,event.currentTarget());
344   case EventPhase:
345     return Number((unsigned int)event.eventPhase());
346   case Bubbles:
347     return Boolean(event.bubbles());
348   case CancelBubble:
349     return Boolean(event.getCancelBubble());
350   case ReturnValue:
351     return Boolean(!event.defaultPrevented());
352   case Cancelable:
353     return Boolean(event.cancelable());
354   case TimeStamp:
355     return Number((long unsigned int)event.timeStamp()); // ### long long ?
356   case ClipboardData:
357   {
358     DOM::EventImpl *ei = event.handle();
359     if (ei->isClipboardEvent()) {
360       DOM::ClipboardEventImpl *impl = static_cast<DOM::ClipboardEventImpl *>(event.handle());
361       if (!clipboard) {
362         clipboard = new Clipboard(exec, impl->clipboard());
363       }
364       return Object(clipboard);
365     } else {
366       return Undefined();
367     }
368   }
369   case DataTransfer:
370   {
371     DOM::EventImpl *ei = event.handle();
372     if (ei->isDragEvent()) {
373       DOM::MouseEventImpl *impl = static_cast<DOM::MouseEventImpl *>(event.handle());
374       if (!clipboard) {
375         clipboard = new Clipboard(exec, impl->clipboard());
376       }
377       return Object(clipboard);
378     } else {
379       return Undefined();
380     }
381   }
382   default:
383     kdWarning() << "Unhandled token in DOMEvent::getValueProperty : " << token << endl;
384     return Value();
385   }
386 }
387
388 void DOMEvent::tryPut(ExecState *exec, const Identifier &propertyName,
389                       const Value& value, int attr)
390 {
391   DOMObjectLookupPut<DOMEvent, DOMObject>(exec, propertyName, value, attr,
392                                           &DOMEventTable, this);
393 }
394
395 void DOMEvent::putValue(ExecState *exec, int token, const Value& value, int)
396 {
397   switch (token) {
398   case ReturnValue:
399     event.setDefaultPrevented(!value.toBoolean(exec));
400     break;
401   case CancelBubble:
402     event.setCancelBubble(value.toBoolean(exec));
403     break;
404   default:
405     break;
406   }
407 }
408
409 Value DOMEventProtoFunc::tryCall(ExecState *exec, Object & thisObj, const List &args)
410 {
411   if (!thisObj.inherits(&KJS::DOMEvent::info)) {
412     Object err = Error::create(exec,TypeError);
413     exec->setException(err);
414     return err;
415   }
416   DOM::Event event = static_cast<DOMEvent *>( thisObj.imp() )->toEvent();
417   switch (id) {
418     case DOMEvent::StopPropagation:
419       event.stopPropagation();
420     case DOMEvent::PreventDefault:
421       event.preventDefault();
422       return Undefined();
423     case DOMEvent::InitEvent:
424       event.initEvent(args[0].toString(exec).string(),args[1].toBoolean(exec),args[2].toBoolean(exec));
425       return Undefined();
426   };
427   return Undefined();
428 }
429
430 Value KJS::getDOMEvent(ExecState *exec, DOM::Event e)
431 {
432   DOM::EventImpl *ei = e.handle();
433   if (!ei)
434     return Null();
435   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
436
437   KJS::Interpreter::lock();
438
439   DOMObject *ret = interp->getDOMObject(ei);
440   if (!ret) {
441     if (ei->isKeyboardEvent())
442       ret = new DOMKeyboardEvent(exec, e);
443     else if (ei->isMouseEvent())
444       ret = new DOMMouseEvent(exec, e);
445     else if (ei->isUIEvent())
446       ret = new DOMUIEvent(exec, e);
447     else if (ei->isMutationEvent())
448       ret = new DOMMutationEvent(exec, e);
449     else
450       ret = new DOMEvent(exec, e);
451
452     interp->putDOMObject(ei, ret);
453   }
454
455   KJS::Interpreter::unlock();
456
457   return Value(ret);
458 }
459
460 DOM::Event KJS::toEvent(const Value& val)
461 {
462   Object obj = Object::dynamicCast(val);
463   if (obj.isNull() || !obj.inherits(&DOMEvent::info))
464     return DOM::Event();
465
466   const DOMEvent *dobj = static_cast<const DOMEvent*>(obj.imp());
467   return dobj->toEvent();
468 }
469
470 // -------------------------------------------------------------------------
471
472
473 const ClassInfo EventExceptionConstructor::info = { "EventExceptionConstructor", 0, &EventExceptionConstructorTable, 0 };
474 /*
475 @begin EventExceptionConstructorTable 1
476   UNSPECIFIED_EVENT_TYPE_ERR    DOM::EventException::UNSPECIFIED_EVENT_TYPE_ERR DontDelete|ReadOnly
477 @end
478 */
479 Value EventExceptionConstructor::tryGet(ExecState *exec, const Identifier &p) const
480 {
481   return DOMObjectLookupGetValue<EventExceptionConstructor, DOMObject>(exec,p,&EventExceptionConstructorTable,this);
482 }
483
484 Value EventExceptionConstructor::getValueProperty(ExecState *, int token) const
485 {
486   // We use the token as the value to return directly
487   return Number(token);
488 }
489
490 Value KJS::getEventExceptionConstructor(ExecState *exec)
491 {
492   return cacheGlobalObject<EventExceptionConstructor>(exec, "[[eventException.constructor]]");
493 }
494
495 // -------------------------------------------------------------------------
496
497 const ClassInfo DOMUIEvent::info = { "UIEvent", &DOMEvent::info, &DOMUIEventTable, 0 };
498 /*
499 @begin DOMUIEventTable 8
500   view          DOMUIEvent::View        DontDelete|ReadOnly
501   detail        DOMUIEvent::Detail      DontDelete|ReadOnly
502   keyCode       DOMUIEvent::KeyCode     DontDelete|ReadOnly
503   charCode      DOMUIEvent::CharCode    DontDelete|ReadOnly
504   layerX        DOMUIEvent::LayerX      DontDelete|ReadOnly
505   layerY        DOMUIEvent::LayerY      DontDelete|ReadOnly
506   pageX         DOMUIEvent::PageX       DontDelete|ReadOnly
507   pageY         DOMUIEvent::PageY       DontDelete|ReadOnly
508   which         DOMUIEvent::Which       DontDelete|ReadOnly
509 @end
510 @begin DOMUIEventProtoTable 1
511   initUIEvent   DOMUIEvent::InitUIEvent DontDelete|Function 5
512 @end
513 */
514 DEFINE_PROTOTYPE("DOMUIEvent",DOMUIEventProto)
515 IMPLEMENT_PROTOFUNC(DOMUIEventProtoFunc)
516 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMUIEventProto,DOMUIEventProtoFunc,DOMEventProto)
517
518 DOMUIEvent::~DOMUIEvent()
519 {
520 }
521
522 Value DOMUIEvent::tryGet(ExecState *exec, const Identifier &p) const
523 {
524   return DOMObjectLookupGetValue<DOMUIEvent,DOMEvent>(exec,p,&DOMUIEventTable,this);
525 }
526
527 Value DOMUIEvent::getValueProperty(ExecState *exec, int token) const
528 {
529   switch (token) {
530   case View:
531     return getDOMAbstractView(exec,static_cast<DOM::UIEvent>(event).view());
532   case Detail:
533     return Number(static_cast<DOM::UIEvent>(event).detail());
534   case KeyCode:
535     return Number(static_cast<DOM::UIEvent>(event).keyCode());
536   case CharCode:
537     return Number(static_cast<DOM::UIEvent>(event).charCode());
538   case LayerX:
539     return Number(static_cast<DOM::UIEvent>(event).layerX());
540   case LayerY:
541     return Number(static_cast<DOM::UIEvent>(event).layerY());
542   case PageX:
543     return Number(static_cast<DOM::UIEvent>(event).pageX());
544   case PageY:
545     return Number(static_cast<DOM::UIEvent>(event).pageY());
546   case Which:
547     return Number(static_cast<DOM::UIEvent>(event).which());
548   default:
549     kdWarning() << "Unhandled token in DOMUIEvent::getValueProperty : " << token << endl;
550     return Undefined();
551   }
552 }
553
554 Value DOMUIEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
555 {
556   if (!thisObj.inherits(&KJS::DOMUIEvent::info)) {
557     Object err = Error::create(exec,TypeError);
558     exec->setException(err);
559     return err;
560   }
561   DOM::UIEvent uiEvent = static_cast<DOMUIEvent *>(thisObj.imp())->toUIEvent();
562   switch (id) {
563     case DOMUIEvent::InitUIEvent: {
564       DOM::AbstractView v = toAbstractView(args[3]);
565       static_cast<DOM::UIEvent>(uiEvent).initUIEvent(args[0].toString(exec).string(),
566                                                      args[1].toBoolean(exec),
567                                                      args[2].toBoolean(exec),
568                                                      v,
569                                                      args[4].toInt32(exec));
570       }
571       return Undefined();
572   }
573   return Undefined();
574 }
575
576 // -------------------------------------------------------------------------
577
578 const ClassInfo DOMMouseEvent::info = { "MouseEvent", &DOMUIEvent::info, &DOMMouseEventTable, 0 };
579
580 /*
581 @begin DOMMouseEventTable 16
582   screenX       DOMMouseEvent::ScreenX  DontDelete|ReadOnly
583   screenY       DOMMouseEvent::ScreenY  DontDelete|ReadOnly
584   clientX       DOMMouseEvent::ClientX  DontDelete|ReadOnly
585   x             DOMMouseEvent::X        DontDelete|ReadOnly
586   clientY       DOMMouseEvent::ClientY  DontDelete|ReadOnly
587   y             DOMMouseEvent::Y        DontDelete|ReadOnly
588   offsetX       DOMMouseEvent::OffsetX  DontDelete|ReadOnly
589   offsetY       DOMMouseEvent::OffsetY  DontDelete|ReadOnly
590   ctrlKey       DOMMouseEvent::CtrlKey  DontDelete|ReadOnly
591   shiftKey      DOMMouseEvent::ShiftKey DontDelete|ReadOnly
592   altKey        DOMMouseEvent::AltKey   DontDelete|ReadOnly
593   metaKey       DOMMouseEvent::MetaKey  DontDelete|ReadOnly
594   button        DOMMouseEvent::Button   DontDelete|ReadOnly
595   relatedTarget DOMMouseEvent::RelatedTarget DontDelete|ReadOnly
596   fromElement   DOMMouseEvent::FromElement DontDelete|ReadOnly
597   toElement     DOMMouseEvent::ToElement        DontDelete|ReadOnly
598 @end
599 @begin DOMMouseEventProtoTable 1
600   initMouseEvent        DOMMouseEvent::InitMouseEvent   DontDelete|Function 15
601 @end
602 */
603 DEFINE_PROTOTYPE("DOMMouseEvent",DOMMouseEventProto)
604 IMPLEMENT_PROTOFUNC(DOMMouseEventProtoFunc)
605 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMMouseEventProto,DOMMouseEventProtoFunc,DOMUIEventProto)
606
607 DOMMouseEvent::~DOMMouseEvent()
608 {
609 }
610
611 Value DOMMouseEvent::tryGet(ExecState *exec, const Identifier &p) const
612 {
613 #ifdef KJS_VERBOSE
614   kdDebug(6070) << "DOMMouseEvent::tryGet " << p.qstring() << endl;
615 #endif
616   return DOMObjectLookupGetValue<DOMMouseEvent,DOMUIEvent>(exec,p,&DOMMouseEventTable,this);
617 }
618
619 Value DOMMouseEvent::getValueProperty(ExecState *exec, int token) const
620 {
621   switch (token) {
622   case ScreenX:
623     return Number(static_cast<DOM::MouseEvent>(event).screenX());
624   case ScreenY:
625     return Number(static_cast<DOM::MouseEvent>(event).screenY());
626   case ClientX:
627   case X:
628     return Number(static_cast<DOM::MouseEvent>(event).clientX());
629   case ClientY:
630   case Y:
631     return Number(static_cast<DOM::MouseEvent>(event).clientY());
632   case OffsetX:
633   case OffsetY: // MSIE extension
634   {
635     DOM::Node node = event.target();
636     node.handle()->getDocument()->updateRendering();
637     khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
638     int x = static_cast<DOM::MouseEvent>(event).clientX();
639     int y = static_cast<DOM::MouseEvent>(event).clientY();
640     if ( rend ) {
641       int xPos, yPos;
642       if ( rend->absolutePosition( xPos, yPos ) ) {
643         kdDebug() << "DOMMouseEvent::getValueProperty rend=" << rend << "  xPos=" << xPos << "  yPos=" << yPos << endl;
644         x -= xPos;
645         y -= yPos;
646       }
647     }
648     return Number( token == OffsetX ? x : y );
649   }
650   case CtrlKey:
651     return Boolean(static_cast<DOM::MouseEvent>(event).ctrlKey());
652   case ShiftKey:
653     return Boolean(static_cast<DOM::MouseEvent>(event).shiftKey());
654   case AltKey:
655     return Boolean(static_cast<DOM::MouseEvent>(event).altKey());
656   case MetaKey:
657     return Boolean(static_cast<DOM::MouseEvent>(event).metaKey());
658   case Button:
659   {
660     // Tricky. The DOM (and khtml) use 0 for LMB, 1 for MMB and 2 for RMB
661     // but MSIE uses 1=LMB, 2=RMB, 4=MMB, as a bitfield
662     int domButton = static_cast<DOM::MouseEvent>(event).button();
663     int button = domButton==0 ? 1 : domButton==1 ? 4 : domButton==2 ? 2 : 0;
664     return Number( (unsigned int)button );
665   }
666   case ToElement:
667     // MSIE extension - "the object toward which the user is moving the mouse pointer"
668     if (event.handle()->id() == DOM::EventImpl::MOUSEOUT_EVENT)
669       return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).relatedTarget());
670     return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).target());
671   case FromElement:
672     // MSIE extension - "object from which activation
673     // or the mouse pointer is exiting during the event" (huh?)
674     if (event.handle()->id() == DOM::EventImpl::MOUSEOUT_EVENT)
675       return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).target());
676     /* fall through */
677   case RelatedTarget:
678     return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).relatedTarget());
679   default:
680     kdWarning() << "Unhandled token in DOMMouseEvent::getValueProperty : " << token << endl;
681     return Value();
682   }
683 }
684
685 Value DOMMouseEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
686 {
687   if (!thisObj.inherits(&KJS::DOMMouseEvent::info)) {
688     Object err = Error::create(exec,TypeError);
689     exec->setException(err);
690     return err;
691   }
692   DOM::MouseEvent mouseEvent = static_cast<DOMMouseEvent *>(thisObj.imp())->toMouseEvent();
693   switch (id) {
694     case DOMMouseEvent::InitMouseEvent:
695       mouseEvent.initMouseEvent(args[0].toString(exec).string(), // typeArg
696                                 args[1].toBoolean(exec), // canBubbleArg
697                                 args[2].toBoolean(exec), // cancelableArg
698                                 toAbstractView(args[3]), // viewArg
699                                 args[4].toInt32(exec), // detailArg
700                                 args[5].toInt32(exec), // screenXArg
701                                 args[6].toInt32(exec), // screenYArg
702                                 args[7].toInt32(exec), // clientXArg
703                                 args[8].toInt32(exec), // clientYArg
704                                 args[9].toBoolean(exec), // ctrlKeyArg
705                                 args[10].toBoolean(exec), // altKeyArg
706                                 args[11].toBoolean(exec), // shiftKeyArg
707                                 args[12].toBoolean(exec), // metaKeyArg
708                                 args[13].toInt32(exec), // buttonArg
709                                 toNode(args[14])); // relatedTargetArg
710       return Undefined();
711   }
712   return Undefined();
713 }
714
715 // -------------------------------------------------------------------------
716
717 const ClassInfo DOMKeyboardEvent::info = { "KeyboardEvent", &DOMUIEvent::info, &DOMKeyboardEventTable, 0 };
718
719 /*
720 @begin DOMKeyboardEventTable 5
721   keyIdentifier DOMKeyboardEvent::KeyIdentifier DontDelete|ReadOnly
722   keyLocation   DOMKeyboardEvent::KeyLocation   DontDelete|ReadOnly
723   ctrlKey       DOMKeyboardEvent::CtrlKey       DontDelete|ReadOnly
724   shiftKey      DOMKeyboardEvent::ShiftKey      DontDelete|ReadOnly
725   altKey        DOMKeyboardEvent::AltKey        DontDelete|ReadOnly
726   metaKey       DOMKeyboardEvent::MetaKey       DontDelete|ReadOnly
727   altGraphKey   DOMKeyboardEvent::AltGraphKey   DontDelete|ReadOnly
728 @end
729 @begin DOMKeyboardEventProtoTable 1
730   initKeyboardEvent     DOMKeyboardEvent::InitKeyboardEvent     DontDelete|Function 11
731 @end
732 */
733 DEFINE_PROTOTYPE("DOMKeyboardEvent", DOMKeyboardEventProto)
734 IMPLEMENT_PROTOFUNC(DOMKeyboardEventProtoFunc)
735 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMKeyboardEventProto, DOMKeyboardEventProtoFunc, DOMUIEventProto)
736
737 DOMKeyboardEvent::~DOMKeyboardEvent()
738 {
739 }
740
741 const ClassInfo* DOMKeyboardEvent::classInfo() const
742 {
743     return &info;
744 }
745
746 Value DOMKeyboardEvent::tryGet(ExecState *exec, const Identifier &p) const
747 {
748 #ifdef KJS_VERBOSE
749   kdDebug(6070) << "DOMKeyboardEvent::tryGet " << p.qstring() << endl;
750 #endif
751   return DOMObjectLookupGetValue<DOMKeyboardEvent, DOMUIEvent>(exec, p, &DOMKeyboardEventTable, this);
752 }
753
754 Value DOMKeyboardEvent::getValueProperty(ExecState *exec, int token) const
755 {
756   switch (token) {
757   case KeyIdentifier:
758     return String(static_cast<KeyboardEvent>(event).keyIdentifier());
759   case KeyLocation:
760     return Number(static_cast<KeyboardEvent>(event).keyLocation());
761   case CtrlKey:
762     return Boolean(static_cast<KeyboardEvent>(event).ctrlKey());
763   case ShiftKey:
764     return Boolean(static_cast<KeyboardEvent>(event).shiftKey());
765   case AltKey:
766     return Boolean(static_cast<KeyboardEvent>(event).altKey());
767   case MetaKey:
768     return Boolean(static_cast<KeyboardEvent>(event).metaKey());
769   case AltGraphKey:
770     return Boolean(static_cast<KeyboardEvent>(event).altGraphKey());
771   default:
772     kdWarning() << "Unhandled token in DOMKeyboardEvent::getValueProperty : " << token << endl;
773     return Value();
774   }
775 }
776
777 Value DOMKeyboardEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
778 {
779   if (!thisObj.inherits(&DOMKeyboardEvent::info)) {
780     Object err = Error::create(exec,TypeError);
781     exec->setException(err);
782     return err;
783   }
784   KeyboardEvent event = static_cast<DOMKeyboardEvent *>(thisObj.imp())->toKeyboardEvent();
785   switch (id) {
786     case DOMKeyboardEvent::InitKeyboardEvent:
787       event.initKeyboardEvent(args[0].toString(exec).string(), // typeArg
788                               args[1].toBoolean(exec), // canBubbleArg
789                               args[2].toBoolean(exec), // cancelableArg
790                               toAbstractView(args[3]), // viewArg
791                               args[4].toString(exec).string(), // keyIdentifier
792                               args[5].toInt32(exec), // keyLocationArg
793                               args[6].toBoolean(exec), // ctrlKeyArg
794                               args[7].toBoolean(exec), // altKeyArg
795                               args[8].toBoolean(exec), // shiftKeyArg
796                               args[9].toBoolean(exec), // metaKeyArg
797                               args[10].toBoolean(exec)); // altGraphKeyArg
798       return Undefined();
799   }
800   return Undefined();
801 }
802
803 // -------------------------------------------------------------------------
804
805 const ClassInfo MutationEventConstructor::info = { "MutationEventConstructor", 0, &MutationEventConstructorTable, 0 };
806 /*
807 @begin MutationEventConstructorTable 3
808   MODIFICATION  DOM::MutationEvent::MODIFICATION        DontDelete|ReadOnly
809   ADDITION      DOM::MutationEvent::ADDITION            DontDelete|ReadOnly
810   REMOVAL       DOM::MutationEvent::REMOVAL             DontDelete|ReadOnly
811 @end
812 */
813 Value MutationEventConstructor::tryGet(ExecState *exec, const Identifier &p) const
814 {
815   return DOMObjectLookupGetValue<MutationEventConstructor,DOMObject>(exec,p,&MutationEventConstructorTable,this);
816 }
817
818 Value MutationEventConstructor::getValueProperty(ExecState *, int token) const
819 {
820   // We use the token as the value to return directly
821   return Number(token);
822 }
823
824 Value KJS::getMutationEventConstructor(ExecState *exec)
825 {
826   return cacheGlobalObject<MutationEventConstructor>(exec, "[[mutationEvent.constructor]]");
827 }
828
829 // -------------------------------------------------------------------------
830
831 const ClassInfo DOMMutationEvent::info = { "MutationEvent", &DOMEvent::info, &DOMMutationEventTable, 0 };
832 /*
833 @begin DOMMutationEventTable 5
834   relatedNode   DOMMutationEvent::RelatedNode   DontDelete|ReadOnly
835   prevValue     DOMMutationEvent::PrevValue     DontDelete|ReadOnly
836   newValue      DOMMutationEvent::NewValue      DontDelete|ReadOnly
837   attrName      DOMMutationEvent::AttrName      DontDelete|ReadOnly
838   attrChange    DOMMutationEvent::AttrChange    DontDelete|ReadOnly
839 @end
840 @begin DOMMutationEventProtoTable 1
841   initMutationEvent     DOMMutationEvent::InitMutationEvent     DontDelete|Function 8
842 @end
843 */
844 DEFINE_PROTOTYPE("DOMMutationEvent",DOMMutationEventProto)
845 IMPLEMENT_PROTOFUNC(DOMMutationEventProtoFunc)
846 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMMutationEventProto,DOMMutationEventProtoFunc,DOMEventProto)
847
848 DOMMutationEvent::~DOMMutationEvent()
849 {
850 }
851
852 Value DOMMutationEvent::tryGet(ExecState *exec, const Identifier &p) const
853 {
854   return DOMObjectLookupGetValue<DOMMutationEvent,DOMEvent>(exec,p,&DOMMutationEventTable,this);
855 }
856
857 Value DOMMutationEvent::getValueProperty(ExecState *exec, int token) const
858 {
859   switch (token) {
860   case RelatedNode:
861     return getDOMNode(exec,static_cast<DOM::MutationEvent>(event).relatedNode());
862   case PrevValue:
863     return String(static_cast<DOM::MutationEvent>(event).prevValue());
864   case NewValue:
865     return String(static_cast<DOM::MutationEvent>(event).newValue());
866   case AttrName:
867     return String(static_cast<DOM::MutationEvent>(event).attrName());
868   case AttrChange:
869     return Number((unsigned int)static_cast<DOM::MutationEvent>(event).attrChange());
870   default:
871     kdWarning() << "Unhandled token in DOMMutationEvent::getValueProperty : " << token << endl;
872     return Value();
873   }
874 }
875
876 Value DOMMutationEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
877 {
878   if (!thisObj.inherits(&KJS::DOMMutationEvent::info)) {
879     Object err = Error::create(exec,TypeError);
880     exec->setException(err);
881     return err;
882   }
883   DOM::MutationEvent mutationEvent = static_cast<DOMMutationEvent *>(thisObj.imp())->toMutationEvent();
884   switch (id) {
885     case DOMMutationEvent::InitMutationEvent:
886       mutationEvent.initMutationEvent(args[0].toString(exec).string(), // typeArg,
887                                       args[1].toBoolean(exec), // canBubbleArg
888                                       args[2].toBoolean(exec), // cancelableArg
889                                       toNode(args[3]), // relatedNodeArg
890                                       args[4].toString(exec).string(), // prevValueArg
891                                       args[5].toString(exec).string(), // newValueArg
892                                       args[6].toString(exec).string(), // attrNameArg
893                                       args[7].toInt32(exec)); // attrChangeArg
894       return Undefined();
895   }
896   return Undefined();
897 }
898
899 // -------------------------------------------------------------------------
900
901 const ClassInfo Clipboard::info = { "Clipboard", 0, &ClipboardTable, 0 };
902
903 /* Source for ClipboardTable. Use "make hashtables" to regenerate.
904 @begin ClipboardTable 3
905   dropEffect    Clipboard::DropEffect   DontDelete
906   effectAllowed Clipboard::EffectAllowed        DontDelete
907   types         Clipboard::Types        DontDelete|ReadOnly
908 @end
909 @begin ClipboardProtoTable 4
910   clearData     Clipboard::ClearData    DontDelete|Function 0
911   getData       Clipboard::GetData      DontDelete|Function 1
912   setData       Clipboard::SetData      DontDelete|Function 2
913   setDragImage  Clipboard::SetDragImage DontDelete|Function 3
914 @end
915 */
916
917 DEFINE_PROTOTYPE("Clipboard", ClipboardProto)
918 IMPLEMENT_PROTOFUNC(ClipboardProtoFunc)
919 IMPLEMENT_PROTOTYPE(ClipboardProto, ClipboardProtoFunc)
920
921 Clipboard::Clipboard(ExecState *exec, DOM::ClipboardImpl *cb)
922 : DOMObject(ClipboardProto::self(exec)), clipboard(cb)
923 {
924     if (clipboard)
925         clipboard->ref();
926 }
927
928 Clipboard::~Clipboard()
929 {
930     if (clipboard)
931         clipboard->deref();
932 }
933
934 static Value stringOrUndefined(const DOM::DOMString &str)
935 {
936     if (str.isNull()) {
937         return Undefined();
938     } else {
939         return String(str);
940     }
941 }
942
943 Value Clipboard::tryGet(ExecState *exec, const Identifier &propertyName) const
944 {
945     return DOMObjectLookupGetValue<Clipboard,DOMObject>(exec, propertyName, &ClipboardTable, this);
946 }
947
948 Value Clipboard::getValueProperty(ExecState *exec, int token) const
949 {
950     switch (token) {
951         case DropEffect:
952             assert(clipboard->isForDragging() || clipboard->dropEffect().isNull());
953             return stringOrUndefined(clipboard->dropEffect());
954         case EffectAllowed:
955             assert(clipboard->isForDragging() || clipboard->effectAllowed().isNull());
956             return stringOrUndefined(clipboard->effectAllowed());
957         case Types:
958         {
959             QStringList qTypes = clipboard->types();
960             if (qTypes.isEmpty()) {
961                 return Null(); 
962             } else {
963                 List list;
964                 for (QStringList::Iterator it = qTypes.begin(); it != qTypes.end(); ++it) {
965                     list.append(String(UString(*it)));
966                 }
967                 return exec->lexicalInterpreter()->builtinArray().construct(exec, list);
968             }
969         }
970         default:
971             kdWarning() << "Clipboard::getValueProperty unhandled token " << token << endl;
972             return Value();
973     }
974 }
975
976 void Clipboard::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
977 {
978     DOMObjectLookupPut<Clipboard,DOMObject>(exec, propertyName, value, attr, &ClipboardTable, this );
979 }
980
981 void Clipboard::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
982 {
983     switch (token) {
984         case DropEffect:
985             // can never set this when not for dragging, thus getting always returns NULL string
986             if (clipboard->isForDragging())
987                 clipboard->setDropEffect(value.toString(exec).string());
988             break;
989         case EffectAllowed:
990             // can never set this when not for dragging, thus getting always returns NULL string
991             if (clipboard->isForDragging())
992                 clipboard->setEffectAllowed(value.toString(exec).string());
993             break;
994         default:
995             kdWarning() << "Clipboard::putValue unhandled token " << token << endl;
996     }
997 }
998
999 Value ClipboardProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1000 {
1001     if (!thisObj.inherits(&KJS::Clipboard::info)) {
1002         Object err = Error::create(exec,TypeError);
1003         exec->setException(err);
1004         return err;
1005     }
1006
1007     Clipboard *cb = static_cast<Clipboard *>(thisObj.imp());
1008     switch (id) {
1009         case Clipboard::ClearData:
1010             if (args.size() == 0) {
1011                 cb->clipboard->clearAllData();
1012                 return Undefined();
1013             } else if (args.size() == 1) {
1014                 cb->clipboard->clearData(args[0].toString(exec).string());
1015                 return Undefined();
1016             } else {
1017                 Object err = Error::create(exec,SyntaxError,"clearData: Invalid number of arguments");
1018                 exec->setException(err);
1019                 return err;
1020             }
1021         case Clipboard::GetData:
1022         {
1023             if (args.size() == 1) {
1024                 bool success;
1025                 DOM::DOMString result = cb->clipboard->getData(args[0].toString(exec).string(), success);
1026                 if (success) {
1027                     return String(result);
1028                 } else {
1029                     return Undefined();
1030                 }
1031             } else {
1032                 Object err = Error::create(exec,SyntaxError,"getData: Invalid number of arguments");
1033                 exec->setException(err);
1034                 return err;
1035             }
1036         }
1037         case Clipboard::SetData:
1038             if (args.size() == 2) {
1039                 return Boolean(cb->clipboard->setData(args[0].toString(exec).string(), args[1].toString(exec).string()));
1040             } else {
1041                 Object err = Error::create(exec,SyntaxError,"setData: Invalid number of arguments");
1042                 exec->setException(err);
1043                 return err;
1044             }
1045         case Clipboard::SetDragImage:
1046         {
1047             if (!cb->clipboard->isForDragging()) {
1048                 return Undefined();
1049             }
1050
1051             if (args.size() != 3) {
1052                 Object err = Error::create(exec, SyntaxError,"setDragImage: Invalid number of arguments");
1053                 exec->setException(err);
1054                 return err;
1055             }
1056
1057             int x = (int)args[1].toNumber(exec);
1058             int y = (int)args[2].toNumber(exec);
1059
1060             // See if they passed us a node
1061             DOM::Node node = toNode(args[0]);
1062             if (!node.isNull()) {
1063                 if (node.nodeType() == DOM::Node::ELEMENT_NODE) {
1064                     cb->clipboard->setDragImageElement(node, QPoint(x,y));                    
1065                     return Undefined();
1066                 } else {
1067                     Object err = Error::create(exec, SyntaxError,"setDragImageFromElement: Invalid first argument");
1068                     exec->setException(err);
1069                     return err;
1070                 }
1071             }
1072
1073             // See if they passed us an Image object
1074             ObjectImp *o = static_cast<ObjectImp*>(args[0].imp());
1075             if (o->inherits(&Image::info)) {
1076                 Image *JSImage = static_cast<Image*>(o);
1077                 cb->clipboard->setDragImage(JSImage->image()->pixmap(), QPoint(x,y));                
1078                 return Undefined();
1079             } else {
1080                 Object err = Error::create(exec,TypeError);
1081                 exec->setException(err);
1082                 return err;
1083             }
1084         }
1085     }
1086     return Undefined();
1087 }
1088