kjs_events.cpp 16.2 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
#include "Chrome.h"
weinig's avatar
 
weinig committed
26 27
#include "Clipboard.h"
#include "ClipboardEvent.h"
darin's avatar
darin committed
28
#include "Document.h"
weinig's avatar
 
weinig committed
29
#include "Event.h"
darin's avatar
darin committed
30 31
#include "EventNames.h"
#include "Frame.h"
darin's avatar
darin committed
32
#include "FrameLoader.h"
weinig's avatar
 
weinig committed
33 34
#include "HTMLImageElement.h"
#include "HTMLNames.h"
ggaren's avatar
ggaren committed
35
#include "JSEvent.h"
weinig's avatar
weinig committed
36
#include "JSEventTargetNode.h"
darin's avatar
darin committed
37
#include "KURL.h"
andersca's avatar
andersca committed
38
#include "Page.h"
darin's avatar
darin committed
39 40
#include "kjs_proxy.h"
#include "kjs_window.h"
kocienda's avatar
kocienda committed
41

darin's avatar
darin committed
42
#include "kjs_events.lut.h"
43

weinig's avatar
weinig committed
44 45 46
namespace WebCore {

using namespace KJS;
darin's avatar
darin committed
47
using namespace EventNames;
48
using namespace HTMLNames;
darin's avatar
darin committed
49

weinig's avatar
weinig committed
50 51
JSAbstractEventListener::JSAbstractEventListener(bool html)
    : m_html(html)
kocienda's avatar
kocienda committed
52 53 54
{
}

darin's avatar
darin committed
55
void JSAbstractEventListener::handleEvent(Event* ele, bool isWindowEvent)
kocienda's avatar
kocienda committed
56
{
57
#ifdef KJS_DEBUGGER
darin's avatar
darin committed
58 59
    if (KJSDebugWin::instance() && KJSDebugWin::instance()->inSession())
        return;
60
#endif
61

weinig's avatar
weinig committed
62
    Event* event = ele;
63

darin's avatar
darin committed
64 65 66
    JSObject* listener = listenerObj();
    if (!listener)
        return;
mjs's avatar
mjs committed
67

darin's avatar
darin committed
68
    Window* window = windowObj();
andrew's avatar
andrew committed
69 70 71 72
    // Null check as clearWindowObj() can clear this and we still get called back by
    // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275
    if (!window)
        return;
mjs's avatar
mjs committed
73 74
    Frame *frame = window->frame();
    if (!frame)
darin's avatar
darin committed
75
        return;
darin's avatar
darin committed
76
    KJSProxy* proxy = frame->scriptProxy();
darin's avatar
darin committed
77 78
    if (!proxy)
        return;
darin's avatar
darin committed
79

darin's avatar
darin committed
80
    JSLock lock;
weinig's avatar
weinig committed
81

darin's avatar
darin committed
82 83
    ScriptInterpreter* interpreter = proxy->interpreter();
    ExecState* exec = interpreter->globalExec();
weinig's avatar
weinig committed
84

darin's avatar
darin committed
85 86
    JSValue* handleEventFuncValue = listener->get(exec, "handleEvent");
    JSObject* handleEventFunc = 0;
weinig's avatar
weinig committed
87
    if (handleEventFuncValue->isObject()) {
darin's avatar
darin committed
88 89 90 91
        handleEventFunc = static_cast<JSObject*>(handleEventFuncValue);
        if (!handleEventFunc->implementsCall())
            handleEventFunc = 0;
    }
weinig's avatar
weinig committed
92

darin's avatar
darin committed
93 94
    if (handleEventFunc || listener->implementsCall()) {
        ref();
weinig's avatar
weinig committed
95

darin's avatar
darin committed
96
        List args;
darin's avatar
darin committed
97
        args.append(toJS(exec, event));
weinig's avatar
weinig committed
98

darin's avatar
darin committed
99 100 101 102
        // Set the event we're handling in the Window object
        window->setCurrentEvent(event);
        // ... and in the interpreter
        interpreter->setCurrentEvent(event);
weinig's avatar
weinig committed
103

darin's avatar
darin committed
104
        JSValue* retval;
andersca's avatar
andersca committed
105 106
        if (handleEventFunc) {
            interpreter->startTimeoutCheck();
darin's avatar
darin committed
107
            retval = handleEventFunc->call(exec, listener, args);
andersca's avatar
andersca committed
108
        } else {
darin's avatar
darin committed
109 110 111 112
            JSObject* thisObj;
            if (isWindowEvent)
                thisObj = window;
            else
darin's avatar
darin committed
113
                thisObj = static_cast<JSObject*>(toJS(exec, event->currentTarget()));
andersca's avatar
andersca committed
114
            interpreter->startTimeoutCheck();
darin's avatar
darin committed
115 116
            retval = listener->call(exec, thisObj, args);
        }
andersca's avatar
andersca committed
117
        interpreter->stopTimeoutCheck();
darin's avatar
darin committed
118 119 120 121 122 123

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

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

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

darin's avatar
darin committed
147
bool JSAbstractEventListener::isHTMLEventListener() const
kocienda's avatar
kocienda committed
148
{
weinig's avatar
weinig committed
149
    return m_html;
kocienda's avatar
kocienda committed
150 151
}

mjs's avatar
mjs committed
152 153
// -------------------------------------------------------------------------

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

JSUnprotectedEventListener::~JSUnprotectedEventListener()
{
weinig's avatar
weinig committed
168
    if (m_listener && m_win) {
darin's avatar
darin committed
169
        Window::UnprotectedListenersMap& listeners = isHTMLEventListener()
weinig's avatar
weinig committed
170 171
            ? m_win->jsUnprotectedHTMLEventListeners() : m_win->jsUnprotectedEventListeners();
        listeners.remove(m_listener);
darin's avatar
darin committed
172
    }
mjs's avatar
mjs committed
173 174
}

darin's avatar
darin committed
175
JSObject* JSUnprotectedEventListener::listenerObj() const
weinig's avatar
weinig committed
176 177
{
    return m_listener;
mjs's avatar
mjs committed
178 179
}

darin's avatar
darin committed
180
Window* JSUnprotectedEventListener::windowObj() const
mjs's avatar
mjs committed
181
{
weinig's avatar
weinig committed
182
    return m_win;
mjs's avatar
mjs committed
183 184
}

sullivan's avatar
sullivan committed
185 186
void JSUnprotectedEventListener::clearWindowObj()
{
weinig's avatar
weinig committed
187
    m_win = 0;
sullivan's avatar
sullivan committed
188 189
}

mjs's avatar
mjs committed
190 191
void JSUnprotectedEventListener::mark()
{
weinig's avatar
weinig committed
192 193
    if (m_listener && !m_listener->marked())
        m_listener->mark();
mjs's avatar
mjs committed
194 195
}

weinig's avatar
weinig committed
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
#ifndef NDEBUG
#ifndef LOG_CHANNEL_PREFIX
#define LOG_CHANNEL_PREFIX Log
#endif
WTFLogChannel LogWebCoreEventListenerLeaks = { 0x00000000, "", WTFLogChannelOn };

struct EventListenerCounter {
    static unsigned count;
    ~EventListenerCounter()
    {
        if (count)
            LOG(WebCoreEventListenerLeaks, "LEAK: %u EventListeners\n", count);
    }
};
unsigned EventListenerCounter::count = 0;
static EventListenerCounter eventListenerCounter;
#endif

mjs's avatar
mjs committed
214 215
// -------------------------------------------------------------------------

weinig's avatar
weinig committed
216 217 218 219
JSEventListener::JSEventListener(JSObject* listener, Window* win, bool html)
    : JSAbstractEventListener(html)
    , m_listener(listener)
    , m_win(win)
mjs's avatar
mjs committed
220
{
weinig's avatar
weinig committed
221 222 223 224
    if (m_listener) {
        Window::ListenersMap& listeners = html
            ? m_win->jsHTMLEventListeners() : m_win->jsEventListeners();
        listeners.set(m_listener, this);
darin's avatar
darin committed
225
    }
weinig's avatar
weinig committed
226 227 228
#ifndef NDEBUG
    ++eventListenerCounter.count;
#endif
mjs's avatar
mjs committed
229 230 231 232
}

JSEventListener::~JSEventListener()
{
weinig's avatar
weinig committed
233
    if (m_listener && m_win) {
darin's avatar
darin committed
234
        Window::ListenersMap& listeners = isHTMLEventListener()
weinig's avatar
weinig committed
235 236
            ? m_win->jsHTMLEventListeners() : m_win->jsEventListeners();
        listeners.remove(m_listener);
darin's avatar
darin committed
237
    }
weinig's avatar
weinig committed
238 239 240
#ifndef NDEBUG
    --eventListenerCounter.count;
#endif
mjs's avatar
mjs committed
241
}
mjs's avatar
mjs committed
242

darin's avatar
darin committed
243
JSObject* JSEventListener::listenerObj() const
weinig's avatar
weinig committed
244 245
{
    return m_listener;
mjs's avatar
mjs committed
246 247
}

darin's avatar
darin committed
248
Window* JSEventListener::windowObj() const
mjs's avatar
mjs committed
249
{
weinig's avatar
weinig committed
250
    return m_win;
mjs's avatar
mjs committed
251 252
}

sullivan's avatar
sullivan committed
253 254
void JSEventListener::clearWindowObj()
{
weinig's avatar
weinig committed
255
    m_win = 0;
sullivan's avatar
sullivan committed
256 257
}

mjs's avatar
mjs committed
258 259
// -------------------------------------------------------------------------

weinig's avatar
weinig committed
260 261 262 263 264 265 266
JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& code, Window* win, Node* node, int lineNumber)
    : JSEventListener(0, win, true)
    , m_functionName(functionName)
    , m_code(code)
    , m_parsed(false)
    , m_lineNumber(lineNumber)
    , m_originalNode(node)
mjs's avatar
mjs committed
267
{
darin's avatar
darin committed
268
    // We don't retain the original node because we assume it
mjs's avatar
mjs committed
269 270 271 272
    // 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
273 274
}

darin's avatar
darin committed
275
JSObject* JSLazyEventListener::listenerObj() const
mjs's avatar
mjs committed
276
{
darin's avatar
darin committed
277
    parseCode();
weinig's avatar
weinig committed
278
    return m_listener;
mjs's avatar
mjs committed
279 280
}

darin's avatar
darin committed
281
JSValue* JSLazyEventListener::eventParameterName() const
eseidel's avatar
eseidel committed
282 283 284 285 286
{
    static ProtectedPtr<JSValue> eventString = jsString("event");
    return eventString.get();
}

mjs's avatar
mjs committed
287 288
void JSLazyEventListener::parseCode() const
{
weinig's avatar
weinig committed
289
    if (m_parsed)
darin's avatar
darin committed
290
        return;
weinig's avatar
weinig committed
291
    m_parsed = true;
darin's avatar
darin committed
292

weinig's avatar
weinig committed
293 294
    Frame* frame = windowObj()->frame();
    KJSProxy* proxy = 0;
mjs's avatar
mjs committed
295
    if (frame)
darin's avatar
darin committed
296
        proxy = frame->scriptProxy();
mjs's avatar
mjs committed
297 298

    if (proxy) {
darin's avatar
darin committed
299 300 301 302 303 304 305
        ScriptInterpreter* interpreter = proxy->interpreter();
        ExecState* exec = interpreter->globalExec();

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

darin's avatar
darin committed
306
        UString sourceURL(frame->loader()->url().url());
darin's avatar
darin committed
307
        args.append(eventParameterName());
weinig's avatar
weinig committed
308 309
        args.append(jsString(m_code));
        m_listener = constr->construct(exec, args, m_functionName, sourceURL, m_lineNumber); // FIXME: is globalExec ok ?
darin's avatar
darin committed
310

weinig's avatar
weinig committed
311
        FunctionImp* listenerAsFunction = static_cast<FunctionImp*>(m_listener.get());
mjs's avatar
mjs committed
312

darin's avatar
darin committed
313 314 315 316
        if (exec->hadException()) {
            exec->clearException();

            // failed to parse, so let's just make this listener a no-op
weinig's avatar
weinig committed
317 318
            m_listener = 0;
        } else if (m_originalNode) {
darin's avatar
darin committed
319
            // Add the event's home element to the scope
darin's avatar
darin committed
320
            // (and the document, and the form - see JSHTMLElement::eventHandlerScope)
mjs's avatar
mjs committed
321
            ScopeChain scope = listenerAsFunction->scope();
darin's avatar
darin committed
322

weinig's avatar
weinig committed
323
            JSValue* thisObj = toJS(exec, m_originalNode);
darin's avatar
darin committed
324
            if (thisObj->isObject()) {
weinig's avatar
weinig committed
325
                static_cast<JSEventTargetNode*>(thisObj)->pushEventHandlerScope(exec, scope);
mjs's avatar
mjs committed
326
                listenerAsFunction->setScope(scope);
darin's avatar
darin committed
327
            }
mjs's avatar
mjs committed
328
        }
mjs's avatar
mjs committed
329 330 331
    }

    // no more need to keep the unparsed code around
darin's avatar
darin committed
332
    m_functionName = String();
weinig's avatar
weinig committed
333
    m_code = String();
darin's avatar
darin committed
334

weinig's avatar
weinig committed
335
    if (m_listener) {
darin's avatar
darin committed
336
        Window::ListenersMap& listeners = isHTMLEventListener()
mjs's avatar
mjs committed
337
            ? windowObj()->jsHTMLEventListeners() : windowObj()->jsEventListeners();
weinig's avatar
weinig committed
338
        listeners.set(m_listener, const_cast<JSLazyEventListener*>(this));
darin's avatar
darin committed
339
    }
mjs's avatar
mjs committed
340 341
}

darin's avatar
darin committed
342
JSValue* getNodeEventListener(EventTargetNode* n, const AtomicString& eventType)
kocienda's avatar
kocienda committed
343
{
weinig's avatar
weinig committed
344
    if (JSAbstractEventListener* listener = static_cast<JSAbstractEventListener*>(n->getHTMLEventListener(eventType))) {
darin's avatar
darin committed
345 346
        if (JSValue* obj = listener->listenerObj())
            return obj;
weinig's avatar
weinig committed
347
    }
darin's avatar
darin committed
348
    return jsNull();
kocienda's avatar
kocienda committed
349 350 351 352
}

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

weinig's avatar
weinig committed
353
const ClassInfo JSClipboard::info = { "Clipboard", 0, &JSClipboardTable, 0 };
trey's avatar
trey committed
354

weinig's avatar
weinig committed
355 356
/* Source for JSClipboardTable. Use "make hashtables" to regenerate.
@begin JSClipboardTable 3
weinig's avatar
weinig committed
357 358 359
  dropEffect    WebCore::JSClipboard::DropEffect   DontDelete
  effectAllowed WebCore::JSClipboard::EffectAllowed        DontDelete
  types         WebCore::JSClipboard::Types        DontDelete|ReadOnly
trey's avatar
trey committed
360
@end
weinig's avatar
weinig committed
361
@begin JSClipboardPrototypeTable 4
weinig's avatar
weinig committed
362 363 364 365
  clearData     WebCore::JSClipboard::ClearData    DontDelete|Function 0
  getData       WebCore::JSClipboard::GetData      DontDelete|Function 1
  setData       WebCore::JSClipboard::SetData      DontDelete|Function 2
  setDragImage  WebCore::JSClipboard::SetDragImage DontDelete|Function 3
trey's avatar
trey committed
366 367 368
@end
*/

weinig's avatar
weinig committed
369 370 371
KJS_DEFINE_PROTOTYPE(JSClipboardPrototype)
KJS_IMPLEMENT_PROTOTYPE_FUNCTION(JSClipboardPrototypeFunction)
KJS_IMPLEMENT_PROTOTYPE("Clipboard", JSClipboardPrototype, JSClipboardPrototypeFunction)
trey's avatar
trey committed
372

weinig's avatar
weinig committed
373 374
JSClipboard::JSClipboard(ExecState* exec, Clipboard* clipboard)
    : m_impl(clipboard)
trey's avatar
trey committed
375
{
weinig's avatar
weinig committed
376
    setPrototype(JSClipboardPrototype::self(exec));
trey's avatar
trey committed
377 378
}

weinig's avatar
weinig committed
379
JSClipboard::~JSClipboard()
trey's avatar
trey committed
380
{
weinig's avatar
weinig committed
381
    ScriptInterpreter::forgetDOMObject(m_impl.get());
trey's avatar
trey committed
382 383
}

weinig's avatar
weinig committed
384
bool JSClipboard::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
trey's avatar
trey committed
385
{
weinig's avatar
weinig committed
386 387 388 389 390
    return getStaticValueSlot<JSClipboard, DOMObject>(exec, &JSClipboardTable, this, propertyName, slot);
}

JSValue* JSClipboard::getValueProperty(ExecState* exec, int token) const
{
weinig's avatar
weinig committed
391
    Clipboard* clipboard = impl();
trey's avatar
trey committed
392 393
    switch (token) {
        case DropEffect:
ggaren's avatar
ggaren committed
394
            ASSERT(clipboard->isForDragging() || clipboard->dropEffect().isNull());
darin's avatar
darin committed
395
            return jsStringOrUndefined(clipboard->dropEffect());
trey's avatar
trey committed
396
        case EffectAllowed:
ggaren's avatar
ggaren committed
397
            ASSERT(clipboard->isForDragging() || clipboard->effectAllowed().isNull());
darin's avatar
darin committed
398
            return jsStringOrUndefined(clipboard->effectAllowed());
399 400
        case Types:
        {
401 402
            HashSet<String> types = clipboard->types();
            if (types.isEmpty())
weinig's avatar
weinig committed
403
                return jsNull();
404
            else {
405
                List list;
406
                HashSet<String>::const_iterator end = types.end();
weinig's avatar
weinig committed
407
                for (HashSet<String>::const_iterator it = types.begin(); it != end; ++it)
darin's avatar
darin committed
408
                    list.append(jsString(UString(*it)));
darin's avatar
darin committed
409
                return exec->lexicalInterpreter()->builtinArray()->construct(exec, list);
410 411
            }
        }
trey's avatar
trey committed
412
        default:
weinig's avatar
weinig committed
413
            return 0;
trey's avatar
trey committed
414 415 416
    }
}

weinig's avatar
weinig committed
417
void JSClipboard::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
trey's avatar
trey committed
418
{
weinig's avatar
weinig committed
419
    lookupPut<JSClipboard, DOMObject>(exec, propertyName, value, attr, &JSClipboardTable, this );
trey's avatar
trey committed
420 421
}

weinig's avatar
weinig committed
422
void JSClipboard::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)
trey's avatar
trey committed
423
{
weinig's avatar
weinig committed
424
    Clipboard* clipboard = impl();
trey's avatar
trey committed
425 426
    switch (token) {
        case DropEffect:
427 428
            // can never set this when not for dragging, thus getting always returns NULL string
            if (clipboard->isForDragging())
darin's avatar
darin committed
429
                clipboard->setDropEffect(value->toString(exec));
trey's avatar
trey committed
430
            break;
trey's avatar
trey committed
431
        case EffectAllowed:
432 433
            // can never set this when not for dragging, thus getting always returns NULL string
            if (clipboard->isForDragging())
darin's avatar
darin committed
434
                clipboard->setEffectAllowed(value->toString(exec));
trey's avatar
trey committed
435 436 437 438
            break;
    }
}

weinig's avatar
weinig committed
439
JSValue* JSClipboardPrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
trey's avatar
trey committed
440
{
weinig's avatar
weinig committed
441
    if (!thisObj->inherits(&JSClipboard::info))
darin's avatar
darin committed
442
        return throwError(exec, TypeError);
trey's avatar
trey committed
443

weinig's avatar
weinig committed
444
    Clipboard* clipboard = static_cast<JSClipboard*>(thisObj)->impl();
trey's avatar
trey committed
445
    switch (id) {
weinig's avatar
weinig committed
446
        case JSClipboard::ClearData:
trey's avatar
trey committed
447
            if (args.size() == 0) {
weinig's avatar
weinig committed
448
                clipboard->clearAllData();
darin's avatar
darin committed
449
                return jsUndefined();
trey's avatar
trey committed
450
            } else if (args.size() == 1) {
weinig's avatar
weinig committed
451
                clipboard->clearData(args[0]->toString(exec));
darin's avatar
darin committed
452
                return jsUndefined();
453
            } else
darin's avatar
darin committed
454
                return throwError(exec, SyntaxError, "clearData: Invalid number of arguments");
weinig's avatar
weinig committed
455
        case JSClipboard::GetData:
trey's avatar
trey committed
456 457 458
        {
            if (args.size() == 1) {
                bool success;
weinig's avatar
weinig committed
459
                String result = clipboard->getData(args[0]->toString(exec), success);
460
                if (success)
darin's avatar
darin committed
461
                    return jsString(result);
weinig's avatar
weinig committed
462
                return jsUndefined();
463
            } else
darin's avatar
darin committed
464
                return throwError(exec, SyntaxError, "getData: Invalid number of arguments");
trey's avatar
trey committed
465
        }
weinig's avatar
weinig committed
466
        case JSClipboard::SetData:
467
            if (args.size() == 2)
weinig's avatar
weinig committed
468 469 470
                return jsBoolean(clipboard->setData(args[0]->toString(exec), args[1]->toString(exec)));
            return throwError(exec, SyntaxError, "setData: Invalid number of arguments");
        case JSClipboard::SetDragImage:
trey's avatar
trey committed
471
        {
weinig's avatar
weinig committed
472
            if (!clipboard->isForDragging())
darin's avatar
darin committed
473
                return jsUndefined();
474

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

weinig's avatar
weinig committed
478 479
            int x = static_cast<int>(args[1]->toNumber(exec));
            int y = static_cast<int>(args[2]->toNumber(exec));
trey's avatar
trey committed
480 481

            // See if they passed us a node
weinig's avatar
weinig committed
482
            Node* node = toNode(args[0]);
483
            if (!node)
andersca's avatar
andersca committed
484
                return throwError(exec, TypeError);
weinig's avatar
weinig committed
485

486 487 488
            if (!node->isElementNode())
                return throwError(exec, SyntaxError, "setDragImageFromElement: Invalid first argument");

weinig's avatar
weinig committed
489
            if (static_cast<Element*>(node)->hasLocalName(imgTag) &&
490
                !node->inDocument())
weinig's avatar
weinig committed
491
                clipboard->setDragImage(static_cast<HTMLImageElement*>(node)->cachedImage(), IntPoint(x, y));
492
            else
weinig's avatar
weinig committed
493 494
                clipboard->setDragImageElement(node, IntPoint(x, y));

495
            return jsUndefined();
trey's avatar
trey committed
496
        }
trey's avatar
trey committed
497
    }
darin's avatar
darin committed
498
    return jsUndefined();
trey's avatar
trey committed
499 500
}

weinig's avatar
weinig committed
501
JSValue* toJS(ExecState* exec, Clipboard* obj)
weinig's avatar
weinig committed
502
{
weinig's avatar
weinig committed
503
    return cacheDOMObject<Clipboard, JSClipboard>(exec, obj);
weinig's avatar
weinig committed
504 505
}

weinig's avatar
weinig committed
506
Clipboard* toClipboard(JSValue* val)
weinig's avatar
weinig committed
507 508 509 510
{
    return val->isObject(&JSClipboard::info) ? static_cast<JSClipboard*>(val)->impl() : 0;
}

weinig's avatar
weinig committed
511
} // namespace WebCore