kjs_events.cpp 16.5 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::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
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's avatar
weinig committed
369 370
JSClipboard::JSClipboard(ExecState* exec, Clipboard* clipboard)
    : m_impl(clipboard)
trey's avatar
trey committed
371
{
weinig's avatar
weinig committed
372
    setPrototype(JSClipboardPrototype::self(exec));
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::callAsFunction(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 453 454 455
JSValue* JSClipboardPrototypeFunctionGetData::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
    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 470 471 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
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
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's avatar
weinig committed
516
    return cacheDOMObject<Clipboard, JSClipboard>(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