1 // -*- c-basic-offset: 2 -*-
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
5 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "kjs_proxy.h"
24 #include "kjs_window.h"
25 #include "kjs_events.h"
26 #include <khtml_part.h>
27 #include <kprotocolmanager.h>
29 #include <kjs/collector.h>
34 KJSProxy *kjs_html_init(KHTMLPart *khtmlpart);
37 class KJSProxyImpl : public KJSProxy {
39 KJSProxyImpl(KHTMLPart *part);
40 virtual ~KJSProxyImpl();
41 virtual QVariant evaluate(QString filename, int baseLine, const QString&str, const DOM::Node &n);
43 virtual DOM::EventListener *createHTMLEventHandler(QString sourceUrl, QString code);
44 virtual void finishedWithEvent(const DOM::Event &event);
45 virtual KJS::ScriptInterpreter *interpreter();
47 virtual void setDebugEnabled(bool enabled);
48 virtual bool paused() const;
49 virtual void setSourceFile(QString url, QString code);
50 virtual void appendSourceFile(QString url, QString code);
55 KJS::ScriptInterpreter* m_script;
63 int KJSProxyImpl::s_count = 0;
66 KJSProxyImpl::KJSProxyImpl(KHTMLPart *part)
70 m_debugEnabled = false;
76 KJSProxyImpl::~KJSProxyImpl()
78 //kdDebug() << "KJSProxyImpl::~KJSProxyImpl deleting interpreter " << m_script << endl;
82 // If it was the last interpreter, we should have nothing left
85 Interpreter::finalCheck();
90 QVariant KJSProxyImpl::evaluate(QString filename, int baseLine,
91 const QString&str, const DOM::Node &n) {
92 // evaluate code. Returns the JS return value or an invalid QVariant
93 // if there was none, an error occured or the type couldn't be converted.
96 // inlineCode is true for <a href="javascript:doSomething()">
97 // and false for <script>doSomething()</script>. Check if it has the
98 // expected value in all cases.
99 // See smart window.open policy for where this is used.
100 bool inlineCode = filename.isNull();
101 //kdDebug(6070) << "KJSProxyImpl::evaluate inlineCode=" << inlineCode << endl;
104 // ### KJSDebugWin::instance()->attach(m_script);
106 filename = "(unknown file)";
107 if (KJSDebugWin::instance())
108 KJSDebugWin::instance()->setNextSourceInfo(filename,baseLine);
109 // KJSDebugWin::instance()->setMode(KJS::Debugger::Step);
114 m_script->setInlineCode(inlineCode);
115 KJS::Value thisNode = n.isNull() ? Window::retrieve( m_part ) : getDOMNode(m_script->globalExec(),n);
118 Completion comp = m_script->evaluate(filename, baseLine, code, thisNode);
119 bool success = ( comp.complType() == Normal ) || ( comp.complType() == ReturnValue );
121 // KJSDebugWin::instance()->setCode(QString::null);
124 // let's try to convert the return value
125 if (success && !comp.value().isNull())
126 return ValueToVariant( m_script->globalExec(), comp.value());
129 if ( comp.complType() == Throw )
131 KJS::Interpreter::lock();
132 UString errorMessage = comp.value().toString(m_script->globalExec());
133 int lineNumber = comp.value().toObject(m_script->globalExec()).get(m_script->globalExec(), "line").toInt32(m_script->globalExec());
134 UString sourceURL = comp.value().toObject(m_script->globalExec()).get(m_script->globalExec(), "sourceURL").toString(m_script->globalExec());
135 KJS::Interpreter::unlock();
138 KWQ(m_part)->addMessageToConsole(errorMessage.qstring(), lineNumber, sourceURL.qstring());
140 kdWarning(6070) << "Script threw exception: " << errorMessage.qstring() << endl;
147 void KJSProxyImpl::clear() {
148 // clear resources allocated by the interpreter, and make it ready to be used by another page
149 // We have to keep it, so that the Window object for the part remains the same.
150 // (we used to delete and re-create it, previously)
153 KJSDebugWin *debugWin = KJSDebugWin::instance();
154 if (debugWin && debugWin->currentScript() == m_script) {
155 debugWin->setMode(KJSDebugWin::Stop);
156 // debugWin->leaveSession();
159 Window *win = Window::retrieveWindow(m_part);
161 win->clear( m_script->globalExec() );
165 DOM::EventListener *KJSProxyImpl::createHTMLEventHandler(QString sourceUrl, QString code)
168 if (KJSDebugWin::instance())
169 KJSDebugWin::instance()->setNextSourceInfo(sourceUrl,m_handlerLineno);
175 return KJS::Window::retrieveWindow(m_part)->getJSLazyEventListener(code,true,m_handlerLineno);
178 void KJSProxyImpl::finishedWithEvent(const DOM::Event &event)
180 // This is called when the DOM implementation has finished with a particular event. This
181 // is the case in sitations where an event has been created just for temporary usage,
182 // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten
183 // by the DOM implementation and so does not need to be cached still by the interpreter
184 m_script->forgetDOMObject(event.handle());
187 KJS::ScriptInterpreter *KJSProxyImpl::interpreter()
195 void KJSProxyImpl::setDebugEnabled(bool enabled)
198 m_debugEnabled = enabled;
200 m_script->setDebuggingEnabled(enabled);
201 // NOTE: this is consistent across all KJSProxyImpl instances, as we only
202 // ever have 1 debug window
203 if (!enabled && KJSDebugWin::instance()) {
204 KJSDebugWin::destroyInstance();
206 else if (enabled && !KJSDebugWin::instance()) {
207 KJSDebugWin::createInstance();
209 KJSDebugWin::instance()->attach(m_script);
216 bool KJSProxyImpl::paused() const
219 if (KJSDebugWin::instance())
220 return KJSDebugWin::instance()->inSession();
225 void KJSProxyImpl::setSourceFile(QString url, QString code)
228 if (KJSDebugWin::instance())
229 KJSDebugWin::instance()->setSourceFile(url,code);
237 void KJSProxyImpl::appendSourceFile(QString url, QString code)
240 if (KJSDebugWin::instance())
241 KJSDebugWin::instance()->appendSourceFile(url,code);
248 // Implementation of the debug() function
249 class TestFunctionImp : public ObjectImp {
251 TestFunctionImp() : ObjectImp() {}
252 virtual bool implementsCall() const { return true; }
253 virtual Value call(ExecState *exec, Object &thisObj, const List &args);
256 Value TestFunctionImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
258 fprintf(stderr,"--> %s\n",args[0].toString(exec).ascii());
262 void KJSProxyImpl::initScript()
267 // Build the global object - which is a Window instance
268 KJS::Interpreter::lock();
269 Object globalObject( new Window(m_part) );
270 KJS::Interpreter::unlock();
272 // Create a KJS interpreter for this part
273 m_script = new KJS::ScriptInterpreter(globalObject, m_part);
276 m_script->setDebuggingEnabled(m_debugEnabled);
278 //m_script->enableDebug();
279 KJS::Interpreter::lock();
280 globalObject.put(m_script->globalExec(),
281 "debug", Value(new TestFunctionImp()), Internal);
282 KJS::Interpreter::unlock();
285 QString userAgent = KWQ(m_part)->userAgent();
287 QString userAgent = KProtocolManager::userAgentForHost(m_part->url().host());
289 if (userAgent.find(QString::fromLatin1("Microsoft")) >= 0 ||
290 userAgent.find(QString::fromLatin1("MSIE")) >= 0)
291 m_script->setCompatMode(Interpreter::IECompat);
293 // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape
294 if (userAgent.find(QString::fromLatin1("Mozilla")) >= 0 &&
295 userAgent.find(QString::fromLatin1("compatible")) == -1)
296 m_script->setCompatMode(Interpreter::NetscapeCompat);
299 // Helper method, so that all classes which need jScript() don't need to be added
300 // as friend to KHTMLPart
301 KJSProxy * KJSProxy::proxy( KHTMLPart *part )
303 return part->jScript();
306 // initialize HTML module
307 KJSProxy *kjs_html_init(KHTMLPart *khtmlpart)
309 return new KJSProxyImpl(khtmlpart);