diff options
Diffstat (limited to 'khtml/ecma/kjs_dom.cpp')
-rw-r--r-- | khtml/ecma/kjs_dom.cpp | 1849 |
1 files changed, 1849 insertions, 0 deletions
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(); +} + +} |