kjs_events.cpp 20.3 KB
Newer Older
kocienda's avatar
kocienda committed
1 2 3
/*
 *  This file is part of the KDE libraries
 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
darin's avatar
darin committed
4
 *  Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
kocienda's avatar
kocienda committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  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
 */
darin's avatar
darin committed
20

mjs's avatar
mjs committed
21
#include "config.h"
kocienda's avatar
kocienda committed
22
#include "kjs_events.h"
darin's avatar
darin committed
23

darin's avatar
darin committed
24
#include "CString.h"
weinig's avatar
 
weinig committed
25 26
#include "Clipboard.h"
#include "ClipboardEvent.h"
darin's avatar
darin committed
27
#include "Document.h"
weinig's avatar
 
weinig committed
28
#include "Event.h"
darin's avatar
darin committed
29 30
#include "EventNames.h"
#include "Frame.h"
weinig's avatar
 
weinig committed
31 32
#include "HTMLImageElement.h"
#include "HTMLNames.h"
ggaren's avatar
ggaren committed
33
#include "JSEvent.h"
weinig's avatar
 
weinig committed
34 35
#include "JSKeyboardEvent.h"
#include "JSMouseEvent.h"
darin's avatar
darin committed
36
#include "JSMutationEvent.h"
andersca's avatar
andersca committed
37
#include "JSOverflowEvent.h"
darin's avatar
darin committed
38
#include "JSWheelEvent.h"
darin's avatar
darin committed
39
#include "KURL.h"
weinig's avatar
 
weinig committed
40 41 42
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "MutationEvent.h"
andersca's avatar
andersca committed
43
#include "OverflowEvent.h"
weinig's avatar
 
weinig committed
44 45
#include "UIEvent.h"
#include "WheelEvent.h"
darin's avatar
darin committed
46 47
#include "kjs_proxy.h"
#include "kjs_window.h"
kocienda's avatar
kocienda committed
48

darin's avatar
darin committed
49
#include "kjs_events.lut.h"
50

51
using namespace WebCore;
darin's avatar
darin committed
52
using namespace EventNames;
53
using namespace HTMLNames;
darin's avatar
darin committed
54

55 56
namespace KJS {

darin's avatar
darin committed
57 58
JSAbstractEventListener::JSAbstractEventListener(bool _html)
    : html(_html)
kocienda's avatar
kocienda committed
59 60 61
{
}

darin's avatar
darin committed
62
void JSAbstractEventListener::handleEvent(Event* ele, bool isWindowEvent)
kocienda's avatar
kocienda committed
63
{
64
#ifdef KJS_DEBUGGER
darin's avatar
darin committed
65 66
    if (KJSDebugWin::instance() && KJSDebugWin::instance()->inSession())
        return;
67
#endif
68

darin's avatar
darin committed
69
    Event *event = ele;
70

darin's avatar
darin committed
71 72 73
    JSObject* listener = listenerObj();
    if (!listener)
        return;
mjs's avatar
mjs committed
74

darin's avatar
darin committed
75
    Window* window = windowObj();
mjs's avatar
mjs committed
76 77
    Frame *frame = window->frame();
    if (!frame)
darin's avatar
darin committed
78
        return;
darin's avatar
darin committed
79
    KJSProxy* proxy = frame->scriptProxy();
darin's avatar
darin committed
80 81
    if (!proxy)
        return;
darin's avatar
darin committed
82

darin's avatar
darin committed
83
    JSLock lock;
darin's avatar
darin committed
84
  
darin's avatar
darin committed
85 86
    ScriptInterpreter* interpreter = proxy->interpreter();
    ExecState* exec = interpreter->globalExec();
darin's avatar
darin committed
87
  
darin's avatar
darin committed
88 89 90 91 92 93 94
    JSValue* handleEventFuncValue = listener->get(exec, "handleEvent");
    JSObject* handleEventFunc = 0;
    if (handleEventFuncValue->isObject()) {      
        handleEventFunc = static_cast<JSObject*>(handleEventFuncValue);
        if (!handleEventFunc->implementsCall())
            handleEventFunc = 0;
    }
darin's avatar
darin committed
95
  
darin's avatar
darin committed
96 97
    if (handleEventFunc || listener->implementsCall()) {
        ref();
mjs's avatar
mjs committed
98
      
darin's avatar
darin committed
99
        List args;
darin's avatar
darin committed
100
        args.append(toJS(exec, event));
mjs's avatar
mjs committed
101
      
darin's avatar
darin committed
102 103 104 105
        // Set the event we're handling in the Window object
        window->setCurrentEvent(event);
        // ... and in the interpreter
        interpreter->setCurrentEvent(event);
mjs's avatar
mjs committed
106
      
darin's avatar
darin committed
107
        JSValue* retval;
andersca's avatar
andersca committed
108 109
        if (handleEventFunc) {
            interpreter->startTimeoutCheck();
darin's avatar
darin committed
110
            retval = handleEventFunc->call(exec, listener, args);
andersca's avatar
andersca committed
111
        } else {
darin's avatar
darin committed
112 113 114 115
            JSObject* thisObj;
            if (isWindowEvent)
                thisObj = window;
            else
darin's avatar
darin committed
116
                thisObj = static_cast<JSObject*>(toJS(exec, event->currentTarget()));
andersca's avatar
andersca committed
117
            interpreter->startTimeoutCheck();
darin's avatar
darin committed
118 119
            retval = listener->call(exec, thisObj, args);
        }
andersca's avatar
andersca committed
120
        interpreter->stopTimeoutCheck();
darin's avatar
darin committed
121 122 123 124 125 126

        window->setCurrentEvent(0);
        interpreter->setCurrentEvent(0);

        if (exec->hadException()) {
            JSObject* exception = exec->exception()->toObject(exec);
darin's avatar
darin committed
127
            String message = exception->get(exec, messagePropertyName)->toString(exec);
darin's avatar
darin committed
128
            int lineNumber = exception->get(exec, "line")->toInt32(exec);
darin's avatar
darin committed
129
            String sourceURL = exception->get(exec, "sourceURL")->toString(exec);
darin's avatar
darin committed
130
            if (Interpreter::shouldPrintExceptions())
131
                printf("(event handler):%s\n", message.utf8().data());
132
            frame->addMessageToConsole(message, lineNumber, sourceURL);
darin's avatar
darin committed
133 134 135
            exec->clearException();
        } else {
            if (!retval->isUndefinedOrNull() && event->storesResultAsString())
darin's avatar
darin committed
136
                event->storeResult(retval->toString(exec));
137
            if (html) {
darin's avatar
darin committed
138 139
                bool retvalbool;
                if (retval->getBoolean(retvalbool) && !retvalbool)
darin's avatar
darin committed
140
                    event->preventDefault();
141
            }
darin's avatar
darin committed
142 143
        }

darin's avatar
darin committed
144
        Document::updateDocumentsRendering();
darin's avatar
darin committed
145 146
        deref();
    }
kocienda's avatar
kocienda committed
147 148
}

darin's avatar
darin committed
149
bool JSAbstractEventListener::isHTMLEventListener() const
kocienda's avatar
kocienda committed
150
{
darin's avatar
darin committed
151
    return html;
kocienda's avatar
kocienda committed
152 153
}

mjs's avatar
mjs committed
154 155
// -------------------------------------------------------------------------

darin's avatar
darin committed
156
JSUnprotectedEventListener::JSUnprotectedEventListener(JSObject* _listener, Window* _win, bool _html)
mjs's avatar
mjs committed
157 158 159 160
  : JSAbstractEventListener(_html)
  , listener(_listener)
  , win(_win)
{
darin's avatar
darin committed
161 162 163 164 165
    if (_listener) {
        Window::UnprotectedListenersMap& listeners = _html
            ? _win->jsUnprotectedHTMLEventListeners : _win->jsUnprotectedEventListeners;
        listeners.set(_listener, this);
    }
mjs's avatar
mjs committed
166 167 168 169
}

JSUnprotectedEventListener::~JSUnprotectedEventListener()
{
darin's avatar
darin committed
170 171 172 173 174
    if (listener && win) {
        Window::UnprotectedListenersMap& listeners = isHTMLEventListener()
            ? win->jsUnprotectedHTMLEventListeners : win->jsUnprotectedEventListeners;
        listeners.remove(listener);
    }
mjs's avatar
mjs committed
175 176
}

darin's avatar
darin committed
177
JSObject* JSUnprotectedEventListener::listenerObj() const
mjs's avatar
mjs committed
178 179 180 181
{ 
    return listener; 
}

darin's avatar
darin committed
182
Window* JSUnprotectedEventListener::windowObj() const
mjs's avatar
mjs committed
183 184 185 186
{
    return win;
}

sullivan's avatar
sullivan committed
187 188
void JSUnprotectedEventListener::clearWindowObj()
{
darin's avatar
darin committed
189
    win = 0;
sullivan's avatar
sullivan committed
190 191
}

mjs's avatar
mjs committed
192 193
void JSUnprotectedEventListener::mark()
{
darin's avatar
darin committed
194 195
    if (listener && !listener->marked())
        listener->mark();
mjs's avatar
mjs committed
196 197 198 199
}

// -------------------------------------------------------------------------

darin's avatar
darin committed
200 201 202 203
JSEventListener::JSEventListener(JSObject* _listener, Window* _win, bool _html)
    : JSAbstractEventListener(_html)
    , listener(_listener)
    , win(_win)
mjs's avatar
mjs committed
204
{
darin's avatar
darin committed
205 206 207 208 209
    if (_listener) {
        Window::ListenersMap& listeners = _html
            ? _win->jsHTMLEventListeners : _win->jsEventListeners;
        listeners.set(_listener, this);
    }
mjs's avatar
mjs committed
210 211 212 213
}

JSEventListener::~JSEventListener()
{
darin's avatar
darin committed
214 215 216 217 218
    if (listener && win) {
        Window::ListenersMap& listeners = isHTMLEventListener()
            ? win->jsHTMLEventListeners : win->jsEventListeners;
        listeners.remove(listener);
    }
mjs's avatar
mjs committed
219
}
mjs's avatar
mjs committed
220

darin's avatar
darin committed
221
JSObject* JSEventListener::listenerObj() const
mjs's avatar
mjs committed
222
{ 
mjs's avatar
mjs committed
223
    return listener; 
mjs's avatar
mjs committed
224 225
}

darin's avatar
darin committed
226
Window* JSEventListener::windowObj() const
mjs's avatar
mjs committed
227 228 229 230
{
    return win;
}

sullivan's avatar
sullivan committed
231 232
void JSEventListener::clearWindowObj()
{
darin's avatar
darin committed
233
    win = 0;
sullivan's avatar
sullivan committed
234 235
}

mjs's avatar
mjs committed
236 237
// -------------------------------------------------------------------------

darin's avatar
darin committed
238
JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& code, Window* win, Node* node, int lineno)
darin's avatar
darin committed
239 240 241 242 243 244
  : JSEventListener(0, win, true)
  , m_functionName(functionName)
  , code(code)
  , parsed(false)
  , lineNumber(lineno)
  , originalNode(node)
mjs's avatar
mjs committed
245
{
darin's avatar
darin committed
246
    // We don't retain the original node because we assume it
mjs's avatar
mjs committed
247 248 249 250
    // 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.
mjs's avatar
mjs committed
251 252
}

darin's avatar
darin committed
253
JSObject* JSLazyEventListener::listenerObj() const
mjs's avatar
mjs committed
254
{
darin's avatar
darin committed
255
    parseCode();
darin's avatar
darin committed
256
    return listener;
mjs's avatar
mjs committed
257 258
}

darin's avatar
darin committed
259
JSValue* JSLazyEventListener::eventParameterName() const
eseidel's avatar
eseidel committed
260 261 262 263 264
{
    static ProtectedPtr<JSValue> eventString = jsString("event");
    return eventString.get();
}

mjs's avatar
mjs committed
265 266
void JSLazyEventListener::parseCode() const
{
darin's avatar
darin committed
267 268 269 270
    if (parsed)
        return;
    parsed = true;

mjs's avatar
mjs committed
271
    Frame *frame = windowObj()->frame();
darin's avatar
darin committed
272
    KJSProxy *proxy = 0;
mjs's avatar
mjs committed
273
    if (frame)
darin's avatar
darin committed
274
        proxy = frame->scriptProxy();
mjs's avatar
mjs committed
275 276

    if (proxy) {
darin's avatar
darin committed
277 278 279 280 281 282 283
        ScriptInterpreter* interpreter = proxy->interpreter();
        ExecState* exec = interpreter->globalExec();

        JSLock lock;
        JSObject* constr = interpreter->builtinFunction();
        List args;

284
        UString sourceURL(frame->url().url());
darin's avatar
darin committed
285 286
        args.append(eventParameterName());
        args.append(jsString(code));
darin's avatar
darin committed
287
        listener = constr->construct(exec, args, m_functionName, sourceURL, lineNumber); // ### is globalExec ok ?
darin's avatar
darin committed
288

mjs's avatar
mjs committed
289 290
        FunctionImp* listenerAsFunction = static_cast<FunctionImp*>(listener.get());

darin's avatar
darin committed
291 292 293 294 295 296 297
        if (exec->hadException()) {
            exec->clearException();

            // failed to parse, so let's just make this listener a no-op
            listener = 0;
        } else if (originalNode) {
            // Add the event's home element to the scope
darin's avatar
darin committed
298
            // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
mjs's avatar
mjs committed
299
            ScopeChain scope = listenerAsFunction->scope();
darin's avatar
darin committed
300

darin's avatar
darin committed
301
            JSValue* thisObj = toJS(exec, originalNode);
darin's avatar
darin committed
302
            if (thisObj->isObject()) {
ggaren's avatar
ggaren committed
303
                static_cast<DOMEventTargetNode*>(thisObj)->pushEventHandlerScope(exec, scope);
mjs's avatar
mjs committed
304
                listenerAsFunction->setScope(scope);
darin's avatar
darin committed
305
            }
mjs's avatar
mjs committed
306
        }
mjs's avatar
mjs committed
307 308 309
    }

    // no more need to keep the unparsed code around
darin's avatar
darin committed
310
    m_functionName = String();
darin's avatar
darin committed
311
    code = String();
darin's avatar
darin committed
312

darin's avatar
darin committed
313 314 315 316 317
    if (listener) {
        Window::ListenersMap& listeners = isHTMLEventListener()
            ? windowObj()->jsHTMLEventListeners : windowObj()->jsEventListeners;
        listeners.set(listener, const_cast<JSLazyEventListener*>(this));
    }
mjs's avatar
mjs committed
318 319
}

darin's avatar
darin committed
320
JSValue* getNodeEventListener(EventTargetNode* n, const AtomicString& eventType)
kocienda's avatar
kocienda committed
321
{
darin's avatar
darin committed
322 323 324 325
    if (JSAbstractEventListener* listener = static_cast<JSAbstractEventListener*>(n->getHTMLEventListener(eventType)))
        if (JSValue* obj = listener->listenerObj())
            return obj;
    return jsNull();
kocienda's avatar
kocienda committed
326 327 328 329
}

// -------------------------------------------------------------------------

330 331
const ClassInfo DOMEvent::info = { "Event", 0, &DOMEventTable, 0 };
/*
trey's avatar
trey committed
332
@begin DOMEventTable 12
darin's avatar
darin committed
333 334 335 336 337 338 339 340
  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
darin's avatar
darin committed
341 342
  returnValue   DOMEvent::ReturnValue   DontDelete
  cancelBubble  DOMEvent::CancelBubble  DontDelete
darin's avatar
darin committed
343
  dataTransfer  DOMEvent::DataTransfer  DontDelete|ReadOnly
trey's avatar
trey committed
344
  clipboardData  DOMEvent::ClipboardData  DontDelete|ReadOnly
345 346
@end
@begin DOMEventProtoTable 3
darin's avatar
darin committed
347 348 349
  stopPropagation       DOMEvent::StopPropagation       DontDelete|Function 0
  preventDefault        DOMEvent::PreventDefault        DontDelete|Function 0
  initEvent             DOMEvent::InitEvent             DontDelete|Function 3
350 351
@end
*/
352 353
KJS_IMPLEMENT_PROTOFUNC(DOMEventProtoFunc)
KJS_IMPLEMENT_PROTOTYPE("DOMEvent", DOMEventProto, DOMEventProtoFunc)
354

darin's avatar
darin committed
355
DOMEvent::DOMEvent(ExecState *exec, Event *e)
356
  : m_impl(e), clipboard(0) 
mjs's avatar
mjs committed
357
{
358
    setPrototype(DOMEventProto::self(exec));
mjs's avatar
mjs committed
359
}
kocienda's avatar
kocienda committed
360 361 362

DOMEvent::~DOMEvent()
{
363
    ScriptInterpreter::forgetDOMObject(m_impl.get());
kocienda's avatar
kocienda committed
364 365
}

trey's avatar
trey committed
366
// pass marks through to JS objects we hold during garbage collection
367
void DOMEvent::mark()
trey's avatar
trey committed
368
{
369
    DOMObject::mark();
trey's avatar
trey committed
370 371 372 373
    if (clipboard && !clipboard->marked())
        clipboard->mark();
}

mjs's avatar
mjs committed
374
bool DOMEvent::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
375
{
376
    return getStaticValueSlot<DOMEvent, DOMObject>(exec, &DOMEventTable, this, propertyName, slot);
377
}
kocienda's avatar
kocienda committed
378

darin's avatar
darin committed
379
JSValue *DOMEvent::getValueProperty(ExecState *exec, int token) const
kocienda's avatar
kocienda committed
380
{
darin's avatar
darin committed
381
  Event &event = *m_impl;
382 383
  switch (token) {
  case Type:
darin's avatar
darin committed
384
    return jsString(event.type());
385 386
  case Target:
  case SrcElement: /*MSIE extension - "the object that fired the event"*/
darin's avatar
darin committed
387
    return toJS(exec, event.target());
388
  case CurrentTarget:
darin's avatar
darin committed
389
    return toJS(exec, event.currentTarget());
390
  case EventPhase:
darin's avatar
darin committed
391
    return jsNumber(event.eventPhase());
392
  case Bubbles:
darin's avatar
darin committed
393
    return jsBoolean(event.bubbles());
mjs's avatar
mjs committed
394
  case CancelBubble:
darin's avatar
darin committed
395
    return jsBoolean(event.getCancelBubble());
mjs's avatar
mjs committed
396
  case ReturnValue:
darin's avatar
darin committed
397
    return jsBoolean(!event.defaultPrevented());
398
  case Cancelable:
darin's avatar
darin committed
399
    return jsBoolean(event.cancelable());
400
  case TimeStamp:
darin's avatar
darin committed
401
    return jsNumber(event.timeStamp());
trey's avatar
trey committed
402 403
  case ClipboardData:
  {
404
    if (event.isClipboardEvent()) {
darin's avatar
darin committed
405
      ClipboardEvent *impl = static_cast<ClipboardEvent *>(&event);
406
      if (!clipboard)
trey's avatar
trey committed
407
        clipboard = new Clipboard(exec, impl->clipboard());
darin's avatar
darin committed
408
      return clipboard;
409
    } else
darin's avatar
darin committed
410
      return jsUndefined();
trey's avatar
trey committed
411 412 413
  }
  case DataTransfer:
  {
414
    if (event.isDragEvent()) {
darin's avatar
darin committed
415
      MouseEvent *impl = static_cast<MouseEvent *>(&event);
416
      if (!clipboard)
trey's avatar
trey committed
417
        clipboard = new Clipboard(exec, impl->clipboard());
darin's avatar
darin committed
418
      return clipboard;
419
    } else
darin's avatar
darin committed
420
      return jsUndefined();
trey's avatar
trey committed
421
  }
422
  default:
423
    return 0;
424
  }
kocienda's avatar
kocienda committed
425 426
}

darin's avatar
darin committed
427
void DOMEvent::put(ExecState *exec, const Identifier &propertyName,
darin's avatar
darin committed
428
                      JSValue *value, int attr)
darin's avatar
darin committed
429
{
430
    lookupPut<DOMEvent, DOMObject>(exec, propertyName, value, attr, &DOMEventTable, this);
darin's avatar
darin committed
431 432
}

darin's avatar
darin committed
433
void DOMEvent::putValueProperty(ExecState *exec, int token, JSValue *value, int)
darin's avatar
darin committed
434
{
darin's avatar
darin committed
435
  Event &event = *m_impl;
darin's avatar
darin committed
436 437
  switch (token) {
  case ReturnValue:
darin's avatar
darin committed
438
    event.setDefaultPrevented(!value->toBoolean(exec));
darin's avatar
darin committed
439 440
    break;
  case CancelBubble:
darin's avatar
darin committed
441
    event.setCancelBubble(value->toBoolean(exec));
darin's avatar
darin committed
442 443 444 445 446 447
    break;
  default:
    break;
  }
}

darin's avatar
darin committed
448
JSValue *DOMEventProtoFunc::callAsFunction(ExecState *exec, JSObject * thisObj, const List &args)
kocienda's avatar
kocienda committed
449
{
darin's avatar
darin committed
450 451
  if (!thisObj->inherits(&DOMEvent::info))
    return throwError(exec, TypeError);
darin's avatar
darin committed
452
  Event &event = *static_cast<DOMEvent *>( thisObj )->impl();
kocienda's avatar
kocienda committed
453
  switch (id) {
454
    case DOMEvent::StopPropagation:
kocienda's avatar
kocienda committed
455
      event.stopPropagation();
darin's avatar
darin committed
456
      return jsUndefined();
457
    case DOMEvent::PreventDefault:
kocienda's avatar
kocienda committed
458
      event.preventDefault();
darin's avatar
darin committed
459
      return jsUndefined();
460
    case DOMEvent::InitEvent:
darin's avatar
darin committed
461
      event.initEvent(AtomicString(args[0]->toString(exec)), args[1]->toBoolean(exec), args[2]->toBoolean(exec));
darin's avatar
darin committed
462
      return jsUndefined();
kocienda's avatar
kocienda committed
463
  };
darin's avatar
darin committed
464
  return jsUndefined();
kocienda's avatar
kocienda committed
465 466
}

darin's avatar
darin committed
467
JSValue *toJS(ExecState *exec, Event *e)
kocienda's avatar
kocienda committed
468
{
469
  if (!e)
darin's avatar
darin committed
470
    return jsNull();
mjs's avatar
mjs committed
471
  ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
mjs's avatar
mjs committed
472

mjs's avatar
mjs committed
473
  JSLock lock;
mjs's avatar
mjs committed
474

475
  DOMObject *ret = interp->getDOMObject(e);
darin's avatar
darin committed
476
  if (!ret) {
477
    if (e->isKeyboardEvent())
478
      ret = new JSKeyboardEvent(exec, static_cast<KeyboardEvent *>(e));
479
    else if (e->isMouseEvent())
480
      ret = new JSMouseEvent(exec, static_cast<MouseEvent *>(e));
481
    else if (e->isWheelEvent())
darin's avatar
darin committed
482
      ret = new JSWheelEvent(exec, static_cast<WheelEvent *>(e));
483
    else if (e->isUIEvent())
484
      ret = new JSUIEvent(exec, static_cast<UIEvent *>(e));
485
    else if (e->isMutationEvent())
darin's avatar
darin committed
486
      ret = new JSMutationEvent(exec, static_cast<MutationEvent *>(e));
andersca's avatar
andersca committed
487 488
    else if (e->isOverflowEvent())
      ret = new JSOverflowEvent(exec, static_cast<OverflowEvent*>(e));
darin's avatar
darin committed
489
    else
ggaren's avatar
ggaren committed
490
      ret = new JSEvent(exec, e);
darin's avatar
darin committed
491

492
    interp->putDOMObject(e, ret);
darin's avatar
darin committed
493
  }
mjs's avatar
mjs committed
494

495
  return ret;
kocienda's avatar
kocienda committed
496 497
}

darin's avatar
darin committed
498
Event *toEvent(JSValue *val)
kocienda's avatar
kocienda committed
499
{
500
    if (!val || !val->isObject(&DOMEvent::info))
501 502
        return 0;
    return static_cast<DOMEvent *>(val)->impl();
kocienda's avatar
kocienda committed
503 504 505 506
}

// -------------------------------------------------------------------------

trey's avatar
trey committed
507 508 509
const ClassInfo Clipboard::info = { "Clipboard", 0, &ClipboardTable, 0 };

/* Source for ClipboardTable. Use "make hashtables" to regenerate.
510
@begin ClipboardTable 3
darin's avatar
darin committed
511 512 513
  dropEffect    Clipboard::DropEffect   DontDelete
  effectAllowed Clipboard::EffectAllowed        DontDelete
  types         Clipboard::Types        DontDelete|ReadOnly
trey's avatar
trey committed
514
@end
trey's avatar
trey committed
515
@begin ClipboardProtoTable 4
darin's avatar
darin committed
516 517 518 519
  clearData     Clipboard::ClearData    DontDelete|Function 0
  getData       Clipboard::GetData      DontDelete|Function 1
  setData       Clipboard::SetData      DontDelete|Function 2
  setDragImage  Clipboard::SetDragImage DontDelete|Function 3
trey's avatar
trey committed
520 521 522
@end
*/

523 524 525
KJS_DEFINE_PROTOTYPE(ClipboardProto)
KJS_IMPLEMENT_PROTOFUNC(ClipboardProtoFunc)
KJS_IMPLEMENT_PROTOTYPE("Clipboard", ClipboardProto, ClipboardProtoFunc)
trey's avatar
trey committed
526

darin's avatar
darin committed
527
Clipboard::Clipboard(ExecState *exec, WebCore::Clipboard *cb)
mjs's avatar
mjs committed
528
  : clipboard(cb)
trey's avatar
trey committed
529
{
mjs's avatar
mjs committed
530
    setPrototype(ClipboardProto::self(exec));
trey's avatar
trey committed
531 532
}

mjs's avatar
mjs committed
533
bool Clipboard::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
trey's avatar
trey committed
534
{
mjs's avatar
mjs committed
535
    return getStaticValueSlot<Clipboard, DOMObject>(exec, &ClipboardTable, this, propertyName, slot);
trey's avatar
trey committed
536 537
}

darin's avatar
darin committed
538
JSValue *Clipboard::getValueProperty(ExecState *exec, int token) const
trey's avatar
trey committed
539 540 541
{
    switch (token) {
        case DropEffect:
542
            assert(clipboard->isForDragging() || clipboard->dropEffect().isNull());
darin's avatar
darin committed
543
            return jsStringOrUndefined(clipboard->dropEffect());
trey's avatar
trey committed
544
        case EffectAllowed:
545
            assert(clipboard->isForDragging() || clipboard->effectAllowed().isNull());
darin's avatar
darin committed
546
            return jsStringOrUndefined(clipboard->effectAllowed());
547 548
        case Types:
        {
549 550
            HashSet<String> types = clipboard->types();
            if (types.isEmpty())
darin's avatar
darin committed
551
                return jsNull(); 
552
            else {
553
                List list;
554 555
                HashSet<String>::const_iterator end = types.end();
                for (HashSet<String>::const_iterator it = types.begin(); it != end; ++it) 
darin's avatar
darin committed
556
                    list.append(jsString(UString(*it)));
darin's avatar
darin committed
557
                return exec->lexicalInterpreter()->builtinArray()->construct(exec, list);
558 559
            }
        }
trey's avatar
trey committed
560
        default:
darin's avatar
darin committed
561
            return NULL;
trey's avatar
trey committed
562 563 564
    }
}

darin's avatar
darin committed
565
void Clipboard::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
trey's avatar
trey committed
566
{
darin's avatar
darin committed
567
    lookupPut<Clipboard,DOMObject>(exec, propertyName, value, attr, &ClipboardTable, this );
trey's avatar
trey committed
568 569
}

darin's avatar
darin committed
570
void Clipboard::putValueProperty(ExecState *exec, int token, JSValue *value, int /*attr*/)
trey's avatar
trey committed
571 572 573
{
    switch (token) {
        case DropEffect:
574 575
            // can never set this when not for dragging, thus getting always returns NULL string
            if (clipboard->isForDragging())
darin's avatar
darin committed
576
                clipboard->setDropEffect(value->toString(exec));
trey's avatar
trey committed
577
            break;
trey's avatar
trey committed
578
        case EffectAllowed:
579 580
            // can never set this when not for dragging, thus getting always returns NULL string
            if (clipboard->isForDragging())
darin's avatar
darin committed
581
                clipboard->setEffectAllowed(value->toString(exec));
trey's avatar
trey committed
582 583 584 585
            break;
    }
}

darin's avatar
darin committed
586
JSValue *ClipboardProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
trey's avatar
trey committed
587
{
darin's avatar
darin committed
588 589
    if (!thisObj->inherits(&Clipboard::info))
        return throwError(exec, TypeError);
trey's avatar
trey committed
590

darin's avatar
darin committed
591
    Clipboard *cb = static_cast<Clipboard *>(thisObj);
trey's avatar
trey committed
592 593 594 595
    switch (id) {
        case Clipboard::ClearData:
            if (args.size() == 0) {
                cb->clipboard->clearAllData();
darin's avatar
darin committed
596
                return jsUndefined();
trey's avatar
trey committed
597
            } else if (args.size() == 1) {
darin's avatar
darin committed
598
                cb->clipboard->clearData(args[0]->toString(exec));
darin's avatar
darin committed
599
                return jsUndefined();
600
            } else
darin's avatar
darin committed
601
                return throwError(exec, SyntaxError, "clearData: Invalid number of arguments");
trey's avatar
trey committed
602 603 604 605
        case Clipboard::GetData:
        {
            if (args.size() == 1) {
                bool success;
darin's avatar
darin committed
606
                String result = cb->clipboard->getData(args[0]->toString(exec), success);
607
                if (success)
darin's avatar
darin committed
608
                    return jsString(result);
609
                else
darin's avatar
darin committed
610
                    return jsUndefined();
611
            } else
darin's avatar
darin committed
612
                return throwError(exec, SyntaxError, "getData: Invalid number of arguments");
trey's avatar
trey committed
613 614
        }
        case Clipboard::SetData:
615
            if (args.size() == 2)
darin's avatar
darin committed
616
                return jsBoolean(cb->clipboard->setData(args[0]->toString(exec), args[1]->toString(exec)));
617
            else
darin's avatar
darin committed
618
                return throwError(exec, SyntaxError, "setData: Invalid number of arguments");
trey's avatar
trey committed
619 620
        case Clipboard::SetDragImage:
        {
621
            if (!cb->clipboard->isForDragging())
darin's avatar
darin committed
622
                return jsUndefined();
623

darin's avatar
darin committed
624 625
            if (args.size() != 3)
                return throwError(exec, SyntaxError, "setDragImage: Invalid number of arguments");
trey's avatar
trey committed
626

darin's avatar
darin committed
627 628
            int x = (int)args[1]->toNumber(exec);
            int y = (int)args[2]->toNumber(exec);
trey's avatar
trey committed
629 630

            // See if they passed us a node
darin's avatar
darin committed
631
            Node *node = toNode(args[0]);
632
            if (!node)
andersca's avatar
andersca committed
633
                return throwError(exec, TypeError);
634 635 636 637
            
            if (!node->isElementNode())
                return throwError(exec, SyntaxError, "setDragImageFromElement: Invalid first argument");

darin's avatar
darin committed
638
            if (static_cast<Element*>(node)->hasLocalName(imgTag) && 
639
                !node->inDocument())
darin's avatar
darin committed
640
                cb->clipboard->setDragImage(static_cast<HTMLImageElement*>(node)->cachedImage(), IntPoint(x, y));
641 642 643 644
            else
                cb->clipboard->setDragImageElement(node, IntPoint(x, y));                    
                
            return jsUndefined();
trey's avatar
trey committed
645
        }
trey's avatar
trey committed
646
    }
darin's avatar
darin committed
647
    return jsUndefined();
trey's avatar
trey committed
648 649
}

650
}