kjs_events.cpp 16.7 KB
Newer Older
kocienda's avatar
kocienda committed
1 2
/*
 *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
3
 *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All Rights Reserved.
kocienda's avatar
kocienda committed
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 *  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
ddkilzer's avatar
ddkilzer committed
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
kocienda's avatar
kocienda committed
18
 */
darin's avatar
darin committed
19

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

darin's avatar
darin committed
23
#include "CString.h"
weinig's avatar
weinig committed
24
#include "Chrome.h"
weinig's avatar
 
weinig committed
25 26
#include "Clipboard.h"
#include "ClipboardEvent.h"
weinig's avatar
weinig committed
27
#include "DOMWindow.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

68
    KJS::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;
weinig's avatar
weinig committed
73
    Frame *frame = window->impl()->frame();
mjs's avatar
mjs committed
74
    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
    ScriptInterpreter* interpreter = proxy->interpreter();
ggaren@apple.com's avatar
ggaren@apple.com committed
83
    ExecState* exec = proxy->globalObject()->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

99
        // Set the event we're handling in the KJS::Window object
darin's avatar
darin committed
100 101 102
        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
// -------------------------------------------------------------------------

154
JSUnprotectedEventListener::JSUnprotectedEventListener(JSObject* listener, KJS::Window* win, bool html)
weinig's avatar
weinig committed
155 156 157
    : JSAbstractEventListener(html)
    , m_listener(listener)
    , m_win(win)
mjs's avatar
mjs committed
158
{
weinig's avatar
weinig committed
159
    if (m_listener) {
160
        KJS::Window::UnprotectedListenersMap& listeners = html
weinig's avatar
weinig committed
161 162
            ? 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) {
169
        KJS::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
}

180
KJS::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
}

190
void JSUnprotectedEventListener::mark()
mjs's avatar
mjs committed
191
{
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
// -------------------------------------------------------------------------

216
JSEventListener::JSEventListener(JSObject* listener, KJS::Window* win, bool html)
weinig's avatar
weinig committed
217 218 219
    : JSAbstractEventListener(html)
    , m_listener(listener)
    , m_win(win)
mjs's avatar
mjs committed
220
{
weinig's avatar
weinig committed
221
    if (m_listener) {
222
        KJS::Window::ListenersMap& listeners = html
weinig's avatar
weinig committed
223 224
            ? 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) {
234
        KJS::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
}

248
KJS::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
// -------------------------------------------------------------------------

260
JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& code, KJS::Window* win, Node* node, int lineNumber)
weinig's avatar
weinig committed
261 262 263 264 265 266
    : 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
    Frame* frame = windowObj()->impl()->frame();
weinig's avatar
weinig committed
294
    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
        ScriptInterpreter* interpreter = proxy->interpreter();
ggaren@apple.com's avatar
ggaren@apple.com committed
300
        ExecState* exec = proxy->globalObject()->globalExec();
darin's avatar
darin committed
301 302 303 304 305

        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) {
336
        KJS::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@apple.com's avatar
weinig@apple.com committed
353
const ClassInfo JSClipboard::info = { "Clipboard", 0, &JSClipboardTable };
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@apple.com's avatar
weinig@apple.com 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@apple.com's avatar
weinig@apple.com committed
362 363 364 365
  clearData     &WebCore::JSClipboardPrototypeFunctionClearData::create    DontDelete|Function 0
  getData       &WebCore::JSClipboardPrototypeFunctionGetData::create      DontDelete|Function 1
  setData       &WebCore::JSClipboardPrototypeFunctionSetData::create      DontDelete|Function 2
  setDragImage  &WebCore::JSClipboardPrototypeFunctionSetDragImage::create DontDelete|Function 3
trey's avatar
trey committed
366 367 368
@end
*/

weinig's avatar
weinig committed
369
KJS_DEFINE_PROTOTYPE(JSClipboardPrototype)
weinig@apple.com's avatar
weinig@apple.com committed
370
KJS_IMPLEMENT_PROTOTYPE("Clipboard", JSClipboardPrototype)
trey's avatar
trey committed
371

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

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

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

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

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

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

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

weinig's avatar
weinig committed
443
    Clipboard* clipboard = static_cast<JSClipboard*>(thisObj)->impl();
444

weinig@apple.com's avatar
weinig@apple.com committed
445 446 447 448 449 450 451 452 453
    if (args.size() == 0) {
        clipboard->clearAllData();
        return jsUndefined();
    } else if (args.size() == 1) {
        clipboard->clearData(args[0]->toString(exec));
        return jsUndefined();
    } else
        return throwError(exec, SyntaxError, "clearData: Invalid number of arguments");
}
trey's avatar
trey committed
454

weinig@apple.com's avatar
weinig@apple.com committed
455 456 457 458
JSValue* JSClipboardPrototypeFunctionGetData::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
    if (!thisObj->inherits(&JSClipboard::info))
        return throwError(exec, TypeError);
trey's avatar
trey committed
459

weinig@apple.com's avatar
weinig@apple.com committed
460
    Clipboard* clipboard = static_cast<JSClipboard*>(thisObj)->impl();
weinig's avatar
weinig committed
461

weinig@apple.com's avatar
weinig@apple.com committed
462 463 464 465 466 467 468 469 470
    if (args.size() == 1) {
        bool success;
        String result = clipboard->getData(args[0]->toString(exec), success);
        if (success)
            return jsString(result);
        return jsUndefined();
    } else
        return throwError(exec, SyntaxError, "getData: Invalid number of arguments");
}
471

weinig@apple.com's avatar
weinig@apple.com committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
JSValue* JSClipboardPrototypeFunctionSetData::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
    if (!thisObj->inherits(&JSClipboard::info))
        return throwError(exec, TypeError);

    Clipboard* clipboard = static_cast<JSClipboard*>(thisObj)->impl();

    if (args.size() == 2)
        return jsBoolean(clipboard->setData(args[0]->toString(exec), args[1]->toString(exec)));
    return throwError(exec, SyntaxError, "setData: Invalid number of arguments");
}

JSValue* JSClipboardPrototypeFunctionSetDragImage::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
    if (!thisObj->inherits(&JSClipboard::info))
        return throwError(exec, TypeError);

    Clipboard* clipboard = static_cast<JSClipboard*>(thisObj)->impl();

    if (!clipboard->isForDragging())
        return jsUndefined();

    if (args.size() != 3)
        return throwError(exec, SyntaxError, "setDragImage: Invalid number of arguments");

    int x = args[1]->toInt32(exec);
    int y = args[2]->toInt32(exec);

    // See if they passed us a node
    Node* node = toNode(args[0]);
    if (!node)
        return throwError(exec, TypeError);

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

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

darin's avatar
darin committed
514
    return jsUndefined();
trey's avatar
trey committed
515 516
}

weinig's avatar
weinig committed
517
JSValue* toJS(ExecState* exec, Clipboard* obj)
weinig's avatar
weinig committed
518
{
weinig's avatar
weinig committed
519
    return cacheDOMObject<Clipboard, JSClipboard>(exec, obj);
weinig's avatar
weinig committed
520 521
}

weinig's avatar
weinig committed
522
Clipboard* toClipboard(JSValue* val)
weinig's avatar
weinig committed
523 524 525 526
{
    return val->isObject(&JSClipboard::info) ? static_cast<JSClipboard*>(val)->impl() : 0;
}

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