kjs_events.cpp 16.4 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"
ggaren@apple.com's avatar
ggaren@apple.com committed
41 42
#include <kjs/array_object.h>
#include <kjs/function_object.h>
kocienda's avatar
kocienda committed
43

darin's avatar
darin committed
44
#include "kjs_events.lut.h"
45

weinig's avatar
weinig committed
46 47 48
namespace WebCore {

using namespace KJS;
darin's avatar
darin committed
49
using namespace EventNames;
50
using namespace HTMLNames;
darin's avatar
darin committed
51

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

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

weinig's avatar
weinig committed
64
    Event* event = ele;
65

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

70
    KJS::Window* window = windowObj();
andrew's avatar
andrew committed
71 72 73 74
    // 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
75
    Frame *frame = window->impl()->frame();
mjs's avatar
mjs committed
76
    if (!frame)
darin's avatar
darin committed
77
        return;
darin's avatar
darin committed
78
    KJSProxy* proxy = frame->scriptProxy();
darin's avatar
darin committed
79 80
    if (!proxy)
        return;
darin's avatar
darin committed
81

darin's avatar
darin committed
82
    JSLock lock;
weinig's avatar
weinig committed
83

ggaren@apple.com's avatar
ggaren@apple.com committed
84 85
    JSGlobalObject* globalObject = proxy->globalObject();
    ExecState* exec = globalObject->globalExec();
weinig's avatar
weinig committed
86

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

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

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

darin's avatar
darin committed
101
        window->setCurrentEvent(event);
weinig's avatar
weinig committed
102

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

        window->setCurrentEvent(0);

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

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

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

mjs's avatar
mjs committed
150 151
// -------------------------------------------------------------------------

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

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

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

178
KJS::Window* JSUnprotectedEventListener::windowObj() const
mjs's avatar
mjs committed
179
{
weinig's avatar
weinig committed
180
    return m_win;
mjs's avatar
mjs committed
181 182
}

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

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

weinig's avatar
weinig committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
#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
212 213
// -------------------------------------------------------------------------

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

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

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

246
KJS::Window* JSEventListener::windowObj() const
mjs's avatar
mjs committed
247
{
weinig's avatar
weinig committed
248
    return m_win;
mjs's avatar
mjs committed
249 250
}

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

mjs's avatar
mjs committed
256 257
// -------------------------------------------------------------------------

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

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

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

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

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

    if (proxy) {
ggaren@apple.com's avatar
ggaren@apple.com committed
297
        ExecState* exec = proxy->globalObject()->globalExec();
darin's avatar
darin committed
298 299

        JSLock lock;
ggaren@apple.com's avatar
ggaren@apple.com committed
300
        JSObject* constr = proxy->globalObject()->functionConstructor();
darin's avatar
darin committed
301 302
        List args;

weinig@apple.com's avatar
weinig@apple.com committed
303
        UString sourceURL(frame->loader()->url().string());
darin's avatar
darin committed
304
        args.append(eventParameterName());
weinig's avatar
weinig committed
305 306
        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
307

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

darin's avatar
darin committed
310 311 312 313
        if (exec->hadException()) {
            exec->clearException();

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

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

    // no more need to keep the unparsed code around
darin's avatar
darin committed
329
    m_functionName = String();
weinig's avatar
weinig committed
330
    m_code = String();
darin's avatar
darin committed
331

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

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

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

weinig@apple.com's avatar
weinig@apple.com committed
350
const ClassInfo JSClipboard::info = { "Clipboard", 0, &JSClipboardTable };
trey's avatar
trey committed
351

weinig's avatar
weinig committed
352 353
/* Source for JSClipboardTable. Use "make hashtables" to regenerate.
@begin JSClipboardTable 3
weinig@apple.com's avatar
weinig@apple.com committed
354 355 356
  dropEffect    WebCore::JSClipboard::DropEffect                           DontDelete
  effectAllowed WebCore::JSClipboard::EffectAllowed                        DontDelete
  types         WebCore::JSClipboard::Types                                DontDelete|ReadOnly
trey's avatar
trey committed
357
@end
weinig's avatar
weinig committed
358
@begin JSClipboardPrototypeTable 4
weinig@apple.com's avatar
weinig@apple.com committed
359 360 361 362
  clearData     WebCore::jsClipboardPrototypeFunctionClearData    DontDelete|Function 0
  getData       WebCore::jsClipboardPrototypeFunctionGetData      DontDelete|Function 1
  setData       WebCore::jsClipboardPrototypeFunctionSetData      DontDelete|Function 2
  setDragImage  WebCore::jsClipboardPrototypeFunctionSetDragImage DontDelete|Function 3
trey's avatar
trey committed
363 364 365
@end
*/

weinig's avatar
weinig committed
366
KJS_DEFINE_PROTOTYPE(JSClipboardPrototype)
weinig@apple.com's avatar
weinig@apple.com committed
367
KJS_IMPLEMENT_PROTOTYPE("Clipboard", JSClipboardPrototype)
trey's avatar
trey committed
368

weinig@apple.com's avatar
weinig@apple.com committed
369 370 371
JSClipboard::JSClipboard(JSObject* prototype, Clipboard* clipboard)
    : DOMObject(prototype)
    , m_impl(clipboard)
trey's avatar
trey committed
372
{
trey's avatar
trey committed
373 374
}

weinig's avatar
weinig committed
375
JSClipboard::~JSClipboard()
trey's avatar
trey committed
376
{
weinig's avatar
weinig committed
377
    ScriptInterpreter::forgetDOMObject(m_impl.get());
trey's avatar
trey committed
378 379
}

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

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

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

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

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

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

weinig@apple.com's avatar
weinig@apple.com committed
442 443 444 445 446 447 448 449 450
    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
451

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

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

weinig@apple.com's avatar
weinig@apple.com committed
459 460 461 462 463 464 465 466 467
    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");
}
468

weinig@apple.com's avatar
weinig@apple.com committed
469
JSValue* jsClipboardPrototypeFunctionSetData(ExecState* exec, JSObject* thisObj, const List& args)
weinig@apple.com's avatar
weinig@apple.com committed
470 471 472 473 474 475 476 477 478 479 480
{
    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");
}

weinig@apple.com's avatar
weinig@apple.com committed
481
JSValue* jsClipboardPrototypeFunctionSetDragImage(ExecState* exec, JSObject* thisObj, const List& args)
weinig@apple.com's avatar
weinig@apple.com committed
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
{
    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
510

darin's avatar
darin committed
511
    return jsUndefined();
trey's avatar
trey committed
512 513
}

weinig's avatar
weinig committed
514
JSValue* toJS(ExecState* exec, Clipboard* obj)
weinig's avatar
weinig committed
515
{
weinig@apple.com's avatar
weinig@apple.com committed
516
    return cacheDOMObject<Clipboard, JSClipboard, JSClipboardPrototype>(exec, obj);
weinig's avatar
weinig committed
517 518
}

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

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