diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /khtml/ecma | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'khtml/ecma')
39 files changed, 18628 insertions, 0 deletions
diff --git a/khtml/ecma/AUTHORS b/khtml/ecma/AUTHORS new file mode 100644 index 000000000..2a129330d --- /dev/null +++ b/khtml/ecma/AUTHORS @@ -0,0 +1,4 @@ +Harri Porten <porten@kde.org> +Peter Kelly <pmk@post.com> +Dirk Mueller <mueller@kde.org> +Daniel Molkentin <molkentin@kde.org> diff --git a/khtml/ecma/Makefile.am b/khtml/ecma/Makefile.am new file mode 100644 index 000000000..c88b51d33 --- /dev/null +++ b/khtml/ecma/Makefile.am @@ -0,0 +1,90 @@ +# This file is part of the KDE libraries +# Copyright (C) 1999 Harri Porten (porten@kde.org) + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public License +# along with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/kio -I$(top_srcdir)/kio/bookmarks -I$(top_srcdir)/khtml -I$(top_srcdir)/khtml/java -I$(top_srcdir)/kwallet/client -I$(top_srcdir)/kutils -I$(top_builddir)/kjs $(all_includes) + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES = libkjs_html.la + +noinst_HEADERS = kjs_html.h kjs_dom.h kjs_window.h kjs_navigator.h \ + kjs_binding.h kjs_proxy.h kjs_css.h kjs_range.h \ + kjs_traversal.h kjs_events.h kjs_views.h kjs_debugwin.h + +libkjs_html_la_SOURCES = kjs_binding.cpp kjs_dom.cpp kjs_html.cpp kjs_window.cpp \ + kjs_navigator.cpp kjs_proxy.cpp \ + kjs_css.cpp kjs_range.cpp kjs_traversal.cpp kjs_events.cpp \ + kjs_views.cpp kjs_debugwin.cpp kjs_mozilla.cpp xmlhttprequest.cpp \ + xmlserializer.cpp domparser.cpp +#libkjs_html_la_LDFLAGS = -module -avoid-version $(all_libraries) +libkjs_html_la_LIBADD = $(top_builddir)/kjs/libkjs.la # ../libkhtml.la +libkjs_html_la_METASOURCES = AUTO + +LUT_FILES = kjs_dom.lut.h kjs_html.lut.h kjs_css.lut.h kjs_events.lut.h kjs_navigator.lut.h \ + kjs_mozilla.lut.h kjs_range.lut.h kjs_traversal.lut.h kjs_views.lut.h kjs_window.lut.h + +CREATE_HASH_TABLE = $(top_srcdir)/kjs/create_hash_table + +kjs_dom.lut.h : $(srcdir)/kjs_dom.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_dom.cpp > $@ +kjs_dom.lo: kjs_dom.lut.h +kjs_html.lut.h : $(srcdir)/kjs_html.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_html.cpp > $@ +kjs_html.lo: kjs_html.lut.h +kjs_css.lut.h : $(srcdir)/kjs_css.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_css.cpp > $@ +kjs_css.lo: kjs_css.lut.h +kjs_events.lut.h : $(srcdir)/kjs_events.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_events.cpp > $@ +kjs_events.lo: kjs_events.lut.h +kjs_navigator.lut.h : $(srcdir)/kjs_navigator.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_navigator.cpp > $@ +kjs_navigator.lo: kjs_navigator.lut.h +kjs_mozilla.lut.h : $(srcdir)/kjs_mozilla.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_mozilla.cpp > $@ +kjs_mozilla.lo: kjs_mozilla.lut.h +kjs_range.lut.h : $(srcdir)/kjs_range.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_range.cpp > $@ +kjs_range.lo: kjs_range.lut.h +kjs_traversal.lut.h : $(srcdir)/kjs_traversal.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_traversal.cpp > $@ +kjs_traversal.lo: kjs_traversal.lut.h +kjs_views.lut.h : $(srcdir)/kjs_views.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_views.cpp > $@ +kjs_views.lo: kjs_views.lut.h +kjs_window.lut.h : $(srcdir)/kjs_window.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/kjs_window.cpp > $@ +kjs_window.lo: kjs_window.lut.h +xmlhttprequest.lut.h : $(srcdir)/xmlhttprequest.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/xmlhttprequest.cpp > $@ +xmlhttprequest.lo: xmlhttprequest.lut.h +xmlserializer.lut.h : $(srcdir)/xmlserializer.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/xmlserializer.cpp > $@ +xmlserializer.lo: xmlserializer.lut.h +domparser.lut.h : $(srcdir)/domparser.cpp $(CREATE_HASH_TABLE) + $(PERL) $(CREATE_HASH_TABLE) $(srcdir)/domparser.cpp > $@ +domparser.lo: domparser.lut.h + + +CLEANFILES = $(LUT_FILES) + +# interactive test program +#check_PROGRAMS = testecma +#testecma_SOURCES = testecma.cpp +#testecma_LDADD = ../libkhtml.la $(top_builddir)/kjs/libkjs.la + diff --git a/khtml/ecma/README b/khtml/ecma/README new file mode 100644 index 000000000..4c341699a --- /dev/null +++ b/khtml/ecma/README @@ -0,0 +1,21 @@ +This module contains the ECMAScript a.k.a. JavaScript language bindings for +the KHTML Part. + +The module is loaded into KHTML's address space on demand. + +To test the non-HTML DOM functions you may compile a little interactive +interpreter called 'testecma' with 'make check' (see testecma.cpp for +further details). + +Harri Porten <porten@kde.org> + +======================================================================== +Appendix A: Web sites with useful tests + +http://oucsace.cs.ohiou.edu/~ywang/JavaScript +http://www.xs4all.nl/~ppk/js/index.html?version5.html + +Appendix B: References for HTML JavaScript bindings + +http://msdn.microsoft.com/workshop/author/dhtml/reference/objects.asp +http://docs.sun.com/source/816-6408-10/ diff --git a/khtml/ecma/THANKS b/khtml/ecma/THANKS new file mode 100644 index 000000000..b21dce741 --- /dev/null +++ b/khtml/ecma/THANKS @@ -0,0 +1,9 @@ +Vadim Plessky <lucy-ples@mtu-net.ru> for dissecting an endless number +of bug reports and therefore taking quite some load of our shoulders. + +Ferdinand Gassauer <f.gassauer@aon.at> for numerous useful bug reports +and keeping track of them later. + +David Faure <faure@kde.org> for taking some time off from Konqueror +and making a lotto site working fixing bugs along the way. + diff --git a/khtml/ecma/TODO b/khtml/ecma/TODO new file mode 100644 index 000000000..16a7152c5 --- /dev/null +++ b/khtml/ecma/TODO @@ -0,0 +1,12 @@ +Has to be done +============== +- frame[] correct search and sorting order (DONE ?) +- optional error message output +- change KParts::WindowArgs && friends + that we can detect if a locationbar is on/or not + +Could be done +============= +- Make the graphical debugger useable +- Improve internal structures to give a really useful + output on errors (i.e. improve backtrance capabilities) diff --git a/khtml/ecma/domparser.cpp b/khtml/ecma/domparser.cpp new file mode 100644 index 000000000..63a9dce36 --- /dev/null +++ b/khtml/ecma/domparser.cpp @@ -0,0 +1,112 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2005 Anders Carlsson (andersca@mac.com) + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "domparser.h" +#include "domparser.lut.h" + +#include "kjs_dom.h" +#include "kjs_window.h" +#include "xml/dom_nodeimpl.h" +#include "xml/dom_docimpl.h" + +#include "html/html_documentimpl.h" + +using DOM::DocumentImpl; + +////////////////////// DOMParser Object //////////////////////// + +/* Source for DOMParserProtoTable. +@begin DOMParserProtoTable 1 + parseFromString DOMParser::ParseFromString DontDelete|Function 2 +@end +*/ + + +namespace KJS { + +KJS_DEFINE_PROTOTYPE(DOMParserProto) +IMPLEMENT_PROTOFUNC_DOM(DOMParserProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMParser", DOMParserProto, DOMParserProtoFunc) + + +DOMParserConstructorImp::DOMParserConstructorImp(ExecState *, DOM::DocumentImpl *d) + : doc(d) +{ +} + +bool DOMParserConstructorImp::implementsConstruct() const +{ + return true; +} + +Object DOMParserConstructorImp::construct(ExecState *exec, const List &) +{ + return Object(new DOMParser(exec, doc.get())); +} + +const ClassInfo DOMParser::info = { "DOMParser", 0, 0 /* &DOMParserTable*/, 0 }; + + +DOMParser::DOMParser(ExecState *exec, DOM::DocumentImpl *d) + : DOMObject(DOMParserProto::self(exec)), doc(d) +{ +// setPrototype(DOMParserProto::self(exec)); +} + + +Value DOMParserProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + if (!thisObj.inherits(&DOMParser::info)) { + Object err = Error::create(exec,TypeError); + exec->setException(err); + return err; + } + + DOMParser *parser = static_cast<DOMParser *>(thisObj.imp()); + + switch (id) { + case DOMParser::ParseFromString: + { + if (args.size() != 2) { + return Undefined(); + } + + QString str = args[0].toString(exec).qstring(); + QString contentType = args[1].toString(exec).qstring().stripWhiteSpace(); + + if (contentType == "text/xml" || contentType == "application/xml" || contentType == "application/xhtml+xml") { + DocumentImpl *docImpl = parser->doc->implementation()->createDocument(); + + docImpl->open(); + docImpl->write(str); + docImpl->finishParsing(); + docImpl->close(); + + return getDOMNode(exec, docImpl); + } + } + } + + return Undefined(); +} + +} // end namespace + + diff --git a/khtml/ecma/domparser.h b/khtml/ecma/domparser.h new file mode 100644 index 000000000..233872602 --- /dev/null +++ b/khtml/ecma/domparser.h @@ -0,0 +1,58 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2005 Anders Carlsson (andersca@mac.com) + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DOMPARSER_H +#define DOMPARSER_H + +#include <qguardedptr.h> +#include <kjs/object.h> +#include <kjs/interpreter.h> +#include <misc/shared.h> + +#include "kjs_dom.h" + +namespace KJS { + + class DOMParserConstructorImp : public ObjectImp { + public: + DOMParserConstructorImp(ExecState *, DOM::DocumentImpl *d); + virtual bool implementsConstruct() const; + virtual Object construct(ExecState *exec, const List &args); +private: + khtml::SharedPtr<DOM::DocumentImpl> doc; + }; + + class DOMParser : public DOMObject { + public: + DOMParser(ExecState *, DOM::DocumentImpl *d); + virtual bool toBoolean(ExecState *) const { return true; } + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { ParseFromString }; + + private: + QGuardedPtr<DOM::DocumentImpl> doc; + + friend class DOMParserProtoFunc; + }; + +} // namespace + +#endif diff --git a/khtml/ecma/jsk.html b/khtml/ecma/jsk.html new file mode 100644 index 000000000..917c083e8 --- /dev/null +++ b/khtml/ecma/jsk.html @@ -0,0 +1,113 @@ +<html> +<!-- +Javascript Konsole (c) 2001 Till Krech <till@snafu.de> +Dieser Code unterliegt den Bedingungen der Gnu Public License Version 2. +--> +<head> +<title>Javascript Konsole</title> +<style type="text/css"> +code { + color:#444488; +} +em { + font-weight: bold; +} +</style> +<script language="JavaScript"> + +function do_eval() { + var fo = document.forms.fo; + fo.restyp.value = ""; + fo.field.value = ""; + var fo = document.fo; + var expr = fo.zeile.value; + var result = eval(expr); + fo.restyp.value = typeof(result); + var tuedel = ""; + if (typeof(result) == "string") { + tuedel = '"'; + } + fo.field.value = tuedel + result + tuedel; +} + +function do_properties() { + var fo = document.forms.fo; + fo.restyp.value = ""; + fo.field.value = ""; + var fo = document.fo; + var expr = fo.zeile.value; + var result = eval(expr); + var i; + fo.restyp.value = typeof(result); + var fieldvalue = ""; + if (typeof(result) != "undefined") { + for (i in result) { + var tuedel = ""; + var propval = result[i]; + if (typeof(propval) == "string") { + tuedel = '"'; + } + fieldvalue += + i + + " [" + typeof(propval) + "] = " + + tuedel + propval + tuedel + "\n"; + } + fo.field.value = fieldvalue; + } +} + + +</script> +</head> +<body bgcolor="#dddddd"> +<h1>JavaScript Konsole</h1> +<form name="fo"> +<table bgcolor="#cccccc" cellspacing="1" cellpadding="8"> + <tr bgcolor="#ffeeee"><th height="40" align="right">Expression</th><td><input name="zeile" type="text" size="60"></td></tr> + <tr bgcolor="#eeeeee"><th align="right">Result Type</th><td><input name="restyp" readonly type="text" size="60"></td></tr> + <tr bgcolor="#eeeeee"><th align="right">Result(s)</th><td><textarea readonly name="field" rows="10" cols="60"></textarea></td></tr> +<tr bgcolor="#ffeeee"><td> </td><td> + <input type="button" value="list properties" onclick="do_properties()"> + <input type="button" value="evaluate" onclick="do_eval()"> + <input type="reset" value="clear fields" +</td></tr> +</table> +</form> +<h2>Explanation</h2> +<h3>Operation</h3> +<blockquote> +When <em>evaluate</em> is pressed, the given expression is evaluated and the result is displayed in the result(s) field. +In case of <em>list properties</em> being pressed, the result of the expression is taken as an object +and the objects properties are displayed with their type and value in the the result(s) field. +</blockquote> +<h3>Expression</h3> +<blockquote> +Expression must be a valid javascript expression, e.g.<br><code>window</code> +<br>or<br><code>document.body.innerHTML</code><br>or<br> +<code>"Today: " + (new Date()).toString()</code><br> +or<br> +<code>"Cablecar".match(/ab.*c/)</code> +<br>It is also possible to assign a value, +e.g.<br><code>document.getElementsByTagName('H1').item(0).innerText="Hello World"</code><br> +You may execute these examples by pasting them into the expression field. +</blockquote> +<h3>Result Type</h3> +<blockquote> +The type of the result of the given expression. +</blockquote> +<h3>Result(s)</h3> +<blockquote> +The result of the expression is implicitly converted to a primitive type by the javascript interpreter, +if <em>evaluate</em> was pressed. When <em>list properties</em> was pressed, a <code>for (var i in obj)</code> loop +is executed to list the properties. These object properties are in turn evaluated and their types and values +are displayed. +</blockquote> +<p> +<a href="mailto:till@snafu.de?subject=JavaScript%20Konsole">Till Krech</a> +</p> +<p> +<br> +</p> + +</body> +</html> diff --git a/khtml/ecma/kjs_binding.cpp b/khtml/ecma/kjs_binding.cpp new file mode 100644 index 000000000..295d8c5e9 --- /dev/null +++ b/khtml/ecma/kjs_binding.cpp @@ -0,0 +1,467 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999-2003 Harri Porten (porten@kde.org) + * Copyright (C) 2001-2003 David Faure (faure@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_binding.h" +#include "kjs_dom.h" + +#include "dom/dom_exception.h" +#include "dom/dom2_range.h" +#include "xml/dom2_eventsimpl.h" +#include "khtmlpart_p.h" + +#include <kdebug.h> +#include <kparts/browserextension.h> + +#include <assert.h> + +using namespace KJS; + +/* TODO: + * The catch all (...) clauses below shouldn't be necessary. + * But they helped to view for example www.faz.net in an stable manner. + * Those unknown exceptions should be treated as severe bugs and be fixed. + * + * these may be CSS exceptions - need to check - pmk + */ + +Value DOMObject::get(ExecState *exec, const Identifier &p) const +{ + Value result; + try { + result = tryGet(exec,p); + } + catch (DOM::DOMException e) { + // ### translate code into readable string ? + // ### oh, and s/QString/i18n or I18N_NOOP (the code in kjs uses I18N_NOOP... but where is it translated ?) + // and where does it appear to the user ? + Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit()); + exec->setException( err ); + result = Undefined(); + } + catch (...) { + kdError(6070) << "Unknown exception in DOMObject::get()" << endl; + result = String("Unknown exception"); + } + + return result; +} + +void DOMObject::put(ExecState *exec, const Identifier &propertyName, + const Value &value, int attr) +{ + try { + tryPut(exec, propertyName, value, attr); + } + catch (DOM::DOMException e) { + Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit()); + exec->setException(err); + } + catch (...) { + kdError(6070) << "Unknown exception in DOMObject::put()" << endl; + } +} + +void DOMObject::tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr) +{ + static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->customizedDOMObject(this); + ObjectImp::put(exec,propertyName,value,attr); +} + +UString DOMObject::toString(ExecState *) const +{ + return "[object " + className() + "]"; +} + +Boolean DOMObject::hasInstance(ExecState *exec, const Value &value) +{ + if (value.type() != ObjectType) + return Boolean(false); + + Value prot = get(exec,prototypePropertyName); + if (prot.type() != ObjectType && prot.type() != NullType) { + Object err = Error::create(exec, TypeError, "Invalid prototype encountered " + "in instanceof operation."); + exec->setException(err); + return Boolean(false); + } + + Object v = Object(static_cast<ObjectImp*>(value.imp())); + while ((v = Object::dynamicCast(v.prototype())).imp()) { + if (v.imp() == prot.imp()) + return Boolean(true); + } + return Boolean(false); +} + + +Value DOMFunction::get(ExecState *exec, const Identifier &propertyName) const +{ + try { + return tryGet(exec, propertyName); + } + catch (DOM::DOMException e) { + Object err = Error::create(exec, GeneralError, QString("DOM exception %1").arg(e.code).local8Bit()); + exec->setException(err); + return Undefined(); + } + catch (...) { + kdError(6070) << "Unknown exception in DOMFunction::get()" << endl; + return String("Unknown exception"); + } +} + +Value DOMFunction::call(ExecState *exec, Object &thisObj, const List &args) +{ + try { + return tryCall(exec, thisObj, args); + } + // pity there's no way to distinguish between these in JS code + // ### Look into setting prototypes of these & the use of instanceof so the exception + // type can be determined. See what other browsers do. + catch (DOM::DOMException e) { + Object err = Error::create(exec, GeneralError, QString("DOM Exception %1").arg(e.code).local8Bit()); + err.put(exec, "code", Number(e.code)); + exec->setException(err); + return Undefined(); + } + catch (DOM::RangeException e) { + Object err = Error::create(exec, GeneralError, QString("DOM Range Exception %1").arg(e.code).local8Bit()); + err.put(exec, "code", Number(e.code)); + exec->setException(err); + return Undefined(); + } + catch (DOM::CSSException e) { + Object err = Error::create(exec, GeneralError, QString("CSS Exception %1").arg(e.code).local8Bit()); + err.put(exec, "code", Number(e.code)); + exec->setException(err); + return Undefined(); + } + catch (DOM::EventException e) { + Object err = Error::create(exec, GeneralError, QString("DOM Event Exception %1").arg(e.code).local8Bit()); + err.put(exec, "code", Number(e.code)); + exec->setException(err); + return Undefined(); + } + catch (...) { + kdError(6070) << "Unknown exception in DOMFunction::call()" << endl; + Object err = Error::create(exec, GeneralError, "Unknown exception"); + exec->setException(err); + return Undefined(); + } +} + +typedef QPtrList<ScriptInterpreter> InterpreterList; +static InterpreterList *interpreterList; + +ScriptInterpreter::ScriptInterpreter( const Object &global, khtml::ChildFrame* frame ) + : Interpreter( global ), m_frame( frame ), m_domObjects(1021), + m_evt( 0L ), m_inlineCode(false), m_timerCallback(false) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "ScriptInterpreter::ScriptInterpreter " << this << " for part=" << m_frame << endl; +#endif + if ( !interpreterList ) + interpreterList = new InterpreterList; + interpreterList->append( this ); +} + +ScriptInterpreter::~ScriptInterpreter() +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "ScriptInterpreter::~ScriptInterpreter " << this << " for part=" << m_frame << endl; +#endif + assert( interpreterList && interpreterList->contains( this ) ); + interpreterList->remove( this ); + if ( interpreterList->isEmpty() ) { + delete interpreterList; + interpreterList = 0; + } +} + +void ScriptInterpreter::forgetDOMObject( void* objectHandle ) +{ + if( !interpreterList ) return; + + QPtrListIterator<ScriptInterpreter> it( *interpreterList ); + while ( it.current() ) { + (*it)->deleteDOMObject( objectHandle ); + ++it; + } +} + +void ScriptInterpreter::mark() +{ + Interpreter::mark(); +#ifdef KJS_VERBOSE + kdDebug(6070) << "ScriptInterpreter::mark " << this << " marking " << m_customizedDomObjects.count() << " DOM objects" << endl; +#endif + QPtrDictIterator<void> it( m_customizedDomObjects ); + for( ; it.current(); ++it ) + static_cast<DOMObject*>(it.currentKey())->mark(); +} + +KParts::ReadOnlyPart* ScriptInterpreter::part() const { + return m_frame->m_part; +} + +bool ScriptInterpreter::isWindowOpenAllowed() const +{ + if ( m_evt ) + { + int id = m_evt->handle()->id(); + bool eventOk = ( // mouse events + id == DOM::EventImpl::CLICK_EVENT || + id == DOM::EventImpl::MOUSEUP_EVENT || id == DOM::EventImpl::MOUSEDOWN_EVENT || + id == DOM::EventImpl::KHTML_ECMA_CLICK_EVENT || id == DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT || + // keyboard events + id == DOM::EventImpl::KEYDOWN_EVENT || id == DOM::EventImpl::KEYPRESS_EVENT || + id == DOM::EventImpl::KEYUP_EVENT || + // other accepted events + id == DOM::EventImpl::SELECT_EVENT || id == DOM::EventImpl::CHANGE_EVENT || + id == DOM::EventImpl::SUBMIT_EVENT ); + kdDebug(6070) << "Window.open, smart policy: id=" << id << " eventOk=" << eventOk << endl; + if (eventOk) + return true; + } else // no event + { + if ( m_inlineCode && !m_timerCallback ) + { + // This is the <a href="javascript:window.open('...')> case -> we let it through + return true; + kdDebug(6070) << "Window.open, smart policy, no event, inline code -> ok" << endl; + } + else // This is the <script>window.open(...)</script> case or a timer callback -> block it + kdDebug(6070) << "Window.open, smart policy, no event, <script> tag -> refused" << endl; + } + return false; +} + + +UString::UString(const QString &d) +{ + unsigned int len = d.length(); + UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = UString::Rep::create(dat, len); +} + +UString::UString(const DOM::DOMString &d) +{ + if (d.isNull()) { + // we do a conversion here as null DOMStrings shouldn't cross + // the boundary to kjs. They should either be empty strings + // or explicitly converted to KJS::Null via getString(). + attach(&Rep::empty); + return; + } + + unsigned int len = d.length(); + UChar *dat = new UChar[len]; + memcpy(dat, d.unicode(), len * sizeof(UChar)); + rep = UString::Rep::create(dat, len); +} + +DOM::DOMString UString::string() const +{ + return DOM::DOMString((QChar*) data(), size()); +} + +QString UString::qstring() const +{ + return QString((QChar*) data(), size()); +} + +QConstString UString::qconststring() const +{ + return QConstString((QChar*) data(), size()); +} + +DOM::DOMString Identifier::string() const +{ + return DOM::DOMString((QChar*) data(), size()); +} + +QString Identifier::qstring() const +{ + return QString((QChar*) data(), size()); +} + +DOM::Node KJS::toNode(const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMNode::info)) + return DOM::Node(); + + const DOMNode *dobj = static_cast<const DOMNode*>(obj.imp()); + return dobj->toNode(); +} + +Value KJS::getString(DOM::DOMString s) +{ + if (s.isNull()) + return Null(); + else + return String(s); +} + +QVariant KJS::ValueToVariant(ExecState* exec, const Value &val) { + QVariant res; + switch (val.type()) { + case BooleanType: + res = QVariant(val.toBoolean(exec), 0); + break; + case NumberType: + res = QVariant(val.toNumber(exec)); + break; + case StringType: + res = QVariant(val.toString(exec).qstring()); + break; + default: + // everything else will be 'invalid' + break; + } + return res; +} + +class EmbedLiveConnect : public ObjectImp +{ + friend Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id); + EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id); +public: + ~EmbedLiveConnect(); + + virtual Value get(ExecState *, const Identifier & prop) const; + virtual void put(ExecState * exec, const Identifier &prop, const Value & value, int=None); + virtual Value call(ExecState * exec, Object &, const List &args); + virtual bool implementsCall() const; + virtual bool toBoolean(ExecState *) const; + virtual Value toPrimitive(ExecState *exec, Type) const; + virtual UString toString(ExecState *) const; + +private: + EmbedLiveConnect(const EmbedLiveConnect &); + QGuardedPtr<KParts::LiveConnectExtension> m_liveconnect; + UString name; + KParts::LiveConnectExtension::Type objtype; + unsigned long objid; +}; + +Value KJS::getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id) +{ + KParts::LiveConnectExtension::Type t=(KParts::LiveConnectExtension::Type)type; + switch(t) { + case KParts::LiveConnectExtension::TypeBool: { + bool ok; + int i = value.toInt(&ok); + if (ok) + return Boolean(i); + return Boolean(!strcasecmp(value.latin1(), "true")); + } + case KParts::LiveConnectExtension::TypeObject: + case KParts::LiveConnectExtension::TypeFunction: + return Value(new EmbedLiveConnect(lc, name, t, id)); + case KParts::LiveConnectExtension::TypeNumber: { + bool ok; + int i = value.toInt(&ok); + if (ok) + return Number(i); + else + return Number(value.toDouble(&ok)); + } + case KParts::LiveConnectExtension::TypeString: + return String(value); + case KParts::LiveConnectExtension::TypeVoid: + default: + return Undefined(); + } +} + +/* only with gcc > 3.4 KDE_NO_EXPORT */ +EmbedLiveConnect::EmbedLiveConnect(KParts::LiveConnectExtension *lc, UString n, KParts::LiveConnectExtension::Type t, int id) + : m_liveconnect (lc), name(n), objtype(t), objid(id) +{} + +/* only with gcc > 3.4 KDE_NO_EXPORT */ +EmbedLiveConnect::~EmbedLiveConnect() { + if (m_liveconnect) + m_liveconnect->unregister(objid); +} + +KDE_NO_EXPORT +Value EmbedLiveConnect::get(ExecState *, const Identifier & prop) const +{ + if (m_liveconnect) { + KParts::LiveConnectExtension::Type rettype; + QString retval; + unsigned long retobjid; + if (m_liveconnect->get(objid, prop.qstring(), rettype, retobjid, retval)) + return getLiveConnectValue(m_liveconnect, prop.qstring(), rettype, retval, retobjid); + } + return Undefined(); +} + +KDE_NO_EXPORT +void EmbedLiveConnect::put(ExecState * exec, const Identifier &prop, const Value & value, int) +{ + if (m_liveconnect) + m_liveconnect->put(objid, prop.qstring(), value.toString(exec).qstring()); +} + +KDE_NO_EXPORT +bool EmbedLiveConnect::implementsCall() const { + return objtype == KParts::LiveConnectExtension::TypeFunction; +} + +KDE_NO_EXPORT +Value EmbedLiveConnect::call(ExecState *exec, Object&, const List &args) +{ + if (m_liveconnect) { + QStringList qargs; + for (ListIterator i = args.begin(); i != args.end(); ++i) + qargs.append((*i).toString(exec).qstring()); + KParts::LiveConnectExtension::Type rtype; + QString rval; + unsigned long robjid; + if (m_liveconnect->call(objid, name.qstring(), qargs, rtype, robjid, rval)) + return getLiveConnectValue(m_liveconnect, name.qstring(), rtype, rval, robjid); + } + return Undefined(); +} + +KDE_NO_EXPORT +bool EmbedLiveConnect::toBoolean(ExecState *) const { + return true; +} + +KDE_NO_EXPORT +Value EmbedLiveConnect::toPrimitive(ExecState *exec, Type) const { + return String(toString(exec)); +} + +KDE_NO_EXPORT +UString EmbedLiveConnect::toString(ExecState *) const { + QString str; + const char *type = objtype == KParts::LiveConnectExtension::TypeFunction ? "Function" : "Object"; + str.sprintf("[object %s ref=%d]", type, (int) objid); + return UString(str); +} diff --git a/khtml/ecma/kjs_binding.h b/khtml/ecma/kjs_binding.h new file mode 100644 index 000000000..4b49e866b --- /dev/null +++ b/khtml/ecma/kjs_binding.h @@ -0,0 +1,409 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_BINDING_H_ +#define _KJS_BINDING_H_ + +#include <kjs/interpreter.h> +#include <kjs/function_object.h> /// for FunctionPrototypeImp + +#include <dom/dom_node.h> +#include <qvariant.h> +#include <qptrdict.h> +#include <kurl.h> +#include <kjs/lookup.h> + +namespace KParts { + class ReadOnlyPart; + class LiveConnectExtension; +} + +namespace khtml { + class ChildFrame; +} + +namespace KJS { + + /** + * Base class for all objects in this binding - get() and put() run + * tryGet() and tryPut() respectively, and catch exceptions if they + * occur. + */ + class DOMObject : public ObjectImp { + public: + DOMObject(const Object &proto) : ObjectImp(proto) {} + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const + { return ObjectImp::get(exec, propertyName); } + virtual bool implementsHasInstance() const { return true; } + virtual Boolean hasInstance(ExecState *exec, const Value &value); + virtual void put(ExecState *exec, const Identifier &propertyName, + const Value &value, int attr = None); + virtual void tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr = None); + + virtual UString toString(ExecState *exec) const; + }; + + /** + * Base class for all functions in this binding - get() and call() run + * tryGet() and tryCall() respectively, and catch exceptions if they + * occur. + */ + class DOMFunction : public InternalFunctionImp { + public: + DOMFunction(ExecState* exec) : InternalFunctionImp( + static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) + ) {} + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const + { return ObjectImp::get(exec, propertyName); } + + virtual bool implementsCall() const { return true; } + virtual Value call(ExecState *exec, Object &thisObj, const List &args); + + virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args) + { return ObjectImp::call(exec, thisObj, args); } + virtual bool toBoolean(ExecState *) const { return true; } + }; + + /** + * We inherit from Interpreter, to save a pointer to the HTML part + * that the interpreter runs for. + * The interpreter also stores the DOM object - >KJS::DOMObject cache. + */ + class KDE_EXPORT ScriptInterpreter : public Interpreter + { + public: + ScriptInterpreter( const Object &global, khtml::ChildFrame* frame ); + virtual ~ScriptInterpreter(); + + DOMObject* getDOMObject( void* objectHandle ) const { + return m_domObjects[objectHandle]; + } + void putDOMObject( void* objectHandle, DOMObject* obj ) { + m_domObjects.insert( objectHandle, obj ); + } + void customizedDOMObject( DOMObject* obj ) { + m_customizedDomObjects.replace( obj, this ); + } + bool deleteDOMObject( void* objectHandle ) { + DOMObject* obj = m_domObjects.take( objectHandle ); + if (obj) { + m_customizedDomObjects.remove( obj ); + return true; + } + else + return false; + } + void clear() { + m_customizedDomObjects.clear(); + m_domObjects.clear(); + } + /** + * Static method. Makes all interpreters forget about the object + */ + static void forgetDOMObject( void* objectHandle ); + + /** + * Mark objects in the DOMObject cache. + */ + virtual void mark(); + KParts::ReadOnlyPart* part() const; + + virtual int rtti() { return 1; } + + /** + * Set the event that is triggering the execution of a script, if any + */ + void setCurrentEvent( DOM::Event *evt ) { m_evt = evt; } + void setInlineCode( bool inlineCode ) { m_inlineCode = inlineCode; } + void setProcessingTimerCallback( bool timerCallback ) { m_timerCallback = timerCallback; } + /** + * "Smart" window.open policy + */ + bool isWindowOpenAllowed() const; + + private: + khtml::ChildFrame* m_frame; + QPtrDict<DOMObject> m_domObjects; + QPtrDict<void> m_customizedDomObjects; //Objects which had custom properties set, + //and should not be GC'd. key is DOMObject* + DOM::Event *m_evt; + bool m_inlineCode; + bool m_timerCallback; + }; + /** + * Retrieve from cache, or create, a KJS object around a DOM object + */ + template<class DOMObj, class KJSDOMObj> + inline Value cacheDOMObject(ExecState *exec, DOMObj domObj) + { + DOMObject *ret; + if (domObj.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(domObj.handle()))) + return Value(ret); + else { + ret = new KJSDOMObj(exec, domObj); + interp->putDOMObject(domObj.handle(),ret); + return Value(ret); + } + } + + /** + * Convert an object to a Node. Returns a null Node if not possible. + */ + DOM::Node toNode(const Value&); + /** + * Get a String object, or Null() if s is null + */ + Value getString(DOM::DOMString s); + + /** + * Convery a KJS value into a QVariant + */ + QVariant ValueToVariant(ExecState* exec, const Value& val); + + /** + * We need a modified version of lookupGet because + * we call tryGet instead of get, in DOMObjects. + */ + template <class FuncImp, class ThisImp, class ParentImp> + inline Value DOMObjectLookupGet(ExecState *exec, const Identifier &propertyName, + const HashTable* table, const ThisImp* thisObj) + { + const HashEntry* entry = Lookup::findEntry(table, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::tryGet(exec, propertyName); + + if (entry->attr & Function) { + return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr); + } + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * Simplified version of DOMObjectLookupGet in case there are no + * functions, only "values". + */ + template <class ThisImp, class ParentImp> + inline Value DOMObjectLookupGetValue(ExecState *exec, const Identifier &propertyName, + const HashTable* table, const ThisImp* thisObj) + { + const HashEntry* entry = Lookup::findEntry(table, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::tryGet(exec, propertyName); + + if (entry->attr & Function) + fprintf(stderr, "Function bit set! Shouldn't happen in lookupValue!\n" ); + return thisObj->getValueProperty(exec, entry->value); + } + + /** + * We need a modified version of lookupPut because + * we call tryPut instead of put, in DOMObjects. + */ + template <class ThisImp, class ParentImp> + inline void DOMObjectLookupPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr, + const HashTable* table, ThisImp* thisObj) + { + const HashEntry* entry = Lookup::findEntry(table, propertyName); + + if (!entry) // not found: forward to parent + thisObj->ParentImp::tryPut(exec, propertyName, value, attr); + else if (entry->attr & Function) // function: put as override property + thisObj->ObjectImp::put(exec, propertyName, value, attr); + else if (entry->attr & ReadOnly) // readonly! Can't put! +#ifdef KJS_VERBOSE + fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii()); +#else + ; // do nothing +#endif + else + thisObj->putValueProperty(exec, entry->value, value, attr); + } + +// Versions of prototype functions that properly support instanceof, +// and are compatible with trunk. +#define KJS_DEFINE_PROTOTYPE_IMP(ClassProto,ProtoCode) \ + class ClassProto : public ObjectImp { \ + friend Object cacheGlobalObject<ClassProto>(ExecState *exec, const Identifier &propertyName); \ + public: \ + static Object self(ExecState *exec); \ + virtual const ClassInfo *classInfo() const { return &info; } \ + static const ClassInfo info; \ + Value get(ExecState *exec, const Identifier &propertyName) const; \ + protected: \ + ClassProto( ExecState *exec ) \ + : ObjectImp( ProtoCode ) {} \ + \ + static Identifier* s_name; \ + static Identifier* name(); \ + }; + +#define KJS_DEFINE_PROTOTYPE(ClassProto) \ + KJS_DEFINE_PROTOTYPE_IMP(ClassProto, exec->interpreter()->builtinObjectPrototype()) + +#define KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(ClassProto, ClassProtoProto) \ + KJS_DEFINE_PROTOTYPE_IMP(ClassProto, ClassProtoProto::self(exec)) + +#define KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ProtoCode) \ + class ClassProto : public ObjectImp { \ + friend Object cacheGlobalObject<ClassProto>(ExecState *exec, const Identifier &propertyName); \ + public: \ + static Object self(ExecState *exec) { \ + return cacheGlobalObject<ClassProto>(exec, *name()); \ + } \ + virtual const ClassInfo *classInfo() const { return &info; } \ + static const ClassInfo info; \ + protected: \ + ClassProto( ExecState *exec ) \ + : ObjectImp( ProtoCode ) {} \ + \ + static Identifier* s_name; \ + static Identifier* name() { \ + if (!s_name) s_name = new Identifier("[[" ClassName ".prototype]]"); \ + return s_name; \ + }\ + }; \ + Identifier* ClassProto::s_name = 0; \ + const ClassInfo ClassProto::info = { ClassName, 0, 0, 0 }; + +#define KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE(ClassName, ClassProto, ClassProtoProto) \ + KJS_EMPTY_PROTOTYPE_IMP(ClassName, ClassProto, ClassProtoProto::self(exec)) + +//### this doesn't implement hasProperty, but stuff in lookup.h didn't +//either (just did the forward) +#define KJS_IMPLEMENT_PROTOTYPE(ClassName, ClassProto, ClassFunc) \ + const ClassInfo ClassProto::info = { ClassName, 0, &ClassProto##Table, 0 }; \ + Identifier* ClassProto::s_name = 0; \ + Object ClassProto::self(ExecState *exec) \ + { \ + return cacheGlobalObject<ClassProto>(exec, *name()); \ + } \ + Value ClassProto::get(ExecState *exec, const Identifier &propertyName) const \ + { \ + /*fprintf( stderr, "%sProto::get(%s) [in macro, no parent]\n", info.className, propertyName.ascii());*/ \ + return lookupGetFunction<ClassFunc,ObjectImp>(exec, propertyName, &ClassProto##Table, this ); \ + } \ + Identifier* ClassProto::name() \ + { \ + if (!s_name) s_name = new Identifier("[[" ClassName ".prototype]]"); \ + return s_name; \ + } + + // Modified version of IMPLEMENT_PROTOFUNC, to use DOMFunction and tryCall +#define IMPLEMENT_PROTOFUNC_DOM(ClassFunc) \ + class ClassFunc : public DOMFunction { \ + public: \ + ClassFunc(ExecState *exec, int i, int len) \ + : DOMFunction( exec ), id(i) { \ + Value protect(this); \ + put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); \ + } \ + /** You need to implement that one */ \ + virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args); \ + private: \ + int id; \ + }; + + Value getLiveConnectValue(KParts::LiveConnectExtension *lc, const QString & name, const int type, const QString & value, int id); + + +// This is used to create pseudo-constructor objects, like Mozillaish +// Element, HTMLDocument, etc., which do not act like real constructors, +// but do have the prototype property pointing to prototype of "instances" +#define DEFINE_PSEUDO_CONSTRUCTOR(ClassName) \ + class ClassName : public DOMObject { \ + public: \ + ClassName(ExecState *); \ + virtual const ClassInfo* classInfo() const { return &info; } \ + static const ClassInfo info; \ + static Object self(ExecState *exec); \ + }; + +#define IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProto) \ + const ClassInfo Class::info = { ClassName, 0, 0, 0 }; \ + Class::Class(ExecState* exec): DOMObject(ParentProto) {\ + Object proto = ProtoClass::self(exec); \ + putDirect(prototypePropertyName, proto.imp(), DontDelete|ReadOnly); \ + }\ + Object Class::self(ExecState *exec) { \ + return Object(cacheGlobalObject<Class>(exec, "[[" ClassName ".constructor]]")); \ + } + +#define IMPLEMENT_PSEUDO_CONSTRUCTOR(Class,ClassName,ProtoClass) \ + IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,exec->lexicalInterpreter()->builtinObjectPrototype()) + +#define IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(Class,ClassName,ProtoClass,ParentProtoClass) \ + IMPLEMENT_PSEUDO_CONSTRUCTOR_IMP(Class,ClassName,ProtoClass,ParentProtoClass::self(exec)) + +// This declares a constant table, which merely maps everything in its +// table to its token value. Can be used as a prototype +#define DEFINE_CONSTANT_TABLE(Class) \ + class Class : public DOMObject { \ + public: \ + Class(ExecState *exec): DOMObject(exec->lexicalInterpreter()->builtinObjectPrototype()) {} \ + \ + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const;\ + Value getValueProperty(ExecState * /*exec*/, int token) const; \ + virtual const ClassInfo* classInfo() const { return &info; } \ + static const ClassInfo info; \ + static Object self(ExecState *exec);\ + static Identifier* s_name; \ + static Identifier* name(); \ + }; + +// Emits an implementation of a constant table +#define IMPLEMENT_CONSTANT_TABLE(Class,ClassName) \ + Value Class::tryGet(ExecState *exec, const Identifier &propertyName) const { \ + return DOMObjectLookupGetValue<Class, DOMObject>(exec, propertyName, &Class##Table, this);\ + } \ + Value Class::getValueProperty(ExecState * /*exec*/, int token) const { \ + /* We use the token as the value to return directly*/ \ + return Number((unsigned int)token); \ + } \ + Object Class::self(ExecState *exec) { \ + return cacheGlobalObject<Class>(exec, *name()); \ + } \ + Identifier* Class::s_name = 0; \ + Identifier* Class::name() { \ + if (!s_name) s_name = new Identifier("[[" ClassName ".constant_table]]"); \ + return s_name; \ + } \ + const ClassInfo Class::info = { ClassName, 0, &Class##Table, 0 }; + + +// Hide some of the stuff in lookup.h.. +#undef PUBLIC_DEFINE_PROTOTYPE +#undef DEFINE_PROTOTYPE +#undef IMPLEMENT_PROTOTYPE +#undef PUBLIC_IMPLEMENT_PROTOTYPE +#undef IMPLEMENT_PROTOTYPE_WITH_PARENT + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_css.cpp b/khtml/ecma/kjs_css.cpp new file mode 100644 index 000000000..167809046 --- /dev/null +++ b/khtml/ecma/kjs_css.cpp @@ -0,0 +1,1302 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_css.h" +#include "kjs_css.lut.h" + +#include <dom/html_head.h> // for HTMLStyleElement + +#include <css/css_base.h> +#include "kjs_dom.h" + + +#include <kdebug.h> + +namespace KJS { + +static QString cssPropertyName( const Identifier &p, bool& hadPixelPrefix ) +{ + QString prop = p.qstring(); + int i = prop.length(); + while ( --i ) { + char c = prop[i].latin1(); + if ( c >= 'A' && c <= 'Z' ) + prop.insert( i, '-' ); + } + + prop = prop.lower(); + hadPixelPrefix = false; + + if (prop.startsWith("css-")) { + prop = prop.mid(4); + } else if (prop.startsWith("pixel-")) { + prop = prop.mid(6); + hadPixelPrefix = true; + } else if (prop.startsWith("pos-")) { + prop = prop.mid(4); + hadPixelPrefix = true; + } + + return prop; +} + +/* +@begin DOMCSSStyleDeclarationProtoTable 7 + getPropertyValue DOMCSSStyleDeclaration::GetPropertyValue DontDelete|Function 1 + getPropertyCSSValue DOMCSSStyleDeclaration::GetPropertyCSSValue DontDelete|Function 1 + removeProperty DOMCSSStyleDeclaration::RemoveProperty DontDelete|Function 1 + getPropertyPriority DOMCSSStyleDeclaration::GetPropertyPriority DontDelete|Function 1 + setProperty DOMCSSStyleDeclaration::SetProperty DontDelete|Function 3 + item DOMCSSStyleDeclaration::Item DontDelete|Function 1 +# IE names for it (#36063) + getAttribute DOMCSSStyleDeclaration::GetPropertyValue DontDelete|Function 1 + removeAttribute DOMCSSStyleDeclaration::RemoveProperty DontDelete|Function 1 + setAttribute DOMCSSStyleDeclaration::SetProperty DontDelete|Function 3 +@end +@begin DOMCSSStyleDeclarationTable 3 + cssText DOMCSSStyleDeclaration::CssText DontDelete + length DOMCSSStyleDeclaration::Length DontDelete|ReadOnly + parentRule DOMCSSStyleDeclaration::ParentRule DontDelete|ReadOnly +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMCSSStyleDeclarationProto) +IMPLEMENT_PROTOFUNC_DOM(DOMCSSStyleDeclarationProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMCSSStyleDeclaration", DOMCSSStyleDeclarationProto, DOMCSSStyleDeclarationProtoFunc) + +IMPLEMENT_PSEUDO_CONSTRUCTOR(CSSStyleDeclarationPseudoCtor, "DOMCSSStyleDeclaration",DOMCSSStyleDeclarationProto) + +const ClassInfo DOMCSSStyleDeclaration::info = { "CSSStyleDeclaration", 0, &DOMCSSStyleDeclarationTable, 0 }; + +DOMCSSStyleDeclaration::DOMCSSStyleDeclaration(ExecState *exec, const DOM::CSSStyleDeclaration& s) + : DOMObject(DOMCSSStyleDeclarationProto::self(exec)), styleDecl(s) +{ } + +DOMCSSStyleDeclaration::~DOMCSSStyleDeclaration() +{ + ScriptInterpreter::forgetDOMObject(styleDecl.handle()); +} + +bool DOMCSSStyleDeclaration::hasProperty(ExecState *exec, const Identifier &p) const +{ + bool hadPixelPrefix; + QString cssprop = cssPropertyName(p, hadPixelPrefix); + if (DOM::getPropertyID(cssprop.latin1(), cssprop.length())) + return true; + + return ObjectImp::hasProperty(exec, p); +} + +Value DOMCSSStyleDeclaration::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMCSSStyleDeclaration::tryGet " << propertyName.qstring() << endl; +#endif + const HashEntry* entry = Lookup::findEntry(&DOMCSSStyleDeclarationTable, propertyName); + if (entry) + switch (entry->value) { + case CssText: + return String(styleDecl.cssText()); + case Length: + return Number(styleDecl.length()); + case ParentRule: + return getDOMCSSRule(exec,styleDecl.parentRule()); + default: + break; + } + + // Look in the prototype (for functions) before assuming it's a name + Object proto = Object::dynamicCast(prototype()); + if (proto.isValid() && proto.hasProperty(exec,propertyName)) + return proto.get(exec,propertyName); + + bool ok; + long unsigned int u = propertyName.toULong(&ok); + if (ok) + return String(DOM::CSSStyleDeclaration(styleDecl).item(u)); + + // pixelTop returns "CSS Top" as number value in unit pixels + // posTop returns "CSS top" as number value in unit pixels _if_ its a + // positioned element. if it is not a positioned element, return 0 + // from MSIE documentation ### IMPLEMENT THAT (Dirk) + bool asNumber; + QString p = cssPropertyName(propertyName, asNumber); + +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMCSSStyleDeclaration: converting to css property name: " << p << ( asNumber ? "px" : "" ) << endl; +#endif + + if (asNumber) { + DOM::CSSValue v = styleDecl.getPropertyCSSValue(p); + if ( !v.isNull() && v.cssValueType() == DOM::CSSValue::CSS_PRIMITIVE_VALUE) + return Number(static_cast<DOM::CSSPrimitiveValue>(v).getFloatValue(DOM::CSSPrimitiveValue::CSS_PX)); + } + + DOM::DOMString str = const_cast<DOM::CSSStyleDeclaration &>( styleDecl ).getPropertyValue(p); + if (!str.isNull()) + return String(str); + + // see if we know this css property, return empty then + if (DOM::getPropertyID(p.latin1(), p.length())) + return String(DOM::DOMString("")); + + return DOMObject::tryGet(exec, propertyName); +} + + +void DOMCSSStyleDeclaration::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr ) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMCSSStyleDeclaration::tryPut " << propertyName.qstring() << endl; +#endif + if (propertyName == "cssText") { + styleDecl.setCssText(value.toString(exec).string()); + } + else { + bool pxSuffix; + QString prop = cssPropertyName(propertyName, pxSuffix); + QString propvalue = value.toString(exec).qstring(); + + if (pxSuffix) + propvalue += "px"; +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMCSSStyleDeclaration: prop=" << prop << " propvalue=" << propvalue << endl; +#endif + // Look whether the property is known.d In that case add it as a CSS property. + if (DOM::getPropertyID(prop.latin1(), prop.length())) { + if (propvalue.isEmpty()) + styleDecl.removeProperty(prop); + else { + int important = propvalue.find("!important", 0, false); + if (important == -1) + styleDecl.setProperty(prop, DOM::DOMString(propvalue), ""); + else + styleDecl.setProperty(prop, DOM::DOMString(propvalue.left(important - 1)), "important"); + } + } + else + // otherwise add it as a JS property + DOMObject::tryPut( exec, propertyName, value, attr ); + } +} + +Value DOMCSSStyleDeclarationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSStyleDeclaration, thisObj ); + DOM::CSSStyleDeclaration styleDecl = static_cast<DOMCSSStyleDeclaration *>(thisObj.imp())->toStyleDecl(); + String str = args[0].toString(exec); + DOM::DOMString s = str.value().string(); + + switch (id) { + case DOMCSSStyleDeclaration::GetPropertyValue: + return String(styleDecl.getPropertyValue(s)); + case DOMCSSStyleDeclaration::GetPropertyCSSValue: + return getDOMCSSValue(exec,styleDecl.getPropertyCSSValue(s)); + case DOMCSSStyleDeclaration::RemoveProperty: + return String(styleDecl.removeProperty(s)); + case DOMCSSStyleDeclaration::GetPropertyPriority: + return String(styleDecl.getPropertyPriority(s)); + case DOMCSSStyleDeclaration::SetProperty: + styleDecl.setProperty(args[0].toString(exec).string(), + args[1].toString(exec).string(), + args[2].toString(exec).string()); + return Undefined(); + case DOMCSSStyleDeclaration::Item: + return String(styleDecl.item(args[0].toInteger(exec))); + default: + return Undefined(); + } +} + +Value getDOMCSSStyleDeclaration(ExecState *exec, const DOM::CSSStyleDeclaration& s) +{ + return cacheDOMObject<DOM::CSSStyleDeclaration, KJS::DOMCSSStyleDeclaration>(exec, s); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMStyleSheet::info = { "StyleSheet", 0, &DOMStyleSheetTable, 0 }; +/* +@begin DOMStyleSheetTable 7 + type DOMStyleSheet::Type DontDelete|ReadOnly + disabled DOMStyleSheet::Disabled DontDelete + ownerNode DOMStyleSheet::OwnerNode DontDelete|ReadOnly + parentStyleSheet DOMStyleSheet::ParentStyleSheet DontDelete|ReadOnly + href DOMStyleSheet::Href DontDelete|ReadOnly + title DOMStyleSheet::Title DontDelete|ReadOnly + media DOMStyleSheet::Media DontDelete|ReadOnly +@end +*/ + +DOMStyleSheet::DOMStyleSheet(ExecState* exec, const DOM::StyleSheet& ss) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), styleSheet(ss) +{ +} + +DOMStyleSheet::~DOMStyleSheet() +{ + ScriptInterpreter::forgetDOMObject(styleSheet.handle()); +} + +Value DOMStyleSheet::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<DOMStyleSheet,DOMObject>(exec,propertyName,&DOMStyleSheetTable,this); +} + +Value DOMStyleSheet::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Type: + return String(styleSheet.type()); + case Disabled: + return Boolean(styleSheet.disabled()); + case OwnerNode: + return getDOMNode(exec,styleSheet.ownerNode()); + case ParentStyleSheet: + return getDOMStyleSheet(exec,styleSheet.parentStyleSheet()); + case Href: + return String(styleSheet.href()); + case Title: + return String(styleSheet.title()); + case Media: + return getDOMMediaList(exec, styleSheet.media()); + } + return Value(); +} + +void DOMStyleSheet::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + if (propertyName == "disabled") { + styleSheet.setDisabled(value.toBoolean(exec)); + } + else + DOMObject::tryPut(exec, propertyName, value, attr); +} + +Value getDOMStyleSheet(ExecState *exec, const DOM::StyleSheet& ss) +{ + DOMObject *ret; + if (ss.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(ss.handle()))) + return Value(ret); + else { + if (ss.isCSSStyleSheet()) { + DOM::CSSStyleSheet cs; + cs = ss; + ret = new DOMCSSStyleSheet(exec,cs); + } + else + ret = new DOMStyleSheet(exec,ss); + interp->putDOMObject(ss.handle(),ret); + return Value(ret); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMStyleSheetList::info = { "StyleSheetList", 0, &DOMStyleSheetListTable, 0 }; + +/* +@begin DOMStyleSheetListTable 2 + length DOMStyleSheetList::Length DontDelete|ReadOnly + item DOMStyleSheetList::Item DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMStyleSheetListFunc) // not really a proto, but doesn't matter + +DOMStyleSheetList::DOMStyleSheetList(ExecState *exec, const DOM::StyleSheetList& ssl, const DOM::Document& doc) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), styleSheetList(ssl), m_doc(doc) +{ +} + +DOMStyleSheetList::~DOMStyleSheetList() +{ + ScriptInterpreter::forgetDOMObject(styleSheetList.handle()); +} + +Value DOMStyleSheetList::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMStyleSheetList::tryGet " << p.qstring() << endl; +#endif + if (p == lengthPropertyName) + return Number(styleSheetList.length()); + else if (p == "item") + return lookupOrCreateFunction<DOMStyleSheetListFunc>(exec,p,this,DOMStyleSheetList::Item,1,DontDelete|Function); + + // Retrieve stylesheet by index + bool ok; + long unsigned int u = p.toULong(&ok); + if (ok) + return getDOMStyleSheet(exec, DOM::StyleSheetList(styleSheetList).item(u)); + + // IE also supports retrieving a stylesheet by name, using the name/id of the <style> tag + // (this is consistent with all the other collections) +#if 0 + // Bad implementation because DOM::StyleSheet doesn't inherit DOM::Node + // so we can't use DOMNamedNodesCollection..... + // We could duplicate it for stylesheets though - worth it ? + // Other problem of this implementation: it doesn't look for the ID attribute! + DOM::NameNodeListImpl namedList( m_doc.documentElement().handle(), p.string() ); + int len = namedList.length(); + if ( len ) { + QValueList<DOM::Node> styleSheets; + for ( int i = 0 ; i < len ; ++i ) { + DOM::HTMLStyleElement elem = DOM::Node(namedList.item(i)); + if (!elem.isNull()) + styleSheets.append(elem.sheet()); + } + if ( styleSheets.count() == 1 ) // single result + return getDOMStyleSheet(exec, styleSheets[0]); + else if ( styleSheets.count() > 1 ) { + return new DOMNamedItemsCollection(exec,styleSheets); + } + } +#endif + // ### Bad implementation because returns a single element (are IDs always unique?) + // and doesn't look for name attribute (see implementation above). + // But unicity of stylesheet ids is good practice anyway ;) + DOM::DOMString pstr = p.string(); + DOM::HTMLStyleElement styleElem = m_doc.getElementById( pstr ); + if (!styleElem.isNull()) + return getDOMStyleSheet(exec, styleElem.sheet()); + + return DOMObject::tryGet(exec, p); +} + +Value KJS::DOMStyleSheetList::call(ExecState *exec, Object &thisObj, const List &args) +{ + // This code duplication is necessary, DOMStyleSheetList isn't a DOMFunction + Value val; + try { + val = tryCall(exec, thisObj, args); + } + // pity there's no way to distinguish between these in JS code + catch (...) { + Object err = Error::create(exec, GeneralError, "Exception from DOMStyleSheetList"); + exec->setException(err); + } + return val; +} + +Value DOMStyleSheetList::tryCall(ExecState *exec, Object & /*thisObj*/, const List &args) +{ + if (args.size() == 1) { + // support for styleSheets(<index>) and styleSheets(<name>) + return tryGet( exec, Identifier(args[0].toString(exec)) ); + } + return Undefined(); +} + +Value getDOMStyleSheetList(ExecState *exec, const DOM::StyleSheetList& ssl, const DOM::Document& doc) +{ + // Can't use the cacheDOMObject macro because of the doc argument + DOMObject *ret; + if (ssl.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(ssl.handle()))) + return Value(ret); + else { + ret = new DOMStyleSheetList(exec, ssl, doc); + interp->putDOMObject(ssl.handle(),ret); + return Value(ret); + } +} + +Value DOMStyleSheetListFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMStyleSheetList, thisObj ); + DOM::StyleSheetList styleSheetList = static_cast<DOMStyleSheetList *>(thisObj.imp())->toStyleSheetList(); + if (id == DOMStyleSheetList::Item) + return getDOMStyleSheet(exec, styleSheetList.item(args[0].toInteger(exec))); + return Undefined(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMMediaList::info = { "MediaList", 0, &DOMMediaListTable, 0 }; + +/* +@begin DOMMediaListTable 2 + mediaText DOMMediaList::MediaText DontDelete|ReadOnly + length DOMMediaList::Length DontDelete|ReadOnly +@end +@begin DOMMediaListProtoTable 3 + item DOMMediaList::Item DontDelete|Function 1 + deleteMedium DOMMediaList::DeleteMedium DontDelete|Function 1 + appendMedium DOMMediaList::AppendMedium DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMMediaListProto) +IMPLEMENT_PROTOFUNC_DOM(DOMMediaListProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMMediaList", DOMMediaListProto, DOMMediaListProtoFunc) + +DOMMediaList::DOMMediaList(ExecState *exec, const DOM::MediaList& ml) + : DOMObject(DOMMediaListProto::self(exec)), mediaList(ml) { } + +DOMMediaList::~DOMMediaList() +{ + ScriptInterpreter::forgetDOMObject(mediaList.handle()); +} + +Value DOMMediaList::tryGet(ExecState *exec, const Identifier &p) const +{ + if (p == "mediaText") + return String(mediaList.mediaText()); + else if (p == lengthPropertyName) + return Number(mediaList.length()); + + bool ok; + long unsigned int u = p.toULong(&ok); + if (ok) + return String(mediaList.item(u)); + + return DOMObject::tryGet(exec, p); +} + +void DOMMediaList::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + if (propertyName == "mediaText") + mediaList.setMediaText(value.toString(exec).string()); + else + DOMObject::tryPut(exec, propertyName, value, attr); +} + +Value getDOMMediaList(ExecState *exec, const DOM::MediaList& ml) +{ + return cacheDOMObject<DOM::MediaList, KJS::DOMMediaList>(exec, ml); +} + +Value KJS::DOMMediaListProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMMediaList, thisObj ); + DOM::MediaList mediaList = static_cast<DOMMediaList *>(thisObj.imp())->toMediaList(); + switch (id) { + case DOMMediaList::Item: + return String(mediaList.item(args[0].toInteger(exec))); + case DOMMediaList::DeleteMedium: + mediaList.deleteMedium(args[0].toString(exec).string()); + return Undefined(); + case DOMMediaList::AppendMedium: + mediaList.appendMedium(args[0].toString(exec).string()); + return Undefined(); + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCSSStyleSheet::info = { "CSSStyleSheet", 0, &DOMCSSStyleSheetTable, 0 }; + +/* +@begin DOMCSSStyleSheetTable 2 + ownerRule DOMCSSStyleSheet::OwnerRule DontDelete|ReadOnly + cssRules DOMCSSStyleSheet::CssRules DontDelete|ReadOnly +# MSIE extension + rules DOMCSSStyleSheet::Rules DontDelete|ReadOnly +@end +@begin DOMCSSStyleSheetProtoTable 2 + insertRule DOMCSSStyleSheet::InsertRule DontDelete|Function 2 + deleteRule DOMCSSStyleSheet::DeleteRule DontDelete|Function 1 +# IE extensions + addRule DOMCSSStyleSheet::AddRule DontDelete|Function 3 + removeRule DOMCSSStyleSheet::RemoveRule DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMCSSStyleSheetProto) +IMPLEMENT_PROTOFUNC_DOM(DOMCSSStyleSheetProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMCSSStyleSheet",DOMCSSStyleSheetProto,DOMCSSStyleSheetProtoFunc) // warning, use _WITH_PARENT if DOMStyleSheet gets a proto + +DOMCSSStyleSheet::DOMCSSStyleSheet(ExecState *exec, const DOM::CSSStyleSheet& ss) + : DOMStyleSheet(DOMCSSStyleSheetProto::self(exec),ss) { } + +DOMCSSStyleSheet::~DOMCSSStyleSheet() +{ +} + +Value DOMCSSStyleSheet::tryGet(ExecState *exec, const Identifier &p) const +{ + DOM::CSSStyleSheet cssStyleSheet = static_cast<DOM::CSSStyleSheet>(styleSheet); + if (p == "ownerRule") + return getDOMCSSRule(exec,cssStyleSheet.ownerRule()); + else if (p == "cssRules" || p == "rules" /* MSIE extension */) + return getDOMCSSRuleList(exec,cssStyleSheet.cssRules()); + return DOMStyleSheet::tryGet(exec,p); +} + +Value DOMCSSStyleSheetProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSStyleSheet, thisObj ); + DOM::CSSStyleSheet styleSheet = static_cast<DOMCSSStyleSheet *>(thisObj.imp())->toCSSStyleSheet(); + + switch (id) { + case DOMCSSStyleSheet::InsertRule: + return Number(styleSheet.insertRule(args[0].toString(exec).string(),(long unsigned int)args[1].toInteger(exec))); + case DOMCSSStyleSheet::DeleteRule: + styleSheet.deleteRule(args[0].toInteger(exec)); + return Undefined(); + // IE extensions + case DOMCSSStyleSheet::AddRule: { + //Unpassed/-1 means append. Since insertRule is picky (throws exceptions) + //we adjust it to the desired length + unsigned long index = args[2].toInteger(exec); + unsigned long length = styleSheet.cssRules().length(); + if (args[2].type() == UndefinedType) index = length; + if (index > length) index = length; + DOM::DOMString str = args[0].toString(exec).string() + " { " + args[1].toString(exec).string() + " } "; + return Number(styleSheet.insertRule(str,index)); + } + case DOMCSSStyleSheet::RemoveRule: { + int index = args.size() > 0 ? args[0].toInteger(exec) : 0 /*first one*/; + styleSheet.deleteRule(index); + return Undefined(); + } + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCSSRuleList::info = { "CSSRuleList", 0, &DOMCSSRuleListTable, 0 }; +/* +@begin DOMCSSRuleListTable 3 + length DOMCSSRuleList::Length DontDelete|ReadOnly + item DOMCSSRuleList::Item DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMCSSRuleListFunc) // not really a proto, but doesn't matter + +DOMCSSRuleList::DOMCSSRuleList(ExecState* exec, const DOM::CSSRuleList& rl) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), cssRuleList(rl) +{ +} + +DOMCSSRuleList::~DOMCSSRuleList() +{ + ScriptInterpreter::forgetDOMObject(cssRuleList.handle()); +} + +Value DOMCSSRuleList::tryGet(ExecState *exec, const Identifier &p) const +{ + Value result; + if (p == lengthPropertyName) + return Number(cssRuleList.length()); + else if (p == "item") + return lookupOrCreateFunction<DOMCSSRuleListFunc>(exec,p,this,DOMCSSRuleList::Item,1,DontDelete|Function); + + bool ok; + long unsigned int u = p.toULong(&ok); + if (ok) + return getDOMCSSRule(exec,DOM::CSSRuleList(cssRuleList).item(u)); + + return DOMObject::tryGet(exec,p); +} + +Value DOMCSSRuleListFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSRuleList, thisObj ); + DOM::CSSRuleList cssRuleList = static_cast<DOMCSSRuleList *>(thisObj.imp())->toCSSRuleList(); + switch (id) { + case DOMCSSRuleList::Item: + return getDOMCSSRule(exec,cssRuleList.item(args[0].toInteger(exec))); + default: + return Undefined(); + } +} + +Value getDOMCSSRuleList(ExecState *exec, const DOM::CSSRuleList& rl) +{ + return cacheDOMObject<DOM::CSSRuleList, KJS::DOMCSSRuleList>(exec, rl); +} + +// ------------------------------------------------------------------------- + +IMPLEMENT_PROTOFUNC_DOM(DOMCSSRuleFunc) // Not a proto, but doesn't matter + +DOMCSSRule::DOMCSSRule(ExecState* exec, const DOM::CSSRule& r) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), cssRule(r) +{ +} + +DOMCSSRule::~DOMCSSRule() +{ + ScriptInterpreter::forgetDOMObject(cssRule.handle()); +} + +const ClassInfo DOMCSSRule::info = { "CSSRule", 0, &DOMCSSRuleTable, 0 }; +const ClassInfo DOMCSSRule::style_info = { "CSSStyleRule", &DOMCSSRule::info, &DOMCSSStyleRuleTable, 0 }; +const ClassInfo DOMCSSRule::media_info = { "CSSMediaRule", &DOMCSSRule::info, &DOMCSSMediaRuleTable, 0 }; +const ClassInfo DOMCSSRule::fontface_info = { "CSSFontFaceRule", &DOMCSSRule::info, &DOMCSSFontFaceRuleTable, 0 }; +const ClassInfo DOMCSSRule::page_info = { "CSSPageRule", &DOMCSSRule::info, &DOMCSSPageRuleTable, 0 }; +const ClassInfo DOMCSSRule::import_info = { "CSSImportRule", &DOMCSSRule::info, &DOMCSSImportRuleTable, 0 }; +const ClassInfo DOMCSSRule::charset_info = { "CSSCharsetRule", &DOMCSSRule::info, &DOMCSSCharsetRuleTable, 0 }; + +const ClassInfo* DOMCSSRule::classInfo() const +{ + switch (cssRule.type()) { + case DOM::CSSRule::STYLE_RULE: + return &style_info; + case DOM::CSSRule::MEDIA_RULE: + return &media_info; + case DOM::CSSRule::FONT_FACE_RULE: + return &fontface_info; + case DOM::CSSRule::PAGE_RULE: + return &page_info; + case DOM::CSSRule::IMPORT_RULE: + return &import_info; + case DOM::CSSRule::CHARSET_RULE: + return &charset_info; + case DOM::CSSRule::UNKNOWN_RULE: + default: + return &info; + } +} +/* +@begin DOMCSSRuleTable 4 + type DOMCSSRule::Type DontDelete|ReadOnly + cssText DOMCSSRule::CssText DontDelete|ReadOnly + parentStyleSheet DOMCSSRule::ParentStyleSheet DontDelete|ReadOnly + parentRule DOMCSSRule::ParentRule DontDelete|ReadOnly +@end +@begin DOMCSSStyleRuleTable 2 + selectorText DOMCSSRule::Style_SelectorText DontDelete + style DOMCSSRule::Style_Style DontDelete|ReadOnly +@end +@begin DOMCSSMediaRuleTable 4 + media DOMCSSRule::Media_Media DontDelete|ReadOnly + cssRules DOMCSSRule::Media_CssRules DontDelete|ReadOnly + insertRule DOMCSSRule::Media_InsertRule DontDelete|Function 2 + deleteRule DOMCSSRule::Media_DeleteRule DontDelete|Function 1 +@end +@begin DOMCSSFontFaceRuleTable 1 + style DOMCSSRule::FontFace_Style DontDelete|ReadOnly +@end +@begin DOMCSSPageRuleTable 2 + selectorText DOMCSSRule::Page_SelectorText DontDelete + style DOMCSSRule::Page_Style DontDelete|ReadOnly +@end +@begin DOMCSSImportRuleTable 3 + href DOMCSSRule::Import_Href DontDelete|ReadOnly + media DOMCSSRule::Import_Media DontDelete|ReadOnly + styleSheet DOMCSSRule::Import_StyleSheet DontDelete|ReadOnly +@end +@begin DOMCSSCharsetRuleTable 1 + encoding DOMCSSRule::Charset_Encoding DontDelete +@end +*/ +Value DOMCSSRule::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMCSSRule::tryGet " << propertyName.qstring() << endl; +#endif + const HashTable* table = classInfo()->propHashTable; // get the right hashtable + const HashEntry* entry = Lookup::findEntry(table, propertyName); + if (entry) { + if (entry->attr & Function) + return lookupOrCreateFunction<DOMCSSRuleFunc>(exec, propertyName, this, entry->value, entry->params, entry->attr); + return getValueProperty(exec, entry->value); + } + + // Base CSSRule stuff or parent class forward, as usual + return DOMObjectLookupGet<DOMCSSRuleFunc, DOMCSSRule, DOMObject>(exec, propertyName, &DOMCSSRuleTable, this); +} + +Value DOMCSSRule::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Type: + return Number(cssRule.type()); + case CssText: + return String(cssRule.cssText()); + case ParentStyleSheet: + return getDOMStyleSheet(exec,cssRule.parentStyleSheet()); + case ParentRule: + return getDOMCSSRule(exec,cssRule.parentRule()); + + // for DOM::CSSRule::STYLE_RULE: + case Style_SelectorText: + return String(static_cast<DOM::CSSStyleRule>(cssRule).selectorText()); + case Style_Style: + return getDOMCSSStyleDeclaration(exec,static_cast<DOM::CSSStyleRule>(cssRule).style()); + + // for DOM::CSSRule::MEDIA_RULE: + case Media_Media: + return getDOMMediaList(exec,static_cast<DOM::CSSMediaRule>(cssRule).media()); + case Media_CssRules: + return getDOMCSSRuleList(exec,static_cast<DOM::CSSMediaRule>(cssRule).cssRules()); + + // for DOM::CSSRule::FONT_FACE_RULE: + case FontFace_Style: + return getDOMCSSStyleDeclaration(exec,static_cast<DOM::CSSFontFaceRule>(cssRule).style()); + + // for DOM::CSSRule::PAGE_RULE: + case Page_SelectorText: + return String(static_cast<DOM::CSSPageRule>(cssRule).selectorText()); + case Page_Style: + return getDOMCSSStyleDeclaration(exec,static_cast<DOM::CSSPageRule>(cssRule).style()); + + // for DOM::CSSRule::IMPORT_RULE: + case Import_Href: + return String(static_cast<DOM::CSSImportRule>(cssRule).href()); + case Import_Media: + return getDOMMediaList(exec,static_cast<DOM::CSSImportRule>(cssRule).media()); + case Import_StyleSheet: + return getDOMStyleSheet(exec,static_cast<DOM::CSSImportRule>(cssRule).styleSheet()); + + // for DOM::CSSRule::CHARSET_RULE: + case Charset_Encoding: + return String(static_cast<DOM::CSSCharsetRule>(cssRule).encoding()); + + default: + kdDebug(6070) << "WARNING: DOMCSSRule::getValueProperty unhandled token " << token << endl; + } + return Undefined(); +} + +void DOMCSSRule::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + const HashTable* table = classInfo()->propHashTable; // get the right hashtable + const HashEntry* entry = Lookup::findEntry(table, propertyName); + if (entry) { + if (entry->attr & Function) // function: put as override property + { + ObjectImp::put(exec, propertyName, value, attr); + return; + } + else if ((entry->attr & ReadOnly) == 0) // let DOMObjectLookupPut print the warning if not + { + putValueProperty(exec, entry->value, value, attr); + return; + } + } + DOMObjectLookupPut<DOMCSSRule, DOMObject>(exec, propertyName, value, attr, &DOMCSSRuleTable, this); +} + +void DOMCSSRule::putValueProperty(ExecState *exec, int token, const Value& value, int) +{ + switch (token) { + // for DOM::CSSRule::STYLE_RULE: + case Style_SelectorText: + static_cast<DOM::CSSStyleRule>(cssRule).setSelectorText(value.toString(exec).string()); + return; + + // for DOM::CSSRule::PAGE_RULE: + case Page_SelectorText: + static_cast<DOM::CSSPageRule>(cssRule).setSelectorText(value.toString(exec).string()); + return; + + // for DOM::CSSRule::CHARSET_RULE: + case Charset_Encoding: + static_cast<DOM::CSSCharsetRule>(cssRule).setEncoding(value.toString(exec).string()); + return; + + default: + kdDebug(6070) << "WARNING: DOMCSSRule::putValueProperty unhandled token " << token << endl; + } +} + +Value DOMCSSRuleFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSRule, thisObj ); + DOM::CSSRule cssRule = static_cast<DOMCSSRule *>(thisObj.imp())->toCSSRule(); + + if (cssRule.type() == DOM::CSSRule::MEDIA_RULE) { + DOM::CSSMediaRule rule = static_cast<DOM::CSSMediaRule>(cssRule); + if (id == DOMCSSRule::Media_InsertRule) + return Number(rule.insertRule(args[0].toString(exec).string(),args[1].toInteger(exec))); + else if (id == DOMCSSRule::Media_DeleteRule) + rule.deleteRule(args[0].toInteger(exec)); + } + + return Undefined(); +} + +Value getDOMCSSRule(ExecState *exec, const DOM::CSSRule& r) +{ + return cacheDOMObject<DOM::CSSRule, KJS::DOMCSSRule>(exec, r); +} + +// ------------------------------------------------------------------------- + + +DOM::CSSRule toCSSRule(const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMCSSRule::info)) + return DOM::CSSRule(); + + const DOMCSSRule *dobj = static_cast<const DOMCSSRule*>(obj.imp()); + return dobj->toCSSRule(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo CSSRuleConstructor::info = { "CSSRuleConstructor", 0, &CSSRuleConstructorTable, 0 }; +/* +@begin CSSRuleConstructorTable 7 + UNKNOWN_RULE CSSRuleConstructor::UNKNOWN_RULE DontDelete|ReadOnly + STYLE_RULE CSSRuleConstructor::STYLE_RULE DontDelete|ReadOnly + CHARSET_RULE CSSRuleConstructor::CHARSET_RULE DontDelete|ReadOnly + IMPORT_RULE CSSRuleConstructor::IMPORT_RULE DontDelete|ReadOnly + MEDIA_RULE CSSRuleConstructor::MEDIA_RULE DontDelete|ReadOnly + FONT_FACE_RULE CSSRuleConstructor::FONT_FACE_RULE DontDelete|ReadOnly + PAGE_RULE CSSRuleConstructor::PAGE_RULE DontDelete|ReadOnly +@end +*/ + +CSSRuleConstructor::CSSRuleConstructor(ExecState *exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value CSSRuleConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<CSSRuleConstructor,DOMObject>(exec,p,&CSSRuleConstructorTable,this); +} + +Value CSSRuleConstructor::getValueProperty(ExecState *, int token) const +{ + switch (token) { + case UNKNOWN_RULE: + return Number(DOM::CSSRule::UNKNOWN_RULE); + case STYLE_RULE: + return Number(DOM::CSSRule::STYLE_RULE); + case CHARSET_RULE: + return Number(DOM::CSSRule::CHARSET_RULE); + case IMPORT_RULE: + return Number(DOM::CSSRule::IMPORT_RULE); + case MEDIA_RULE: + return Number(DOM::CSSRule::MEDIA_RULE); + case FONT_FACE_RULE: + return Number(DOM::CSSRule::FONT_FACE_RULE); + case PAGE_RULE: + return Number(DOM::CSSRule::PAGE_RULE); + } + return Value(); +} + +Value getCSSRuleConstructor(ExecState *exec) +{ + return cacheGlobalObject<CSSRuleConstructor>( exec, "[[cssRule.constructor]]" ); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCSSValue::info = { "CSSValue", 0, &DOMCSSValueTable, 0 }; + +/* +@begin DOMCSSValueTable 2 + cssText DOMCSSValue::CssText DontDelete|ReadOnly + cssValueType DOMCSSValue::CssValueType DontDelete|ReadOnly +@end +*/ + +DOMCSSValue::DOMCSSValue(ExecState* exec, const DOM::CSSValue& val) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), cssValue(val) +{ +} + +DOMCSSValue::~DOMCSSValue() +{ + ScriptInterpreter::forgetDOMObject(cssValue.handle()); +} + +Value DOMCSSValue::tryGet(ExecState *exec, const Identifier &p) const +{ + if (p == "cssText") + return String(cssValue.cssText()); + else if (p == "cssValueType") + return Number(cssValue.cssValueType()); + return DOMObject::tryGet(exec,p); +} + +void DOMCSSValue::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + if (propertyName == "cssText") + cssValue.setCssText(value.toString(exec).string()); + else + DOMObject::tryPut(exec, propertyName, value, attr); +} + +Value getDOMCSSValue(ExecState *exec, const DOM::CSSValue& v) +{ + DOMObject *ret; + if (v.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(v.handle()))) + return Value(ret); + else { + if (v.isCSSValueList()) + ret = new DOMCSSValueList(exec,v); + else if (v.isCSSPrimitiveValue()) + ret = new DOMCSSPrimitiveValue(exec,v); + else + ret = new DOMCSSValue(exec,v); + interp->putDOMObject(v.handle(),ret); + return Value(ret); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo CSSValueConstructor::info = { "CSSValueConstructor", 0, &CSSValueConstructorTable, 0 }; +/* +@begin CSSValueConstructorTable 5 + CSS_INHERIT CSSValueConstructor::CSS_INHERIT DontDelete|ReadOnly + CSS_PRIMITIVE_VALUE CSSValueConstructor::CSS_PRIMITIVE_VALUE DontDelete|ReadOnly + CSS_VALUE_LIST CSSValueConstructor::CSS_VALUE_LIST DontDelete|ReadOnly + CSS_CUSTOM CSSValueConstructor::CSS_CUSTOM DontDelete|ReadOnly +@end +*/ + +CSSValueConstructor::CSSValueConstructor(ExecState *exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value CSSValueConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<CSSValueConstructor,DOMObject>(exec,p,&CSSValueConstructorTable,this); +} + +Value CSSValueConstructor::getValueProperty(ExecState *, int token) const +{ + switch (token) { + case CSS_INHERIT: + return Number(DOM::CSSValue::CSS_INHERIT); + case CSS_PRIMITIVE_VALUE: + return Number(DOM::CSSValue::CSS_PRIMITIVE_VALUE); + case CSS_VALUE_LIST: + return Number(DOM::CSSValue::CSS_VALUE_LIST); + case CSS_CUSTOM: + return Number(DOM::CSSValue::CSS_CUSTOM); + } + return Value(); +} + +Value getCSSValueConstructor(ExecState *exec) +{ + return cacheGlobalObject<CSSValueConstructor>( exec, "[[cssValue.constructor]]" ); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCSSPrimitiveValue::info = { "CSSPrimitiveValue", 0, &DOMCSSPrimitiveValueTable, 0 }; +/* +@begin DOMCSSPrimitiveValueTable 1 + primitiveType DOMCSSPrimitiveValue::PrimitiveType DontDelete|ReadOnly +@end +@begin DOMCSSPrimitiveValueProtoTable 3 + setFloatValue DOMCSSPrimitiveValue::SetFloatValue DontDelete|Function 2 + getFloatValue DOMCSSPrimitiveValue::GetFloatValue DontDelete|Function 1 + setStringValue DOMCSSPrimitiveValue::SetStringValue DontDelete|Function 2 + getStringValue DOMCSSPrimitiveValue::GetStringValue DontDelete|Function 0 + getCounterValue DOMCSSPrimitiveValue::GetCounterValue DontDelete|Function 0 + getRectValue DOMCSSPrimitiveValue::GetRectValue DontDelete|Function 0 + getRGBColorValue DOMCSSPrimitiveValue::GetRGBColorValue DontDelete|Function 0 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMCSSPrimitiveValueProto) +IMPLEMENT_PROTOFUNC_DOM(DOMCSSPrimitiveValueProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMCSSPrimitiveValue",DOMCSSPrimitiveValueProto,DOMCSSPrimitiveValueProtoFunc) + +DOMCSSPrimitiveValue::DOMCSSPrimitiveValue(ExecState *exec, const DOM::CSSPrimitiveValue& v) + : DOMCSSValue(DOMCSSPrimitiveValueProto::self(exec), v) { } + +Value DOMCSSPrimitiveValue::tryGet(ExecState *exec, const Identifier &p) const +{ + if (p=="primitiveType") + return Number(static_cast<DOM::CSSPrimitiveValue>(cssValue).primitiveType()); + return DOMObject::tryGet(exec,p); +} + +Value DOMCSSPrimitiveValueProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSPrimitiveValue, thisObj ); + DOM::CSSPrimitiveValue val = static_cast<DOMCSSPrimitiveValue *>(thisObj.imp())->toCSSPrimitiveValue(); + switch (id) { + case DOMCSSPrimitiveValue::SetFloatValue: + val.setFloatValue(args[0].toInteger(exec),args[1].toNumber(exec)); + return Undefined(); + case DOMCSSPrimitiveValue::GetFloatValue: + return Number(val.getFloatValue(args[0].toInteger(exec))); + case DOMCSSPrimitiveValue::SetStringValue: + val.setStringValue(args[0].toInteger(exec),args[1].toString(exec).string()); + return Undefined(); + case DOMCSSPrimitiveValue::GetStringValue: + return String(val.getStringValue()); + case DOMCSSPrimitiveValue::GetCounterValue: + return getDOMCounter(exec,val.getCounterValue()); + case DOMCSSPrimitiveValue::GetRectValue: + return getDOMRect(exec,val.getRectValue()); + case DOMCSSPrimitiveValue::GetRGBColorValue: + return getDOMRGBColor(exec,val.getRGBColorValue()); + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo CSSPrimitiveValueConstructor::info = { "CSSPrimitiveValueConstructor", 0, &CSSPrimitiveValueConstructorTable, 0 }; + +/* +@begin CSSPrimitiveValueConstructorTable 27 + CSS_UNKNOWN DOM::CSSPrimitiveValue::CSS_UNKNOWN DontDelete|ReadOnly + CSS_NUMBER DOM::CSSPrimitiveValue::CSS_NUMBER DontDelete|ReadOnly + CSS_PERCENTAGE DOM::CSSPrimitiveValue::CSS_PERCENTAGE DontDelete|ReadOnly + CSS_EMS DOM::CSSPrimitiveValue::CSS_EMS DontDelete|ReadOnly + CSS_EXS DOM::CSSPrimitiveValue::CSS_EXS DontDelete|ReadOnly + CSS_PX DOM::CSSPrimitiveValue::CSS_PX DontDelete|ReadOnly + CSS_CM DOM::CSSPrimitiveValue::CSS_CM DontDelete|ReadOnly + CSS_MM DOM::CSSPrimitiveValue::CSS_MM DontDelete|ReadOnly + CSS_IN DOM::CSSPrimitiveValue::CSS_IN DontDelete|ReadOnly + CSS_PT DOM::CSSPrimitiveValue::CSS_PT DontDelete|ReadOnly + CSS_PC DOM::CSSPrimitiveValue::CSS_PC DontDelete|ReadOnly + CSS_DEG DOM::CSSPrimitiveValue::CSS_DEG DontDelete|ReadOnly + CSS_RAD DOM::CSSPrimitiveValue::CSS_RAD DontDelete|ReadOnly + CSS_GRAD DOM::CSSPrimitiveValue::CSS_GRAD DontDelete|ReadOnly + CSS_MS DOM::CSSPrimitiveValue::CSS_MS DontDelete|ReadOnly + CSS_S DOM::CSSPrimitiveValue::CSS_S DontDelete|ReadOnly + CSS_HZ DOM::CSSPrimitiveValue::CSS_HZ DontDelete|ReadOnly + CSS_KHZ DOM::CSSPrimitiveValue::CSS_KHZ DontDelete|ReadOnly + CSS_DIMENSION DOM::CSSPrimitiveValue::CSS_DIMENSION DontDelete|ReadOnly + CSS_STRING DOM::CSSPrimitiveValue::CSS_STRING DontDelete|ReadOnly + CSS_URI DOM::CSSPrimitiveValue::CSS_URI DontDelete|ReadOnly + CSS_IDENT DOM::CSSPrimitiveValue::CSS_IDENT DontDelete|ReadOnly + CSS_ATTR DOM::CSSPrimitiveValue::CSS_ATTR DontDelete|ReadOnly + CSS_COUNTER DOM::CSSPrimitiveValue::CSS_COUNTER DontDelete|ReadOnly + CSS_RECT DOM::CSSPrimitiveValue::CSS_RECT DontDelete|ReadOnly + CSS_RGBCOLOR DOM::CSSPrimitiveValue::CSS_RGBCOLOR DontDelete|ReadOnly +@end +*/ + +Value CSSPrimitiveValueConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<CSSPrimitiveValueConstructor,CSSValueConstructor>(exec,p,&CSSPrimitiveValueConstructorTable,this); +} + +Value CSSPrimitiveValueConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number(token); +} + +Value getCSSPrimitiveValueConstructor(ExecState *exec) +{ + return cacheGlobalObject<CSSPrimitiveValueConstructor>( exec, "[[cssPrimitiveValue.constructor]]" ); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCSSValueList::info = { "CSSValueList", 0, &DOMCSSValueListTable, 0 }; + +/* +@begin DOMCSSValueListTable 3 + length DOMCSSValueList::Length DontDelete|ReadOnly + item DOMCSSValueList::Item DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMCSSValueListFunc) // not really a proto, but doesn't matter + +DOMCSSValueList::DOMCSSValueList(ExecState *exec, const DOM::CSSValueList& v) + : DOMCSSValue(exec, v) { } + +Value DOMCSSValueList::tryGet(ExecState *exec, const Identifier &p) const +{ + Value result; + DOM::CSSValueList valueList = static_cast<DOM::CSSValueList>(cssValue); + + if (p == lengthPropertyName) + return Number(valueList.length()); + else if (p == "item") + return lookupOrCreateFunction<DOMCSSValueListFunc>(exec,p,this,DOMCSSValueList::Item,1,DontDelete|Function); + + bool ok; + long unsigned int u = p.toULong(&ok); + if (ok) + return getDOMCSSValue(exec,valueList.item(u)); + + return DOMCSSValue::tryGet(exec,p); +} + +Value DOMCSSValueListFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCSSValueList, thisObj ); + DOM::CSSValueList valueList = static_cast<DOMCSSValueList *>(thisObj.imp())->toValueList(); + switch (id) { + case DOMCSSValueList::Item: + return getDOMCSSValue(exec,valueList.item(args[0].toInteger(exec))); + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMRGBColor::info = { "RGBColor", 0, &DOMRGBColorTable, 0 }; + +/* +@begin DOMRGBColorTable 3 + red DOMRGBColor::Red DontDelete|ReadOnly + green DOMRGBColor::Green DontDelete|ReadOnly + blue DOMRGBColor::Blue DontDelete|ReadOnly +@end +*/ + +DOMRGBColor::DOMRGBColor(ExecState* exec, const DOM::RGBColor& c) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), rgbColor(c) +{ +} + +DOMRGBColor::~DOMRGBColor() +{ + //rgbColors.remove(rgbColor.handle()); +} + +Value DOMRGBColor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMRGBColor,DOMObject>(exec, p, + &DOMRGBColorTable, + this); +} + +Value DOMRGBColor::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Red: + return getDOMCSSValue(exec, rgbColor.red()); + case Green: + return getDOMCSSValue(exec, rgbColor.green()); + case Blue: + return getDOMCSSValue(exec, rgbColor.blue()); + default: + return Value(); + } +} + +Value getDOMRGBColor(ExecState *exec, const DOM::RGBColor& c) +{ + // ### implement equals for RGBColor since they're not refcounted objects + return Value(new DOMRGBColor(exec, c)); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMRect::info = { "Rect", 0, &DOMRectTable, 0 }; +/* +@begin DOMRectTable 4 + top DOMRect::Top DontDelete|ReadOnly + right DOMRect::Right DontDelete|ReadOnly + bottom DOMRect::Bottom DontDelete|ReadOnly + left DOMRect::Left DontDelete|ReadOnly +@end +*/ + +DOMRect::DOMRect(ExecState *exec, const DOM::Rect& r) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), rect(r) +{ +} + +DOMRect::~DOMRect() +{ + ScriptInterpreter::forgetDOMObject(rect.handle()); +} + +Value DOMRect::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMRect,DOMObject>(exec, p, + &DOMRectTable, this); +} + +Value DOMRect::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Top: + return getDOMCSSValue(exec, rect.top()); + case Right: + return getDOMCSSValue(exec, rect.right()); + case Bottom: + return getDOMCSSValue(exec, rect.bottom()); + case Left: + return getDOMCSSValue(exec, rect.left()); + default: + return Value(); + } +} + +Value getDOMRect(ExecState *exec, const DOM::Rect& r) +{ + return cacheDOMObject<DOM::Rect, KJS::DOMRect>(exec, r); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCounter::info = { "Counter", 0, &DOMCounterTable, 0 }; +/* +@begin DOMCounterTable 3 + identifier DOMCounter::identifier DontDelete|ReadOnly + listStyle DOMCounter::listStyle DontDelete|ReadOnly + separator DOMCounter::separator DontDelete|ReadOnly +@end +*/ +DOMCounter::DOMCounter(ExecState *exec, const DOM::Counter& c) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), counter(c) +{ +} + +DOMCounter::~DOMCounter() +{ + ScriptInterpreter::forgetDOMObject(counter.handle()); +} + +Value DOMCounter::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMCounter,DOMObject>(exec, p, + &DOMCounterTable, this); +} + +Value DOMCounter::getValueProperty(ExecState *, int token) const +{ + switch (token) { + case identifier: + return String(counter.identifier()); + case listStyle: + return String(counter.listStyle()); + case separator: + return String(counter.separator()); + default: + return Value(); + } +} + +Value getDOMCounter(ExecState *exec, const DOM::Counter& c) +{ + return cacheDOMObject<DOM::Counter, KJS::DOMCounter>(exec, c); +} + +} //namespace KJS diff --git a/khtml/ecma/kjs_css.h b/khtml/ecma/kjs_css.h new file mode 100644 index 000000000..2b7d14712 --- /dev/null +++ b/khtml/ecma/kjs_css.h @@ -0,0 +1,304 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_CSS_H_ +#define _KJS_CSS_H_ + +#include <dom/dom_node.h> +#include <dom/dom_doc.h> +#include <kjs/object.h> +#include <dom/css_value.h> +#include <dom/css_stylesheet.h> +#include <dom/css_rule.h> +#include "kjs_binding.h" + +namespace KJS { + + class DOMCSSStyleDeclaration : public DOMObject { + public: + DOMCSSStyleDeclaration(ExecState *exec, const DOM::CSSStyleDeclaration& s); + virtual ~DOMCSSStyleDeclaration(); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual bool hasProperty(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo *classInfo() const { return &info; } + static const ClassInfo info; + enum { CssText, Length, ParentRule, + GetPropertyValue, GetPropertyCSSValue, RemoveProperty, GetPropertyPriority, + SetProperty, Item }; + DOM::CSSStyleDeclaration toStyleDecl() const { return styleDecl; } + protected: + DOM::CSSStyleDeclaration styleDecl; + }; + + DEFINE_PSEUDO_CONSTRUCTOR(CSSStyleDeclarationPseudoCtor) + + Value getDOMCSSStyleDeclaration(ExecState *exec, const DOM::CSSStyleDeclaration& n); + + class DOMStyleSheet : public DOMObject { + public: + // Build a DOMStyleSheet + DOMStyleSheet(ExecState *, const DOM::StyleSheet& ss); + // Constructor for inherited classes + DOMStyleSheet(const Object& proto, const DOM::StyleSheet& ss) : DOMObject(proto), styleSheet(ss) { } + virtual ~DOMStyleSheet(); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual bool toBoolean(ExecState *) const { return true; } + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Type, Disabled, OwnerNode, ParentStyleSheet, Href, Title, Media }; + protected: + DOM::StyleSheet styleSheet; + }; + + Value getDOMStyleSheet(ExecState *exec, const DOM::StyleSheet& ss); + + class DOMStyleSheetList : public DOMObject { + public: + DOMStyleSheetList(ExecState *, const DOM::StyleSheetList& ssl, const DOM::Document& doc); + virtual ~DOMStyleSheetList(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + virtual Value call(ExecState *exec, Object &thisObj, const List &args); + Value tryCall(ExecState *exec, Object &thisObj, const List &args); + virtual bool implementsCall() const { return true; } + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + virtual bool toBoolean(ExecState* ) const { return true; } + static const ClassInfo info; + DOM::StyleSheetList toStyleSheetList() const { return styleSheetList; } + enum { Item, Length }; + private: + DOM::StyleSheetList styleSheetList; + DOM::Document m_doc; + }; + + // The document is only used for get-stylesheet-by-name (make optional if necessary) + Value getDOMStyleSheetList(ExecState *exec, const DOM::StyleSheetList& ss, const DOM::Document& doc); + + class DOMMediaList : public DOMObject { + public: + DOMMediaList(ExecState *, const DOM::MediaList& ml); + virtual ~DOMMediaList(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual const ClassInfo* classInfo() const { return &info; } + virtual bool toBoolean(ExecState* ) const { return true; } + static const ClassInfo info; + enum { MediaText, Length, + Item, DeleteMedium, AppendMedium }; + DOM::MediaList toMediaList() const { return mediaList; } + private: + DOM::MediaList mediaList; + }; + + Value getDOMMediaList(ExecState *exec, const DOM::MediaList& ss); + + class DOMCSSStyleSheet : public DOMStyleSheet { + public: + DOMCSSStyleSheet(ExecState *exec, const DOM::CSSStyleSheet& ss); + virtual ~DOMCSSStyleSheet(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { OwnerRule, CssRules, Rules, + InsertRule, DeleteRule, AddRule, RemoveRule }; + DOM::CSSStyleSheet toCSSStyleSheet() const { return static_cast<DOM::CSSStyleSheet>(styleSheet); } + }; + + class DOMCSSRuleList : public DOMObject { + public: + DOMCSSRuleList(ExecState *, const DOM::CSSRuleList& rl); + virtual ~DOMCSSRuleList(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Item, Length }; + DOM::CSSRuleList toCSSRuleList() const { return cssRuleList; } + protected: + DOM::CSSRuleList cssRuleList; + }; + + Value getDOMCSSRuleList(ExecState *exec, const DOM::CSSRuleList& rl); + + class DOMCSSRule : public DOMObject { + public: + DOMCSSRule(ExecState *, const DOM::CSSRule& r); + virtual ~DOMCSSRule(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int attr); + virtual const ClassInfo* classInfo() const; + static const ClassInfo info; + static const ClassInfo style_info, media_info, fontface_info, page_info, import_info, charset_info; + enum { ParentStyleSheet, Type, CssText, ParentRule, + Style_SelectorText, Style_Style, + Media_Media, Media_InsertRule, Media_DeleteRule, Media_CssRules, + FontFace_Style, Page_SelectorText, Page_Style, + Import_Href, Import_Media, Import_StyleSheet, Charset_Encoding }; + DOM::CSSRule toCSSRule() const { return cssRule; } + protected: + DOM::CSSRule cssRule; + }; + + Value getDOMCSSRule(ExecState *exec, const DOM::CSSRule& r); + + /** + * Convert an object to a CSSRule. Returns a null CSSRule if not possible. + */ + DOM::CSSRule toCSSRule(const Value&); + + // Constructor for CSSRule - currently only used for some global values + class CSSRuleConstructor : public DOMObject { + public: + CSSRuleConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { UNKNOWN_RULE, STYLE_RULE, CHARSET_RULE, IMPORT_RULE, MEDIA_RULE, FONT_FACE_RULE, PAGE_RULE }; + }; + + Value getCSSRuleConstructor(ExecState *exec); + + class DOMCSSValue : public DOMObject { + public: + DOMCSSValue(ExecState *, const DOM::CSSValue& v); + DOMCSSValue(const Object& proto, const DOM::CSSValue& v) : DOMObject(proto), cssValue(v) { } + virtual ~DOMCSSValue(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { CssText, CssValueType }; + protected: + DOM::CSSValue cssValue; + }; + + Value getDOMCSSValue(ExecState *exec, const DOM::CSSValue& v); + + // Constructor for CSSValue - currently only used for some global values + class CSSValueConstructor : public DOMObject { + public: + CSSValueConstructor(ExecState *exec); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { CSS_VALUE_LIST, CSS_PRIMITIVE_VALUE, CSS_CUSTOM, CSS_INHERIT }; + }; + + Value getCSSValueConstructor(ExecState *exec); + + class DOMCSSPrimitiveValue : public DOMCSSValue { + public: + DOMCSSPrimitiveValue(ExecState *exec, const DOM::CSSPrimitiveValue& v); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + DOM::CSSPrimitiveValue toCSSPrimitiveValue() const { return static_cast<DOM::CSSPrimitiveValue>(cssValue); } + enum { PrimitiveType, SetFloatValue, GetFloatValue, SetStringValue, GetStringValue, + GetCounterValue, GetRectValue, GetRGBColorValue }; + }; + + // Constructor for CSSPrimitiveValue - currently only used for some global values + class CSSPrimitiveValueConstructor : public CSSValueConstructor { + public: + CSSPrimitiveValueConstructor(ExecState *exec) : CSSValueConstructor(exec) { } + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + Value getCSSPrimitiveValueConstructor(ExecState *exec); + + class DOMCSSValueList : public DOMCSSValue { + public: + DOMCSSValueList(ExecState *exec, const DOM::CSSValueList& v); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Item, Length }; + DOM::CSSValueList toValueList() const { return static_cast<DOM::CSSValueList>(cssValue); } + }; + + class DOMRGBColor : public DOMObject { + public: + DOMRGBColor(ExecState*, const DOM::RGBColor& c); + ~DOMRGBColor(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Red, Green, Blue }; + protected: + DOM::RGBColor rgbColor; + }; + + Value getDOMRGBColor(ExecState *exec, const DOM::RGBColor& c); + + class DOMRect : public DOMObject { + public: + DOMRect(ExecState *, const DOM::Rect& r); + ~DOMRect(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Top, Right, Bottom, Left }; + protected: + DOM::Rect rect; + }; + + Value getDOMRect(ExecState *exec, const DOM::Rect& r); + + class DOMCounter : public DOMObject { + public: + DOMCounter(ExecState *, const DOM::Counter& c); + ~DOMCounter(); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { identifier, listStyle, separator }; + protected: + DOM::Counter counter; + }; + + Value getDOMCounter(ExecState *exec, const DOM::Counter& c); + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_debugwin.cpp b/khtml/ecma/kjs_debugwin.cpp new file mode 100644 index 000000000..13a12ce5f --- /dev/null +++ b/khtml/ecma/kjs_debugwin.cpp @@ -0,0 +1,1139 @@ +/* + * This file is part of the KDE libraries + * Copyright (C) 2000-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_debugwin.h" +#include "kjs_proxy.h" + +#ifdef KJS_DEBUGGER + +#include <assert.h> +#include <stdlib.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qtextedit.h> +#include <qlistbox.h> +#include <qmultilineedit.h> +#include <qapplication.h> +#include <qsplitter.h> +#include <qcombobox.h> +#include <qbitmap.h> +#include <qwidgetlist.h> +#include <qlabel.h> +#include <qdatastream.h> +#include <qcstring.h> +#include <qpainter.h> +#include <qscrollbar.h> + +#include <klocale.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kglobal.h> +#include <kmessagebox.h> +#include <kguiitem.h> +#include <kpopupmenu.h> +#include <kmenubar.h> +#include <kaction.h> +#include <kactioncollection.h> +#include <kglobalsettings.h> +#include <kshortcut.h> +#include <kconfig.h> +#include <kconfigbase.h> +#include <kapplication.h> +#include <dcop/dcopclient.h> +#include <kstringhandler.h> + +#include "kjs_dom.h" +#include "kjs_binding.h" +#include "khtml_part.h" +#include "khtmlview.h" +#include "khtml_pagecache.h" +#include "khtml_settings.h" +#include "khtml_factory.h" +#include "misc/decoder.h" +#include <kjs/ustring.h> +#include <kjs/object.h> +#include <kjs/function.h> +#include <kjs/interpreter.h> + +using namespace KJS; +using namespace khtml; + +SourceDisplay::SourceDisplay(KJSDebugWin *debugWin, QWidget *parent, const char *name) + : QScrollView(parent,name), m_currentLine(-1), m_sourceFile(0), m_debugWin(debugWin), + m_font(KGlobalSettings::fixedFont()) +{ + verticalScrollBar()->setLineStep(QFontMetrics(m_font).height()); + viewport()->setBackgroundMode(Qt::NoBackground); + m_breakpointIcon = KGlobal::iconLoader()->loadIcon("stop",KIcon::Small); +} + +SourceDisplay::~SourceDisplay() +{ + if (m_sourceFile) { + m_sourceFile->deref(); + m_sourceFile = 0L; + } +} + +void SourceDisplay::setSource(SourceFile *sourceFile) +{ + if ( sourceFile ) + sourceFile->ref(); + if (m_sourceFile) + m_sourceFile->deref(); + m_sourceFile = sourceFile; + if ( m_sourceFile ) + m_sourceFile->ref(); + + if (!m_sourceFile || !m_debugWin->isVisible()) { + return; + } + + QString code = sourceFile->getCode(); + const QChar *chars = code.unicode(); + uint len = code.length(); + QChar newLine('\n'); + QChar cr('\r'); + QChar tab('\t'); + QString tabstr(" "); + QString line; + m_lines.clear(); + int width = 0; + QFontMetrics metrics(m_font); + + for (uint pos = 0; pos < len; pos++) { + QChar c = chars[pos]; + if (c == cr) { + if (pos < len-1 && chars[pos+1] == newLine) + continue; + else + c = newLine; + } + if (c == newLine) { + m_lines.append(line); + int lineWidth = metrics.width(line); + if (lineWidth > width) + width = lineWidth; + line = ""; + } + else if (c == tab) { + line += tabstr; + } + else { + line += c; + } + } + if (line.length()) { + m_lines.append(line); + int lineWidth = metrics.width(line); + if (lineWidth > width) + width = lineWidth; + } + + int linenoDisplayWidth = metrics.width("888888"); + resizeContents(linenoDisplayWidth+4+width,metrics.height()*m_lines.count()); + update(); + sourceFile->deref(); +} + +void SourceDisplay::setCurrentLine(int lineno, bool doCenter) +{ + m_currentLine = lineno; + + if (doCenter && m_currentLine >= 0) { + QFontMetrics metrics(m_font); + int height = metrics.height(); + center(0,height*m_currentLine+height/2); + } + + updateContents(); +} + +void SourceDisplay::contentsMousePressEvent(QMouseEvent *e) +{ + QScrollView::mouseDoubleClickEvent(e); + QFontMetrics metrics(m_font); + int lineno = e->y()/metrics.height(); + emit lineDoubleClicked(lineno+1); // line numbers start from 1 +} + +void SourceDisplay::showEvent(QShowEvent *) +{ + setSource(m_sourceFile); +} + +void SourceDisplay::drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph) +{ + if (!m_sourceFile) { + p->fillRect(clipx,clipy,clipw,cliph,palette().active().base()); + return; + } + + QFontMetrics metrics(m_font); + int height = metrics.height(); + + int bottom = clipy + cliph; + int right = clipx + clipw; + + int firstLine = clipy/height-1; + if (firstLine < 0) + firstLine = 0; + int lastLine = bottom/height+2; + if (lastLine > (int)m_lines.count()) + lastLine = m_lines.count(); + + p->setFont(m_font); + + int linenoWidth = metrics.width("888888"); + + for (int lineno = firstLine; lineno <= lastLine; lineno++) { + QString linenoStr = QString().sprintf("%d",lineno+1); + + + p->fillRect(0,height*lineno,linenoWidth,height,palette().active().mid()); + + p->setPen(palette().active().text()); + p->drawText(0,height*lineno,linenoWidth,height,Qt::AlignRight,linenoStr); + + QColor bgColor; + QColor textColor; + + if (lineno == m_currentLine) { + bgColor = palette().active().highlight(); + textColor = palette().active().highlightedText(); + } + else if (m_debugWin->haveBreakpoint(m_sourceFile,lineno+1,lineno+1)) { + bgColor = palette().active().text(); + textColor = palette().active().base(); + p->drawPixmap(2,height*lineno+height/2-m_breakpointIcon.height()/2,m_breakpointIcon); + } + else { + bgColor = palette().active().base(); + textColor = palette().active().text(); + } + + p->fillRect(linenoWidth,height*lineno,right-linenoWidth,height,bgColor); + p->setPen(textColor); + p->drawText(linenoWidth+4,height*lineno,contentsWidth()-linenoWidth-4,height, + Qt::AlignLeft,m_lines[lineno]); + } + + int remainingTop = height*(lastLine+1); + p->fillRect(0,remainingTop,linenoWidth,bottom-remainingTop,palette().active().mid()); + + p->fillRect(linenoWidth,remainingTop, + right-linenoWidth,bottom-remainingTop,palette().active().base()); +} + +//------------------------------------------------------------------------- + +KJSDebugWin * KJSDebugWin::kjs_html_debugger = 0; + +QString SourceFile::getCode() +{ + if (interpreter) { + KHTMLPart *part = ::qt_cast<KHTMLPart*>(static_cast<ScriptInterpreter*>(interpreter)->part()); + if (part && url == part->url().url() && KHTMLPageCache::self()->isValid(part->cacheId())) { + Decoder *decoder = part->createDecoder(); + QByteArray data; + QDataStream stream(data,IO_WriteOnly); + KHTMLPageCache::self()->saveData(part->cacheId(),&stream); + QString str; + if (data.size() == 0) + str = ""; + else + str = decoder->decode(data.data(),data.size()) + decoder->flush(); + delete decoder; + return str; + } + } + + return code; +} + +//------------------------------------------------------------------------- + +SourceFragment::SourceFragment(int sid, int bl, int el, SourceFile *sf) +{ + sourceId = sid; + baseLine = bl; + errorLine = el; + sourceFile = sf; + sourceFile->ref(); +} + +SourceFragment::~SourceFragment() +{ + sourceFile->deref(); + sourceFile = 0L; +} + +//------------------------------------------------------------------------- + +KJSErrorDialog::KJSErrorDialog(QWidget *parent, const QString& errorMessage, bool showDebug) + : KDialogBase(parent,0,true,i18n("JavaScript Error"), + showDebug ? KDialogBase::Ok|KDialogBase::User1 : KDialogBase::Ok, + KDialogBase::Ok,false,KGuiItem("&Debug","gear")) +{ + QWidget *page = new QWidget(this); + setMainWidget(page); + + QLabel *iconLabel = new QLabel("",page); + iconLabel->setPixmap(KGlobal::iconLoader()->loadIcon("messagebox_critical", + KIcon::NoGroup,KIcon::SizeMedium, + KIcon::DefaultState,0,true)); + + QWidget *contents = new QWidget(page); + QLabel *label = new QLabel(errorMessage,contents); + m_dontShowAgainCb = new QCheckBox(i18n("&Do not show this message again"),contents); + + QVBoxLayout *vl = new QVBoxLayout(contents,0,spacingHint()); + vl->addWidget(label); + vl->addWidget(m_dontShowAgainCb); + + QHBoxLayout *topLayout = new QHBoxLayout(page,0,spacingHint()); + topLayout->addWidget(iconLabel); + topLayout->addWidget(contents); + topLayout->addStretch(10); + + m_debugSelected = false; +} + +KJSErrorDialog::~KJSErrorDialog() +{ +} + +void KJSErrorDialog::slotUser1() +{ + m_debugSelected = true; + close(); +} + +//------------------------------------------------------------------------- +EvalMultiLineEdit::EvalMultiLineEdit(QWidget *parent) + : QMultiLineEdit(parent) { +} + +void EvalMultiLineEdit::keyPressEvent(QKeyEvent * e) +{ + if (e->key() == Qt::Key_Return) { + if (hasSelectedText()) { + m_code = selectedText(); + } else { + int para, index; + getCursorPosition(¶, &index); + m_code = text(para); + } + end(); + } + QMultiLineEdit::keyPressEvent(e); +} +//------------------------------------------------------------------------- +KJSDebugWin::KJSDebugWin(QWidget *parent, const char *name) + : KMainWindow(parent, name, WType_TopLevel), KInstance("kjs_debugger") +{ + m_breakpoints = 0; + m_breakpointCount = 0; + + m_curSourceFile = 0; + m_mode = Continue; + m_nextSourceUrl = ""; + m_nextSourceBaseLine = 1; + m_execs = 0; + m_execsCount = 0; + m_execsAlloc = 0; + m_steppingDepth = 0; + + m_stopIcon = KGlobal::iconLoader()->loadIcon("stop",KIcon::Small); + m_emptyIcon = QPixmap(m_stopIcon.width(),m_stopIcon.height()); + QBitmap emptyMask(m_stopIcon.width(),m_stopIcon.height(),true); + m_emptyIcon.setMask(emptyMask); + + setCaption(i18n("JavaScript Debugger")); + + QWidget *mainWidget = new QWidget(this); + setCentralWidget(mainWidget); + + QVBoxLayout *vl = new QVBoxLayout(mainWidget,5); + + // frame list & code + QSplitter *hsplitter = new QSplitter(Qt::Vertical,mainWidget); + QSplitter *vsplitter = new QSplitter(hsplitter); + QFont font(KGlobalSettings::fixedFont()); + + QWidget *contextContainer = new QWidget(vsplitter); + + QLabel *contextLabel = new QLabel(i18n("Call stack"),contextContainer); + QWidget *contextListContainer = new QWidget(contextContainer); + m_contextList = new QListBox(contextListContainer); + m_contextList->setMinimumSize(100,200); + connect(m_contextList,SIGNAL(highlighted(int)),this,SLOT(slotShowFrame(int))); + + QHBoxLayout *clistLayout = new QHBoxLayout(contextListContainer); + clistLayout->addWidget(m_contextList); + clistLayout->addSpacing(KDialog::spacingHint()); + + QVBoxLayout *contextLayout = new QVBoxLayout(contextContainer); + contextLayout->addWidget(contextLabel); + contextLayout->addSpacing(KDialog::spacingHint()); + contextLayout->addWidget(contextListContainer); + + // source selection & display + QWidget *sourceSelDisplay = new QWidget(vsplitter); + QVBoxLayout *ssdvl = new QVBoxLayout(sourceSelDisplay); + + m_sourceSel = new QComboBox(toolBar()); + connect(m_sourceSel,SIGNAL(activated(int)),this,SLOT(slotSourceSelected(int))); + + m_sourceDisplay = new SourceDisplay(this,sourceSelDisplay); + ssdvl->addWidget(m_sourceDisplay); + connect(m_sourceDisplay,SIGNAL(lineDoubleClicked(int)),SLOT(slotToggleBreakpoint(int))); + + QValueList<int> vsplitSizes; + vsplitSizes.insert(vsplitSizes.end(),120); + vsplitSizes.insert(vsplitSizes.end(),480); + vsplitter->setSizes(vsplitSizes); + + // evaluate + + QWidget *evalContainer = new QWidget(hsplitter); + + QLabel *evalLabel = new QLabel(i18n("JavaScript console"),evalContainer); + m_evalEdit = new EvalMultiLineEdit(evalContainer); + m_evalEdit->setWordWrap(QMultiLineEdit::NoWrap); + m_evalEdit->setFont(font); + connect(m_evalEdit,SIGNAL(returnPressed()),SLOT(slotEval())); + m_evalDepth = 0; + + QVBoxLayout *evalLayout = new QVBoxLayout(evalContainer); + evalLayout->addSpacing(KDialog::spacingHint()); + evalLayout->addWidget(evalLabel); + evalLayout->addSpacing(KDialog::spacingHint()); + evalLayout->addWidget(m_evalEdit); + + QValueList<int> hsplitSizes; + hsplitSizes.insert(hsplitSizes.end(),400); + hsplitSizes.insert(hsplitSizes.end(),200); + hsplitter->setSizes(hsplitSizes); + + vl->addWidget(hsplitter); + + // actions + KPopupMenu *debugMenu = new KPopupMenu(this); + menuBar()->insertItem("&Debug",debugMenu); + + m_actionCollection = new KActionCollection(this); + m_actionCollection->setInstance(this); + + // Venkman use F12, KDevelop F10 + KShortcut scNext = KShortcut(KKeySequence(KKey(Qt::Key_F12))); + scNext.append(KKeySequence(KKey(Qt::Key_F10))); + m_nextAction = new KAction(i18n("Next breakpoint","&Next"),"dbgnext",scNext,this,SLOT(slotNext()), + m_actionCollection,"next"); + m_stepAction = new KAction(i18n("&Step"),"dbgstep",KShortcut(Qt::Key_F11),this,SLOT(slotStep()), + m_actionCollection,"step"); + // Venkman use F5, Kdevelop F9 + KShortcut scCont = KShortcut(KKeySequence(KKey(Qt::Key_F5))); + scCont.append(KKeySequence(KKey(Qt::Key_F9))); + m_continueAction = new KAction(i18n("&Continue"),"dbgrun",scCont,this,SLOT(slotContinue()), + m_actionCollection,"cont"); + m_stopAction = new KAction(i18n("St&op"),"stop",KShortcut(Qt::Key_F4),this,SLOT(slotStop()), + m_actionCollection,"stop"); + m_breakAction = new KAction(i18n("&Break at Next Statement"),"dbgrunto",KShortcut(Qt::Key_F8),this,SLOT(slotBreakNext()), + m_actionCollection,"breaknext"); + + + m_nextAction->setToolTip(i18n("Next breakpoint","Next")); + m_stepAction->setToolTip(i18n("Step")); + m_continueAction->setToolTip(i18n("Continue")); + m_stopAction->setToolTip(i18n("Stop")); + m_breakAction->setToolTip("Break at next Statement"); + + m_nextAction->setEnabled(false); + m_stepAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_stopAction->setEnabled(false); + m_breakAction->setEnabled(true); + + m_nextAction->plug(debugMenu); + m_stepAction->plug(debugMenu); + m_continueAction->plug(debugMenu); +// m_stopAction->plug(debugMenu); ### disabled until DebuggerImp::stop() works reliably + m_breakAction->plug(debugMenu); + + m_nextAction->plug(toolBar()); + m_stepAction->plug(toolBar()); + m_continueAction->plug(toolBar()); +// m_stopAction->plug(toolBar()); ### + m_breakAction->plug(toolBar()); + + toolBar()->insertWidget(1,300,m_sourceSel); + toolBar()->setItemAutoSized(1); + + updateContextList(); + setMinimumSize(300,200); + resize(600,450); + +} + +KJSDebugWin::~KJSDebugWin() +{ + free(m_breakpoints); + free(m_execs); +} + +KJSDebugWin *KJSDebugWin::createInstance() +{ + assert(!kjs_html_debugger); + kjs_html_debugger = new KJSDebugWin(); + return kjs_html_debugger; +} + +void KJSDebugWin::destroyInstance() +{ + assert(kjs_html_debugger); + kjs_html_debugger->hide(); + delete kjs_html_debugger; +} + +void KJSDebugWin::slotNext() +{ + m_mode = Next; + leaveSession(); +} + +void KJSDebugWin::slotStep() +{ + m_mode = Step; + leaveSession(); +} + +void KJSDebugWin::slotContinue() +{ + m_mode = Continue; + leaveSession(); +} + +void KJSDebugWin::slotStop() +{ + m_mode = Stop; + while (!m_execStates.isEmpty()) + leaveSession(); +} + +void KJSDebugWin::slotBreakNext() +{ + m_mode = Step; +} + +void KJSDebugWin::slotToggleBreakpoint(int lineno) +{ + if (m_sourceSel->currentItem() < 0) + return; + + SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem()); + + // Find the source fragment containing the selected line (if any) + int sourceId = -1; + int highestBaseLine = -1; + QMap<int,SourceFragment*>::Iterator it; + + for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it) { + SourceFragment *sourceFragment = it.data(); + if (sourceFragment && + sourceFragment->sourceFile == sourceFile && + sourceFragment->baseLine <= lineno && + sourceFragment->baseLine > highestBaseLine) { + + sourceId = sourceFragment->sourceId; + highestBaseLine = sourceFragment->baseLine; + } + } + + if (sourceId < 0) + return; + + // Update the source code display with the appropriate icon + int fragmentLineno = lineno-highestBaseLine+1; + if (!setBreakpoint(sourceId,fragmentLineno)) // was already set + deleteBreakpoint(sourceId,fragmentLineno); + + m_sourceDisplay->updateContents(); +} + +void KJSDebugWin::slotShowFrame(int frameno) +{ + if (frameno < 0 || frameno >= m_execsCount) + return; + + Context ctx = m_execs[frameno]->context(); + setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine()); +} + +void KJSDebugWin::slotSourceSelected(int sourceSelIndex) +{ + // A source file has been selected from the drop-down list - display the file + if (sourceSelIndex < 0 || sourceSelIndex >= (int)m_sourceSel->count()) + return; + SourceFile *sourceFile = m_sourceSelFiles.at(sourceSelIndex); + displaySourceFile(sourceFile,true); + + // If the currently selected context is in the current source file, then hilight + // the line it's on. + if (m_contextList->currentItem() >= 0) { + Context ctx = m_execs[m_contextList->currentItem()]->context(); + if (m_sourceFragments[ctx.sourceId()]->sourceFile == m_sourceSelFiles.at(sourceSelIndex)) + setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine()); + } +} + +void KJSDebugWin::slotEval() +{ + // Work out which execution state to use. If we're currently in a debugging session, + // use the current context - otherwise, use the global execution state from the interpreter + // corresponding to the currently displayed source file. + ExecState *exec; + Object thisobj; + if (m_execStates.isEmpty()) { + if (m_sourceSel->currentItem() < 0) + return; + SourceFile *sourceFile = m_sourceSelFiles.at(m_sourceSel->currentItem()); + if (!sourceFile->interpreter) + return; + exec = sourceFile->interpreter->globalExec(); + thisobj = exec->interpreter()->globalObject(); + } + else { + exec = m_execStates.top(); + thisobj = exec->context().thisValue(); + } + + // Evaluate the js code from m_evalEdit + UString code(m_evalEdit->code()); + QString msg; + + KJSCPUGuard guard; + guard.start(); + + Interpreter *interp = exec->interpreter(); + + Object obj = Object::dynamicCast(interp->globalObject().get(exec, "eval")); + List args; + args.append(String(code)); + + m_evalDepth++; + Value retval = obj.call(exec, thisobj, args); + m_evalDepth--; + guard.stop(); + + // Print the return value or exception message to the console + if (exec->hadException()) { + Value exc = exec->exception(); + exec->clearException(); + msg = "Exception: " + exc.toString(interp->globalExec()).qstring(); + } + else { + msg = retval.toString(interp->globalExec()).qstring(); + } + + m_evalEdit->insert(msg+"\n"); + updateContextList(); +} + +void KJSDebugWin::closeEvent(QCloseEvent *e) +{ + while (!m_execStates.isEmpty()) // ### not sure if this will work + leaveSession(); + return QWidget::closeEvent(e); +} + +bool KJSDebugWin::eventFilter(QObject *o, QEvent *e) +{ + switch (e->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::Destroy: + case QEvent::Close: + case QEvent::Quit: + while (o->parent()) + o = o->parent(); + if (o == this) + return QWidget::eventFilter(o,e); + else + return true; + break; + default: + return QWidget::eventFilter(o,e); + } +} + +void KJSDebugWin::disableOtherWindows() +{ + QWidgetList *widgets = QApplication::allWidgets(); + QWidgetListIt it(*widgets); + for (; it.current(); ++it) + it.current()->installEventFilter(this); +} + +void KJSDebugWin::enableOtherWindows() +{ + QWidgetList *widgets = QApplication::allWidgets(); + QWidgetListIt it(*widgets); + for (; it.current(); ++it) + it.current()->removeEventFilter(this); +} + +bool KJSDebugWin::sourceParsed(KJS::ExecState *exec, int sourceId, + const KJS::UString &source, int errorLine) +{ + // Work out which source file this fragment is in + SourceFile *sourceFile = 0; + if (!m_nextSourceUrl.isEmpty()) + sourceFile = getSourceFile(exec->interpreter(),m_nextSourceUrl); + + int index; + if (!sourceFile) { + index = m_sourceSel->count(); + if (!m_nextSourceUrl.isEmpty()) { + + QString code = source.qstring(); + KParts::ReadOnlyPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part(); + if (m_nextSourceUrl == part->url().url()) { + // Only store the code here if it's not from the part's html page... in that + // case we can get it from KHTMLPageCache + code = QString::null; + } + + sourceFile = new SourceFile(m_nextSourceUrl,code,exec->interpreter()); + setSourceFile(exec->interpreter(),m_nextSourceUrl,sourceFile); + m_sourceSelFiles.append(sourceFile); + m_sourceSel->insertItem(m_nextSourceUrl); + } + else { + // Sourced passed from somewhere else (possibly an eval call)... we don't know the url, + // but we still know the interpreter + sourceFile = new SourceFile("(unknown)",source.qstring(),exec->interpreter()); + m_sourceSelFiles.append(sourceFile); + m_sourceSel->insertItem(QString::number(index) += "-???"); + } + } + else { + // Ensure that each source file to be displayed is associated with + // an appropriate interpreter + if (!sourceFile->interpreter) + sourceFile->interpreter = exec->interpreter(); + for (index = 0; index < m_sourceSel->count(); index++) { + if (m_sourceSelFiles.at(index) == sourceFile) + break; + } + assert(index < m_sourceSel->count()); + } + + SourceFragment *sf = new SourceFragment(sourceId,m_nextSourceBaseLine,errorLine,sourceFile); + m_sourceFragments[sourceId] = sf; + + if (m_sourceSel->currentItem() < 0) + m_sourceSel->setCurrentItem(index); + + if (m_sourceSel->currentItem() == index) { + displaySourceFile(sourceFile,true); + } + + m_nextSourceBaseLine = 1; + m_nextSourceUrl = ""; + + return (m_mode != Stop); +} + +bool KJSDebugWin::sourceUnused(KJS::ExecState *exec, int sourceId) +{ + // Verify that there aren't any contexts on the stack using the given sourceId + // This should never be the case because this function is only called when + // the interpreter has deleted all Node objects for the source. + for (int e = 0; e < m_execsCount; e++) + assert(m_execs[e]->context().sourceId() != sourceId); + + // Now remove the fragment (and the SourceFile, if it was the last fragment in that file) + SourceFragment *fragment = m_sourceFragments[sourceId]; + if (fragment) { + m_sourceFragments.erase(sourceId); + + SourceFile *sourceFile = fragment->sourceFile; + if (sourceFile->hasOneRef()) { + for (int i = 0; i < m_sourceSel->count(); i++) { + if (m_sourceSelFiles.at(i) == sourceFile) { + m_sourceSel->removeItem(i); + m_sourceSelFiles.remove(i); + break; + } + } + removeSourceFile(exec->interpreter(),sourceFile->url); + } + delete fragment; + } + + return (m_mode != Stop); +} + +bool KJSDebugWin::exception(ExecState *exec, const Value &value, bool inTryCatch) +{ + assert(value.isValid()); + + // Ignore exceptions that will be caught by the script + if (inTryCatch) + return true; + + KParts::ReadOnlyPart *part = static_cast<ScriptInterpreter*>(exec->interpreter())->part(); + KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart*>(part); + if (khtmlpart && !khtmlpart->settings()->isJavaScriptErrorReportingEnabled()) + return true; + + QWidget *dlgParent = (m_evalDepth == 0) ? (QWidget*)part->widget() : (QWidget*)this; + + QString exceptionMsg = value.toString(exec).qstring(); + + // Syntax errors are a special case. For these we want to display the url & lineno, + // which isn't included in the exception messeage. So we work it out from the values + // passed to sourceParsed() + Object valueObj = Object::dynamicCast(value); + Object syntaxError = exec->interpreter()->builtinSyntaxError(); + if (valueObj.isValid() && valueObj.get(exec,"constructor").imp() == syntaxError.imp()) { + Value sidValue = valueObj.get(exec,"sid"); + if (sidValue.isA(NumberType)) { // sid is not set for Function() constructor + int sourceId = (int)sidValue.toNumber(exec); + assert(m_sourceFragments[sourceId]); + exceptionMsg = i18n("Parse error at %1 line %2") + .arg(m_sourceFragments[sourceId]->sourceFile->url) + .arg(m_sourceFragments[sourceId]->baseLine+m_sourceFragments[sourceId]->errorLine-1); + } + } + + bool dontShowAgain = false; + if (m_execsCount == 0) { + // An exception occurred and we're not currently executing any code... this can + // happen in some cases e.g. a parse error, or native code accessing funcitons like + // Object::put() + QString msg = i18n("An error occurred while attempting to run a script on this page.\n\n%1") + .arg(exceptionMsg); + KJSErrorDialog dlg(dlgParent,msg,false); + dlg.exec(); + dontShowAgain = dlg.dontShowAgain(); + } + else { + Context ctx = m_execs[m_execsCount-1]->context(); + SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()]; + QString msg = i18n("An error occurred while attempting to run a script on this page.\n\n%1 line %2:\n%3") + .arg(KStringHandler::rsqueeze( sourceFragment->sourceFile->url,80), + QString::number( sourceFragment->baseLine+ctx.curStmtFirstLine()-1), + exceptionMsg); + + KJSErrorDialog dlg(dlgParent,msg,true); + dlg.exec(); + dontShowAgain = dlg.dontShowAgain(); + + if (dlg.debugSelected()) { + m_mode = Next; + m_steppingDepth = m_execsCount-1; + enterSession(exec); + } + } + + if (dontShowAgain) { + KConfig *config = kapp->config(); + KConfigGroupSaver saver(config,QString::fromLatin1("Java/JavaScript Settings")); + config->writeEntry("ReportJavaScriptErrors",QVariant(false,0)); + config->sync(); + QByteArray data; + kapp->dcopClient()->send( "konqueror*", "KonquerorIface", "reparseConfiguration()", data ); + } + + return (m_mode != Stop); +} + +bool KJSDebugWin::atStatement(KJS::ExecState *exec) +{ + assert(m_execsCount > 0); + assert(m_execs[m_execsCount-1] == exec); + checkBreak(exec); + return (m_mode != Stop); +} + +bool KJSDebugWin::enterContext(ExecState *exec) +{ + if (m_execsCount >= m_execsAlloc) { + m_execsAlloc += 10; + m_execs = (ExecState**)realloc(m_execs,m_execsAlloc*sizeof(ExecState*)); + } + m_execs[m_execsCount++] = exec; + + if (m_mode == Step) + m_steppingDepth = m_execsCount-1; + + checkBreak(exec); + return (m_mode != Stop); +} + +bool KJSDebugWin::exitContext(ExecState *exec, const Completion &/*completion*/) +{ + assert(m_execsCount > 0); + assert(m_execs[m_execsCount-1] == exec); + + checkBreak(exec); + + m_execsCount--; + if (m_steppingDepth > m_execsCount-1) + m_steppingDepth = m_execsCount-1; + if (m_execsCount == 0) + updateContextList(); + + return (m_mode != Stop); +} + +void KJSDebugWin::displaySourceFile(SourceFile *sourceFile, bool forceRefresh) +{ + if (m_curSourceFile == sourceFile && !forceRefresh) + return; + sourceFile->ref(); + m_sourceDisplay->setSource(sourceFile); + if (m_curSourceFile) + m_curSourceFile->deref(); + m_curSourceFile = sourceFile; +} + +void KJSDebugWin::setSourceLine(int sourceId, int lineno) +{ + SourceFragment *source = m_sourceFragments[sourceId]; + if (!source) + return; + + SourceFile *sourceFile = source->sourceFile; + if (m_curSourceFile != source->sourceFile) { + for (int i = 0; i < m_sourceSel->count(); i++) + if (m_sourceSelFiles.at(i) == sourceFile) + m_sourceSel->setCurrentItem(i); + displaySourceFile(sourceFile,false); + } + m_sourceDisplay->setCurrentLine(source->baseLine+lineno-2); +} + +void KJSDebugWin::setNextSourceInfo(QString url, int baseLine) +{ + m_nextSourceUrl = url; + m_nextSourceBaseLine = baseLine; +} + +void KJSDebugWin::sourceChanged(Interpreter *interpreter, QString url) +{ + SourceFile *sourceFile = getSourceFile(interpreter,url); + if (sourceFile && m_curSourceFile == sourceFile) + displaySourceFile(sourceFile,true); +} + +void KJSDebugWin::clearInterpreter(Interpreter *interpreter) +{ + QMap<int,SourceFragment*>::Iterator it; + + for (it = m_sourceFragments.begin(); it != m_sourceFragments.end(); ++it) + if (it.data() && it.data()->sourceFile->interpreter == interpreter) + it.data()->sourceFile->interpreter = 0; +} + +SourceFile *KJSDebugWin::getSourceFile(Interpreter *interpreter, QString url) +{ + QString key = QString("%1|%2").arg((long)interpreter).arg(url); + return m_sourceFiles[key]; +} + +void KJSDebugWin::setSourceFile(Interpreter *interpreter, QString url, SourceFile *sourceFile) +{ + QString key = QString("%1|%2").arg((long)interpreter).arg(url); + sourceFile->ref(); + if (SourceFile* oldFile = m_sourceFiles[key]) + oldFile->deref(); + m_sourceFiles[key] = sourceFile; +} + +void KJSDebugWin::removeSourceFile(Interpreter *interpreter, QString url) +{ + QString key = QString("%1|%2").arg((long)interpreter).arg(url); + if (SourceFile* oldFile = m_sourceFiles[key]) + oldFile->deref(); + m_sourceFiles.remove(key); +} + +void KJSDebugWin::checkBreak(ExecState *exec) +{ + if (m_breakpointCount > 0) { + Context ctx = m_execs[m_execsCount-1]->context(); + if (haveBreakpoint(ctx.sourceId(),ctx.curStmtFirstLine(),ctx.curStmtLastLine())) { + m_mode = Next; + m_steppingDepth = m_execsCount-1; + } + } + + if ((m_mode == Step || m_mode == Next) && m_steppingDepth == m_execsCount-1) + enterSession(exec); +} + +void KJSDebugWin::enterSession(ExecState *exec) +{ + // This "enters" a new debugging session, i.e. enables usage of the debugging window + // It re-enters the qt event loop here, allowing execution of other parts of the + // program to continue while the script is stopped. We have to be a bit careful here, + // i.e. make sure the user can't quit the app, and disable other event handlers which + // could interfere with the debugging session. + if (!isVisible()) + show(); + + m_mode = Continue; + + if (m_execStates.isEmpty()) { + disableOtherWindows(); + m_nextAction->setEnabled(true); + m_stepAction->setEnabled(true); + m_continueAction->setEnabled(true); + m_stopAction->setEnabled(true); + m_breakAction->setEnabled(false); + } + m_execStates.push(exec); + + updateContextList(); + + qApp->enter_loop(); // won't return until leaveSession() is called +} + +void KJSDebugWin::leaveSession() +{ + // Disables debugging for this window and returns to execute the rest of the script + // (or aborts execution, if the user pressed stop). When this returns, the program + // will exit the qt event loop, i.e. return to whatever processing was being done + // before the debugger was stopped. + assert(!m_execStates.isEmpty()); + + m_execStates.pop(); + + if (m_execStates.isEmpty()) { + m_nextAction->setEnabled(false); + m_stepAction->setEnabled(false); + m_continueAction->setEnabled(false); + m_stopAction->setEnabled(false); + m_breakAction->setEnabled(true); + m_sourceDisplay->setCurrentLine(-1); + enableOtherWindows(); + } + + qApp->exit_loop(); +} + +void KJSDebugWin::updateContextList() +{ + disconnect(m_contextList,SIGNAL(highlighted(int)),this,SLOT(slotShowFrame(int))); + + m_contextList->clear(); + for (int i = 0; i < m_execsCount; i++) + m_contextList->insertItem(contextStr(m_execs[i]->context())); + + if (m_execsCount > 0) { + m_contextList->setSelected(m_execsCount-1, true); + Context ctx = m_execs[m_execsCount-1]->context(); + setSourceLine(ctx.sourceId(),ctx.curStmtFirstLine()); + } + + connect(m_contextList,SIGNAL(highlighted(int)),this,SLOT(slotShowFrame(int))); +} + +QString KJSDebugWin::contextStr(const Context &ctx) +{ + QString str = ""; + SourceFragment *sourceFragment = m_sourceFragments[ctx.sourceId()]; + QString url = sourceFragment->sourceFile->url; + int fileLineno = sourceFragment->baseLine+ctx.curStmtFirstLine()-1; + + switch (ctx.codeType()) { + case GlobalCode: + str = QString("Global code at %1:%2").arg(url).arg(fileLineno); + break; + case EvalCode: + str = QString("Eval code at %1:%2").arg(url).arg(fileLineno); + break; + case FunctionCode: + if (!ctx.functionName().isNull()) + str = QString("%1() at %2:%3").arg(ctx.functionName().qstring()).arg(url).arg(fileLineno); + else + str = QString("Anonymous function at %1:%2").arg(url).arg(fileLineno); + break; + } + + return str; +} + +bool KJSDebugWin::setBreakpoint(int sourceId, int lineno) +{ + if (haveBreakpoint(sourceId,lineno,lineno)) + return false; + + m_breakpointCount++; + m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints, + m_breakpointCount*sizeof(Breakpoint))); + m_breakpoints[m_breakpointCount-1].sourceId = sourceId; + m_breakpoints[m_breakpointCount-1].lineno = lineno; + + return true; +} + +bool KJSDebugWin::deleteBreakpoint(int sourceId, int lineno) +{ + for (int i = 0; i < m_breakpointCount; i++) { + if (m_breakpoints[i].sourceId == sourceId && m_breakpoints[i].lineno == lineno) { + + memmove(m_breakpoints+i,m_breakpoints+i+1,(m_breakpointCount-i-1)*sizeof(Breakpoint)); + m_breakpointCount--; + m_breakpoints = static_cast<Breakpoint*>(realloc(m_breakpoints, + m_breakpointCount*sizeof(Breakpoint))); + return true; + } + } + + return false; +} + +bool KJSDebugWin::haveBreakpoint(SourceFile *sourceFile, int line0, int line1) +{ + for (int i = 0; i < m_breakpointCount; i++) { + int sourceId = m_breakpoints[i].sourceId; + int lineno = m_breakpoints[i].lineno; + if (m_sourceFragments.contains(sourceId) && + m_sourceFragments[sourceId]->sourceFile == sourceFile) { + int absLineno = m_sourceFragments[sourceId]->baseLine+lineno-1; + if (absLineno >= line0 && absLineno <= line1) + return true; + } + } + + return false; +} + +#include "kjs_debugwin.moc" + +#endif // KJS_DEBUGGER diff --git a/khtml/ecma/kjs_debugwin.h b/khtml/ecma/kjs_debugwin.h new file mode 100644 index 000000000..5a2ce2f1f --- /dev/null +++ b/khtml/ecma/kjs_debugwin.h @@ -0,0 +1,285 @@ +/* + * This file is part of the KDE libraries + * Copyright (C) 2000-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_DEBUGGER_H_ +#define _KJS_DEBUGGER_H_ + +#include <qglobal.h> + +#define KJS_DEBUGGER + +#ifdef KJS_DEBUGGER + +#include <qwidget.h> +#include <qmultilineedit.h> +#include <qpixmap.h> +#include <qptrlist.h> +#include <qptrstack.h> +#include <qcheckbox.h> +#include <kdialogbase.h> +#include <kmainwindow.h> +#include <qscrollview.h> + +#include <kjs/debugger.h> + +#include "dom/dom_misc.h" + +class QListBox; +class QComboBox; +class KActionCollection; +class KAction; + +namespace KJS { + class FunctionImp; + class List; + class Interpreter; + class KJSDebugWin; + + class SourceFile : public DOM::DomShared + { + public: + SourceFile(QString u, QString c, Interpreter *interp) + : url(u), code(c), interpreter(interp) {} + QString getCode(); + QString url; + QString code; + Interpreter *interpreter; + }; + + /** + * @internal + * + * When kjs parses some code, it generates a source code fragment (or just "source"). + * This is referenced by its source id in future calls to functions such as atLine() + * and callEvent(). We keep a record of all source fragments parsed in order to display + * then to the user. + * + * For .js files, the source fragment will be the entire file. For js code included + * in html files, however, there may be multiple source fragments within the one file + * (e.g. multiple SCRIPT tags or onclick="..." attributes) + * + * In the case where a single file has multiple source fragments, the source objects + * for these fragments will all point to the same SourceFile for their code. + */ + class SourceFragment + { + public: + SourceFragment(int sid, int bl, int el, SourceFile *sf); + ~SourceFragment(); + + int sourceId; + int baseLine; + int errorLine; + SourceFile *sourceFile; + private: + SourceFragment(const SourceFragment& other); + SourceFragment& operator = (const SourceFragment& other); + }; + + class KJSErrorDialog : public KDialogBase { + Q_OBJECT + public: + KJSErrorDialog(QWidget *parent, const QString& errorMessage, bool showDebug); + virtual ~KJSErrorDialog(); + + bool debugSelected() const { return m_debugSelected; } + bool dontShowAgain() const { return m_dontShowAgainCb->isChecked(); } + + protected slots: + virtual void slotUser1(); + + private: + QCheckBox *m_dontShowAgainCb; + bool m_debugSelected; + }; + + class EvalMultiLineEdit : public QMultiLineEdit { + Q_OBJECT + public: + EvalMultiLineEdit(QWidget *parent); + const QString & code() const { return m_code; } + protected: + void keyPressEvent(QKeyEvent * e); + private: + QString m_code; + }; + + class SourceDisplay : public QScrollView { + Q_OBJECT + public: + SourceDisplay(KJSDebugWin *debugWin, QWidget *parent, const char *name = 0); + ~SourceDisplay(); + + void setSource(SourceFile *sourceFile); + void setCurrentLine(int lineno, bool doCenter = true); + + signals: + void lineDoubleClicked(int lineno); + + protected: + virtual void contentsMousePressEvent(QMouseEvent *e); + virtual void showEvent(QShowEvent *); + virtual void drawContents(QPainter *p, int clipx, int clipy, int clipw, int cliph); + + QString m_source; + int m_currentLine; + SourceFile *m_sourceFile; + QStringList m_lines; + + KJSDebugWin *m_debugWin; + QFont m_font; + QPixmap m_breakpointIcon; + }; + + /** + * @internal + * + * KJSDebugWin represents the debugger window that is visible to the user. It contains + * a stack frame list, a code viewer and a source fragment selector, plus buttons + * to control execution including next, step and continue. + * + * There is only one debug window per program. This can be obtained by calling #instance + */ + class KJSDebugWin : public KMainWindow, public Debugger, public KInstance + { + Q_OBJECT + friend class SourceDisplay; + public: + KJSDebugWin(QWidget *parent=0, const char *name=0); + virtual ~KJSDebugWin(); + + static KJSDebugWin *createInstance(); + static void destroyInstance(); + static KJSDebugWin *debugWindow() { return kjs_html_debugger; } + + enum Mode { Disabled = 0, // No break on any statements + Next = 1, // Will break on next statement in current context + Step = 2, // Will break on next statement in current or deeper context + Continue = 3, // Will continue until next breakpoint + Stop = 4 // The script will stop execution completely, + // as soon as possible + }; + + void setSourceLine(int sourceId, int lineno); + void setNextSourceInfo(QString url, int baseLine); + void sourceChanged(Interpreter *interpreter, QString url); + bool inSession() const { return !m_execStates.isEmpty(); } + void setMode(Mode m) { m_mode = m; } + void clearInterpreter(Interpreter *interpreter); + ExecState *getExecState() const { return m_execStates.top(); } + + // functions overridden from KJS:Debugger + bool sourceParsed(ExecState *exec, int sourceId, + const UString &source, int errorLine); + bool sourceUnused(ExecState * exec, int sourceId); + bool exception(ExecState *exec, const Value &value, bool inTryCatch); + bool atStatement(ExecState *exec); + bool enterContext(ExecState *exec); + bool exitContext(ExecState *exec, const Completion &completion); + + public slots: + void slotNext(); + void slotStep(); + void slotContinue(); + void slotStop(); + void slotBreakNext(); + void slotToggleBreakpoint(int lineno); + void slotShowFrame(int frameno); + void slotSourceSelected(int sourceSelIndex); + void slotEval(); + + protected: + + void closeEvent(QCloseEvent *e); + bool eventFilter(QObject *obj, QEvent *evt); + void disableOtherWindows(); + void enableOtherWindows(); + + private: + + SourceFile *getSourceFile(Interpreter *interpreter, QString url); + void setSourceFile(Interpreter *interpreter, QString url, SourceFile *sourceFile); + void removeSourceFile(Interpreter *interpreter, QString url); + + void checkBreak(ExecState *exec); + void enterSession(ExecState *exec); + void leaveSession(); + void displaySourceFile(SourceFile *sourceFile, bool forceRefresh); + void updateContextList(); + + QString contextStr(const Context &ctx); + + struct Breakpoint { + int sourceId; + int lineno; + }; + Breakpoint *m_breakpoints; + int m_breakpointCount; + bool setBreakpoint(int sourceId, int lineno); + bool deleteBreakpoint(int sourceId, int lineno); + bool haveBreakpoint(SourceFile *sourceFile, int line0, int line1); + bool haveBreakpoint(int sourceId, int line0, int line1) const { + for (int i = 0; i < m_breakpointCount; i++) { + if (m_breakpoints[i].sourceId == sourceId && + m_breakpoints[i].lineno >= line0 && + m_breakpoints[i].lineno <= line1) + return true; + } + return false; + } + + SourceFile *m_curSourceFile; + Mode m_mode; + QString m_nextSourceUrl; + int m_nextSourceBaseLine; + QPtrStack<ExecState> m_execStates; + ExecState **m_execs; + int m_execsCount; + int m_execsAlloc; + int m_steppingDepth; + + QMap<QString,SourceFile*> m_sourceFiles; /* maps url->SourceFile */ + QMap<int,SourceFragment*> m_sourceFragments; /* maps SourceId->SourceFragment */ + QPtrList<SourceFile> m_sourceSelFiles; /* maps combobox index->SourceFile */ + + KActionCollection *m_actionCollection; + QPixmap m_stopIcon; + QPixmap m_emptyIcon; + SourceDisplay *m_sourceDisplay; + QListBox *m_contextList; + + KAction *m_stepAction; + KAction *m_nextAction; + KAction *m_continueAction; + KAction *m_stopAction; + KAction *m_breakAction; + + QComboBox *m_sourceSel; + EvalMultiLineEdit *m_evalEdit; + int m_evalDepth; + + static KJSDebugWin *kjs_html_debugger; + }; + +} // namespace + +#endif // KJS_DEBUGGER + +#endif // _KJS_DEBUGGER_H_ diff --git a/khtml/ecma/kjs_dom.cpp b/khtml/ecma/kjs_dom.cpp new file mode 100644 index 000000000..74a90a9d2 --- /dev/null +++ b/khtml/ecma/kjs_dom.cpp @@ -0,0 +1,1849 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <khtmlview.h> +#include "xml/dom2_eventsimpl.h" +#include "rendering/render_canvas.h" +#include "rendering/render_layer.h" +#include "xml/dom_nodeimpl.h" +#include "xml/dom_docimpl.h" +#include "misc/htmltags.h" // ID_* +#include "misc/htmlattrs.h" // ATTR_* +#include "html/html_baseimpl.h" +#include <kdebug.h> +#include <khtml_part.h> + +#include "kjs_dom.h" +#include "kjs_html.h" +#include "kjs_css.h" +#include "kjs_range.h" +#include "kjs_traversal.h" +#include "kjs_events.h" +#include "kjs_views.h" +#include "kjs_window.h" +#include "dom/dom_exception.h" +#include "kjs_dom.lut.h" +#include "khtmlpart_p.h" + +namespace KJS { + +// ------------------------------------------------------------------------- +/* Source for DOMNodeConstantsTable. +@begin DOMNodeConstantsTable 11 + ELEMENT_NODE DOM::Node::ELEMENT_NODE DontDelete|ReadOnly + ATTRIBUTE_NODE DOM::Node::ATTRIBUTE_NODE DontDelete|ReadOnly + TEXT_NODE DOM::Node::TEXT_NODE DontDelete|ReadOnly + CDATA_SECTION_NODE DOM::Node::CDATA_SECTION_NODE DontDelete|ReadOnly + ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE DontDelete|ReadOnly + ENTITY_NODE DOM::Node::ENTITY_NODE DontDelete|ReadOnly + PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly + COMMENT_NODE DOM::Node::COMMENT_NODE DontDelete|ReadOnly + DOCUMENT_NODE DOM::Node::DOCUMENT_NODE DontDelete|ReadOnly + DOCUMENT_TYPE_NODE DOM::Node::DOCUMENT_TYPE_NODE DontDelete|ReadOnly + DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE DontDelete|ReadOnly + NOTATION_NODE DOM::Node::NOTATION_NODE DontDelete|ReadOnly +@end +*/ +IMPLEMENT_CONSTANT_TABLE(DOMNodeConstants,"DOMNodeConstants") +// ------------------------------------------------------------------------- +/* Source for DOMNodeProtoTable. +@begin DOMNodeProtoTable 13 + insertBefore DOMNode::InsertBefore DontDelete|Function 2 + replaceChild DOMNode::ReplaceChild DontDelete|Function 2 + removeChild DOMNode::RemoveChild DontDelete|Function 1 + appendChild DOMNode::AppendChild DontDelete|Function 1 + hasAttributes DOMNode::HasAttributes DontDelete|Function 0 + hasChildNodes DOMNode::HasChildNodes DontDelete|Function 0 + cloneNode DOMNode::CloneNode DontDelete|Function 1 +# DOM2 + normalize DOMNode::Normalize DontDelete|Function 0 + isSupported DOMNode::IsSupported DontDelete|Function 2 +# from the EventTarget interface + addEventListener DOMNode::AddEventListener DontDelete|Function 3 + removeEventListener DOMNode::RemoveEventListener DontDelete|Function 3 + dispatchEvent DOMNode::DispatchEvent DontDelete|Function 1 +# IE extensions + contains DOMNode::Contains DontDelete|Function 1 + insertAdjacentHTML DOMNode::InsertAdjacentHTML DontDelete|Function 2 +# "DOM level 0" (from Gecko DOM reference; also in WinIE) + item DOMNode::Item DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMNodeProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMNode", DOMNodeProto, DOMNodeProtoFunc) + +const ClassInfo DOMNode::info = { "Node", 0, &DOMNodeTable, 0 }; + +DOMNode::DOMNode(ExecState *exec, const DOM::Node& n) + : DOMObject(DOMNodeProto::self(exec)), node(n) +{ +} + +DOMNode::DOMNode(const Object& proto, const DOM::Node& n) + : DOMObject(proto), node(n) +{ +} + +DOMNode::~DOMNode() +{ + ScriptInterpreter::forgetDOMObject(node.handle()); +} + +bool DOMNode::toBoolean(ExecState *) const +{ + return !node.isNull(); +} + +/* Source for DOMNodeTable. +@begin DOMNodeTable 53 + nodeName DOMNode::NodeName DontDelete|ReadOnly + nodeValue DOMNode::NodeValue DontDelete + nodeType DOMNode::NodeType DontDelete|ReadOnly + parentNode DOMNode::ParentNode DontDelete|ReadOnly + parentElement DOMNode::ParentElement DontDelete|ReadOnly + childNodes DOMNode::ChildNodes DontDelete|ReadOnly + firstChild DOMNode::FirstChild DontDelete|ReadOnly + lastChild DOMNode::LastChild DontDelete|ReadOnly + previousSibling DOMNode::PreviousSibling DontDelete|ReadOnly + nextSibling DOMNode::NextSibling DontDelete|ReadOnly + attributes DOMNode::Attributes DontDelete|ReadOnly + namespaceURI DOMNode::NamespaceURI DontDelete|ReadOnly +# DOM2 + prefix DOMNode::Prefix DontDelete + localName DOMNode::LocalName DontDelete|ReadOnly + ownerDocument DOMNode::OwnerDocument DontDelete|ReadOnly +# DOM3 + textContent DOMNode::TextContent DontDelete +# Event handlers +# IE also has: onactivate, onbefore*, oncontextmenu, oncontrolselect, oncut, +# ondeactivate, ondrag*, ondrop, onfocusin, onfocusout, onhelp, onmousewheel, +# onmove*, onpaste, onpropertychange, onreadystatechange, onresizeend/start, +# onselectionchange, onstop + onabort DOMNode::OnAbort DontDelete + onblur DOMNode::OnBlur DontDelete + onchange DOMNode::OnChange DontDelete + onclick DOMNode::OnClick DontDelete + ondblclick DOMNode::OnDblClick DontDelete + ondragdrop DOMNode::OnDragDrop DontDelete + onerror DOMNode::OnError DontDelete + onfocus DOMNode::OnFocus DontDelete + onkeydown DOMNode::OnKeyDown DontDelete + onkeypress DOMNode::OnKeyPress DontDelete + onkeyup DOMNode::OnKeyUp DontDelete + onload DOMNode::OnLoad DontDelete + onmousedown DOMNode::OnMouseDown DontDelete + onmousemove DOMNode::OnMouseMove DontDelete + onmouseout DOMNode::OnMouseOut DontDelete + onmouseover DOMNode::OnMouseOver DontDelete + onmouseup DOMNode::OnMouseUp DontDelete + onmove DOMNode::OnMove DontDelete + onreset DOMNode::OnReset DontDelete + onresize DOMNode::OnResize DontDelete + onselect DOMNode::OnSelect DontDelete + onsubmit DOMNode::OnSubmit DontDelete + onunload DOMNode::OnUnload DontDelete +# IE extensions + offsetLeft DOMNode::OffsetLeft DontDelete|ReadOnly + offsetTop DOMNode::OffsetTop DontDelete|ReadOnly + offsetWidth DOMNode::OffsetWidth DontDelete|ReadOnly + offsetHeight DOMNode::OffsetHeight DontDelete|ReadOnly + offsetParent DOMNode::OffsetParent DontDelete|ReadOnly + clientWidth DOMNode::ClientWidth DontDelete|ReadOnly + clientHeight DOMNode::ClientHeight DontDelete|ReadOnly + scrollLeft DOMNode::ScrollLeft DontDelete + scrollTop DOMNode::ScrollTop DontDelete + scrollWidth DOMNode::ScrollWidth DontDelete|ReadOnly + scrollHeight DOMNode::ScrollHeight DontDelete|ReadOnly + sourceIndex DOMNode::SourceIndex DontDelete|ReadOnly +@end +*/ +Value DOMNode::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMNode::tryGet " << propertyName.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMNode, DOMObject>(exec, propertyName, &DOMNodeTable, this); +} + +static khtml::RenderObject* handleBodyRootQuirk(const DOM::Node& node, khtml::RenderObject* rend, int token) +{ + //This emulates the quirks of various height/width properties on the viewport and root. Note that it + //is (mostly) IE-compatible in quirks, and mozilla-compatible in strict. + if (!rend) return 0; + + bool quirksMode = rend->style() && rend->style()->htmlHacks(); + + //There are a couple quirks here. One is that in quirks mode body is always forwarded to root... + //This is relevant for even the scrollTop/scrollLeft type properties. + if (quirksMode && node.handle()->id() == ID_BODY) { + while (rend->parent() && !rend->isRoot()) + rend = rend->parent(); + } + + //Also, some properties of the root are really done in terms of the viewport. + //These are {offset/client}{Height/Width}. The offset versions do it only in + //quirks mode, the client always. + if (!rend->isRoot()) return rend; //Don't care about non-root things here! + bool needViewport = false; + + switch (token) { + case DOMNode::OffsetHeight: + case DOMNode::OffsetWidth: + needViewport = quirksMode; + break; + case DOMNode::ClientHeight: + case DOMNode::ClientWidth: + needViewport = true; + break; + } + + if (needViewport) { + //Scan up to find the new target + while (rend->parent()) + rend = rend->parent(); + } + return rend; +} + +Value DOMNode::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case NodeName: + return String(node.nodeName()); + case NodeValue: + return getString(node.nodeValue()); // initially null, per domts/level1/core/hc_documentcreateelement.html + case NodeType: + return Number((unsigned int)node.nodeType()); + case ParentNode: + return getDOMNode(exec,node.parentNode()); + case ParentElement: // IE only apparently + return getDOMNode(exec,node.parentNode()); + case ChildNodes: + return getDOMNodeList(exec,node.childNodes()); + case FirstChild: + return getDOMNode(exec,node.firstChild()); + case LastChild: + return getDOMNode(exec,node.lastChild()); + case PreviousSibling: + return getDOMNode(exec,node.previousSibling()); + case NextSibling: + return getDOMNode(exec,node.nextSibling()); + case Attributes: + return getDOMNamedNodeMap(exec,node.attributes()); + case NamespaceURI: + return getString(node.namespaceURI()); // Moz returns null if not set (dom/namespaces.html) + case Prefix: + return getString(node.prefix()); // Moz returns null if not set (dom/namespaces.html) + case TextContent: + return getString(node.textContent()); //DOM3 says return null, but I really should test mozilla.. + case LocalName: + return getString(node.localName()); // Moz returns null if not set (dom/namespaces.html) + case OwnerDocument: + return getDOMNode(exec,node.ownerDocument()); + case OnAbort: + return getListener(DOM::EventImpl::ABORT_EVENT); + case OnBlur: + return getListener(DOM::EventImpl::BLUR_EVENT); + case OnChange: + return getListener(DOM::EventImpl::CHANGE_EVENT); + case OnClick: + return getListener(DOM::EventImpl::KHTML_ECMA_CLICK_EVENT); + case OnDblClick: + return getListener(DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT); + case OnDragDrop: + return getListener(DOM::EventImpl::KHTML_DRAGDROP_EVENT); + case OnError: + return getListener(DOM::EventImpl::ERROR_EVENT); + case OnFocus: + return getListener(DOM::EventImpl::FOCUS_EVENT); + case OnKeyDown: + return getListener(DOM::EventImpl::KEYDOWN_EVENT); + case OnKeyPress: + return getListener(DOM::EventImpl::KEYPRESS_EVENT); + case OnKeyUp: + return getListener(DOM::EventImpl::KEYUP_EVENT); + case OnLoad: + return getListener(DOM::EventImpl::LOAD_EVENT); + case OnMouseDown: + return getListener(DOM::EventImpl::MOUSEDOWN_EVENT); + case OnMouseMove: + return getListener(DOM::EventImpl::MOUSEMOVE_EVENT); + case OnMouseOut: + return getListener(DOM::EventImpl::MOUSEOUT_EVENT); + case OnMouseOver: + return getListener(DOM::EventImpl::MOUSEOVER_EVENT); + case OnMouseUp: + return getListener(DOM::EventImpl::MOUSEUP_EVENT); + case OnMove: + return getListener(DOM::EventImpl::KHTML_MOVE_EVENT); + case OnReset: + return getListener(DOM::EventImpl::RESET_EVENT); + case OnResize: + return getListener(DOM::EventImpl::RESIZE_EVENT); + case OnSelect: + return getListener(DOM::EventImpl::SELECT_EVENT); + case OnSubmit: + return getListener(DOM::EventImpl::SUBMIT_EVENT); + case OnUnload: + return getListener(DOM::EventImpl::UNLOAD_EVENT); + case SourceIndex: { + // Retrieves the ordinal position of the object, in source order, as the object + // appears in the document's all collection + // i.e. document.all[n.sourceIndex] == n + DOM::Document doc = node.ownerDocument(); + if (doc.isHTMLDocument()) { + DOM::HTMLCollection all = static_cast<DOM::HTMLDocument>(doc).all(); + unsigned long i = 0; + DOM::Node n = all.firstItem(); + for ( ; !n.isNull() && n != node; n = all.nextItem() ) + ++i; + Q_ASSERT( !n.isNull() ); // node not in document.all !? + return Number(i); + } + } + default: + // no DOM standard, found in IE only + + // Make sure our layout is up to date before we allow a query on these attributes. + DOM::DocumentImpl* docimpl = node.handle()->getDocument(); + if (docimpl) { + docimpl->updateLayout(); + } + + khtml::RenderObject *rend = node.handle()->renderer(); + + //In quirks mode, may need to forward if to body. + rend = handleBodyRootQuirk(node, rend, token); + + switch (token) { + case OffsetLeft: + return rend ? static_cast<Value>( Number( rend->offsetLeft() ) ) : Undefined(); + case OffsetTop: + return rend ? static_cast<Value>( Number( rend->offsetTop() ) ) : Undefined(); + case OffsetWidth: + return rend ? static_cast<Value>( Number( rend->offsetWidth() ) ) : Undefined(); + case OffsetHeight: + return rend ? static_cast<Value>( Number( rend->offsetHeight() ) ) : Undefined(); + case OffsetParent: + { + khtml::RenderObject* par = rend ? rend->offsetParent() : 0; + return getDOMNode( exec, par ? par->element() : 0 ); + } + case ClientWidth: + return rend ? static_cast<Value>( Number( rend->clientWidth() ) ) : Undefined(); + case ClientHeight: + return rend ? static_cast<Value>( Number( rend->clientHeight() ) ) : Undefined(); + case ScrollWidth: + return rend ? static_cast<Value>( Number(rend->scrollWidth()) ) : Undefined(); + case ScrollHeight: + return rend ? static_cast<Value>( Number(rend->scrollHeight()) ) : Undefined(); + case ScrollLeft: + if (rend && rend->layer()) { + if (rend->isRoot() && !rend->style()->hidesOverflow()) + return Number( node.ownerDocument().view() ? node.ownerDocument().view()->contentsX() : 0); + return Number( rend->layer()->scrollXOffset() ); + } + return Number( 0 ); + case ScrollTop: + if (rend && rend->layer()) { + if (rend->isRoot() && !rend->style()->hidesOverflow()) + return Number( node.ownerDocument().view() ? node.ownerDocument().view()->contentsY() : 0); + return Number( rend->layer()->scrollYOffset() ); + } + return Number( 0 ); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMNode::getValueProperty : " << token << endl; + break; + } + } + return Undefined(); +} + + +void DOMNode::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMNode::tryPut " << propertyName.qstring() << endl; +#endif + DOMObjectLookupPut<DOMNode,DOMObject>(exec, propertyName, value, attr, + &DOMNodeTable, this ); +} + +void DOMNode::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/) +{ + switch (token) { + case NodeValue: + node.setNodeValue(value.toString(exec).string()); + break; + case Prefix: + node.setPrefix(value.toString(exec).string()); + break; + case TextContent: + node.setTextContent(value.toString(exec).string()); + break; + case OnAbort: + setListener(exec,DOM::EventImpl::ABORT_EVENT,value); + break; + case OnBlur: + setListener(exec,DOM::EventImpl::BLUR_EVENT,value); + break; + case OnChange: + setListener(exec,DOM::EventImpl::CHANGE_EVENT,value); + break; + case OnClick: + setListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT,value); + break; + case OnDblClick: + setListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT,value); + break; + case OnDragDrop: + setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value); + break; + case OnError: + setListener(exec,DOM::EventImpl::ERROR_EVENT,value); + break; + case OnFocus: + setListener(exec,DOM::EventImpl::FOCUS_EVENT,value); + break; + case OnKeyDown: + setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value); + break; + case OnKeyPress: + setListener(exec,DOM::EventImpl::KEYPRESS_EVENT,value); + break; + case OnKeyUp: + setListener(exec,DOM::EventImpl::KEYUP_EVENT,value); + break; + case OnLoad: + setListener(exec,DOM::EventImpl::LOAD_EVENT,value); + break; + case OnMouseDown: + setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value); + break; + case OnMouseMove: + setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value); + break; + case OnMouseOut: + setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value); + break; + case OnMouseOver: + setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value); + break; + case OnMouseUp: + setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value); + break; + case OnMove: + setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value); + break; + case OnReset: + setListener(exec,DOM::EventImpl::RESET_EVENT,value); + break; + case OnResize: + setListener(exec,DOM::EventImpl::RESIZE_EVENT,value); + break; + case OnSelect: + setListener(exec,DOM::EventImpl::SELECT_EVENT,value); + break; + case OnSubmit: + setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value); + break; + case OnUnload: + setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value); + break; + default: + // Make sure our layout is up to date + DOM::DocumentImpl* docimpl = node.handle()->getDocument(); + if (docimpl) + docimpl->updateLayout(); + + khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L; + + //In quirks mode, may need to forward. + rend = handleBodyRootQuirk(node, rend, token); + + switch (token) { + case ScrollLeft: + if (rend && rend->layer()) { + if (rend->style()->hidesOverflow()) + rend->layer()->scrollToXOffset(value.toInt32(exec)); + else if (rend->isRoot()) { + QScrollView* sview = node.ownerDocument().view(); + if (sview) + sview->setContentsPos(value.toInt32(exec), sview->contentsY()); + } + } + break; + case ScrollTop: + if (rend && rend->layer()) { + if (rend->style()->hidesOverflow()) + rend->layer()->scrollToYOffset(value.toInt32(exec)); + else if (rend->isRoot()) { + QScrollView* sview = node.ownerDocument().view(); + if (sview) + sview->setContentsPos(sview->contentsX(), value.toInt32(exec)); + } + } + break; + default: + kdDebug(6070) << "WARNING: DOMNode::putValueProperty unhandled token " << token << endl; + } + } +} + +Value DOMNode::toPrimitive(ExecState *exec, Type /*preferred*/) const +{ + if (node.isNull()) + return Null(); + + return String(toString(exec)); +} + +UString DOMNode::toString(ExecState *) const +{ + if (node.isNull()) + return "null"; + UString s; + + DOM::Element e = node; + if ( !e.isNull() ) { + s = e.nodeName().string(); + } else + s = className(); // fallback + + return "[object " + s + "]"; +} + +void DOMNode::setListener(ExecState *exec, int eventId, const Value& func) const +{ + node.handle()->setHTMLEventListener(eventId,Window::retrieveActive(exec)->getJSEventListener(func,true)); +} + +Value DOMNode::getListener(int eventId) const +{ + DOM::EventListener *listener = node.handle()->getHTMLEventListener(eventId); + JSEventListener *jsListener = static_cast<JSEventListener*>(listener); + if ( jsListener && jsListener->listenerObjImp() ) + return jsListener->listenerObj(); + else + return Null(); +} + +void DOMNode::pushEventHandlerScope(ExecState *, ScopeChain &) const +{ +} + +Value DOMNodeProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( DOMNode, thisObj ); + DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode(); + switch (id) { + case DOMNode::HasAttributes: + return Boolean(node.hasAttributes()); + case DOMNode::HasChildNodes: + return Boolean(node.hasChildNodes()); + case DOMNode::CloneNode: + return getDOMNode(exec,node.cloneNode(args[0].toBoolean(exec))); + case DOMNode::Normalize: + node.normalize(); + return Undefined(); + case DOMNode::IsSupported: + return Boolean(node.isSupported(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMNode::AddEventListener: { + JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); + node.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); + return Undefined(); + } + case DOMNode::RemoveEventListener: { + JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); + node.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec)); + return Undefined(); + } + case DOMNode::DispatchEvent: + return Boolean(node.dispatchEvent(toEvent(args[0]))); + case DOMNode::AppendChild: + return getDOMNode(exec,node.appendChild(toNode(args[0]))); + case DOMNode::RemoveChild: + return getDOMNode(exec,node.removeChild(toNode(args[0]))); + case DOMNode::InsertBefore: + return getDOMNode(exec,node.insertBefore(toNode(args[0]), toNode(args[1]))); + case DOMNode::ReplaceChild: + return getDOMNode(exec,node.replaceChild(toNode(args[0]), toNode(args[1]))); + case DOMNode::Contains: + { + DOM::Node other = toNode(args[0]); + if (!other.isNull() && node.nodeType()==DOM::Node::ELEMENT_NODE) + { + DOM::NodeBaseImpl *impl = static_cast<DOM::NodeBaseImpl *>(node.handle()); + bool retval = other.handle()->isAncestor(impl); + return Boolean(retval); + } + return Undefined(); + } + case DOMNode::InsertAdjacentHTML: + { + // see http://www.faqts.com/knowledge_base/view.phtml/aid/5756 + // and http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertAdjacentHTML.asp + Range range = node.ownerDocument().createRange(); + + range.setStartBefore(node); + + DocumentFragment docFrag = range.createContextualFragment(args[1].toString(exec).string()); + + DOMString where = args[0].toString(exec).string(); + + if (where == "beforeBegin" || where == "BeforeBegin") + node.parentNode().insertBefore(docFrag, node); + else if (where == "afterBegin" || where == "AfterBegin") + node.insertBefore(docFrag, node.firstChild()); + else if (where == "beforeEnd" || where == "BeforeEnd") + return getDOMNode(exec, node.appendChild(docFrag)); + else if (where == "afterEnd" || where == "AfterEnd") + if (!node.nextSibling().isNull()) + node.parentNode().insertBefore(docFrag, node.nextSibling()); + else + node.parentNode().appendChild(docFrag); + + return Undefined(); + } + case DOMNode::Item: + return getDOMNode(exec, node.childNodes().item(static_cast<unsigned long>(args[0].toNumber(exec)))); + } + + return Undefined(); +} + +// ------------------------------------------------------------------------- + +/* +@begin DOMNodeListProtoTable 2 + item DOMNodeList::Item DontDelete|Function 1 +# IE extension (IE treats DOMNodeList like an HTMLCollection) + namedItem DOMNodeList::NamedItem DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMNodeListProto) +IMPLEMENT_PROTOFUNC_DOM(DOMNodeListProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMNodeList", DOMNodeListProto, DOMNodeListProtoFunc) + + +const ClassInfo DOMNodeList::info = { "NodeList", 0, 0, 0 }; + +DOMNodeList::DOMNodeList(ExecState *exec, const DOM::NodeList& l) + : DOMObject(DOMNodeListProto::self(exec)), list(l) { } + +DOMNodeList::~DOMNodeList() +{ + ScriptInterpreter::forgetDOMObject(list.handle()); +} + +// We have to implement hasProperty since we don't use a hashtable for 'length' +// ## this breaks "for (..in..)" though. +bool DOMNodeList::hasProperty(ExecState *exec, const Identifier &p) const +{ + if (p == lengthPropertyName) + return true; + + if (ObjectImp::hasProperty(exec, p)) + return true; + + bool ok; + unsigned long pos = p.toULong(&ok); + if (ok && pos < list.length()) + return true; + + // ## missing: accept p if item id... + return false; +} + +Value DOMNodeList::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMNodeList::tryGet " << p.ascii() << endl; +#endif + if (p == lengthPropertyName) + return Number(list.length()); + + // Look in the prototype (for functions) before assuming it's an item's name + Object proto = Object::dynamicCast(prototype()); + if (proto.isValid() && proto.hasProperty(exec,p)) + return proto.get(exec,p); + + Value result; + + // array index ? + bool ok; + long unsigned int idx = p.toULong(&ok); + if (ok) + result = getDOMNode(exec,list.item(idx)); + else { + // Find by ID + DOM::HTMLElement e; + unsigned long l = list.length(); + bool found = false; + + for ( unsigned long i = 0; i < l; i++ ) + if ( ( e = list.item( i ) ).id() == p.string() ) { + result = getDOMNode(exec, list.item( i ) ); + found = true; + break; + } + + if ( !found ) + result = ObjectImp::get(exec, p); + } + + return result; +} + +ReferenceList DOMNodeList::propList(ExecState *exec, bool recursive) +{ + ReferenceList properties = ObjectImp::propList(exec,recursive); + + for (unsigned i = 0; i < list.length(); ++i) { + if (!ObjectImp::hasProperty(exec,Identifier::from(i))) { + properties.append(Reference(this, i)); + } + } + + if (!ObjectImp::hasProperty(exec, lengthPropertyName)) + properties.append(Reference(this, lengthPropertyName)); + + return properties; +} + +// Need to support both get and call, so that list[0] and list(0) work. +Value DOMNodeList::call(ExecState *exec, Object &thisObj, const List &args) +{ + // This code duplication is necessary, DOMNodeList isn't a DOMFunction + Value val; + try { + val = tryCall(exec, thisObj, args); + } + // pity there's no way to distinguish between these in JS code + catch (...) { + Object err = Error::create(exec, GeneralError, "Exception from DOMNodeList"); + exec->setException(err); + } + return val; +} + +Value DOMNodeList::tryCall(ExecState *exec, Object &, const List &args) +{ + // Do not use thisObj here. See HTMLCollection. + UString s = args[0].toString(exec); + + // index-based lookup? + bool ok; + unsigned int u = s.toULong(&ok); + if (ok) + return getDOMNode(exec,list.item(u)); + + // try lookup by name + // ### NodeList::namedItem() would be cool to have + // ### do we need to support the same two arg overload as in HTMLCollection? + Value result = tryGet(exec, Identifier(s)); + + if (result.isValid()) + return result; + + return Undefined(); +} + +// Not a prototype class currently, but should probably be converted to one +Value DOMNodeListProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMNodeList, thisObj ); + DOM::NodeList list = static_cast<DOMNodeList *>(thisObj.imp())->nodeList(); + switch (id) { + case KJS::DOMNodeList::Item: + return getDOMNode(exec, list.item(args[0].toInt32(exec))); + case KJS::DOMNodeList::NamedItem: + { + // Not a real namedItem implementation like the one HTMLCollection has. + // This is only an IE extension... + DOM::HTMLElement e; + unsigned long len = list.length(); + DOM::DOMString s = args[0].toString(exec).string(); + + for ( unsigned long i = 0; i < len; i++ ) + { + e = list.item( i ); + if ( !e.isNull() && ( + e.id() == s || static_cast<ElementImpl *>(e.handle())->getAttribute(ATTR_NAME) == s ) + ) + { + return getDOMNode(exec, e ); + } + } + return Null(); // see HTMLCollection::NamedItem implementation + } + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +//### FIXME: link to the node prototype. +const ClassInfo DOMAttr::info = { "Attr", &DOMNode::info, &DOMAttrTable, 0 }; + +/* Source for DOMAttrTable. +@begin DOMAttrTable 5 + name DOMAttr::Name DontDelete|ReadOnly + specified DOMAttr::Specified DontDelete|ReadOnly + value DOMAttr::ValueProperty DontDelete + ownerElement DOMAttr::OwnerElement DontDelete|ReadOnly +@end +*/ +Value DOMAttr::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMAttr::tryGet " << propertyName.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMAttr,DOMNode>(exec, propertyName, + &DOMAttrTable, this ); +} + +Value DOMAttr::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Name: + return String(static_cast<DOM::Attr>(node).name()); + case Specified: + return Boolean(static_cast<DOM::Attr>(node).specified()); + case ValueProperty: + return String(static_cast<DOM::Attr>(node).value()); + case OwnerElement: // DOM2 + return getDOMNode(exec,static_cast<DOM::Attr>(node).ownerElement()); + } + return Value(); // not reached +} + +void DOMAttr::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl; +#endif + DOMObjectLookupPut<DOMAttr,DOMNode>(exec, propertyName, value, attr, + &DOMAttrTable, this ); +} + +void DOMAttr::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/) +{ + switch (token) { + case ValueProperty: + static_cast<DOM::Attr>(node).setValue(value.toString(exec).string()); + return; + default: + kdDebug(6070) << "WARNING: DOMAttr::putValueProperty unhandled token " << token << endl; + } +} + +// ------------------------------------------------------------------------- + +/* Source for DOMDocumentProtoTable. +@begin DOMDocumentProtoTable 23 + createElement DOMDocument::CreateElement DontDelete|Function 1 + createDocumentFragment DOMDocument::CreateDocumentFragment DontDelete|Function 1 + createTextNode DOMDocument::CreateTextNode DontDelete|Function 1 + createComment DOMDocument::CreateComment DontDelete|Function 1 + createCDATASection DOMDocument::CreateCDATASection DontDelete|Function 1 + createProcessingInstruction DOMDocument::CreateProcessingInstruction DontDelete|Function 1 + createAttribute DOMDocument::CreateAttribute DontDelete|Function 1 + createEntityReference DOMDocument::CreateEntityReference DontDelete|Function 1 + getElementsByTagName DOMDocument::GetElementsByTagName DontDelete|Function 1 + importNode DOMDocument::ImportNode DontDelete|Function 2 + createElementNS DOMDocument::CreateElementNS DontDelete|Function 2 + createAttributeNS DOMDocument::CreateAttributeNS DontDelete|Function 2 + getElementsByTagNameNS DOMDocument::GetElementsByTagNameNS DontDelete|Function 2 + getElementById DOMDocument::GetElementById DontDelete|Function 1 + createRange DOMDocument::CreateRange DontDelete|Function 0 + createNodeIterator DOMDocument::CreateNodeIterator DontDelete|Function 3 + createTreeWalker DOMDocument::CreateTreeWalker DontDelete|Function 4 + createEvent DOMDocument::CreateEvent DontDelete|Function 1 + getOverrideStyle DOMDocument::GetOverrideStyle DontDelete|Function 2 + abort DOMDocument::Abort DontDelete|Function 0 + load DOMDocument::Load DontDelete|Function 1 + loadXML DOMDocument::LoadXML DontDelete|Function 2 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMDocumentProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMDocument", DOMDocumentProto, DOMDocumentProtoFunc) +IMPLEMENT_PSEUDO_CONSTRUCTOR(DocumentPseudoCtor, "Document", DOMDocumentProto) + +const ClassInfo DOMDocument::info = { "Document", &DOMNode::info, &DOMDocumentTable, 0 }; + +/* Source for DOMDocumentTable. +@begin DOMDocumentTable 4 + doctype DOMDocument::DocType DontDelete|ReadOnly + implementation DOMDocument::Implementation DontDelete|ReadOnly + characterSet DOMDocument::CharacterSet DontDelete|ReadOnly + documentElement DOMDocument::DocumentElement DontDelete|ReadOnly + styleSheets DOMDocument::StyleSheets DontDelete|ReadOnly + preferredStylesheetSet DOMDocument::PreferredStylesheetSet DontDelete|ReadOnly + selectedStylesheetSet DOMDocument::SelectedStylesheetSet DontDelete + readyState DOMDocument::ReadyState DontDelete|ReadOnly + defaultView DOMDocument::DefaultView DontDelete|ReadOnly + async DOMDocument::Async DontDelete +@end +*/ + +DOMDocument::DOMDocument(ExecState *exec, const DOM::Document& d) + : DOMNode(DOMDocumentProto::self(exec), d) { } + +DOMDocument::DOMDocument(const Object& proto, const DOM::Document& d) + : DOMNode(proto, d) { } + +DOMDocument::~DOMDocument() +{ + ScriptInterpreter::forgetDOMObject(node.handle()); +} + +Value DOMDocument::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMDocument::tryGet " << propertyName.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMDocument, DOMNode>( + exec, propertyName, &DOMDocumentTable, this); +} + +Value DOMDocument::getValueProperty(ExecState *exec, int token) const +{ + DOM::Document doc = static_cast<DOM::Document>(node); + + switch(token) { + case DocType: + return getDOMNode(exec,doc.doctype()); + case Implementation: + return getDOMDOMImplementation(exec,doc.implementation()); + case DocumentElement: + return getDOMNode(exec,doc.documentElement()); + case CharacterSet: { + DOM::DocumentImpl* docImpl = static_cast<DOM::DocumentImpl*>(doc.handle()); + if (docImpl->part()) + return String(docImpl->part()->encoding()); + else + return Undefined(); + } + case StyleSheets: + //kdDebug() << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets" << endl; + return getDOMStyleSheetList(exec, doc.styleSheets(), doc); + case DOMDocument::DefaultView: // DOM2 + { + KHTMLView *view = node.handle()->getDocument()->view(); + if (view) + return Window::retrieve(view->part()); + return getDOMAbstractView(exec, doc.defaultView()); + } + case PreferredStylesheetSet: + return String(doc.preferredStylesheetSet()); + case SelectedStylesheetSet: + return String(doc.selectedStylesheetSet()); + case ReadyState: + { + DOM::DocumentImpl* docimpl = node.handle()->getDocument(); + if ( docimpl && docimpl->view() ) + { + KHTMLPart* part = docimpl->view()->part(); + if ( part ) { + if (part->d->m_bComplete) return String("complete"); + if (docimpl->parsing()) return String("loading"); + return String("loaded"); + // What does the interactive value mean ? + // Missing support for "uninitialized" + } + } + return Undefined(); + } + case Async: + return Boolean(doc.async()); + default: + kdDebug(6070) << "WARNING: DOMDocument::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +void DOMDocument::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMDocument::tryPut " << propertyName.qstring() << endl; +#endif + DOMObjectLookupPut<DOMDocument,DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this ); +} + +void DOMDocument::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/) +{ + DOM::Document doc = static_cast<DOM::Document>(node); + switch (token) { + case SelectedStylesheetSet: { + doc.setSelectedStylesheetSet(value.toString(exec).string()); + break; + } + case Async: { + doc.setAsync(value.toBoolean(exec)); + break; + } + } +} + +Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMDocument, thisObj ); + DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode(); + DOM::Document doc = static_cast<DOM::Document>(node); + String str = args[0].toString(exec); + DOM::DOMString s = str.value().string(); + + switch(id) { + case DOMDocument::CreateElement: + return getDOMNode(exec,doc.createElement(s)); + case DOMDocument::CreateDocumentFragment: + return getDOMNode(exec,doc.createDocumentFragment()); + case DOMDocument::CreateTextNode: + return getDOMNode(exec,doc.createTextNode(s)); + case DOMDocument::CreateComment: + return getDOMNode(exec,doc.createComment(s)); + case DOMDocument::CreateCDATASection: + return getDOMNode(exec,doc.createCDATASection(s)); /* TODO: okay ? */ + case DOMDocument::CreateProcessingInstruction: + return getDOMNode(exec,doc.createProcessingInstruction(args[0].toString(exec).string(), + args[1].toString(exec).string())); + case DOMDocument::CreateAttribute: + return getDOMNode(exec,doc.createAttribute(s)); + case DOMDocument::CreateEntityReference: + return getDOMNode(exec,doc.createEntityReference(args[0].toString(exec).string())); + case DOMDocument::GetElementsByTagName: + return getDOMNodeList(exec,doc.getElementsByTagName(s)); + case DOMDocument::ImportNode: // DOM2 + return getDOMNode(exec,doc.importNode(toNode(args[0]), args[1].toBoolean(exec))); + case DOMDocument::CreateElementNS: // DOM2 + return getDOMNode(exec,doc.createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string())); + case DOMDocument::CreateAttributeNS: // DOM2 + return getDOMNode(exec,doc.createAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMDocument::GetElementsByTagNameNS: // DOM2 + return getDOMNodeList(exec,doc.getElementsByTagNameNS(args[0].toString(exec).string(), + args[1].toString(exec).string())); + case DOMDocument::GetElementById: +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMDocument::GetElementById looking for " << args[0].toString(exec).string() << endl; +#endif + return getDOMNode(exec,doc.getElementById(args[0].toString(exec).string())); + case DOMDocument::CreateRange: + return getDOMRange(exec,doc.createRange()); + case DOMDocument::CreateNodeIterator: + if (args[2].isA(NullType)) { + DOM::NodeFilter filter; + return getDOMNodeIterator(exec, + doc.createNodeIterator(toNode(args[0]), + (long unsigned int)(args[1].toNumber(exec)), + filter,args[3].toBoolean(exec))); + } + else { + Object obj = Object::dynamicCast(args[2]); + if (obj.isValid()) + { + DOM::CustomNodeFilter *customFilter = new JSNodeFilter(obj); + DOM::NodeFilter filter = DOM::NodeFilter::createCustom(customFilter); + return getDOMNodeIterator(exec, + doc.createNodeIterator( + toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)), + filter,args[3].toBoolean(exec))); + }// else? + } + case DOMDocument::CreateTreeWalker: + return getDOMTreeWalker(exec,doc.createTreeWalker(toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)), + toNodeFilter(args[2]),args[3].toBoolean(exec))); + case DOMDocument::CreateEvent: + return getDOMEvent(exec,doc.createEvent(s)); + case DOMDocument::GetOverrideStyle: { + DOM::Node arg0 = toNode(args[0]); + if (arg0.nodeType() != DOM::Node::ELEMENT_NODE) + return Undefined(); // throw exception? + else + return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string())); + } + case DOMDocument::Abort: + doc.abort(); + break; + case DOMDocument::Load: { + Window* active = Window::retrieveActive(exec); + // Complete the URL using the "active part" (running interpreter). We do this for the security + // check and to make sure we load exactly the same url as we have verified to be safe + KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart *>(active->part()); + if (khtmlpart) { + // Security: only allow documents to be loaded from the same host + QString dstUrl = khtmlpart->htmlDocument().completeURL(s).string(); + KParts::ReadOnlyPart *part = static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part(); + if (part->url().host() == KURL(dstUrl).host()) { + kdDebug(6070) << "JavaScript: access granted for document.load() of " << dstUrl << endl; + doc.load(dstUrl); + } + else { + kdDebug(6070) << "JavaScript: access denied for document.load() of " << dstUrl << endl; + } + } + break; + } + case DOMDocument::LoadXML: + doc.loadXML(s); + break; + default: + break; + } + + return Undefined(); +} + +// ------------------------------------------------------------------------- + +/* Source for DOMElementProtoTable. +@begin DOMElementProtoTable 17 + getAttribute DOMElement::GetAttribute DontDelete|Function 1 + setAttribute DOMElement::SetAttribute DontDelete|Function 2 + removeAttribute DOMElement::RemoveAttribute DontDelete|Function 1 + getAttributeNode DOMElement::GetAttributeNode DontDelete|Function 1 + setAttributeNode DOMElement::SetAttributeNode DontDelete|Function 2 + removeAttributeNode DOMElement::RemoveAttributeNode DontDelete|Function 1 + getElementsByTagName DOMElement::GetElementsByTagName DontDelete|Function 1 + hasAttribute DOMElement::HasAttribute DontDelete|Function 1 + getAttributeNS DOMElement::GetAttributeNS DontDelete|Function 2 + setAttributeNS DOMElement::SetAttributeNS DontDelete|Function 3 + removeAttributeNS DOMElement::RemoveAttributeNS DontDelete|Function 2 + getAttributeNodeNS DOMElement::GetAttributeNodeNS DontDelete|Function 2 + setAttributeNodeNS DOMElement::SetAttributeNodeNS DontDelete|Function 1 + getElementsByTagNameNS DOMElement::GetElementsByTagNameNS DontDelete|Function 2 + hasAttributeNS DOMElement::HasAttributeNS DontDelete|Function 2 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMElementProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMElement", DOMElementProto, DOMElementProtoFunc) + +IMPLEMENT_PSEUDO_CONSTRUCTOR(ElementPseudoCtor, "Element", DOMElementProto) + +const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 }; +/* Source for DOMElementTable. +@begin DOMElementTable 3 + tagName DOMElement::TagName DontDelete|ReadOnly + style DOMElement::Style DontDelete|ReadOnly +@end +*/ +DOMElement::DOMElement(ExecState *exec, const DOM::Element& e) + : DOMNode(DOMElementProto::self(exec), e) { } + +DOMElement::DOMElement(const Object& proto, const DOM::Element& e) + : DOMNode(proto, e) { } + +Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl; +#endif + DOM::Element element = static_cast<DOM::Element>(node); + + const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName); + if (entry) + { + switch( entry->value ) { + case TagName: + return String(element.tagName()); + case Style: + return getDOMCSSStyleDeclaration(exec,element.style()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMElement::tryGet : " << entry->value << endl; + break; + } + } + // We have to check in DOMNode before giving access to attributes, otherwise + // onload="..." would make onload return the string (attribute value) instead of + // the listener object (function). + if (DOMNode::hasProperty(exec, propertyName)) + return DOMNode::tryGet(exec, propertyName); + + DOM::DOMString attr = element.getAttribute( propertyName.string() ); + // Give access to attributes + if ( !attr.isNull() ) + return String( attr ); + + return Undefined(); +} + +Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMNode, thisObj ); // node should be enough here, given the cast + DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode(); + DOM::Element element = static_cast<DOM::Element>(node); + + switch(id) { + case DOMElement::GetAttribute: + /** In theory, we should not return null here, as per DOM. In practice, that + breaks websites + */ + return getString(element.getAttribute(args[0].toString(exec).string())); + case DOMElement::SetAttribute: + element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string()); + return Undefined(); + case DOMElement::RemoveAttribute: + element.removeAttribute(args[0].toString(exec).string()); + return Undefined(); + case DOMElement::GetAttributeNode: + return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string())); + case DOMElement::SetAttributeNode: + return getDOMNode(exec,element.setAttributeNode(KJS::toNode(args[0]))); + case DOMElement::RemoveAttributeNode: + return getDOMNode(exec,element.removeAttributeNode(KJS::toNode(args[0]))); + case DOMElement::GetElementsByTagName: + return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string())); + case DOMElement::HasAttribute: // DOM2 + return Boolean(element.hasAttribute(args[0].toString(exec).string())); + case DOMElement::GetAttributeNS: // DOM2 + return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMElement::SetAttributeNS: // DOM2 + element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()); + return Undefined(); + case DOMElement::RemoveAttributeNS: // DOM2 + element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()); + return Undefined(); + case DOMElement::GetAttributeNodeNS: // DOM2 + return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMElement::SetAttributeNodeNS: // DOM2 + return getDOMNode(exec,element.setAttributeNodeNS(KJS::toNode(args[0]))); + case DOMElement::GetElementsByTagNameNS: // DOM2 + return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMElement::HasAttributeNS: // DOM2 + return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- + +/* Source for DOMDOMImplementationProtoTable. +@begin DOMDOMImplementationProtoTable 5 + hasFeature DOMDOMImplementation::HasFeature DontDelete|Function 2 + createCSSStyleSheet DOMDOMImplementation::CreateCSSStyleSheet DontDelete|Function 2 +# DOM2 + createDocumentType DOMDOMImplementation::CreateDocumentType DontDelete|Function 3 + createDocument DOMDOMImplementation::CreateDocument DontDelete|Function 3 + createHTMLDocument DOMDOMImplementation::CreateHTMLDocument DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMDOMImplementationProto) +IMPLEMENT_PROTOFUNC_DOM(DOMDOMImplementationProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMImplementation", DOMDOMImplementationProto, DOMDOMImplementationProtoFunc) + +const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 }; + +DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i) + : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { } + +DOMDOMImplementation::~DOMDOMImplementation() +{ + ScriptInterpreter::forgetDOMObject(implementation.handle()); +} + +Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMDOMImplementation, thisObj ); + DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation(); + + switch(id) { + case DOMDOMImplementation::HasFeature: + return Boolean(implementation.hasFeature(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMDOMImplementation::CreateDocumentType: // DOM2 + return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string())); + case DOMDOMImplementation::CreateDocument: { // DOM2 + // Initially set the URL to document of the creator... this is so that it resides in the same + // host/domain for security checks. The URL will be updated if Document.load() is called. + KHTMLPart *part = ::qt_cast<KHTMLPart*>(static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part()); + if (part) { + Document doc = implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2])); + KURL url = static_cast<DocumentImpl*>(part->document().handle())->URL(); + static_cast<DocumentImpl*>(doc.handle())->setURL(url.url()); + return getDOMNode(exec,doc); + } + break; + } + case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2 + return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML + return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string())); + default: + break; + } + return Undefined(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 }; + +/* Source for DOMDocumentTypeTable. +@begin DOMDocumentTypeTable 6 + name DOMDocumentType::Name DontDelete|ReadOnly + entities DOMDocumentType::Entities DontDelete|ReadOnly + notations DOMDocumentType::Notations DontDelete|ReadOnly +# DOM2 + publicId DOMDocumentType::PublicId DontDelete|ReadOnly + systemId DOMDocumentType::SystemId DontDelete|ReadOnly + internalSubset DOMDocumentType::InternalSubset DontDelete|ReadOnly +@end +*/ +DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType& dt) + : DOMNode( /*### no proto yet*/exec, dt ) { } + +Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMDocumentType::tryGet " << propertyName.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this); +} + +Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const +{ + DOM::DocumentType type = static_cast<DOM::DocumentType>(node); + switch (token) { + case Name: + return String(type.name()); + case Entities: + return getDOMNamedNodeMap(exec,type.entities()); + case Notations: + return getDOMNamedNodeMap(exec,type.notations()); + case PublicId: // DOM2 + return String(type.publicId()); + case SystemId: // DOM2 + return String(type.systemId()); + case InternalSubset: // DOM2 + return getString(type.internalSubset()); // can be null, see domts/level2/core/internalSubset01.html + default: + kdDebug(6070) << "WARNING: DOMDocumentType::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +// ------------------------------------------------------------------------- + +/* Source for DOMNamedNodeMapProtoTable. +@begin DOMNamedNodeMapProtoTable 7 + getNamedItem DOMNamedNodeMap::GetNamedItem DontDelete|Function 1 + setNamedItem DOMNamedNodeMap::SetNamedItem DontDelete|Function 1 + removeNamedItem DOMNamedNodeMap::RemoveNamedItem DontDelete|Function 1 + item DOMNamedNodeMap::Item DontDelete|Function 1 +# DOM2 + getNamedItemNS DOMNamedNodeMap::GetNamedItemNS DontDelete|Function 2 + setNamedItemNS DOMNamedNodeMap::SetNamedItemNS DontDelete|Function 1 + removeNamedItemNS DOMNamedNodeMap::RemoveNamedItemNS DontDelete|Function 2 +@end +@begin DOMNamedNodeMapTable 7 + length DOMNamedNodeMap::Length DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMNamedNodeMapProto) +IMPLEMENT_PROTOFUNC_DOM(DOMNamedNodeMapProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto, DOMNamedNodeMapProtoFunc) + +const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, &DOMNamedNodeMapTable, 0 }; + +DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m) + : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { } + +DOMNamedNodeMap::~DOMNamedNodeMap() +{ + ScriptInterpreter::forgetDOMObject(map.handle()); +} + +bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const +{ + // ## missing? array index + return DOMObject::hasProperty(exec, p); +} + +Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const +{ + if (p == lengthPropertyName) + return Number(map.length()); + + // array index ? + bool ok; + long unsigned int idx = p.toULong(&ok); + if (ok) + return getDOMNode(exec,map.item(idx)); + + // Anything else (including functions, defined in the prototype) + return DOMObject::tryGet(exec, p); +} + +Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMNamedNodeMap, thisObj ); + DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap(); + + switch(id) { + case DOMNamedNodeMap::GetNamedItem: + return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string())); + case DOMNamedNodeMap::SetNamedItem: + return getDOMNode(exec, map.setNamedItem(KJS::toNode(args[0]))); + case DOMNamedNodeMap::RemoveNamedItem: + return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string())); + case DOMNamedNodeMap::Item: + return getDOMNode(exec, map.item(args[0].toInt32(exec))); + case DOMNamedNodeMap::GetNamedItemNS: // DOM2 + return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + case DOMNamedNodeMap::SetNamedItemNS: // DOM2 + return getDOMNode(exec, map.setNamedItemNS(toNode(args[0]))); + case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2 + return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string())); + default: + break; + } + + return Undefined(); +} + +// ------------------------------------------------------------------------- +//### FIXME: proto +const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 }; + +/* Source for DOMProcessingInstructionTable. +@begin DOMProcessingInstructionTable 3 + target DOMProcessingInstruction::Target DontDelete|ReadOnly + data DOMProcessingInstruction::Data DontDelete + sheet DOMProcessingInstruction::Sheet DontDelete|ReadOnly +@end +*/ +Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this); +} + +Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Target: + return String(static_cast<DOM::ProcessingInstruction>(node).target()); + case Data: + return String(static_cast<DOM::ProcessingInstruction>(node).data()); + case Sheet: + return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet()); + default: + kdDebug(6070) << "WARNING: DOMProcessingInstruction::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + // Not worth using the hashtable for this one ;) + if (propertyName == "data") + static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string()); + else + DOMNode::tryPut(exec, propertyName,value,attr); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 }; + +/* Source for DOMNotationTable. +@begin DOMNotationTable 2 + publicId DOMNotation::PublicId DontDelete|ReadOnly + systemId DOMNotation::SystemId DontDelete|ReadOnly +@end +*/ +Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this); +} + +Value DOMNotation::getValueProperty(ExecState *, int token) const +{ + switch (token) { + case PublicId: + return String(static_cast<DOM::Notation>(node).publicId()); + case SystemId: + return String(static_cast<DOM::Notation>(node).systemId()); + default: + kdDebug(6070) << "WARNING: DOMNotation::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 }; + +/* Source for DOMEntityTable. +@begin DOMEntityTable 2 + publicId DOMEntity::PublicId DontDelete|ReadOnly + systemId DOMEntity::SystemId DontDelete|ReadOnly + notationName DOMEntity::NotationName DontDelete|ReadOnly +@end +*/ +Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this); +} + +Value DOMEntity::getValueProperty(ExecState *, int token) const +{ + switch (token) { + case PublicId: + return String(static_cast<DOM::Entity>(node).publicId()); + case SystemId: + return String(static_cast<DOM::Entity>(node).systemId()); + case NotationName: + return String(static_cast<DOM::Entity>(node).notationName()); + default: + kdDebug(6070) << "WARNING: DOMEntity::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +// ------------------------------------------------------------------------- + +bool checkNodeSecurity(ExecState *exec, const DOM::Node& n) +{ + // Check to see if the currently executing interpreter is allowed to access the specified node + if (n.isNull()) + return true; + KHTMLView *view = n.handle()->getDocument()->view(); + Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L; + if ( !win || !win->isSafeScript(exec) ) + return false; + return true; +} + +Value getDOMNode(ExecState *exec, const DOM::Node& n) +{ + DOMObject *ret = 0; + if (n.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(n.handle()))) + return Value(ret); + + switch (n.nodeType()) { + case DOM::Node::ELEMENT_NODE: + if (static_cast<DOM::Element>(n).isHTMLElement()) + ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n)); + else + ret = new DOMElement(exec, static_cast<DOM::Element>(n)); + break; + case DOM::Node::ATTRIBUTE_NODE: + ret = new DOMAttr(exec, static_cast<DOM::Attr>(n)); + break; + case DOM::Node::TEXT_NODE: + case DOM::Node::CDATA_SECTION_NODE: + ret = new DOMText(exec, static_cast<DOM::Text>(n)); + break; + case DOM::Node::ENTITY_REFERENCE_NODE: + ret = new DOMNode(exec, n); + break; + case DOM::Node::ENTITY_NODE: + ret = new DOMEntity(exec, static_cast<DOM::Entity>(n)); + break; + case DOM::Node::PROCESSING_INSTRUCTION_NODE: + ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n)); + break; + case DOM::Node::COMMENT_NODE: + ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n)); + break; + case DOM::Node::DOCUMENT_NODE: + if (static_cast<DOM::Document>(n).isHTMLDocument()) + ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n)); + else + ret = new DOMDocument(exec, static_cast<DOM::Document>(n)); + break; + case DOM::Node::DOCUMENT_TYPE_NODE: + ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n)); + break; + case DOM::Node::DOCUMENT_FRAGMENT_NODE: + ret = new DOMNode(exec, n); + break; + case DOM::Node::NOTATION_NODE: + ret = new DOMNotation(exec, static_cast<DOM::Notation>(n)); + break; + default: + ret = new DOMNode(exec, n); + } + interp->putDOMObject(n.handle(),ret); + + return Value(ret); +} + +Value getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m) +{ + return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m)); +} + +Value getDOMNodeList(ExecState *exec, const DOM::NodeList& l) +{ + return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l)); +} + +Value getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i) +{ + return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i)); +} + +// ------------------------------------------------------------------------- +IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(NodeConstructor, "NodeConstructor", DOMNodeProto, DOMNodeConstants) +// ------------------------------------------------------------------------- + +const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 }; + +/* Source for DOMExceptionConstructorTable. +@begin DOMExceptionConstructorTable 15 + INDEX_SIZE_ERR DOM::DOMException::INDEX_SIZE_ERR DontDelete|ReadOnly + DOMSTRING_SIZE_ERR DOM::DOMException::DOMSTRING_SIZE_ERR DontDelete|ReadOnly + HIERARCHY_REQUEST_ERR DOM::DOMException::HIERARCHY_REQUEST_ERR DontDelete|ReadOnly + WRONG_DOCUMENT_ERR DOM::DOMException::WRONG_DOCUMENT_ERR DontDelete|ReadOnly + INVALID_CHARACTER_ERR DOM::DOMException::INVALID_CHARACTER_ERR DontDelete|ReadOnly + NO_DATA_ALLOWED_ERR DOM::DOMException::NO_DATA_ALLOWED_ERR DontDelete|ReadOnly + NO_MODIFICATION_ALLOWED_ERR DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR DontDelete|ReadOnly + NOT_FOUND_ERR DOM::DOMException::NOT_FOUND_ERR DontDelete|ReadOnly + NOT_SUPPORTED_ERR DOM::DOMException::NOT_SUPPORTED_ERR DontDelete|ReadOnly + INUSE_ATTRIBUTE_ERR DOM::DOMException::INUSE_ATTRIBUTE_ERR DontDelete|ReadOnly + INVALID_STATE_ERR DOM::DOMException::INVALID_STATE_ERR DontDelete|ReadOnly + SYNTAX_ERR DOM::DOMException::SYNTAX_ERR DontDelete|ReadOnly + INVALID_MODIFICATION_ERR DOM::DOMException::INVALID_MODIFICATION_ERR DontDelete|ReadOnly + NAMESPACE_ERR DOM::DOMException::NAMESPACE_ERR DontDelete|ReadOnly + INVALID_ACCESS_ERR DOM::DOMException::INVALID_ACCESS_ERR DontDelete|ReadOnly +@end +*/ + +DOMExceptionConstructor::DOMExceptionConstructor(ExecState* exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this); +} + +Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number((unsigned int)token); +#if 0 + switch (token) { + case INDEX_SIZE_ERR: + return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR); + case DOMSTRING_SIZE_ERR: + return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR); + case HIERARCHY_REQUEST_ERR: + return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR); + case WRONG_DOCUMENT_ERR: + return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR); + case INVALID_CHARACTER_ERR: + return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR); + case NO_DATA_ALLOWED_ERR: + return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR); + case NO_MODIFICATION_ALLOWED_ERR: + return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR); + case NOT_FOUND_ERR: + return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR); + case NOT_SUPPORTED_ERR: + return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR); + case INUSE_ATTRIBUTE_ERR: + return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR); + case INVALID_STATE_ERR: + return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR); + case SYNTAX_ERR: + return Number((unsigned int)DOM::DOMException::SYNTAX_ERR); + case INVALID_MODIFICATION_ERR: + return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR); + case NAMESPACE_ERR: + return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR); + case INVALID_ACCESS_ERR: + return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR); + default: + kdDebug(6070) << "WARNING: DOMExceptionConstructor::getValueProperty unhandled token " << token << endl; + return Value(); + } +#endif +} + +Object getDOMExceptionConstructor(ExecState *exec) +{ + return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]"); +} + +// ------------------------------------------------------------------------- + +/* Source for DOMNamedNodesCollection. +@begin DOMNamedNodesCollectionTable 1 + length KJS::DOMNamedNodesCollection::Length DontDelete|ReadOnly +@end +*/ +const ClassInfo KJS::DOMNamedNodesCollection::info = { "DOMNamedNodesCollection", 0, &DOMNamedNodesCollectionTable, 0 }; + +// Such a collection is usually very short-lived, it only exists +// for constructs like document.forms.<name>[1], +// so it shouldn't be a problem that it's storing all the nodes (with the same name). (David) +DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *exec, const QValueList<DOM::Node>& nodes ) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), + m_nodes(nodes) +{ + // Maybe we should ref (and deref in the dtor) the nodes, though ? +} + +Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + kdDebug(6070) << k_funcinfo << propertyName.ascii() << endl; + if (propertyName == lengthPropertyName) + return Number(m_nodes.count()); + // index? + bool ok; + unsigned int u = propertyName.toULong(&ok); + if (ok && u < m_nodes.count()) { + DOM::Node node = m_nodes[u]; + return getDOMNode(exec,node); + } + return DOMObject::tryGet(exec,propertyName); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMCharacterData::info = { "CharacterImp", + &DOMNode::info, &DOMCharacterDataTable, 0 }; +/* +@begin DOMCharacterDataTable 2 + data DOMCharacterData::Data DontDelete + length DOMCharacterData::Length DontDelete|ReadOnly +@end +@begin DOMCharacterDataProtoTable 7 + substringData DOMCharacterData::SubstringData DontDelete|Function 2 + appendData DOMCharacterData::AppendData DontDelete|Function 1 + insertData DOMCharacterData::InsertData DontDelete|Function 2 + deleteData DOMCharacterData::DeleteData DontDelete|Function 2 + replaceData DOMCharacterData::ReplaceData DontDelete|Function 2 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMCharacterDataProto, DOMNodeProto) +IMPLEMENT_PROTOFUNC_DOM(DOMCharacterDataProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMCharacterData", DOMCharacterDataProto, DOMCharacterDataProtoFunc) + +DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData& d) + : DOMNode(DOMCharacterDataProto::self(exec), d) {} + +DOMCharacterData::DOMCharacterData(const Object& proto, const DOM::CharacterData& d) + : DOMNode(proto, d) {} + +Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl; +#endif + return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this); +} + +Value DOMCharacterData::getValueProperty(ExecState *, int token) const +{ + DOM::CharacterData data = static_cast<DOM::CharacterData>(node); + switch (token) { + case Data: + return String(data.data()); + case Length: + return Number(data.length()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMCharacterData::getValueProperty : " << token << endl; + return Value(); + } +} + +void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + if (propertyName == "data") + static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string()); + else + DOMNode::tryPut(exec, propertyName,value,attr); +} + +Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMCharacterData, thisObj ); + DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData(); + switch(id) { + case DOMCharacterData::SubstringData: + return String(data.substringData(args[0].toInteger(exec),args[1].toInteger(exec))); + case DOMCharacterData::AppendData: + data.appendData(args[0].toString(exec).string()); + return Undefined(); + break; + case DOMCharacterData::InsertData: + data.insertData(args[0].toInteger(exec),args[1].toString(exec).string()); + return Undefined(); + break; + case DOMCharacterData::DeleteData: + data.deleteData(args[0].toInteger(exec),args[1].toInteger(exec)); + return Undefined(); + break; + case DOMCharacterData::ReplaceData: + data.replaceData(args[0].toInteger(exec),args[1].toInteger(exec),args[2].toString(exec).string()); + return Undefined(); + default: + break; + } + return Undefined(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMText::info = { "Text", + &DOMCharacterData::info, 0, 0 }; +/* +@begin DOMTextProtoTable 1 + splitText DOMText::SplitText DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMTextProto, DOMCharacterDataProto) +IMPLEMENT_PROTOFUNC_DOM(DOMTextProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMText", DOMTextProto, DOMTextProtoFunc) + +DOMText::DOMText(ExecState *exec, const DOM::Text& t) + : DOMCharacterData(DOMTextProto::self(exec), t) { } + +Value DOMText::tryGet(ExecState *exec, const Identifier &p) const +{ + if (p.isEmpty()) + return Undefined(); // ### TODO + else + return DOMCharacterData::tryGet(exec, p); +} + +Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMText, thisObj ); + DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText(); + switch(id) { + case DOMText::SplitText: + return getDOMNode(exec,text.splitText(args[0].toInteger(exec))); + default: + break; + } + return Undefined(); +} + +} diff --git a/khtml/ecma/kjs_dom.h b/khtml/ecma/kjs_dom.h new file mode 100644 index 000000000..e6b593fdb --- /dev/null +++ b/khtml/ecma/kjs_dom.h @@ -0,0 +1,299 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_DOM_H_ +#define _KJS_DOM_H_ + +#include "dom/dom_node.h" +#include "dom/dom_doc.h" +#include "dom/dom_element.h" +#include "dom/dom_xml.h" + +#include "ecma/kjs_binding.h" + + +namespace KJS { + + class DOMNode : public DOMObject { + public: + // Build a DOMNode + DOMNode(ExecState *exec, const DOM::Node& n); + // Constructor for inherited classes + DOMNode(const Object& proto, const DOM::Node& n); + ~DOMNode(); + virtual bool toBoolean(ExecState *) const; + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int attr); + virtual DOM::Node toNode() const { return node; } + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + virtual Value toPrimitive(ExecState *exec, Type preferred = UndefinedType) const; + virtual UString toString(ExecState *exec) const; + void setListener(ExecState *exec, int eventId, const Value& func) const; + Value getListener(int eventId) const; + virtual void pushEventHandlerScope(ExecState *exec, ScopeChain &scope) const; + + enum { NodeName, NodeValue, NodeType, ParentNode, ParentElement, + ChildNodes, FirstChild, LastChild, PreviousSibling, NextSibling, Item, + Attributes, NamespaceURI, Prefix, LocalName, OwnerDocument, InsertBefore, + ReplaceChild, RemoveChild, AppendChild, HasAttributes, HasChildNodes, + CloneNode, Normalize, IsSupported, AddEventListener, RemoveEventListener, + DispatchEvent, Contains, InsertAdjacentHTML, + OnAbort, OnBlur, OnChange, OnClick, OnDblClick, OnDragDrop, OnError, + OnFocus, OnKeyDown, OnKeyPress, OnKeyUp, OnLoad, OnMouseDown, + OnMouseMove, OnMouseOut, OnMouseOver, OnMouseUp, OnMove, OnReset, + OnResize, OnSelect, OnSubmit, OnUnload, + OffsetLeft, OffsetTop, OffsetWidth, OffsetHeight, OffsetParent, + ClientWidth, ClientHeight, ScrollLeft, ScrollTop, + ScrollWidth, ScrollHeight, SourceIndex, TextContent }; + + protected: + DOM::Node node; + }; + + DEFINE_CONSTANT_TABLE(DOMNodeConstants) + KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMNodeProto, DOMNodeConstants) + DEFINE_PSEUDO_CONSTRUCTOR(NodeConstructor) + + class DOMNodeList : public DOMObject { + public: + DOMNodeList(ExecState *, const DOM::NodeList& l); + ~DOMNodeList(); + virtual bool hasProperty(ExecState *exec, const Identifier &p) const; + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual Value call(ExecState *exec, Object &thisObj, const List&args); + virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args); + virtual bool implementsCall() const { return true; } + virtual ReferenceList propList(ExecState *exec, bool recursive); + + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + virtual bool toBoolean(ExecState *) const { return true; } + static const ClassInfo info; + DOM::NodeList nodeList() const { return list; } + enum { Item, NamedItem }; + private: + DOM::NodeList list; + }; + + class DOMDocument : public DOMNode { + public: + // Build a DOMDocument + DOMDocument(ExecState *exec, const DOM::Document& d); + // Constructor for inherited classes + DOMDocument(const Object& proto, const DOM::Document& d); + virtual ~DOMDocument(); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int attr); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { DocType, Implementation, DocumentElement, CharacterSet, + // Functions + CreateElement, CreateDocumentFragment, CreateTextNode, CreateComment, + CreateCDATASection, CreateProcessingInstruction, CreateAttribute, + CreateEntityReference, GetElementsByTagName, ImportNode, CreateElementNS, + CreateAttributeNS, GetElementsByTagNameNS, GetElementById, + CreateRange, CreateNodeIterator, CreateTreeWalker, DefaultView, + CreateEvent, StyleSheets, GetOverrideStyle, Abort, Load, LoadXML, + PreferredStylesheetSet, SelectedStylesheetSet, ReadyState, Async }; + }; + + KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMDocumentProto, DOMNodeProto) + + DEFINE_PSEUDO_CONSTRUCTOR(DocumentPseudoCtor) + + class DOMAttr : public DOMNode { + public: + DOMAttr(ExecState *exec, const DOM::Attr& a) : DOMNode(exec, a) { } + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + Value getValueProperty(ExecState *exec, int token) const; + void putValueProperty(ExecState *exec, int token, const Value& value, int attr); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Name, Specified, ValueProperty, OwnerElement }; + }; + + class DOMElement : public DOMNode { + public: + // Build a DOMElement + DOMElement(ExecState *exec, const DOM::Element& e); + // Constructor for inherited classes + DOMElement(const Object& proto, const DOM::Element& e); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { TagName, Style, + GetAttribute, SetAttribute, RemoveAttribute, GetAttributeNode, + SetAttributeNode, RemoveAttributeNode, GetElementsByTagName, + GetAttributeNS, SetAttributeNS, RemoveAttributeNS, GetAttributeNodeNS, + SetAttributeNodeNS, GetElementsByTagNameNS, HasAttribute, HasAttributeNS }; + }; + + KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMElementProto, DOMNodeProto) + DEFINE_PSEUDO_CONSTRUCTOR(ElementPseudoCtor) + + class DOMDOMImplementation : public DOMObject { + public: + // Build a DOMDOMImplementation + DOMDOMImplementation(ExecState *, const DOM::DOMImplementation& i); + ~DOMDOMImplementation(); + // no put - all functions + virtual const ClassInfo* classInfo() const { return &info; } + virtual bool toBoolean(ExecState *) const { return true; } + static const ClassInfo info; + enum { HasFeature, CreateDocumentType, CreateDocument, CreateCSSStyleSheet, CreateHTMLDocument }; + DOM::DOMImplementation toImplementation() const { return implementation; } + private: + DOM::DOMImplementation implementation; + }; + + class DOMDocumentType : public DOMNode { + public: + // Build a DOMDocumentType + DOMDocumentType(ExecState *exec, const DOM::DocumentType& dt); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Name, Entities, Notations, PublicId, SystemId, InternalSubset }; + }; + + class DOMNamedNodeMap : public DOMObject { + public: + DOMNamedNodeMap(ExecState *, const DOM::NamedNodeMap& m); + ~DOMNamedNodeMap(); + virtual bool hasProperty(ExecState *exec, const Identifier &p) const; + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + virtual bool toBoolean(ExecState *) const { return true; } + static const ClassInfo info; + enum { GetNamedItem, SetNamedItem, RemoveNamedItem, Item, Length, + GetNamedItemNS, SetNamedItemNS, RemoveNamedItemNS }; + DOM::NamedNodeMap toMap() const { return map; } + private: + DOM::NamedNodeMap map; + }; + + class DOMProcessingInstruction : public DOMNode { + public: + DOMProcessingInstruction(ExecState *exec, const DOM::ProcessingInstruction& pi) : DOMNode(exec, pi) { } + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Target, Data, Sheet }; + }; + + class DOMNotation : public DOMNode { + public: + DOMNotation(ExecState *exec, const DOM::Notation& n) : DOMNode(exec, n) { } + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { PublicId, SystemId }; + }; + + class DOMEntity : public DOMNode { + public: + DOMEntity(ExecState *exec, const DOM::Entity& e) : DOMNode(exec, e) { } + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { PublicId, SystemId, NotationName }; + }; + + // Constructor for DOMException - constructor stuff not implemented yet + class DOMExceptionConstructor : public DOMObject { + public: + DOMExceptionConstructor(ExecState *); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + bool checkNodeSecurity(ExecState *exec, const DOM::Node& n); + KDE_EXPORT Value getDOMNode(ExecState *exec, const DOM::Node& n); + Value getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m); + Value getDOMNodeList(ExecState *exec, const DOM::NodeList& l); + Value getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i); + Object getDOMExceptionConstructor(ExecState *exec); + + // Internal class, used for the collection return by e.g. document.forms.myinput + // when multiple nodes have the same name. + class DOMNamedNodesCollection : public DOMObject { + public: + DOMNamedNodesCollection(ExecState *exec, const QValueList<DOM::Node>& nodes ); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + const QValueList<DOM::Node>& nodes() const { return m_nodes; } + enum { Length }; + private: + QValueList<DOM::Node> m_nodes; + }; + + class DOMCharacterData : public DOMNode { + public: + // Build a DOMCharacterData + DOMCharacterData(ExecState *exec, const DOM::CharacterData& d); + // Constructor for inherited classes + DOMCharacterData(const Object& proto, const DOM::CharacterData& d); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + DOM::CharacterData toData() const { return static_cast<DOM::CharacterData>(node); } + enum { Data, Length, + SubstringData, AppendData, InsertData, DeleteData, ReplaceData }; + }; + + class DOMText : public DOMCharacterData { + public: + DOMText(ExecState *exec, const DOM::Text& t); + virtual Value tryGet(ExecState *exec,const Identifier &propertyName) const; + Value getValueProperty(ExecState *, int token) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + DOM::Text toText() const { return static_cast<DOM::Text>(node); } + enum { SplitText }; + }; + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_events.cpp b/khtml/ecma/kjs_events.cpp new file mode 100644 index 000000000..8ebda7193 --- /dev/null +++ b/khtml/ecma/kjs_events.cpp @@ -0,0 +1,993 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_window.h" +#include "kjs_events.h" +#include "kjs_events.lut.h" +#include "kjs_views.h" +#include "kjs_proxy.h" +#include "xml/dom_nodeimpl.h" +#include "xml/dom_docimpl.h" +#include "xml/dom2_eventsimpl.h" +#include "rendering/render_object.h" +#include "rendering/render_canvas.h" +#include "xml/dom2_eventsimpl.h" +#include "khtml_part.h" + +#include <kdebug.h> + +using namespace DOM; + +namespace KJS { + +// ------------------------------------------------------------------------- + +JSEventListener::JSEventListener(Object _listener, ObjectImp *_compareListenerImp, const Object &_win, bool _html) + : listener( _listener ), compareListenerImp( _compareListenerImp ), html( _html ), win( _win ) +{ + //fprintf(stderr,"JSEventListener::JSEventListener this=%p listener=%p\n",this,listener.imp()); + if (compareListenerImp) { + static_cast<Window*>(win.imp())->jsEventListeners.insert(compareListenerImp, this); + } +} + +JSEventListener::~JSEventListener() +{ + if (compareListenerImp) { + static_cast<Window*>(win.imp())->jsEventListeners.remove(compareListenerImp); + } + //fprintf(stderr,"JSEventListener::~JSEventListener this=%p listener=%p\n",this,listener.imp()); +} + +void JSEventListener::handleEvent(DOM::Event &evt) +{ +#ifdef KJS_DEBUGGER + if (KJSDebugWin::debugWindow() && KJSDebugWin::debugWindow()->inSession()) + return; +#endif + KHTMLPart *part = ::qt_cast<KHTMLPart *>(static_cast<Window*>(win.imp())->part()); + KJSProxy *proxy = 0L; + if (part) + proxy = part->jScript(); + + if (proxy && listener.isValid() && listener.implementsCall()) { + ref(); + + KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter()); + ExecState *exec = interpreter->globalExec(); + + List args; + args.append(getDOMEvent(exec,evt)); + + // Set "this" to the event's current target + Object thisObj = Object::dynamicCast(getDOMNode(exec,evt.currentTarget())); + if ( !thisObj.isValid() ) { + // Window events (window.onload/window.onresize etc.) must have 'this' set to the window. + // DocumentImpl::defaultEventHandler sets currentTarget to 0 to mean 'window'. + thisObj = win; + } + + Window *window = static_cast<Window*>(win.imp()); + // Set the event we're handling in the Window object + window->setCurrentEvent( &evt ); + // ... and in the interpreter + interpreter->setCurrentEvent( &evt ); + + KJSCPUGuard guard; + guard.start(); + Value retval = listener.call(exec, thisObj, args); + guard.stop(); + + window->setCurrentEvent( 0 ); + interpreter->setCurrentEvent( 0 ); + if ( exec->hadException() ) + exec->clearException(); + else if (html) + { + QVariant ret = ValueToVariant(exec, retval); + if (ret.type() == QVariant::Bool && ret.toBool() == false) + evt.preventDefault(); + } + window->afterScriptExecution(); + deref(); + } +} + +DOM::DOMString JSEventListener::eventListenerType() +{ + if (html) + return "_khtml_HTMLEventListener"; + else + return "_khtml_JSEventListener"; +} + +Object JSEventListener::listenerObj() const +{ + return listener; +} + +JSLazyEventListener::JSLazyEventListener(const QString &_code, const QString &_name, const Object &_win, DOM::NodeImpl* _originalNode) + : JSEventListener(Object(), 0, _win, true), + code(_code), name(_name), + parsed(false) +{ + // We don't retain the original node, because we assume it + // 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. + + originalNode = _originalNode; +} + +JSLazyEventListener::~JSLazyEventListener() +{ + if (listener.isValid()) { + static_cast<Window*>(win.imp())->jsEventListeners.remove(listener.imp()); + } +} + +void JSLazyEventListener::handleEvent(DOM::Event &evt) +{ + parseCode(); + if (listener.isValid()) { + JSEventListener::handleEvent(evt); + } +} + + +Object JSLazyEventListener::listenerObj() const +{ + parseCode(); + return listener; +} + +void JSLazyEventListener::parseCode() const +{ + if (!parsed) { + KHTMLPart *part = ::qt_cast<KHTMLPart *>(static_cast<Window*>(win.imp())->part()); + KJSProxy *proxy = 0L; + if (part) + proxy = part->jScript(); + + if (proxy) { + KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter()); + ExecState *exec = interpreter->globalExec(); + + //KJS::Constructor constr(KJS::Global::current().get("Function").imp()); + KJS::Object constr = interpreter->builtinFunction(); + KJS::List args; + + static KJS::String eventString("event"); + + args.append(eventString); + args.append(KJS::String(code)); + listener = constr.construct(exec, args); // ### is globalExec ok ? + + if (exec->hadException()) { + exec->clearException(); + + // failed to parse, so let's just make this listener a no-op + listener = Object(); + } else if (!listener.inherits(&DeclaredFunctionImp::info)) { + listener = Object();// Error creating function + } else { + DeclaredFunctionImp *declFunc = static_cast<DeclaredFunctionImp*>(listener.imp()); + declFunc->setName(Identifier(name)); + + if (originalNode) + { + // Add the event's home element to the scope + // (and the document, and the form - see KJS::HTMLElement::eventHandlerScope) + ScopeChain scope = listener.scope(); + + Object thisObj = Object::dynamicCast(getDOMNode(exec, originalNode)); + + if (thisObj.isValid()) { + static_cast<DOMNode*>(thisObj.imp())->pushEventHandlerScope(exec, scope); + + listener.setScope(scope); + } + } + } + } + + // no more need to keep the unparsed code around + code = QString(); + + if (listener.isValid()) { + static_cast<Window*>(win.imp())->jsEventListeners.insert(listener.imp(), + (KJS::JSEventListener *)(this)); + } + + parsed = true; + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMEvent::info = { "Event", 0, &DOMEventTable, 0 }; +/* +@begin DOMEventTable 7 + type DOMEvent::Type DontDelete|ReadOnly + target DOMEvent::Target DontDelete|ReadOnly + currentTarget DOMEvent::CurrentTarget DontDelete|ReadOnly + srcElement DOMEvent::SrcElement DontDelete|ReadOnly + eventPhase DOMEvent::EventPhase DontDelete|ReadOnly + bubbles DOMEvent::Bubbles DontDelete|ReadOnly + cancelable DOMEvent::Cancelable DontDelete|ReadOnly + timeStamp DOMEvent::TimeStamp DontDelete|ReadOnly + returnValue DOMEvent::ReturnValue DontDelete + cancelBubble DOMEvent::CancelBubble DontDelete +@end +@begin DOMEventProtoTable 3 + stopPropagation DOMEvent::StopPropagation DontDelete|Function 0 + preventDefault DOMEvent::PreventDefault DontDelete|Function 0 + initEvent DOMEvent::InitEvent DontDelete|Function 3 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMEventProto) +IMPLEMENT_PROTOFUNC_DOM(DOMEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMEvent", DOMEventProto, DOMEventProtoFunc) + +DOMEvent::DOMEvent(ExecState *exec, DOM::Event e) + : DOMObject(DOMEventProto::self(exec)), event(e) { } + +DOMEvent::DOMEvent(const Object &proto, DOM::Event e) + : DOMObject(proto), event(e) { } + +DOMEvent::~DOMEvent() +{ + ScriptInterpreter::forgetDOMObject(event.handle()); +} + +Value DOMEvent::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug() << "KJS::DOMEvent::tryGet " << p.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMEvent,DOMObject>(exec, p, &DOMEventTable, this ); +} + +Value DOMEvent::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case Type: + return String(event.type()); + case Target: + case SrcElement: /*MSIE extension - "the object that fired the event"*/ + return getDOMNode(exec,event.target()); + case CurrentTarget: + return getDOMNode(exec,event.currentTarget()); + case EventPhase: + return Number((unsigned int)event.eventPhase()); + case Bubbles: + return Boolean(event.bubbles()); + case Cancelable: + return Boolean(event.cancelable()); + case TimeStamp: + return Number((long unsigned int)event.timeStamp()); // ### long long ? + case ReturnValue: // MSIE extension + // return false == cancel, so this returns the -opposite- of defaultPrevented + return Boolean(!event.handle()->defaultPrevented()); + case CancelBubble: // MSIE extension + return Boolean(event.handle()->propagationStopped()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMEvent::getValueProperty : " << token << endl; + return Value(); + } +} + +Value DOMEvent::defaultValue(ExecState *exec, KJS::Type hint) const +{ + if (event.handle()->id() == EventImpl::ERROR_EVENT && !event.handle()->message().isNull()) { + return String(event.handle()->message()); + } + else + return DOMObject::defaultValue(exec,hint); +} + +void DOMEvent::tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr) +{ + DOMObjectLookupPut<DOMEvent, DOMObject>(exec, propertyName, value, attr, + &DOMEventTable, this); +} + +void DOMEvent::putValueProperty(ExecState *exec, int token, const Value& value, int) +{ + switch (token) { + case ReturnValue: // MSIE equivalent for "preventDefault" (but with a way to reset it) + // returnValue=false means "default action of the event on the source object is canceled", + // which means preventDefault(true). Hence the '!'. + event.handle()->preventDefault(!value.toBoolean(exec)); + break; + case CancelBubble: // MSIE equivalent for "stopPropagation" (but with a way to reset it) + event.handle()->stopPropagation(value.toBoolean(exec)); + break; + default: + break; + } +} + +Value DOMEventProtoFunc::tryCall(ExecState *exec, Object & thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMEvent, thisObj ); + DOM::Event event = static_cast<DOMEvent *>( thisObj.imp() )->toEvent(); + switch (id) { + case DOMEvent::StopPropagation: + event.stopPropagation(); + return Undefined(); + case DOMEvent::PreventDefault: + event.preventDefault(); + return Undefined(); + case DOMEvent::InitEvent: + event.initEvent(args[0].toString(exec).string(),args[1].toBoolean(exec),args[2].toBoolean(exec)); + return Undefined(); + }; + return Undefined(); +} + +Value getDOMEvent(ExecState *exec, DOM::Event e) +{ + DOM::EventImpl *ei = e.handle(); + if (!ei) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + DOMObject *ret = interp->getDOMObject(ei); + if (!ret) { + if (ei->isTextInputEvent()) + ret = new DOMTextEvent(exec, e); + else if (ei->isKeyboardEvent()) + ret = new DOMKeyboardEvent(exec, e); + else if (ei->isMouseEvent()) + ret = new DOMMouseEvent(exec, e); + else if (ei->isUIEvent()) + ret = new DOMUIEvent(exec, e); + else if (ei->isMutationEvent()) + ret = new DOMMutationEvent(exec, e); + else + ret = new DOMEvent(exec, e); + + interp->putDOMObject(ei, ret); + } + + return Value(ret); +} + +DOM::Event toEvent(const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMEvent::info)) + return DOM::Event(); + + const DOMEvent *dobj = static_cast<const DOMEvent*>(obj.imp()); + return dobj->toEvent(); +} + +// ------------------------------------------------------------------------- +/* +@begin EventConstantsTable 23 + CAPTURING_PHASE DOM::Event::CAPTURING_PHASE DontDelete|ReadOnly + AT_TARGET DOM::Event::AT_TARGET DontDelete|ReadOnly + BUBBLING_PHASE DOM::Event::BUBBLING_PHASE DontDelete|ReadOnly +# Reverse-engineered from Netscape + MOUSEDOWN 1 DontDelete|ReadOnly + MOUSEUP 2 DontDelete|ReadOnly + MOUSEOVER 4 DontDelete|ReadOnly + MOUSEOUT 8 DontDelete|ReadOnly + MOUSEMOVE 16 DontDelete|ReadOnly + MOUSEDRAG 32 DontDelete|ReadOnly + CLICK 64 DontDelete|ReadOnly + DBLCLICK 128 DontDelete|ReadOnly + KEYDOWN 256 DontDelete|ReadOnly + KEYUP 512 DontDelete|ReadOnly + KEYPRESS 1024 DontDelete|ReadOnly + DRAGDROP 2048 DontDelete|ReadOnly + FOCUS 4096 DontDelete|ReadOnly + BLUR 8192 DontDelete|ReadOnly + SELECT 16384 DontDelete|ReadOnly + CHANGE 32768 DontDelete|ReadOnly +@end +*/ +DEFINE_CONSTANT_TABLE(EventConstants) +IMPLEMENT_CONSTANT_TABLE(EventConstants, "EventConstants") + +IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(EventConstructor, "EventConstructor", DOMEventProto, EventConstants) +// ------------------------------------------------------------------------- + + +const ClassInfo EventExceptionConstructor::info = { "EventExceptionConstructor", 0, &EventExceptionConstructorTable, 0 }; +/* +@begin EventExceptionConstructorTable 1 + UNSPECIFIED_EVENT_TYPE_ERR DOM::EventException::UNSPECIFIED_EVENT_TYPE_ERR DontDelete|ReadOnly +@end +*/ +EventExceptionConstructor::EventExceptionConstructor(ExecState *exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value EventExceptionConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<EventExceptionConstructor, DOMObject>(exec,p,&EventExceptionConstructorTable,this); +} + +Value EventExceptionConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number(token); +} + +Value getEventExceptionConstructor(ExecState *exec) +{ + return cacheGlobalObject<EventExceptionConstructor>(exec, "[[eventException.constructor]]"); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMUIEvent::info = { "UIEvent", &DOMEvent::info, &DOMUIEventTable, 0 }; +/* +@begin DOMUIEventTable 7 + view DOMUIEvent::View DontDelete|ReadOnly + detail DOMUIEvent::Detail DontDelete|ReadOnly + keyCode DOMUIEvent::KeyCode DontDelete|ReadOnly + charCode DOMUIEvent::CharCode DontDelete|ReadOnly + layerX DOMUIEvent::LayerX DontDelete|ReadOnly + layerY DOMUIEvent::LayerY DontDelete|ReadOnly + pageX DOMUIEvent::PageX DontDelete|ReadOnly + pageY DOMUIEvent::PageY DontDelete|ReadOnly + which DOMUIEvent::Which DontDelete|ReadOnly +@end +@begin DOMUIEventProtoTable 1 + initUIEvent DOMUIEvent::InitUIEvent DontDelete|Function 5 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMUIEventProto, DOMEventProto) +IMPLEMENT_PROTOFUNC_DOM(DOMUIEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMUIEvent", DOMUIEventProto, DOMUIEventProtoFunc) + +DOMUIEvent::DOMUIEvent(ExecState *exec, DOM::UIEvent ue) : + DOMEvent(DOMUIEventProto::self(exec), ue) {} + +DOMUIEvent::DOMUIEvent(const Object &proto, DOM::UIEvent ue) : + DOMEvent(proto, ue) {} + +DOMUIEvent::~DOMUIEvent() +{ +} + +Value DOMUIEvent::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMUIEvent,DOMEvent>(exec,p,&DOMUIEventTable,this); +} + +Value DOMUIEvent::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case View: + return getDOMAbstractView(exec,static_cast<DOM::UIEvent>(event).view()); + case Detail: + return Number(static_cast<DOM::UIEvent>(event).detail()); + case KeyCode: + // IE-compatibility + return Number(static_cast<DOM::UIEvent>(event).keyCode()); + case CharCode: + // IE-compatibility + return Number(static_cast<DOM::UIEvent>(event).charCode()); + case LayerX: + // NS-compatibility + return Number(static_cast<DOM::UIEvent>(event).layerX()); + case LayerY: + // NS-compatibility + return Number(static_cast<DOM::UIEvent>(event).layerY()); + case PageX: + // NS-compatibility + return Number(static_cast<DOM::UIEvent>(event).pageX()); + case PageY: + // NS-compatibility + return Number(static_cast<DOM::UIEvent>(event).pageY()); + case Which: + // NS-compatibility + return Number(static_cast<DOM::UIEvent>(event).which()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMUIEvent::getValueProperty : " << token << endl; + return Undefined(); + } +} + +Value DOMUIEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMUIEvent, thisObj ); + DOM::UIEvent uiEvent = static_cast<DOMUIEvent *>(thisObj.imp())->toUIEvent(); + switch (id) { + case DOMUIEvent::InitUIEvent: { + DOM::AbstractView v = toAbstractView(args[3]); + static_cast<DOM::UIEvent>(uiEvent).initUIEvent(args[0].toString(exec).string(), + args[1].toBoolean(exec), + args[2].toBoolean(exec), + v, + args[4].toInteger(exec)); + } + return Undefined(); + } + return Undefined(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMMouseEvent::info = { "MouseEvent", &DOMUIEvent::info, &DOMMouseEventTable, 0 }; + +/* +@begin DOMMouseEventTable 2 + screenX DOMMouseEvent::ScreenX DontDelete|ReadOnly + screenY DOMMouseEvent::ScreenY DontDelete|ReadOnly + clientX DOMMouseEvent::ClientX DontDelete|ReadOnly + x DOMMouseEvent::X DontDelete|ReadOnly + clientY DOMMouseEvent::ClientY DontDelete|ReadOnly + y DOMMouseEvent::Y DontDelete|ReadOnly + offsetX DOMMouseEvent::OffsetX DontDelete|ReadOnly + offsetY DOMMouseEvent::OffsetY DontDelete|ReadOnly + ctrlKey DOMMouseEvent::CtrlKey DontDelete|ReadOnly + shiftKey DOMMouseEvent::ShiftKey DontDelete|ReadOnly + altKey DOMMouseEvent::AltKey DontDelete|ReadOnly + metaKey DOMMouseEvent::MetaKey DontDelete|ReadOnly + button DOMMouseEvent::Button DontDelete|ReadOnly + relatedTarget DOMMouseEvent::RelatedTarget DontDelete|ReadOnly + fromElement DOMMouseEvent::FromElement DontDelete|ReadOnly + toElement DOMMouseEvent::ToElement DontDelete|ReadOnly +@end +@begin DOMMouseEventProtoTable 1 + initMouseEvent DOMMouseEvent::InitMouseEvent DontDelete|Function 15 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMMouseEventProto, DOMUIEventProto) +IMPLEMENT_PROTOFUNC_DOM(DOMMouseEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMMouseEvent", DOMMouseEventProto, DOMMouseEventProtoFunc) + +DOMMouseEvent::DOMMouseEvent(ExecState *exec, DOM::MouseEvent me) : + DOMUIEvent(DOMMouseEventProto::self(exec), me) {} + +DOMMouseEvent::~DOMMouseEvent() +{ +} + +Value DOMMouseEvent::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMMouseEvent::tryGet " << p.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMMouseEvent,DOMUIEvent>(exec,p,&DOMMouseEventTable,this); +} + +Value DOMMouseEvent::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case ScreenX: + return Number(static_cast<DOM::MouseEvent>(event).screenX()); + case ScreenY: + return Number(static_cast<DOM::MouseEvent>(event).screenY()); + case ClientX: + case X: + return Number(static_cast<DOM::MouseEvent>(event).clientX()); + case ClientY: + case Y: + return Number(static_cast<DOM::MouseEvent>(event).clientY()); + case OffsetX: + case OffsetY: // MSIE extension + { + DOM::Node node = event.target(); + khtml::RenderObject *rend = 0; + if (node.handle()) { + node.handle()->getDocument()->updateRendering(); + rend = node.handle()->renderer(); + } + int x = static_cast<DOM::MouseEvent>(event).clientX(); + int y = static_cast<DOM::MouseEvent>(event).clientY(); + if ( rend ) { + int xPos, yPos; + if ( rend->absolutePosition( xPos, yPos ) ) { + //kdDebug() << "DOMMouseEvent::getValueProperty rend=" << rend << " xPos=" << xPos << " yPos=" << yPos << endl; + x -= xPos; + y -= yPos; + } + if ( rend->canvas() ) { + int cYPos, cXPos; + rend->canvas()->absolutePosition( cXPos, cYPos, true ); + x += cXPos; + y += cYPos; + } + } + return Number( token == OffsetX ? x : y ); + } + case CtrlKey: + return Boolean(static_cast<DOM::MouseEvent>(event).ctrlKey()); + case ShiftKey: + return Boolean(static_cast<DOM::MouseEvent>(event).shiftKey()); + case AltKey: + return Boolean(static_cast<DOM::MouseEvent>(event).altKey()); + case MetaKey: + return Boolean(static_cast<DOM::MouseEvent>(event).metaKey()); + case Button: + { + if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat ) { + return Number(static_cast<DOM::MouseEvent>(event).button()); + } + // Tricky. The DOM (and khtml) use 0 for LMB, 1 for MMB and 2 for RMB + // but MSIE uses 1=LMB, 2=RMB, 4=MMB, as a bitfield + int domButton = static_cast<DOM::MouseEvent>(event).button(); + int button = domButton==0 ? 1 : domButton==1 ? 4 : domButton==2 ? 2 : 0; + return Number( (unsigned int)button ); + } + case ToElement: + // MSIE extension - "the object toward which the user is moving the mouse pointer" + if (event.handle()->id() == DOM::EventImpl::MOUSEOUT_EVENT) + return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).relatedTarget()); + return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).target()); + case FromElement: + // MSIE extension - "object from which activation + // or the mouse pointer is exiting during the event" (huh?) + if (event.handle()->id() == DOM::EventImpl::MOUSEOUT_EVENT) + return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).target()); + /* fall through */ + case RelatedTarget: + return getDOMNode(exec,static_cast<DOM::MouseEvent>(event).relatedTarget()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMMouseEvent::getValueProperty : " << token << endl; + return Value(); + } +} + +Value DOMMouseEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMMouseEvent, thisObj ); + DOM::MouseEvent mouseEvent = static_cast<DOMMouseEvent *>(thisObj.imp())->toMouseEvent(); + switch (id) { + case DOMMouseEvent::InitMouseEvent: + mouseEvent.initMouseEvent(args[0].toString(exec).string(), // typeArg + args[1].toBoolean(exec), // canBubbleArg + args[2].toBoolean(exec), // cancelableArg + toAbstractView(args[3]), // viewArg + args[4].toInteger(exec), // detailArg + args[5].toInteger(exec), // screenXArg + args[6].toInteger(exec), // screenYArg + args[7].toInteger(exec), // clientXArg + args[8].toInteger(exec), // clientYArg + args[9].toBoolean(exec), // ctrlKeyArg + args[10].toBoolean(exec), // altKeyArg + args[11].toBoolean(exec), // shiftKeyArg + args[12].toBoolean(exec), // metaKeyArg + args[13].toInteger(exec), // buttonArg + toNode(args[14])); // relatedTargetArg + return Undefined(); + } + return Undefined(); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMKeyEventBase::info = { "KeyEventBase", &DOMUIEvent::info, &DOMKeyEventBaseTable, 0 }; + +/* +@begin DOMKeyEventBaseTable 5 + keyVal DOMKeyEventBase::Key DontDelete|ReadOnly + virtKeyVal DOMKeyEventBase::VirtKey DontDelete|ReadOnly + ctrlKey DOMKeyEventBase::CtrlKey DontDelete|ReadOnly + altKey DOMKeyEventBase::AltKey DontDelete|ReadOnly + shiftKey DOMKeyEventBase::ShiftKey DontDelete|ReadOnly + altKey DOMKeyEventBase::AltKey DontDelete|ReadOnly +@end +*/ + +DOMKeyEventBase::DOMKeyEventBase(const Object &proto, DOM::TextEvent ke) : + DOMUIEvent(proto, ke) {} + +DOMKeyEventBase::~DOMKeyEventBase() +{} + +Value DOMKeyEventBase::tryGet(ExecState *exec,const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMKeyEventBase::tryGet " << p.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMKeyEventBase,DOMUIEvent>(exec,p,&DOMKeyEventBaseTable,this); +} + +Value DOMKeyEventBase::getValueProperty(ExecState *, int token) const +{ + DOM::KeyEventBaseImpl* tevent = impl(); + switch (token) { + case Key: + return Number(tevent->keyVal()); + case VirtKey: + return Number(tevent->virtKeyVal()); + // these modifier attributes actually belong into a KeyboardEvent interface, + // but we want them on "keypress" as well. + case CtrlKey: + return Boolean(tevent->ctrlKey()); + case ShiftKey: + return Boolean(tevent->shiftKey()); + case AltKey: + return Boolean(tevent->altKey()); + case MetaKey: + return Boolean(tevent->metaKey()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMTextEvent::getValueProperty : " << token << endl; + return KJS::Undefined(); + } +} + +// ------------------------------------------------------------------------- +const ClassInfo DOMTextEvent::info = { "TextEvent", &DOMKeyEventBase::info, &DOMTextEventTable, 0 }; + +/* +@begin DOMTextEventTable 1 + data DOMTextEvent::Data DontDelete|ReadOnly +@end +@begin DOMTextEventProtoTable 1 + initTextEvent DOMTextEvent::InitTextEvent DontDelete|Function 5 + # Missing: initTextEventNS +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMTextEventProto, DOMUIEventProto) //Note: no proto in KeyBase +IMPLEMENT_PROTOFUNC_DOM(DOMTextEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMTextEvent", DOMTextEventProto, DOMTextEventProtoFunc) + +DOMTextEvent::DOMTextEvent(ExecState *exec, DOM::TextEvent ke) : + DOMKeyEventBase(DOMTextEventProto::self(exec), ke) {} + +DOMTextEvent::~DOMTextEvent() +{ +} + +Value DOMTextEvent::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMTextEvent::tryGet " << p.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMTextEvent,DOMKeyEventBase>(exec,p,&DOMTextEventTable,this); +} + +Value DOMTextEvent::getValueProperty(ExecState *, int token) const +{ + DOM::TextEventImpl* tevent = impl(); + switch (token) { + case Data: + return String(tevent->data()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMTextEvent::getValueProperty : " << token << endl; + return KJS::Undefined(); + } +} + +Value DOMTextEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMTextEvent, thisObj ); + DOM::TextEventImpl* keyEvent = static_cast<DOMTextEvent *>(thisObj.imp())->impl(); + switch (id) { + case DOMTextEvent::InitTextEvent: + keyEvent->initTextEvent(args[0].toString(exec).string(), // typeArg + args[1].toBoolean(exec), // canBubbleArg + args[2].toBoolean(exec), // cancelableArg + toAbstractView(args[3]), // viewArg + args[4].toString(exec).string()); // dataArg + + return Undefined(); + } + return Undefined(); +} +// ------------------------------------------------------------------------- +const ClassInfo DOMKeyboardEvent::info = { "KeyboardEvent", &DOMKeyEventBase::info, &DOMKeyboardEventTable, 0 }; + +/* +@begin DOMKeyboardEventTable 2 + keyIdentifier DOMKeyboardEvent::KeyIdentifier DontDelete|ReadOnly + keyLocation DOMKeyboardEvent::KeyLocation DontDelete|ReadOnly +@end +@begin DOMKeyboardEventProtoTable 2 + initKeyboardEvent DOMKeyboardEvent::InitKeyboardEvent DontDelete|Function 7 + getModifierState DOMKeyboardEvent::GetModifierState DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMKeyboardEventProto, DOMUIEventProto) //Note: no proto in KeyBase +IMPLEMENT_PROTOFUNC_DOM(DOMKeyboardEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMKeyboardEvent", DOMKeyboardEventProto, DOMKeyboardEventProtoFunc) + +DOMKeyboardEvent::DOMKeyboardEvent(ExecState *exec, DOM::TextEvent ke) : + DOMKeyEventBase(DOMKeyboardEventProto::self(exec), ke) {} + +DOMKeyboardEvent::~DOMKeyboardEvent() +{ +} + +Value DOMKeyboardEvent::tryGet(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "DOMKeyboardEvent::tryGet " << p.qstring() << endl; +#endif + return DOMObjectLookupGetValue<DOMKeyboardEvent,DOMKeyEventBase>(exec,p,&DOMKeyboardEventTable,this); +} + +Value DOMKeyboardEvent::getValueProperty(ExecState *, int token) const +{ + DOM::KeyboardEventImpl* tevent = impl(); + switch (token) { + case KeyIdentifier: + return String(tevent->keyIdentifier()); + case KeyLocation: + return Number(tevent->keyLocation()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMKeyboardEvent::getValueProperty : " << token << endl; + return KJS::Undefined(); + } +} + +Value DOMKeyboardEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMKeyboardEvent, thisObj ); + DOM::KeyboardEventImpl* keyEvent = static_cast<DOMKeyboardEvent *>(thisObj.imp())->impl(); + switch (id) { + case DOMKeyboardEvent::InitKeyboardEvent: + keyEvent->initKeyboardEvent(args[0].toString(exec).string(), // typeArg + args[1].toBoolean(exec), // canBubbleArg + args[2].toBoolean(exec), // cancelableArg + toAbstractView(args[3]), // viewArg + args[4].toString(exec).string(), // keyIdentifierArg + args[5].toInteger(exec), // keyLocationArg + args[6].toString(exec).string()); //modifiersList + break; + case DOMKeyboardEvent::GetModifierState: + return Boolean(keyEvent->getModifierState(args[0].toString(exec).string())); + } + return Undefined(); +} + +// ------------------------------------------------------------------------- +const ClassInfo KeyboardEventConstructor::info = { "KeyboardEventConstructor", 0, &KeyboardEventConstructorTable, 0 }; +/* +@begin KeyboardEventConstructorTable 4 + DOM_KEY_LOCATION_STANDARD DOM::KeyboardEventImpl::DOM_KEY_LOCATION_STANDARD DontDelete|ReadOnly + DOM_KEY_LOCATION_LEFT DOM::KeyboardEventImpl::DOM_KEY_LOCATION_LEFT DontDelete|ReadOnly + DOM_KEY_LOCATION_RIGHT DOM::KeyboardEventImpl::DOM_KEY_LOCATION_RIGHT DontDelete|ReadOnly + DOM_KEY_LOCATION_NUMPAD DOM::KeyboardEventImpl::DOM_KEY_LOCATION_NUMPAD DontDelete|ReadOnly +@end +*/ +KeyboardEventConstructor::KeyboardEventConstructor(ExecState* exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{} + +Value KeyboardEventConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<KeyboardEventConstructor,DOMObject>(exec,p,&KeyboardEventConstructorTable,this); +} + +Value KeyboardEventConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number(token); +} + +Value getKeyboardEventConstructor(ExecState *exec) +{ + return cacheGlobalObject<KeyboardEventConstructor>(exec, "[[keyboardEvent.constructor]]"); +} + + +// ------------------------------------------------------------------------- +const ClassInfo MutationEventConstructor::info = { "MutationEventConstructor", 0, &MutationEventConstructorTable, 0 }; +/* +@begin MutationEventConstructorTable 3 + MODIFICATION DOM::MutationEvent::MODIFICATION DontDelete|ReadOnly + ADDITION DOM::MutationEvent::ADDITION DontDelete|ReadOnly + REMOVAL DOM::MutationEvent::REMOVAL DontDelete|ReadOnly +@end +*/ +MutationEventConstructor::MutationEventConstructor(ExecState* exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value MutationEventConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<MutationEventConstructor,DOMObject>(exec,p,&MutationEventConstructorTable,this); +} + +Value MutationEventConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number(token); +} + +Value getMutationEventConstructor(ExecState *exec) +{ + return cacheGlobalObject<MutationEventConstructor>(exec, "[[mutationEvent.constructor]]"); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMMutationEvent::info = { "MutationEvent", &DOMEvent::info, &DOMMutationEventTable, 0 }; +/* +@begin DOMMutationEventTable 5 + relatedNode DOMMutationEvent::RelatedNode DontDelete|ReadOnly + prevValue DOMMutationEvent::PrevValue DontDelete|ReadOnly + newValue DOMMutationEvent::NewValue DontDelete|ReadOnly + attrName DOMMutationEvent::AttrName DontDelete|ReadOnly + attrChange DOMMutationEvent::AttrChange DontDelete|ReadOnly +@end +@begin DOMMutationEventProtoTable 1 + initMutationEvent DOMMutationEvent::InitMutationEvent DontDelete|Function 8 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(DOMMutationEventProto, DOMEventProto) +IMPLEMENT_PROTOFUNC_DOM(DOMMutationEventProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMMutationEvent", DOMMutationEventProto, DOMMutationEventProtoFunc) + +DOMMutationEvent::DOMMutationEvent(ExecState *exec, DOM::MutationEvent me) : + DOMEvent(DOMMutationEventProto::self(exec), me) {} + +DOMMutationEvent::~DOMMutationEvent() +{ +} + +Value DOMMutationEvent::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMMutationEvent,DOMEvent>(exec,p,&DOMMutationEventTable,this); +} + +Value DOMMutationEvent::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case RelatedNode: + return getDOMNode(exec,static_cast<DOM::MutationEvent>(event).relatedNode()); + case PrevValue: + return String(static_cast<DOM::MutationEvent>(event).prevValue()); + case NewValue: + return String(static_cast<DOM::MutationEvent>(event).newValue()); + case AttrName: + return String(static_cast<DOM::MutationEvent>(event).attrName()); + case AttrChange: + return Number((unsigned int)static_cast<DOM::MutationEvent>(event).attrChange()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMMutationEvent::getValueProperty : " << token << endl; + return Value(); + } +} + +Value DOMMutationEventProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMMutationEvent, thisObj ); + DOM::MutationEvent mutationEvent = static_cast<DOMMutationEvent *>(thisObj.imp())->toMutationEvent(); + switch (id) { + case DOMMutationEvent::InitMutationEvent: + mutationEvent.initMutationEvent(args[0].toString(exec).string(), // typeArg, + args[1].toBoolean(exec), // canBubbleArg + args[2].toBoolean(exec), // cancelableArg + toNode(args[3]), // relatedNodeArg + args[4].toString(exec).string(), // prevValueArg + args[5].toString(exec).string(), // newValueArg + args[6].toString(exec).string(), // attrNameArg + args[7].toInteger(exec)); // attrChangeArg + return Undefined(); + } + return Undefined(); +} + +} //namespace KJS diff --git a/khtml/ecma/kjs_events.h b/khtml/ecma/kjs_events.h new file mode 100644 index 000000000..9fedfe594 --- /dev/null +++ b/khtml/ecma/kjs_events.h @@ -0,0 +1,250 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_EVENTS_H_ +#define _KJS_EVENTS_H_ + +#include "ecma/kjs_dom.h" +#include "dom/dom2_events.h" +#include "dom/dom_misc.h" +#include "xml/dom2_eventsimpl.h" + +namespace KJS { + + class Window; + + class JSEventListener : public DOM::EventListener { + public: + /** + * @param _listener the function object, that will be called when the event is emitted + * @param _compareListenerImp Compare Listener implementation. + * @param _win Window object, for memory management and caching. + * @param _html \c true if it is HTML. + * Never create a JSEventListener directly, use Window::getJSEventListener. + */ + JSEventListener(Object _listener, ObjectImp *_compareListenerImp, const Object &_win, bool _html = false); + virtual ~JSEventListener(); + virtual void handleEvent(DOM::Event &evt); + virtual DOM::DOMString eventListenerType(); + // Return the KJS function object executed when this event is emitted + virtual Object listenerObj() const; + ObjectImp *listenerObjImp() const { return listenerObj().imp(); } + // for Window::clear(). This is a bad hack though. The JSEventListener might not get deleted + // if it was added to a DOM node in another frame (#61467). But calling removeEventListener on + // all nodes we're listening to is quite difficult. + void clear() { listener = Object(); } + bool isHTMLEventListener() const { return html; } + + protected: + mutable Object listener; + // Storing a different ObjectImp ptr is needed to support addEventListener(.. [Object] ..) calls + // In the real-life case (where a 'function' is passed to addEventListener) we can directly call + // the 'listener' object and can cache the 'listener.imp()'. If the event listener should be removed + // the implementation will call removeEventListener(.. [Function] ..), and we can lookup the event + // listener by the passed function's imp() ptr. + // In the only dom-approved way (passing an Object to add/removeEventListener), the 'listener' + // variable stores the function object 'passedListener.handleEvent'. But we need to cache + // the imp() ptr of the 'passedListener' function _object_, as the implementation will + // call removeEventListener(.. [Object ..] on removal, and now we can successfully lookup + // the correct event listener, as well as the 'listener.handleEvent' function, we need to call. + mutable ObjectImp *compareListenerImp; + bool html; + Object win; + }; + + class JSLazyEventListener : public JSEventListener { + public: + JSLazyEventListener(const QString &_code, const QString &_name, const Object &_win, DOM::NodeImpl* node); + ~JSLazyEventListener(); + virtual void handleEvent(DOM::Event &evt); + Object listenerObj() const; + private: + void parseCode() const; + + mutable QString code; + mutable QString name; + mutable bool parsed; + DOM::NodeImpl *originalNode; + }; + + // Constructor for Event - currently only used for some global vars + DEFINE_PSEUDO_CONSTRUCTOR(EventConstructor) + + class DOMEvent : public DOMObject { + public: + // Build a DOMEvent + DOMEvent(ExecState *exec, DOM::Event e); + // Constructor for inherited classes + DOMEvent(const Object &proto, DOM::Event e); + ~DOMEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr = None); + virtual Value defaultValue(ExecState *exec, KJS::Type hint) const; + void putValueProperty(ExecState *exec, int token, const Value& value, int); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Type, Target, CurrentTarget, EventPhase, Bubbles, + Cancelable, TimeStamp, StopPropagation, PreventDefault, InitEvent, + // MS IE equivalents + SrcElement, ReturnValue, CancelBubble }; + DOM::Event toEvent() const { return event; } + protected: + DOM::Event event; + }; + + Value getDOMEvent(ExecState *exec, DOM::Event e); + + /** + * Convert an object to an Event. Returns a null Event if not possible. + */ + DOM::Event toEvent(const Value&); + + // Constructor object EventException + class EventExceptionConstructor : public DOMObject { + public: + EventExceptionConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + Value getEventExceptionConstructor(ExecState *exec); + + class DOMUIEvent : public DOMEvent { + public: + // Build a DOMUIEvent + DOMUIEvent(ExecState *exec, DOM::UIEvent ue); + // Constructor for inherited classes + DOMUIEvent(const Object &proto, DOM::UIEvent ue); + ~DOMUIEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { View, Detail, KeyCode, CharCode, LayerX, LayerY, PageX, PageY, Which, InitUIEvent }; + DOM::UIEvent toUIEvent() const { return static_cast<DOM::UIEvent>(event); } + }; + + class DOMMouseEvent : public DOMUIEvent { + public: + DOMMouseEvent(ExecState *exec, DOM::MouseEvent me); + ~DOMMouseEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { ScreenX, ScreenY, ClientX, X, ClientY, Y, OffsetX, OffsetY, + CtrlKey, ShiftKey, AltKey, + MetaKey, Button, RelatedTarget, FromElement, ToElement, + InitMouseEvent + }; + DOM::MouseEvent toMouseEvent() const { return static_cast<DOM::MouseEvent>(event); } + }; + + class DOMKeyEventBase : public DOMUIEvent { + public: + DOMKeyEventBase(const Object &proto, DOM::TextEvent ke); + ~DOMKeyEventBase(); + + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Key, VirtKey, CtrlKey, ShiftKey, AltKey, MetaKey }; + DOM::KeyEventBaseImpl* impl() const { return static_cast<DOM::KeyEventBaseImpl*>(event.handle()); } + }; + + class DOMTextEvent : public DOMKeyEventBase { + public: + DOMTextEvent(ExecState *exec, DOM::TextEvent ke); + ~DOMTextEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum {Data, InitTextEvent}; + DOM::TextEventImpl* impl() const { return static_cast<DOM::TextEventImpl*>(event.handle()); } + }; + + class DOMKeyboardEvent : public DOMKeyEventBase { + public: + DOMKeyboardEvent(ExecState *exec, DOM::TextEvent ke); + ~DOMKeyboardEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum {KeyIdentifier, KeyLocation, GetModifierState, InitKeyboardEvent}; + DOM::KeyboardEventImpl* impl() const { return static_cast<DOM::KeyboardEventImpl*>(event.handle()); } + }; + + // Constructor object KeyboardEvent + class KeyboardEventConstructor : public DOMObject { + public: + KeyboardEventConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + Value getKeyboardEventConstructor(ExecState *exec); + + // Constructor object MutationEvent + class MutationEventConstructor : public DOMObject { + public: + MutationEventConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + Value getMutationEventConstructor(ExecState *exec); + + class DOMMutationEvent : public DOMEvent { + public: + DOMMutationEvent(ExecState *exec, DOM::MutationEvent me); + ~DOMMutationEvent(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { AttrChange, RelatedNode, AttrName, PrevValue, NewValue, + InitMutationEvent }; + DOM::MutationEvent toMutationEvent() const { return static_cast<DOM::MutationEvent>(event); } + }; + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_html.cpp b/khtml/ecma/kjs_html.cpp new file mode 100644 index 000000000..94f89079f --- /dev/null +++ b/khtml/ecma/kjs_html.cpp @@ -0,0 +1,3946 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999-2002 Harri Porten (porten@kde.org) + * Copyright (C) 2001-2003 David Faure (faure@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "misc/loader.h" +#include "dom/html_block.h" +#include "dom/html_head.h" +#include "dom/html_image.h" +#include "dom/html_inline.h" +#include "dom/html_list.h" +#include "dom/html_table.h" +#include "dom/html_object.h" +#include "dom/dom_exception.h" + +// ### HACK +#include "html/html_baseimpl.h" +#include "html/html_documentimpl.h" +#include "html/html_formimpl.h" +#include "html/html_imageimpl.h" +#include "html/html_miscimpl.h" +#include "xml/dom2_eventsimpl.h" + +#include <kparts/browserextension.h> + +#include "khtml_part.h" +#include "khtmlview.h" + +#include "ecma/kjs_css.h" +#include "ecma/kjs_events.h" +#include "ecma/kjs_html.h" +#include "ecma/kjs_window.h" +#include "kjs_html.lut.h" + +#include "misc/htmltags.h" +#include "misc/htmlattrs.h" +#include "rendering/render_object.h" +#include "rendering/render_canvas.h" +#include "rendering/render_frames.h" +#include "rendering/render_layer.h" + +#include "kmessagebox.h" +#include <kstringhandler.h> +#include <klocale.h> + +#include <kdebug.h> + +namespace KJS { + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLDocumentProto, DOMDocumentProto) +IMPLEMENT_PROTOFUNC_DOM(HTMLDocFunction) +KJS_IMPLEMENT_PROTOTYPE("HTMLDocument", HTMLDocumentProto, HTMLDocFunction) + +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLDocumentPseudoCtor, "HTMLDocument", HTMLDocumentProto) + +/* Source for HTMLDocumentProtoTable. +@begin HTMLDocumentProtoTable 11 + clear HTMLDocument::Clear DontDelete|Function 0 + open HTMLDocument::Open DontDelete|Function 0 + close HTMLDocument::Close DontDelete|Function 0 + write HTMLDocument::Write DontDelete|Function 1 + writeln HTMLDocument::WriteLn DontDelete|Function 1 + getElementsByName HTMLDocument::GetElementsByName DontDelete|Function 1 + getSelection HTMLDocument::GetSelection DontDelete|Function 1 + captureEvents HTMLDocument::CaptureEvents DontDelete|Function 0 + releaseEvents HTMLDocument::ReleaseEvents DontDelete|Function 0 +@end +*/ + + +Value KJS::HTMLDocFunction::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( HTMLDocument, thisObj ); + + DOM::HTMLDocument doc = static_cast<KJS::HTMLDocument *>(thisObj.imp())->toDocument(); + + switch (id) { + case HTMLDocument::Clear: // even IE doesn't support that one... + //doc.clear(); // TODO + return Undefined(); + case HTMLDocument::Open: + if (args.size() >= 3) // IE extension for document.open: it means window.open if it has 3 args or more + { + KHTMLView *view = static_cast<DOM::DocumentImpl*>(doc.handle())->view(); + if ( view && view->part() ) { + Window* win = Window::retrieveWindow(view->part()); + if( win ) { + win->openWindow(exec, args); + } + } + } + + doc.open(); + return Undefined(); + case HTMLDocument::Close: + // see khtmltests/ecma/tokenizer-script-recursion.html + doc.close(); + return Undefined(); + case HTMLDocument::Write: + case HTMLDocument::WriteLn: { + // DOM only specifies single string argument, but NS & IE allow multiple + // or no arguments + UString str = ""; + for (int i = 0; i < args.size(); i++) + str += args[i].toString(exec); + if (id == HTMLDocument::WriteLn) + str += "\n"; +#ifdef KJS_VERBOSE + kdDebug(6070) << "document.write: " << str.string().string() << endl; +#endif + doc.write(str.string()); + return Undefined(); + } + case HTMLDocument::GetElementsByName: + return getDOMNodeList(exec,doc.getElementsByName(args[0].toString(exec).string())); + case HTMLDocument::GetSelection: { + // NS4 and Mozilla specific. IE uses document.selection.createRange() + // http://docs.sun.com/source/816-6408-10/document.htm#1195981 + KHTMLView *view = static_cast<DOM::DocumentImpl*>(doc.handle())->view(); + if ( view && view->part() ) + return String(view->part()->selectedText()); + else + return Undefined(); + } + case HTMLDocument::CaptureEvents: + case HTMLDocument::ReleaseEvents: + // Do nothing for now. These are NS-specific legacy calls. + break; + } + + return Undefined(); +} + +const ClassInfo KJS::HTMLDocument::info = + { "HTMLDocument", &DOMDocument::info, &HTMLDocumentTable, 0 }; +/* Source for HTMLDocumentTable. +@begin HTMLDocumentTable 31 + title HTMLDocument::Title DontDelete + referrer HTMLDocument::Referrer DontDelete|ReadOnly + domain HTMLDocument::Domain DontDelete + URL HTMLDocument::URL DontDelete|ReadOnly + body HTMLDocument::Body DontDelete + location HTMLDocument::Location DontDelete + cookie HTMLDocument::Cookie DontDelete + images HTMLDocument::Images DontDelete|ReadOnly + applets HTMLDocument::Applets DontDelete|ReadOnly + links HTMLDocument::Links DontDelete|ReadOnly + forms HTMLDocument::Forms DontDelete|ReadOnly + anchors HTMLDocument::Anchors DontDelete|ReadOnly + scripts HTMLDocument::Scripts DontDelete|ReadOnly + all HTMLDocument::All DontDelete|ReadOnly + bgColor HTMLDocument::BgColor DontDelete + fgColor HTMLDocument::FgColor DontDelete + alinkColor HTMLDocument::AlinkColor DontDelete + linkColor HTMLDocument::LinkColor DontDelete + vlinkColor HTMLDocument::VlinkColor DontDelete + lastModified HTMLDocument::LastModified DontDelete|ReadOnly + height HTMLDocument::Height DontDelete|ReadOnly + width HTMLDocument::Width DontDelete|ReadOnly + dir HTMLDocument::Dir DontDelete + compatMode HTMLDocument::CompatMode DontDelete|ReadOnly +#IE extension + frames HTMLDocument::Frames DontDelete|ReadOnly +#NS4 extension + layers HTMLDocument::Layers DontDelete|ReadOnly +#potentially obsolete array properties +# plugins +# tags +#potentially obsolete properties +# embeds +# ids +@end +*/ + +KJS::HTMLDocument::HTMLDocument(ExecState *exec, const DOM::HTMLDocument& d) + : DOMDocument(HTMLDocumentProto::self(exec), d) { } + +bool KJS::HTMLDocument::hasProperty(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + //kdDebug(6070) << "KJS::HTMLDocument::hasProperty " << p.qstring() << endl; +#endif + DOM::HTMLDocument doc = static_cast<DOM::HTMLDocument>(node); + DOM::DocumentImpl* docImpl = static_cast<DOM::DocumentImpl*>(doc.handle()); + KHTMLView *view = docImpl->view(); + Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L; + if ( !win || !win->isSafeScript(exec) ) + return false; + + + if ( docImpl->underDocNamedCache().contains( p.qstring() ) ) + return true; + + if ( view && view->part() ) + { + KHTMLPart *kp = view->part()->findFrame( p.qstring() ); + if (kp) + return true; + } + + return DOMDocument::hasProperty(exec, p); +} + +Value KJS::HTMLDocument::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLDocument::tryGet " << propertyName.qstring() << endl; +#endif + + DOM::HTMLDocument doc = static_cast<DOM::HTMLDocument>(node); + DOM::DocumentImpl* docImpl = static_cast<DOM::DocumentImpl*>(doc.handle()); + KHTMLView *view = docImpl->view(); + + Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L; + if ( !win || !win->isSafeScript(exec) ) + return Undefined(); + + //Check for images, forms, objects, etc. + ElementMappingCache::ItemInfo* info = docImpl->underDocNamedCache().get(propertyName.qstring()); + if (info) { + //May be a false positive, but we can try to avoid doing it the hard way in + //simpler cases. The trickiness here is that the cache is kept under both + //name and id, but we sometimes ignore id for IE compat + DOM::DOMString propertyDOMString = propertyName.string(); + + if (info->nd && DOM::HTMLMappedNameCollectionImpl::matchesName(info->nd, + HTMLCollectionImpl::DOCUMENT_NAMED_ITEMS, propertyDOMString)) { + return getDOMNode(exec, info->nd); + } else { + //Can't tell it just like that, so better go through collection and count stuff. This is the slow path... + DOM::HTMLMappedNameCollection coll(docImpl, HTMLCollectionImpl::DOCUMENT_NAMED_ITEMS, propertyDOMString); + + if (coll.length() == 1) { + DOM::Node node = coll.firstItem(); + return getDOMNode(exec, node); + } else if (coll.length() > 1) { + return getHTMLCollection(exec, coll); + } + } + } + + // Check for frames/iframes with name==propertyName + if ( view && view->part() ) + { + // ###### TODO return a collection in case several frames have the same name + // (IE does that). Hard to do with findFrame :} + KHTMLPart *kp = view->part()->findFrame( propertyName.qstring() ); + if (kp) + return Window::retrieve(kp); + } + + const HashEntry* entry = Lookup::findEntry(&HTMLDocumentTable, propertyName); + if (entry) { + switch (entry->value) { + case Title: + return String(doc.title()); + case Referrer: + return String(doc.referrer()); + case Domain: + return String(doc.domain()); + case URL: + return String(doc.URL()); + case Body: + return getDOMNode(exec,doc.body()); + case Location: + if (win) + return Value(win->location()); + else + return Undefined(); + case Cookie: + return String(doc.cookie()); + case Images: + return getHTMLCollection(exec,doc.images()); + case Applets: + return getHTMLCollection(exec,doc.applets()); + case Links: + return getHTMLCollection(exec,doc.links()); + case Forms: + return getHTMLCollection(exec,doc.forms()); + case Layers: + // ### Should not be hidden when we emulate Netscape4 + return getHTMLCollection(exec,doc.layers(), true); + case Anchors: + return getHTMLCollection(exec,doc.anchors()); + case Scripts: + return getHTMLCollection(exec,doc.scripts()); + case All: + // Disable document.all when we try to be Netscape-compatible + if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat ) + return Undefined(); + else + if ( exec->interpreter()->compatMode() == Interpreter::IECompat ) + return getHTMLCollection(exec,doc.all()); + else // enabled but hidden + return getHTMLCollection(exec,doc.all(), true); + case CompatMode: + return String(static_cast<HTMLDocumentImpl *>(doc.handle())->parseMode() + == DocumentImpl::Compat ? "BackCompat" : "CSS1Compat"); + } + } + // Look for overrides + ValueImp * val = ObjectImp::getDirect(propertyName); + if (val) + return Value(val); + + DOM::HTMLBodyElement body = doc.body(); + if (entry) { + switch (entry->value) { + case BgColor: + return String(body.bgColor()); + case FgColor: + return String(body.text()); + case AlinkColor: + return String(body.aLink()); + case LinkColor: + return String(body.link()); + case VlinkColor: + return String(body.vLink()); + case LastModified: + return String(doc.lastModified()); + case Height: // NS-only, not available in IE + return Number(view ? view->contentsHeight() : 0); + case Width: // NS-only, not available in IE + return Number(view ? view->contentsWidth() : 0); + case Dir: + return String(body.dir()); + case Frames: + if ( win ) + return Value(win->frames(exec)); + else + return Undefined(); + } + } + return DOMDocument::tryGet(exec, propertyName); +} + +void KJS::HTMLDocument::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLDocument::tryPut " << propertyName.qstring() << endl; +#endif + KHTMLView *view = static_cast<DOM::DocumentImpl*>(node.handle())->view(); + + Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L; + if ( !win || !win->isSafeScript(exec) ) + return; + + DOMObjectLookupPut<HTMLDocument, DOMDocument>( exec, propertyName, value, attr, &HTMLDocumentTable, this ); +} + +void KJS::HTMLDocument::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/) +{ + DOM::HTMLDocument doc = static_cast<DOM::HTMLDocument>(node); + + DOM::HTMLBodyElement body = doc.body(); + DOM::DOMString val = value.toString(exec).string(); + + switch (token) { + case Title: + if (doc.title() != val) doc.setTitle(val); + break; + case Body: { + DOMNode *node = new DOMNode(exec, KJS::toNode(value)); + // This is required to avoid leaking the node. + Value nodeValue(node); + doc.setBody(node->toNode()); + break; + } + case Domain: { // not part of the DOM + DOM::HTMLDocumentImpl* docimpl = static_cast<DOM::HTMLDocumentImpl*>(doc.handle()); + if (docimpl) + docimpl->setDomain(val); + break; + } + case Cookie: + doc.setCookie(val); + break; + case Location: + { + KHTMLView *view = static_cast<DOM::DocumentImpl*>(doc.handle())->view(); + if ( view ) + Window::retrieveWindow(view->part())->goURL(exec, value.toString(exec).qstring(), false /*don't lock history*/); + break; + } + case BgColor: + if (body.bgColor() != val) body.setBgColor(val); + break; + case FgColor: + if (body.text() != val) body.setText(val); + break; + case AlinkColor: + if (body.aLink() != val) body.setALink(val); + break; + case LinkColor: + if (body.link() != val) body.setLink(val); + break; + case VlinkColor: + if (body.vLink() != val) body.setVLink(val); + break; + case Dir: + body.setDir(val); + break; + default: + kdDebug(6070) << "WARNING: HTMLDocument::putValueProperty unhandled token " << token << endl; + } +} + +// ------------------------------------------------------------------------- + +const ClassInfo KJS::HTMLElement::info = { "HTMLElement", &DOMElement::info, &HTMLElementTable, 0 }; +const ClassInfo KJS::HTMLElement::html_info = { "HTMLHtmlElement", &KJS::HTMLElement::info, &HTMLHtmlElementTable, 0 }; +const ClassInfo KJS::HTMLElement::head_info = { "HTMLHeadElement", &KJS::HTMLElement::info, &HTMLHeadElementTable, 0 }; +const ClassInfo KJS::HTMLElement::link_info = { "HTMLLinkElement", &KJS::HTMLElement::info, &HTMLLinkElementTable, 0 }; +const ClassInfo KJS::HTMLElement::title_info = { "HTMLTitleElement", &KJS::HTMLElement::info, &HTMLTitleElementTable, 0 }; +const ClassInfo KJS::HTMLElement::meta_info = { "HTMLMetaElement", &KJS::HTMLElement::info, &HTMLMetaElementTable, 0 }; +const ClassInfo KJS::HTMLElement::base_info = { "HTMLBaseElement", &KJS::HTMLElement::info, &HTMLBaseElementTable, 0 }; +const ClassInfo KJS::HTMLElement::isIndex_info = { "HTMLIsIndexElement", &KJS::HTMLElement::info, &HTMLIsIndexElementTable, 0 }; +const ClassInfo KJS::HTMLElement::style_info = { "HTMLStyleElement", &KJS::HTMLElement::info, &HTMLStyleElementTable, 0 }; +const ClassInfo KJS::HTMLElement::body_info = { "HTMLBodyElement", &KJS::HTMLElement::info, &HTMLBodyElementTable, 0 }; +const ClassInfo KJS::HTMLElement::form_info = { "HTMLFormElement", &KJS::HTMLElement::info, &HTMLFormElementTable, 0 }; +const ClassInfo KJS::HTMLElement::select_info = { "HTMLSelectElement", &KJS::HTMLElement::info, &HTMLSelectElementTable, 0 }; +const ClassInfo KJS::HTMLElement::optGroup_info = { "HTMLOptGroupElement", &KJS::HTMLElement::info, &HTMLOptGroupElementTable, 0 }; +const ClassInfo KJS::HTMLElement::option_info = { "HTMLOptionElement", &KJS::HTMLElement::info, &HTMLOptionElementTable, 0 }; +const ClassInfo KJS::HTMLElement::input_info = { "HTMLInputElement", &KJS::HTMLElement::info, &HTMLInputElementTable, 0 }; +const ClassInfo KJS::HTMLElement::textArea_info = { "HTMLTextAreaElement", &KJS::HTMLElement::info, &HTMLTextAreaElementTable, 0 }; +const ClassInfo KJS::HTMLElement::button_info = { "HTMLButtonElement", &KJS::HTMLElement::info, &HTMLButtonElementTable, 0 }; +const ClassInfo KJS::HTMLElement::label_info = { "HTMLLabelElement", &KJS::HTMLElement::info, &HTMLLabelElementTable, 0 }; +const ClassInfo KJS::HTMLElement::fieldSet_info = { "HTMLFieldSetElement", &KJS::HTMLElement::info, &HTMLFieldSetElementTable, 0 }; +const ClassInfo KJS::HTMLElement::legend_info = { "HTMLLegendElement", &KJS::HTMLElement::info, &HTMLLegendElementTable, 0 }; +const ClassInfo KJS::HTMLElement::ul_info = { "HTMLUListElement", &KJS::HTMLElement::info, &HTMLUListElementTable, 0 }; +const ClassInfo KJS::HTMLElement::ol_info = { "HTMLOListElement", &KJS::HTMLElement::info, &HTMLOListElementTable, 0 }; +const ClassInfo KJS::HTMLElement::dl_info = { "HTMLDListElement", &KJS::HTMLElement::info, &HTMLDListElementTable, 0 }; +const ClassInfo KJS::HTMLElement::dir_info = { "HTMLDirectoryElement", &KJS::HTMLElement::info, &HTMLDirectoryElementTable, 0 }; +const ClassInfo KJS::HTMLElement::menu_info = { "HTMLMenuElement", &KJS::HTMLElement::info, &HTMLMenuElementTable, 0 }; +const ClassInfo KJS::HTMLElement::li_info = { "HTMLLIElement", &KJS::HTMLElement::info, &HTMLLIElementTable, 0 }; +const ClassInfo KJS::HTMLElement::div_info = { "HTMLDivElement", &KJS::HTMLElement::info, &HTMLDivElementTable, 0 }; +const ClassInfo KJS::HTMLElement::p_info = { "HTMLParagraphElement", &KJS::HTMLElement::info, &HTMLParagraphElementTable, 0 }; +const ClassInfo KJS::HTMLElement::heading_info = { "HTMLHeadingElement", &KJS::HTMLElement::info, &HTMLHeadingElementTable, 0 }; +const ClassInfo KJS::HTMLElement::blockQuote_info = { "HTMLBlockQuoteElement", &KJS::HTMLElement::info, &HTMLBlockQuoteElementTable, 0 }; +const ClassInfo KJS::HTMLElement::q_info = { "HTMLQuoteElement", &KJS::HTMLElement::info, &HTMLQuoteElementTable, 0 }; +const ClassInfo KJS::HTMLElement::pre_info = { "HTMLPreElement", &KJS::HTMLElement::info, &HTMLPreElementTable, 0 }; +const ClassInfo KJS::HTMLElement::br_info = { "HTMLBRElement", &KJS::HTMLElement::info, &HTMLBRElementTable, 0 }; +const ClassInfo KJS::HTMLElement::baseFont_info = { "HTMLBaseFontElement", &KJS::HTMLElement::info, &HTMLBaseFontElementTable, 0 }; +const ClassInfo KJS::HTMLElement::font_info = { "HTMLFontElement", &KJS::HTMLElement::info, &HTMLFontElementTable, 0 }; +const ClassInfo KJS::HTMLElement::hr_info = { "HTMLHRElement", &KJS::HTMLElement::info, &HTMLHRElementTable, 0 }; +const ClassInfo KJS::HTMLElement::mod_info = { "HTMLModElement", &KJS::HTMLElement::info, &HTMLModElementTable, 0 }; +const ClassInfo KJS::HTMLElement::a_info = { "HTMLAnchorElement", &KJS::HTMLElement::info, &HTMLAnchorElementTable, 0 }; +const ClassInfo KJS::HTMLElement::img_info = { "HTMLImageElement", &KJS::HTMLElement::info, &HTMLImageElementTable, 0 }; +const ClassInfo KJS::HTMLElement::object_info = { "HTMLObjectElement", &KJS::HTMLElement::info, &HTMLObjectElementTable, 0 }; +const ClassInfo KJS::HTMLElement::param_info = { "HTMLParamElement", &KJS::HTMLElement::info, &HTMLParamElementTable, 0 }; +const ClassInfo KJS::HTMLElement::applet_info = { "HTMLAppletElement", &KJS::HTMLElement::info, &HTMLAppletElementTable, 0 }; +const ClassInfo KJS::HTMLElement::map_info = { "HTMLMapElement", &KJS::HTMLElement::info, &HTMLMapElementTable, 0 }; +const ClassInfo KJS::HTMLElement::area_info = { "HTMLAreaElement", &KJS::HTMLElement::info, &HTMLAreaElementTable, 0 }; +const ClassInfo KJS::HTMLElement::script_info = { "HTMLScriptElement", &KJS::HTMLElement::info, &HTMLScriptElementTable, 0 }; +const ClassInfo KJS::HTMLElement::table_info = { "HTMLTableElement", &KJS::HTMLElement::info, &HTMLTableElementTable, 0 }; +const ClassInfo KJS::HTMLElement::caption_info = { "HTMLTableCaptionElement", &KJS::HTMLElement::info, &HTMLTableCaptionElementTable, 0 }; +const ClassInfo KJS::HTMLElement::col_info = { "HTMLTableColElement", &KJS::HTMLElement::info, &HTMLTableColElementTable, 0 }; +const ClassInfo KJS::HTMLElement::tablesection_info = { "HTMLTableSectionElement", &KJS::HTMLElement::info, &HTMLTableSectionElementTable, 0 }; +const ClassInfo KJS::HTMLElement::tr_info = { "HTMLTableRowElement", &KJS::HTMLElement::info, &HTMLTableRowElementTable, 0 }; +const ClassInfo KJS::HTMLElement::tablecell_info = { "HTMLTableCellElement", &KJS::HTMLElement::info, &HTMLTableCellElementTable, 0 }; +const ClassInfo KJS::HTMLElement::frameSet_info = { "HTMLFrameSetElement", &KJS::HTMLElement::info, &HTMLFrameSetElementTable, 0 }; +const ClassInfo KJS::HTMLElement::frame_info = { "HTMLFrameElement", &KJS::HTMLElement::info, &HTMLFrameElementTable, 0 }; +const ClassInfo KJS::HTMLElement::iFrame_info = { "HTMLIFrameElement", &KJS::HTMLElement::info, &HTMLIFrameElementTable, 0 }; +const ClassInfo KJS::HTMLElement::marquee_info = { "HTMLMarqueeElement", &KJS::HTMLElement::info, 0, 0 }; +const ClassInfo KJS::HTMLElement::layer_info = { "HTMLLayerElement", &KJS::HTMLElement::info, &HTMLLayerElementTable, 0 }; + +static Object prototypeForID(ExecState* exec, DOM::NodeImpl::Id id); + +KJS::HTMLElement::HTMLElement(ExecState *exec, const DOM::HTMLElement& e) : + DOMElement(prototypeForID(exec, e.elementId()), e) { } + +const ClassInfo* KJS::HTMLElement::classInfo() const +{ + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); + switch (element.elementId()) { + case ID_HTML: + return &html_info; + case ID_HEAD: + return &head_info; + case ID_LINK: + return &link_info; + case ID_TITLE: + return &title_info; + case ID_META: + return &meta_info; + case ID_BASE: + return &base_info; + case ID_ISINDEX: + return &isIndex_info; + case ID_STYLE: + return &style_info; + case ID_BODY: + return &body_info; + case ID_FORM: + return &form_info; + case ID_SELECT: + return &select_info; + case ID_OPTGROUP: + return &optGroup_info; + case ID_OPTION: + return &option_info; + case ID_INPUT: + return &input_info; + case ID_TEXTAREA: + return &textArea_info; + case ID_BUTTON: + return &button_info; + case ID_LABEL: + return &label_info; + case ID_FIELDSET: + return &fieldSet_info; + case ID_LEGEND: + return &legend_info; + case ID_UL: + return &ul_info; + case ID_OL: + return &ol_info; + case ID_DL: + return &dl_info; + case ID_DIR: + return &dir_info; + case ID_MENU: + return &menu_info; + case ID_LI: + return &li_info; + case ID_DIV: + return &div_info; + case ID_P: + return &p_info; + case ID_H1: + case ID_H2: + case ID_H3: + case ID_H4: + case ID_H5: + case ID_H6: + return &heading_info; + case ID_BLOCKQUOTE: + return &blockQuote_info; + case ID_Q: + return &q_info; + case ID_PRE: + return &pre_info; + case ID_BR: + return &br_info; + case ID_BASEFONT: + return &baseFont_info; + case ID_FONT: + return &font_info; + case ID_HR: + return &hr_info; + case ID_INS: + case ID_DEL: + return &mod_info; + case ID_A: + return &a_info; + case ID_IMG: + return &img_info; + case ID_OBJECT: + return &object_info; + case ID_PARAM: + return ¶m_info; + case ID_APPLET: + return &applet_info; + case ID_MAP: + return &map_info; + case ID_AREA: + return &area_info; + case ID_SCRIPT: + return &script_info; + case ID_TABLE: + return &table_info; + case ID_CAPTION: + return &caption_info; + case ID_COL: + case ID_COLGROUP: + return &col_info; + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: + return &tablesection_info; + case ID_TR: + return &tr_info; + case ID_TH: + case ID_TD: + return &tablecell_info; + case ID_FRAMESET: + return &frameSet_info; + case ID_FRAME: + return &frame_info; + case ID_IFRAME: + return &iFrame_info; + case ID_MARQUEE: + return &marquee_info; + case ID_LAYER: + return &layer_info; + default: + return &info; + } +} +/* +@begin HTMLElementTable 11 + id KJS::HTMLElement::ElementId DontDelete + title KJS::HTMLElement::ElementTitle DontDelete + lang KJS::HTMLElement::ElementLang DontDelete + dir KJS::HTMLElement::ElementDir DontDelete +### isn't this "class" in the HTML spec? + className KJS::HTMLElement::ElementClassName DontDelete + innerHTML KJS::HTMLElement::ElementInnerHTML DontDelete + innerText KJS::HTMLElement::ElementInnerText DontDelete + document KJS::HTMLElement::ElementDocument DontDelete|ReadOnly +# IE extension + children KJS::HTMLElement::ElementChildren DontDelete|ReadOnly + all KJS::HTMLElement::ElementAll DontDelete|ReadOnly +@end +@begin HTMLElementProtoTable 1 + scrollIntoView KJS::HTMLElement::ElementScrollIntoView DontDelete|Function 0 +@end +@begin HTMLHtmlElementTable 1 + version KJS::HTMLElement::HtmlVersion DontDelete +@end +@begin HTMLHeadElementTable 1 + profile KJS::HTMLElement::HeadProfile DontDelete +@end +@begin HTMLLinkElementTable 11 + disabled KJS::HTMLElement::LinkDisabled DontDelete + charset KJS::HTMLElement::LinkCharset DontDelete + href KJS::HTMLElement::LinkHref DontDelete + hreflang KJS::HTMLElement::LinkHrefLang DontDelete + media KJS::HTMLElement::LinkMedia DontDelete + rel KJS::HTMLElement::LinkRel DontDelete + rev KJS::HTMLElement::LinkRev DontDelete + target KJS::HTMLElement::LinkTarget DontDelete + type KJS::HTMLElement::LinkType DontDelete + sheet KJS::HTMLElement::LinkSheet DontDelete|ReadOnly +@end +@begin HTMLTitleElementTable 1 + text KJS::HTMLElement::TitleText DontDelete +@end +@begin HTMLMetaElementTable 4 + content KJS::HTMLElement::MetaContent DontDelete + httpEquiv KJS::HTMLElement::MetaHttpEquiv DontDelete + name KJS::HTMLElement::MetaName DontDelete + scheme KJS::HTMLElement::MetaScheme DontDelete +@end +@begin HTMLBaseElementTable 2 + href KJS::HTMLElement::BaseHref DontDelete + target KJS::HTMLElement::BaseTarget DontDelete +@end +@begin HTMLIsIndexElementTable 2 + form KJS::HTMLElement::IsIndexForm DontDelete|ReadOnly + prompt KJS::HTMLElement::IsIndexPrompt DontDelete +@end +@begin HTMLStyleElementTable 4 + disabled KJS::HTMLElement::StyleDisabled DontDelete + media KJS::HTMLElement::StyleMedia DontDelete + type KJS::HTMLElement::StyleType DontDelete + sheet KJS::HTMLElement::StyleSheet DontDelete|ReadOnly +@end +@begin HTMLBodyElementTable 8 + aLink KJS::HTMLElement::BodyALink DontDelete + background KJS::HTMLElement::BodyBackground DontDelete + bgColor KJS::HTMLElement::BodyBgColor DontDelete + link KJS::HTMLElement::BodyLink DontDelete + text KJS::HTMLElement::BodyText DontDelete + vLink KJS::HTMLElement::BodyVLink DontDelete +# IE extension + onload KJS::HTMLElement::BodyOnLoad DontDelete +@end +@begin HTMLBodyElementProtoTable 2 +# Mozilla'ish extension. Ideally we would want to support this on all elements. +# Not hard, but not an immediate need. + focus KJS::HTMLElement::BodyFocus DontDelete|Function 0 +@end +@begin HTMLFormElementTable 11 +# Also supported, by name/index + elements KJS::HTMLElement::FormElements DontDelete|ReadOnly + length KJS::HTMLElement::FormLength DontDelete|ReadOnly + name KJS::HTMLElement::FormName DontDelete + acceptCharset KJS::HTMLElement::FormAcceptCharset DontDelete + action KJS::HTMLElement::FormAction DontDelete + encoding KJS::HTMLElement::FormEncType DontDelete + enctype KJS::HTMLElement::FormEncType DontDelete + method KJS::HTMLElement::FormMethod DontDelete + target KJS::HTMLElement::FormTarget DontDelete +@end +@begin HTMLFormElementProtoTable 2 + submit KJS::HTMLElement::FormSubmit DontDelete|Function 0 + reset KJS::HTMLElement::FormReset DontDelete|Function 0 +@end +@begin HTMLSelectElementTable 11 +# Also supported, by index + type KJS::HTMLElement::SelectType DontDelete|ReadOnly + selectedIndex KJS::HTMLElement::SelectSelectedIndex DontDelete + value KJS::HTMLElement::SelectValue DontDelete + length KJS::HTMLElement::SelectLength DontDelete + form KJS::HTMLElement::SelectForm DontDelete|ReadOnly + options KJS::HTMLElement::SelectOptions DontDelete|ReadOnly + disabled KJS::HTMLElement::SelectDisabled DontDelete + multiple KJS::HTMLElement::SelectMultiple DontDelete + name KJS::HTMLElement::SelectName DontDelete + size KJS::HTMLElement::SelectSize DontDelete + tabIndex KJS::HTMLElement::SelectTabIndex DontDelete +@end +@begin HTMLSelectElementProtoTable 4 + add KJS::HTMLElement::SelectAdd DontDelete|Function 2 + remove KJS::HTMLElement::SelectRemove DontDelete|Function 1 + blur KJS::HTMLElement::SelectBlur DontDelete|Function 0 + focus KJS::HTMLElement::SelectFocus DontDelete|Function 0 +@end +@begin HTMLOptGroupElementTable 2 + disabled KJS::HTMLElement::OptGroupDisabled DontDelete + label KJS::HTMLElement::OptGroupLabel DontDelete +@end +@begin HTMLOptionElementTable 8 + form KJS::HTMLElement::OptionForm DontDelete|ReadOnly + defaultSelected KJS::HTMLElement::OptionDefaultSelected DontDelete + text KJS::HTMLElement::OptionText DontDelete + index KJS::HTMLElement::OptionIndex DontDelete|ReadOnly + disabled KJS::HTMLElement::OptionDisabled DontDelete + label KJS::HTMLElement::OptionLabel DontDelete + selected KJS::HTMLElement::OptionSelected DontDelete + value KJS::HTMLElement::OptionValue DontDelete +@end +@begin HTMLInputElementTable 25 + defaultValue KJS::HTMLElement::InputDefaultValue DontDelete + defaultChecked KJS::HTMLElement::InputDefaultChecked DontDelete + form KJS::HTMLElement::InputForm DontDelete|ReadOnly + accept KJS::HTMLElement::InputAccept DontDelete + accessKey KJS::HTMLElement::InputAccessKey DontDelete + align KJS::HTMLElement::InputAlign DontDelete + alt KJS::HTMLElement::InputAlt DontDelete + checked KJS::HTMLElement::InputChecked DontDelete + indeterminate KJS::HTMLElement::InputIndeterminate DontDelete + status KJS::HTMLElement::InputChecked DontDelete + disabled KJS::HTMLElement::InputDisabled DontDelete + maxLength KJS::HTMLElement::InputMaxLength DontDelete + name KJS::HTMLElement::InputName DontDelete + readOnly KJS::HTMLElement::InputReadOnly DontDelete + size KJS::HTMLElement::InputSize DontDelete + src KJS::HTMLElement::InputSrc DontDelete + tabIndex KJS::HTMLElement::InputTabIndex DontDelete + type KJS::HTMLElement::InputType DontDelete + useMap KJS::HTMLElement::InputUseMap DontDelete + value KJS::HTMLElement::InputValue DontDelete + selectionStart KJS::HTMLElement::InputSelectionStart DontDelete + selectionEnd KJS::HTMLElement::InputSelectionEnd DontDelete +@end +@begin HTMLInputElementProtoTable 5 + blur KJS::HTMLElement::InputBlur DontDelete|Function 0 + focus KJS::HTMLElement::InputFocus DontDelete|Function 0 + select KJS::HTMLElement::InputSelect DontDelete|Function 0 + click KJS::HTMLElement::InputClick DontDelete|Function 0 + setSelectionRange KJS::HTMLElement::InputSetSelectionRange DontDelete|Function 2 +@end +@begin HTMLTextAreaElementTable 13 + defaultValue KJS::HTMLElement::TextAreaDefaultValue DontDelete + form KJS::HTMLElement::TextAreaForm DontDelete|ReadOnly + accessKey KJS::HTMLElement::TextAreaAccessKey DontDelete + cols KJS::HTMLElement::TextAreaCols DontDelete + disabled KJS::HTMLElement::TextAreaDisabled DontDelete + name KJS::HTMLElement::TextAreaName DontDelete + readOnly KJS::HTMLElement::TextAreaReadOnly DontDelete + rows KJS::HTMLElement::TextAreaRows DontDelete + tabIndex KJS::HTMLElement::TextAreaTabIndex DontDelete + type KJS::HTMLElement::TextAreaType DontDelete|ReadOnly + value KJS::HTMLElement::TextAreaValue DontDelete + selectionStart KJS::HTMLElement::TextAreaSelectionStart DontDelete + selectionEnd KJS::HTMLElement::TextAreaSelectionEnd DontDelete + textLength KJS::HTMLElement::TextAreaTextLength DontDelete|ReadOnly +@end +@begin HTMLTextAreaElementProtoTable 4 + blur KJS::HTMLElement::TextAreaBlur DontDelete|Function 0 + focus KJS::HTMLElement::TextAreaFocus DontDelete|Function 0 + select KJS::HTMLElement::TextAreaSelect DontDelete|Function 0 + setSelectionRange KJS::HTMLElement::TextAreaSetSelectionRange DontDelete|Function 2 +@end +@begin HTMLButtonElementTable 9 + form KJS::HTMLElement::ButtonForm DontDelete|ReadOnly + accessKey KJS::HTMLElement::ButtonAccessKey DontDelete + disabled KJS::HTMLElement::ButtonDisabled DontDelete + name KJS::HTMLElement::ButtonName DontDelete + tabIndex KJS::HTMLElement::ButtonTabIndex DontDelete + type KJS::HTMLElement::ButtonType DontDelete|ReadOnly + value KJS::HTMLElement::ButtonValue DontDelete +@end +@begin HTMLButtonElementProtoTable 2 + blur KJS::HTMLElement::ButtonBlur DontDelete|Function 0 + focus KJS::HTMLElement::ButtonFocus DontDelete|Function 0 +@end +@begin HTMLLabelElementTable 3 + form KJS::HTMLElement::LabelForm DontDelete|ReadOnly + accessKey KJS::HTMLElement::LabelAccessKey DontDelete + htmlFor KJS::HTMLElement::LabelHtmlFor DontDelete +@end +@begin HTMLFieldSetElementTable 1 + form KJS::HTMLElement::FieldSetForm DontDelete|ReadOnly +@end +@begin HTMLLegendElementTable 3 + form KJS::HTMLElement::LegendForm DontDelete|ReadOnly + accessKey KJS::HTMLElement::LegendAccessKey DontDelete + align KJS::HTMLElement::LegendAlign DontDelete +@end +@begin HTMLUListElementTable 2 + compact KJS::HTMLElement::UListCompact DontDelete + type KJS::HTMLElement::UListType DontDelete +@end +@begin HTMLOListElementTable 3 + compact KJS::HTMLElement::OListCompact DontDelete + start KJS::HTMLElement::OListStart DontDelete + type KJS::HTMLElement::OListType DontDelete +@end +@begin HTMLDListElementTable 1 + compact KJS::HTMLElement::DListCompact DontDelete +@end +@begin HTMLDirectoryElementTable 1 + compact KJS::HTMLElement::DirectoryCompact DontDelete +@end +@begin HTMLMenuElementTable 1 + compact KJS::HTMLElement::MenuCompact DontDelete +@end +@begin HTMLLIElementTable 2 + type KJS::HTMLElement::LIType DontDelete + value KJS::HTMLElement::LIValue DontDelete +@end +@begin HTMLDivElementTable 1 + align KJS::HTMLElement::DivAlign DontDelete +@end +@begin HTMLParagraphElementTable 1 + align KJS::HTMLElement::ParagraphAlign DontDelete +@end +@begin HTMLHeadingElementTable 1 + align KJS::HTMLElement::HeadingAlign DontDelete +@end +@begin HTMLBlockQuoteElementTable 1 + cite KJS::HTMLElement::BlockQuoteCite DontDelete +@end +@begin HTMLQuoteElementTable 1 + cite KJS::HTMLElement::QuoteCite DontDelete +@end +@begin HTMLPreElementTable 1 + width KJS::HTMLElement::PreWidth DontDelete +@end +@begin HTMLBRElementTable 1 + clear KJS::HTMLElement::BRClear DontDelete +@end +@begin HTMLBaseFontElementTable 3 + color KJS::HTMLElement::BaseFontColor DontDelete + face KJS::HTMLElement::BaseFontFace DontDelete + size KJS::HTMLElement::BaseFontSize DontDelete +@end +@begin HTMLFontElementTable 3 + color KJS::HTMLElement::FontColor DontDelete + face KJS::HTMLElement::FontFace DontDelete + size KJS::HTMLElement::FontSize DontDelete +@end +@begin HTMLHRElementTable 4 + align KJS::HTMLElement::HRAlign DontDelete + noShade KJS::HTMLElement::HRNoShade DontDelete + size KJS::HTMLElement::HRSize DontDelete + width KJS::HTMLElement::HRWidth DontDelete +@end +@begin HTMLModElementTable 2 + cite KJS::HTMLElement::ModCite DontDelete + dateTime KJS::HTMLElement::ModDateTime DontDelete +@end +@begin HTMLAnchorElementTable 23 + accessKey KJS::HTMLElement::AnchorAccessKey DontDelete + charset KJS::HTMLElement::AnchorCharset DontDelete + coords KJS::HTMLElement::AnchorCoords DontDelete + href KJS::HTMLElement::AnchorHref DontDelete + hreflang KJS::HTMLElement::AnchorHrefLang DontDelete + hash KJS::HTMLElement::AnchorHash DontDelete|ReadOnly + host KJS::HTMLElement::AnchorHost DontDelete|ReadOnly + hostname KJS::HTMLElement::AnchorHostname DontDelete|ReadOnly + name KJS::HTMLElement::AnchorName DontDelete + pathname KJS::HTMLElement::AnchorPathName DontDelete|ReadOnly + port KJS::HTMLElement::AnchorPort DontDelete|ReadOnly + protocol KJS::HTMLElement::AnchorProtocol DontDelete|ReadOnly + rel KJS::HTMLElement::AnchorRel DontDelete + rev KJS::HTMLElement::AnchorRev DontDelete + search KJS::HTMLElement::AnchorSearch DontDelete + shape KJS::HTMLElement::AnchorShape DontDelete + tabIndex KJS::HTMLElement::AnchorTabIndex DontDelete + target KJS::HTMLElement::AnchorTarget DontDelete + text KJS::HTMLElement::AnchorText DontDelete|ReadOnly + type KJS::HTMLElement::AnchorType DontDelete +@end +@begin HTMLAnchorElementProtoTable 3 + blur KJS::HTMLElement::AnchorBlur DontDelete|Function 0 + focus KJS::HTMLElement::AnchorFocus DontDelete|Function 0 + click KJS::HTMLElement::AnchorClick DontDelete|Function 0 +@end +@begin HTMLImageElementTable 15 + name KJS::HTMLElement::ImageName DontDelete + align KJS::HTMLElement::ImageAlign DontDelete + alt KJS::HTMLElement::ImageAlt DontDelete + border KJS::HTMLElement::ImageBorder DontDelete + complete KJS::HTMLElement::ImageComplete DontDelete|ReadOnly + height KJS::HTMLElement::ImageHeight DontDelete + hspace KJS::HTMLElement::ImageHspace DontDelete + isMap KJS::HTMLElement::ImageIsMap DontDelete + longDesc KJS::HTMLElement::ImageLongDesc DontDelete + src KJS::HTMLElement::ImageSrc DontDelete + useMap KJS::HTMLElement::ImageUseMap DontDelete + vspace KJS::HTMLElement::ImageVspace DontDelete + width KJS::HTMLElement::ImageWidth DontDelete + x KJS::HTMLElement::ImageX DontDelete|ReadOnly + y KJS::HTMLElement::ImageY DontDelete|ReadOnly +@end +@begin HTMLObjectElementTable 20 + form KJS::HTMLElement::ObjectForm DontDelete|ReadOnly + code KJS::HTMLElement::ObjectCode DontDelete + align KJS::HTMLElement::ObjectAlign DontDelete + archive KJS::HTMLElement::ObjectArchive DontDelete + border KJS::HTMLElement::ObjectBorder DontDelete + codeBase KJS::HTMLElement::ObjectCodeBase DontDelete + codeType KJS::HTMLElement::ObjectCodeType DontDelete + contentDocument KJS::HTMLElement::ObjectContentDocument DontDelete|ReadOnly + data KJS::HTMLElement::ObjectData DontDelete + declare KJS::HTMLElement::ObjectDeclare DontDelete + height KJS::HTMLElement::ObjectHeight DontDelete + hspace KJS::HTMLElement::ObjectHspace DontDelete + name KJS::HTMLElement::ObjectName DontDelete + standby KJS::HTMLElement::ObjectStandby DontDelete + tabIndex KJS::HTMLElement::ObjectTabIndex DontDelete + type KJS::HTMLElement::ObjectType DontDelete + useMap KJS::HTMLElement::ObjectUseMap DontDelete + vspace KJS::HTMLElement::ObjectVspace DontDelete + width KJS::HTMLElement::ObjectWidth DontDelete +@end +@begin HTMLParamElementTable 4 + name KJS::HTMLElement::ParamName DontDelete + type KJS::HTMLElement::ParamType DontDelete + value KJS::HTMLElement::ParamValue DontDelete + valueType KJS::HTMLElement::ParamValueType DontDelete +@end +@begin HTMLAppletElementTable 11 + align KJS::HTMLElement::AppletAlign DontDelete + alt KJS::HTMLElement::AppletAlt DontDelete + archive KJS::HTMLElement::AppletArchive DontDelete + code KJS::HTMLElement::AppletCode DontDelete + codeBase KJS::HTMLElement::AppletCodeBase DontDelete + height KJS::HTMLElement::AppletHeight DontDelete + hspace KJS::HTMLElement::AppletHspace DontDelete + name KJS::HTMLElement::AppletName DontDelete + object KJS::HTMLElement::AppletObject DontDelete + vspace KJS::HTMLElement::AppletVspace DontDelete + width KJS::HTMLElement::AppletWidth DontDelete +@end +@begin HTMLMapElementTable 2 + areas KJS::HTMLElement::MapAreas DontDelete|ReadOnly + name KJS::HTMLElement::MapName DontDelete +@end +@begin HTMLAreaElementTable 15 + accessKey KJS::HTMLElement::AreaAccessKey DontDelete + alt KJS::HTMLElement::AreaAlt DontDelete + coords KJS::HTMLElement::AreaCoords DontDelete + href KJS::HTMLElement::AreaHref DontDelete + hash KJS::HTMLElement::AreaHash DontDelete|ReadOnly + host KJS::HTMLElement::AreaHost DontDelete|ReadOnly + hostname KJS::HTMLElement::AreaHostName DontDelete|ReadOnly + pathname KJS::HTMLElement::AreaPathName DontDelete|ReadOnly + port KJS::HTMLElement::AreaPort DontDelete|ReadOnly + protocol KJS::HTMLElement::AreaProtocol DontDelete|ReadOnly + search KJS::HTMLElement::AreaSearch DontDelete|ReadOnly + noHref KJS::HTMLElement::AreaNoHref DontDelete + shape KJS::HTMLElement::AreaShape DontDelete + tabIndex KJS::HTMLElement::AreaTabIndex DontDelete + target KJS::HTMLElement::AreaTarget DontDelete +@end +@begin HTMLScriptElementTable 7 + text KJS::HTMLElement::ScriptText DontDelete + htmlFor KJS::HTMLElement::ScriptHtmlFor DontDelete + event KJS::HTMLElement::ScriptEvent DontDelete + charset KJS::HTMLElement::ScriptCharset DontDelete + defer KJS::HTMLElement::ScriptDefer DontDelete + src KJS::HTMLElement::ScriptSrc DontDelete + type KJS::HTMLElement::ScriptType DontDelete +@end +@begin HTMLTableElementTable 23 + caption KJS::HTMLElement::TableCaption DontDelete + tHead KJS::HTMLElement::TableTHead DontDelete + tFoot KJS::HTMLElement::TableTFoot DontDelete + rows KJS::HTMLElement::TableRows DontDelete|ReadOnly + tBodies KJS::HTMLElement::TableTBodies DontDelete|ReadOnly + align KJS::HTMLElement::TableAlign DontDelete + bgColor KJS::HTMLElement::TableBgColor DontDelete + border KJS::HTMLElement::TableBorder DontDelete + cellPadding KJS::HTMLElement::TableCellPadding DontDelete + cellSpacing KJS::HTMLElement::TableCellSpacing DontDelete + frame KJS::HTMLElement::TableFrame DontDelete + rules KJS::HTMLElement::TableRules DontDelete + summary KJS::HTMLElement::TableSummary DontDelete + width KJS::HTMLElement::TableWidth DontDelete +@end +@begin HTMLTableElementProtoTable 8 + createTHead KJS::HTMLElement::TableCreateTHead DontDelete|Function 0 + deleteTHead KJS::HTMLElement::TableDeleteTHead DontDelete|Function 0 + createTFoot KJS::HTMLElement::TableCreateTFoot DontDelete|Function 0 + deleteTFoot KJS::HTMLElement::TableDeleteTFoot DontDelete|Function 0 + createCaption KJS::HTMLElement::TableCreateCaption DontDelete|Function 0 + deleteCaption KJS::HTMLElement::TableDeleteCaption DontDelete|Function 0 + insertRow KJS::HTMLElement::TableInsertRow DontDelete|Function 1 + deleteRow KJS::HTMLElement::TableDeleteRow DontDelete|Function 1 +@end +@begin HTMLTableCaptionElementTable 1 + align KJS::HTMLElement::TableCaptionAlign DontDelete +@end +@begin HTMLTableColElementTable 7 + align KJS::HTMLElement::TableColAlign DontDelete + ch KJS::HTMLElement::TableColCh DontDelete + chOff KJS::HTMLElement::TableColChOff DontDelete + span KJS::HTMLElement::TableColSpan DontDelete + vAlign KJS::HTMLElement::TableColVAlign DontDelete + width KJS::HTMLElement::TableColWidth DontDelete +@end +@begin HTMLTableSectionElementTable 7 + align KJS::HTMLElement::TableSectionAlign DontDelete + ch KJS::HTMLElement::TableSectionCh DontDelete + chOff KJS::HTMLElement::TableSectionChOff DontDelete + vAlign KJS::HTMLElement::TableSectionVAlign DontDelete + rows KJS::HTMLElement::TableSectionRows DontDelete|ReadOnly +@end +@begin HTMLTableSectionElementProtoTable 2 + insertRow KJS::HTMLElement::TableSectionInsertRow DontDelete|Function 1 + deleteRow KJS::HTMLElement::TableSectionDeleteRow DontDelete|Function 1 +@end +@begin HTMLTableRowElementTable 11 + rowIndex KJS::HTMLElement::TableRowRowIndex DontDelete|ReadOnly + sectionRowIndex KJS::HTMLElement::TableRowSectionRowIndex DontDelete|ReadOnly + cells KJS::HTMLElement::TableRowCells DontDelete|ReadOnly + align KJS::HTMLElement::TableRowAlign DontDelete + bgColor KJS::HTMLElement::TableRowBgColor DontDelete + ch KJS::HTMLElement::TableRowCh DontDelete + chOff KJS::HTMLElement::TableRowChOff DontDelete + vAlign KJS::HTMLElement::TableRowVAlign DontDelete +@end +@begin HTMLTableRowElementProtoTable 2 + insertCell KJS::HTMLElement::TableRowInsertCell DontDelete|Function 1 + deleteCell KJS::HTMLElement::TableRowDeleteCell DontDelete|Function 1 +@end +@begin HTMLTableCellElementTable 15 + cellIndex KJS::HTMLElement::TableCellCellIndex DontDelete|ReadOnly + abbr KJS::HTMLElement::TableCellAbbr DontDelete + align KJS::HTMLElement::TableCellAlign DontDelete + axis KJS::HTMLElement::TableCellAxis DontDelete + bgColor KJS::HTMLElement::TableCellBgColor DontDelete + ch KJS::HTMLElement::TableCellCh DontDelete + chOff KJS::HTMLElement::TableCellChOff DontDelete + colSpan KJS::HTMLElement::TableCellColSpan DontDelete + headers KJS::HTMLElement::TableCellHeaders DontDelete + height KJS::HTMLElement::TableCellHeight DontDelete + noWrap KJS::HTMLElement::TableCellNoWrap DontDelete + rowSpan KJS::HTMLElement::TableCellRowSpan DontDelete + scope KJS::HTMLElement::TableCellScope DontDelete + vAlign KJS::HTMLElement::TableCellVAlign DontDelete + width KJS::HTMLElement::TableCellWidth DontDelete +@end +@begin HTMLFrameSetElementTable 2 + cols KJS::HTMLElement::FrameSetCols DontDelete + rows KJS::HTMLElement::FrameSetRows DontDelete +@end +@begin HTMLLayerElementTable 6 + top KJS::HTMLElement::LayerTop DontDelete + left KJS::HTMLElement::LayerLeft DontDelete + visibility KJS::HTMLElement::LayerVisibility DontDelete + bgColor KJS::HTMLElement::LayerBgColor DontDelete + document KJS::HTMLElement::LayerDocument DontDelete|ReadOnly + clip KJS::HTMLElement::LayerClip DontDelete|ReadOnly + layers KJS::HTMLElement::LayerLayers DontDelete|ReadOnly +@end +@begin HTMLFrameElementTable 13 + contentDocument KJS::HTMLElement::FrameContentDocument DontDelete|ReadOnly + contentWindow KJS::HTMLElement::FrameContentWindow DontDelete|ReadOnly + frameBorder KJS::HTMLElement::FrameFrameBorder DontDelete + longDesc KJS::HTMLElement::FrameLongDesc DontDelete + marginHeight KJS::HTMLElement::FrameMarginHeight DontDelete + marginWidth KJS::HTMLElement::FrameMarginWidth DontDelete + name KJS::HTMLElement::FrameName DontDelete + noResize KJS::HTMLElement::FrameNoResize DontDelete + scrolling KJS::HTMLElement::FrameScrolling DontDelete + src KJS::HTMLElement::FrameSrc DontDelete + location KJS::HTMLElement::FrameLocation DontDelete +# IE extension + width KJS::HTMLElement::FrameWidth DontDelete|ReadOnly + height KJS::HTMLElement::FrameHeight DontDelete|ReadOnly +@end +@begin HTMLIFrameElementTable 12 + align KJS::HTMLElement::IFrameAlign DontDelete + contentDocument KJS::HTMLElement::IFrameContentDocument DontDelete|ReadOnly + contentWindow KJS::HTMLElement::IFrameContentWindow DontDelete|ReadOnly + frameBorder KJS::HTMLElement::IFrameFrameBorder DontDelete + height KJS::HTMLElement::IFrameHeight DontDelete + longDesc KJS::HTMLElement::IFrameLongDesc DontDelete + marginHeight KJS::HTMLElement::IFrameMarginHeight DontDelete + marginWidth KJS::HTMLElement::IFrameMarginWidth DontDelete + name KJS::HTMLElement::IFrameName DontDelete + scrolling KJS::HTMLElement::IFrameScrolling DontDelete + src KJS::HTMLElement::IFrameSrc DontDelete + width KJS::HTMLElement::IFrameWidth DontDelete +@end + +@begin HTMLMarqueeElementProtoTable 2 + start KJS::HTMLElement::MarqueeStart DontDelete|Function 0 + stop KJS::HTMLElement::MarqueeStop DontDelete|Function 0 +@end + +*/ + +static KParts::LiveConnectExtension *getLiveConnectExtension(const DOM::HTMLElement & element) +{ + DOM::HTMLDocument doc = element.ownerDocument(); + KHTMLView *view = static_cast<DOM::DocumentImpl*>(doc.handle())->view(); + if (view && element.handle()) + return view->part()->liveConnectExtension(static_cast<khtml::RenderPart*>(element.handle()->renderer())); + return 0L; +} + +Value KJS::HTMLElement::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLElement::tryGet " << propertyName.qstring() << " thisTag=" << element.tagName().string() << endl; +#endif + // First look at dynamic properties + switch (element.elementId()) { + case ID_FORM: { + DOM::HTMLFormElement form = element; + // Check if we're retrieving an element (by index or by name) + bool ok; + uint u = propertyName.toULong(&ok); + + if (ok) + return getDOMNode(exec,form.elements().item(u)); + KJS::HTMLCollection coll(exec, form.elements()); + Value namedItems = coll.getNamedItems(exec, propertyName); + if (namedItems.type() != UndefinedType) + return namedItems; + } + break; + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + bool ok; + uint u = propertyName.toULong(&ok); + if (ok) + return getDOMNode(exec,select.options().item(u)); // not specified by DOM(?) but supported in netscape/IE + } + break; + case ID_APPLET: + case ID_OBJECT: + case ID_EMBED: { + KParts::LiveConnectExtension *lc = getLiveConnectExtension(element); + QString rvalue; + KParts::LiveConnectExtension::Type rtype; + unsigned long robjid; + if (lc && lc->get(0, propertyName.qstring(), rtype, robjid, rvalue)) + return getLiveConnectValue(lc, propertyName.qstring(), rtype, rvalue, robjid); + } + break; + default: + break; + } + + const HashTable* table = classInfo()->propHashTable; // get the right hashtable + const HashEntry* entry = table ? Lookup::findEntry(table, propertyName) : 0; + if (entry) { + if (entry->attr & Function) + return lookupOrCreateFunction<KJS::HTMLElementFunction>(exec, propertyName, this, entry->value, entry->params, entry->attr); + return getValueProperty(exec, entry->value); + } + + // Base HTMLElement stuff or parent class forward, as usual + return DOMObjectLookupGet<KJS::HTMLElementFunction, KJS::HTMLElement, DOMElement>(exec, propertyName, &KJS::HTMLElementTable, this); +} + +Value KJS::HTMLElement::getValueProperty(ExecState *exec, int token) const +{ + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); + switch (element.elementId()) { + case ID_HTML: { + DOM::HTMLHtmlElement html = element; + if (token == HtmlVersion) return String(html.version()); + } + break; + case ID_HEAD: { + DOM::HTMLHeadElement head = element; + if (token == HeadProfile) return String(head.profile()); + } + break; + case ID_LINK: { + DOM::HTMLLinkElement link = element; + switch (token) { + case LinkDisabled: return Boolean(link.disabled()); + case LinkCharset: return String(link.charset()); + case LinkHref: return String(link.href()); + case LinkHrefLang: return String(link.hreflang()); + case LinkMedia: return String(link.media()); + case LinkRel: return String(link.rel()); + case LinkRev: return String(link.rev()); + case LinkTarget: return String(link.target()); + case LinkType: return String(link.type()); + case LinkSheet: return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet()); + } + } + break; + case ID_TITLE: { + DOM::HTMLTitleElement title = element; + switch (token) { + case TitleText: return String(title.text()); + } + } + break; + case ID_META: { + DOM::HTMLMetaElement meta = element; + switch (token) { + case MetaContent: return String(meta.content()); + case MetaHttpEquiv: return String(meta.httpEquiv()); + case MetaName: return String(meta.name()); + case MetaScheme: return String(meta.scheme()); + } + } + break; + case ID_BASE: { + DOM::HTMLBaseElement base = element; + switch (token) { + case BaseHref: return String(base.href()); + case BaseTarget: return String(base.target()); + } + } + break; + case ID_ISINDEX: { + DOM::HTMLIsIndexElement isindex = element; + switch (token) { + case IsIndexForm: return getDOMNode(exec,isindex.form()); // type HTMLFormElement + case IsIndexPrompt: return String(isindex.prompt()); + } + } + break; + case ID_STYLE: { + DOM::HTMLStyleElement style = element; + switch (token) { + case StyleDisabled: return Boolean(style.disabled()); + case StyleMedia: return String(style.media()); + case StyleType: return String(style.type()); + case StyleSheet: return getDOMStyleSheet(exec,style.sheet()); + } + } + break; + case ID_BODY: { + DOM::HTMLBodyElement body = element; + switch (token) { + case BodyALink: return String(body.aLink()); + case BodyBackground: return String(body.background()); + case BodyBgColor: return String(body.bgColor()); + case BodyLink: return String(body.link()); + case BodyText: return String(body.text()); + case BodyVLink: return String(body.vLink()); + case BodyOnLoad: { + DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(node.ownerDocument().handle()); + if (!doc || !checkNodeSecurity(exec, node)) + return Undefined(); + DOMNode* kjsDocNode = new DOMNode(exec, doc); + // Need to create a Value wrapper to avoid leaking the KJS::DOMNode + Value nodeValue(kjsDocNode); + return kjsDocNode->getListener( DOM::EventImpl::LOAD_EVENT ); + } + } + } + break; + + case ID_FORM: { + DOM::HTMLFormElement form = element; + switch (token) { + case FormElements: return getHTMLCollection(exec,form.elements()); + case FormLength: return Number(form.length()); + case FormName: return String(form.name()); // NOT getString (IE gives empty string) + case FormAcceptCharset: return String(form.acceptCharset()); + case FormAction: return String(form.action()); + case FormEncType: return String(form.enctype()); + case FormMethod: return String(form.method()); + case FormTarget: return String(form.target()); + } + } + break; + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + switch (token) { + case SelectType: return String(select.type()); + case SelectSelectedIndex: return Number(select.selectedIndex()); + case SelectValue: return String(select.value()); + case SelectLength: return Number(select.length()); + case SelectForm: return getDOMNode(exec,select.form()); // type HTMLFormElement + case SelectOptions: return getSelectHTMLCollection(exec, select.options(), select); // type HTMLCollection + case SelectDisabled: return Boolean(select.disabled()); + case SelectMultiple: return Boolean(select.multiple()); + case SelectName: return String(select.name()); + case SelectSize: return Number(select.size()); + case SelectTabIndex: return Number(select.tabIndex()); + } + } + break; + case ID_OPTGROUP: { + DOM::HTMLOptGroupElement optgroup = element; + switch (token) { + case OptGroupDisabled: return Boolean(optgroup.disabled()); + case OptGroupLabel: return String(optgroup.label()); + } + } + break; + case ID_OPTION: { + DOM::HTMLOptionElement option = element; + switch (token) { + case OptionForm: return getDOMNode(exec,option.form()); // type HTMLFormElement + case OptionDefaultSelected: return Boolean(option.defaultSelected()); + case OptionText: return String(option.text()); + case OptionIndex: return Number(option.index()); + case OptionDisabled: return Boolean(option.disabled()); + case OptionLabel: return String(option.label()); + case OptionSelected: return Boolean(option.selected()); + case OptionValue: return String(option.value()); + } + } + break; + case ID_INPUT: { + DOM::HTMLInputElement input = element; + switch (token) { + case InputDefaultValue: return String(input.defaultValue()); + case InputDefaultChecked: return Boolean(input.defaultChecked()); + case InputForm: return getDOMNode(exec,input.form()); // type HTMLFormElement + case InputAccept: return String(input.accept()); + case InputAccessKey: return String(input.accessKey()); + case InputAlign: return String(input.align()); + case InputAlt: return String(input.alt()); + case InputChecked: return Boolean(input.checked()); + case InputIndeterminate: return Boolean(input.indeterminate()); + case InputDisabled: return Boolean(input.disabled()); + case InputMaxLength: return Number(input.maxLength()); + case InputName: return String(input.name()); // NOT getString (IE gives empty string) + case InputReadOnly: return Boolean(input.readOnly()); + case InputSize: return Number(input.getSize()); + case InputSrc: return String(input.src()); + case InputTabIndex: return Number(input.tabIndex()); + case InputType: return String(input.type()); + case InputUseMap: return String(input.useMap()); + case InputValue: return String(input.value()); + case InputSelectionStart: { + long val = input.selectionStart(); + if (val != -1) + return Number(val); + else + return Undefined(); + } + case InputSelectionEnd: { + long val = input.selectionEnd(); + if (val != -1) + return Number(val); + else + return Undefined(); + } + } + } + break; + case ID_TEXTAREA: { + DOM::HTMLTextAreaElement textarea = element; + switch (token) { + case TextAreaDefaultValue: return String(textarea.defaultValue()); + case TextAreaForm: return getDOMNode(exec,textarea.form()); // type HTMLFormElement + case TextAreaAccessKey: return String(textarea.accessKey()); + case TextAreaCols: return Number(textarea.cols()); + case TextAreaDisabled: return Boolean(textarea.disabled()); + case TextAreaName: return String(textarea.name()); + case TextAreaReadOnly: return Boolean(textarea.readOnly()); + case TextAreaRows: return Number(textarea.rows()); + case TextAreaTabIndex: return Number(textarea.tabIndex()); + case TextAreaType: return String(textarea.type()); + case TextAreaValue: return String(textarea.value()); + case TextAreaSelectionStart: return Number(textarea.selectionStart()); + case TextAreaSelectionEnd: return Number(textarea.selectionEnd()); + case TextAreaTextLength: return Number(textarea.textLength()); + } + } + break; + case ID_BUTTON: { + DOM::HTMLButtonElement button = element; + switch (token) { + case ButtonForm: return getDOMNode(exec,button.form()); // type HTMLFormElement + case ButtonAccessKey: return String(button.accessKey()); + case ButtonDisabled: return Boolean(button.disabled()); + case ButtonName: return String(button.name()); + case ButtonTabIndex: return Number(button.tabIndex()); + case ButtonType: return String(button.type()); + case ButtonValue: return String(button.value()); + } + } + break; + case ID_LABEL: { + DOM::HTMLLabelElement label = element; + switch (token) { + case LabelForm: return getDOMNode(exec,label.form()); // type HTMLFormElement + case LabelAccessKey: return String(label.accessKey()); + case LabelHtmlFor: return String(label.htmlFor()); + } + } + break; + case ID_FIELDSET: { + DOM::HTMLFieldSetElement fieldSet = element; + switch (token) { + case FieldSetForm: return getDOMNode(exec,fieldSet.form()); // type HTMLFormElement + } + } + break; + case ID_LEGEND: { + DOM::HTMLLegendElement legend = element; + switch (token) { + case LegendForm: return getDOMNode(exec,legend.form()); // type HTMLFormElement + case LegendAccessKey: return String(legend.accessKey()); + case LegendAlign: return String(legend.align()); + } + } + break; + case ID_UL: { + DOM::HTMLUListElement uList = element; + switch (token) { + case UListCompact: return Boolean(uList.compact()); + case UListType: return String(uList.type()); + } + } + break; + case ID_OL: { + DOM::HTMLOListElement oList = element; + switch (token) { + case OListCompact: return Boolean(oList.compact()); + case OListStart: return Number(oList.start()); + case OListType: return String(oList.type()); + } + } + break; + case ID_DL: { + DOM::HTMLDListElement dList = element; + switch (token) { + case DListCompact: return Boolean(dList.compact()); + } + } + break; + case ID_DIR: { + DOM::HTMLDirectoryElement directory = element; + switch (token) { + case DirectoryCompact: return Boolean(directory.compact()); + } + } + break; + case ID_MENU: { + DOM::HTMLMenuElement menu = element; + switch (token) { + case MenuCompact: return Boolean(menu.compact()); + } + } + break; + case ID_LI: { + DOM::HTMLLIElement li = element; + switch (token) { + case LIType: return String(li.type()); + case LIValue: return Number(li.value()); + } + } + break; + case ID_DIV: { + DOM::HTMLDivElement div = element; + switch (token) { + case DivAlign: return String(div.align()); + } + } + break; + case ID_P: { + DOM::HTMLParagraphElement paragraph = element; + switch (token) { + case ParagraphAlign: return String(paragraph.align()); + } + } + break; + case ID_H1: + case ID_H2: + case ID_H3: + case ID_H4: + case ID_H5: + case ID_H6: { + DOM::HTMLHeadingElement heading = element; + switch (token) { + case HeadingAlign: return String(heading.align()); + } + } + break; + case ID_BLOCKQUOTE: { + DOM::HTMLBlockquoteElement blockquote = element; + switch (token) { + case BlockQuoteCite: return String(blockquote.cite()); + } + } + case ID_Q: { + DOM::HTMLQuoteElement quote = element; + switch (token) { + case QuoteCite: return String(quote.cite()); + } + } + case ID_PRE: { + DOM::HTMLPreElement pre = element; + switch (token) { + case PreWidth: return Number(pre.width()); + } + } + break; + case ID_BR: { + DOM::HTMLBRElement br = element; + switch (token) { + case BRClear: return String(br.clear()); + } + } + break; + case ID_BASEFONT: { + DOM::HTMLBaseFontElement baseFont = element; + switch (token) { + case BaseFontColor: return String(baseFont.color()); + case BaseFontFace: return String(baseFont.face()); + case BaseFontSize: return Number(baseFont.getSize()); + } + } + break; + case ID_FONT: { + DOM::HTMLFontElement font = element; + switch (token) { + case FontColor: return String(font.color()); + case FontFace: return String(font.face()); + case FontSize: return String(font.size()); + } + } + break; + case ID_HR: { + DOM::HTMLHRElement hr = element; + switch (token) { + case HRAlign: return String(hr.align()); + case HRNoShade: return Boolean(hr.noShade()); + case HRSize: return String(hr.size()); + case HRWidth: return String(hr.width()); + } + } + break; + case ID_INS: + case ID_DEL: { + DOM::HTMLModElement mod = element; + switch (token) { + case ModCite: return String(mod.cite()); + case ModDateTime: return String(mod.dateTime()); + } + } + break; + case ID_A: { + DOM::HTMLAnchorElement anchor = element; + switch (token) { + case AnchorAccessKey: return String(anchor.accessKey()); + case AnchorCharset: return String(anchor.charset()); + case AnchorCoords: return String(anchor.coords()); + case AnchorHref: return String(anchor.href()); + case AnchorHrefLang: return String(anchor.hreflang()); + case AnchorHash: return String('#'+KURL(anchor.href().string()).ref()); + case AnchorHost: return String(KURL(anchor.href().string()).host()); + case AnchorHostname: { + KURL url(anchor.href().string()); + kdDebug(6070) << "anchor::hostname uses:" <<url.url()<<endl; + if (url.port()==0) + return String(url.host()); + else + return String(url.host() + ":" + QString::number(url.port())); + } + case AnchorPathName: return String(KURL(anchor.href().string()).path()); + case AnchorPort: return String(QString::number(KURL(anchor.href().string()).port())); + case AnchorProtocol: return String(KURL(anchor.href().string()).protocol()+":"); + case AnchorSearch: { KURL u(anchor.href().string()); + QString q = u.query(); + if (q.length() == 1) + return String(); + return String(q); } + case AnchorName: return String(anchor.name()); + case AnchorRel: return String(anchor.rel()); + case AnchorRev: return String(anchor.rev()); + case AnchorShape: return String(anchor.shape()); + case AnchorTabIndex: return Number(anchor.tabIndex()); + case AnchorTarget: return String(anchor.target()); + // Not specified in http://msdn.microsoft.com/workshop/author/dhtml/reference/objects/a.asp + // Mozilla returns the inner text. + case AnchorText: return String(anchor.innerText()); + case AnchorType: return String(anchor.type()); + } + } + break; + case ID_IMG: { + DOM::HTMLImageElement image = element; + switch (token) { + case ImageName: return String(image.name()); // NOT getString (IE gives empty string) + case ImageAlign: return String(image.align()); + case ImageAlt: return String(image.alt()); + case ImageBorder: return String(image.getBorder()); + case ImageComplete: return Boolean(static_cast<DOM::HTMLImageElementImpl*>( image.handle() )->complete()); + case ImageHeight: return Number(image.height()); + case ImageHspace: return Number(image.hspace()); + case ImageIsMap: return Boolean(image.isMap()); + case ImageLongDesc: return String(image.longDesc()); + case ImageSrc: return String(image.src()); + case ImageUseMap: return String(image.useMap()); + case ImageVspace: return Number(image.vspace()); + case ImageWidth: return Number(image.width()); + case ImageX: return Number(image.x()); + case ImageY: return Number(image.y()); + } + } + break; + case ID_OBJECT: { + DOM::HTMLObjectElement object = element; + switch (token) { + case ObjectForm: return getDOMNode(exec,object.form()); // type HTMLFormElement + case ObjectCode: return String(object.code()); + case ObjectAlign: return String(object.align()); + case ObjectArchive: return String(object.archive()); + case ObjectBorder: return String(object.border()); + case ObjectCodeBase: return String(object.codeBase()); + case ObjectCodeType: return String(object.codeType()); + case ObjectContentDocument: return checkNodeSecurity(exec,object.contentDocument()) ? + getDOMNode(exec, object.contentDocument()) : Undefined(); + case ObjectData: return String(object.data()); + case ObjectDeclare: return Boolean(object.declare()); + case ObjectHeight: return String(object.height()); + case ObjectHspace: return Number(object.getHspace()); + case ObjectName: return String(object.name()); + case ObjectStandby: return String(object.standby()); + case ObjectTabIndex: return Number(object.tabIndex()); + case ObjectType: return String(object.type()); + case ObjectUseMap: return String(object.useMap()); + case ObjectVspace: return Number(object.getVspace()); + case ObjectWidth: return String(object.width()); + } + } + break; + case ID_PARAM: { + DOM::HTMLParamElement param = element; + switch (token) { + case ParamName: return String(param.name()); + case ParamType: return String(param.type()); + case ParamValue: return String(param.value()); + case ParamValueType: return String(param.valueType()); + } + } + break; + case ID_APPLET: { + DOM::HTMLAppletElement applet = element; + switch (token) { + case AppletAlign: return String(applet.align()); + case AppletAlt: return String(applet.alt()); + case AppletArchive: return String(applet.archive()); + case AppletCode: return String(applet.code()); + case AppletCodeBase: return String(applet.codeBase()); + case AppletHeight: return String(applet.height()); + case AppletHspace: return Number(applet.getHspace()); + case AppletName: return String(applet.name()); + case AppletObject: return String(applet.object()); + case AppletVspace: return Number(applet.getVspace()); + case AppletWidth: return String(applet.width()); + } + } + break; + case ID_MAP: { + DOM::HTMLMapElement map = element; + switch (token) { + case MapAreas: return getHTMLCollection(exec, map.areas()); // type HTMLCollection + case MapName: return String(map.name()); + } + } + break; + case ID_AREA: { + DOM::HTMLAreaElement area = element; + switch (token) { + case AreaAccessKey: return String(area.accessKey()); + case AreaAlt: return String(area.alt()); + case AreaCoords: return String(area.coords()); + // Group everything that needs href + case AreaHref: + case AreaHash: + case AreaHost: + case AreaHostName: + case AreaPathName: + case AreaPort: + case AreaProtocol: + case AreaSearch: + { + DOM::Document doc = area.ownerDocument(); + DOM::DOMString href = area.href(); + KURL url; + if ( !href.isNull() ) { + url = doc.completeURL( href ).string(); + if ( href.isEmpty() ) + url.setFileName( QString::null ); // href="" clears the filename (in IE) + } + switch(token) { + case AreaHref: + return String(url.url()); + case AreaHash: return String(url.isEmpty() ? "" : '#'+url.ref()); + case AreaHost: return String(url.host()); + case AreaHostName: { + if (url.port()==0) + return String(url.host()); + else + return String(url.host() + ":" + QString::number(url.port())); + } + case AreaPathName: { + return String(url.path()); + } + case AreaPort: return String(QString::number(url.port())); + case AreaProtocol: return String(url.isEmpty() ? "" : url.protocol()+":"); + case AreaSearch: return String(url.query()); + } + } + case AreaNoHref: return Boolean(area.noHref()); + case AreaShape: return String(area.shape()); + case AreaTabIndex: return Number(area.tabIndex()); + case AreaTarget: return String(area.target()); + } + } + break; + case ID_SCRIPT: { + DOM::HTMLScriptElement script = element; + switch (token) { + case ScriptText: return String(script.text()); + case ScriptHtmlFor: return String(script.htmlFor()); + case ScriptEvent: return String(script.event()); + case ScriptCharset: return String(script.charset()); + case ScriptDefer: return Boolean(script.defer()); + case ScriptSrc: return String(script.src()); + case ScriptType: return String(script.type()); + } + } + break; + case ID_TABLE: { + DOM::HTMLTableElement table = element; + switch (token) { + case TableCaption: return getDOMNode(exec,table.caption()); // type HTMLTableCaptionElement + case TableTHead: return getDOMNode(exec,table.tHead()); // type HTMLTableSectionElement + case TableTFoot: return getDOMNode(exec,table.tFoot()); // type HTMLTableSectionElement + case TableRows: return getHTMLCollection(exec,table.rows()); // type HTMLCollection + case TableTBodies: return getHTMLCollection(exec,table.tBodies()); // type HTMLCollection + case TableAlign: return String(table.align()); + case TableBgColor: return String(table.bgColor()); + case TableBorder: return String(table.border()); + case TableCellPadding: return String(table.cellPadding()); + case TableCellSpacing: return String(table.cellSpacing()); + case TableFrame: return String(table.frame()); + case TableRules: return String(table.rules()); + case TableSummary: return String(table.summary()); + case TableWidth: return String(table.width()); + } + } + break; + case ID_CAPTION: { + DOM::HTMLTableCaptionElement tableCaption = element; + switch (token) { + case TableCaptionAlign: return String(tableCaption.align()); + } + } + break; + case ID_COL: + case ID_COLGROUP: { + DOM::HTMLTableColElement tableCol = element; + switch (token) { + case TableColAlign: return String(tableCol.align()); + case TableColCh: return String(tableCol.ch()); + case TableColChOff: return String(tableCol.chOff()); + case TableColSpan: return Number(tableCol.span()); + case TableColVAlign: return String(tableCol.vAlign()); + case TableColWidth: return String(tableCol.width()); + } + } + break; + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: { + DOM::HTMLTableSectionElement tableSection = element; + switch (token) { + case TableSectionAlign: return String(tableSection.align()); + case TableSectionCh: return String(tableSection.ch()); + case TableSectionChOff: return String(tableSection.chOff()); + case TableSectionVAlign: return String(tableSection.vAlign()); + case TableSectionRows: return getHTMLCollection(exec,tableSection.rows()); // type HTMLCollection + } + } + break; + case ID_TR: { + DOM::HTMLTableRowElement tableRow = element; + switch (token) { + case TableRowRowIndex: return Number(tableRow.rowIndex()); + case TableRowSectionRowIndex: return Number(tableRow.sectionRowIndex()); + case TableRowCells: return getHTMLCollection(exec,tableRow.cells()); // type HTMLCollection + case TableRowAlign: return String(tableRow.align()); + case TableRowBgColor: return String(tableRow.bgColor()); + case TableRowCh: return String(tableRow.ch()); + case TableRowChOff: return String(tableRow.chOff()); + case TableRowVAlign: return String(tableRow.vAlign()); + } + } + break; + case ID_TH: + case ID_TD: { + DOM::HTMLTableCellElement tableCell = element; + switch (token) { + case TableCellCellIndex: return Number(tableCell.cellIndex()); + case TableCellAbbr: return String(tableCell.abbr()); + case TableCellAlign: return String(tableCell.align()); + case TableCellAxis: return String(tableCell.axis()); + case TableCellBgColor: return String(tableCell.bgColor()); + case TableCellCh: return String(tableCell.ch()); + case TableCellChOff: return String(tableCell.chOff()); + case TableCellColSpan: return Number(tableCell.colSpan()); + case TableCellHeaders: return String(tableCell.headers()); + case TableCellHeight: return String(tableCell.height()); + case TableCellNoWrap: return Boolean(tableCell.noWrap()); + case TableCellRowSpan: return Number(tableCell.rowSpan()); + case TableCellScope: return String(tableCell.scope()); + case TableCellVAlign: return String(tableCell.vAlign()); + case TableCellWidth: return String(tableCell.width()); + } + } + break; + case ID_FRAMESET: { + DOM::HTMLFrameSetElement frameSet = element; + switch (token) { + case FrameSetCols: return String(frameSet.cols()); + case FrameSetRows: return String(frameSet.rows()); + } + } + break; + case ID_LAYER: { + DOM::HTMLLayerElement layerElement = element; + switch (token) { + case LayerTop: return Number(layerElement.top()); + case LayerLeft: return Number(layerElement.left()); + case LayerVisibility: return getString(layerElement.visibility()); + case LayerBgColor: return getString(layerElement.bgColor()); + /*case LayerClip: return getLayerClip(exec, layerElement); */ + case LayerDocument: return Undefined(); + case LayerLayers: return getHTMLCollection(exec,layerElement.layers()); + } + } + break; + case ID_FRAME: { + DOM::HTMLFrameElement frameElement = element; + switch (token) { + case FrameContentDocument: return checkNodeSecurity(exec,frameElement.contentDocument()) ? + getDOMNode(exec, frameElement.contentDocument()) : Undefined(); + case FrameContentWindow: { + KHTMLPart* part = static_cast<DOM::HTMLFrameElementImpl*>(frameElement.handle())->contentPart(); + if (part) { + Window *w = Window::retrieveWindow(part); + if (w) + return Value(w); + } + return Undefined(); + } + case FrameFrameBorder: return String(frameElement.frameBorder()); + case FrameLongDesc: return String(frameElement.longDesc()); + case FrameMarginHeight: return String(frameElement.marginHeight()); + case FrameMarginWidth: return String(frameElement.marginWidth()); + case FrameName: return String(frameElement.name()); + case FrameNoResize: return Boolean(frameElement.noResize()); + case FrameScrolling: return String(frameElement.scrolling()); + case FrameSrc: + case FrameLocation: return String(frameElement.src()); + // IE only + case FrameWidth: + case FrameHeight: + { + frameElement.handle()->getDocument()->updateLayout(); + khtml::RenderObject* r = frameElement.handle()->renderer(); + return Number( r ? (token == FrameWidth ? r->width() : r->height()) : 0 ); + } + } + } + break; + case ID_IFRAME: { + DOM::HTMLIFrameElement iFrame = element; + switch (token) { + case IFrameAlign: return String(iFrame.align()); + case IFrameContentDocument: return checkNodeSecurity(exec,iFrame.contentDocument()) ? + getDOMNode(exec, iFrame.contentDocument()) : Undefined(); + case IFrameContentWindow: { + KHTMLPart* part = static_cast<DOM::HTMLIFrameElementImpl*>(iFrame.handle())->contentPart(); + if (part) { + Window *w = Window::retrieveWindow(part); + if (w) + return Value(w); + } + return Undefined(); + } + case IFrameFrameBorder: return String(iFrame.frameBorder()); + case IFrameHeight: return String(iFrame.height()); + case IFrameLongDesc: return String(iFrame.longDesc()); + case IFrameMarginHeight: return String(iFrame.marginHeight()); + case IFrameMarginWidth: return String(iFrame.marginWidth()); + case IFrameName: return String(iFrame.name()); + case IFrameScrolling: return String(iFrame.scrolling()); + case IFrameSrc: return String(iFrame.src()); + case IFrameWidth: return String(iFrame.width()); + } + break; + } + } // xemacs (or arnt) could be a bit smarter when it comes to indenting switch()es ;) + // its not arnt to blame - its the original Stroustrup style we like :) (Dirk) + + // generic properties + switch (token) { + case ElementId: + return String(element.id()); // String is wrong here. Other browsers return empty string if no id specified. + case ElementTitle: + return String(element.title()); + case ElementLang: + return String(element.lang()); + case ElementDir: + return String(element.dir()); + case ElementClassName: + return String(element.className()); + case ElementInnerHTML: + return String(element.innerHTML()); + case ElementInnerText: + return String(element.innerText()); + case ElementDocument: + return getDOMNode(exec,element.ownerDocument()); + case ElementChildren: + return getHTMLCollection(exec,element.children()); + case ElementAll: + // Disable element.all when we try to be Netscape-compatible + if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat ) + return Undefined(); + else + if ( exec->interpreter()->compatMode() == Interpreter::IECompat ) + return getHTMLCollection(exec,element.all()); + else // Enabled but hidden by default + return getHTMLCollection(exec,element.all(), true); + // ### what about style? or is this used instead for DOM2 stylesheets? + } + kdError() << "HTMLElement::getValueProperty unhandled token " << token << endl; + return Undefined(); +} + +bool KJS::HTMLElement::hasProperty(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + //kdDebug(6070) << "HTMLElement::hasProperty " << propertyName.qstring() << endl; +#endif + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); + // First look at dynamic properties - keep this in sync with tryGet + switch (element.elementId()) { + case ID_FORM: { + DOM::HTMLFormElement form = element; + // Check if we're retrieving an element (by index or by name) + bool ok; + uint u = propertyName.toULong(&ok); + if (ok && !(form.elements().item(u).isNull())) + return true; + DOM::Node testnode = form.elements().namedItem(propertyName.string()); + if (!testnode.isNull()) + return true; + } + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + bool ok; + uint u = propertyName.toULong(&ok); + if (ok && !(select.options().item(u).isNull())) + return true; + } + default: + break; + } + + return DOMElement::hasProperty(exec, propertyName); +} + +UString KJS::HTMLElement::toString(ExecState *exec) const +{ + if (node.elementId() == ID_A) + return UString(static_cast<const DOM::HTMLAnchorElement&>(node).href()); + else if (node.elementId() == ID_APPLET) { + KParts::LiveConnectExtension *lc = getLiveConnectExtension(node); + QStringList qargs; + QString retvalue; + KParts::LiveConnectExtension::Type rettype; + unsigned long retobjid; + if (lc && lc->call(0, "hashCode", qargs, rettype, retobjid, retvalue)) { + QString str("[object APPLET ref="); + return UString(str + retvalue + QString("]")); + } + } else if (node.elementId() == ID_IMG) { + DOM::HTMLImageElement image(node); + if (!image.alt().isEmpty()) + return UString(image.alt()) + " " + DOMElement::toString(exec); + } + return DOMElement::toString(exec); +} + +static void getForm(DOM::HTMLFormElement* form, const DOM::HTMLElement& element) +{ + switch (element.elementId()) { + case ID_ISINDEX: { + DOM::HTMLIsIndexElement isindex = element; + *form = isindex.form(); + break; + } + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + *form = select.form(); + break; + } + case ID_OPTION: { + DOM::HTMLOptionElement option = element; + *form = option.form(); + break; + } + case ID_INPUT: { + DOM::HTMLInputElement input = element; + *form = input.form(); + break; + } + case ID_TEXTAREA: { + DOM::HTMLTextAreaElement textarea = element; + *form = textarea.form(); + break; + } + case ID_LABEL: { + DOM::HTMLLabelElement label = element; + *form = label.form(); + break; + } + case ID_FIELDSET: { + DOM::HTMLFieldSetElement fieldset = element; + *form = fieldset.form(); + break; + } + case ID_LEGEND: { + DOM::HTMLLegendElement legend = element; + *form = legend.form(); + break; + } + case ID_OBJECT: { + DOM::HTMLObjectElement object = element; + *form = object.form(); + break; + } + default: + break; + } +} + +void KJS::HTMLElement::pushEventHandlerScope(ExecState *exec, ScopeChain &scope) const +{ + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); + + // The document is put on first, fall back to searching it only after the element and form. + scope.push(static_cast<ObjectImp *>(getDOMNode(exec, element.ownerDocument()).imp())); + + // The form is next, searched before the document, but after the element itself. + DOM::HTMLFormElement formElt; + + // First try to obtain the form from the element itself. We do this to deal with + // the malformed case where <form>s aren't in our parent chain (e.g., when they were inside + // <table> or <tbody>. + getForm(&formElt, element); + if (!formElt.isNull()) + scope.push(static_cast<ObjectImp *>(getDOMNode(exec, formElt).imp())); + else { + DOM::Node form = element.parentNode(); + while (!form.isNull() && form.elementId() != ID_FORM) + form = form.parentNode(); + + if (!form.isNull()) + scope.push(static_cast<ObjectImp *>(getDOMNode(exec, form).imp())); + } + + // The element is on top, searched first. + scope.push(static_cast<ObjectImp *>(getDOMNode(exec, element).imp())); +} + +HTMLElementFunction::HTMLElementFunction(ExecState *exec, int i, int len) + : DOMFunction(exec), id(i) +{ + Value protect(this); + put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum); +} + +Value KJS::HTMLElementFunction::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( HTMLElement, thisObj ); + +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLElementFunction::tryCall " << endl; +#endif + DOM::HTMLElement element = static_cast<KJS::HTMLElement *>(thisObj.imp())->toElement(); + + switch (element.elementId()) { + case ID_FORM: { + DOM::HTMLFormElement form = element; + if (id == KJS::HTMLElement::FormSubmit) { + + + DOM::HTMLDocument doc = element.ownerDocument(); + KHTMLView *view = static_cast<DOM::DocumentImpl*>(doc.handle())->view(); + KHTMLSettings::KJSWindowOpenPolicy policy = KHTMLSettings::KJSWindowOpenAllow; + if (view) + policy = view->part()->settings()->windowOpenPolicy(view->part()->url().host()); + + bool block = false; + + if ( policy != KHTMLSettings::KJSWindowOpenAllow ) { + block = true; + + // if this is a form without a target, or a special target, don't block + QString trg = form.target().lower().string(); + if( trg.isEmpty() || trg == "_top" || trg == "_self" || + trg == "_parent") + block = false; + + QString caption; + + // if there is a frame with the target name, don't block + if ( view && view->part() ) { + if (!view->part()->url().host().isEmpty()) + caption = view->part()->url().host() + " - "; + // search all (possibly nested) framesets + KHTMLPart *currentPart = view->part()->parentPart(); + while( currentPart != 0L ) { + if( currentPart->frameExists( form.target().string() ) ) + block = false; + currentPart = currentPart->parentPart(); + } + } + + if ( block && policy == KHTMLSettings::KJSWindowOpenAsk && view ) { + if (view && view->part()) + emit view->part()->browserExtension()->requestFocus(view->part()); + caption += i18n( "Confirmation: JavaScript Popup" ); + if ( KMessageBox::questionYesNo(view, form.action().isEmpty() ? + i18n( "This site is submitting a form which will open up a new browser " + "window via JavaScript.\n" + "Do you want to allow the form to be submitted?" ) : + i18n( "<qt>This site is submitting a form which will open <p>%1</p> in a new browser window via JavaScript.<br />" + "Do you want to allow the form to be submitted?</qt>").arg(KStringHandler::csqueeze(form.action().string(), 100)), + caption, i18n("Allow"), i18n("Do Not Allow") ) == KMessageBox::Yes ) + block = false; + + } else if ( block && policy == KHTMLSettings::KJSWindowOpenSmart ) { + if( static_cast<KJS::ScriptInterpreter *>(exec->interpreter())->isWindowOpenAllowed() ) { + // This submission has been triggered by the user + block = false; + } + } + } + + if( !block ) + form.submit(); + + return Undefined(); + } + else if (id == KJS::HTMLElement::FormReset) { + form.reset(); + return Undefined(); + } + } + break; + case ID_BODY: { + if (id == KJS::HTMLElement::BodyFocus) { + // Just blur everything. Not perfect, but good enough for now + if (DOM::NodeImpl* impl = element.handle()) { + impl->getDocument()->setFocusNode(0); + } + } + } + break; + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + if (id == KJS::HTMLElement::SelectAdd) { + select.add(KJS::toNode(args[0]),KJS::toNode(args[1])); + return Undefined(); + } + else if (id == KJS::HTMLElement::SelectRemove) { + select.remove(int(args[0].toNumber(exec))); + return Undefined(); + } + else if (id == KJS::HTMLElement::SelectBlur) { + select.blur(); + return Undefined(); + } + else if (id == KJS::HTMLElement::SelectFocus) { + select.focus(); + return Undefined(); + } + } + break; + case ID_INPUT: { + DOM::HTMLInputElement input = element; + if (id == KJS::HTMLElement::InputBlur) { + input.blur(); + return Undefined(); + } + else if (id == KJS::HTMLElement::InputFocus) { + input.focus(); + return Undefined(); + } + else if (id == KJS::HTMLElement::InputSelect) { + input.select(); + return Undefined(); + } + else if (id == KJS::HTMLElement::InputClick) { + input.click(); + return Undefined(); + } + else if (id == KJS::HTMLElement::InputSetSelectionRange) { + input.setSelectionRange(args[0].toNumber(exec), args[1].toNumber(exec)); + return Undefined(); + } + } + break; + case ID_BUTTON: { + DOM::HTMLButtonElement button = element; + if (id == KJS::HTMLElement::ButtonBlur) { + button.blur(); + return Undefined(); + } + else if (id == KJS::HTMLElement::ButtonFocus) { + button.focus(); + return Undefined(); + } + } + break; + case ID_TEXTAREA: { + DOM::HTMLTextAreaElement textarea = element; + if (id == KJS::HTMLElement::TextAreaBlur) { + textarea.blur(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TextAreaFocus) { + textarea.focus(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TextAreaSelect) { + textarea.select(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TextAreaSetSelectionRange) { + textarea.setSelectionRange(args[0].toNumber(exec), args[1].toNumber(exec)); + return Undefined(); + } + + } + break; + case ID_A: { + DOM::HTMLAnchorElement anchor = element; + if (id == KJS::HTMLElement::AnchorBlur) { + anchor.blur(); + return Undefined(); + } + else if (id == KJS::HTMLElement::AnchorFocus) { + anchor.focus(); + return Undefined(); + } + else if (id == KJS::HTMLElement::AnchorClick) { + static_cast<DOM::HTMLAnchorElementImpl*>(anchor.handle())->click(); + return Undefined(); + } + } + break; + case ID_TABLE: { + DOM::HTMLTableElement table = element; + if (id == KJS::HTMLElement::TableCreateTHead) + return getDOMNode(exec,table.createTHead()); + else if (id == KJS::HTMLElement::TableDeleteTHead) { + table.deleteTHead(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TableCreateTFoot) + return getDOMNode(exec,table.createTFoot()); + else if (id == KJS::HTMLElement::TableDeleteTFoot) { + table.deleteTFoot(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TableCreateCaption) + return getDOMNode(exec,table.createCaption()); + else if (id == KJS::HTMLElement::TableDeleteCaption) { + table.deleteCaption(); + return Undefined(); + } + else if (id == KJS::HTMLElement::TableInsertRow) + return getDOMNode(exec,table.insertRow(args[0].toInteger(exec))); + else if (id == KJS::HTMLElement::TableDeleteRow) { + table.deleteRow(args[0].toInteger(exec)); + return Undefined(); + } + } + break; + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: { + DOM::HTMLTableSectionElement tableSection = element; + if (id == KJS::HTMLElement::TableSectionInsertRow) + return getDOMNode(exec,tableSection.insertRow(args[0].toInteger(exec))); + else if (id == KJS::HTMLElement::TableSectionDeleteRow) { + tableSection.deleteRow(args[0].toInteger(exec)); + return Undefined(); + } + } + break; + case ID_TR: { + DOM::HTMLTableRowElement tableRow = element; + if (id == KJS::HTMLElement::TableRowInsertCell) + return getDOMNode(exec,tableRow.insertCell(args[0].toInteger(exec))); + else if (id == KJS::HTMLElement::TableRowDeleteCell) { + tableRow.deleteCell(args[0].toInteger(exec)); + return Undefined(); + } + break; + } + case ID_MARQUEE: { + if (id == KJS::HTMLElement::MarqueeStart && element.handle()->renderer() && + element.handle()->renderer()->layer() && + element.handle()->renderer()->layer()->marquee()) { + element.handle()->renderer()->layer()->marquee()->start(); + return Undefined(); + } + else if (id == KJS::HTMLElement::MarqueeStop && element.handle()->renderer() && + element.handle()->renderer()->layer() && + element.handle()->renderer()->layer()->marquee()) { + element.handle()->renderer()->layer()->marquee()->stop(); + return Undefined(); + } + break; + } + } + + if (id == HTMLElement::ElementScrollIntoView) { + bool alignToTop = true; + if (args.size() > 0) + alignToTop = args[0].toBoolean(exec); + static_cast<HTMLElementImpl*>(element.handle())->scrollIntoView(alignToTop); + return Undefined(); + } + + return Undefined(); +} + +void KJS::HTMLElement::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ +#ifdef KJS_VERBOSE + DOM::DOMString str = value.isA(NullType) ? DOM::DOMString() : value.toString(exec).string(); +#endif + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLElement::tryPut " << propertyName.qstring() + << " thisTag=" << element.tagName().string() + << " str=" << str.string() << endl; +#endif + // First look at dynamic properties + switch (element.elementId()) { + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + bool ok; + /*uint u =*/ propertyName.toULong(&ok); + if (ok) { + Object coll = Object::dynamicCast( getSelectHTMLCollection(exec, select.options(), select) ); + if ( coll.isValid() ) + coll.put(exec,propertyName,value); + return; + } + break; + } + case ID_APPLET: + case ID_OBJECT: + case ID_EMBED: { + KParts::LiveConnectExtension *lc = getLiveConnectExtension(element); + if (lc && lc->put(0, propertyName.qstring(), value.toString(exec).qstring())) + return; + break; + } + default: + break; + } + + const HashTable* table = classInfo()->propHashTable; // get the right hashtable + const HashEntry* entry = table ? Lookup::findEntry(table, propertyName) : 0; + if (entry) { + if (entry->attr & Function) // function: put as override property + { + ObjectImp::put(exec, propertyName, value, attr); + return; + } + else if ((entry->attr & ReadOnly) == 0) // let DOMObjectLookupPut print the warning if not + { + putValueProperty(exec, entry->value, value, attr); + return; + } + } + DOMObjectLookupPut<KJS::HTMLElement, DOMElement>(exec, propertyName, value, attr, &KJS::HTMLElementTable, this); +} + +void KJS::HTMLElement::putValueProperty(ExecState *exec, int token, const Value& value, int) +{ + DOM::DOMString str = value.isA(NullType) ? DOM::DOMString() : value.toString(exec).string(); + DOMNode *kjsNode = new DOMNode(exec, KJS::toNode(value)); + // Need to create a Value wrapper to avoid leaking the KJS::DOMNode + Value nodeValue(kjsNode); + DOM::Node n = kjsNode->toNode(); + DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node); +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLElement::putValueProperty " + << " thisTag=" << element.tagName().string() + << " token=" << token << endl; +#endif + + switch (element.elementId()) { + case ID_HTML: { + DOM::HTMLHtmlElement html = element; + switch (token) { + case HtmlVersion: { html.setVersion(str); return; } + } + } + break; + case ID_HEAD: { + DOM::HTMLHeadElement head = element; + switch (token) { + case HeadProfile: { head.setProfile(str); return; } + } + } + break; + case ID_LINK: { + DOM::HTMLLinkElement link = element; + switch (token) { + case LinkDisabled: { link.setDisabled(value.toBoolean(exec)); return; } + case LinkCharset: { link.setCharset(str); return; } + case LinkHref: { link.setHref(str); return; } + case LinkHrefLang: { link.setHreflang(str); return; } + case LinkMedia: { link.setMedia(str); return; } + case LinkRel: { link.setRel(str); return; } + case LinkRev: { link.setRev(str); return; } + case LinkTarget: { link.setTarget(str); return; } + case LinkType: { link.setType(str); return; } + } + } + break; + case ID_TITLE: { + DOM::HTMLTitleElement title = element; + switch (token) { + case TitleText: { title.setText(str); return; } + } + } + break; + case ID_META: { + DOM::HTMLMetaElement meta = element; + switch (token) { + case MetaContent: { meta.setContent(str); return; } + case MetaHttpEquiv: { meta.setHttpEquiv(str); return; } + case MetaName: { meta.setName(str); return; } + case MetaScheme: { meta.setScheme(str); return; } + } + } + break; + case ID_BASE: { + DOM::HTMLBaseElement base = element; + switch (token) { + case BaseHref: { base.setHref(str); return; } + case BaseTarget: { base.setTarget(str); return; } + } + } + break; + case ID_ISINDEX: { + DOM::HTMLIsIndexElement isindex = element; + switch (token) { + // read-only: form + case IsIndexPrompt: { isindex.setPrompt(str); return; } + } + } + break; + case ID_STYLE: { + DOM::HTMLStyleElement style = element; + switch (token) { + case StyleDisabled: { style.setDisabled(value.toBoolean(exec)); return; } + case StyleMedia: { style.setMedia(str); return; } + case StyleType: { style.setType(str); return; } + } + } + break; + case ID_BODY: { + DOM::HTMLBodyElement body = element; + switch (token) { + case BodyALink: { body.setALink(str); return; } + case BodyBackground: { body.setBackground(str); return; } + case BodyBgColor: { body.setBgColor(str); return; } + case BodyLink: { body.setLink(str); return; } + case BodyText: { body.setText(str); return; } + case BodyVLink: { body.setVLink(str); return; } + case BodyOnLoad: + DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(node.ownerDocument().handle()); + if (doc && checkNodeSecurity(exec, node)) + { + DOMNode* kjsDocNode = new DOMNode(exec, doc); + // Need to create a Value wrapper to avoid leaking the KJS::DOMNode + Value nodeValue(kjsDocNode); + kjsDocNode->setListener(exec,DOM::EventImpl::LOAD_EVENT,value); + } + return; + } + } + break; + case ID_FORM: { + DOM::HTMLFormElement form = element; + switch (token) { + // read-only: elements + // read-only: length + case FormName: { form.setName(str); return; } + case FormAcceptCharset: { form.setAcceptCharset(str); return; } + case FormAction: { form.setAction(str.string()); return; } + case FormEncType: { form.setEnctype(str); return; } + case FormMethod: { form.setMethod(str); return; } + case FormTarget: { form.setTarget(str); return; } + } + } + break; + case ID_SELECT: { + DOM::HTMLSelectElement select = element; + switch (token) { + // read-only: type + case SelectSelectedIndex: { select.setSelectedIndex(value.toInteger(exec)); return; } + case SelectValue: { select.setValue(str); return; } + case SelectLength: { // read-only according to the NS spec, but webpages need it writeable + Object coll = Object::dynamicCast( getSelectHTMLCollection(exec, select.options(), select) ); + if ( coll.isValid() ) + coll.put(exec,"length",value); + return; + } + // read-only: form + // read-only: options + case SelectDisabled: { select.setDisabled(value.toBoolean(exec)); return; } + case SelectMultiple: { select.setMultiple(value.toBoolean(exec)); return; } + case SelectName: { select.setName(str); return; } + case SelectSize: { select.setSize(value.toInteger(exec)); return; } + case SelectTabIndex: { select.setTabIndex(value.toInteger(exec)); return; } + } + } + break; + case ID_OPTGROUP: { + DOM::HTMLOptGroupElement optgroup = element; + switch (token) { + case OptGroupDisabled: { optgroup.setDisabled(value.toBoolean(exec)); return; } + case OptGroupLabel: { optgroup.setLabel(str); return; } + } + } + break; + case ID_OPTION: { + DOM::HTMLOptionElement option = element; + switch (token) { + // read-only: form + case OptionDefaultSelected: { option.setDefaultSelected(value.toBoolean(exec)); return; } + // read-only: text <--- According to the DOM, but JavaScript and JScript both allow changes. + // So, we'll do it here and not add it to our DOM headers. + case OptionText: { DOM::NodeList nl(option.childNodes()); + for (unsigned int i = 0; i < nl.length(); i++) { + if (nl.item(i).nodeType() == DOM::Node::TEXT_NODE) { + static_cast<DOM::Text>(nl.item(i)).setData(str); + return; + } + } + // No child text node found, creating one + DOM::Text t = option.ownerDocument().createTextNode(str); + try { option.appendChild(t); } + catch(DOM::DOMException& e) { + // #### exec->setException ? + } + + return; + } + // read-only: index + case OptionDisabled: { option.setDisabled(value.toBoolean(exec)); return; } + case OptionLabel: { option.setLabel(str); return; } + case OptionSelected: { option.setSelected(value.toBoolean(exec)); return; } + case OptionValue: { option.setValue(str); return; } + } + } + break; + case ID_INPUT: { + DOM::HTMLInputElement input = element; + switch (token) { + case InputDefaultValue: { input.setDefaultValue(str); return; } + case InputDefaultChecked: { input.setDefaultChecked(value.toBoolean(exec)); return; } + // read-only: form + case InputAccept: { input.setAccept(str); return; } + case InputAccessKey: { input.setAccessKey(str); return; } + case InputAlign: { input.setAlign(str); return; } + case InputAlt: { input.setAlt(str); return; } + case InputChecked: { input.setChecked(value.toBoolean(exec)); return; } + case InputIndeterminate: { input.setIndeterminate(value.toBoolean(exec)); return; } + case InputDisabled: { input.setDisabled(value.toBoolean(exec)); return; } + case InputMaxLength: { input.setMaxLength(value.toInteger(exec)); return; } + case InputName: { input.setName(str); return; } + case InputReadOnly: { input.setReadOnly(value.toBoolean(exec)); return; } + case InputSize: { input.setSize(value.toInteger(exec)); return; } + case InputSrc: { input.setSrc(str); return; } + case InputTabIndex: { input.setTabIndex(value.toInteger(exec)); return; } + case InputType: { input.setType(str); return; } + case InputUseMap: { input.setUseMap(str); return; } + case InputValue: { input.setValue(str); return; } + case InputSelectionStart: { input.setSelectionStart(value.toInteger(exec)); return; } + case InputSelectionEnd: { input.setSelectionEnd (value.toInteger(exec)); return; } + } + } + break; + case ID_TEXTAREA: { + DOM::HTMLTextAreaElement textarea = element; + switch (token) { + case TextAreaDefaultValue: { textarea.setDefaultValue(str); return; } + // read-only: form + case TextAreaAccessKey: { textarea.setAccessKey(str); return; } + case TextAreaCols: { textarea.setCols(value.toInteger(exec)); return; } + case TextAreaDisabled: { textarea.setDisabled(value.toBoolean(exec)); return; } + case TextAreaName: { textarea.setName(str); return; } + case TextAreaReadOnly: { textarea.setReadOnly(value.toBoolean(exec)); return; } + case TextAreaRows: { textarea.setRows(value.toInteger(exec)); return; } + case TextAreaTabIndex: { textarea.setTabIndex(value.toInteger(exec)); return; } + // read-only: type + case TextAreaValue: { textarea.setValue(str); return; } + case TextAreaSelectionStart: { textarea.setSelectionStart(value.toInteger(exec)); return; } + case TextAreaSelectionEnd: { textarea.setSelectionEnd (value.toInteger(exec)); return; } + } + } + break; + case ID_BUTTON: { + DOM::HTMLButtonElement button = element; + switch (token) { + // read-only: form + case ButtonAccessKey: { button.setAccessKey(str); return; } + case ButtonDisabled: { button.setDisabled(value.toBoolean(exec)); return; } + case ButtonName: { button.setName(str); return; } + case ButtonTabIndex: { button.setTabIndex(value.toInteger(exec)); return; } + // read-only: type + case ButtonValue: { button.setValue(str); return; } + } + } + break; + case ID_LABEL: { + DOM::HTMLLabelElement label = element; + switch (token) { + // read-only: form + case LabelAccessKey: { label.setAccessKey(str); return; } + case LabelHtmlFor: { label.setHtmlFor(str); return; } + } + } + break; +// case ID_FIELDSET: { +// DOM::HTMLFieldSetElement fieldSet = element; +// // read-only: form +// } +// break; + case ID_LEGEND: { + DOM::HTMLLegendElement legend = element; + switch (token) { + // read-only: form + case LegendAccessKey: { legend.setAccessKey(str); return; } + case LegendAlign: { legend.setAlign(str); return; } + } + } + break; + case ID_UL: { + DOM::HTMLUListElement uList = element; + switch (token) { + case UListCompact: { uList.setCompact(value.toBoolean(exec)); return; } + case UListType: { uList.setType(str); return; } + } + } + break; + case ID_OL: { + DOM::HTMLOListElement oList = element; + switch (token) { + case OListCompact: { oList.setCompact(value.toBoolean(exec)); return; } + case OListStart: { oList.setStart(value.toInteger(exec)); return; } + case OListType: { oList.setType(str); return; } + } + } + break; + case ID_DL: { + DOM::HTMLDListElement dList = element; + switch (token) { + case DListCompact: { dList.setCompact(value.toBoolean(exec)); return; } + } + } + break; + case ID_DIR: { + DOM::HTMLDirectoryElement directory = element; + switch (token) { + case DirectoryCompact: { directory.setCompact(value.toBoolean(exec)); return; } + } + } + break; + case ID_MENU: { + DOM::HTMLMenuElement menu = element; + switch (token) { + case MenuCompact: { menu.setCompact(value.toBoolean(exec)); return; } + } + } + break; + case ID_LI: { + DOM::HTMLLIElement li = element; + switch (token) { + case LIType: { li.setType(str); return; } + case LIValue: { li.setValue(value.toInteger(exec)); return; } + } + } + break; + case ID_DIV: { + DOM::HTMLDivElement div = element; + switch (token) { + case DivAlign: { div.setAlign(str); return; } + } + } + break; + case ID_P: { + DOM::HTMLParagraphElement paragraph = element; + switch (token) { + case ParagraphAlign: { paragraph.setAlign(str); return; } + } + } + break; + case ID_H1: + case ID_H2: + case ID_H3: + case ID_H4: + case ID_H5: + case ID_H6: { + DOM::HTMLHeadingElement heading = element; + switch (token) { + case HeadingAlign: { heading.setAlign(str); return; } + } + } + break; + case ID_BLOCKQUOTE: { + DOM::HTMLBlockquoteElement blockquote = element; + switch (token) { + case BlockQuoteCite: { blockquote.setCite(str); return; } + } + } + break; + case ID_Q: { + DOM::HTMLQuoteElement quote = element; + switch (token) { + case QuoteCite: { quote.setCite(str); return; } + } + } + break; + case ID_PRE: { + DOM::HTMLPreElement pre = element; + switch (token) { + case PreWidth: { pre.setWidth(value.toInteger(exec)); return; } + } + } + break; + case ID_BR: { + DOM::HTMLBRElement br = element; + switch (token) { + case BRClear: { br.setClear(str); return; } + } + } + break; + case ID_BASEFONT: { + DOM::HTMLBaseFontElement baseFont = element; + switch (token) { + case BaseFontColor: { baseFont.setColor(str); return; } + case BaseFontFace: { baseFont.setFace(str); return; } + case BaseFontSize: { baseFont.setSize(value.toInteger(exec)); return; } + } + } + break; + case ID_FONT: { + DOM::HTMLFontElement font = element; + switch (token) { + case FontColor: { font.setColor(str); return; } + case FontFace: { font.setFace(str); return; } + case FontSize: { font.setSize(str); return; } + } + } + break; + case ID_HR: { + DOM::HTMLHRElement hr = element; + switch (token) { + case HRAlign: { hr.setAlign(str); return; } + case HRNoShade: { hr.setNoShade(value.toBoolean(exec)); return; } + case HRSize: { hr.setSize(str); return; } + case HRWidth: { hr.setWidth(str); return; } + } + } + break; + case ID_INS: + case ID_DEL: { + DOM::HTMLModElement mod = element; + switch (token) { + case ModCite: { mod.setCite(str); return; } + case ModDateTime: { mod.setDateTime(str); return; } + } + } + break; + case ID_A: { + DOM::HTMLAnchorElement anchor = element; + switch (token) { + case AnchorAccessKey: { anchor.setAccessKey(str); return; } + case AnchorCharset: { anchor.setCharset(str); return; } + case AnchorCoords: { anchor.setCoords(str); return; } + case AnchorHref: { anchor.setHref(str); return; } + case AnchorHrefLang: { anchor.setHreflang(str); return; } + case AnchorSearch: { KURL href(anchor.href().string()); + QString q = str.isEmpty() ? QString() : str.string(); + href.setQuery(q); + anchor.setHref(href.url()); return; } + case AnchorName: { anchor.setName(str); return; } + case AnchorRel: { anchor.setRel(str); return; } + case AnchorRev: { anchor.setRev(str); return; } + case AnchorShape: { anchor.setShape(str); return; } + case AnchorTabIndex: { anchor.setTabIndex(value.toInteger(exec)); return; } + case AnchorTarget: { anchor.setTarget(str); return; } + case AnchorType: { anchor.setType(str); return; } + } + } + break; + case ID_IMG: { + DOM::HTMLImageElement image = element; + switch (token) { + case ImageName: { image.setName(str); return; } + case ImageAlign: { image.setAlign(str); return; } + case ImageAlt: { image.setAlt(str); return; } + case ImageBorder: { image.setBorder(str); return; } + case ImageHeight: { image.setHeight(value.toInteger(exec)); return; } + case ImageHspace: { image.setHspace(value.toInteger(exec)); return; } + case ImageIsMap: { image.setIsMap(value.toBoolean(exec)); return; } + case ImageLongDesc: { image.setLongDesc(str); return; } + case ImageSrc: { image.setSrc(str); return; } + case ImageUseMap: { image.setUseMap(str); return; } + case ImageVspace: { image.setVspace(value.toInteger(exec)); return; } + case ImageWidth: { image.setWidth(value.toInteger(exec)); return; } + } + } + break; + case ID_OBJECT: { + DOM::HTMLObjectElement object = element; + switch (token) { + // read-only: form + case ObjectCode: { object.setCode(str); return; } + case ObjectAlign: { object.setAlign(str); return; } + case ObjectArchive: { object.setArchive(str); return; } + case ObjectBorder: { object.setBorder(str); return; } + case ObjectCodeBase: { object.setCodeBase(str); return; } + case ObjectCodeType: { object.setCodeType(str); return; } + // read-only: ObjectContentDocument + case ObjectData: { object.setData(str); return; } + case ObjectDeclare: { object.setDeclare(value.toBoolean(exec)); return; } + case ObjectHeight: { object.setHeight(str); return; } + case ObjectHspace: { object.setHspace(value.toInteger(exec)); return; } + case ObjectName: { object.setName(str); return; } + case ObjectStandby: { object.setStandby(str); return; } + case ObjectTabIndex: { object.setTabIndex(value.toInteger(exec)); return; } + case ObjectType: { object.setType(str); return; } + case ObjectUseMap: { object.setUseMap(str); return; } + case ObjectVspace: { object.setVspace(value.toInteger(exec)); return; } + case ObjectWidth: { object.setWidth(str); return; } + } + } + break; + case ID_PARAM: { + DOM::HTMLParamElement param = element; + switch (token) { + case ParamName: { param.setName(str); return; } + case ParamType: { param.setType(str); return; } + case ParamValue: { param.setValue(str); return; } + case ParamValueType: { param.setValueType(str); return; } + } + } + break; + case ID_APPLET: { + DOM::HTMLAppletElement applet = element; + switch (token) { + case AppletAlign: { applet.setAlign(str); return; } + case AppletAlt: { applet.setAlt(str); return; } + case AppletArchive: { applet.setArchive(str); return; } + case AppletCode: { applet.setCode(str); return; } + case AppletCodeBase: { applet.setCodeBase(str); return; } + case AppletHeight: { applet.setHeight(str); return; } + case AppletHspace: { applet.setHspace(value.toInteger(exec)); return; } + case AppletName: { applet.setName(str); return; } + case AppletObject: { applet.setObject(str); return; } + case AppletVspace: { applet.setVspace(value.toInteger(exec)); return; } + case AppletWidth: { applet.setWidth(str); return; } + } + } + break; + case ID_MAP: { + DOM::HTMLMapElement map = element; + switch (token) { + // read-only: areas + case MapName: { map.setName(str); return; } + } + } + break; + case ID_AREA: { + DOM::HTMLAreaElement area = element; + switch (token) { + case AreaAccessKey: { area.setAccessKey(str); return; } + case AreaAlt: { area.setAlt(str); return; } + case AreaCoords: { area.setCoords(str); return; } + case AreaHref: { area.setHref(str); return; } + case AreaNoHref: { area.setNoHref(value.toBoolean(exec)); return; } + case AreaShape: { area.setShape(str); return; } + case AreaTabIndex: { area.setTabIndex(value.toInteger(exec)); return; } + case AreaTarget: { area.setTarget(str); return; } + } + } + break; + case ID_SCRIPT: { + DOM::HTMLScriptElement script = element; + switch (token) { + case ScriptText: { script.setText(str); return; } + case ScriptHtmlFor: { script.setHtmlFor(str); return; } + case ScriptEvent: { script.setEvent(str); return; } + case ScriptCharset: { script.setCharset(str); return; } + case ScriptDefer: { script.setDefer(value.toBoolean(exec)); return; } + case ScriptSrc: { script.setSrc(str); return; } + case ScriptType: { script.setType(str); return; } + } + } + break; + case ID_TABLE: { + DOM::HTMLTableElement table = element; + switch (token) { + case TableCaption: { table.setCaption(n); return; } // type HTMLTableCaptionElement + case TableTHead: { table.setTHead(n); return; } // type HTMLTableSectionElement + case TableTFoot: { table.setTFoot(n); return; } // type HTMLTableSectionElement + // read-only: rows + // read-only: tbodies + case TableAlign: { table.setAlign(str); return; } + case TableBgColor: { table.setBgColor(str); return; } + case TableBorder: { table.setBorder(str); return; } + case TableCellPadding: { table.setCellPadding(str); return; } + case TableCellSpacing: { table.setCellSpacing(str); return; } + case TableFrame: { table.setFrame(str); return; } + case TableRules: { table.setRules(str); return; } + case TableSummary: { table.setSummary(str); return; } + case TableWidth: { table.setWidth(str); return; } + } + } + break; + case ID_CAPTION: { + DOM::HTMLTableCaptionElement tableCaption = element; + switch (token) { + case TableCaptionAlign: { tableCaption.setAlign(str); return; } + } + } + break; + case ID_COL: + case ID_COLGROUP: { + DOM::HTMLTableColElement tableCol = element; + switch (token) { + case TableColAlign: { tableCol.setAlign(str); return; } + case TableColCh: { tableCol.setCh(str); return; } + case TableColChOff: { tableCol.setChOff(str); return; } + case TableColSpan: { tableCol.setSpan(value.toInteger(exec)); return; } + case TableColVAlign: { tableCol.setVAlign(str); return; } + case TableColWidth: { tableCol.setWidth(str); return; } + } + } + break; + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: { + DOM::HTMLTableSectionElement tableSection = element; + switch (token) { + case TableSectionAlign: { tableSection.setAlign(str); return; } + case TableSectionCh: { tableSection.setCh(str); return; } + case TableSectionChOff: { tableSection.setChOff(str); return; } + case TableSectionVAlign: { tableSection.setVAlign(str); return; } + // read-only: rows + } + } + break; + case ID_TR: { + DOM::HTMLTableRowElement tableRow = element; + switch (token) { + // read-only: rowIndex + // read-only: sectionRowIndex + // read-only: cells + case TableRowAlign: { tableRow.setAlign(str); return; } + case TableRowBgColor: { tableRow.setBgColor(str); return; } + case TableRowCh: { tableRow.setCh(str); return; } + case TableRowChOff: { tableRow.setChOff(str); return; } + case TableRowVAlign: { tableRow.setVAlign(str); return; } + } + } + break; + case ID_TH: + case ID_TD: { + DOM::HTMLTableCellElement tableCell = element; + switch (token) { + // read-only: cellIndex + case TableCellAbbr: { tableCell.setAbbr(str); return; } + case TableCellAlign: { tableCell.setAlign(str); return; } + case TableCellAxis: { tableCell.setAxis(str); return; } + case TableCellBgColor: { tableCell.setBgColor(str); return; } + case TableCellCh: { tableCell.setCh(str); return; } + case TableCellChOff: { tableCell.setChOff(str); return; } + case TableCellColSpan: { tableCell.setColSpan(value.toInteger(exec)); return; } + case TableCellHeaders: { tableCell.setHeaders(str); return; } + case TableCellHeight: { tableCell.setHeight(str); return; } + case TableCellNoWrap: { tableCell.setNoWrap(value.toBoolean(exec)); return; } + case TableCellRowSpan: { tableCell.setRowSpan(value.toInteger(exec)); return; } + case TableCellScope: { tableCell.setScope(str); return; } + case TableCellVAlign: { tableCell.setVAlign(str); return; } + case TableCellWidth: { tableCell.setWidth(str); return; } + } + } + break; + case ID_FRAMESET: { + DOM::HTMLFrameSetElement frameSet = element; + switch (token) { + case FrameSetCols: { frameSet.setCols(str); return; } + case FrameSetRows: { frameSet.setRows(str); return; } + } + } + break; + case ID_LAYER: { + DOM::HTMLLayerElement layerElement = element; + switch (token) { + case LayerTop: { layerElement.setTop(value.toInteger(exec)); return; } + case LayerLeft: { layerElement.setLeft(value.toInteger(exec)); return; } + case LayerVisibility: { layerElement.setVisibility(str); return; } + case LayerBgColor: { layerElement.setBgColor(str); return; } + // read-only: layers, clip + } + } + break; + case ID_FRAME: { + DOM::HTMLFrameElement frameElement = element; + switch (token) { + // read-only: FrameContentDocument: + case FrameFrameBorder: { frameElement.setFrameBorder(str); return; } + case FrameLongDesc: { frameElement.setLongDesc(str); return; } + case FrameMarginHeight: { frameElement.setMarginHeight(str); return; } + case FrameMarginWidth: { frameElement.setMarginWidth(str); return; } + case FrameName: { frameElement.setName(str); return; } + case FrameNoResize: { frameElement.setNoResize(value.toBoolean(exec)); return; } + case FrameScrolling: { frameElement.setScrolling(str); return; } + case FrameSrc: { frameElement.setSrc(str); return; } + case FrameLocation: { + static_cast<DOM::HTMLFrameElementImpl *>(frameElement.handle())->setLocation(str); + return; + } + } + } + break; + case ID_IFRAME: { + DOM::HTMLIFrameElement iFrame = element; + switch (token) { + case IFrameAlign: { iFrame.setAlign(str); return; } + // read-only: IFrameContentDocument + case IFrameFrameBorder: { iFrame.setFrameBorder(str); return; } + case IFrameHeight: { iFrame.setHeight(str); return; } + case IFrameLongDesc: { iFrame.setLongDesc(str); return; } + case IFrameMarginHeight: { iFrame.setMarginHeight(str); return; } + case IFrameMarginWidth: { iFrame.setMarginWidth(str); return; } + case IFrameName: { iFrame.setName(str); return; } + case IFrameScrolling: { iFrame.setScrolling(str); return; } + case IFrameSrc: { iFrame.setSrc(str); return; } + case IFrameWidth: { iFrame.setWidth(str); return; } + } + break; + } + } + + // generic properties + switch (token) { + case ElementId: + element.setId(str); + return; + case ElementTitle: + element.setTitle(str); + return; + case ElementLang: + element.setLang(str); + return; + case ElementDir: + element.setDir(str); + return; + case ElementClassName: + element.setClassName(str); + return; + case ElementInnerHTML: + element.setInnerHTML(str); + return; + case ElementInnerText: + element.setInnerText(str); + return; + default: + kdDebug(6070) << "WARNING: KJS::HTMLElement::putValueProperty unhandled token " << token << " thisTag=" << element.tagName().string() << " str=" << str.string() << endl; + } +} + +//Prototype mess for this... +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLElementProto, DOMElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLElement", HTMLElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLElementPseudoCtor, "HTMLElement", HTMLElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLHtmlElement", HTMLHtmlElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLHtmlElementPseudoCtor, "HTMLHtmlElement", HTMLHtmlElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLHeadElement", HTMLHeadElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLHeadElementPseudoCtor, "HTMLHeadElement", HTMLHeadElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLLinkElement", HTMLLinkElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLLinkElementPseudoCtor, "HTMLLinkElement", HTMLLinkElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLTitleElement", HTMLTitleElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTitleElementPseudoCtor, "HTMLTitleElement", HTMLTitleElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLMetaElement", HTMLMetaElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLMetaElementPseudoCtor, "HTMLMetaElement", HTMLMetaElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLBaseElement", HTMLBaseElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLBaseElementPseudoCtor, "HTMLBaseElement", HTMLBaseElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLIsIndexElement", HTMLIsIndexElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLIsIndexElementPseudoCtor, "HTMLIsIndexElement", HTMLIsIndexElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLStyleElement", HTMLStyleElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLStyleElementPseudoCtor, "HTMLStyleElement", HTMLStyleElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLBodyElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLBodyElement", HTMLBodyElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLBodyElementPseudoCtor, "HTMLBodyElement", HTMLBodyElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLFormElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLFormElement", HTMLFormElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLFormElementPseudoCtor, "HTMLFormElement", HTMLFormElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLSelectElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLSelectElement", HTMLSelectElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLSelectElementPseudoCtor, "HTMLSelectElement", HTMLSelectElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLOptGroupElement", HTMLOptGroupElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLOptGroupElementPseudoCtor, "HTMLOptGroupElement", HTMLOptGroupElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLOptionElement", HTMLOptionElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLOptionElementPseudoCtor, "HTMLOptionElement", HTMLOptionElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLInputElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLInputElement", HTMLInputElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLInputElementPseudoCtor, "HTMLInputElement", HTMLInputElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLTextAreaElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLTextAreaElement", HTMLTextAreaElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTextAreaElementPseudoCtor, "HTMLTextAreaElement", HTMLTextAreaElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLButtonElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLButtonElement", HTMLButtonElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLButtonElementPseudoCtor, "HTMLButtonElement", HTMLButtonElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLLabelElement", HTMLLabelElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLLabelElementPseudoCtor, "HTMLLabelElement", HTMLLabelElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLFieldSetElement", HTMLFieldSetElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLFieldSetElementPseudoCtor, "HTMLFieldSetElement", HTMLFieldSetElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLLegendElement", HTMLLegendElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLLegendElementPseudoCtor, "HTMLLegendElement", HTMLLegendElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLUListElement", HTMLUListElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLUListElementPseudoCtor, "HTMLUListElement", HTMLUListElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLOListElement", HTMLOListElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLOListElementPseudoCtor, "HTMLOListElement", HTMLOListElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLDListElement", HTMLDListElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLDListElementPseudoCtor, "HTMLDListElement", HTMLDListElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLDirectoryElement", HTMLDirectoryElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLDirectoryElementPseudoCtor, "HTMLDirectoryElement", HTMLDirectoryElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLMenuElement", HTMLMenuElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLMenuElementPseudoCtor, "HTMLMenuElement", HTMLMenuElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLLIElement", HTMLLIElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLLIElementPseudoCtor, "HTMLLIElement", HTMLLIElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLDivElement", HTMLDivElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLDivElementPseudoCtor, "HTMLDivElement", HTMLDivElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLParagraphElement", HTMLParagraphElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLParagraphElementPseudoCtor, "HTMLParagraphElement", HTMLParagraphElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLHeadingElement", HTMLHeadingElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLHeadingElementPseudoCtor, "HTMLHeadingElement", HTMLHeadingElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLBlockQuoteElement", HTMLBlockQuoteElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLBlockQuoteElementPseudoCtor, "HTMLBlockQuoteElement", HTMLBlockQuoteElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLQuoteElement", HTMLQuoteElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLQuoteElementPseudoCtor, "HTMLQuoteElement", HTMLQuoteElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLPreElement", HTMLPreElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLPreElementPseudoCtor, "HTMLPreElement", HTMLPreElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLBRElement", HTMLBRElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLBRElementPseudoCtor, "HTMLBRElement", HTMLBRElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLBaseFontElement", HTMLBaseFontElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLBaseFontElementPseudoCtor, "HTMLBaseFontElement", HTMLBaseFontElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLFontElement", HTMLFontElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLFontElementPseudoCtor, "HTMLFontElement", HTMLFontElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLHRElement", HTMLHRElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLHRElementPseudoCtor, "HTMLHRElement", HTMLHRElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLModElement", HTMLModElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLModElementPseudoCtor, "HTMLModElement", HTMLModElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLAnchorElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLAnchorElement", HTMLAnchorElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLAnchorElementPseudoCtor, "HTMLAnchorElement", HTMLAnchorElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLImageElement", HTMLImageElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLImageElementPseudoCtor, "HTMLImageElement", HTMLImageElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLObjectElement", HTMLObjectElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLObjectElementPseudoCtor, "HTMLObjectElement", HTMLObjectElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLParamElement", HTMLParamElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLParamElementPseudoCtor, "HTMLParamElement", HTMLParamElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLAppletElement", HTMLAppletElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLAppletElementPseudoCtor, "HTMLAppletElement", HTMLAppletElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLMapElement", HTMLMapElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLMapElementPseudoCtor, "HTMLMapElement", HTMLMapElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLAreaElement", HTMLAreaElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLAreaElementPseudoCtor, "HTMLAreaElement", HTMLAreaElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLScriptElement", HTMLScriptElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLScriptElementPseudoCtor, "HTMLScriptElement", HTMLScriptElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLTableElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLTableElement", HTMLTableElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableElementPseudoCtor, "HTMLTableElement", HTMLTableElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLTableCaptionElement", HTMLTableCaptionElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableCaptionElementPseudoCtor, "HTMLTableCaptionElement", HTMLTableCaptionElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLTableColElement", HTMLTableColElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableColElementPseudoCtor, "HTMLTableColElement", HTMLTableColElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLTableSectionElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLTableSectionElement", HTMLTableSectionElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableSectionElementPseudoCtor, "HTMLTableSectionElement", HTMLTableSectionElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLTableRowElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLTableRowElement", HTMLTableRowElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableRowElementPseudoCtor, "HTMLTableRowElement", HTMLTableRowElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLTableCellElement", HTMLTableCellElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLTableCellElementPseudoCtor, "HTMLTableCellElement", HTMLTableCellElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLFrameSetElement", HTMLFrameSetElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLFrameSetElementPseudoCtor, "HTMLFrameSetElement", HTMLFrameSetElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLLayerElement", HTMLLayerElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLLayerElementPseudoCtor, "HTMLLayerElement", HTMLLayerElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLFrameElement", HTMLFrameElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLFrameElementPseudoCtor, "HTMLFrameElement", HTMLFrameElementProto) + +KJS_EMPTY_PROTOTYPE_WITH_PROTOTYPE("HTMLIFrameElement", HTMLIFrameElementProto, HTMLElementProto) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLIFrameElementPseudoCtor, "HTMLIFrameElement", HTMLIFrameElementProto) + +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLMarqueeElementProto, HTMLElementProto) +KJS_IMPLEMENT_PROTOTYPE("HTMLMarqueeElement", HTMLMarqueeElementProto, HTMLElementFunction) +IMPLEMENT_PSEUDO_CONSTRUCTOR(HTMLMarqueeElementPseudoCtor, "HTMLMarqueeElement", HTMLMarqueeElementProto) + +static Object prototypeForID(ExecState* exec, DOM::NodeImpl::Id id) { + switch (id) { + case ID_HTML: + return HTMLHtmlElementProto::self(exec); + case ID_HEAD: + return HTMLHeadElementProto::self(exec); + case ID_LINK: + return HTMLLinkElementProto::self(exec); + case ID_TITLE: + return HTMLTitleElementProto::self(exec); + case ID_META: + return HTMLMetaElementProto::self(exec); + case ID_BASE: + return HTMLBaseElementProto::self(exec); + case ID_ISINDEX: + return HTMLIsIndexElementProto::self(exec); + case ID_STYLE: + return HTMLStyleElementProto::self(exec); + case ID_BODY: + return HTMLBodyElementProto::self(exec); + case ID_FORM: + return HTMLFormElementProto::self(exec); + case ID_SELECT: + return HTMLSelectElementProto::self(exec); + case ID_OPTGROUP: + return HTMLOptGroupElementProto::self(exec); + case ID_OPTION: + return HTMLOptionElementProto::self(exec); + case ID_INPUT: + return HTMLInputElementProto::self(exec); + case ID_TEXTAREA: + return HTMLTextAreaElementProto::self(exec); + case ID_BUTTON: + return HTMLButtonElementProto::self(exec); + case ID_LABEL: + return HTMLLabelElementProto::self(exec); + case ID_FIELDSET: + return HTMLFieldSetElementProto::self(exec); + case ID_LEGEND: + return HTMLLegendElementProto::self(exec); + case ID_UL: + return HTMLUListElementProto::self(exec); + case ID_OL: + return HTMLOListElementProto::self(exec); + case ID_DL: + return HTMLDListElementProto::self(exec); + case ID_DIR: + return HTMLDirectoryElementProto::self(exec); + case ID_MENU: + return HTMLMenuElementProto::self(exec); + case ID_LI: + return HTMLLIElementProto::self(exec); + case ID_DIV: + return HTMLDivElementProto::self(exec); + case ID_P: + return HTMLParagraphElementProto::self(exec); + case ID_H1: + case ID_H2: + case ID_H3: + case ID_H4: + case ID_H5: + case ID_H6: + return HTMLHeadingElementProto::self(exec); + case ID_BLOCKQUOTE: + return HTMLBlockQuoteElementProto::self(exec); + case ID_Q: + return HTMLQuoteElementProto::self(exec); + case ID_PRE: + return HTMLPreElementProto::self(exec); + case ID_BR: + return HTMLBRElementProto::self(exec); + case ID_BASEFONT: + return HTMLBaseFontElementProto::self(exec); + case ID_FONT: + return HTMLFontElementProto::self(exec); + case ID_HR: + return HTMLHRElementProto::self(exec); + case ID_INS: + case ID_DEL: + return HTMLModElementProto::self(exec); + case ID_A: + return HTMLAnchorElementProto::self(exec); + case ID_IMG: + return HTMLImageElementProto::self(exec); + case ID_OBJECT: + return HTMLObjectElementProto::self(exec); + case ID_PARAM: + return HTMLParamElementProto::self(exec); + case ID_APPLET: + return HTMLAppletElementProto::self(exec); + case ID_MAP: + return HTMLMapElementProto::self(exec); + case ID_AREA: + return HTMLAreaElementProto::self(exec); + case ID_SCRIPT: + return HTMLScriptElementProto::self(exec); + case ID_TABLE: + return HTMLTableElementProto::self(exec); + case ID_CAPTION: + return HTMLTableCaptionElementProto::self(exec); + case ID_COL: + case ID_COLGROUP: + return HTMLTableColElementProto::self(exec); + case ID_THEAD: + case ID_TBODY: + case ID_TFOOT: + return HTMLTableSectionElementProto::self(exec); + case ID_TR: + return HTMLTableRowElementProto::self(exec); + case ID_TD: + case ID_TH: + return HTMLTableCellElementProto::self(exec); + case ID_FRAMESET: + return HTMLFrameSetElementProto::self(exec); + case ID_LAYER: + return HTMLLayerElementProto::self(exec); + case ID_FRAME: + return HTMLFrameElementProto::self(exec); + case ID_IFRAME: + return HTMLIFrameElementProto::self(exec); + case ID_MARQUEE: + return HTMLMarqueeElementProto::self(exec); + default: + return HTMLElementProto::self(exec); + } +} + +// ------------------------------------------------------------------------- +/* Source for HTMLCollectionProtoTable. +@begin HTMLCollectionProtoTable 3 + item HTMLCollection::Item DontDelete|Function 1 + namedItem HTMLCollection::NamedItem DontDelete|Function 1 + tags HTMLCollection::Tags DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(HTMLCollectionProto) +IMPLEMENT_PROTOFUNC_DOM(HTMLCollectionProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("HTMLCollection", HTMLCollectionProto,HTMLCollectionProtoFunc) + +const ClassInfo KJS::HTMLCollection::info = { "HTMLCollection", 0, 0, 0 }; + +KJS::HTMLCollection::HTMLCollection(ExecState *exec, const DOM::HTMLCollection& c) + : DOMObject(HTMLCollectionProto::self(exec)), collection(c), hidden(false) {} + +KJS::HTMLCollection::HTMLCollection(const KJS::Object& proto, const DOM::HTMLCollection& c) + : DOMObject(proto), collection(c), hidden(false) {} + +KJS::HTMLCollection::~HTMLCollection() +{ + ScriptInterpreter::forgetDOMObject(collection.handle()); +} + +bool KJS::HTMLCollection::toBoolean(ExecState *) const { + return !hidden; +} + +// We have to implement hasProperty since we don't use a hashtable for 'selectedIndex' and 'length', +// and for indices in "for (..in..)" +bool KJS::HTMLCollection::hasProperty(ExecState *exec, const Identifier &p) const +{ + if (p == lengthPropertyName) + return true; + if ( collection.handle()->getType() == HTMLCollectionImpl::SELECT_OPTIONS && + ( p == "selectedIndex" || p == "value" ) ) + return true; + + bool ok; + unsigned long pos = p.toULong(&ok); + if (ok && pos < collection.length()) + return true; + + return DOMObject::hasProperty(exec, p); +} + +ReferenceList KJS::HTMLCollection::propList(ExecState *exec, bool recursive) +{ + ReferenceList properties = ObjectImp::propList(exec,recursive); + + for (unsigned i = 0; i < collection.length(); ++i) { + if (!ObjectImp::hasProperty(exec,Identifier::from(i))) { + properties.append(Reference(this, i)); + } + } + + if (!ObjectImp::hasProperty(exec, lengthPropertyName)) + properties.append(Reference(this, lengthPropertyName)); + + return properties; +} + +Value KJS::HTMLCollection::tryGet(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLCollection::tryGet " << propertyName.ascii() << endl; +#endif + if (propertyName == lengthPropertyName) + { +#ifdef KJS_VERBOSE + kdDebug(6070) << " collection length is " << collection.length() << endl; +#endif + return Number(collection.length()); + } + + if (collection.handle()->getType() == HTMLCollectionImpl::SELECT_OPTIONS) { + DOM::HTMLSelectElement parentSelect = collection.base(); + if ( parentSelect.isNull() ) + return Undefined(); + if (propertyName == "selectedIndex") { + // NON-STANDARD options.selectedIndex + return Number(parentSelect.selectedIndex()); + } else if ( propertyName == "value" ) { + // NON-STANDARD options.value + return String(parentSelect.value()); + } + } + + // Look in the prototype (for functions) before assuming it's an item's name + Object proto = Object::dynamicCast(prototype()); + if (proto.isValid() && proto.hasProperty(exec,propertyName)) + return proto.get(exec,propertyName); + + // name or index ? + bool ok; + unsigned int u = propertyName.toULong(&ok); + if (ok) { + if ( u < collection.length() ) { + DOM::Node node = collection.item(u); + return getDOMNode(exec,node); + } else + return Undefined(); + } + else + return getNamedItems(exec,propertyName); +} + +// HTMLCollections are strange objects, they support both get and call, +// so that document.forms.item(0) and document.forms(0) both work. +Value KJS::HTMLCollection::call(ExecState *exec, Object &thisObj, const List &args) +{ + // This code duplication is necessary, HTMLCollection isn't a DOMFunction + Value val; + try { + val = tryCall(exec, thisObj, args); + } + // pity there's no way to distinguish between these in JS code + catch (...) { + Object err = Error::create(exec, GeneralError, "Exception from HTMLCollection"); + exec->setException(err); + } + return val; +} + +Value KJS::HTMLCollection::tryCall(ExecState *exec, Object &, const List &args) +{ + // Do not use thisObj here. It can be the HTMLDocument, in the document.forms(i) case. + /*if( thisObj.imp() != this ) + { + kdDebug(6070) << "WARNING: thisObj.imp() != this in HTMLCollection::tryCall" << endl; + KJS::printInfo(exec,"KJS::HTMLCollection::tryCall thisObj",thisObj,-1); + KJS::printInfo(exec,"KJS::HTMLCollection::tryCall this",Value(this),-1); + }*/ + // Also, do we need the TypeError test here ? + + if (args.size() == 1) { + // support for document.all(<index>) etc. + bool ok; + UString s = args[0].toString(exec); + unsigned int u = s.toULong(&ok); + if (ok) { + DOM::Element element = collection.item(u); + return getDOMNode(exec,element); + } + // support for document.images('<name>') etc. + return getNamedItems(exec,Identifier(s)); + } + else if (args.size() >= 1) // the second arg, if set, is the index of the item we want + { + bool ok; + UString s = args[0].toString(exec); + unsigned int u = args[1].toString(exec).toULong(&ok); + if (ok) + { + DOM::DOMString pstr = s.string(); + DOM::Node node = collection.namedItem(pstr); + while (!node.isNull()) { + if (!u) + return getDOMNode(exec,node); + node = collection.nextNamedItem(pstr); + --u; + } + } + } + return Undefined(); +} + +Value KJS::HTMLCollection::getNamedItems(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLCollection::getNamedItems " << propertyName.ascii() << endl; +#endif + + DOM::DOMString pstr = propertyName.string(); + + QValueList<DOM::NodeImpl*> matches = collection.handle()->namedItems(pstr); + + if (!matches.isEmpty()) { + if (matches.size() == 1) { + DOM::Node node(matches[0]); +#ifdef KJS_VERBOSE + kdDebug(6070) << "returning single node" << endl; +#endif + return getDOMNode(exec,node); + } + else { + // multiple items, return a collection + QValueList<DOM::Node> nodes; + for (QValueList<DOM::NodeImpl*>::const_iterator i = matches.begin(); + i != matches.end(); ++i) + nodes.append(DOM::Node(*i)); +#ifdef KJS_VERBOSE + kdDebug(6070) << "returning list of " << nodes.count() << " nodes" << endl; +#endif + return Value(new DOMNamedNodesCollection(exec, nodes)); + } + } +#ifdef KJS_VERBOSE + kdDebug(6070) << "not found" << endl; +#endif + return Undefined(); +} + +Value KJS::HTMLCollectionProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::HTMLCollection, thisObj ); + DOM::HTMLCollection coll = static_cast<KJS::HTMLCollection *>(thisObj.imp())->toCollection(); + + switch (id) { + case KJS::HTMLCollection::Item: + { + // support for item(<index>) (DOM) + bool ok; + UString s = args[0].toString(exec); + unsigned int u = s.toULong(&ok); + if (ok) { + return getDOMNode(exec,coll.item(u)); + } + // support for item('<name>') (IE only) + kdWarning() << "non-standard HTMLCollection.item('" << s.ascii() << "') called, use namedItem instead" << endl; + return getDOMNode(exec,coll.namedItem(s.string())); + } + case KJS::HTMLCollection::Tags: + { + DOM::DOMString tagName = args[0].toString(exec).string(); + DOM::NodeList list; + // getElementsByTagName exists in Document and in Element, pick up the right one + if ( coll.base().nodeType() == DOM::Node::DOCUMENT_NODE ) + { + DOM::Document doc = coll.base(); + list = doc.getElementsByTagName(tagName); +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLCollectionProtoFunc::tryCall document.tags(" << tagName.string() << ") -> " << list.length() << " items in node list" << endl; +#endif + } else + { + DOM::Element e = coll.base(); + list = e.getElementsByTagName(tagName); +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLCollectionProtoFunc::tryCall element.tags(" << tagName.string() << ") -> " << list.length() << " items in node list" << endl; +#endif + } + return getDOMNodeList(exec, list); + } + case KJS::HTMLCollection::NamedItem: + { + Value val = static_cast<HTMLCollection *>(thisObj.imp())->getNamedItems(exec, Identifier(args[0].toString(exec))); + // Must return null when asking for a named item that isn't in the collection + // (DOM2 testsuite, HTMLCollection12 test) + if ( val.type() == KJS::UndefinedType ) + return Null(); + else + return val; + } + default: + return Undefined(); + } +} + +// ------------------------------------------------------------------------- +/* Source for HTMLSelectCollectionProtoTable. +@begin HTMLSelectCollectionProtoTable 1 + add HTMLSelectCollection::Add DontDelete|Function 2 +@end +*/ +KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(HTMLSelectCollectionProto, HTMLCollectionProto) +IMPLEMENT_PROTOFUNC_DOM(HTMLSelectCollectionProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("HTMLOptionsCollection", HTMLSelectCollectionProto, HTMLSelectCollectionProtoFunc) + +const ClassInfo KJS::HTMLSelectCollection::info = { "HTMLOptionsCollection", &HTMLCollection::info, 0, 0 }; + +KJS::HTMLSelectCollection::HTMLSelectCollection(ExecState *exec, const DOM::HTMLCollection& c, + const DOM::HTMLSelectElement& e) + : HTMLCollection(HTMLSelectCollectionProto::self(exec), c), element(e) { } + +Value KJS::HTMLSelectCollection::tryGet(ExecState *exec, const Identifier &p) const +{ + if (p == "selectedIndex") + return Number(element.selectedIndex()); + + return HTMLCollection::tryGet(exec, p); +} + +void KJS::HTMLSelectCollection::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "KJS::HTMLSelectCollection::tryPut " << propertyName.qstring() << endl; +#endif + if ( propertyName == "selectedIndex" ) { + element.setSelectedIndex( value.toInteger( exec ) ); + return; + } + // resize ? + else if (propertyName == lengthPropertyName) { + unsigned newLen; + bool converted = value.toUInt32(newLen); + + if (!converted) { + return; + } + + long diff = element.length() - newLen; + + if (diff < 0) { // add dummy elements + do { + element.add(element.ownerDocument().createElement("OPTION"), DOM::HTMLElement()); + } while (++diff); + } + else // remove elements + while (diff-- > 0) + element.remove(newLen + diff); + + return; + } + // an index ? + bool ok; + unsigned int u = propertyName.toULong(&ok); + if (!ok) + return; + + if (value.isA(NullType) || value.isA(UndefinedType)) { + // null and undefined delete. others, too ? + element.remove(u); + return; + } + + // is v an option element ? + DOM::Node node = KJS::toNode(value); + if (node.isNull() || node.elementId() != ID_OPTION) + return; + + DOM::HTMLOptionElement option = static_cast<DOM::HTMLOptionElement>(node); + if ( option.ownerDocument() != element.ownerDocument() ) + option = static_cast<DOM::HTMLOptionElement>(element.ownerDocument().importNode(option, true)); + long diff = long(u) - element.length(); + DOM::HTMLElement before; + // out of array bounds ? first insert empty dummies + if (diff > 0) { + while (diff--) { + element.add(element.ownerDocument().createElement("OPTION"), before); + } + // replace an existing entry ? + } else if (diff < 0) { + before = element.options().item(u+1); + element.remove(u); + } + // finally add the new element + element.add(option, before); +} + + +Value KJS::HTMLSelectCollectionProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::HTMLSelectCollection, thisObj ); + DOM::HTMLSelectElement element = static_cast<KJS::HTMLSelectCollection *>(thisObj.imp())->toElement(); + + switch (id) { + case KJS::HTMLSelectCollection::Add: + { + //Non-standard select.options.add. + //The first argument is the item, 2nd is offset. + //IE and Mozilla are both quite picky here, too... + DOM::Node node = KJS::toNode(args[0]); + if (node.isNull() || node.elementId() != ID_OPTION) { + Object err = Error::create(exec, GeneralError, "Invalid argument to HTMLOptionsCollection::add"); + exec->setException(err); + return Undefined(); + } + + DOM::HTMLOptionElement option = static_cast<DOM::HTMLOptionElement>(node); + if ( option.ownerDocument() != element.ownerDocument() ) //### remove this once auto-adopt works... + option = static_cast<DOM::HTMLOptionElement>(element.ownerDocument().importNode(option, true)); + + int pos = 0; + //By default append, if not specified or null.. + if (args[1].isA(UndefinedType)) + pos = element.length(); + else + pos = (int)args[1].toNumber(exec); + + if (pos < 0) { + Object err = Error::create(exec, GeneralError, "Invalid index argument to HTMLOptionsCollection::add"); + exec->setException(err); + return Undefined(); + } + + if (pos >= element.length()) { + //Append + element.add(option, DOM::Node()); + } else { + //Find what to prepend before.. + DOM::HTMLSelectElementImpl* impl = static_cast<HTMLSelectElementImpl*>(element.handle()); + QMemArray<HTMLGenericFormElementImpl*> items = impl->listItems(); + int dummy; + impl->insertBefore(option.handle(), items.at(pos), dummy); + } + return Undefined(); + break; + } + default: + break; + } + return Undefined(); +} + + +////////////////////// Option Object //////////////////////// + +OptionConstructorImp::OptionConstructorImp(ExecState *exec, const DOM::Document &d) + : ObjectImp(), doc(d) +{ + // ## isn't there some redundancy between ObjectImp::_proto and the "prototype" property ? + //put(exec,"prototype", ...,DontEnum|DontDelete|ReadOnly); + + // no. of arguments for constructor + // ## is 4 correct ? 0 to 4, it seems to be + put(exec,lengthPropertyName, Number(4), ReadOnly|DontDelete|DontEnum); +} + +bool OptionConstructorImp::implementsConstruct() const +{ + return true; +} + +Object OptionConstructorImp::construct(ExecState *exec, const List &args) +{ + DOM::Element el = doc.createElement("OPTION"); + DOM::HTMLOptionElement opt = static_cast<DOM::HTMLOptionElement>(el); + int sz = args.size(); + DOM::Text t = doc.createTextNode(""); + try { opt.appendChild(t); } + catch(DOM::DOMException& e) { + // #### exec->setException ? + } + if (sz > 0) + t.setData(args[0].toString(exec).string()); // set the text + if (sz > 1) + opt.setValue(args[1].toString(exec).string()); + if (sz > 2) + opt.setDefaultSelected(args[2].toBoolean(exec)); + if (sz > 3) + opt.setSelected(args[3].toBoolean(exec)); + + return Object::dynamicCast(getDOMNode(exec,opt)); +} + +////////////////////// Image Object //////////////////////// + +//Like in other browsers, we merely make a new HTMLImageElement +//not in tree for this. +ImageConstructorImp::ImageConstructorImp(ExecState *, const DOM::Document &d) + : ObjectImp(), doc(d) +{ +} + +bool ImageConstructorImp::implementsConstruct() const +{ + return true; +} + +Object ImageConstructorImp::construct(ExecState *exec, const List &list) +{ + bool widthSet = false, heightSet = false; + int width = 0, height = 0; + if (list.size() > 0) { + widthSet = true; + Value w = list.at(0); + width = w.toInt32(exec); + } + if (list.size() > 1) { + heightSet = true; + Value h = list.at(1); + height = h.toInt32(exec); + } + + HTMLImageElement image(doc.createElement("image")); + + if (widthSet) + image.setWidth(width); + + if (heightSet) + image.setHeight(height); + + return Object::dynamicCast(getDOMNode(exec,image)); +} + +Value getHTMLCollection(ExecState *exec, const DOM::HTMLCollection& c, bool hide) +{ + Value coll = cacheDOMObject<DOM::HTMLCollection, KJS::HTMLCollection>(exec, c); + if (hide) { + KJS::HTMLCollection *impl = static_cast<KJS::HTMLCollection*>(coll.imp()); + impl->hide(); + } + return coll; +} + +Value getSelectHTMLCollection(ExecState *exec, const DOM::HTMLCollection& c, const DOM::HTMLSelectElement& e) +{ + DOMObject *ret; + if (c.isNull()) + return Null(); + ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter()); + if ((ret = interp->getDOMObject(c.handle()))) + return Value(ret); + else { + ret = new HTMLSelectCollection(exec, c, e); + interp->putDOMObject(c.handle(),ret); + return Value(ret); + } +} + +} //namespace KJS diff --git a/khtml/ecma/kjs_html.h b/khtml/ecma/kjs_html.h new file mode 100644 index 000000000..53da38462 --- /dev/null +++ b/khtml/ecma/kjs_html.h @@ -0,0 +1,294 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999 Harri Porten (porten@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_HTML_H_ +#define _KJS_HTML_H_ + +#include "dom/html_document.h" +#include "dom/html_base.h" +#include "dom/html_misc.h" +#include "dom/html_form.h" +#include "misc/loader_client.h" + +#include "ecma/kjs_binding.h" +#include "ecma/kjs_dom.h" +#include "xml/dom_nodeimpl.h" // for NodeImpl::Id + +namespace KJS { + + class HTMLElement; + + class HTMLDocument : public DOMDocument { + public: + HTMLDocument(ExecState *exec, const DOM::HTMLDocument& d); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/); + virtual bool hasProperty(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Title, Referrer, Domain, URL, Body, Location, Cookie, + Images, Applets, Links, Forms, Layers, Anchors, Scripts, All, Clear, Open, Close, + Write, WriteLn, GetElementsByName, GetSelection, CaptureEvents, ReleaseEvents, + BgColor, FgColor, AlinkColor, LinkColor, VlinkColor, LastModified, + Height, Width, Dir, Frames, CompatMode }; + DOM::Document toDocument() const { return static_cast<DOM::Document>( node ); } + }; + + DEFINE_PSEUDO_CONSTRUCTOR(HTMLDocumentPseudoCtor) + + class HTMLElement : public DOMElement { + public: + HTMLElement(ExecState *exec, const DOM::HTMLElement& e); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int); + virtual bool hasProperty(ExecState *exec, const Identifier &propertyName) const; + virtual UString toString(ExecState *exec) const; + virtual void pushEventHandlerScope(ExecState *exec, ScopeChain &scope) const; + virtual const ClassInfo* classInfo() const; + static const ClassInfo info; + + static const ClassInfo html_info, head_info, link_info, title_info, + meta_info, base_info, isIndex_info, style_info, body_info, form_info, + select_info, optGroup_info, option_info, input_info, textArea_info, + button_info, label_info, fieldSet_info, legend_info, ul_info, ol_info, + dl_info, dir_info, menu_info, li_info, div_info, p_info, heading_info, + blockQuote_info, q_info, pre_info, br_info, baseFont_info, font_info, + hr_info, mod_info, a_info, img_info, object_info, param_info, + applet_info, map_info, area_info, script_info, table_info, + caption_info, col_info, tablesection_info, tr_info, + tablecell_info, frameSet_info, frame_info, iFrame_info, marquee_info, layer_info; + + enum { HtmlVersion, HeadProfile, LinkHref, LinkRel, LinkMedia, + LinkCharset, LinkDisabled, LinkHrefLang, LinkRev, LinkTarget, LinkType, + LinkSheet, TitleText, MetaName, MetaHttpEquiv, MetaContent, MetaScheme, + BaseHref, BaseTarget, IsIndexForm, IsIndexPrompt, StyleDisabled, + StyleSheet, StyleType, StyleMedia, BodyBackground, BodyVLink, BodyText, + BodyLink, BodyALink, BodyBgColor, BodyOnLoad, BodyFocus, + FormAction, FormEncType, FormElements, FormLength, FormAcceptCharset, + FormReset, FormTarget, FormName, FormMethod, FormSubmit, SelectAdd, + SelectTabIndex, SelectValue, SelectSelectedIndex, SelectLength, + SelectRemove, SelectForm, SelectBlur, SelectType, SelectOptions, + SelectDisabled, SelectMultiple, SelectName, SelectSize, SelectFocus, + OptGroupDisabled, OptGroupLabel, OptionIndex, OptionSelected, + OptionForm, OptionText, OptionDefaultSelected, OptionDisabled, + OptionLabel, OptionValue, InputBlur, InputReadOnly, InputAccept, + InputSize, InputDefaultValue, InputTabIndex, InputValue, InputType, + InputFocus, InputMaxLength, InputDefaultChecked, InputDisabled, + InputChecked, InputIndeterminate, InputForm, InputAccessKey, InputAlign, InputAlt, + InputName, InputSrc, InputUseMap, InputSelect, InputClick, + InputSelectionStart, InputSelectionEnd, InputSetSelectionRange, + TextAreaAccessKey, TextAreaName, TextAreaDefaultValue, TextAreaSelect, + TextAreaCols, TextAreaDisabled, TextAreaForm, TextAreaType, + TextAreaTabIndex, TextAreaReadOnly, TextAreaRows, TextAreaValue, + TextAreaBlur, TextAreaFocus, TextAreaSelectionStart, TextAreaSelectionEnd, TextAreaSetSelectionRange, + TextAreaTextLength, ButtonBlur, ButtonFocus, ButtonForm, ButtonTabIndex, ButtonName, + ButtonDisabled, ButtonAccessKey, ButtonType, ButtonValue, LabelHtmlFor, + LabelForm, LabelAccessKey, FieldSetForm, LegendForm, LegendAccessKey, + LegendAlign, UListType, UListCompact, OListStart, OListCompact, + OListType, DListCompact, DirectoryCompact, MenuCompact, LIType, + LIValue, DivAlign, ParagraphAlign, HeadingAlign, BlockQuoteCite, + QuoteCite, PreWidth, BRClear, BaseFontColor, BaseFontSize, + BaseFontFace, FontColor, FontSize, FontFace, HRWidth, HRNoShade, + HRAlign, HRSize, ModCite, ModDateTime, AnchorShape, AnchorRel, + AnchorAccessKey, AnchorCoords, AnchorHref, AnchorProtocol, AnchorHost, + AnchorCharset, AnchorHrefLang, AnchorHostname, AnchorType, AnchorFocus, + AnchorPort, AnchorPathName, AnchorHash, AnchorSearch, AnchorName, + AnchorRev, AnchorTabIndex, AnchorTarget, AnchorText, AnchorBlur, AnchorClick, + ImageName, ImageAlign, ImageHspace, ImageVspace, ImageUseMap, ImageAlt, + ImageLowSrc, ImageWidth, ImageIsMap, ImageBorder, ImageHeight, + ImageLongDesc, ImageSrc, ImageX, ImageY, ImageComplete, ObjectHspace, ObjectHeight, ObjectAlign, + ObjectBorder, ObjectCode, ObjectType, ObjectVspace, ObjectArchive, + ObjectDeclare, ObjectForm, ObjectCodeBase, ObjectCodeType, ObjectData, + ObjectName, ObjectStandby, ObjectTabIndex, ObjectUseMap, ObjectWidth, ObjectContentDocument, + ParamName, ParamType, ParamValueType, ParamValue, AppletArchive, + AppletAlt, AppletCode, AppletWidth, AppletAlign, AppletCodeBase, + AppletName, AppletHeight, AppletHspace, AppletObject, AppletVspace, + MapAreas, MapName, AreaHash, AreaHref, AreaTarget, AreaPort, AreaShape, + AreaCoords, AreaAlt, AreaAccessKey, AreaNoHref, AreaHost, AreaProtocol, + AreaHostName, AreaPathName, AreaSearch, AreaTabIndex, ScriptEvent, + ScriptType, ScriptHtmlFor, ScriptText, ScriptSrc, ScriptCharset, + ScriptDefer, TableSummary, TableTBodies, TableTHead, TableCellPadding, + TableDeleteCaption, TableCreateCaption, TableCaption, TableWidth, + TableCreateTFoot, TableAlign, TableTFoot, TableDeleteRow, + TableCellSpacing, TableRows, TableBgColor, TableBorder, TableFrame, + TableRules, TableCreateTHead, TableDeleteTHead, TableDeleteTFoot, + TableInsertRow, TableCaptionAlign, TableColCh, TableColChOff, + TableColAlign, TableColSpan, TableColVAlign, TableColWidth, + TableSectionCh, TableSectionDeleteRow, TableSectionChOff, + TableSectionRows, TableSectionAlign, TableSectionVAlign, + TableSectionInsertRow, TableRowSectionRowIndex, TableRowRowIndex, + TableRowChOff, TableRowCells, TableRowVAlign, TableRowCh, + TableRowAlign, TableRowBgColor, TableRowDeleteCell, TableRowInsertCell, + TableCellColSpan, TableCellNoWrap, TableCellAbbr, TableCellHeight, + TableCellWidth, TableCellCellIndex, TableCellChOff, TableCellBgColor, + TableCellCh, TableCellVAlign, TableCellRowSpan, TableCellHeaders, + TableCellAlign, TableCellAxis, TableCellScope, FrameSetCols, + FrameSetRows, FrameSrc, FrameLocation, FrameFrameBorder, FrameScrolling, + FrameMarginWidth, FrameLongDesc, FrameMarginHeight, FrameName, + FrameContentDocument, FrameContentWindow, + FrameNoResize, FrameWidth, FrameHeight, IFrameLongDesc, IFrameAlign, + IFrameFrameBorder, IFrameSrc, IFrameName, IFrameHeight, + IFrameMarginHeight, IFrameMarginWidth, IFrameScrolling, IFrameWidth, + IFrameContentDocument, IFrameContentWindow, + MarqueeStart, MarqueeStop, + LayerTop, LayerLeft, LayerVisibility, LayerBgColor, LayerClip, LayerDocument, LayerLayers, + ElementInnerHTML, ElementTitle, ElementId, ElementDir, ElementLang, + ElementClassName, ElementInnerText, ElementDocument, + ElementChildren, ElementAll, ElementScrollIntoView }; + + DOM::HTMLElement toElement() const { return static_cast<DOM::HTMLElement>(node); } + }; + + class HTMLElementFunction : public DOMFunction { + public: + HTMLElementFunction(ExecState *exec, int i, int len); + virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args); + private: + int id; + }; + + class HTMLCollection : public DOMObject { + public: + HTMLCollection(ExecState *exec, const DOM::HTMLCollection& c); + HTMLCollection(const KJS::Object& proto, const DOM::HTMLCollection& c); + ~HTMLCollection(); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual Value call(ExecState *exec, Object &thisObj, const List&args); + virtual Value tryCall(ExecState *exec, Object &thisObj, const List&args); + virtual bool implementsCall() const { return true; } + virtual bool toBoolean(ExecState *) const; + virtual bool hasProperty(ExecState *exec, const Identifier &p) const; + virtual ReferenceList propList(ExecState *exec, bool recursive); + enum { Item, NamedItem, Tags }; + Value getNamedItems(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + DOM::HTMLCollection toCollection() const { return collection; } + virtual void hide() { hidden = true; } + protected: + DOM::HTMLCollection collection; + bool hidden; + }; + + class HTMLSelectCollection : public HTMLCollection { + public: + enum { Add }; + HTMLSelectCollection(ExecState *exec, const DOM::HTMLCollection& c, const DOM::HTMLSelectElement& e); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + + DOM::HTMLSelectElement toElement() const { return element; } + private: + DOM::HTMLSelectElement element; + }; + + ////////////////////// Option Object //////////////////////// + + class OptionConstructorImp : public ObjectImp { + public: + OptionConstructorImp(ExecState *exec, const DOM::Document &d); + virtual bool implementsConstruct() const; + virtual Object construct(ExecState *exec, const List &args); + private: + DOM::Document doc; + }; + + ////////////////////// Image Object //////////////////////// + + class ImageConstructorImp : public ObjectImp { + public: + ImageConstructorImp(ExecState *exec, const DOM::Document &d); + virtual bool implementsConstruct() const; + virtual Object construct(ExecState *exec, const List &args); + private: + DOM::Document doc; + }; + + Value getHTMLCollection(ExecState *exec, const DOM::HTMLCollection& c, bool hide=false); + Value getSelectHTMLCollection(ExecState *exec, const DOM::HTMLCollection& c, const DOM::HTMLSelectElement& e); + + + //All the pseudo constructors.. + DEFINE_PSEUDO_CONSTRUCTOR(HTMLElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLHtmlElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLHeadElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLLinkElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTitleElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLMetaElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLBaseElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLIsIndexElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLStyleElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLBodyElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLFormElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLSelectElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLOptGroupElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLOptionElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLInputElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTextAreaElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLButtonElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLLabelElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLFieldSetElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLLegendElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLUListElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLOListElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLDListElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLDirectoryElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLMenuElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLLIElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLDivElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLParagraphElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLHeadingElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLBlockQuoteElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLQuoteElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLPreElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLBRElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLBaseFontElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLFontElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLHRElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLModElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLAnchorElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLImageElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLObjectElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLParamElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLAppletElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLMapElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLAreaElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLScriptElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableCaptionElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableColElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableSectionElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableRowElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLTableCellElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLFrameSetElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLLayerElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLFrameElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLIFrameElementPseudoCtor) + DEFINE_PSEUDO_CONSTRUCTOR(HTMLMarqueeElementPseudoCtor) +} // namespace + +#endif diff --git a/khtml/ecma/kjs_mozilla.cpp b/khtml/ecma/kjs_mozilla.cpp new file mode 100644 index 000000000..4b1520b9a --- /dev/null +++ b/khtml/ecma/kjs_mozilla.cpp @@ -0,0 +1,94 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (c) 2003 George Staikos (staikos@kde.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <klocale.h> +#include <kdebug.h> + +#include "kjs_mozilla.h" +#include "kjs/lookup.h" +#include "kjs_binding.h" +#include "khtml_part.h" +#include "kjs_mozilla.lut.h" + +using namespace KJS; + +namespace KJS { + +const ClassInfo MozillaSidebarExtension::info = { "sidebar", 0, &MozillaSidebarExtensionTable, 0 }; +/* +@begin MozillaSidebarExtensionTable 1 + addPanel MozillaSidebarExtension::addPanel DontDelete|Function 0 +@end +*/ +} +IMPLEMENT_PROTOFUNC_DOM(MozillaSidebarExtensionFunc) + +MozillaSidebarExtension::MozillaSidebarExtension(ExecState *exec, KHTMLPart *p) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()), m_part(p) { } + +Value MozillaSidebarExtension::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "MozillaSidebarExtension::get " << propertyName.ascii() << endl; +#endif + return lookupGet<MozillaSidebarExtensionFunc,MozillaSidebarExtension,ObjectImp>(exec,propertyName,&MozillaSidebarExtensionTable,this); +} + +Value MozillaSidebarExtension::getValueProperty(ExecState *exec, int token) const +{ + Q_UNUSED(exec); + switch (token) { + default: + kdDebug(6070) << "WARNING: Unhandled token in MozillaSidebarExtension::getValueProperty : " << token << endl; + return Value(); + } +} + +Value MozillaSidebarExtensionFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::MozillaSidebarExtension, thisObj ); + MozillaSidebarExtension *mse = static_cast<MozillaSidebarExtension*>(thisObj.imp()); + + KHTMLPart *part = mse->part(); + if (!part) + return Undefined(); + + // addPanel() id == 0 + KParts::BrowserExtension *ext = part->browserExtension(); + if (ext) { + QString url, name; + if (args.size() == 1) { // I've seen this, don't know if it's legal. + name = QString::null; + url = args[0].toString(exec).qstring(); + } else if (args.size() == 2 || args.size() == 3) { + name = args[0].toString(exec).qstring(); + url = args[1].toString(exec).qstring(); + // 2 is the "CURL" which I don't understand and don't think we need. + } else { + return Boolean(false); + } + emit ext->addWebSideBar(KURL( url ), name); + return Boolean(true); + } + + return Undefined(); +} + + diff --git a/khtml/ecma/kjs_mozilla.h b/khtml/ecma/kjs_mozilla.h new file mode 100644 index 000000000..220094f63 --- /dev/null +++ b/khtml/ecma/kjs_mozilla.h @@ -0,0 +1,44 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2003 George Staikos (staikos@kde.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_MOZILLA_H_ +#define _KJS_MOZILLA_H_ + +#include <kjs/object.h> + +class KHTMLPart; + +namespace KJS { + + class MozillaSidebarExtension : public ObjectImp { + public: + MozillaSidebarExtension(ExecState *exec, KHTMLPart *p); + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { addPanel }; + KHTMLPart *part() const { return m_part; } + private: + KHTMLPart *m_part; + }; +} // namespace + +#endif diff --git a/khtml/ecma/kjs_navigator.cpp b/khtml/ecma/kjs_navigator.cpp new file mode 100644 index 000000000..d962cac36 --- /dev/null +++ b/khtml/ecma/kjs_navigator.cpp @@ -0,0 +1,670 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (c) 2000 Daniel Molkentin (molkentin@kde.org) + * Copyright (c) 2000 Stefan Schimanski (schimmi@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <klocale.h> + +#include <kstandarddirs.h> +#include <kconfig.h> +#include <kdebug.h> + +#include <kio/kprotocolmanager.h> +#include <kio/kmimetype.h> +#include <kio/kservice.h> +#include <kio/ktrader.h> +#include "kjs_navigator.h" +#include "kjs/lookup.h" +#include "kjs_binding.h" +#include "khtml_part.h" +#include <sys/utsname.h> +#include "kjs_navigator.lut.h" + +using namespace KJS; + +namespace KJS { + + // All objects that need plugin info must inherit from PluginBase + // Its ctor and dtor take care of the refcounting on the static lists. + class PluginBase : public ObjectImp { + public: + PluginBase(ExecState *exec, bool loadPluginInfo); + virtual ~PluginBase(); + + struct MimeClassInfo; + struct PluginInfo; + + struct MimeClassInfo { + QString type; + QString desc; + QString suffixes; + PluginInfo *plugin; + }; + + struct PluginInfo { + QString name; + QString file; + QString desc; + QPtrList<MimeClassInfo> mimes; + }; + + static QPtrList<PluginInfo> *plugins; + static QPtrList<MimeClassInfo> *mimes; + + private: + static int m_refCount; + }; + + + class Plugins : public PluginBase { + public: + Plugins(ExecState *exec, bool pluginsEnabled) + : PluginBase(exec, pluginsEnabled), + m_pluginsEnabled(pluginsEnabled) {}; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + Value pluginByName( ExecState* exec, const QString& name ) const; + bool pluginsEnabled() const { return m_pluginsEnabled; }; + private: + bool m_pluginsEnabled; + }; + + + class MimeTypes : public PluginBase { + public: + MimeTypes(ExecState *exec, bool pluginsEnabled) + : PluginBase(exec, pluginsEnabled), + m_pluginsEnabled(pluginsEnabled) {}; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + Value getValueProperty(ExecState *exec, int token) const; + Value mimeTypeByName( ExecState* exec, const QString& name ) const; + bool pluginsEnabled() const { return m_pluginsEnabled; }; + private: + bool m_pluginsEnabled; + }; + + + class Plugin : public PluginBase { + public: + Plugin( ExecState *exec, PluginBase::PluginInfo *info ) + : PluginBase( exec, true ) + { m_info = info; }; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + Value mimeByName(ExecState* exec, const QString& name ) const; + Value getValueProperty(ExecState *exec, int token) const; + PluginBase::PluginInfo *pluginInfo() const { return m_info; } + private: + PluginBase::PluginInfo *m_info; + }; + + + class MimeType : public PluginBase { + public: + MimeType( ExecState *exec, PluginBase::MimeClassInfo *info ) + : PluginBase( exec, true ) + { m_info = info; }; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + Value getValueProperty(ExecState *exec, int token) const; + private: + PluginBase::MimeClassInfo *m_info; + }; + +} + + +QPtrList<PluginBase::PluginInfo> *KJS::PluginBase::plugins = 0; +QPtrList<PluginBase::MimeClassInfo> *KJS::PluginBase::mimes = 0; +int KJS::PluginBase::m_refCount = 0; + +const ClassInfo Navigator::info = { "Navigator", 0, &NavigatorTable, 0 }; +/* +@begin NavigatorTable 12 + appCodeName Navigator::AppCodeName DontDelete|ReadOnly + appName Navigator::AppName DontDelete|ReadOnly + appVersion Navigator::AppVersion DontDelete|ReadOnly + language Navigator::Language DontDelete|ReadOnly + userAgent Navigator::UserAgent DontDelete|ReadOnly + userLanguage Navigator::UserLanguage DontDelete|ReadOnly + browserLanguage Navigator::BrowserLanguage DontDelete|ReadOnly + platform Navigator::Platform DontDelete|ReadOnly + cpuClass Navigator::CpuClass DontDelete|ReadOnly + plugins Navigator::_Plugins DontDelete|ReadOnly + mimeTypes Navigator::_MimeTypes DontDelete|ReadOnly + product Navigator::Product DontDelete|ReadOnly + vendor Navigator::Vendor DontDelete|ReadOnly + productSub Navigator::ProductSub DontDelete|ReadOnly + cookieEnabled Navigator::CookieEnabled DontDelete|ReadOnly + javaEnabled Navigator::JavaEnabled DontDelete|Function 0 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(NavigatorFunc) + +Navigator::Navigator(ExecState *exec, KHTMLPart *p) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()), m_part(p) { } + +Value Navigator::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Navigator::get " << propertyName.ascii() << endl; +#endif + return lookupGet<NavigatorFunc,Navigator,ObjectImp>(exec,propertyName,&NavigatorTable,this); +} + +Value Navigator::getValueProperty(ExecState *exec, int token) const +{ + KURL url = m_part->url(); + QString userAgent = url.host(); + if (userAgent.isEmpty()) + userAgent = "localhost"; + userAgent = KProtocolManager::userAgentForHost(userAgent); + switch (token) { + case AppCodeName: + return String("Mozilla"); + case AppName: + // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape + if (userAgent.find(QString::fromLatin1("Mozilla")) >= 0 && + userAgent.find(QString::fromLatin1("compatible")) == -1) + { + //kdDebug() << "appName -> Mozilla" << endl; + return String("Netscape"); + } + if (userAgent.find(QString::fromLatin1("Microsoft")) >= 0 || + userAgent.find(QString::fromLatin1("MSIE")) >= 0) + { + //kdDebug() << "appName -> IE" << endl; + return String("Microsoft Internet Explorer"); + } + //kdDebug() << "appName -> Konqueror" << endl; + return String("Konqueror"); + case AppVersion: + // We assume the string is something like Mozilla/version (properties) + return String(userAgent.mid(userAgent.find('/') + 1)); + case Product: + // We are pretending to be Mozilla or Safari + if (userAgent.find(QString::fromLatin1("Mozilla")) >= 0 && + userAgent.find(QString::fromLatin1("compatible")) == -1) + { + return String("Gecko"); + } + // When spoofing as IE, we use Undefined(). + if (userAgent.find(QString::fromLatin1("Microsoft")) >= 0 || + userAgent.find(QString::fromLatin1("MSIE")) >= 0) + { + return Undefined(); + } + // We are acting straight + return String("Konqueror/khtml"); + case ProductSub: + { + int ix = userAgent.find("Gecko"); + if (ix >= 0 && userAgent.length() >= (uint)ix+14 && userAgent.unicode()[ix+5] == QChar('/') && + userAgent.find(QRegExp("\\d{8}"), ix+6) == ix+6) + { + // We have Gecko/<productSub> in the UA string + return String(userAgent.mid(ix+6, 8)); + } + else if (ix >= 0) + { + return String("20040107"); + } + } + return Undefined(); + case Vendor: + return String("KDE"); + case BrowserLanguage: + case Language: + case UserLanguage: + return String(KGlobal::locale()->language()); + case UserAgent: + return String(userAgent); + case Platform: + // yet another evil hack, but necessary to spoof some sites... + if ( (userAgent.find(QString::fromLatin1("Win"),0,false)>=0) ) + return String(QString::fromLatin1("Win32")); + else if ( (userAgent.find(QString::fromLatin1("Macintosh"),0,false)>=0) || + (userAgent.find(QString::fromLatin1("Mac_PowerPC"),0,false)>=0) ) + return String(QString::fromLatin1("MacPPC")); + else + { + struct utsname name; + int ret = uname(&name); + if ( ret >= 0 ) + return String(QString::fromLatin1("%1 %1 X11").arg(name.sysname).arg(name.machine)); + else // can't happen + return String(QString::fromLatin1("Unix X11")); + } + case CpuClass: + { + struct utsname name; + int ret = uname(&name); + if ( ret >= 0 ) + return String(name.machine); + else // can't happen + return String("x86"); + } + case _Plugins: + return Value(new Plugins(exec, m_part->pluginsEnabled())); + case _MimeTypes: + return Value(new MimeTypes(exec, m_part->pluginsEnabled())); + case CookieEnabled: + return Boolean(true); /// ##### FIXME + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMEvent::getValueProperty : " << token << endl; + return Value(); + } +} + +/*******************************************************************/ + +PluginBase::PluginBase(ExecState *exec, bool loadPluginInfo) + : ObjectImp(exec->interpreter()->builtinObjectPrototype() ) +{ + if ( loadPluginInfo && !plugins ) { + plugins = new QPtrList<PluginInfo>; + mimes = new QPtrList<MimeClassInfo>; + plugins->setAutoDelete( true ); + mimes->setAutoDelete( true ); + + // read in using KTrader + KTrader::OfferList offers = KTrader::self()->query("Browser/View"); + KTrader::OfferList::iterator it; + for ( it = offers.begin(); it != offers.end(); ++it ) { + + QVariant pluginsinfo = (**it).property( "X-KDE-BrowserView-PluginsInfo" ); + if ( !pluginsinfo.isValid() ) { + // <backwards compatible> + if ((**it).library() == QString("libnsplugin")) + pluginsinfo = QVariant("nsplugins/pluginsinfo"); + else + // </backwards compatible> + continue; + } + // read configuration + KConfig kc( locate ("data", pluginsinfo.toString()) ); + unsigned num = (unsigned int) kc.readNumEntry("number"); + for ( unsigned n = 0; n < num; n++ ) { + kc.setGroup( QString::number(n) ); + PluginInfo *plugin = new PluginInfo; + + plugin->name = kc.readEntry("name"); + plugin->file = kc.readPathEntry("file"); + plugin->desc = kc.readEntry("description"); + + plugins->append( plugin ); + + // get mime types from string + QStringList types = QStringList::split( ';', kc.readEntry("mime") ); + QStringList::Iterator type; + for ( type=types.begin(); type!=types.end(); ++type ) { + + // get mime information + QStringList tokens = QStringList::split(':', *type, true); + if ( tokens.count() < 3 ) // we need 3 items + continue; + + MimeClassInfo *mime = new MimeClassInfo; + QStringList::Iterator token = tokens.begin(); + mime->type = (*token).lower(); + //kdDebug(6070) << "mime->type=" << mime->type << endl; + ++token; + + mime->suffixes = *token; + ++token; + + mime->desc = *token; + ++token; + + mime->plugin = plugin; + + mimes->append( mime ); + plugin->mimes.append( mime ); + + } + } + } + } + + m_refCount++; +} + +PluginBase::~PluginBase() +{ + m_refCount--; + if ( m_refCount==0 ) { + delete plugins; + delete mimes; + plugins = 0; + mimes = 0; + } +} + + +/*******************************************************************/ + +const ClassInfo Plugins::info = { "PluginArray", 0, &PluginsTable, 0 }; +/* +@begin PluginsTable 4 + length Plugins_Length DontDelete|ReadOnly + refresh Plugins_Refresh DontDelete|Function 0 + item Plugins_Item DontDelete|Function 1 + namedItem Plugins_NamedItem DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(PluginsFunc) + +Value Plugins::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Plugins::get " << propertyName.qstring() << endl; +#endif + if (!pluginsEnabled()) { + if (propertyName == lengthPropertyName ) + return Number(0); + } else { + if ( propertyName == lengthPropertyName ) + return Number(plugins->count()); + + // plugins[#] + bool ok; + unsigned int i = propertyName.toULong(&ok); + if( ok && i<plugins->count() ) + return Value( new Plugin( exec, plugins->at(i) ) ); + + // plugin[name] + Value val = pluginByName( exec, propertyName.qstring() ); + if (!val.isA(UndefinedType)) + return val; + } + + return lookupGet<PluginsFunc,Plugins,ObjectImp>(exec,propertyName,&PluginsTable,this); +} + +Value Plugins::pluginByName( ExecState* exec, const QString& name ) const +{ + Q_ASSERT(plugins); + for ( PluginInfo *pl = plugins->first(); pl!=0; pl = plugins->next() ) { + if ( pl->name == name ) + return Value( new Plugin( exec, pl ) ); + } + return Undefined(); +} + +Value Plugins::getValueProperty(ExecState* /*exec*/, int token) const +{ + kdDebug(6070) << "WARNING: Unhandled token in Plugins::getValueProperty : " << token << endl; + return Undefined(); +} + +Value PluginsFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::Plugins, thisObj ); + KJS::Plugins* base = static_cast<KJS::Plugins *>(thisObj.imp()); + if (!base->pluginsEnabled()) { + if (id == Plugins_Refresh || //## TODO + id == Plugins_Item || + id == Plugins_NamedItem) + return Undefined(); + } else { + switch( id ) { + case Plugins_Refresh: + return Undefined(); //## TODO + case Plugins_Item: + { + bool ok; + unsigned int i = args[0].toString(exec).toArrayIndex(&ok); + if( ok && i<base->plugins->count() ) + return Value( new Plugin( exec, base->plugins->at(i) ) ); + return Undefined(); + } + case Plugins_NamedItem: + UString s = args[0].toString(exec); + return base->pluginByName( exec, s.qstring() ); + } + } + kdDebug(6070) << "WARNING: Unhandled token in PluginsFunc::tryCall : " << id << endl; + return Undefined(); +} + +/*******************************************************************/ + +const ClassInfo MimeTypes::info = { "MimeTypeArray", 0, &MimeTypesTable, 0 }; +/* +@begin MimeTypesTable 3 + length MimeTypes_Length DontDelete|ReadOnly + item MimeTypes_Item DontDelete|Function 1 + namedItem MimeTypes_NamedItem DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(MimeTypesFunc) + +Value MimeTypes::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "MimeTypes::get " << propertyName.qstring() << endl; +#endif + if (!pluginsEnabled()) { + if (propertyName == lengthPropertyName ) + return Number(0); + } else { + if( propertyName==lengthPropertyName ) + return Number( mimes->count() ); + + // mimeTypes[#] + bool ok; + unsigned int i = propertyName.toULong(&ok); + if( ok && i<mimes->count() ) + return Value( new MimeType( exec, mimes->at(i) ) ); + + // mimeTypes[name] + Value val = mimeTypeByName( exec, propertyName.qstring() ); + if (!val.isA(UndefinedType)) + return val; + } + + return lookupGet<MimeTypesFunc,MimeTypes,ObjectImp>(exec,propertyName,&MimeTypesTable,this); +} + +Value MimeTypes::mimeTypeByName( ExecState* exec, const QString& name ) const +{ + //kdDebug(6070) << "MimeTypes[" << name << "]" << endl; + Q_ASSERT(mimes); + for ( MimeClassInfo *m = mimes->first(); m!=0; m = mimes->next() ) { + if ( m->type == name ) + return Value( new MimeType( exec, m ) ); + } + return Undefined(); +} + +Value MimeTypes::getValueProperty(ExecState* /*exec*/, int token) const +{ + kdDebug(6070) << "WARNING: Unhandled token in MimeTypes::getValueProperty : " << token << endl; + return Undefined(); +} + +Value MimeTypesFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::MimeTypes, thisObj ); + KJS::MimeTypes* base = static_cast<KJS::MimeTypes *>(thisObj.imp()); + if (!base->pluginsEnabled()) { + if (id == MimeTypes_Item || + id == MimeTypes_NamedItem) + return Undefined(); + } else { + switch( id ) { + case MimeTypes_Item: + { + bool ok; + unsigned int i = args[0].toString(exec).toArrayIndex(&ok); + if( ok && i<base->mimes->count() ) + return Value( new MimeType( exec, base->mimes->at(i) ) ); + return Undefined(); + } + case MimeTypes_NamedItem: + UString s = args[0].toString(exec); + return base->mimeTypeByName( exec, s.qstring() ); + } + } + kdDebug(6070) << "WARNING: Unhandled token in MimeTypesFunc::tryCall : " << id << endl; + return Undefined(); +} + +/************************************************************************/ +const ClassInfo Plugin::info = { "Plugin", 0, &PluginTable, 0 }; +/* +@begin PluginTable 7 + name Plugin_Name DontDelete|ReadOnly + filename Plugin_FileName DontDelete|ReadOnly + description Plugin_Description DontDelete|ReadOnly + length Plugin_Length DontDelete|ReadOnly + item Plugin_Item DontDelete|Function 1 + namedItem Plugin_NamedItem DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(PluginFunc) + +Value Plugin::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Plugin::get " << propertyName.qstring() << endl; +#endif + if ( propertyName == lengthPropertyName ) + return Number( m_info->mimes.count() ); + + // plugin[#] + bool ok; + unsigned int i = propertyName.toULong(&ok); + //kdDebug(6070) << "Plugin::get plugin[" << i << "]" << endl; + if( ok && i<m_info->mimes.count() ) + { + //kdDebug(6070) << "returning mimetype " << m_info->mimes.at(i)->type << endl; + return Value(new MimeType(exec, m_info->mimes.at(i))); + } + + // plugin["name"] + Value val = mimeByName( exec, propertyName.qstring() ); + if (!val.isA(UndefinedType)) + return val; + + return lookupGet<PluginFunc,Plugin,ObjectImp>(exec, propertyName, &PluginTable, this ); +} + +Value Plugin::mimeByName(ExecState* exec, const QString& name) const +{ + for ( PluginBase::MimeClassInfo *m = m_info->mimes.first(); + m != 0; m = m_info->mimes.next() ) { + if ( m->type == name ) + return Value(new MimeType(exec, m)); + } + return Undefined(); +} + +Value Plugin::getValueProperty(ExecState* /*exec*/, int token) const +{ + switch( token ) { + case Plugin_Name: + return String( m_info->name ); + case Plugin_FileName: + return String( m_info->file ); + case Plugin_Description: + return String( m_info->desc ); + default: + kdDebug(6070) << "WARNING: Unhandled token in Plugin::getValueProperty : " << token << endl; + return Undefined(); + } +} + +Value PluginFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::Plugin, thisObj ); + KJS::Plugin* plugin = static_cast<KJS::Plugin *>(thisObj.imp()); + switch( id ) { + case Plugin_Item: + { + bool ok; + unsigned int i = args[0].toString(exec).toArrayIndex(&ok); + if( ok && i< plugin->pluginInfo()->mimes.count() ) + return Value( new MimeType( exec, plugin->pluginInfo()->mimes.at(i) ) ); + return Undefined(); + } + case Plugin_NamedItem: + { + UString s = args[0].toString(exec); + return plugin->mimeByName( exec, s.qstring() ); + } + default: + kdDebug(6070) << "WARNING: Unhandled token in PluginFunc::tryCall : " << id << endl; + return Undefined(); + } +} + +/*****************************************************************************/ + +const ClassInfo MimeType::info = { "MimeType", 0, &MimeTypeTable, 0 }; +/* +@begin MimeTypeTable 4 + description MimeType_Description DontDelete|ReadOnly + enabledPlugin MimeType_EnabledPlugin DontDelete|ReadOnly + suffixes MimeType_Suffixes DontDelete|ReadOnly + type MimeType_Type DontDelete|ReadOnly +@end +*/ + +Value MimeType::get(ExecState *exec, const Identifier &propertyName) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "MimeType::get " << propertyName.qstring() << endl; +#endif + return lookupGetValue<MimeType,ObjectImp>(exec, propertyName, &MimeTypeTable, this ); +} + +Value MimeType::getValueProperty(ExecState* exec, int token) const +{ + switch( token ) { + case MimeType_Type: + return String( m_info->type ); + case MimeType_Suffixes: + return String( m_info->suffixes ); + case MimeType_Description: + return String( m_info->desc ); + case MimeType_EnabledPlugin: + return Value(new Plugin(exec, m_info->plugin)); + default: + kdDebug(6070) << "WARNING: Unhandled token in MimeType::getValueProperty : " << token << endl; + return Undefined(); + } +} + + +Value NavigatorFunc::tryCall(ExecState *exec, Object &thisObj, const List &) +{ + KJS_CHECK_THIS( KJS::Navigator, thisObj ); + Navigator *nav = static_cast<Navigator *>(thisObj.imp()); + // javaEnabled() + return Boolean(nav->part()->javaEnabled()); +} diff --git a/khtml/ecma/kjs_navigator.h b/khtml/ecma/kjs_navigator.h new file mode 100644 index 000000000..ccd1ba63b --- /dev/null +++ b/khtml/ecma/kjs_navigator.h @@ -0,0 +1,53 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_NAVIGATOR_H_ +#define _KJS_NAVIGATOR_H_ + +#include <kjs/object.h> + +class KHTMLPart; + +namespace KJS { + + class Navigator : public ObjectImp { + public: + Navigator(ExecState *exec, KHTMLPart *p); + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { AppCodeName, AppName, AppVersion, Language, UserAgent, UserLanguage, Platform, + _Plugins, _MimeTypes, Product, ProductSub, Vendor, CookieEnabled, JavaEnabled, + BrowserLanguage, CpuClass }; + KHTMLPart *part() const { return m_part; } + private: + KHTMLPart *m_part; + }; + + // Hashtable enums + enum { Plugins_Refresh, Plugins_Length, Plugins_Item, Plugins_NamedItem }; + enum { MimeTypes_Length, MimeTypes_Item, MimeTypes_NamedItem }; + enum { Plugin_Name, Plugin_FileName, Plugin_Description, Plugin_Length, Plugin_Item, Plugin_NamedItem }; + enum { MimeType_Type, MimeType_Description, MimeType_EnabledPlugin, MimeType_Suffixes }; + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_proxy.cpp b/khtml/ecma/kjs_proxy.cpp new file mode 100644 index 000000000..789f99f38 --- /dev/null +++ b/khtml/ecma/kjs_proxy.cpp @@ -0,0 +1,411 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001,2003 Peter Kelly (pmk@post.com) + * Copyright (C) 2001-2003 David Faure (faure@kde.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#if defined(HAVE_VALGRIND_MEMCHECK_H) && !defined(NDEBUG) + +#include <valgrind/memcheck.h> +#define VALGRIND_SUPPORT + +#endif + + +#include "kjs_proxy.h" + +#include "kjs_window.h" +#include "kjs_events.h" +#include "kjs_debugwin.h" +#include "xml/dom_nodeimpl.h" +#include "khtmlpart_p.h" +#include <khtml_part.h> +#include <kprotocolmanager.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <assert.h> +#include <kjs/function.h> + +using namespace KJS; + +extern "C" { + KJSProxy *kjs_html_init(khtml::ChildFrame *childframe); +} + +namespace KJS { + +class KJSProxyImpl : public KJSProxy { +public: + KJSProxyImpl(khtml::ChildFrame *frame); + virtual ~KJSProxyImpl(); + virtual QVariant evaluate(QString filename, int baseLine, const QString &, const DOM::Node &n, + Completion *completion = 0); + virtual void clear(); + virtual DOM::EventListener *createHTMLEventHandler(QString sourceUrl, QString name, QString code, DOM::NodeImpl *node); + virtual void finishedWithEvent(const DOM::Event &event); + virtual KJS::Interpreter *interpreter(); + + virtual void setDebugEnabled(bool enabled); + virtual void showDebugWindow(bool show=true); + virtual bool paused() const; + virtual void dataReceived(); + + void initScript(); + void applyUserAgent(); + +private: + KJS::ScriptInterpreter* m_script; + bool m_debugEnabled; +#ifndef NDEBUG + static int s_count; +#endif +}; + +} // namespace KJS + +#ifndef NDEBUG +int KJSProxyImpl::s_count = 0; +#endif + +KJSProxyImpl::KJSProxyImpl(khtml::ChildFrame *frame) +{ + m_script = 0; + m_frame = frame; + m_debugEnabled = false; +#ifndef NDEBUG + s_count++; +#endif +} + +KJSProxyImpl::~KJSProxyImpl() +{ + if ( m_script ) { + //kdDebug() << "KJSProxyImpl::~KJSProxyImpl clearing global object " << m_script->globalObject().imp() << endl; + // This allows to delete the global-object properties, like all the protos + static_cast<ObjectImp*>(m_script->globalObject().imp())->deleteAllProperties( m_script->globalExec() ); + //kdDebug() << "KJSProxyImpl::~KJSProxyImpl garbage collecting" << endl; + while (KJS::Interpreter::collect()) + ; + //kdDebug() << "KJSProxyImpl::~KJSProxyImpl deleting interpreter " << m_script << endl; + delete m_script; + //kdDebug() << "KJSProxyImpl::~KJSProxyImpl garbage collecting again" << endl; + // Garbage collect - as many times as necessary + // (we could delete an object which was holding another object, so + // the deref() will happen too late for deleting the impl of the 2nd object). + while (KJS::Interpreter::collect()) + ; + } + +#ifndef NDEBUG + s_count--; + // If it was the last interpreter, we should have nothing left +#ifdef KJS_DEBUG_MEM + if ( s_count == 0 ) + Interpreter::finalCheck(); +#endif +#endif +} + +QVariant KJSProxyImpl::evaluate(QString filename, int baseLine, + const QString&str, const DOM::Node &n, Completion *completion) { + // evaluate code. Returns the JS return value or an invalid QVariant + // if there was none, an error occurred or the type couldn't be converted. + + initScript(); + // inlineCode is true for <a href="javascript:doSomething()"> + // and false for <script>doSomething()</script>. Check if it has the + // expected value in all cases. + // See smart window.open policy for where this is used. + bool inlineCode = filename.isNull(); + //kdDebug(6070) << "KJSProxyImpl::evaluate inlineCode=" << inlineCode << endl; + +#ifdef KJS_DEBUGGER + if (inlineCode) + filename = "(unknown file)"; + if (KJSDebugWin::debugWindow()) { + KJSDebugWin::debugWindow()->attach(m_script); + KJSDebugWin::debugWindow()->setNextSourceInfo(filename,baseLine); + // KJSDebugWin::debugWindow()->setMode(KJSDebugWin::Step); + } +#else + Q_UNUSED(baseLine); +#endif + + m_script->setInlineCode(inlineCode); + Window* window = Window::retrieveWindow( m_frame->m_part ); + KJS::Value thisNode = n.isNull() ? Window::retrieve( m_frame->m_part ) : getDOMNode(m_script->globalExec(),n); + + UString code( str ); + + KJSCPUGuard guard; + guard.start(); + Completion comp = m_script->evaluate(code, thisNode); + guard.stop(); + + bool success = ( comp.complType() == Normal ) || ( comp.complType() == ReturnValue ); + + if (completion) + *completion = comp; + +#ifdef KJS_DEBUGGER + // KJSDebugWin::debugWindow()->setCode(QString::null); +#endif + + window->afterScriptExecution(); + + // let's try to convert the return value + if (success && comp.value().isValid()) + return ValueToVariant( m_script->globalExec(), comp.value()); + else + { + if ( comp.complType() == Throw ) + { + UString msg = comp.value().toString(m_script->globalExec()); + kdDebug(6070) << "WARNING: Script threw exception: " << msg.qstring() << endl; + } + return QVariant(); + } +} + +// Implementation of the debug() function +class TestFunctionImp : public ObjectImp { +public: + TestFunctionImp() : ObjectImp() {} + virtual bool implementsCall() const { return true; } + virtual Value call(ExecState *exec, Object &thisObj, const List &args); +}; + +Value TestFunctionImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) +{ + fprintf(stderr,"--> %s\n",args[0].toString(exec).ascii()); + return Undefined(); +} + +void KJSProxyImpl::clear() { + // clear resources allocated by the interpreter, and make it ready to be used by another page + // We have to keep it, so that the Window object for the part remains the same. + // (we used to delete and re-create it, previously) + if (m_script) { +#ifdef KJS_DEBUGGER + // ### + KJSDebugWin *debugWin = KJSDebugWin::debugWindow(); + if (debugWin) { + if (debugWin->getExecState() && + debugWin->getExecState()->interpreter() == m_script) + debugWin->slotStop(); + debugWin->clearInterpreter(m_script); + } +#endif + m_script->clear(); + + Window *win = static_cast<Window *>(m_script->globalObject().imp()); + if (win) { + win->clear( m_script->globalExec() ); + // re-add "debug", clear() removed it + m_script->globalObject().put(m_script->globalExec(), + "debug", Value(new TestFunctionImp()), Internal); + if ( win->part() ) + applyUserAgent(); + } + + // Really delete everything that can be, so that the DOM nodes get deref'ed + //kdDebug() << k_funcinfo << "all done -> collecting" << endl; + while (KJS::Interpreter::collect()) + ; + } +} + +DOM::EventListener *KJSProxyImpl::createHTMLEventHandler(QString sourceUrl, QString name, QString code, DOM::NodeImpl *node) +{ + initScript(); + +#ifdef KJS_DEBUGGER + if (KJSDebugWin::debugWindow()) { + KJSDebugWin::debugWindow()->attach(m_script); + KJSDebugWin::debugWindow()->setNextSourceInfo(sourceUrl,m_handlerLineno); + } +#else + Q_UNUSED(sourceUrl); +#endif + + return KJS::Window::retrieveWindow(m_frame->m_part)->getJSLazyEventListener(code,name,node); +} + +void KJSProxyImpl::finishedWithEvent(const DOM::Event &event) +{ + // This is called when the DOM implementation has finished with a particular event. This + // is the case in sitations where an event has been created just for temporary usage, + // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten + // by the DOM implementation and so does not need to be cached still by the interpreter + ScriptInterpreter::forgetDOMObject(event.handle()); +} + +KJS::Interpreter *KJSProxyImpl::interpreter() +{ + if (!m_script) + initScript(); + return m_script; +} + +void KJSProxyImpl::setDebugEnabled(bool enabled) +{ +#ifdef KJS_DEBUGGER + m_debugEnabled = enabled; + //if (m_script) + // m_script->setDebuggingEnabled(enabled); + // NOTE: this is consistent across all KJSProxyImpl instances, as we only + // ever have 1 debug window + if (!enabled && KJSDebugWin::debugWindow()) { + KJSDebugWin::destroyInstance(); + } + else if (enabled && !KJSDebugWin::debugWindow()) { + KJSDebugWin::createInstance(); + initScript(); + KJSDebugWin::debugWindow()->attach(m_script); + } +#else + Q_UNUSED(enabled); +#endif +} + +void KJSProxyImpl::showDebugWindow(bool /*show*/) +{ +#ifdef KJS_DEBUGGER + if (KJSDebugWin::debugWindow()) + KJSDebugWin::debugWindow()->show(); +#else + //Q_UNUSED(show); +#endif +} + +bool KJSProxyImpl::paused() const +{ +#ifdef KJS_DEBUGGER + if (KJSDebugWin::debugWindow()) + return KJSDebugWin::debugWindow()->inSession(); +#endif + return false; +} + +void KJSProxyImpl::dataReceived() +{ +#ifdef KJS_DEBUGGER + if (KJSDebugWin::debugWindow() && m_frame->m_part) + KJSDebugWin::debugWindow()->sourceChanged(m_script,m_frame->m_part->url().url()); +#endif +} + +void KJSProxyImpl::initScript() +{ + if (m_script) + return; + + // Build the global object - which is a Window instance + Object globalObject( new Window(m_frame) ); + + // Create a KJS interpreter for this part + m_script = new KJS::ScriptInterpreter(globalObject, m_frame); + static_cast<ObjectImp*>(globalObject.imp())->setPrototype(m_script->builtinObjectPrototype()); + +#ifdef KJS_DEBUGGER + //m_script->setDebuggingEnabled(m_debugEnabled); +#endif + //m_script->enableDebug(); + globalObject.put(m_script->globalExec(), + "debug", Value(new TestFunctionImp()), Internal); + applyUserAgent(); +} + +void KJSProxyImpl::applyUserAgent() +{ + assert( m_script ); + QString host = m_frame->m_part->url().isLocalFile() ? "localhost" : m_frame->m_part->url().host(); + QString userAgent = KProtocolManager::userAgentForHost(host); + if (userAgent.find(QString::fromLatin1("Microsoft")) >= 0 || + userAgent.find(QString::fromLatin1("MSIE")) >= 0) + { + m_script->setCompatMode(Interpreter::IECompat); +#ifdef KJS_VERBOSE + kdDebug() << "Setting IE compat mode" << endl; +#endif + } + else + // If we find "Mozilla" but not "(compatible, ...)" we are a real Netscape + if (userAgent.find(QString::fromLatin1("Mozilla")) >= 0 && + userAgent.find(QString::fromLatin1("compatible")) == -1 && + userAgent.find(QString::fromLatin1("KHTML")) == -1) + { + m_script->setCompatMode(Interpreter::NetscapeCompat); +#ifdef KJS_VERBOSE + kdDebug() << "Setting NS compat mode" << endl; +#endif + } +} + +// Helper method, so that all classes which need jScript() don't need to be added +// as friend to KHTMLPart +KJSProxy * KJSProxy::proxy( KHTMLPart *part ) +{ + return part->jScript(); +} + +// initialize HTML module +KJSProxy *kjs_html_init(khtml::ChildFrame *childframe) +{ + return new KJSProxyImpl(childframe); +} + +void KJSCPUGuard::start(unsigned int ms, unsigned int i_ms) +{ +#ifdef VALGRIND_SUPPORT + if (RUNNING_ON_VALGRIND) { + ms *= 50; + i_ms *= 50; + } +#endif + + oldAlarmHandler = signal(SIGVTALRM, alarmHandler); + itimerval tv = { + { i_ms / 1000, (i_ms % 1000) * 1000 }, + { ms / 1000, (ms % 1000) * 1000 } + }; + setitimer(ITIMER_VIRTUAL, &tv, &oldtv); +} + +void KJSCPUGuard::stop() +{ + setitimer(ITIMER_VIRTUAL, &oldtv, 0L); + signal(SIGVTALRM, oldAlarmHandler); +} + +bool KJSCPUGuard::confirmTerminate() { + kdDebug(6070) << "alarmhandler" << endl; + return KMessageBox::warningYesNo(0L, i18n("A script on this page is causing KHTML to freeze. If it continues to run, other applications may become less responsive.\nDo you want to abort the script?"), i18n("JavaScript"), i18n("&Abort"), KStdGuiItem::cont(), "kjscupguard_alarmhandler") == KMessageBox::Yes; +} + +void KJSCPUGuard::alarmHandler(int) { + ExecState::requestTerminate(); + ExecState::confirmTerminate = KJSCPUGuard::confirmTerminate; +} diff --git a/khtml/ecma/kjs_proxy.h b/khtml/ecma/kjs_proxy.h new file mode 100644 index 000000000..f76543451 --- /dev/null +++ b/khtml/ecma/kjs_proxy.h @@ -0,0 +1,91 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 1999 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_PROXY_H_ +#define _KJS_PROXY_H_ + +#include <qvariant.h> +#include <qstring.h> +#include <sys/time.h> + +class KHTMLPart; + +namespace DOM { + class Node; + class NodeImpl; + class EventListener; + class Event; +} + +namespace KJS { + class List; + class Interpreter; + class Completion; + class KJSDebugWin; +} + +namespace khtml { + class ChildFrame; +} + +/** + * @internal + * + * @short Proxy class serving as interface when being dlopen'ed. + */ +class KJSProxy { +public: + KJSProxy() { m_handlerLineno = 0; } + virtual ~KJSProxy() { } + virtual QVariant evaluate(QString filename, int baseLine, const QString &, const DOM::Node &n, + KJS::Completion *completion = 0) = 0; + virtual void clear() = 0; + virtual DOM::EventListener *createHTMLEventHandler(QString sourceUrl, QString name, QString code, DOM::NodeImpl* node) = 0; + virtual void finishedWithEvent(const DOM::Event &event) = 0; + virtual KJS::Interpreter *interpreter() = 0; + + virtual void setDebugEnabled(bool enabled) = 0; + virtual void showDebugWindow(bool show=true) = 0; + virtual bool paused() const = 0; + virtual void dataReceived() = 0; + + void setEventHandlerLineno(int lineno) { m_handlerLineno = lineno; } + + khtml::ChildFrame *m_frame; + int m_handlerLineno; + + // Helper method, to access the private KHTMLPart::jScript() + static KJSProxy *proxy( KHTMLPart *part ); +}; + +class KJSCPUGuard { +public: + KJSCPUGuard() {} + void start(unsigned int msec=5000, unsigned int i_msec=10000); + void stop(); +private: + void (*oldAlarmHandler)(int); + static void alarmHandler(int); + static bool confirmTerminate(); + itimerval oldtv; +}; + +#endif diff --git a/khtml/ecma/kjs_range.cpp b/khtml/ecma/kjs_range.cpp new file mode 100644 index 000000000..bf148ffe8 --- /dev/null +++ b/khtml/ecma/kjs_range.cpp @@ -0,0 +1,233 @@ + +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_range.h" +#include "kjs_range.lut.h" +#include <kdebug.h> + +namespace KJS { + +// ------------------------------------------------------------------------- + +const ClassInfo DOMRange::info = { "Range", 0, &DOMRangeTable, 0 }; +/* +@begin DOMRangeTable 7 + startContainer DOMRange::StartContainer DontDelete|ReadOnly + startOffset DOMRange::StartOffset DontDelete|ReadOnly + endContainer DOMRange::EndContainer DontDelete|ReadOnly + endOffset DOMRange::EndOffset DontDelete|ReadOnly + collapsed DOMRange::Collapsed DontDelete|ReadOnly + commonAncestorContainer DOMRange::CommonAncestorContainer DontDelete|ReadOnly +@end +@begin DOMRangeProtoTable 17 +setStart DOMRange::SetStart DontDelete|Function 2 + setEnd DOMRange::SetEnd DontDelete|Function 2 + setStartBefore DOMRange::SetStartBefore DontDelete|Function 1 + setStartAfter DOMRange::SetStartAfter DontDelete|Function 1 + setEndBefore DOMRange::SetEndBefore DontDelete|Function 1 + setEndAfter DOMRange::SetEndAfter DontDelete|Function 1 + collapse DOMRange::Collapse DontDelete|Function 1 + selectNode DOMRange::SelectNode DontDelete|Function 1 + selectNodeContents DOMRange::SelectNodeContents DontDelete|Function 1 + compareBoundaryPoints DOMRange::CompareBoundaryPoints DontDelete|Function 2 + deleteContents DOMRange::DeleteContents DontDelete|Function 0 + extractContents DOMRange::ExtractContents DontDelete|Function 0 + cloneContents DOMRange::CloneContents DontDelete|Function 0 + insertNode DOMRange::InsertNode DontDelete|Function 1 + surroundContents DOMRange::SurroundContents DontDelete|Function 1 + cloneRange DOMRange::CloneRange DontDelete|Function 0 + toString DOMRange::ToString DontDelete|Function 0 + detach DOMRange::Detach DontDelete|Function 0 + createContextualFragment DOMRange::CreateContextualFragment DontDelete|Function 1 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMRangeProto) +IMPLEMENT_PROTOFUNC_DOM(DOMRangeProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMRange",DOMRangeProto,DOMRangeProtoFunc) + +DOMRange::DOMRange(ExecState *exec, DOM::Range r) + : DOMObject(DOMRangeProto::self(exec)), range(r) {} + +DOMRange::~DOMRange() +{ + ScriptInterpreter::forgetDOMObject(range.handle()); +} + +Value DOMRange::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMRange,DOMObject>(exec,p,&DOMRangeTable,this); +} + +Value DOMRange::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case StartContainer: + return getDOMNode(exec,range.startContainer()); + case StartOffset: + return Number(range.startOffset()); + case EndContainer: + return getDOMNode(exec,range.endContainer()); + case EndOffset: + return Number(range.endOffset()); + case Collapsed: + return Boolean(range.collapsed()); + case CommonAncestorContainer: { + DOM::Range range2 = range; // avoid const error + return getDOMNode(exec,range2.commonAncestorContainer()); + } + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMRange::getValueProperty : " << token << endl; + return Value(); + } +} + +Value DOMRangeProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMRange, thisObj ); + DOM::Range range = static_cast<DOMRange *>(thisObj.imp())->toRange(); + Value result; + + switch (id) { + case DOMRange::SetStart: + range.setStart(toNode(args[0]),args[1].toInteger(exec)); + result = Undefined(); + break; + case DOMRange::SetEnd: + range.setEnd(toNode(args[0]),args[1].toInteger(exec)); + result = Undefined(); + break; + case DOMRange::SetStartBefore: + range.setStartBefore(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::SetStartAfter: + range.setStartAfter(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::SetEndBefore: + range.setEndBefore(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::SetEndAfter: + range.setEndAfter(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::Collapse: + range.collapse(args[0].toBoolean(exec)); + result = Undefined(); + break; + case DOMRange::SelectNode: + range.selectNode(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::SelectNodeContents: + range.selectNodeContents(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::CompareBoundaryPoints: + result = Number(range.compareBoundaryPoints(static_cast<DOM::Range::CompareHow>(args[0].toInteger(exec)),toRange(args[1]))); + break; + case DOMRange::DeleteContents: + range.deleteContents(); + result = Undefined(); + break; + case DOMRange::ExtractContents: + result = getDOMNode(exec,range.extractContents()); + break; + case DOMRange::CloneContents: + result = getDOMNode(exec,range.cloneContents()); + break; + case DOMRange::InsertNode: + range.insertNode(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::SurroundContents: + range.surroundContents(toNode(args[0])); + result = Undefined(); + break; + case DOMRange::CloneRange: + result = getDOMRange(exec,range.cloneRange()); + break; + case DOMRange::ToString: + result = String(range.toString()); + break; + case DOMRange::Detach: + range.detach(); + result = Undefined(); + break; + case DOMRange::CreateContextualFragment: + Value value = args[0]; + DOM::DOMString str = value.isA(NullType) ? DOM::DOMString() : value.toString(exec).string(); + result = getDOMNode(exec, range.createContextualFragment(str)); + break; + }; + + return result; +} + +Value getDOMRange(ExecState *exec, DOM::Range r) +{ + return cacheDOMObject<DOM::Range, KJS::DOMRange>(exec, r); +} + +// ------------------------------------------------------------------------- + +const ClassInfo RangeConstructor::info = { "RangeConstructor", 0, &RangeConstructorTable, 0 }; +/* +@begin RangeConstructorTable 5 + START_TO_START DOM::Range::START_TO_START DontDelete|ReadOnly + START_TO_END DOM::Range::START_TO_END DontDelete|ReadOnly + END_TO_END DOM::Range::END_TO_END DontDelete|ReadOnly + END_TO_START DOM::Range::END_TO_START DontDelete|ReadOnly +@end +*/ + +RangeConstructor::RangeConstructor(ExecState *exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) { } + +Value RangeConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<RangeConstructor,DOMObject>(exec,p,&RangeConstructorTable,this); +} + +Value RangeConstructor::getValueProperty(ExecState *, int token) const +{ + return Number(token); +} + +Value getRangeConstructor(ExecState *exec) +{ + return cacheGlobalObject<RangeConstructor>(exec, "[[range.constructor]]"); +} + + +DOM::Range toRange(const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMRange::info)) + return DOM::Range(); + + const DOMRange *dobj = static_cast<const DOMRange*>(obj.imp()); + return dobj->toRange(); +} + +} //namespace KJS diff --git a/khtml/ecma/kjs_range.h b/khtml/ecma/kjs_range.h new file mode 100644 index 000000000..fbf47020f --- /dev/null +++ b/khtml/ecma/kjs_range.h @@ -0,0 +1,71 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_RANGE_H_ +#define _KJS_RANGE_H_ + +#include "ecma/kjs_dom.h" +#include "dom/dom2_range.h" + +namespace KJS { + + class DOMRange : public DOMObject { + public: + DOMRange(ExecState *exec, DOM::Range r); + ~DOMRange(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { StartContainer, StartOffset, EndContainer, EndOffset, Collapsed, + CommonAncestorContainer, + SetStart, SetEnd, SetStartBefore, SetStartAfter, SetEndBefore, + SetEndAfter, Collapse, SelectNode, SelectNodeContents, + CompareBoundaryPoints, DeleteContents, ExtractContents, + CloneContents, InsertNode, SurroundContents, CloneRange, ToString, + Detach, CreateContextualFragment }; + DOM::Range toRange() const { return range; } + protected: + DOM::Range range; + }; + + // Constructor object Range + class RangeConstructor : public DOMObject { + public: + RangeConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + Value getDOMRange(ExecState *exec, DOM::Range r); + Value getRangeConstructor(ExecState *exec); + + /** + * Convert an object to a Range. Returns a null Node if not possible. + */ + DOM::Range toRange(const Value&); + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_traversal.cpp b/khtml/ecma/kjs_traversal.cpp new file mode 100644 index 000000000..5b521b6d5 --- /dev/null +++ b/khtml/ecma/kjs_traversal.cpp @@ -0,0 +1,327 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "kjs_traversal.h" +#include "kjs_traversal.lut.h" +#include "kjs_proxy.h" +#include <dom/dom_node.h> +#include <xml/dom_nodeimpl.h> +#include <xml/dom_docimpl.h> +#include <khtmlview.h> +#include <khtml_part.h> +#include <kdebug.h> + +namespace KJS { + +// ------------------------------------------------------------------------- + +const ClassInfo DOMNodeIterator::info = { "NodeIterator", 0, &DOMNodeIteratorTable, 0 }; +/* +@begin DOMNodeIteratorTable 5 + root DOMNodeIterator::Root DontDelete|ReadOnly + whatToShow DOMNodeIterator::WhatToShow DontDelete|ReadOnly + filter DOMNodeIterator::Filter DontDelete|ReadOnly + expandEntityReferences DOMNodeIterator::ExpandEntityReferences DontDelete|ReadOnly +@end +@begin DOMNodeIteratorProtoTable 3 + nextNode DOMNodeIterator::NextNode DontDelete|Function 0 + previousNode DOMNodeIterator::PreviousNode DontDelete|Function 0 + detach DOMNodeIterator::Detach DontDelete|Function 0 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMNodeIteratorProto) +IMPLEMENT_PROTOFUNC_DOM(DOMNodeIteratorProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMNodeIterator", DOMNodeIteratorProto,DOMNodeIteratorProtoFunc) + +DOMNodeIterator::DOMNodeIterator(ExecState *exec, DOM::NodeIterator ni) + : DOMObject(DOMNodeIteratorProto::self(exec)), nodeIterator(ni) {} + +DOMNodeIterator::~DOMNodeIterator() +{ + ScriptInterpreter::forgetDOMObject(nodeIterator.handle()); +} + +Value DOMNodeIterator::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMNodeIterator,DOMObject>(exec,p,&DOMNodeIteratorTable,this); +} + +Value DOMNodeIterator::getValueProperty(ExecState *exec, int token) const +{ + DOM::NodeIterator ni(nodeIterator); + switch (token) { + case Root: + return getDOMNode(exec,ni.root()); + case WhatToShow: + return Number(ni.whatToShow()); + case Filter: + return getDOMNodeFilter(exec,ni.filter()); + case ExpandEntityReferences: + return Boolean(ni.expandEntityReferences()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMNodeIterator::getValueProperty : " << token << endl; + return Value(); + } +} + +Value DOMNodeIteratorProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &) +{ + KJS_CHECK_THIS( KJS::DOMNodeIterator, thisObj ); + DOM::NodeIterator nodeIterator = static_cast<DOMNodeIterator *>(thisObj.imp())->toNodeIterator(); + switch (id) { + case DOMNodeIterator::PreviousNode: + return getDOMNode(exec,nodeIterator.previousNode()); + case DOMNodeIterator::NextNode: + return getDOMNode(exec,nodeIterator.nextNode()); + case DOMNodeIterator::Detach: + nodeIterator.detach(); + return Undefined(); + } + return Undefined(); +} + +Value getDOMNodeIterator(ExecState *exec, DOM::NodeIterator ni) +{ + return cacheDOMObject<DOM::NodeIterator, DOMNodeIterator>(exec, ni); +} + + +// ------------------------------------------------------------------------- + +const ClassInfo NodeFilterConstructor::info = { "NodeFilterConstructor", 0, &NodeFilterConstructorTable, 0 }; +/* +@begin NodeFilterConstructorTable 17 + FILTER_ACCEPT DOM::NodeFilter::FILTER_ACCEPT DontDelete|ReadOnly + FILTER_REJECT DOM::NodeFilter::FILTER_REJECT DontDelete|ReadOnly + FILTER_SKIP DOM::NodeFilter::FILTER_SKIP DontDelete|ReadOnly + SHOW_ALL DOM::NodeFilter::SHOW_ALL DontDelete|ReadOnly + SHOW_ELEMENT DOM::NodeFilter::SHOW_ELEMENT DontDelete|ReadOnly + SHOW_ATTRIBUTE DOM::NodeFilter::SHOW_ATTRIBUTE DontDelete|ReadOnly + SHOW_TEXT DOM::NodeFilter::SHOW_TEXT DontDelete|ReadOnly + SHOW_CDATA_SECTION DOM::NodeFilter::SHOW_CDATA_SECTION DontDelete|ReadOnly + SHOW_ENTITY_REFERENCE DOM::NodeFilter::SHOW_ENTITY_REFERENCE DontDelete|ReadOnly + SHOW_ENTITY DOM::NodeFilter::SHOW_ENTITY DontDelete|ReadOnly + SHOW_PROCESSING_INSTRUCTION DOM::NodeFilter::SHOW_PROCESSING_INSTRUCTION DontDelete|ReadOnly + SHOW_COMMENT DOM::NodeFilter::SHOW_COMMENT DontDelete|ReadOnly + SHOW_DOCUMENT DOM::NodeFilter::SHOW_DOCUMENT DontDelete|ReadOnly + SHOW_DOCUMENT_TYPE DOM::NodeFilter::SHOW_DOCUMENT_TYPE DontDelete|ReadOnly + SHOW_DOCUMENT_FRAGMENT DOM::NodeFilter::SHOW_DOCUMENT_FRAGMENT DontDelete|ReadOnly + SHOW_NOTATION DOM::NodeFilter::SHOW_NOTATION DontDelete|ReadOnly +@end +*/ + +NodeFilterConstructor::NodeFilterConstructor(ExecState* exec) + : DOMObject(exec->interpreter()->builtinObjectPrototype()) +{ +} + +Value NodeFilterConstructor::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<NodeFilterConstructor,DOMObject>(exec,p,&NodeFilterConstructorTable,this); +} + +Value NodeFilterConstructor::getValueProperty(ExecState *, int token) const +{ + // We use the token as the value to return directly + return Number(token); +} + +Value getNodeFilterConstructor(ExecState *exec) +{ + return cacheGlobalObject<NodeFilterConstructor>(exec, "[[nodeFilter.constructor]]"); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMNodeFilter::info = { "NodeFilter", 0, 0, 0 }; +/* +@begin DOMNodeFilterProtoTable 1 + acceptNode DOMNodeFilter::AcceptNode DontDelete|Function 0 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMNodeFilterProto) +IMPLEMENT_PROTOFUNC_DOM(DOMNodeFilterProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMNodeFilter",DOMNodeFilterProto,DOMNodeFilterProtoFunc) + +DOMNodeFilter::DOMNodeFilter(ExecState *exec, DOM::NodeFilter nf) + : DOMObject(DOMNodeFilterProto::self(exec)), nodeFilter(nf) {} + +DOMNodeFilter::~DOMNodeFilter() +{ + ScriptInterpreter::forgetDOMObject(nodeFilter.handle()); +} + +Value DOMNodeFilterProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMNodeFilter, thisObj ); + DOM::NodeFilter nodeFilter = static_cast<DOMNodeFilter *>(thisObj.imp())->toNodeFilter(); + switch (id) { + case DOMNodeFilter::AcceptNode: + return Number(nodeFilter.acceptNode(toNode(args[0]))); + } + return Undefined(); +} + +Value getDOMNodeFilter(ExecState *exec, DOM::NodeFilter nf) +{ + return cacheDOMObject<DOM::NodeFilter, DOMNodeFilter>(exec, nf); +} + +// ------------------------------------------------------------------------- + +const ClassInfo DOMTreeWalker::info = { "TreeWalker", 0, &DOMTreeWalkerTable, 0 }; +/* +@begin DOMTreeWalkerTable 5 + root DOMTreeWalker::Root DontDelete|ReadOnly + whatToShow DOMTreeWalker::WhatToShow DontDelete|ReadOnly + filter DOMTreeWalker::Filter DontDelete|ReadOnly + expandEntityReferences DOMTreeWalker::ExpandEntityReferences DontDelete|ReadOnly + currentNode DOMTreeWalker::CurrentNode DontDelete +@end +@begin DOMTreeWalkerProtoTable 7 + parentNode DOMTreeWalker::ParentNode DontDelete|Function 0 + firstChild DOMTreeWalker::FirstChild DontDelete|Function 0 + lastChild DOMTreeWalker::LastChild DontDelete|Function 0 + previousSibling DOMTreeWalker::PreviousSibling DontDelete|Function 0 + nextSibling DOMTreeWalker::NextSibling DontDelete|Function 0 + previousNode DOMTreeWalker::PreviousNode DontDelete|Function 0 + nextNode DOMTreeWalker::NextNode DontDelete|Function 0 +@end +*/ +KJS_DEFINE_PROTOTYPE(DOMTreeWalkerProto) +IMPLEMENT_PROTOFUNC_DOM(DOMTreeWalkerProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("DOMTreeWalker", DOMTreeWalkerProto,DOMTreeWalkerProtoFunc) + +DOMTreeWalker::DOMTreeWalker(ExecState *exec, DOM::TreeWalker tw) + : DOMObject(DOMTreeWalkerProto::self(exec)), treeWalker(tw) {} + +DOMTreeWalker::~DOMTreeWalker() +{ + ScriptInterpreter::forgetDOMObject(treeWalker.handle()); +} + +Value DOMTreeWalker::tryGet(ExecState *exec, const Identifier &p) const +{ + return DOMObjectLookupGetValue<DOMTreeWalker,DOMObject>(exec,p,&DOMTreeWalkerTable,this); +} + +Value DOMTreeWalker::getValueProperty(ExecState *exec, int token) const +{ + DOM::TreeWalker tw(treeWalker); + switch (token) { + case Root: + return getDOMNode(exec,tw.root()); + case WhatToShow: + return Number(tw.whatToShow()); + case Filter: + return getDOMNodeFilter(exec,tw.filter()); + case ExpandEntityReferences: + return Boolean(tw.expandEntityReferences()); + case CurrentNode: + return getDOMNode(exec,tw.currentNode()); + default: + kdDebug(6070) << "WARNING: Unhandled token in DOMTreeWalker::getValueProperty : " << token << endl; + return Value(); + } +} + +void DOMTreeWalker::tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr) +{ + if (propertyName == "currentNode") { + treeWalker.setCurrentNode(toNode(value)); + } + else + ObjectImp::put(exec, propertyName, value, attr); +} + +Value DOMTreeWalkerProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &) +{ + KJS_CHECK_THIS( KJS::DOMTreeWalker, thisObj ); + DOM::TreeWalker treeWalker = static_cast<DOMTreeWalker *>(thisObj.imp())->toTreeWalker(); + switch (id) { + case DOMTreeWalker::ParentNode: + return getDOMNode(exec,treeWalker.parentNode()); + case DOMTreeWalker::FirstChild: + return getDOMNode(exec,treeWalker.firstChild()); + case DOMTreeWalker::LastChild: + return getDOMNode(exec,treeWalker.lastChild()); + case DOMTreeWalker::PreviousSibling: + return getDOMNode(exec,treeWalker.previousSibling()); + case DOMTreeWalker::NextSibling: + return getDOMNode(exec,treeWalker.nextSibling()); + case DOMTreeWalker::PreviousNode: + return getDOMNode(exec,treeWalker.previousSibling()); + case DOMTreeWalker::NextNode: + return getDOMNode(exec,treeWalker.nextNode()); + } + return Undefined(); +} + +Value getDOMTreeWalker(ExecState *exec, DOM::TreeWalker tw) +{ + return cacheDOMObject<DOM::TreeWalker, DOMTreeWalker>(exec, tw); +} + +DOM::NodeFilter toNodeFilter(const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMNodeFilter::info)) + return DOM::NodeFilter(); + + const DOMNodeFilter *dobj = static_cast<const DOMNodeFilter*>(obj.imp()); + return dobj->toNodeFilter(); +} + +// ------------------------------------------------------------------------- + +JSNodeFilter::JSNodeFilter(Object & _filter) : DOM::CustomNodeFilter(), filter( _filter ) +{ +} + +JSNodeFilter::~JSNodeFilter() +{ +} + +short JSNodeFilter::acceptNode(const DOM::Node &n) +{ + KHTMLView *view = static_cast<DOM::DocumentImpl *>( n.handle()->docPtr() )->view(); + if (!view) + return DOM::NodeFilter::FILTER_REJECT; + + KHTMLPart *part = view->part(); + KJSProxy *proxy = part->jScript(); + if (proxy) { + ExecState *exec = proxy->interpreter()->globalExec(); + Object acceptNodeFunc = Object::dynamicCast( filter.get(exec, "acceptNode") ); + if (!acceptNodeFunc.isNull() && acceptNodeFunc.implementsCall()) { + List args; + args.append(getDOMNode(exec,n)); + Value result = acceptNodeFunc.call(exec,filter,args); + if (exec->hadException()) + exec->clearException(); + return result.toInteger(exec); + } + } + + return DOM::NodeFilter::FILTER_REJECT; +} + +} //namespace KJS diff --git a/khtml/ecma/kjs_traversal.h b/khtml/ecma/kjs_traversal.h new file mode 100644 index 000000000..fd7e064b1 --- /dev/null +++ b/khtml/ecma/kjs_traversal.h @@ -0,0 +1,108 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_TRAVERSAL_H_ +#define _KJS_TRAVERSAL_H_ + +#include "ecma/kjs_dom.h" +#include "dom/dom2_traversal.h" + +namespace KJS { + + class DOMNodeIterator : public DOMObject { + public: + DOMNodeIterator(ExecState *exec, DOM::NodeIterator ni); + ~DOMNodeIterator(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Filter, Root, WhatToShow, ExpandEntityReferences, + NextNode, PreviousNode, Detach }; + DOM::NodeIterator toNodeIterator() const { return nodeIterator; } + protected: + DOM::NodeIterator nodeIterator; + }; + + // Constructor object NodeFilter + class NodeFilterConstructor : public DOMObject { + public: + NodeFilterConstructor(ExecState *); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *exec, int token) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + class DOMNodeFilter : public DOMObject { + public: + DOMNodeFilter(ExecState *exec, DOM::NodeFilter nf); + ~DOMNodeFilter(); + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + virtual DOM::NodeFilter toNodeFilter() const { return nodeFilter; } + enum { AcceptNode }; + protected: + DOM::NodeFilter nodeFilter; + }; + + class DOMTreeWalker : public DOMObject { + public: + DOMTreeWalker(ExecState *exec, DOM::TreeWalker tw); + ~DOMTreeWalker(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, + const Value& value, int attr = None); + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Root, WhatToShow, Filter, ExpandEntityReferences, CurrentNode, + ParentNode, FirstChild, LastChild, PreviousSibling, NextSibling, + PreviousNode, NextNode }; + DOM::TreeWalker toTreeWalker() const { return treeWalker; } + protected: + DOM::TreeWalker treeWalker; + }; + + Value getDOMNodeIterator(ExecState *exec, DOM::NodeIterator ni); + Value getNodeFilterConstructor(ExecState *exec); + Value getDOMNodeFilter(ExecState *exec, DOM::NodeFilter nf); + Value getDOMTreeWalker(ExecState *exec, DOM::TreeWalker tw); + + /** + * Convert an object to a NodeFilter. Returns a null Node if not possible. + */ + DOM::NodeFilter toNodeFilter(const Value&); + + class JSNodeFilter : public DOM::CustomNodeFilter { + public: + JSNodeFilter(Object & _filter); + virtual ~JSNodeFilter(); + virtual short acceptNode (const DOM::Node &n); + protected: + Object filter; + }; + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_views.cpp b/khtml/ecma/kjs_views.cpp new file mode 100644 index 000000000..dbf354ce8 --- /dev/null +++ b/khtml/ecma/kjs_views.cpp @@ -0,0 +1,91 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ecma/kjs_views.h" +#include "ecma/kjs_css.h" +#include "ecma/kjs_window.h" +#include "kjs_views.lut.h" + +using namespace KJS; + +// ------------------------------------------------------------------------- + +const ClassInfo DOMAbstractView::info = { "AbstractView", 0, &DOMAbstractViewTable, 0 }; +/* +@begin DOMAbstractViewTable 2 + document DOMAbstractView::Document DontDelete|ReadOnly + getComputedStyle DOMAbstractView::GetComputedStyle DontDelete|Function 2 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(DOMAbstractViewFunc) + +DOMAbstractView::DOMAbstractView(ExecState *exec, DOM::AbstractView av) + : DOMObject(exec->interpreter()->builtinObjectPrototype()), abstractView(av) {} + +DOMAbstractView::~DOMAbstractView() +{ + ScriptInterpreter::forgetDOMObject(abstractView.handle()); +} + +Value DOMAbstractView::tryGet(ExecState *exec, const Identifier &p) const +{ + if ( p == "document" ) + return getDOMNode(exec,abstractView.document()); + else if ( p == "getComputedStyle" ) + return lookupOrCreateFunction<DOMAbstractViewFunc>(exec,p,this,DOMAbstractView::GetComputedStyle,2,DontDelete|Function); + else + return DOMObject::tryGet(exec,p); +} + +Value DOMAbstractViewFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( KJS::DOMAbstractView, thisObj ); + DOM::AbstractView abstractView = static_cast<DOMAbstractView *>(thisObj.imp())->toAbstractView(); + switch (id) { + case DOMAbstractView::GetComputedStyle: { + DOM::Node arg0 = toNode(args[0]); + if (arg0.nodeType() != DOM::Node::ELEMENT_NODE) + return Undefined(); // throw exception? + else + return getDOMCSSStyleDeclaration(exec,abstractView.getComputedStyle(static_cast<DOM::Element>(arg0), + args[1].toString(exec).string())); + } + } + return Undefined(); +} + +Value KJS::getDOMAbstractView(ExecState *exec, DOM::AbstractView av) +{ + return cacheDOMObject<DOM::AbstractView, DOMAbstractView>(exec, av); +} + +DOM::AbstractView KJS::toAbstractView (const Value& val) +{ + Object obj = Object::dynamicCast(val); + if (!obj.isValid() || !obj.inherits(&DOMAbstractView::info)) + return DOM::AbstractView (); + + // the Window object is considered for all practical purposes as a descendant of AbstractView + if (obj.inherits(&Window::info)) + return static_cast<const Window *>(obj.imp())->toAbstractView(); + + const DOMAbstractView *dobj = static_cast<const DOMAbstractView *>(obj.imp()); + return dobj->toAbstractView (); +} diff --git a/khtml/ecma/kjs_views.h b/khtml/ecma/kjs_views.h new file mode 100644 index 000000000..11e103fde --- /dev/null +++ b/khtml/ecma/kjs_views.h @@ -0,0 +1,53 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_VIEWS_H_ +#define _KJS_VIEWS_H_ + +#include "ecma/kjs_dom.h" +#include "dom/dom2_views.h" + +namespace KJS { + + + class DOMAbstractView : public DOMObject { + public: + DOMAbstractView(ExecState *, DOM::AbstractView av); + ~DOMAbstractView(); + virtual Value tryGet(ExecState *exec,const Identifier &p) const; + // no put - all read-only + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + virtual DOM::AbstractView toAbstractView() const { return abstractView; } + enum { Document, GetComputedStyle }; + protected: + DOM::AbstractView abstractView; + }; + + Value getDOMAbstractView(ExecState *exec, DOM::AbstractView av); + + /** + * Convert an object to an AbstractView. Returns a null Node if not possible. + */ + DOM::AbstractView toAbstractView(const Value&); + +} // namespace + +#endif diff --git a/khtml/ecma/kjs_window.cpp b/khtml/ecma/kjs_window.cpp new file mode 100644 index 000000000..bc5a85e19 --- /dev/null +++ b/khtml/ecma/kjs_window.cpp @@ -0,0 +1,2935 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000-2003 Harri Porten (porten@kde.org) + * Copyright (C) 2001-2003 David Faure (faure@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "config.h" + +#include "khtmlview.h" +#include "khtml_part.h" +#include "khtmlpart_p.h" +#include "khtml_settings.h" +#include "xml/dom2_eventsimpl.h" +#include "xml/dom_docimpl.h" +#include "misc/htmltags.h" +#include "html/html_documentimpl.h" +#include "rendering/render_frames.h" + +#include <qstylesheet.h> +#include <qtimer.h> +#include <qpaintdevicemetrics.h> +#include <qapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kmdcodec.h> +#include <kparts/browserinterface.h> +#include <kwin.h> + +#if defined Q_WS_X11 && ! defined K_WS_QTONLY +#include <kwinmodule.h> // schroder +#endif + +#ifndef KONQ_EMBEDDED +#include <kbookmarkmanager.h> +#endif +#include <kglobalsettings.h> +#include <assert.h> +#include <qstyle.h> +#include <qobjectlist.h> +#include <kstringhandler.h> + +#include "kjs_proxy.h" +#include "kjs_window.h" +#include "kjs_navigator.h" +#include "kjs_mozilla.h" +#include "kjs_html.h" +#include "kjs_range.h" +#include "kjs_traversal.h" +#include "kjs_css.h" +#include "kjs_events.h" +#include "kjs_views.h" +#include "xmlhttprequest.h" +#include "xmlserializer.h" +#include "domparser.h" + +using namespace KJS; + +namespace KJS { + + class History : public ObjectImp { + friend class HistoryFunc; + public: + History(ExecState *exec, KHTMLPart *p) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Back, Forward, Go, Length }; + private: + QGuardedPtr<KHTMLPart> part; + }; + + class External : public ObjectImp { + friend class ExternalFunc; + public: + External(ExecState *exec, KHTMLPart *p) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { AddFavorite }; + private: + QGuardedPtr<KHTMLPart> part; + }; + + class FrameArray : public ObjectImp { + public: + FrameArray(ExecState *exec, KHTMLPart *p) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { } + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual Value call(ExecState *exec, Object &thisObj, const List &args); + virtual bool implementsCall() const { return true; } + private: + QGuardedPtr<KHTMLPart> part; + }; + +#ifdef Q_WS_QWS + class KonquerorFunc : public DOMFunction { + public: + KonquerorFunc(ExecState *exec, const Konqueror* k, const char* name) + : DOMFunction(exec), konqueror(k), m_name(name) { } + virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args); + + private: + const Konqueror* konqueror; + QCString m_name; + }; +#endif +} // namespace KJS + +#include "kjs_window.lut.h" +#include "rendering/render_replaced.h" + +////////////////////// Screen Object //////////////////////// +namespace KJS { +// table for screen object +/* +@begin ScreenTable 7 + height Screen::Height DontEnum|ReadOnly + width Screen::Width DontEnum|ReadOnly + colorDepth Screen::ColorDepth DontEnum|ReadOnly + pixelDepth Screen::PixelDepth DontEnum|ReadOnly + availLeft Screen::AvailLeft DontEnum|ReadOnly + availTop Screen::AvailTop DontEnum|ReadOnly + availHeight Screen::AvailHeight DontEnum|ReadOnly + availWidth Screen::AvailWidth DontEnum|ReadOnly +@end +*/ + +const ClassInfo Screen::info = { "Screen", 0, &ScreenTable, 0 }; + +// We set the object prototype so that toString is implemented +Screen::Screen(ExecState *exec) + : ObjectImp(exec->interpreter()->builtinObjectPrototype()) {} + +Value Screen::get(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Screen::get " << p.qstring() << endl; +#endif + return lookupGetValue<Screen,ObjectImp>(exec,p,&ScreenTable,this); +} + +Value Screen::getValueProperty(ExecState *exec, int token) const +{ +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + KWinModule info(0, KWinModule::INFO_DESKTOP); +#endif + QWidget *thisWidget = Window::retrieveActive(exec)->part()->widget(); + QRect sg = KGlobalSettings::desktopGeometry(thisWidget); + + switch( token ) { + case Height: + return Number(sg.height()); + case Width: + return Number(sg.width()); + case ColorDepth: + case PixelDepth: { + QPaintDeviceMetrics m(QApplication::desktop()); + return Number(m.depth()); + } + case AvailLeft: { +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + QRect clipped = info.workArea().intersect(sg); + return Number(clipped.x()-sg.x()); +#else + return Number(10); +#endif + } + case AvailTop: { +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + QRect clipped = info.workArea().intersect(sg); + return Number(clipped.y()-sg.y()); +#else + return Number(10); +#endif + } + case AvailHeight: { +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + QRect clipped = info.workArea().intersect(sg); + return Number(clipped.height()); +#else + return Number(100); +#endif + } + case AvailWidth: { +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + QRect clipped = info.workArea().intersect(sg); + return Number(clipped.width()); +#else + return Number(100); +#endif + } + default: + kdDebug(6070) << "WARNING: Screen::getValueProperty unhandled token " << token << endl; + return Undefined(); + } +} + +////////////////////// Window Object //////////////////////// + +const ClassInfo Window::info = { "Window", &DOMAbstractView::info, &WindowTable, 0 }; + +/* +@begin WindowTable 162 + atob Window::AToB DontDelete|Function 1 + btoa Window::BToA DontDelete|Function 1 + closed Window::Closed DontDelete|ReadOnly + crypto Window::Crypto DontDelete|ReadOnly + defaultStatus Window::DefaultStatus DontDelete + defaultstatus Window::DefaultStatus DontDelete + status Window::Status DontDelete + document Window::Document DontDelete|ReadOnly + frameElement Window::FrameElement DontDelete|ReadOnly + frames Window::Frames DontDelete|ReadOnly + history Window::_History DontDelete|ReadOnly + external Window::_External DontDelete|ReadOnly + event Window::Event DontDelete|ReadOnly + innerHeight Window::InnerHeight DontDelete|ReadOnly + innerWidth Window::InnerWidth DontDelete|ReadOnly + length Window::Length DontDelete|ReadOnly + location Window::_Location DontDelete + name Window::Name DontDelete + navigator Window::_Navigator DontDelete|ReadOnly + clientInformation Window::ClientInformation DontDelete|ReadOnly + konqueror Window::_Konqueror DontDelete|ReadOnly + offscreenBuffering Window::OffscreenBuffering DontDelete|ReadOnly + opener Window::Opener DontDelete|ReadOnly + outerHeight Window::OuterHeight DontDelete|ReadOnly + outerWidth Window::OuterWidth DontDelete|ReadOnly + pageXOffset Window::PageXOffset DontDelete|ReadOnly + pageYOffset Window::PageYOffset DontDelete|ReadOnly + parent Window::Parent DontDelete|ReadOnly + personalbar Window::Personalbar DontDelete|ReadOnly + screenX Window::ScreenX DontDelete|ReadOnly + screenY Window::ScreenY DontDelete|ReadOnly + scrollbars Window::Scrollbars DontDelete|ReadOnly + scroll Window::Scroll DontDelete|Function 2 + scrollBy Window::ScrollBy DontDelete|Function 2 + scrollTo Window::ScrollTo DontDelete|Function 2 + scrollX Window::ScrollX DontDelete|ReadOnly + scrollY Window::ScrollY DontDelete|ReadOnly + moveBy Window::MoveBy DontDelete|Function 2 + moveTo Window::MoveTo DontDelete|Function 2 + resizeBy Window::ResizeBy DontDelete|Function 2 + resizeTo Window::ResizeTo DontDelete|Function 2 + self Window::Self DontDelete|ReadOnly + window Window::_Window DontDelete|ReadOnly + top Window::Top DontDelete|ReadOnly + screen Window::_Screen DontDelete|ReadOnly + alert Window::Alert DontDelete|Function 1 + confirm Window::Confirm DontDelete|Function 1 + prompt Window::Prompt DontDelete|Function 2 + open Window::Open DontDelete|Function 3 + setTimeout Window::SetTimeout DontDelete|Function 2 + clearTimeout Window::ClearTimeout DontDelete|Function 1 + focus Window::Focus DontDelete|Function 0 + blur Window::Blur DontDelete|Function 0 + close Window::Close DontDelete|Function 0 + setInterval Window::SetInterval DontDelete|Function 2 + clearInterval Window::ClearInterval DontDelete|Function 1 + captureEvents Window::CaptureEvents DontDelete|Function 0 + releaseEvents Window::ReleaseEvents DontDelete|Function 0 + print Window::Print DontDelete|Function 0 + addEventListener Window::AddEventListener DontDelete|Function 3 + removeEventListener Window::RemoveEventListener DontDelete|Function 3 +# Normally found in prototype. Add to window object itself to make them +# accessible in closed and cross-site windows + valueOf Window::ValueOf DontDelete|Function 0 + toString Window::ToString DontDelete|Function 0 +# IE extension + navigate Window::Navigate DontDelete|Function 1 +# Mozilla extension + sidebar Window::SideBar DontDelete|ReadOnly + getComputedStyle Window::GetComputedStyle DontDelete|Function 2 + +# Warning, when adding a function to this object you need to add a case in Window::get + +# Event handlers +# IE also has: onactivate, onbefore/afterprint, onbeforedeactivate/unload, oncontrolselect, +# ondeactivate, onhelp, onmovestart/end, onresizestart/end, onscroll. +# It doesn't have onabort, onchange, ondragdrop (but NS has that last one). + onabort Window::Onabort DontDelete + onblur Window::Onblur DontDelete + onchange Window::Onchange DontDelete + onclick Window::Onclick DontDelete + ondblclick Window::Ondblclick DontDelete + ondragdrop Window::Ondragdrop DontDelete + onerror Window::Onerror DontDelete + onfocus Window::Onfocus DontDelete + onkeydown Window::Onkeydown DontDelete + onkeypress Window::Onkeypress DontDelete + onkeyup Window::Onkeyup DontDelete + onload Window::Onload DontDelete + onmousedown Window::Onmousedown DontDelete + onmousemove Window::Onmousemove DontDelete + onmouseout Window::Onmouseout DontDelete + onmouseover Window::Onmouseover DontDelete + onmouseup Window::Onmouseup DontDelete + onmove Window::Onmove DontDelete + onreset Window::Onreset DontDelete + onresize Window::Onresize DontDelete + onselect Window::Onselect DontDelete + onsubmit Window::Onsubmit DontDelete + onunload Window::Onunload DontDelete + +# Constructors/constant tables + Node Window::Node DontDelete + Event Window::EventCtor DontDelete + Range Window::Range DontDelete + NodeFilter Window::NodeFilter DontDelete + DOMException Window::DOMException DontDelete + CSSRule Window::CSSRule DontDelete + MutationEvent Window::MutationEventCtor DontDelete + KeyboardEvent Window::KeyboardEventCtor DontDelete + EventException Window::EventExceptionCtor DontDelete + Image Window::Image DontDelete|ReadOnly + Option Window::Option DontDelete|ReadOnly + XMLHttpRequest Window::XMLHttpRequest DontDelete|ReadOnly + XMLSerializer Window::XMLSerializer DontDelete|ReadOnly + DOMParser Window::DOMParser DontDelete|ReadOnly + +# Mozilla dom emulation ones. + Element Window::ElementCtor DontDelete + Document Window::DocumentCtor DontDelete + #this one is an alias since we don't have a separate XMLDocument + XMLDocument Window::DocumentCtor DontDelete + HTMLElement Window::HTMLElementCtor DontDelete + HTMLDocument Window::HTMLDocumentCtor DontDelete + HTMLHtmlElement Window::HTMLHtmlElementCtor DontDelete + HTMLHeadElement Window::HTMLHeadElementCtor DontDelete + HTMLLinkElement Window::HTMLLinkElementCtor DontDelete + HTMLTitleElement Window::HTMLTitleElementCtor DontDelete + HTMLMetaElement Window::HTMLMetaElementCtor DontDelete + HTMLBaseElement Window::HTMLBaseElementCtor DontDelete + HTMLIsIndexElement Window::HTMLIsIndexElementCtor DontDelete + HTMLStyleElement Window::HTMLStyleElementCtor DontDelete + HTMLBodyElement Window::HTMLBodyElementCtor DontDelete + HTMLFormElement Window::HTMLFormElementCtor DontDelete + HTMLSelectElement Window::HTMLSelectElementCtor DontDelete + HTMLOptGroupElement Window::HTMLOptGroupElementCtor DontDelete + HTMLOptionElement Window::HTMLOptionElementCtor DontDelete + HTMLInputElement Window::HTMLInputElementCtor DontDelete + HTMLTextAreaElement Window::HTMLTextAreaElementCtor DontDelete + HTMLButtonElement Window::HTMLButtonElementCtor DontDelete + HTMLLabelElement Window::HTMLLabelElementCtor DontDelete + HTMLFieldSetElement Window::HTMLFieldSetElementCtor DontDelete + HTMLLegendElement Window::HTMLLegendElementCtor DontDelete + HTMLUListElement Window::HTMLUListElementCtor DontDelete + HTMLOListElement Window::HTMLOListElementCtor DontDelete + HTMLDListElement Window::HTMLDListElementCtor DontDelete + HTMLDirectoryElement Window::HTMLDirectoryElementCtor DontDelete + HTMLMenuElement Window::HTMLMenuElementCtor DontDelete + HTMLLIElement Window::HTMLLIElementCtor DontDelete + HTMLDivElement Window::HTMLDivElementCtor DontDelete + HTMLParagraphElement Window::HTMLParagraphElementCtor DontDelete + HTMLHeadingElement Window::HTMLHeadingElementCtor DontDelete + HTMLBlockQuoteElement Window::HTMLBlockQuoteElementCtor DontDelete + HTMLQuoteElement Window::HTMLQuoteElementCtor DontDelete + HTMLPreElement Window::HTMLPreElementCtor DontDelete + HTMLBRElement Window::HTMLBRElementCtor DontDelete + HTMLBaseFontElement Window::HTMLBaseFontElementCtor DontDelete + HTMLFontElement Window::HTMLFontElementCtor DontDelete + HTMLHRElement Window::HTMLHRElementCtor DontDelete + HTMLModElement Window::HTMLModElementCtor DontDelete + HTMLAnchorElement Window::HTMLAnchorElementCtor DontDelete + HTMLImageElement Window::HTMLImageElementCtor DontDelete + HTMLObjectElement Window::HTMLObjectElementCtor DontDelete + HTMLParamElement Window::HTMLParamElementCtor DontDelete + HTMLAppletElement Window::HTMLAppletElementCtor DontDelete + HTMLMapElement Window::HTMLMapElementCtor DontDelete + HTMLAreaElement Window::HTMLAreaElementCtor DontDelete + HTMLScriptElement Window::HTMLScriptElementCtor DontDelete + HTMLTableElement Window::HTMLTableElementCtor DontDelete + HTMLTableCaptionElement Window::HTMLTableCaptionElementCtor DontDelete + HTMLTableColElement Window::HTMLTableColElementCtor DontDelete + HTMLTableSectionElement Window::HTMLTableSectionElementCtor DontDelete + HTMLTableRowElement Window::HTMLTableRowElementCtor DontDelete + HTMLTableCellElement Window::HTMLTableCellElementCtor DontDelete + HTMLFrameSetElement Window::HTMLFrameSetElementCtor DontDelete + HTMLLayerElement Window::HTMLLayerElementCtor DontDelete + HTMLFrameElement Window::HTMLFrameElementCtor DontDelete + HTMLIFrameElement Window::HTMLIFrameElementCtor DontDelete + CSSStyleDeclaration Window::CSSStyleDeclarationCtor DontDelete +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(WindowFunc) + +Window::Window(khtml::ChildFrame *p) + : ObjectImp(/*no proto*/), m_frame(p), screen(0), history(0), external(0), m_frames(0), loc(0), m_evt(0) +{ + winq = new WindowQObject(this); + //kdDebug(6070) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name() << endl; +} + +Window::~Window() +{ + delete winq; +} + +Window *Window::retrieveWindow(KParts::ReadOnlyPart *p) +{ + Object obj = Object::dynamicCast( retrieve( p ) ); +#ifndef NDEBUG + // obj should never be null, except when javascript has been disabled in that part. + KHTMLPart *part = ::qt_cast<KHTMLPart *>(p); + if ( part && part->jScriptEnabled() ) + { + assert( obj.isValid() ); +#ifndef QWS + assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking +#endif + } +#endif + if ( !obj.isValid() ) // JS disabled + return 0; + return static_cast<KJS::Window*>(obj.imp()); +} + +Window *Window::retrieveActive(ExecState *exec) +{ + ValueImp *imp = exec->interpreter()->globalObject().imp(); + assert( imp ); +#ifndef QWS + assert( dynamic_cast<KJS::Window*>(imp) ); +#endif + return static_cast<KJS::Window*>(imp); +} + +Value Window::retrieve(KParts::ReadOnlyPart *p) +{ + assert(p); + KHTMLPart * part = ::qt_cast<KHTMLPart *>(p); + KJSProxy *proxy = 0L; + if (!part) { + part = ::qt_cast<KHTMLPart *>(p->parent()); + if (part) + proxy = part->framejScript(p); + } else + proxy = part->jScript(); + if (proxy) { +#ifdef KJS_VERBOSE + kdDebug(6070) << "Window::retrieve part=" << part << " '" << part->name() << "' interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject().imp() << endl; +#endif + return proxy->interpreter()->globalObject(); // the Global object is the "window" + } else { +#ifdef KJS_VERBOSE + kdDebug(6070) << "Window::retrieve part=" << p << " '" << p->name() << "' no jsproxy." << endl; +#endif + return Undefined(); // This can happen with JS disabled on the domain of that window + } +} + +Location *Window::location() const +{ + if (!loc) + const_cast<Window*>(this)->loc = new Location(m_frame); + return loc; +} + +ObjectImp* Window::frames( ExecState* exec ) const +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (part) + return m_frames ? m_frames : + (const_cast<Window*>(this)->m_frames = new FrameArray(exec, part)); + return 0L; +} + +// reference our special objects during garbage collection +void Window::mark() +{ + ObjectImp::mark(); + if (screen && !screen->marked()) + screen->mark(); + if (history && !history->marked()) + history->mark(); + if (external && !external->marked()) + external->mark(); + if (m_frames && !m_frames->marked()) + m_frames->mark(); + //kdDebug(6070) << "Window::mark " << this << " marking loc=" << loc << endl; + if (loc && !loc->marked()) + loc->mark(); + if (winq) + winq->mark(); +} + +bool Window::hasProperty(ExecState *exec, const Identifier &p) const +{ + // we don't want any operations on a closed window + if (m_frame.isNull() || m_frame->m_part.isNull()) + return ( p == "closed" ); + + if (ObjectImp::hasProperty(exec, p)) + return true; + + if (Lookup::findEntry(&WindowTable, p)) + return true; + + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part) + return false; + + QString q = p.qstring(); + if (part->findFramePart(p.qstring())) + return true; + // allow window[1] or parent[1] etc. (#56983) + bool ok; + unsigned int i = p.toArrayIndex(&ok); + if (ok) { + QPtrList<KParts::ReadOnlyPart> frames = part->frames(); + unsigned int len = frames.count(); + if (i < len) + return true; + } + + // allow shortcuts like 'Image1' instead of document.images.Image1 + if (part->document().isHTMLDocument()) { // might be XML + DOM::HTMLDocument doc = part->htmlDocument(); + // Keep in sync with tryGet + + if (static_cast<DOM::DocumentImpl*>(doc.handle())->underDocNamedCache().get(p.qstring())) + return true; + + return !doc.getElementById(p.string()).isNull(); + } + + return false; +} + +UString Window::toString(ExecState *) const +{ + return "[object Window]"; +} + +Value Window::get(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Window("<<this<<")::get " << p.qstring() << endl; +#endif + // we want only limited operations on a closed window + if (m_frame.isNull() || m_frame->m_part.isNull()) { + const HashEntry* entry = Lookup::findEntry(&WindowTable, p); + if (entry) { + switch (entry->value) { + case Closed: + return Boolean(true); + case _Location: + return Null(); + case ValueOf: + case ToString: + return lookupOrCreateFunction<WindowFunc>(exec,p, this, entry->value, + entry->params, entry->attr); + default: + break; + } + } + return Undefined(); + } + + // Look for overrides first + ValueImp *val = getDirect(p); + if (val) { + //kdDebug(6070) << "Window::get found dynamic property '" << p.ascii() << "'" << endl; + return isSafeScript(exec) ? Value(val) : Undefined(); + } + + const HashEntry* entry = Lookup::findEntry(&WindowTable, p); + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + + // properties that work on all windows + if (entry) { + // ReadOnlyPart first + switch(entry->value) { + case Closed: + return Boolean( false ); + case _Location: + // No isSafeScript test here, we must be able to _set_ location.href (#49819) + return Value(location()); + case _Window: + case Self: + return retrieve(m_frame->m_part); + default: + break; + } + if (!part) + return Undefined(); + // KHTMLPart next + switch(entry->value) { + case Frames: + return Value(frames(exec)); + case Opener: + if (!part->opener()) + return Null(); // ### a null Window might be better, but == null + else // doesn't work yet + return retrieve(part->opener()); + case Parent: + return retrieve(part->parentPart() ? part->parentPart() : (KHTMLPart*)part); + case Top: { + KHTMLPart *p = part; + while (p->parentPart()) + p = p->parentPart(); + return retrieve(p); + } + case Alert: + case Confirm: + case Prompt: + case Open: + case Close: + case Focus: + case Blur: + case AToB: + case BToA: + case GetComputedStyle: + case ValueOf: + case ToString: + return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); + default: + break; + } + } else if (!part) { + // not a KHTMLPart + QString rvalue; + KParts::LiveConnectExtension::Type rtype; + unsigned long robjid; + if (m_frame->m_liveconnect && + isSafeScript(exec) && + m_frame->m_liveconnect->get(0, p.qstring(), rtype, robjid, rvalue)) + return getLiveConnectValue(m_frame->m_liveconnect, p.qstring(), rtype, rvalue, robjid); + return Undefined(); + } + // properties that only work on safe windows + if (isSafeScript(exec) && entry) + { + //kdDebug(6070) << "token: " << entry->value << endl; + switch( entry->value ) { + case Crypto: + return Undefined(); // ### + case DefaultStatus: + return String(UString(part->jsDefaultStatusBarText())); + case Status: + return String(UString(part->jsStatusBarText())); + case Document: + if (part->document().isNull()) { + kdDebug(6070) << "Document.write: adding <HTML><BODY> to create document" << endl; + part->begin(); + part->write("<HTML><BODY>"); + part->end(); + } + return getDOMNode(exec,part->document()); + case FrameElement: + if (m_frame->m_frame) + return getDOMNode(exec,m_frame->m_frame->element()); + else + return Undefined(); + case Node: + return NodeConstructor::self(exec); + case Range: + return getRangeConstructor(exec); + case NodeFilter: + return getNodeFilterConstructor(exec); + case DOMException: + return getDOMExceptionConstructor(exec); + case CSSRule: + return getCSSRuleConstructor(exec); + case ElementCtor: + return ElementPseudoCtor::self(exec); + case HTMLElementCtor: + return HTMLElementPseudoCtor::self(exec); + case HTMLHtmlElementCtor: + return HTMLHtmlElementPseudoCtor::self(exec); + case HTMLHeadElementCtor: + return HTMLHeadElementPseudoCtor::self(exec); + case HTMLLinkElementCtor: + return HTMLLinkElementPseudoCtor::self(exec); + case HTMLTitleElementCtor: + return HTMLTitleElementPseudoCtor::self(exec); + case HTMLMetaElementCtor: + return HTMLMetaElementPseudoCtor::self(exec); + case HTMLBaseElementCtor: + return HTMLBaseElementPseudoCtor::self(exec); + case HTMLIsIndexElementCtor: + return HTMLIsIndexElementPseudoCtor::self(exec); + case HTMLStyleElementCtor: + return HTMLStyleElementPseudoCtor::self(exec); + case HTMLBodyElementCtor: + return HTMLBodyElementPseudoCtor::self(exec); + case HTMLFormElementCtor: + return HTMLFormElementPseudoCtor::self(exec); + case HTMLSelectElementCtor: + return HTMLSelectElementPseudoCtor::self(exec); + case HTMLOptGroupElementCtor: + return HTMLOptGroupElementPseudoCtor::self(exec); + case HTMLOptionElementCtor: + return HTMLOptionElementPseudoCtor::self(exec); + case HTMLInputElementCtor: + return HTMLInputElementPseudoCtor::self(exec); + case HTMLTextAreaElementCtor: + return HTMLTextAreaElementPseudoCtor::self(exec); + case HTMLButtonElementCtor: + return HTMLButtonElementPseudoCtor::self(exec); + case HTMLLabelElementCtor: + return HTMLLabelElementPseudoCtor::self(exec); + case HTMLFieldSetElementCtor: + return HTMLFieldSetElementPseudoCtor::self(exec); + case HTMLLegendElementCtor: + return HTMLLegendElementPseudoCtor::self(exec); + case HTMLUListElementCtor: + return HTMLUListElementPseudoCtor::self(exec); + case HTMLOListElementCtor: + return HTMLOListElementPseudoCtor::self(exec); + case HTMLDListElementCtor: + return HTMLDListElementPseudoCtor::self(exec); + case HTMLDirectoryElementCtor: + return HTMLDirectoryElementPseudoCtor::self(exec); + case HTMLMenuElementCtor: + return HTMLMenuElementPseudoCtor::self(exec); + case HTMLLIElementCtor: + return HTMLLIElementPseudoCtor::self(exec); + case HTMLDivElementCtor: + return HTMLDivElementPseudoCtor::self(exec); + case HTMLParagraphElementCtor: + return HTMLParagraphElementPseudoCtor::self(exec); + case HTMLHeadingElementCtor: + return HTMLHeadingElementPseudoCtor::self(exec); + case HTMLBlockQuoteElementCtor: + return HTMLBlockQuoteElementPseudoCtor::self(exec); + case HTMLQuoteElementCtor: + return HTMLQuoteElementPseudoCtor::self(exec); + case HTMLPreElementCtor: + return HTMLPreElementPseudoCtor::self(exec); + case HTMLBRElementCtor: + return HTMLBRElementPseudoCtor::self(exec); + case HTMLBaseFontElementCtor: + return HTMLBaseFontElementPseudoCtor::self(exec); + case HTMLFontElementCtor: + return HTMLFontElementPseudoCtor::self(exec); + case HTMLHRElementCtor: + return HTMLHRElementPseudoCtor::self(exec); + case HTMLModElementCtor: + return HTMLModElementPseudoCtor::self(exec); + case HTMLAnchorElementCtor: + return HTMLAnchorElementPseudoCtor::self(exec); + case HTMLImageElementCtor: + return HTMLImageElementPseudoCtor::self(exec); + case HTMLObjectElementCtor: + return HTMLObjectElementPseudoCtor::self(exec); + case HTMLParamElementCtor: + return HTMLParamElementPseudoCtor::self(exec); + case HTMLAppletElementCtor: + return HTMLAppletElementPseudoCtor::self(exec); + case HTMLMapElementCtor: + return HTMLMapElementPseudoCtor::self(exec); + case HTMLAreaElementCtor: + return HTMLAreaElementPseudoCtor::self(exec); + case HTMLScriptElementCtor: + return HTMLScriptElementPseudoCtor::self(exec); + case HTMLTableElementCtor: + return HTMLTableElementPseudoCtor::self(exec); + case HTMLTableCaptionElementCtor: + return HTMLTableCaptionElementPseudoCtor::self(exec); + case HTMLTableColElementCtor: + return HTMLTableColElementPseudoCtor::self(exec); + case HTMLTableSectionElementCtor: + return HTMLTableSectionElementPseudoCtor::self(exec); + case HTMLTableRowElementCtor: + return HTMLTableRowElementPseudoCtor::self(exec); + case HTMLTableCellElementCtor: + return HTMLTableCellElementPseudoCtor::self(exec); + case HTMLFrameSetElementCtor: + return HTMLFrameSetElementPseudoCtor::self(exec); + case HTMLLayerElementCtor: + return HTMLLayerElementPseudoCtor::self(exec); + case HTMLFrameElementCtor: + return HTMLFrameElementPseudoCtor::self(exec); + case HTMLIFrameElementCtor: + return HTMLIFrameElementPseudoCtor::self(exec); + case DocumentCtor: + return DocumentPseudoCtor::self(exec); + case HTMLDocumentCtor: + return HTMLDocumentPseudoCtor::self(exec); + case CSSStyleDeclarationCtor: + return CSSStyleDeclarationPseudoCtor::self(exec); + case EventCtor: + return EventConstructor::self(exec); + case MutationEventCtor: + return getMutationEventConstructor(exec); + case KeyboardEventCtor: + return getKeyboardEventConstructor(exec); + case EventExceptionCtor: + return getEventExceptionConstructor(exec); + case _History: + return Value(history ? history : + (const_cast<Window*>(this)->history = new History(exec,part))); + + case _External: + return Value(external ? external : + (const_cast<Window*>(this)->external = new External(exec,part))); + + case Event: + if (m_evt) + return getDOMEvent(exec,*m_evt); + else { +#ifdef KJS_VERBOSE + kdDebug(6070) << "WARNING: window(" << this << "," << part->name() << ").event, no event!" << endl; +#endif + return Undefined(); + } + case InnerHeight: + if (!part->view()) + return Undefined(); + khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size + return Number(part->view()->visibleHeight()); + case InnerWidth: + if (!part->view()) + return Undefined(); + khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size + return Number(part->view()->visibleWidth()); + case Length: + return Number(part->frames().count()); + case Name: + return String(part->name()); + case SideBar: + return Value(new MozillaSidebarExtension(exec, part)); + case _Navigator: + case ClientInformation: { + // Store the navigator in the object so we get the same one each time. + Value nav( new Navigator(exec, part) ); + const_cast<Window *>(this)->put(exec, "navigator", nav, DontDelete|ReadOnly|Internal); + const_cast<Window *>(this)->put(exec, "clientInformation", nav, DontDelete|ReadOnly|Internal); + return nav; + } +#ifdef Q_WS_QWS + case _Konqueror: { + Value k( new Konqueror(part) ); + const_cast<Window *>(this)->put(exec, "konqueror", k, DontDelete|ReadOnly|Internal); + return k; + } +#endif + case OffscreenBuffering: + return Boolean(true); + case OuterHeight: + case OuterWidth: + { +#if defined Q_WS_X11 && ! defined K_WS_QTONLY + if (!part->widget()) + return Number(0); + KWin::WindowInfo inf = KWin::windowInfo(part->widget()->topLevelWidget()->winId()); + return Number(entry->value == OuterHeight ? + inf.geometry().height() : inf.geometry().width()); +#else + return Number(entry->value == OuterHeight ? + part->view()->height() : part->view()->width()); +#endif + } + case PageXOffset: + return Number(part->view()->contentsX()); + case PageYOffset: + return Number(part->view()->contentsY()); + case Personalbar: + return Undefined(); // ### + case ScreenLeft: + case ScreenX: { + if (!part->view()) + return Undefined(); + QRect sg = KGlobalSettings::desktopGeometry(part->view()); + return Number(part->view()->mapToGlobal(QPoint(0,0)).x() + sg.x()); + } + case ScreenTop: + case ScreenY: { + if (!part->view()) + return Undefined(); + QRect sg = KGlobalSettings::desktopGeometry(part->view()); + return Number(part->view()->mapToGlobal(QPoint(0,0)).y() + sg.y()); + } + case ScrollX: { + if (!part->view()) + return Undefined(); + return Number(part->view()->contentsX()); + } + case ScrollY: { + if (!part->view()) + return Undefined(); + return Number(part->view()->contentsY()); + } + case Scrollbars: + return Undefined(); // ### + case _Screen: + return Value(screen ? screen : + (const_cast<Window*>(this)->screen = new Screen(exec))); + case Image: + return Value(new ImageConstructorImp(exec, part->document())); + case Option: + return Value(new OptionConstructorImp(exec, part->document())); + case XMLHttpRequest: + return Value(new XMLHttpRequestConstructorImp(exec, part->document())); + case XMLSerializer: + return Value(new XMLSerializerConstructorImp(exec)); + case DOMParser: + return Value(new DOMParserConstructorImp(exec, part->xmlDocImpl())); + case Scroll: // compatibility + case ScrollBy: + case ScrollTo: + case MoveBy: + case MoveTo: + case ResizeBy: + case ResizeTo: + case CaptureEvents: + case ReleaseEvents: + case AddEventListener: + case RemoveEventListener: + case SetTimeout: + case ClearTimeout: + case SetInterval: + case ClearInterval: + case Print: + return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); + // IE extension + case Navigate: + // Disabled in NS-compat mode. Supported by default - can't hurt, unless someone uses + // if (navigate) to test for IE (unlikely). + if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat ) + return Undefined(); + return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr); + case Onabort: + return getListener(exec,DOM::EventImpl::ABORT_EVENT); + case Onblur: + return getListener(exec,DOM::EventImpl::BLUR_EVENT); + case Onchange: + return getListener(exec,DOM::EventImpl::CHANGE_EVENT); + case Onclick: + return getListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT); + case Ondblclick: + return getListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT); + case Ondragdrop: + return getListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT); + case Onerror: + return getListener(exec,DOM::EventImpl::ERROR_EVENT); + case Onfocus: + return getListener(exec,DOM::EventImpl::FOCUS_EVENT); + case Onkeydown: + return getListener(exec,DOM::EventImpl::KEYDOWN_EVENT); + case Onkeypress: + return getListener(exec,DOM::EventImpl::KEYPRESS_EVENT); + case Onkeyup: + return getListener(exec,DOM::EventImpl::KEYUP_EVENT); + case Onload: + return getListener(exec,DOM::EventImpl::LOAD_EVENT); + case Onmousedown: + return getListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT); + case Onmousemove: + return getListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT); + case Onmouseout: + return getListener(exec,DOM::EventImpl::MOUSEOUT_EVENT); + case Onmouseover: + return getListener(exec,DOM::EventImpl::MOUSEOVER_EVENT); + case Onmouseup: + return getListener(exec,DOM::EventImpl::MOUSEUP_EVENT); + case Onmove: + return getListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT); + case Onreset: + return getListener(exec,DOM::EventImpl::RESET_EVENT); + case Onresize: + return getListener(exec,DOM::EventImpl::RESIZE_EVENT); + case Onselect: + return getListener(exec,DOM::EventImpl::SELECT_EVENT); + case Onsubmit: + return getListener(exec,DOM::EventImpl::SUBMIT_EVENT); + case Onunload: + return getListener(exec,DOM::EventImpl::UNLOAD_EVENT); + } + } + + // doing the remainder of ObjectImp::get() that is not covered by + // the getDirect() call above. + // #### guessed position. move further up or down? + Object proto = Object::dynamicCast(prototype()); + assert(proto.isValid()); + if (p == specialPrototypePropertyName) + return isSafeScript(exec) ? Value(proto) : Undefined(); + Value val2 = proto.get(exec, p); + if (!val2.isA(UndefinedType)) { + return isSafeScript(exec) ? val2 : Undefined(); + } + + KParts::ReadOnlyPart *rop = part->findFramePart( p.qstring() ); + if (rop) + return retrieve(rop); + + // allow window[1] or parent[1] etc. (#56983) + bool ok; + unsigned int i = p.toArrayIndex(&ok); + if (ok) { + QPtrList<KParts::ReadOnlyPart> frames = part->frames(); + unsigned int len = frames.count(); + if (i < len) { + KParts::ReadOnlyPart* frame = frames.at(i); + if (frame) + return Window::retrieve(frame); + } + } + + //Check for images, forms, objects, etc. + if (isSafeScript(exec) && part->document().isHTMLDocument()) { // might be XML + DOM::DocumentImpl* docImpl = part->xmlDocImpl(); + DOM::ElementMappingCache::ItemInfo* info = docImpl->underDocNamedCache().get(p.qstring()); + if (info) { + //May be a false positive, but we can try to avoid doing it the hard way in + //simpler cases. The trickiness here is that the cache is kept under both + //name and id, but we sometimes ignore id for IE compat + DOM::DOMString propertyDOMString = p.string(); + if (info->nd && DOM::HTMLMappedNameCollectionImpl::matchesName(info->nd, + DOM::HTMLCollectionImpl::WINDOW_NAMED_ITEMS, propertyDOMString)) { + return getDOMNode(exec, info->nd); + } else { + //Can't tell it just like that, so better go through collection and count stuff. This is the slow path... + DOM::HTMLMappedNameCollection coll(docImpl, DOM::HTMLCollectionImpl::WINDOW_NAMED_ITEMS, propertyDOMString); + + if (coll.length() == 1) + return getDOMNode(exec, coll.firstItem()); + else if (coll.length() > 1) + return getHTMLCollection(exec, coll); + } + } + DOM::Element element = part->document().getElementById(p.string()); + if ( !element.isNull() ) + return getDOMNode(exec, element ); + } + + // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1 + // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping. +#ifdef KJS_VERBOSE + kdDebug(6070) << "WARNING: Window::get property not found: " << p.qstring() << endl; +#endif + return Undefined(); +} + +void Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr) +{ + // we don't want any operations on a closed window + if (m_frame.isNull() || m_frame->m_part.isNull()) { + // ### throw exception? allow setting of some props like location? + return; + } + + // Called by an internal KJS call (e.g. InterpreterImp's constructor) ? + // If yes, save time and jump directly to ObjectImp. + if ( (attr != None && attr != DontDelete) || + // Same thing if we have a local override (e.g. "var location") + ( isSafeScript( exec ) && ObjectImp::getDirect(propertyName) ) ) + { + ObjectImp::put( exec, propertyName, value, attr ); + return; + } + + const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName); + if (entry && !m_frame.isNull() && !m_frame->m_part.isNull()) + { +#ifdef KJS_VERBOSE + kdDebug(6070) << "Window("<<this<<")::put " << propertyName.qstring() << endl; +#endif + switch( entry->value) { + case _Location: + goURL(exec, value.toString(exec).qstring(), false /*don't lock history*/); + return; + default: + break; + } + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (part) { + switch( entry->value ) { + case Status: { + if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host()) + == KHTMLSettings::KJSWindowStatusAllow) { + String s = value.toString(exec); + part->setJSStatusBarText(s.value().qstring()); + } + return; + } + case DefaultStatus: { + if (isSafeScript(exec) && part->settings()->windowStatusPolicy(part->url().host()) + == KHTMLSettings::KJSWindowStatusAllow) { + String s = value.toString(exec); + part->setJSDefaultStatusBarText(s.value().qstring()); + } + return; + } + case Onabort: + if (isSafeScript(exec)) + setListener(exec, DOM::EventImpl::ABORT_EVENT,value); + return; + case Onblur: + if (isSafeScript(exec)) + setListener(exec, DOM::EventImpl::BLUR_EVENT,value); + return; + case Onchange: + if (isSafeScript(exec)) + setListener(exec, DOM::EventImpl::CHANGE_EVENT,value); + return; + case Onclick: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT,value); + return; + case Ondblclick: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT,value); + return; + case Ondragdrop: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value); + return; + case Onerror: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::ERROR_EVENT,value); + return; + case Onfocus: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::FOCUS_EVENT,value); + return; + case Onkeydown: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value); + return; + case Onkeypress: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KEYPRESS_EVENT,value); + return; + case Onkeyup: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KEYUP_EVENT,value); + return; + case Onload: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::LOAD_EVENT,value); + return; + case Onmousedown: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value); + return; + case Onmousemove: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value); + return; + case Onmouseout: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value); + return; + case Onmouseover: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value); + return; + case Onmouseup: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value); + return; + case Onmove: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value); + return; + case Onreset: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::RESET_EVENT,value); + return; + case Onresize: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::RESIZE_EVENT,value); + return; + case Onselect: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::SELECT_EVENT,value); + return; + case Onsubmit: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value); + return; + case Onunload: + if (isSafeScript(exec)) + setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value); + return; + case Name: + if (isSafeScript(exec)) + part->setName( value.toString(exec).qstring().local8Bit().data() ); + return; + default: + break; + } + } + } + if (m_frame->m_liveconnect && + isSafeScript(exec) && + m_frame->m_liveconnect->put(0, propertyName.qstring(), value.toString(exec).qstring())) + return; + if (isSafeScript(exec)) { + //kdDebug(6070) << "Window("<<this<<")::put storing " << propertyName.qstring() << endl; + ObjectImp::put(exec, propertyName, value, attr); + } +} + +bool Window::toBoolean(ExecState *) const +{ + return !m_frame.isNull() && !m_frame->m_part.isNull(); +} + +DOM::AbstractView Window::toAbstractView() const +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part) + return DOM::AbstractView(); + return part->document().defaultView(); +} + +void Window::scheduleClose() +{ + kdDebug(6070) << "Window::scheduleClose window.close() " << m_frame << endl; + Q_ASSERT(winq); + QTimer::singleShot( 0, winq, SLOT( timeoutClose() ) ); +} + +void Window::closeNow() +{ + if (m_frame.isNull() || m_frame->m_part.isNull()) { + kdDebug(6070) << k_funcinfo << "part is deleted already" << endl; + } else { + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part) { + kdDebug(6070) << "closeNow on non KHTML part" << endl; + } else { + //kdDebug(6070) << k_funcinfo << " -> closing window" << endl; + // We want to make sure that window.open won't find this part by name. + part->setName( 0 ); + part->deleteLater(); + part = 0; + } + } +} + +void Window::afterScriptExecution() +{ + DOM::DocumentImpl::updateDocumentsRendering(); + QValueList<DelayedAction> delayedActions = m_delayed; + m_delayed.clear(); + QValueList<DelayedAction>::Iterator it = delayedActions.begin(); + for ( ; it != delayedActions.end() ; ++it ) + { + switch ((*it).actionId) { + case DelayedClose: + scheduleClose(); + return; // stop here, in case of multiple actions + case DelayedGoHistory: + goHistory( (*it).param.toInt() ); + break; + case NullAction: + // FIXME: anything needs to be done here? This is warning anyways. + break; + }; + } +} + +bool Window::checkIsSafeScript(KParts::ReadOnlyPart *activePart) const +{ + if (m_frame.isNull() || m_frame->m_part.isNull()) { // part deleted ? can't grant access + kdDebug(6070) << "Window::isSafeScript: accessing deleted part !" << endl; + return false; + } + if (!activePart) { + kdDebug(6070) << "Window::isSafeScript: current interpreter's part is 0L!" << endl; + return false; + } + if ( activePart == m_frame->m_part ) // Not calling from another frame, no problem. + return true; + + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part) + return true; // not a KHTMLPart + + if ( part->document().isNull() ) + return true; // allow to access a window that was just created (e.g. with window.open("about:blank")) + + DOM::HTMLDocument thisDocument = part->htmlDocument(); + if ( thisDocument.isNull() ) { + kdDebug(6070) << "Window::isSafeScript: trying to access an XML document !?" << endl; + return false; + } + + KHTMLPart *activeKHTMLPart = ::qt_cast<KHTMLPart *>(activePart); + if (!activeKHTMLPart) + return true; // not a KHTMLPart + + DOM::HTMLDocument actDocument = activeKHTMLPart->htmlDocument(); + if ( actDocument.isNull() ) { + kdDebug(6070) << "Window::isSafeScript: active part has no document!" << endl; + return false; + } + DOM::DOMString actDomain = actDocument.domain(); + DOM::DOMString thisDomain = thisDocument.domain(); + + if ( actDomain == thisDomain ) { +#ifdef KJS_VERBOSE + //kdDebug(6070) << "JavaScript: access granted, domain is '" << actDomain.string() << "'" << endl; +#endif + return true; + } + + kdDebug(6070) << "WARNING: JavaScript: access denied for current frame '" << actDomain.string() << "' to frame '" << thisDomain.string() << "'" << endl; + // TODO after 3.1: throw security exception (exec->setException()) + return false; +} + +void Window::setListener(ExecState *exec, int eventId, Value func) +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part || !isSafeScript(exec)) + return; + DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(part->htmlDocument().handle()); + if (!doc) + return; + + doc->setHTMLWindowEventListener(eventId,getJSEventListener(func,true)); +} + +Value Window::getListener(ExecState *exec, int eventId) const +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part || !isSafeScript(exec)) + return Undefined(); + DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(part->htmlDocument().handle()); + if (!doc) + return Undefined(); + + DOM::EventListener *listener = doc->getHTMLWindowEventListener(eventId); + if (listener && static_cast<JSEventListener*>(listener)->listenerObjImp()) + return static_cast<JSEventListener*>(listener)->listenerObj(); + else + return Null(); +} + + +JSEventListener *Window::getJSEventListener(const Value& val, bool html) +{ + // This function is so hot that it's worth coding it directly with imps. + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part || val.type() != ObjectType) + return 0; + + // It's ObjectType, so it must be valid. + Object listenerObject = Object::dynamicCast(val); + ObjectImp *listenerObjectImp = listenerObject.imp(); + + // 'listener' is not a simple ecma function. (Always use sanity checks: Better safe than sorry!) + if (!listenerObject.implementsCall() && part && part->jScript() && part->jScript()->interpreter()) + { + Interpreter *interpreter = part->jScript()->interpreter(); + + // 'listener' probably is an EventListener object containing a 'handleEvent' function. + Value handleEventValue = listenerObject.get(interpreter->globalExec(), Identifier("handleEvent")); + Object handleEventObject = Object::dynamicCast(handleEventValue); + + if(handleEventObject.isValid() && handleEventObject.implementsCall()) + { + listenerObject = handleEventObject; + listenerObjectImp = handleEventObject.imp(); + } + } + + JSEventListener *existingListener = jsEventListeners[listenerObjectImp]; + if (existingListener) { + if ( existingListener->isHTMLEventListener() != html ) + // The existingListener will have the wrong type, so onclick= will behave like addEventListener or vice versa. + kdWarning() << "getJSEventListener: event listener already found but with html=" << !html << " - please report this, we thought it would never happen" << endl; + return existingListener; + } + + // Note that the JSEventListener constructor adds it to our jsEventListeners list + return new JSEventListener(listenerObject, listenerObjectImp, Object(this), html); +} + +JSLazyEventListener *Window::getJSLazyEventListener(const QString& code, const QString& name, DOM::NodeImpl *node) +{ + return new JSLazyEventListener(code, name, Object(this), node); +} + +void Window::clear( ExecState *exec ) +{ + delete winq; + winq = 0L; + // Get rid of everything, those user vars could hold references to DOM nodes + deleteAllProperties( exec ); + + // Break the dependency between the listeners and their object + QPtrDictIterator<JSEventListener> it(jsEventListeners); + for (; it.current(); ++it) + it.current()->clear(); + // Forget about the listeners (the DOM::NodeImpls will delete them) + jsEventListeners.clear(); + + if (m_frame) { + KJSProxy* proxy = m_frame->m_jscript; + if (proxy) // i.e. JS not disabled + { + winq = new WindowQObject(this); + // Now recreate a working global object for the next URL that will use us + KJS::Interpreter *interpreter = proxy->interpreter(); + interpreter->initGlobalObject(); + } + } +} + +void Window::setCurrentEvent( DOM::Event *evt ) +{ + m_evt = evt; + //kdDebug(6070) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt << endl; +} + +void Window::goURL(ExecState* exec, const QString& url, bool lockHistory) +{ + Window* active = Window::retrieveActive(exec); + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + KHTMLPart *active_part = ::qt_cast<KHTMLPart *>(active->part()); + // Complete the URL using the "active part" (running interpreter) + if (active_part && part) { + if (url[0] == QChar('#')) { + part->gotoAnchor(url.mid(1)); + } else { + QString dstUrl = active_part->htmlDocument().completeURL(url).string(); + kdDebug(6070) << "Window::goURL dstUrl=" << dstUrl << endl; + + // check if we're allowed to inject javascript + // SYNC check with khtml_part.cpp::slotRedirect! + if ( isSafeScript(exec) || + dstUrl.find(QString::fromLatin1("javascript:"), 0, false) != 0 ) + part->scheduleRedirection(-1, + dstUrl, + lockHistory); + } + } else if (!part && !m_frame->m_part.isNull()) { + KParts::BrowserExtension *b = KParts::BrowserExtension::childObject(m_frame->m_part); + if (b) + b->emit openURLRequest(m_frame->m_frame->element()->getDocument()->completeURL(url)); + kdDebug() << "goURL for ROPart" << endl; + } +} + +KParts::ReadOnlyPart *Window::part() const { + return m_frame.isNull() ? 0L : static_cast<KParts::ReadOnlyPart *>(m_frame->m_part); +} + +void Window::delayedGoHistory( int steps ) +{ + m_delayed.append( DelayedAction( DelayedGoHistory, steps ) ); +} + +void Window::goHistory( int steps ) +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if(!part) + // TODO history readonlypart + return; + KParts::BrowserExtension *ext = part->browserExtension(); + if(!ext) + return; + KParts::BrowserInterface *iface = ext->browserInterface(); + + if ( !iface ) + return; + + iface->callMethod( "goHistory(int)", steps ); + //emit ext->goHistory(steps); +} + +void KJS::Window::resizeTo(QWidget* tl, int width, int height) +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if(!part) + // TODO resizeTo readonlypart + return; + KParts::BrowserExtension *ext = part->browserExtension(); + if (!ext) { + kdDebug(6070) << "Window::resizeTo found no browserExtension" << endl; + return; + } + + // Security check: within desktop limits and bigger than 100x100 (per spec) + if ( width < 100 || height < 100 ) { + kdDebug(6070) << "Window::resizeTo refused, window would be too small ("<<width<<","<<height<<")" << endl; + return; + } + + QRect sg = KGlobalSettings::desktopGeometry(tl); + + if ( width > sg.width() || height > sg.height() ) { + kdDebug(6070) << "Window::resizeTo refused, window would be too big ("<<width<<","<<height<<")" << endl; + return; + } + + kdDebug(6070) << "resizing to " << width << "x" << height << endl; + + emit ext->resizeTopLevelWidget( width, height ); + + // If the window is out of the desktop, move it up/left + // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker) + int right = tl->x() + tl->frameGeometry().width(); + int bottom = tl->y() + tl->frameGeometry().height(); + int moveByX = 0; + int moveByY = 0; + if ( right > sg.right() ) + moveByX = - right + sg.right(); // always <0 + if ( bottom > sg.bottom() ) + moveByY = - bottom + sg.bottom(); // always <0 + if ( moveByX || moveByY ) + emit ext->moveTopLevelWidget( tl->x() + moveByX , tl->y() + moveByY ); +} + +Value Window::openWindow(ExecState *exec, const List& args) +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(m_frame->m_part); + if (!part) + return Undefined(); + KHTMLView *widget = part->view(); + Value v = args[0]; + QString str; + if (v.isValid() && !v.isA(UndefinedType)) + str = v.toString(exec).qstring(); + + // prepare arguments + KURL url; + if (!str.isEmpty()) + { + KHTMLPart* p = ::qt_cast<KHTMLPart *>(Window::retrieveActive(exec)->m_frame->m_part); + if ( p ) + url = p->htmlDocument().completeURL(str).string(); + if ( !p || + !static_cast<DOM::DocumentImpl*>(p->htmlDocument().handle())->isURLAllowed(url.url()) ) + return Undefined(); + } + + KHTMLSettings::KJSWindowOpenPolicy policy = + part->settings()->windowOpenPolicy(part->url().host()); + if ( policy == KHTMLSettings::KJSWindowOpenAsk ) { + emit part->browserExtension()->requestFocus(part); + QString caption; + if (!part->url().host().isEmpty()) + caption = part->url().host() + " - "; + caption += i18n( "Confirmation: JavaScript Popup" ); + if ( KMessageBox::questionYesNo(widget, + str.isEmpty() ? + i18n( "This site is requesting to open up a new browser " + "window via JavaScript.\n" + "Do you want to allow this?" ) : + i18n( "<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />" + "Do you want to allow this?</qt>").arg(KStringHandler::csqueeze(url.htmlURL(), 100)), + caption, i18n("Allow"), i18n("Do Not Allow") ) == KMessageBox::Yes ) + policy = KHTMLSettings::KJSWindowOpenAllow; + } else if ( policy == KHTMLSettings::KJSWindowOpenSmart ) + { + // window.open disabled unless from a key/mouse event + if (static_cast<ScriptInterpreter *>(exec->interpreter())->isWindowOpenAllowed()) + policy = KHTMLSettings::KJSWindowOpenAllow; + } + + QString frameName = args.size() > 1 ? args[1].toString(exec).qstring() : QString("_blank"); + + v = args[2]; + QString features; + if (!v.isNull() && v.type() != UndefinedType && v.toString(exec).size() > 0) { + features = v.toString(exec).qstring(); + // Buggy scripts have ' at beginning and end, cut those + if (features.startsWith("\'") && features.endsWith("\'")) + features = features.mid(1, features.length()-2); + } + + if ( policy != KHTMLSettings::KJSWindowOpenAllow ) { + if ( url.isEmpty() ) + part->setSuppressedPopupIndicator(true, 0); + else { + part->setSuppressedPopupIndicator(true, part); + m_suppressedWindowInfo.append( SuppressedWindowInfo( url, frameName, features ) ); + } + return Undefined(); + } else { + return executeOpenWindow(exec, url, frameName, features); + } +} + +Value Window::executeOpenWindow(ExecState *exec, const KURL& url, const QString& frameName, const QString& features) +{ + KHTMLPart *p = ::qt_cast<KHTMLPart *>(m_frame->m_part); + KHTMLView *widget = p->view(); + KParts::WindowArgs winargs; + + // scan feature argument + if (!features.isEmpty()) { + // specifying window params means false defaults + winargs.menuBarVisible = false; + winargs.toolBarsVisible = false; + winargs.statusBarVisible = false; + winargs.scrollBarsVisible = false; + QStringList flist = QStringList::split(',', features); + QStringList::ConstIterator it = flist.begin(); + while (it != flist.end()) { + QString s = *it++; + QString key, val; + int pos = s.find('='); + if (pos >= 0) { + key = s.left(pos).stripWhiteSpace().lower(); + val = s.mid(pos + 1).stripWhiteSpace().lower(); + QRect screen = KGlobalSettings::desktopGeometry(widget->topLevelWidget()); + + if (key == "left" || key == "screenx") { + winargs.x = (int)val.toFloat() + screen.x(); + if (winargs.x < screen.x() || winargs.x > screen.right()) + winargs.x = screen.x(); // only safe choice until size is determined + } else if (key == "top" || key == "screeny") { + winargs.y = (int)val.toFloat() + screen.y(); + if (winargs.y < screen.y() || winargs.y > screen.bottom()) + winargs.y = screen.y(); // only safe choice until size is determined + } else if (key == "height") { + winargs.height = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2; + if (winargs.height > screen.height()) // should actually check workspace + winargs.height = screen.height(); + if (winargs.height < 100) + winargs.height = 100; + } else if (key == "width") { + winargs.width = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2; + if (winargs.width > screen.width()) // should actually check workspace + winargs.width = screen.width(); + if (winargs.width < 100) + winargs.width = 100; + } else { + goto boolargs; + } + continue; + } else { + // leaving away the value gives true + key = s.stripWhiteSpace().lower(); + val = "1"; + } + boolargs: + if (key == "menubar") + winargs.menuBarVisible = (val == "1" || val == "yes"); + else if (key == "toolbar") + winargs.toolBarsVisible = (val == "1" || val == "yes"); + else if (key == "location") // ### missing in WindowArgs + winargs.toolBarsVisible = (val == "1" || val == "yes"); + else if (key == "status" || key == "statusbar") + winargs.statusBarVisible = (val == "1" || val == "yes"); + else if (key == "scrollbars") + winargs.scrollBarsVisible = (val == "1" || val == "yes"); + else if (key == "resizable") + winargs.resizable = (val == "1" || val == "yes"); + else if (key == "fullscreen") + winargs.fullscreen = (val == "1" || val == "yes"); + } + } + + KParts::URLArgs uargs; + uargs.frameName = frameName; + + if ( uargs.frameName.lower() == "_top" ) + { + while ( p->parentPart() ) + p = p->parentPart(); + Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); + return Window::retrieve(p); + } + if ( uargs.frameName.lower() == "_parent" ) + { + if ( p->parentPart() ) + p = p->parentPart(); + Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); + return Window::retrieve(p); + } + if ( uargs.frameName.lower() == "_self") + { + Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/); + return Window::retrieve(p); + } + if ( uargs.frameName.lower() == "replace" ) + { + Window::retrieveWindow(p)->goURL(exec, url.url(), true /*lock history*/); + return Window::retrieve(p); + } + uargs.serviceType = "text/html"; + + // request window (new or existing if framename is set) + KParts::ReadOnlyPart *newPart = 0L; + emit p->browserExtension()->createNewWindow(KURL(), uargs,winargs,newPart); + if (newPart && ::qt_cast<KHTMLPart*>(newPart)) { + KHTMLPart *khtmlpart = static_cast<KHTMLPart*>(newPart); + //qDebug("opener set to %p (this Window's part) in new Window %p (this Window=%p)",part,win,window); + khtmlpart->setOpener(p); + khtmlpart->setOpenedByJS(true); + if (khtmlpart->document().isNull()) { + khtmlpart->begin(); + khtmlpart->write("<HTML><BODY>"); + khtmlpart->end(); + if ( p->docImpl() ) { + //kdDebug(6070) << "Setting domain to " << p->docImpl()->domain().string() << endl; + khtmlpart->docImpl()->setDomain( p->docImpl()->domain()); + khtmlpart->docImpl()->setBaseURL( p->docImpl()->baseURL() ); + } + } + uargs.serviceType = QString::null; + if (uargs.frameName.lower() == "_blank") + uargs.frameName = QString::null; + if (!url.isEmpty()) + emit khtmlpart->browserExtension()->openURLRequest(url,uargs); + return Window::retrieve(khtmlpart); // global object + } else + return Undefined(); +} + +void Window::forgetSuppressedWindows() +{ + m_suppressedWindowInfo.clear(); +} + +void Window::showSuppressedWindows() +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>( m_frame->m_part ); + KJS::Interpreter *interpreter = part->jScript()->interpreter(); + ExecState *exec = interpreter->globalExec(); + + QValueList<SuppressedWindowInfo> suppressedWindowInfo = m_suppressedWindowInfo; + m_suppressedWindowInfo.clear(); + QValueList<SuppressedWindowInfo>::Iterator it = suppressedWindowInfo.begin(); + for ( ; it != suppressedWindowInfo.end() ; ++it ) { + executeOpenWindow(exec, (*it).url, (*it).frameName, (*it).features); + } +} + +Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( Window, thisObj ); + + // these should work no matter whether the window is already + // closed or not + if (id == Window::ValueOf || id == Window::ToString) { + return String("[object Window]"); + } + + Window *window = static_cast<Window *>(thisObj.imp()); + QString str, str2; + + KHTMLPart *part = ::qt_cast<KHTMLPart *>(window->m_frame->m_part); + if (!part) + return Undefined(); + + KHTMLView *widget = part->view(); + Value v = args[0]; + UString s; + if (v.isValid() && !v.isA(UndefinedType)) { + s = v.toString(exec); + str = s.qstring(); + } + + QString caption; + if (part && !part->url().host().isEmpty()) + caption = part->url().host() + " - "; + caption += "JavaScript"; // TODO: i18n + // functions that work everywhere + switch(id) { + case Window::Alert: + if (!widget->dialogsAllowed()) + return Undefined(); + if ( part && part->xmlDocImpl() ) + part->xmlDocImpl()->updateRendering(); + if ( part ) + emit part->browserExtension()->requestFocus(part); + KMessageBox::error(widget, QStyleSheet::convertFromPlainText(str, QStyleSheetItem::WhiteSpaceNormal), caption); + return Undefined(); + case Window::Confirm: + if (!widget->dialogsAllowed()) + return Undefined(); + if ( part && part->xmlDocImpl() ) + part->xmlDocImpl()->updateRendering(); + if ( part ) + emit part->browserExtension()->requestFocus(part); + return Boolean((KMessageBox::warningYesNo(widget, QStyleSheet::convertFromPlainText(str), caption, + KStdGuiItem::ok(), KStdGuiItem::cancel()) == KMessageBox::Yes)); + case Window::Prompt: +#ifndef KONQ_EMBEDDED + if (!widget->dialogsAllowed()) + return Undefined(); + if ( part && part->xmlDocImpl() ) + part->xmlDocImpl()->updateRendering(); + if ( part ) + emit part->browserExtension()->requestFocus(part); + bool ok; + if (args.size() >= 2) + str2 = KInputDialog::getText(caption, + QStyleSheet::convertFromPlainText(str), + args[1].toString(exec).qstring(), &ok, widget); + else + str2 = KInputDialog::getText(caption, + QStyleSheet::convertFromPlainText(str), + QString::null, &ok, widget); + if ( ok ) + return String(str2); + else + return Null(); +#else + return Undefined(); +#endif + case Window::GetComputedStyle: { + if ( !part || !part->xmlDocImpl() ) + return Undefined(); + DOM::Node arg0 = toNode(args[0]); + if (arg0.nodeType() != DOM::Node::ELEMENT_NODE) + return Undefined(); // throw exception? + else + return getDOMCSSStyleDeclaration(exec, part->document().defaultView().getComputedStyle(static_cast<DOM::Element>(arg0), + args[1].toString(exec).string())); + } + case Window::Open: + return window->openWindow(exec, args); + case Window::Close: { + /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm : + The close method closes only windows opened by JavaScript using the open method. + If you attempt to close any other window, a confirm is generated, which + lets the user choose whether the window closes. + This is a security feature to prevent "mail bombs" containing self.close(). + However, if the window has only one document (the current one) in its + session history, the close is allowed without any confirm. This is a + special case for one-off windows that need to open other windows and + then dispose of themselves. + */ + bool doClose = false; + if (!part->openedByJS()) + { + // To conform to the SPEC, we only ask if the window + // has more than one entry in the history (NS does that too). + History history(exec,part); + + if ( history.get( exec, "length" ).toInt32(exec) <= 1 ) + { + doClose = true; + } + else + { + // Can we get this dialog with tabs??? Does it close the window or the tab in that case? + emit part->browserExtension()->requestFocus(part); + if ( KMessageBox::questionYesNo( window->part()->widget(), + i18n("Close window?"), i18n("Confirmation Required"), + KStdGuiItem::close(), KStdGuiItem::cancel() ) + == KMessageBox::Yes ) + doClose = true; + } + } + else + doClose = true; + + if (doClose) + { + // If this is the current window (the one the interpreter runs in), + // then schedule a delayed close (so that the script terminates first). + // But otherwise, close immediately. This fixes w=window.open("","name");w.close();window.open("name"); + if ( Window::retrieveActive(exec) == window ) { + if (widget) { + // quit all dialogs of this view + // this fixes 'setTimeout('self.close()',1000); alert("Hi");' crash + widget->closeChildDialogs(); + } + //kdDebug() << "scheduling delayed close" << endl; + // We'll close the window at the end of the script execution + Window* w = const_cast<Window*>(window); + w->m_delayed.append( Window::DelayedAction( Window::DelayedClose ) ); + } else { + //kdDebug() << "closing NOW" << endl; + (const_cast<Window*>(window))->closeNow(); + } + } + return Undefined(); + } + case Window::Navigate: + window->goURL(exec, args[0].toString(exec).qstring(), false /*don't lock history*/); + return Undefined(); + case Window::Focus: { + KHTMLSettings::KJSWindowFocusPolicy policy = + part->settings()->windowFocusPolicy(part->url().host()); + if(policy == KHTMLSettings::KJSWindowFocusAllow && widget) { + widget->topLevelWidget()->raise(); + KWin::deIconifyWindow( widget->topLevelWidget()->winId() ); + widget->setActiveWindow(); + emit part->browserExtension()->requestFocus(part); + } + return Undefined(); + } + case Window::Blur: + // TODO + return Undefined(); + case Window::BToA: + case Window::AToB: { + if (!s.is8Bit()) + return Undefined(); + QByteArray in, out; + char *binData = s.ascii(); + in.setRawData( binData, s.size() ); + if (id == Window::AToB) + KCodecs::base64Decode( in, out ); + else + KCodecs::base64Encode( in, out ); + in.resetRawData( binData, s.size() ); + UChar *d = new UChar[out.size()]; + for (uint i = 0; i < out.size(); i++) + d[i].uc = (uchar) out[i]; + UString ret(d, out.size(), false /*no copy*/); + return String(ret); + } + + }; + + + // now unsafe functions.. + if (!window->isSafeScript(exec)) + return Undefined(); + + switch (id) { + case Window::ScrollBy: + if(args.size() == 2 && widget) + widget->scrollBy(args[0].toInt32(exec), args[1].toInt32(exec)); + return Undefined(); + case Window::Scroll: + case Window::ScrollTo: + if(args.size() == 2 && widget) + widget->setContentsPos(args[0].toInt32(exec), args[1].toInt32(exec)); + return Undefined(); + case Window::MoveBy: { + KHTMLSettings::KJSWindowMovePolicy policy = + part->settings()->windowMovePolicy(part->url().host()); + if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) + { + KParts::BrowserExtension *ext = part->browserExtension(); + if (ext) { + QWidget * tl = widget->topLevelWidget(); + QRect sg = KGlobalSettings::desktopGeometry(tl); + + QPoint dest = tl->pos() + QPoint( args[0].toInt32(exec), args[1].toInt32(exec) ); + // Security check (the spec talks about UniversalBrowserWrite to disable this check...) + if ( dest.x() >= sg.x() && dest.y() >= sg.x() && + dest.x()+tl->width() <= sg.width()+sg.x() && + dest.y()+tl->height() <= sg.height()+sg.y() ) + emit ext->moveTopLevelWidget( dest.x(), dest.y() ); + } + } + return Undefined(); + } + case Window::MoveTo: { + KHTMLSettings::KJSWindowMovePolicy policy = + part->settings()->windowMovePolicy(part->url().host()); + if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget) + { + KParts::BrowserExtension *ext = part->browserExtension(); + if (ext) { + QWidget * tl = widget->topLevelWidget(); + QRect sg = KGlobalSettings::desktopGeometry(tl); + + QPoint dest( args[0].toInt32(exec)+sg.x(), args[1].toInt32(exec)+sg.y() ); + // Security check (the spec talks about UniversalBrowserWrite to disable this check...) + if ( dest.x() >= sg.x() && dest.y() >= sg.y() && + dest.x()+tl->width() <= sg.width()+sg.x() && + dest.y()+tl->height() <= sg.height()+sg.y() ) + emit ext->moveTopLevelWidget( dest.x(), dest.y() ); + } + } + return Undefined(); + } + case Window::ResizeBy: { + KHTMLSettings::KJSWindowResizePolicy policy = + part->settings()->windowResizePolicy(part->url().host()); + if(policy == KHTMLSettings::KJSWindowResizeAllow + && args.size() == 2 && widget) + { + QWidget * tl = widget->topLevelWidget(); + QRect geom = tl->frameGeometry(); + window->resizeTo( tl, + geom.width() + args[0].toInt32(exec), + geom.height() + args[1].toInt32(exec) ); + } + return Undefined(); + } + case Window::ResizeTo: { + KHTMLSettings::KJSWindowResizePolicy policy = + part->settings()->windowResizePolicy(part->url().host()); + if(policy == KHTMLSettings::KJSWindowResizeAllow + && args.size() == 2 && widget) + { + QWidget * tl = widget->topLevelWidget(); + window->resizeTo( tl, args[0].toInt32(exec), args[1].toInt32(exec) ); + } + return Undefined(); + } + case Window::SetTimeout: + case Window::SetInterval: { + bool singleShot; + int i; // timeout interval + if (args.size() == 0) + return Undefined(); + if (args.size() > 1) { + singleShot = (id == Window::SetTimeout); + i = args[1].toInt32(exec); + } else { + // second parameter is missing. Emulate Mozilla behavior. + singleShot = true; + i = 4; + } + if (v.isA(StringType)) { + int r = (const_cast<Window*>(window))->winq->installTimeout(Identifier(s), i, singleShot ); + return Number(r); + } + else if (v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) { + Object func = Object::dynamicCast(v); + List funcArgs; + ListIterator it = args.begin(); + int argno = 0; + while (it != args.end()) { + Value arg = it++; + if (argno++ >= 2) + funcArgs.append(arg); + } + if (args.size() < 2) + funcArgs.append(Number(i)); + int r = (const_cast<Window*>(window))->winq->installTimeout(func, funcArgs, i, singleShot ); + return Number(r); + } + else + return Undefined(); + } + case Window::ClearTimeout: + case Window::ClearInterval: + (const_cast<Window*>(window))->winq->clearTimeout(v.toInt32(exec)); + return Undefined(); + case Window::Print: + if ( widget ) { + // ### TODO emit onbeforeprint event + widget->print(); + // ### TODO emit onafterprint event + } + case Window::CaptureEvents: + case Window::ReleaseEvents: + // Do nothing for now. These are NS-specific legacy calls. + break; + case Window::AddEventListener: { + JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); + if (listener) { + DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle()); + docimpl->addWindowEventListener(DOM::EventImpl::typeToId(args[0].toString(exec).string()),listener,args[2].toBoolean(exec)); + } + return Undefined(); + } + case Window::RemoveEventListener: { + JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); + if (listener) { + DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle()); + docimpl->removeWindowEventListener(DOM::EventImpl::typeToId(args[0].toString(exec).string()),listener,args[2].toBoolean(exec)); + } + return Undefined(); + } + + } + return Undefined(); +} + +////////////////////// ScheduledAction //////////////////////// + +// KDE 4: Make those parameters const ... & +ScheduledAction::ScheduledAction(Object _func, List _args, DateTimeMS _nextTime, int _interval, bool _singleShot, + int _timerId) +{ + //kdDebug(6070) << "ScheduledAction::ScheduledAction(isFunction) " << this << endl; + func = static_cast<ObjectImp*>(_func.imp()); + args = _args; + isFunction = true; + singleShot = _singleShot; + nextTime = _nextTime; + interval = _interval; + executing = false; + timerId = _timerId; +} + +// KDE 4: Make it const QString & +ScheduledAction::ScheduledAction(QString _code, DateTimeMS _nextTime, int _interval, bool _singleShot, int _timerId) +{ + //kdDebug(6070) << "ScheduledAction::ScheduledAction(!isFunction) " << this << endl; + //func = 0; + //args = 0; + func = 0; + code = _code; + isFunction = false; + singleShot = _singleShot; + nextTime = _nextTime; + interval = _interval; + executing = false; + timerId = _timerId; +} + +bool ScheduledAction::execute(Window *window) +{ + KHTMLPart *part = ::qt_cast<KHTMLPart *>(window->m_frame->m_part); + if (!part || !part->jScriptEnabled()) + return false; + ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(part->jScript()->interpreter()); + + interpreter->setProcessingTimerCallback(true); + + //kdDebug(6070) << "ScheduledAction::execute " << this << endl; + if (isFunction) { + if (func->implementsCall()) { + // #### check this + Q_ASSERT( part ); + if ( part ) + { + KJS::Interpreter *interpreter = part->jScript()->interpreter(); + ExecState *exec = interpreter->globalExec(); + Q_ASSERT( window == interpreter->globalObject().imp() ); + Object obj( window ); + func->call(exec,obj,args); // note that call() creates its own execution state for the func call + if (exec->hadException()) + exec->clearException(); + + // Update our document's rendering following the execution of the timeout callback. + part->document().updateRendering(); + } + } + } + else { + part->executeScript(DOM::Node(), code); + } + + interpreter->setProcessingTimerCallback(false); + return true; +} + +void ScheduledAction::mark() +{ + if (func && !func->marked()) + func->mark(); + args.mark(); +} + +ScheduledAction::~ScheduledAction() +{ + //kdDebug(6070) << "ScheduledAction::~ScheduledAction " << this << endl; +} + +////////////////////// WindowQObject //////////////////////// + +WindowQObject::WindowQObject(Window *w) + : parent(w) +{ + //kdDebug(6070) << "WindowQObject::WindowQObject " << this << endl; + if ( !parent->m_frame ) + kdDebug(6070) << "WARNING: null part in " << k_funcinfo << endl; + else + connect( parent->m_frame, SIGNAL( destroyed() ), + this, SLOT( parentDestroyed() ) ); + pausedTime = 0; + lastTimerId = 0; + currentlyDispatching = false; +} + +WindowQObject::~WindowQObject() +{ + //kdDebug(6070) << "WindowQObject::~WindowQObject " << this << endl; + parentDestroyed(); // reuse same code +} + +void WindowQObject::parentDestroyed() +{ + killTimers(); + + QPtrListIterator<ScheduledAction> it(scheduledActions); + for (; it.current(); ++it) + delete it.current(); + scheduledActions.clear(); +} + +int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot) +{ + int id = ++lastTimerId; + if (t < 10) t = 10; + DateTimeMS nextTime = DateTimeMS::now().addMSecs(-pausedTime + t); + + ScheduledAction *action = new ScheduledAction(handler.qstring(),nextTime,t,singleShot,id); + scheduledActions.append(action); + setNextTimer(); + return id; +} + +int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot) +{ + Object objFunc = Object::dynamicCast( func ); + if (!objFunc.isValid()) + return 0; + int id = ++lastTimerId; + if (t < 10) t = 10; + + DateTimeMS nextTime = DateTimeMS::now().addMSecs(-pausedTime + t); + ScheduledAction *action = new ScheduledAction(objFunc,args,nextTime,t,singleShot,id); + scheduledActions.append(action); + setNextTimer(); + return id; +} + +void WindowQObject::clearTimeout(int timerId) +{ + QPtrListIterator<ScheduledAction> it(scheduledActions); + for (; it.current(); ++it) { + ScheduledAction *action = it.current(); + if (action->timerId == timerId) { + scheduledActions.removeRef(action); + if (!action->executing) + delete action; + return; + } + } +} + +bool WindowQObject::hasTimers() const +{ + return scheduledActions.count(); +} + +void WindowQObject::mark() +{ + QPtrListIterator<ScheduledAction> it(scheduledActions); + for (; it.current(); ++it) + it.current()->mark(); +} + +void WindowQObject::timerEvent(QTimerEvent *) +{ + killTimers(); + + if (scheduledActions.isEmpty()) + return; + + currentlyDispatching = true; + + + DateTimeMS currentActual = DateTimeMS::now(); + DateTimeMS currentAdjusted = currentActual.addMSecs(-pausedTime); + + // Work out which actions are to be executed. We take a separate copy of + // this list since the main one may be modified during action execution + QPtrList<ScheduledAction> toExecute; + QPtrListIterator<ScheduledAction> it(scheduledActions); + for (; it.current(); ++it) + if (currentAdjusted >= it.current()->nextTime) + toExecute.append(it.current()); + + // ### verify that the window can't be closed (and action deleted) during execution + it = QPtrListIterator<ScheduledAction>(toExecute); + for (; it.current(); ++it) { + ScheduledAction *action = it.current(); + if (!scheduledActions.containsRef(action)) // removed by clearTimeout() + continue; + + action->executing = true; // prevent deletion in clearTimeout() + + if (parent->part()) { + bool ok = action->execute(parent); + if ( !ok ) // e.g. JS disabled + scheduledActions.removeRef( action ); + } + + if (action->singleShot) { + scheduledActions.removeRef(action); + } + + action->executing = false; + + if (!scheduledActions.containsRef(action)) + delete action; + else + action->nextTime = action->nextTime.addMSecs(action->interval); + } + + pausedTime += currentActual.msecsTo(DateTimeMS::now()); + + currentlyDispatching = false; + + // Work out when next event is to occur + setNextTimer(); +} + +DateTimeMS DateTimeMS::addMSecs(int s) const +{ + DateTimeMS c = *this; + c.mTime = mTime.addMSecs(s); + if (s > 0) + { + if (c.mTime < mTime) + c.mDate = mDate.addDays(1); + } + else + { + if (c.mTime > mTime) + c.mDate = mDate.addDays(-1); + } + return c; +} + +bool DateTimeMS::operator >(const DateTimeMS &other) const +{ + if (mDate > other.mDate) + return true; + + if (mDate < other.mDate) + return false; + + return mTime > other.mTime; +} + +bool DateTimeMS::operator >=(const DateTimeMS &other) const +{ + if (mDate > other.mDate) + return true; + + if (mDate < other.mDate) + return false; + + return mTime >= other.mTime; +} + +int DateTimeMS::msecsTo(const DateTimeMS &other) const +{ + int d = mDate.daysTo(other.mDate); + int ms = mTime.msecsTo(other.mTime); + return d*24*60*60*1000 + ms; +} + + +DateTimeMS DateTimeMS::now() +{ + DateTimeMS t; + QTime before = QTime::currentTime(); + t.mDate = QDate::currentDate(); + t.mTime = QTime::currentTime(); + if (t.mTime < before) + t.mDate = QDate::currentDate(); // prevent race condition in hacky way :) + return t; +} + +void WindowQObject::setNextTimer() +{ + if (currentlyDispatching) + return; // Will schedule at the end + + if (scheduledActions.isEmpty()) + return; + + QPtrListIterator<ScheduledAction> it(scheduledActions); + DateTimeMS nextTime = it.current()->nextTime; + for (++it; it.current(); ++it) + if (nextTime > it.current()->nextTime) + nextTime = it.current()->nextTime; + + DateTimeMS nextTimeActual = nextTime.addMSecs(pausedTime); + int nextInterval = DateTimeMS::now().msecsTo(nextTimeActual); + if (nextInterval < 0) + nextInterval = 0; + startTimer(nextInterval); +} + +void WindowQObject::timeoutClose() +{ + parent->closeNow(); +} + +Value FrameArray::get(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "FrameArray::get " << p.qstring() << " part=" << (void*)part << endl; +#endif + if (part.isNull()) + return Undefined(); + + QPtrList<KParts::ReadOnlyPart> frames = part->frames(); + unsigned int len = frames.count(); + if (p == lengthPropertyName) + return Number(len); + else if (p== "location") // non-standard property, but works in NS and IE + { + Object obj = Object::dynamicCast( Window::retrieve( part ) ); + if ( obj.isValid() ) + return obj.get( exec, "location" ); + return Undefined(); + } + + // check for the name or number + KParts::ReadOnlyPart *frame = part->findFramePart(p.qstring()); + if (!frame) { + bool ok; + unsigned int i = p.toArrayIndex(&ok); + if (ok && i < len) + frame = frames.at(i); + } + + // we are potentially fetching a reference to a another Window object here. + // i.e. we may be accessing objects from another interpreter instance. + // Therefore we have to be a bit careful with memory management. + if (frame) { + return Window::retrieve(frame); + } + + // Fun IE quirk: name lookup in there is actually done by document.all + // hence, it can find non-frame things (and even let them hide frame ones!) + // We don't quite do that, but do this as a fallback. + DOM::DocumentImpl* doc = static_cast<DOM::DocumentImpl*>(part->document().handle()); + if (doc) { + DOM::HTMLCollectionImpl docuAll(doc, DOM::HTMLCollectionImpl::DOC_ALL); + DOM::NodeImpl* node = docuAll.namedItem(p.string()); + if (node) { + if (node->id() == ID_FRAME || node->id() == ID_IFRAME) { + //Return the Window object. + KHTMLPart* part = static_cast<DOM::HTMLFrameElementImpl*>(node)->contentPart(); + if (part) + return Value(Window::retrieveWindow(part)); + else + return Undefined(); + } else { + //Just a regular node.. + return getDOMNode(exec, node); + } + } + } else { + kdWarning(6070) << "Missing own document in FrameArray::get()" << endl; + } + + return ObjectImp::get(exec, p); +} + +Value FrameArray::call(ExecState *exec, Object &/*thisObj*/, const List &args) +{ + //IE supports a subset of the get functionality as call... + //... basically, when the return is a window, it supports that, otherwise it + //errors out. We do a cheap-and-easy emulation of that, and just do the same + //thing as get does. + if (args.size() == 1) + return get(exec, Identifier(args[0].toString(exec))); + + return Undefined(); +} + + +////////////////////// Location Object //////////////////////// + +const ClassInfo Location::info = { "Location", 0, &LocationTable, 0 }; +/* +@begin LocationTable 11 + hash Location::Hash DontDelete + host Location::Host DontDelete + hostname Location::Hostname DontDelete + href Location::Href DontDelete + pathname Location::Pathname DontDelete + port Location::Port DontDelete + protocol Location::Protocol DontDelete + search Location::Search DontDelete + [[==]] Location::EqualEqual DontDelete|ReadOnly + assign Location::Assign DontDelete|Function 1 + toString Location::ToString DontDelete|Function 0 + replace Location::Replace DontDelete|Function 1 + reload Location::Reload DontDelete|Function 0 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(LocationFunc) +Location::Location(khtml::ChildFrame *f) : m_frame(f) +{ + //kdDebug(6070) << "Location::Location " << this << " m_part=" << (void*)m_part << endl; +} + +Location::~Location() +{ + //kdDebug(6070) << "Location::~Location " << this << " m_part=" << (void*)m_part << endl; +} + +KParts::ReadOnlyPart *Location::part() const { + return m_frame ? static_cast<KParts::ReadOnlyPart *>(m_frame->m_part) : 0L; +} + +Value Location::get(ExecState *exec, const Identifier &p) const +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Location::get " << p.qstring() << " m_part=" << (void*)m_frame->m_part << endl; +#endif + + if (m_frame.isNull() || m_frame->m_part.isNull()) + return Undefined(); + + const HashEntry *entry = Lookup::findEntry(&LocationTable, p); + + // properties that work on all Location objects + if ( entry && entry->value == Replace ) + return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); + + // XSS check + const Window* window = Window::retrieveWindow( m_frame->m_part ); + if ( !window || !window->isSafeScript(exec) ) + return Undefined(); + + KURL url = m_frame->m_part->url(); + if (entry) + switch (entry->value) { + case Hash: + return String( url.ref().isNull() ? QString("") : "#" + url.ref() ); + case Host: { + UString str = url.host(); + if (url.port()) + str += ":" + QString::number((int)url.port()); + return String(str); + // Note: this is the IE spec. The NS spec swaps the two, it says + // "The hostname property is the concatenation of the host and port properties, separated by a colon." + // Bleh. + } + case Hostname: + return String( url.host() ); + case Href: + if (url.isEmpty()) + return String("about:blank"); + else if (!url.hasPath()) + return String( url.prettyURL()+"/" ); + else + return String( url.prettyURL() ); + case Pathname: + if (url.isEmpty()) + return String(""); + return String( url.path().isEmpty() ? QString("/") : url.path() ); + case Port: + return String( url.port() ? QString::number((int)url.port()) : QString::fromLatin1("") ); + case Protocol: + return String( url.protocol()+":" ); + case Search: + return String( url.query() ); + case EqualEqual: // [[==]] + return String(toString(exec)); + case ToString: + return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); + } + // Look for overrides + ValueImp * val = ObjectImp::getDirect(p); + if (val) + return Value(val); + if (entry && (entry->attr & Function)) + return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr); + + return Undefined(); +} + +void Location::put(ExecState *exec, const Identifier &p, const Value &v, int attr) +{ +#ifdef KJS_VERBOSE + kdDebug(6070) << "Location::put " << p.qstring() << " m_part=" << (void*)m_frame->m_part << endl; +#endif + if (m_frame.isNull() || m_frame->m_part.isNull()) + return; + + const Window* window = Window::retrieveWindow( m_frame->m_part ); + if ( !window ) + return; + + KURL url = m_frame->m_part->url(); + + const HashEntry *entry = Lookup::findEntry(&LocationTable, p); + + if (entry) { + + // XSS check. Only new hrefs can be set from other sites + if (entry->value != Href && !window->isSafeScript(exec)) + return; + + QString str = v.toString(exec).qstring(); + switch (entry->value) { + case Href: { + KHTMLPart* p =::qt_cast<KHTMLPart*>(Window::retrieveActive(exec)->part()); + if ( p ) + url = p->htmlDocument().completeURL( str ).string(); + else + url = str; + break; + } + case Hash: + // when the hash is already the same ignore it + if (str == url.ref()) return; + url.setRef(str); + break; + case Host: { + QString host = str.left(str.find(":")); + QString port = str.mid(str.find(":")+1); + url.setHost(host); + url.setPort(port.toUInt()); + break; + } + case Hostname: + url.setHost(str); + break; + case Pathname: + url.setPath(str); + break; + case Port: + url.setPort(str.toUInt()); + break; + case Protocol: + url.setProtocol(str); + break; + case Search: + url.setQuery(str); + break; + } + } else { + ObjectImp::put(exec, p, v, attr); + return; + } + + Window::retrieveWindow(m_frame->m_part)->goURL(exec, url.url(), false /* don't lock history*/ ); +} + +Value Location::toPrimitive(ExecState *exec, Type) const +{ + if (m_frame) { + Window* window = Window::retrieveWindow( m_frame->m_part ); + if ( window && window->isSafeScript(exec) ) + return String(toString(exec)); + } + return Undefined(); +} + +UString Location::toString(ExecState *exec) const +{ + if (m_frame) { + Window* window = Window::retrieveWindow( m_frame->m_part ); + if ( window && window->isSafeScript(exec) ) + { + KURL url = m_frame->m_part->url(); + if (url.isEmpty()) + return "about:blank"; + else if (!url.hasPath()) + return url.prettyURL()+"/"; + else + return url.prettyURL(); + } + } + return ""; +} + +Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( Location, thisObj ); + Location *location = static_cast<Location *>(thisObj.imp()); + KParts::ReadOnlyPart *part = location->part(); + + if (!part) return Undefined(); + + Window* window = Window::retrieveWindow(part); + + if ( !window->isSafeScript(exec) && id != Location::Replace) + return Undefined(); + + switch (id) { + case Location::Assign: + case Location::Replace: + Window::retrieveWindow(part)->goURL(exec, args[0].toString(exec).qstring(), + id == Location::Replace); + break; + case Location::Reload: { + KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart *>(part); + if (khtmlpart) + khtmlpart->scheduleRedirection(-1, part->url().url(), true/*lock history*/); + else + part->openURL(part->url()); + break; + } + case Location::ToString: + return String(location->toString(exec)); + } + return Undefined(); +} + +////////////////////// External Object //////////////////////// + +const ClassInfo External::info = { "External", 0, 0, 0 }; +/* +@begin ExternalTable 4 + addFavorite External::AddFavorite DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(ExternalFunc) + +Value External::get(ExecState *exec, const Identifier &p) const +{ + return lookupGetFunction<ExternalFunc,ObjectImp>(exec,p,&ExternalTable,this); +} + +Value ExternalFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( External, thisObj ); + External *external = static_cast<External *>(thisObj.imp()); + + KHTMLPart *part = external->part; + if (!part) + return Undefined(); + + KHTMLView *widget = part->view(); + + switch (id) { + case External::AddFavorite: + { +#ifndef KONQ_EMBEDDED + if (!widget->dialogsAllowed()) + return Undefined(); + part->xmlDocImpl()->updateRendering(); + if (args.size() != 1 && args.size() != 2) + return Undefined(); + + QString url = args[0].toString(exec).qstring(); + QString title; + if (args.size() == 2) + title = args[1].toString(exec).qstring(); + + // AK - don't do anything yet, for the moment i + // just wanted the base js handling code in cvs + return Undefined(); + + QString question; + if ( title.isEmpty() ) + question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?") + .arg(url); + else + question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?") + .arg(url).arg(title); + + emit part->browserExtension()->requestFocus(part); + + QString caption; + if (!part->url().host().isEmpty()) + caption = part->url().host() + " - "; + caption += i18n("JavaScript Attempted Bookmark Insert"); + + if (KMessageBox::warningYesNo( + widget, question, caption, + i18n("Insert"), i18n("Disallow")) == KMessageBox::Yes) + { + KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager(); + mgr->addBookmarkDialog(url,title); + } +#else + return Undefined(); +#endif + break; + } + default: + return Undefined(); + } + + return Undefined(); +} + +////////////////////// History Object //////////////////////// + +const ClassInfo History::info = { "History", 0, 0, 0 }; +/* +@begin HistoryTable 4 + length History::Length DontDelete|ReadOnly + back History::Back DontDelete|Function 0 + forward History::Forward DontDelete|Function 0 + go History::Go DontDelete|Function 1 +@end +*/ +IMPLEMENT_PROTOFUNC_DOM(HistoryFunc) + +Value History::get(ExecState *exec, const Identifier &p) const +{ + return lookupGet<HistoryFunc,History,ObjectImp>(exec,p,&HistoryTable,this); +} + +Value History::getValueProperty(ExecState *, int token) const +{ + // if previous or next is implemented, make sure its not a major + // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/) + switch (token) { + case Length: + { + if ( !part ) + return Number( 0 ); + + KParts::BrowserExtension *ext = part->browserExtension(); + if ( !ext ) + return Number( 0 ); + + KParts::BrowserInterface *iface = ext->browserInterface(); + if ( !iface ) + return Number( 0 ); + + QVariant length = iface->property( "historyLength" ); + + if ( length.type() != QVariant::UInt ) + return Number( 0 ); + + return Number( length.toUInt() ); + } + default: + kdDebug(6070) << "WARNING: Unhandled token in History::getValueProperty : " << token << endl; + return Undefined(); + } +} + +Value HistoryFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + KJS_CHECK_THIS( History, thisObj ); + History *history = static_cast<History *>(thisObj.imp()); + + Value v = args[0]; + Number n; + if(v.isValid()) + n = v.toInteger(exec); + + int steps; + switch (id) { + case History::Back: + steps = -1; + break; + case History::Forward: + steps = 1; + break; + case History::Go: + steps = n.intValue(); + break; + default: + return Undefined(); + } + + // Special case for go(0) from a frame -> reload only the frame + // go(i!=0) from a frame navigates into the history of the frame only, + // in both IE and NS (but not in Mozilla).... we can't easily do that + // in Konqueror... + if (!steps) // add && history->part->parentPart() to get only frames, but doesn't matter + { + history->part->openURL( history->part->url() ); /// ## need args.reload=true? + } else + { + // Delay it. + // Testcase: history.back(); alert("hello"); + Window* window = Window::retrieveWindow( history->part ); + window->delayedGoHistory( steps ); + } + return Undefined(); +} + +///////////////////////////////////////////////////////////////////////////// + +#ifdef Q_WS_QWS + +const ClassInfo Konqueror::info = { "Konqueror", 0, 0, 0 }; + +bool Konqueror::hasProperty(ExecState *exec, const Identifier &p) const +{ + if ( p.qstring().startsWith( "goHistory" ) ) return false; + + return true; +} + +Value Konqueror::get(ExecState *exec, const Identifier &p) const +{ + if ( p == "goHistory" || part->url().protocol() != "http" || part->url().host() != "localhost" ) + return Undefined(); + + KParts::BrowserExtension *ext = part->browserExtension(); + if ( ext ) { + KParts::BrowserInterface *iface = ext->browserInterface(); + if ( iface ) { + QVariant prop = iface->property( p.qstring().latin1() ); + + if ( prop.isValid() ) { + switch( prop.type() ) { + case QVariant::Int: + return Number( prop.toInt() ); + case QVariant::String: + return String( prop.toString() ); + default: + break; + } + } + } + } + + return Value( new KonquerorFunc(exec, this, p.qstring().latin1() ) ); +} + +Value KonquerorFunc::tryCall(ExecState *exec, Object &, const List &args) +{ + KParts::BrowserExtension *ext = konqueror->part->browserExtension(); + + if (!ext) + return Undefined(); + + KParts::BrowserInterface *iface = ext->browserInterface(); + + if ( !iface ) + return Undefined(); + + QCString n = m_name.data(); + n += "()"; + iface->callMethod( n.data(), QVariant() ); + + return Undefined(); +} + +UString Konqueror::toString(ExecState *) const +{ + return UString("[object Konqueror]"); +} + +#endif +///////////////////////////////////////////////////////////////////////////// +} //namespace KJS + +#include "kjs_window.moc" diff --git a/khtml/ecma/kjs_window.h b/khtml/ecma/kjs_window.h new file mode 100644 index 000000000..1444110f4 --- /dev/null +++ b/khtml/ecma/kjs_window.h @@ -0,0 +1,309 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2003 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _KJS_WINDOW_H_ +#define _KJS_WINDOW_H_ + +#include <qobject.h> +#include <qguardedptr.h> +#include <qmap.h> +#include <qptrlist.h> +#include <qdatetime.h> + +#include "kjs_binding.h" +#include "kjs_views.h" + +class QTimer; +class KHTMLView; +class KHTMLPart; + +namespace KParts { + class ReadOnlyPart; +} + +namespace khtml { + class ChildFrame; +} + +namespace KJS { + + class WindowFunc; + class WindowQObject; + class Location; + class History; + class External; + class FrameArray; + class JSEventListener; + class JSLazyEventListener; + + class Screen : public ObjectImp { + public: + Screen(ExecState *exec); + enum { + Height, Width, ColorDepth, PixelDepth, AvailLeft, AvailTop, AvailHeight, + AvailWidth + }; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + private: + KHTMLView *view; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + }; + + class KDE_EXPORT Window : public ObjectImp { + friend QGuardedPtr<KHTMLPart> getInstance(); + friend class Location; + friend class WindowFunc; + friend class WindowQObject; + friend class ScheduledAction; + public: + Window(khtml::ChildFrame *p); + public: + ~Window(); + /** + * Returns and registers a window object. In case there's already a Window + * for the specified part p this will be returned in order to have unique + * bindings. + */ + static Value retrieve(KParts::ReadOnlyPart *p); + /** + * Returns the Window object for a given part + */ + static Window *retrieveWindow(KParts::ReadOnlyPart *p); + /** + * returns a pointer to the Window object this javascript interpreting instance + * was called from. + */ + static Window *retrieveActive(ExecState *exec); + KParts::ReadOnlyPart *part() const; + virtual void mark(); + virtual bool hasProperty(ExecState *exec, const Identifier &p) const; + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr = None); + virtual bool toBoolean(ExecState *exec) const; + virtual DOM::AbstractView toAbstractView() const; + void scheduleClose(); + void closeNow(); + void delayedGoHistory(int steps); + void goHistory(int steps); + void goURL(ExecState* exec, const QString& url, bool lockHistory); + Value openWindow(ExecState *exec, const List &args); + Value executeOpenWindow(ExecState *exec, const KURL& url, const QString& frameName, const QString& features); + void resizeTo(QWidget* tl, int width, int height); + void afterScriptExecution(); + bool isSafeScript(ExecState *exec) const { + KParts::ReadOnlyPart *activePart = static_cast<KJS::ScriptInterpreter *>( exec->interpreter() )->part(); + if ( activePart == part() ) return true; + return checkIsSafeScript( activePart ); + } + Location *location() const; + ObjectImp* frames( ExecState* exec ) const; + JSEventListener *getJSEventListener(const Value &val, bool html = false); + JSLazyEventListener *getJSLazyEventListener(const QString &code, const QString &name, DOM::NodeImpl* node); + void clear( ExecState *exec ); + virtual UString toString(ExecState *exec) const; + + // Set the current "event" object + void setCurrentEvent( DOM::Event *evt ); + + QPtrDict<JSEventListener> jsEventListeners; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Closed, Crypto, DefaultStatus, Status, Document, Node, EventCtor, Range, + NodeFilter, DOMException, CSSRule, Frames, _History, _External, Event, InnerHeight, + InnerWidth, Length, _Location, Navigate, Name, _Navigator, _Konqueror, ClientInformation, + OffscreenBuffering, Opener, OuterHeight, OuterWidth, PageXOffset, PageYOffset, + Parent, Personalbar, ScreenX, ScreenY, Scrollbars, Scroll, ScrollBy, + ScreenTop, ScreenLeft, AToB, BToA, FrameElement, GetComputedStyle, + ScrollTo, ScrollX, ScrollY, MoveBy, MoveTo, ResizeBy, ResizeTo, Self, _Window, Top, _Screen, + Image, Option, Alert, Confirm, Prompt, Open, SetTimeout, ClearTimeout, + XMLHttpRequest, XMLSerializer, DOMParser, + Focus, Blur, Close, SetInterval, ClearInterval, CaptureEvents, ReleaseEvents, + Print, AddEventListener, RemoveEventListener, SideBar, + ValueOf, ToString, + Onabort, Onblur, + Onchange, Onclick, Ondblclick, Ondragdrop, Onerror, Onfocus, + Onkeydown, Onkeypress, Onkeyup, Onload, Onmousedown, Onmousemove, + Onmouseout, Onmouseover, Onmouseup, Onmove, Onreset, Onresize, + Onselect, Onsubmit, Onunload, + MutationEventCtor, KeyboardEventCtor, EventExceptionCtor, + ElementCtor, DocumentCtor, HTMLDocumentCtor, + HTMLElementCtor, HTMLHtmlElementCtor, HTMLHeadElementCtor, HTMLLinkElementCtor, + HTMLTitleElementCtor, HTMLMetaElementCtor, HTMLBaseElementCtor, HTMLIsIndexElementCtor, + HTMLStyleElementCtor, HTMLBodyElementCtor, HTMLFormElementCtor, HTMLSelectElementCtor, + HTMLOptGroupElementCtor, HTMLOptionElementCtor, HTMLInputElementCtor, HTMLTextAreaElementCtor, + HTMLButtonElementCtor, HTMLLabelElementCtor, HTMLFieldSetElementCtor, HTMLLegendElementCtor, + HTMLUListElementCtor, HTMLOListElementCtor, HTMLDListElementCtor, HTMLDirectoryElementCtor, + HTMLMenuElementCtor, HTMLLIElementCtor, HTMLDivElementCtor, HTMLParagraphElementCtor, + HTMLHeadingElementCtor, HTMLBlockQuoteElementCtor, HTMLQuoteElementCtor, HTMLPreElementCtor, + HTMLBRElementCtor, HTMLBaseFontElementCtor, HTMLFontElementCtor, HTMLHRElementCtor, HTMLModElementCtor, + HTMLAnchorElementCtor, HTMLImageElementCtor, HTMLObjectElementCtor, HTMLParamElementCtor, + HTMLAppletElementCtor, HTMLMapElementCtor, HTMLAreaElementCtor, HTMLScriptElementCtor, + HTMLTableElementCtor, HTMLTableCaptionElementCtor, HTMLTableColElementCtor, + HTMLTableSectionElementCtor, HTMLTableRowElementCtor, HTMLTableCellElementCtor, + HTMLFrameSetElementCtor, HTMLLayerElementCtor, HTMLFrameElementCtor, HTMLIFrameElementCtor, + CSSStyleDeclarationCtor}; + WindowQObject *winq; + + void forgetSuppressedWindows(); + void showSuppressedWindows(); + + protected: + enum DelayedActionId { NullAction, DelayedClose, DelayedGoHistory }; + + Value getListener(ExecState *exec, int eventId) const; + void setListener(ExecState *exec, int eventId, Value func); + private: + struct DelayedAction; + friend struct DelayedAction; + + bool checkIsSafeScript( KParts::ReadOnlyPart* activePart ) const; + + QGuardedPtr<khtml::ChildFrame> m_frame; + Screen *screen; + History *history; + External *external; + FrameArray *m_frames; + Location *loc; + DOM::Event *m_evt; + + struct DelayedAction { + DelayedAction() : actionId(NullAction) {} // for QValueList + DelayedAction( DelayedActionId id, QVariant p = QVariant() ) : actionId(id), param(p) {} + DelayedActionId actionId; + QVariant param; // just in case + }; + QValueList<DelayedAction> m_delayed; + + struct SuppressedWindowInfo { + SuppressedWindowInfo() {} // for QValueList + SuppressedWindowInfo( KURL u, QString fr, QString fe ) : url(u), frameName(fr), features(fe) {} + KURL url; + QString frameName; + QString features; + }; + QValueList<SuppressedWindowInfo> m_suppressedWindowInfo; + }; + + /** + * like QDateTime, but properly handles milliseconds + */ + class DateTimeMS + { + QDate mDate; + QTime mTime; + public: + DateTimeMS addMSecs(int s) const; + bool operator >(const DateTimeMS &other) const; + bool operator >=(const DateTimeMS &other) const; + + int msecsTo(const DateTimeMS &other) const; + + static DateTimeMS now(); + }; + + /** + * An action (either function or string) to be executed after a specified + * time interval, either once or repeatedly. Used for window.setTimeout() + * and window.setInterval() + */ + class ScheduledAction { + public: + ScheduledAction(Object _func, List _args, DateTimeMS _nextTime, int _interval, bool _singleShot, int _timerId); + ScheduledAction(QString _code, DateTimeMS _nextTime, int _interval, bool _singleShot, int _timerId); + ~ScheduledAction(); + bool execute(Window *window); + void mark(); + + ObjectImp *func; + List args; + QString code; + bool isFunction; + bool singleShot; + + DateTimeMS nextTime; + int interval; + bool executing; + int timerId; + }; + + class KDE_EXPORT WindowQObject : public QObject { + Q_OBJECT + public: + WindowQObject(Window *w); + ~WindowQObject(); + int installTimeout(const Identifier &handler, int t, bool singleShot); + int installTimeout(const Value &func, List args, int t, bool singleShot); + void clearTimeout(int timerId); + void mark(); + bool hasTimers() const; + public slots: + void timeoutClose(); + protected slots: + void parentDestroyed(); + protected: + void timerEvent(QTimerEvent *e); + void setNextTimer(); + private: + Window *parent; + QPtrList<ScheduledAction> scheduledActions; + int pausedTime; + int lastTimerId; + bool currentlyDispatching; + }; + + class Location : public ObjectImp { + public: + ~Location(); + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr = None); + virtual Value toPrimitive(ExecState *exec, Type preferred) const; + virtual UString toString(ExecState *exec) const; + enum { Hash, Href, Hostname, Host, Pathname, Port, Protocol, Search, EqualEqual, + Assign, Replace, Reload, ToString }; + KParts::ReadOnlyPart *part() const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + private: + friend class Window; + Location(khtml::ChildFrame *f); + QGuardedPtr<khtml::ChildFrame> m_frame; + }; + +#ifdef Q_WS_QWS + class Konqueror : public ObjectImp { + friend class KonquerorFunc; + public: + Konqueror(KHTMLPart *p) : part(p) { } + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual bool hasProperty(ExecState *exec, const Identifier &p) const; + virtual UString toString(ExecState *exec) const; + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + private: + KHTMLPart *part; + }; +#endif + +} // namespace + +#endif diff --git a/khtml/ecma/testecma.cpp b/khtml/ecma/testecma.cpp new file mode 100644 index 000000000..44cd7ecb0 --- /dev/null +++ b/khtml/ecma/testecma.cpp @@ -0,0 +1,67 @@ +/* + * This file is part of the KDE libraries + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * An interactive interpreter to test the ECMA Script language bindings + * for the DOM of KHTML. + * The 'document' property is preset to an instance of Document and serves + * as an entrypoint. + * + * Example session: + * + * KJS> text = document.createTextNode('foo'); + * KJS> document.appendChild(text); + * KJS> debug(document.firstChild.nodeValue); + * ---> foo + */ + +#include <stdio.h> +#include <kjs/object.h> +#include <kjs/interpreter.h> +#include "dom/dom_doc.h" +#include "dom/dom_string.h" +#include "ecma/kjs_dom.h" + + +using namespace KJS; + +int main(int, char **) +{ + KJScript kjs; + kjs.enableDebug(); + DOM::Document doc; + + DOMDocument *dd = new DOMDocument(&doc); + Global::current().put("document", KJSO(dd)); + + printf("Entering interactive mode.\n" + "You may access the DOM via the 'document' property.\n" + "Use debug() to print to the console. Press C-d or C-c to exit.\n\n"); + + char buffer[1000]; + FILE *in = fdopen(0, "r"); + + while (1) { + printf("KJS> "); + if (!fgets(buffer, 999, in)) + break; + kjs.evaluate(buffer); + } + printf("\n"); +} diff --git a/khtml/ecma/xmlhttprequest.cpp b/khtml/ecma/xmlhttprequest.cpp new file mode 100644 index 000000000..de77f3d7e --- /dev/null +++ b/khtml/ecma/xmlhttprequest.cpp @@ -0,0 +1,810 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2003 Apple Computer, Inc. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "xmlhttprequest.h" +#include "xmlhttprequest.lut.h" +#include "kjs_window.h" +#include "kjs_events.h" + +#include "dom/dom_doc.h" +#include "dom/dom_exception.h" +#include "dom/dom_string.h" +#include "misc/loader.h" +#include "html/html_documentimpl.h" +#include "xml/dom2_eventsimpl.h" + +#include "khtml_part.h" +#include "khtmlview.h" + +#include <kio/scheduler.h> +#include <kio/job.h> +#include <qobject.h> +#include <kdebug.h> + +#ifdef APPLE_CHANGES +#include "KWQLoader.h" +#else +#include <kio/netaccess.h> +using KIO::NetAccess; +#endif + +#define BANNED_HTTP_HEADERS "authorization,proxy-authorization,"\ + "content-length,host,connect,copy,move,"\ + "delete,head,trace,put,propfind,proppatch,"\ + "mkcol,lock,unlock,options,via,"\ + "accept-charset,accept-encoding,expect,date,"\ + "keep-alive,te,trailer,"\ + "transfer-encoding,upgrade" + +using khtml::Decoder; + +namespace KJS { + +////////////////////// XMLHttpRequest Object //////////////////////// + +/* Source for XMLHttpRequestProtoTable. +@begin XMLHttpRequestProtoTable 7 + abort XMLHttpRequest::Abort DontDelete|Function 0 + getAllResponseHeaders XMLHttpRequest::GetAllResponseHeaders DontDelete|Function 0 + getResponseHeader XMLHttpRequest::GetResponseHeader DontDelete|Function 1 + open XMLHttpRequest::Open DontDelete|Function 5 + overrideMimeType XMLHttpRequest::OverrideMIMEType DontDelete|Function 1 + send XMLHttpRequest::Send DontDelete|Function 1 + setRequestHeader XMLHttpRequest::SetRequestHeader DontDelete|Function 2 +@end +*/ +KJS_DEFINE_PROTOTYPE(XMLHttpRequestProto) +IMPLEMENT_PROTOFUNC_DOM(XMLHttpRequestProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("XMLHttpRequest", XMLHttpRequestProto,XMLHttpRequestProtoFunc) + + +XMLHttpRequestQObject::XMLHttpRequestQObject(XMLHttpRequest *_jsObject) +{ + jsObject = _jsObject; +} + +#ifdef APPLE_CHANGES +void XMLHttpRequestQObject::slotData( KIO::Job* job, const char *data, int size ) +{ + jsObject->slotData(job, data, size); +} +#else +void XMLHttpRequestQObject::slotData( KIO::Job* job, const QByteArray &data ) +{ + jsObject->slotData(job, data); +} +#endif + +void XMLHttpRequestQObject::slotFinished( KIO::Job* job ) +{ + jsObject->slotFinished(job); +} + +void XMLHttpRequestQObject::slotRedirection( KIO::Job* job, const KURL& url) +{ + jsObject->slotRedirection( job, url ); +} + +XMLHttpRequestConstructorImp::XMLHttpRequestConstructorImp(ExecState *, const DOM::Document &d) + : ObjectImp(), doc(d) +{ +} + +bool XMLHttpRequestConstructorImp::implementsConstruct() const +{ + return true; +} + +Object XMLHttpRequestConstructorImp::construct(ExecState *exec, const List &) +{ + return Object(new XMLHttpRequest(exec, doc)); +} + +const ClassInfo XMLHttpRequest::info = { "XMLHttpRequest", 0, &XMLHttpRequestTable, 0 }; + + +/* Source for XMLHttpRequestTable. +@begin XMLHttpRequestTable 7 + readyState XMLHttpRequest::ReadyState DontDelete|ReadOnly + responseText XMLHttpRequest::ResponseText DontDelete|ReadOnly + responseXML XMLHttpRequest::ResponseXML DontDelete|ReadOnly + status XMLHttpRequest::Status DontDelete|ReadOnly + statusText XMLHttpRequest::StatusText DontDelete|ReadOnly + onreadystatechange XMLHttpRequest::Onreadystatechange DontDelete + onload XMLHttpRequest::Onload DontDelete +@end +*/ + +Value XMLHttpRequest::tryGet(ExecState *exec, const Identifier &propertyName) const +{ + return DOMObjectLookupGetValue<XMLHttpRequest,DOMObject>(exec, propertyName, &XMLHttpRequestTable, this); +} + +Value XMLHttpRequest::getValueProperty(ExecState *exec, int token) const +{ + switch (token) { + case ReadyState: + return Number(state); + case ResponseText: + return getString(DOM::DOMString(response)); + case ResponseXML: + if (state != Completed) { + return Null(); + } + if (!createdDocument) { + QString mimeType = "text/xml"; + + if (!m_mimeTypeOverride.isEmpty()) { + mimeType = m_mimeTypeOverride; + } else { + Value header = getResponseHeader("Content-Type"); + if (header.type() != UndefinedType) { + mimeType = QStringList::split(";", header.toString(exec).qstring())[0].stripWhiteSpace(); + } + } + + if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "application/xhtml+xml") { + responseXML = DOM::Document(doc->implementation()->createDocument()); + + DOM::DocumentImpl *docImpl = static_cast<DOM::DocumentImpl *>(responseXML.handle()); + + docImpl->open(); + docImpl->write(response); + docImpl->finishParsing(); + docImpl->close(); + + typeIsXML = true; + } else { + typeIsXML = false; + } + createdDocument = true; + } + + if (!typeIsXML) { + return Undefined(); + } + + return getDOMNode(exec,responseXML); + case Status: + return getStatus(); + case StatusText: + return getStatusText(); + case Onreadystatechange: + if (onReadyStateChangeListener && onReadyStateChangeListener->listenerObjImp()) { + return onReadyStateChangeListener->listenerObj(); + } else { + return Null(); + } + case Onload: + if (onLoadListener && onLoadListener->listenerObjImp()) { + return onLoadListener->listenerObj(); + } else { + return Null(); + } + default: + kdWarning() << "XMLHttpRequest::getValueProperty unhandled token " << token << endl; + return Value(); + } +} + +void XMLHttpRequest::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr) +{ + DOMObjectLookupPut<XMLHttpRequest,DOMObject>(exec, propertyName, value, attr, &XMLHttpRequestTable, this ); +} + +void XMLHttpRequest::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/) +{ + JSEventListener* newListener; + switch(token) { + case Onreadystatechange: + newListener = Window::retrieveActive(exec)->getJSEventListener(value, true); + if (newListener != onReadyStateChangeListener) { + if (onReadyStateChangeListener) onReadyStateChangeListener->deref(); + onReadyStateChangeListener = newListener; + if (onReadyStateChangeListener) onReadyStateChangeListener->ref(); + } + break; + case Onload: + newListener = Window::retrieveActive(exec)->getJSEventListener(value, true); + if (newListener != onLoadListener) { + if (onLoadListener) onLoadListener->deref(); + onLoadListener = newListener; + if (onLoadListener) onLoadListener->ref(); + } + break; + default: + kdWarning() << "XMLHttpRequest::putValue unhandled token " << token << endl; + } +} + +XMLHttpRequest::XMLHttpRequest(ExecState *exec, const DOM::Document &d) + : DOMObject(XMLHttpRequestProto::self(exec)), + qObject(new XMLHttpRequestQObject(this)), + doc(static_cast<DOM::DocumentImpl*>(d.handle())), + async(true), + contentType(QString::null), + job(0), + state(Uninitialized), + onReadyStateChangeListener(0), + onLoadListener(0), + decoder(0), + createdDocument(false), + aborted(false) +{ +} + +XMLHttpRequest::~XMLHttpRequest() +{ + if (onReadyStateChangeListener) + onReadyStateChangeListener->deref(); + if (onLoadListener) + onLoadListener->deref(); + delete qObject; + qObject = 0; + delete decoder; + decoder = 0; +} + +void XMLHttpRequest::changeState(XMLHttpRequestState newState) +{ + if (state != newState) { + state = newState; + + ref(); + + if (onReadyStateChangeListener != 0 && doc->view() && doc->view()->part()) { + DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents"); + ev.initEvent("readystatechange", true, true); + onReadyStateChangeListener->handleEvent(ev); + } + + if (state == Completed && onLoadListener != 0 && doc->view() && doc->view()->part()) { + DOM::Event ev = doc->view()->part()->document().createEvent("HTMLEvents"); + ev.initEvent("load", true, true); + onLoadListener->handleEvent(ev); + } + + deref(); + } +} + +bool XMLHttpRequest::urlMatchesDocumentDomain(const KURL& _url) const +{ + // No need to do work if _url is not valid... + if (!_url.isValid()) + return false; + + KURL documentURL(doc->URL()); + + // a local file can load anything + if (documentURL.protocol().lower() == "file") { + return true; + } + + // but a remote document can only load from the same port on the server + if (documentURL.protocol().lower() == _url.protocol().lower() && + documentURL.host().lower() == _url.host().lower() && + documentURL.port() == _url.port()) { + return true; + } + + return false; +} + +void XMLHttpRequest::open(const QString& _method, const KURL& _url, bool _async) +{ + abort(); + aborted = false; + + // clear stuff from possible previous load + requestHeaders.clear(); + responseHeaders = QString(); + response = QString(); + createdDocument = false; + responseXML = DOM::Document(); + + changeState(Uninitialized); + + if (aborted) { + return; + } + + if (!urlMatchesDocumentDomain(_url)) { + return; + } + + + method = _method.lower(); + url = _url; + async = _async; + + changeState(Loading); +} + +void XMLHttpRequest::send(const QString& _body) +{ + aborted = false; + + if (method == "post") { + QString protocol = url.protocol().lower(); + + // Abondon the request when the protocol is other than "http", + // instead of blindly changing it to a "get" request. + if (!protocol.startsWith("http") && !protocol.startsWith("webdav")) + { + abort(); + return; + } + + // FIXME: determine post encoding correctly by looking in headers + // for charset. + QByteArray buf; + QCString str = _body.utf8(); + buf.duplicate(str.data(), str.size() - 1); + + job = KIO::http_post( url, buf, false ); + if(contentType.isNull()) + job->addMetaData( "content-type", "Content-type: text/plain" ); + else + job->addMetaData( "content-type", contentType ); + } + else { + job = KIO::get( url, false, false ); + } + + if (!requestHeaders.isEmpty()) { + QString rh; + QMap<QString, QString>::ConstIterator begin = requestHeaders.begin(); + QMap<QString, QString>::ConstIterator end = requestHeaders.end(); + for (QMap<QString, QString>::ConstIterator i = begin; i != end; ++i) { + QString key = i.key(); + QString value = i.data(); + if (key == "accept") { + // The HTTP KIO slave supports an override this way + job->addMetaData("accept", value); + } else { + if (i != begin) + rh += "\r\n"; + rh += key + ": " + value; + } + } + + job->addMetaData("customHTTPHeader", rh); + } + + job->addMetaData("PropagateHttpHeader", "true"); + + // Set the default referrer if one is not already supplied + // through setRequestHeader. NOTE: the user can still disable + // this feature at the protocol level (kio_http). + // ### does find() ever succeed? the headers are stored in lower case! + if (requestHeaders.find("Referer") == requestHeaders.end()) { + KURL documentURL(doc->URL()); + documentURL.setPass(QString::null); + documentURL.setUser(QString::null); + job->addMetaData("referrer", documentURL.url()); + // kdDebug() << "Adding referrer: " << documentURL << endl; + } + + if (!async) { + QByteArray data; + KURL finalURL; + QString headers; + +#ifdef APPLE_CHANGES + data = KWQServeSynchronousRequest(khtml::Cache::loader(), doc->docLoader(), job, finalURL, headers); +#else + QMap<QString, QString> metaData; + if ( NetAccess::synchronousRun( job, 0, &data, &finalURL, &metaData ) ) { + headers = metaData[ "HTTP-Headers" ]; + } +#endif + job = 0; + processSyncLoadResults(data, finalURL, headers); + return; + } + + qObject->connect( job, SIGNAL( result( KIO::Job* ) ), + SLOT( slotFinished( KIO::Job* ) ) ); +#ifdef APPLE_CHANGES + qObject->connect( job, SIGNAL( data( KIO::Job*, const char*, int ) ), + SLOT( slotData( KIO::Job*, const char*, int ) ) ); +#else + qObject->connect( job, SIGNAL( data( KIO::Job*, const QByteArray& ) ), + SLOT( slotData( KIO::Job*, const QByteArray& ) ) ); +#endif + qObject->connect( job, SIGNAL(redirection(KIO::Job*, const KURL& ) ), + SLOT( slotRedirection(KIO::Job*, const KURL&) ) ); + +#ifdef APPLE_CHANGES + KWQServeRequest(khtml::Cache::loader(), doc->docLoader(), job); +#else + KIO::Scheduler::scheduleJob( job ); +#endif +} + +void XMLHttpRequest::abort() +{ + if (job) { + job->kill(); + job = 0; + } + delete decoder; + decoder = 0; + aborted = true; +} + +void XMLHttpRequest::overrideMIMEType(const QString& override) +{ + m_mimeTypeOverride = override; +} + +void XMLHttpRequest::setRequestHeader(const QString& _name, const QString &value) +{ + QString name = _name.lower().stripWhiteSpace(); + + // Content-type needs to be set seperately from the other headers + if(name == "content-type") { + contentType = "Content-type: " + value; + return; + } + + // Sanitize the referrer header to protect against spoofing... + if(name == "referer") { + KURL referrerURL(value); + if (urlMatchesDocumentDomain(referrerURL)) + requestHeaders[name] = referrerURL.url(); + return; + } + + // Sanitize the request headers below and handle them as if they are + // calls to open. Otherwise, we will end up ignoring them all together! + // TODO: Do something about "put" which kio_http sort of supports and + // the webDAV headers such as PROPFIND etc... + if (name == "get" || name == "post") { + KURL reqURL (doc->URL(), value.stripWhiteSpace()); + open(name, reqURL, async); + return; + } + + // Reject all banned headers. See BANNED_HTTP_HEADERS above. + // kdDebug() << "Banned HTTP Headers: " << BANNED_HTTP_HEADERS << endl; + QStringList bannedHeaders = QStringList::split(',', + QString::fromLatin1(BANNED_HTTP_HEADERS)); + + if (bannedHeaders.contains(name)) + return; // Denied + + requestHeaders[name] = value.stripWhiteSpace(); +} + +Value XMLHttpRequest::getAllResponseHeaders() const +{ + if (responseHeaders.isEmpty()) { + return Undefined(); + } + + int endOfLine = responseHeaders.find("\n"); + + if (endOfLine == -1) { + return Undefined(); + } + + return String(responseHeaders.mid(endOfLine + 1) + "\n"); +} + +Value XMLHttpRequest::getResponseHeader(const QString& name) const +{ + if (responseHeaders.isEmpty()) { + return Undefined(); + } + + QRegExp headerLinePattern(name + ":", false); + + int matchLength; + int headerLinePos = headerLinePattern.search(responseHeaders, 0); + matchLength = headerLinePattern.matchedLength(); + while (headerLinePos != -1) { + if (headerLinePos == 0 || responseHeaders[headerLinePos-1] == '\n') { + break; + } + + headerLinePos = headerLinePattern.search(responseHeaders, headerLinePos + 1); + matchLength = headerLinePattern.matchedLength(); + } + + + if (headerLinePos == -1) { + return Undefined(); + } + + int endOfLine = responseHeaders.find("\n", headerLinePos + matchLength); + + return String(responseHeaders.mid(headerLinePos + matchLength, endOfLine - (headerLinePos + matchLength)).stripWhiteSpace()); +} + +static Value httpStatus(const QString& response, bool textStatus = false) +{ + if (response.isEmpty()) { + return Undefined(); + } + + int endOfLine = response.find("\n"); + QString firstLine = (endOfLine == -1) ? response : response.left(endOfLine); + int codeStart = firstLine.find(" "); + int codeEnd = firstLine.find(" ", codeStart + 1); + + if (codeStart == -1 || codeEnd == -1) { + return Undefined(); + } + + if (textStatus) { + QString statusText = firstLine.mid(codeEnd + 1, endOfLine - (codeEnd + 1)).stripWhiteSpace(); + return String(statusText); + } + + QString number = firstLine.mid(codeStart + 1, codeEnd - (codeStart + 1)); + + bool ok = false; + int code = number.toInt(&ok); + if (!ok) { + return Undefined(); + } + + return Number(code); +} + +Value XMLHttpRequest::getStatus() const +{ + return httpStatus(responseHeaders); +} + +Value XMLHttpRequest::getStatusText() const +{ + return httpStatus(responseHeaders, true); +} + +void XMLHttpRequest::processSyncLoadResults(const QByteArray &data, const KURL &finalURL, const QString &headers) +{ + if (!urlMatchesDocumentDomain(finalURL)) { + abort(); + return; + } + + responseHeaders = headers; + changeState(Loaded); + if (aborted) { + return; + } + +#ifdef APPLE_CHANGES + const char *bytes = (const char *)data.data(); + int len = (int)data.size(); + + slotData(0, bytes, len); +#else + slotData(0, data); +#endif + + if (aborted) { + return; + } + + slotFinished(0); +} + +void XMLHttpRequest::slotFinished(KIO::Job *) +{ + if (decoder) { + response += decoder->flush(); + } + + // make sure to forget about the job before emitting completed, + // since changeState triggers JS code, which might e.g. call abort. + job = 0; + changeState(Completed); + + delete decoder; + decoder = 0; +} + +void XMLHttpRequest::slotRedirection(KIO::Job*, const KURL& url) +{ + if (!urlMatchesDocumentDomain(url)) { + abort(); + } +} + +#ifdef APPLE_CHANGES +void XMLHttpRequest::slotData( KIO::Job*, const char *data, int len ) +#else +void XMLHttpRequest::slotData(KIO::Job*, const QByteArray &_data) +#endif +{ + if (state < Loaded ) { + responseHeaders = job->queryMetaData("HTTP-Headers"); + + // NOTE: Replace a 304 response with a 200! Both IE and Mozilla do this. + // Problem first reported through bug# 110272. + int codeStart = responseHeaders.find("304"); + if ( codeStart != -1) { + int codeEnd = responseHeaders.find("\n", codeStart+3); + if (codeEnd != -1) + responseHeaders.replace(codeStart, (codeEnd-codeStart), "200 OK"); + } + + changeState(Loaded); + } + +#ifndef APPLE_CHANGES + const char *data = (const char *)_data.data(); + int len = (int)_data.size(); +#endif + + if ( decoder == NULL ) { + int pos = responseHeaders.find("content-type:", 0, false); + + if ( pos > -1 ) { + pos += 13; + int index = responseHeaders.find('\n', pos); + QString type = responseHeaders.mid(pos, (index-pos)); + index = type.find (';'); + if (index > -1) + encoding = type.mid( index+1 ).remove(QRegExp("charset[ ]*=[ ]*", false)).stripWhiteSpace(); + } + + decoder = new Decoder; + if (!encoding.isNull()) + decoder->setEncoding(encoding.latin1(), Decoder::EncodingFromHTTPHeader); + else { + // Per section 2 of W3C working draft spec, fall back to "UTF-8". + decoder->setEncoding("UTF-8", Decoder::DefaultEncoding); + } + } + if (len == 0) + return; + + if (len == -1) + len = strlen(data); + + QString decoded = decoder->decode(data, len); + + response += decoded; + + if (!aborted) { + changeState(Interactive); + } +} + +Value XMLHttpRequestProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + if (!thisObj.inherits(&XMLHttpRequest::info)) { + Object err = Error::create(exec,TypeError); + exec->setException(err); + return err; + } + + XMLHttpRequest *request = static_cast<XMLHttpRequest *>(thisObj.imp()); + switch (id) { + case XMLHttpRequest::Abort: + request->abort(); + return Undefined(); + case XMLHttpRequest::GetAllResponseHeaders: + if (args.size() != 0) { + return Undefined(); + } + + return request->getAllResponseHeaders(); + case XMLHttpRequest::GetResponseHeader: + if (args.size() != 1) { + return Undefined(); + } + + return request->getResponseHeader(args[0].toString(exec).qstring()); + case XMLHttpRequest::Open: + { + if (args.size() < 2 || args.size() > 5) { + return Undefined(); + } + + QString method = args[0].toString(exec).qstring(); + KHTMLPart *part = ::qt_cast<KHTMLPart *>(Window::retrieveActive(exec)->part()); + if (!part) + return Undefined(); + KURL url = KURL(part->document().completeURL(args[1].toString(exec).qstring()).string()); + + bool async = true; + if (args.size() >= 3) { + async = args[2].toBoolean(exec); + } + + if (args.size() >= 4) { + url.setUser(args[3].toString(exec).qstring()); + } + + if (args.size() >= 5) { + url.setPass(args[4].toString(exec).qstring()); + } + + request->open(method, url, async); + + return Undefined(); + } + case XMLHttpRequest::Send: + { + if (args.size() > 1) { + return Undefined(); + } + + if (request->state != Loading) { + return Undefined(); + } + + QString body; + if (args.size() >= 1) { + Object obj = Object::dynamicCast(args[0]); + if (obj.isValid() && obj.inherits(&DOMDocument::info)) { + DOM::Node docNode = static_cast<KJS::DOMDocument *>(obj.imp())->toNode(); + DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(docNode.handle()); + + try { + body = doc->toString().string(); + // FIXME: also need to set content type, including encoding! + + } catch(DOM::DOMException& e) { + Object err = Error::create(exec, GeneralError, "Exception serializing document"); + exec->setException(err); + } + } else { + body = args[0].toString(exec).qstring(); + } + } + + request->send(body); + + return Undefined(); + } + case XMLHttpRequest::SetRequestHeader: + if (args.size() != 2) { + return Undefined(); + } + + request->setRequestHeader(args[0].toString(exec).qstring(), args[1].toString(exec).qstring()); + + return Undefined(); + + case XMLHttpRequest::OverrideMIMEType: + if (args.size() < 1) { + Object err = Error::create(exec, SyntaxError, "Not enough arguments"); + exec->setException(err); + return err; + } + + request->overrideMIMEType(args[0].toString(exec).qstring()); + return Undefined(); + } + + return Undefined(); +} + +} // end namespace + + +#include "xmlhttprequest.moc" diff --git a/khtml/ecma/xmlhttprequest.h b/khtml/ecma/xmlhttprequest.h new file mode 100644 index 000000000..49582a905 --- /dev/null +++ b/khtml/ecma/xmlhttprequest.h @@ -0,0 +1,142 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2003 Apple Computer, Inc. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _XMLHTTPREQUEST_H_ +#define _XMLHTTPREQUEST_H_ + +#include "ecma/kjs_binding.h" +#include "ecma/kjs_dom.h" +#include "misc/decoder.h" +#include "kio/jobclasses.h" + +namespace KJS { + + class JSEventListener; + class XMLHttpRequestQObject; + + // these exact numeric values are important because JS expects them + enum XMLHttpRequestState { + Uninitialized = 0, + Loading = 1, + Loaded = 2, + Interactive = 3, + Completed = 4 + }; + + class XMLHttpRequestConstructorImp : public ObjectImp { + public: + XMLHttpRequestConstructorImp(ExecState *exec, const DOM::Document &d); + virtual bool implementsConstruct() const; + virtual Object construct(ExecState *exec, const List &args); + private: + DOM::Document doc; + }; + + class XMLHttpRequest : public DOMObject { + public: + XMLHttpRequest(ExecState *, const DOM::Document &d); + ~XMLHttpRequest(); + virtual Value tryGet(ExecState *exec, const Identifier &propertyName) const; + Value getValueProperty(ExecState *exec, int token) const; + virtual void tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr = None); + void putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/); + virtual bool toBoolean(ExecState *) const { return true; } + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { Onload, Onreadystatechange, ReadyState, ResponseText, ResponseXML, Status, StatusText, Abort, + GetAllResponseHeaders, GetResponseHeader, Open, Send, SetRequestHeader, + OverrideMIMEType }; + + private: + friend class XMLHttpRequestProtoFunc; + friend class XMLHttpRequestQObject; + + Value getStatusText() const; + Value getStatus() const; + bool urlMatchesDocumentDomain(const KURL&) const; + + XMLHttpRequestQObject *qObject; + +#ifdef APPLE_CHANGES + void slotData( KIO::Job* job, const char *data, int size ); +#else + void slotData( KIO::Job* job, const QByteArray &data ); +#endif + void slotFinished( KIO::Job* ); + void slotRedirection( KIO::Job*, const KURL& ); + + void processSyncLoadResults(const QByteArray &data, const KURL &finalURL, const QString &headers); + + void open(const QString& _method, const KURL& _url, bool _async); + void send(const QString& _body); + void abort(); + void setRequestHeader(const QString& name, const QString &value); + void overrideMIMEType(const QString& override); + Value getAllResponseHeaders() const; + Value getResponseHeader(const QString& name) const; + + void changeState(XMLHttpRequestState newState); + + QGuardedPtr<DOM::DocumentImpl> doc; + + KURL url; + QString method; + bool async; + QMap<QString,QString> requestHeaders; + QString m_mimeTypeOverride; + QString contentType; + + KIO::TransferJob * job; + + XMLHttpRequestState state; + JSEventListener *onReadyStateChangeListener; + JSEventListener *onLoadListener; + + khtml::Decoder *decoder; + QString encoding; + QString responseHeaders; + + QString response; + mutable bool createdDocument; + mutable bool typeIsXML; + mutable DOM::Document responseXML; + + bool aborted; + }; + + + class XMLHttpRequestQObject : public QObject { + Q_OBJECT + + public: + XMLHttpRequestQObject(XMLHttpRequest *_jsObject); + + public slots: + void slotData( KIO::Job* job, const QByteArray &data ); + void slotFinished( KIO::Job* job ); + void slotRedirection( KIO::Job* job, const KURL& url); + + private: + XMLHttpRequest *jsObject; + }; + +} // namespace + +#endif diff --git a/khtml/ecma/xmlserializer.cpp b/khtml/ecma/xmlserializer.cpp new file mode 100644 index 000000000..6abcfe77f --- /dev/null +++ b/khtml/ecma/xmlserializer.cpp @@ -0,0 +1,109 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2003 Apple Computer, Inc. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "xmlserializer.h" +#include "xmlserializer.lut.h" + +#include "dom/dom_exception.h" +#include "dom/dom_doc.h" +#include "xml/dom_docimpl.h" + +#include <kdebug.h> + + +////////////////////// XMLSerializer Object //////////////////////// + +/* Source for XMLSerializerProtoTable. +@begin XMLSerializerProtoTable 1 + serializeToString XMLSerializer::SerializeToString DontDelete|Function 1 +@end +*/ + +namespace KJS { + +KJS_DEFINE_PROTOTYPE(XMLSerializerProto) +IMPLEMENT_PROTOFUNC_DOM(XMLSerializerProtoFunc) +KJS_IMPLEMENT_PROTOTYPE("XMLSerializer", XMLSerializerProto, XMLSerializerProtoFunc) + +XMLSerializerConstructorImp::XMLSerializerConstructorImp(ExecState *) + : ObjectImp() +{ +} + +bool XMLSerializerConstructorImp::implementsConstruct() const +{ + return true; +} + +Object XMLSerializerConstructorImp::construct(ExecState *exec, const List &) +{ + return Object(new XMLSerializer(exec)); +} + +const ClassInfo XMLSerializer::info = { "XMLSerializer", 0, 0, 0 }; + +XMLSerializer::XMLSerializer(ExecState *exec) + : DOMObject(XMLSerializerProto::self(exec)) +{ +} + +Value XMLSerializerProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args) +{ + if (!thisObj.inherits(&XMLSerializer::info)) { + Object err = Error::create(exec,TypeError); + exec->setException(err); + return err; + } + + switch (id) { + case XMLSerializer::SerializeToString: + { + if (args.size() != 1) { + return Undefined(); + } + + if (!args[0].toObject(exec).inherits(&DOMNode::info)) { + return Undefined(); + } + + DOM::NodeImpl *node = static_cast<DOM::NodeImpl *>(static_cast<KJS::DOMNode *>(args[0].toObject(exec).imp())->toNode().handle()); + + if (!node) { + return Undefined(); + } + + QString body; + + try { + body = node->toString().string(); + } catch(DOM::DOMException& e) { + Object err = Error::create(exec, GeneralError, "Exception serializing document"); + exec->setException(err); + return err; + } + + return getString(body); + } + } + + return Undefined(); +} + +} // end namespace diff --git a/khtml/ecma/xmlserializer.h b/khtml/ecma/xmlserializer.h new file mode 100644 index 000000000..629d09afe --- /dev/null +++ b/khtml/ecma/xmlserializer.h @@ -0,0 +1,54 @@ +// -*- c-basic-offset: 2 -*- +/* + * This file is part of the KDE libraries + * Copyright (C) 2003 Apple Computer, Inc. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _XMLSERIALIZER_H_ +#define _XMLSERIALIZER_H_ + +#include "ecma/kjs_binding.h" +#include "ecma/kjs_dom.h" +#include "misc/decoder.h" +#include "kio/jobclasses.h" + +namespace KJS { + + class JSEventListener; + + class XMLSerializerConstructorImp : public ObjectImp { + public: + XMLSerializerConstructorImp(ExecState *); + virtual bool implementsConstruct() const; + virtual Object construct(ExecState *exec, const List &args); + }; + + class XMLSerializer : public DOMObject { + public: + XMLSerializer(ExecState *); + virtual bool toBoolean(ExecState *) const { return true; } + virtual const ClassInfo* classInfo() const { return &info; } + static const ClassInfo info; + enum { SerializeToString }; + + private: + friend class XMLSerializerProtoFunc; + }; + +} // namespace + +#endif |