kjs_dom.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2003 Apple Computer, Inc.
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Library General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Library General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Library General Public
00018  *  License along with this library; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 #include <khtmlview.h>
00023 #include "xml/dom2_eventsimpl.h"
00024 #include "rendering/render_canvas.h"
00025 #include "rendering/render_layer.h"
00026 #include "xml/dom_nodeimpl.h"
00027 #include "xml/dom_docimpl.h"
00028 #include "misc/htmltags.h" // ID_*
00029 #include "misc/htmlattrs.h" // ATTR_*
00030 #include "html/html_baseimpl.h"
00031 #include <kdebug.h>
00032 #include <khtml_part.h>
00033 
00034 #include "kjs_dom.h"
00035 #include "kjs_html.h"
00036 #include "kjs_css.h"
00037 #include "kjs_range.h"
00038 #include "kjs_traversal.h"
00039 #include "kjs_events.h"
00040 #include "kjs_views.h"
00041 #include "kjs_window.h"
00042 #include "dom/dom_exception.h"
00043 #include "kjs_dom.lut.h"
00044 #include "khtmlpart_p.h"
00045 
00046 using namespace KJS;
00047 
00048 // -------------------------------------------------------------------------
00049 /* Source for DOMNodeConstantsTable.
00050 @begin DOMNodeConstantsTable 11
00051   ELEMENT_NODE      DOM::Node::ELEMENT_NODE     DontDelete|ReadOnly
00052   ATTRIBUTE_NODE    DOM::Node::ATTRIBUTE_NODE       DontDelete|ReadOnly
00053   TEXT_NODE     DOM::Node::TEXT_NODE        DontDelete|ReadOnly
00054   CDATA_SECTION_NODE    DOM::Node::CDATA_SECTION_NODE   DontDelete|ReadOnly
00055   ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE    DontDelete|ReadOnly
00056   ENTITY_NODE       DOM::Node::ENTITY_NODE      DontDelete|ReadOnly
00057   PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly
00058   COMMENT_NODE      DOM::Node::COMMENT_NODE     DontDelete|ReadOnly
00059   DOCUMENT_NODE     DOM::Node::DOCUMENT_NODE        DontDelete|ReadOnly
00060   DOCUMENT_TYPE_NODE    DOM::Node::DOCUMENT_TYPE_NODE   DontDelete|ReadOnly
00061   DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE  DontDelete|ReadOnly
00062   NOTATION_NODE     DOM::Node::NOTATION_NODE        DontDelete|ReadOnly
00063 @end
00064 */
00065 CREATE_CONSTANT_TABLE(DOMNodeConstants,"DOMNodeConstants")
00066 // -------------------------------------------------------------------------
00067 /* Source for DOMNodeProtoTable.
00068 @begin DOMNodeProtoTable 13
00069   insertBefore  DOMNode::InsertBefore   DontDelete|Function 2
00070   replaceChild  DOMNode::ReplaceChild   DontDelete|Function 2
00071   removeChild   DOMNode::RemoveChild    DontDelete|Function 1
00072   appendChild   DOMNode::AppendChild    DontDelete|Function 1
00073   hasAttributes DOMNode::HasAttributes  DontDelete|Function 0
00074   hasChildNodes DOMNode::HasChildNodes  DontDelete|Function 0
00075   cloneNode DOMNode::CloneNode  DontDelete|Function 1
00076 # DOM2
00077   normalize DOMNode::Normalize  DontDelete|Function 0
00078   isSupported   DOMNode::IsSupported    DontDelete|Function 2
00079 # from the EventTarget interface
00080   addEventListener  DOMNode::AddEventListener   DontDelete|Function 3
00081   removeEventListener   DOMNode::RemoveEventListener    DontDelete|Function 3
00082   dispatchEvent     DOMNode::DispatchEvent  DontDelete|Function 1
00083 # IE extensions
00084   contains  DOMNode::Contains       DontDelete|Function 1
00085   insertAdjacentHTML    DOMNode::InsertAdjacentHTML DontDelete|Function 2
00086 # "DOM level 0" (from Gecko DOM reference; also in WinIE)
00087   item          DOMNode::Item           DontDelete|Function 1
00088 @end
00089 */
00090 DEFINE_PROTOTYPE("DOMNode",DOMNodeProto)
00091 IMPLEMENT_PROTOFUNC_DOM(DOMNodeProtoFunc)
00092 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMNodeProto,DOMNodeProtoFunc,DOMNodeConstants)
00093 
00094 const ClassInfo DOMNode::info = { "Node", 0, &DOMNodeTable, 0 };
00095 
00096 DOMNode::DOMNode(ExecState *exec, const DOM::Node& n)
00097   : DOMObject(DOMNodeProto::self(exec)), node(n)
00098 {
00099 }
00100 
00101 DOMNode::DOMNode(const Object& proto, const DOM::Node& n)
00102   : DOMObject(proto), node(n)
00103 {
00104 }
00105 
00106 DOMNode::~DOMNode()
00107 {
00108   ScriptInterpreter::forgetDOMObject(node.handle());
00109 }
00110 
00111 bool DOMNode::toBoolean(ExecState *) const
00112 {
00113     return !node.isNull();
00114 }
00115 
00116 /* Source for DOMNodeTable.
00117 @begin DOMNodeTable 53
00118   nodeName  DOMNode::NodeName   DontDelete|ReadOnly
00119   nodeValue DOMNode::NodeValue  DontDelete
00120   nodeType  DOMNode::NodeType   DontDelete|ReadOnly
00121   parentNode    DOMNode::ParentNode DontDelete|ReadOnly
00122   parentElement DOMNode::ParentElement  DontDelete|ReadOnly
00123   childNodes    DOMNode::ChildNodes DontDelete|ReadOnly
00124   firstChild    DOMNode::FirstChild DontDelete|ReadOnly
00125   lastChild DOMNode::LastChild  DontDelete|ReadOnly
00126   previousSibling  DOMNode::PreviousSibling DontDelete|ReadOnly
00127   nextSibling   DOMNode::NextSibling    DontDelete|ReadOnly
00128   attributes    DOMNode::Attributes DontDelete|ReadOnly
00129   namespaceURI  DOMNode::NamespaceURI   DontDelete|ReadOnly
00130 # DOM2
00131   prefix    DOMNode::Prefix     DontDelete
00132   localName DOMNode::LocalName  DontDelete|ReadOnly
00133   ownerDocument DOMNode::OwnerDocument  DontDelete|ReadOnly
00134 # Event handlers
00135 # IE also has: onactivate, onbefore*, oncontextmenu, oncontrolselect, oncut,
00136 # ondeactivate, ondrag*, ondrop, onfocusin, onfocusout, onhelp, onmousewheel,
00137 # onmove*, onpaste, onpropertychange, onreadystatechange, onresizeend/start,
00138 # onselectionchange, onstop
00139   onabort   DOMNode::OnAbort        DontDelete
00140   onblur    DOMNode::OnBlur         DontDelete
00141   onchange  DOMNode::OnChange       DontDelete
00142   onclick   DOMNode::OnClick        DontDelete
00143   ondblclick    DOMNode::OnDblClick     DontDelete
00144   ondragdrop    DOMNode::OnDragDrop     DontDelete
00145   onerror   DOMNode::OnError        DontDelete
00146   onfocus   DOMNode::OnFocus            DontDelete
00147   onkeydown DOMNode::OnKeyDown      DontDelete
00148   onkeypress    DOMNode::OnKeyPress     DontDelete
00149   onkeyup   DOMNode::OnKeyUp        DontDelete
00150   onload    DOMNode::OnLoad         DontDelete
00151   onmousedown   DOMNode::OnMouseDown        DontDelete
00152   onmousemove   DOMNode::OnMouseMove        DontDelete
00153   onmouseout    DOMNode::OnMouseOut     DontDelete
00154   onmouseover   DOMNode::OnMouseOver        DontDelete
00155   onmouseup DOMNode::OnMouseUp      DontDelete
00156   onmove    DOMNode::OnMove         DontDelete
00157   onreset   DOMNode::OnReset        DontDelete
00158   onresize  DOMNode::OnResize       DontDelete
00159   onselect  DOMNode::OnSelect       DontDelete
00160   onsubmit  DOMNode::OnSubmit       DontDelete
00161   onunload  DOMNode::OnUnload       DontDelete
00162 # IE extensions
00163   offsetLeft    DOMNode::OffsetLeft     DontDelete|ReadOnly
00164   offsetTop DOMNode::OffsetTop      DontDelete|ReadOnly
00165   offsetWidth   DOMNode::OffsetWidth        DontDelete|ReadOnly
00166   offsetHeight  DOMNode::OffsetHeight       DontDelete|ReadOnly
00167   offsetParent  DOMNode::OffsetParent       DontDelete|ReadOnly
00168   clientWidth   DOMNode::ClientWidth        DontDelete|ReadOnly
00169   clientHeight  DOMNode::ClientHeight       DontDelete|ReadOnly
00170   scrollLeft    DOMNode::ScrollLeft     DontDelete
00171   scrollTop DOMNode::ScrollTop      DontDelete
00172   scrollWidth   DOMNode::ScrollWidth            DontDelete|ReadOnly
00173   scrollHeight  DOMNode::ScrollHeight           DontDelete|ReadOnly
00174   sourceIndex   DOMNode::SourceIndex        DontDelete|ReadOnly
00175 @end
00176 */
00177 Value DOMNode::tryGet(ExecState *exec, const Identifier &propertyName) const
00178 {
00179 #ifdef KJS_VERBOSE
00180   kdDebug(6070) << "DOMNode::tryGet " << propertyName.qstring() << endl;
00181 #endif
00182   return DOMObjectLookupGetValue<DOMNode, DOMObject>(exec, propertyName, &DOMNodeTable, this);
00183 }
00184 
00185 static khtml::RenderObject* handleBodyRootQuirk(const DOM::Node& node, khtml::RenderObject* rend, int token)
00186 {
00187   //This emulates the quirks of various height/width properties on the viewport and root. Note that it 
00188   //is (mostly) IE-compatible in quirks, and mozilla-compatible in strict.
00189   if (!rend) return 0;
00190 
00191   bool quirksMode = rend->style() && rend->style()->htmlHacks();
00192   
00193   //There are a couple quirks here. One is that in quirks mode body is always forwarded to root...
00194   //This is relevant for even the scrollTop/scrollLeft type properties.
00195   if (quirksMode && node.handle()->id() == ID_BODY) {
00196     while (rend->parent() && !rend->isRoot())
00197       rend = rend->parent();
00198   }
00199 
00200   //Also, some properties of the root are really done in terms of the viewport.
00201   //These are  {offset/client}{Height/Width}. The offset versions do it only in 
00202   //quirks mode, the client always.
00203   if (!rend->isRoot()) return rend; //Don't care about non-root things here!
00204   bool needViewport = false;
00205 
00206   switch (token) {
00207     case DOMNode::OffsetHeight:
00208     case DOMNode::OffsetWidth:
00209       needViewport = quirksMode;
00210       break;
00211     case DOMNode::ClientHeight:
00212     case DOMNode::ClientWidth:
00213       needViewport = true;
00214       break;
00215   }
00216   
00217   if (needViewport) {
00218     //Scan up to find the new target
00219     while (rend->parent())
00220       rend = rend->parent();
00221   }
00222   return rend;
00223 }
00224 
00225 Value DOMNode::getValueProperty(ExecState *exec, int token) const
00226 {
00227   switch (token) {
00228   case NodeName:
00229     return String(node.nodeName());
00230   case NodeValue:
00231     return getString(node.nodeValue()); // initially null, per domts/level1/core/hc_documentcreateelement.html
00232   case NodeType:
00233     return Number((unsigned int)node.nodeType());
00234   case ParentNode:
00235     return getDOMNode(exec,node.parentNode());
00236   case ParentElement: // IE only apparently
00237     return getDOMNode(exec,node.parentNode());
00238   case ChildNodes:
00239     return getDOMNodeList(exec,node.childNodes());
00240   case FirstChild:
00241     return getDOMNode(exec,node.firstChild());
00242   case LastChild:
00243     return getDOMNode(exec,node.lastChild());
00244   case PreviousSibling:
00245     return getDOMNode(exec,node.previousSibling());
00246   case NextSibling:
00247     return getDOMNode(exec,node.nextSibling());
00248   case Attributes:
00249     return getDOMNamedNodeMap(exec,node.attributes());
00250   case NamespaceURI:
00251     return getString(node.namespaceURI()); // Moz returns null if not set (dom/namespaces.html)
00252   case Prefix:
00253     return getString(node.prefix());  // Moz returns null if not set (dom/namespaces.html)
00254   case LocalName:
00255     return getString(node.localName());  // Moz returns null if not set (dom/namespaces.html)
00256   case OwnerDocument:
00257     return getDOMNode(exec,node.ownerDocument());
00258   case OnAbort:
00259     return getListener(DOM::EventImpl::ABORT_EVENT);
00260   case OnBlur:
00261     return getListener(DOM::EventImpl::BLUR_EVENT);
00262   case OnChange:
00263     return getListener(DOM::EventImpl::CHANGE_EVENT);
00264   case OnClick:
00265     return getListener(DOM::EventImpl::KHTML_ECMA_CLICK_EVENT);
00266   case OnDblClick:
00267     return getListener(DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT);
00268   case OnDragDrop:
00269     return getListener(DOM::EventImpl::KHTML_DRAGDROP_EVENT);
00270   case OnError:
00271     return getListener(DOM::EventImpl::ERROR_EVENT);
00272   case OnFocus:
00273     return getListener(DOM::EventImpl::FOCUS_EVENT);
00274   case OnKeyDown:
00275     return getListener(DOM::EventImpl::KEYDOWN_EVENT);
00276   case OnKeyPress:
00277     return getListener(DOM::EventImpl::KEYPRESS_EVENT);
00278   case OnKeyUp:
00279     return getListener(DOM::EventImpl::KEYUP_EVENT);
00280   case OnLoad:
00281     return getListener(DOM::EventImpl::LOAD_EVENT);
00282   case OnMouseDown:
00283     return getListener(DOM::EventImpl::MOUSEDOWN_EVENT);
00284   case OnMouseMove:
00285     return getListener(DOM::EventImpl::MOUSEMOVE_EVENT);
00286   case OnMouseOut:
00287     return getListener(DOM::EventImpl::MOUSEOUT_EVENT);
00288   case OnMouseOver:
00289     return getListener(DOM::EventImpl::MOUSEOVER_EVENT);
00290   case OnMouseUp:
00291     return getListener(DOM::EventImpl::MOUSEUP_EVENT);
00292   case OnMove:
00293     return getListener(DOM::EventImpl::KHTML_MOVE_EVENT);
00294   case OnReset:
00295     return getListener(DOM::EventImpl::RESET_EVENT);
00296   case OnResize:
00297     return getListener(DOM::EventImpl::RESIZE_EVENT);
00298   case OnSelect:
00299     return getListener(DOM::EventImpl::SELECT_EVENT);
00300   case OnSubmit:
00301     return getListener(DOM::EventImpl::SUBMIT_EVENT);
00302   case OnUnload:
00303     return getListener(DOM::EventImpl::UNLOAD_EVENT);
00304   case SourceIndex: {
00305     // Retrieves the ordinal position of the object, in source order, as the object
00306     // appears in the document's all collection
00307     // i.e. document.all[n.sourceIndex] == n
00308     DOM::Document doc = node.ownerDocument();
00309     if (doc.isHTMLDocument()) {
00310       DOM::HTMLCollection all = static_cast<DOM::HTMLDocument>(doc).all();
00311       unsigned long i = 0;
00312       DOM::Node n = all.firstItem();
00313       for ( ; !n.isNull() && n != node; n = all.nextItem() )
00314         ++i;
00315       Q_ASSERT( !n.isNull() ); // node not in document.all !?
00316       return Number(i);
00317     }
00318   }
00319   default:
00320     // no DOM standard, found in IE only
00321 
00322     // Make sure our layout is up to date before we allow a query on these attributes.
00323     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
00324     if (docimpl) {
00325       docimpl->updateLayout();
00326     }
00327 
00328     khtml::RenderObject *rend = node.handle()->renderer();
00329 
00330     //In quirks mode, may need to forward if to body.
00331     rend = handleBodyRootQuirk(node, rend, token);
00332 
00333     switch (token) {
00334     case OffsetLeft:
00335       return rend ? static_cast<Value>( Number( rend->offsetLeft() ) ) : Undefined();
00336     case OffsetTop:
00337       return rend ? static_cast<Value>(  Number( rend->offsetTop() ) ) : Undefined();
00338     case OffsetWidth:
00339       return rend ? static_cast<Value>(  Number( rend->offsetWidth() ) ) : Undefined();
00340     case OffsetHeight:
00341       return rend ? static_cast<Value>(  Number( rend->offsetHeight() ) ) : Undefined();
00342     case OffsetParent:
00343     {
00344       khtml::RenderObject* par = rend ? rend->offsetParent() : 0;
00345       return getDOMNode( exec, par ? par->element() : 0 );
00346     }
00347     case ClientWidth:
00348       return rend ? static_cast<Value>( Number( rend->clientWidth() ) ) : Undefined();
00349     case ClientHeight:
00350       return rend ? static_cast<Value>( Number( rend->clientHeight() ) ) : Undefined();
00351     case ScrollWidth:
00352       return rend ? static_cast<Value>( Number(rend->scrollWidth()) ) : Undefined();
00353     case ScrollHeight:
00354       return rend ? static_cast<Value>( Number(rend->scrollHeight()) ) : Undefined();
00355     case ScrollLeft:
00356       if (rend && rend->layer()) {
00357           if (rend->isRoot() && !rend->style()->hidesOverflow())
00358               return Number( node.ownerDocument().view() ? node.ownerDocument().view()->contentsX() : 0);
00359           return Number( rend->layer()->scrollXOffset() );
00360       }
00361       return Number( 0 );
00362     case ScrollTop:
00363       if (rend && rend->layer()) {
00364           if (rend->isRoot() && !rend->style()->hidesOverflow())
00365               return Number( node.ownerDocument().view() ? node.ownerDocument().view()->contentsY() : 0);
00366           return Number( rend->layer()->scrollYOffset() );
00367       }
00368       return Number( 0 );
00369     default:
00370       kdDebug(6070) << "WARNING: Unhandled token in DOMNode::getValueProperty : " << token << endl;
00371       break;
00372     }
00373   }
00374   return Undefined();
00375 }
00376 
00377 
00378 void DOMNode::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
00379 {
00380 #ifdef KJS_VERBOSE
00381   kdDebug(6070) << "DOMNode::tryPut " << propertyName.qstring() << endl;
00382 #endif
00383   DOMObjectLookupPut<DOMNode,DOMObject>(exec, propertyName, value, attr,
00384                                         &DOMNodeTable, this );
00385 }
00386 
00387 void DOMNode::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/)
00388 {
00389   switch (token) {
00390   case NodeValue:
00391     node.setNodeValue(value.toString(exec).string());
00392     break;
00393   case Prefix:
00394     node.setPrefix(value.toString(exec).string());
00395     break;
00396   case OnAbort:
00397     setListener(exec,DOM::EventImpl::ABORT_EVENT,value);
00398     break;
00399   case OnBlur:
00400     setListener(exec,DOM::EventImpl::BLUR_EVENT,value);
00401     break;
00402   case OnChange:
00403     setListener(exec,DOM::EventImpl::CHANGE_EVENT,value);
00404     break;
00405   case OnClick:
00406     setListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT,value);
00407     break;
00408   case OnDblClick:
00409     setListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT,value);
00410     break;
00411   case OnDragDrop:
00412     setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value);
00413     break;
00414   case OnError:
00415     setListener(exec,DOM::EventImpl::ERROR_EVENT,value);
00416     break;
00417   case OnFocus:
00418     setListener(exec,DOM::EventImpl::FOCUS_EVENT,value);
00419     break;
00420   case OnKeyDown:
00421     setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value);
00422     break;
00423   case OnKeyPress:
00424     setListener(exec,DOM::EventImpl::KEYPRESS_EVENT,value);
00425     break;
00426   case OnKeyUp:
00427     setListener(exec,DOM::EventImpl::KEYUP_EVENT,value);
00428     break;
00429   case OnLoad:
00430     setListener(exec,DOM::EventImpl::LOAD_EVENT,value);
00431     break;
00432   case OnMouseDown:
00433     setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value);
00434     break;
00435   case OnMouseMove:
00436     setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value);
00437     break;
00438   case OnMouseOut:
00439     setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value);
00440     break;
00441   case OnMouseOver:
00442     setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value);
00443     break;
00444   case OnMouseUp:
00445     setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value);
00446     break;
00447   case OnMove:
00448     setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value);
00449     break;
00450   case OnReset:
00451     setListener(exec,DOM::EventImpl::RESET_EVENT,value);
00452     break;
00453   case OnResize:
00454     setListener(exec,DOM::EventImpl::RESIZE_EVENT,value);
00455     break;
00456   case OnSelect:
00457     setListener(exec,DOM::EventImpl::SELECT_EVENT,value);
00458     break;
00459   case OnSubmit:
00460     setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value);
00461     break;
00462   case OnUnload:
00463     setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value);
00464     break;
00465   default:
00466     // Make sure our layout is up to date 
00467     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
00468     if (docimpl)
00469       docimpl->updateLayout();
00470 
00471     khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
00472 
00473     //In quirks mode, may need to forward.
00474     rend = handleBodyRootQuirk(node, rend, token);
00475 
00476     switch (token) {
00477       case ScrollLeft:
00478         if (rend && rend->layer()) {
00479           if (rend->style()->hidesOverflow())
00480             rend->layer()->scrollToXOffset(value.toInt32(exec));
00481           else if (rend->isRoot()) {
00482             QScrollView* sview = node.ownerDocument().view();
00483             if (sview)
00484               sview->setContentsPos(value.toInt32(exec), sview->contentsY());
00485           }
00486         }
00487         break;
00488       case ScrollTop:
00489         if (rend && rend->layer()) {
00490           if (rend->style()->hidesOverflow())
00491             rend->layer()->scrollToYOffset(value.toInt32(exec));
00492           else if (rend->isRoot()) {
00493             QScrollView* sview = node.ownerDocument().view();
00494             if (sview)
00495               sview->setContentsPos(sview->contentsX(), value.toInt32(exec));
00496           }
00497         }
00498         break;
00499       default:
00500       kdDebug(6070) << "WARNING: DOMNode::putValueProperty unhandled token " << token << endl;
00501     }
00502   }
00503 }
00504 
00505 Value DOMNode::toPrimitive(ExecState *exec, Type /*preferred*/) const
00506 {
00507   if (node.isNull())
00508     return Null();
00509 
00510   return String(toString(exec));
00511 }
00512 
00513 UString DOMNode::toString(ExecState *) const
00514 {
00515   if (node.isNull())
00516     return "null";
00517   UString s;
00518 
00519   DOM::Element e = node;
00520   if ( !e.isNull() ) {
00521     s = e.nodeName().string();
00522   } else
00523     s = className(); // fallback
00524 
00525   return "[object " + s + "]";
00526 }
00527 
00528 void DOMNode::setListener(ExecState *exec, int eventId, const Value& func) const
00529 {
00530   node.handle()->setHTMLEventListener(eventId,Window::retrieveActive(exec)->getJSEventListener(func,true));
00531 }
00532 
00533 Value DOMNode::getListener(int eventId) const
00534 {
00535   DOM::EventListener *listener = node.handle()->getHTMLEventListener(eventId);
00536   JSEventListener *jsListener = static_cast<JSEventListener*>(listener);
00537   if ( jsListener && jsListener->listenerObjImp() )
00538     return jsListener->listenerObj();
00539   else
00540     return Null();
00541 }
00542 
00543 void DOMNode::pushEventHandlerScope(ExecState *, ScopeChain &) const
00544 {
00545 }
00546 
00547 Value DOMNodeProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
00548 {
00549   KJS_CHECK_THIS( DOMNode, thisObj );
00550   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
00551   switch (id) {
00552     case DOMNode::HasAttributes:
00553       return Boolean(node.hasAttributes());
00554     case DOMNode::HasChildNodes:
00555       return Boolean(node.hasChildNodes());
00556     case DOMNode::CloneNode:
00557       return getDOMNode(exec,node.cloneNode(args[0].toBoolean(exec)));
00558     case DOMNode::Normalize:
00559       node.normalize();
00560       return Undefined();
00561     case DOMNode::IsSupported:
00562       return Boolean(node.isSupported(args[0].toString(exec).string(),args[1].toString(exec).string()));
00563     case DOMNode::AddEventListener: {
00564         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
00565         node.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
00566         return Undefined();
00567     }
00568     case DOMNode::RemoveEventListener: {
00569         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
00570         node.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
00571         return Undefined();
00572     }
00573     case DOMNode::DispatchEvent:
00574       return Boolean(node.dispatchEvent(toEvent(args[0])));
00575     case DOMNode::AppendChild:
00576       return getDOMNode(exec,node.appendChild(toNode(args[0])));
00577     case DOMNode::RemoveChild:
00578       return getDOMNode(exec,node.removeChild(toNode(args[0])));
00579     case DOMNode::InsertBefore:
00580       return getDOMNode(exec,node.insertBefore(toNode(args[0]), toNode(args[1])));
00581     case DOMNode::ReplaceChild:
00582       return getDOMNode(exec,node.replaceChild(toNode(args[0]), toNode(args[1])));
00583     case DOMNode::Contains:
00584     {
00585     DOM::Node other = toNode(args[0]);
00586     if (!other.isNull() && node.nodeType()==DOM::Node::ELEMENT_NODE)
00587     {
00588         DOM::NodeBaseImpl *impl = static_cast<DOM::NodeBaseImpl *>(node.handle());
00589         bool retval = other.handle()->isAncestor(impl);
00590         return Boolean(retval);
00591     }
00592         return Undefined();
00593     }
00594     case DOMNode::InsertAdjacentHTML:
00595     {
00596       // see http://www.faqts.com/knowledge_base/view.phtml/aid/5756
00597       // and http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertAdjacentHTML.asp
00598       Range range = node.ownerDocument().createRange();
00599 
00600       range.setStartBefore(node);
00601 
00602       DocumentFragment docFrag = range.createContextualFragment(args[1].toString(exec).string());
00603 
00604       DOMString where = args[0].toString(exec).string();
00605 
00606       if (where == "beforeBegin" || where == "BeforeBegin")
00607         node.parentNode().insertBefore(docFrag, node);
00608       else if (where == "afterBegin" || where == "AfterBegin")
00609         node.insertBefore(docFrag, node.firstChild());
00610       else if (where == "beforeEnd" || where == "BeforeEnd")
00611         return getDOMNode(exec, node.appendChild(docFrag));
00612       else if (where == "afterEnd" || where == "AfterEnd")
00613         if (!node.nextSibling().isNull())
00614       node.parentNode().insertBefore(docFrag, node.nextSibling());
00615     else
00616       node.parentNode().appendChild(docFrag);
00617 
00618       return Undefined();
00619     }
00620     case DOMNode::Item:
00621       return getDOMNode(exec, node.childNodes().item(static_cast<unsigned long>(args[0].toNumber(exec))));
00622   }
00623 
00624   return Undefined();
00625 }
00626 
00627 // -------------------------------------------------------------------------
00628 
00629 /*
00630 @begin DOMNodeListProtoTable 2
00631   item      DOMNodeList::Item       DontDelete|Function 1
00632 # IE extension (IE treats DOMNodeList like an HTMLCollection)
00633   namedItem DOMNodeList::NamedItem      DontDelete|Function 1
00634 @end
00635 */
00636 DEFINE_PROTOTYPE("DOMNodeList", DOMNodeListProto)
00637 IMPLEMENT_PROTOFUNC_DOM(DOMNodeListProtoFunc)
00638 IMPLEMENT_PROTOTYPE(DOMNodeListProto,DOMNodeListProtoFunc)
00639 
00640 const ClassInfo DOMNodeList::info = { "NodeList", 0, 0, 0 };
00641 
00642 DOMNodeList::DOMNodeList(ExecState *exec, const DOM::NodeList& l)
00643  : DOMObject(DOMNodeListProto::self(exec)), list(l) { }
00644 
00645 DOMNodeList::~DOMNodeList()
00646 {
00647   ScriptInterpreter::forgetDOMObject(list.handle());
00648 }
00649 
00650 // We have to implement hasProperty since we don't use a hashtable for 'length'
00651 // ## this breaks "for (..in..)" though.
00652 bool DOMNodeList::hasProperty(ExecState *exec, const Identifier &p) const
00653 {
00654   if (p == lengthPropertyName)
00655     return true;
00656 
00657   if (ObjectImp::hasProperty(exec, p))
00658     return true;
00659 
00660   bool ok;
00661   unsigned long pos = p.toULong(&ok);
00662   if (ok && pos < list.length())
00663     return true;
00664 
00665   // ## missing: accept p if item id...
00666   return false;
00667 }
00668 
00669 Value DOMNodeList::tryGet(ExecState *exec, const Identifier &p) const
00670 {
00671 #ifdef KJS_VERBOSE
00672   kdDebug(6070) << "DOMNodeList::tryGet " << p.ascii() << endl;
00673 #endif
00674   if (p == lengthPropertyName)
00675     return Number(list.length());
00676 
00677   // Look in the prototype (for functions) before assuming it's an item's name
00678   Object proto = Object::dynamicCast(prototype());
00679   if (proto.isValid() && proto.hasProperty(exec,p))
00680     return proto.get(exec,p);
00681 
00682   Value result;
00683 
00684   // array index ?
00685   bool ok;
00686   long unsigned int idx = p.toULong(&ok);
00687   if (ok)
00688     result = getDOMNode(exec,list.item(idx));
00689   else {
00690     // Find by ID
00691     DOM::HTMLElement e;
00692     unsigned long l = list.length();
00693     bool found = false;
00694 
00695     for ( unsigned long i = 0; i < l; i++ )
00696       if ( ( e = list.item( i ) ).id() == p.string() ) {
00697         result = getDOMNode(exec, list.item( i ) );
00698         found = true;
00699         break;
00700       }
00701 
00702     if ( !found )
00703       result = ObjectImp::get(exec, p);
00704   }
00705 
00706   return result;
00707 }
00708 
00709 ReferenceList DOMNodeList::propList(ExecState *exec, bool recursive)
00710 {
00711   ReferenceList properties = ObjectImp::propList(exec,recursive);
00712 
00713   for (unsigned i = 0; i < list.length(); ++i) {
00714     if (!ObjectImp::hasProperty(exec,Identifier::from(i))) {
00715       properties.append(Reference(this, i));
00716     }
00717   }
00718 
00719   if (!ObjectImp::hasProperty(exec, lengthPropertyName))
00720     properties.append(Reference(this, lengthPropertyName));
00721 
00722   return properties;
00723 }
00724 
00725 // Need to support both get and call, so that list[0] and list(0) work.
00726 Value DOMNodeList::call(ExecState *exec, Object &thisObj, const List &args)
00727 {
00728   // This code duplication is necessary, DOMNodeList isn't a DOMFunction
00729   Value val;
00730   try {
00731     val = tryCall(exec, thisObj, args);
00732   }
00733   // pity there's no way to distinguish between these in JS code
00734   catch (...) {
00735     Object err = Error::create(exec, GeneralError, "Exception from DOMNodeList");
00736     exec->setException(err);
00737   }
00738   return val;
00739 }
00740 
00741 Value DOMNodeList::tryCall(ExecState *exec, Object &, const List &args)
00742 {
00743   // Do not use thisObj here. See HTMLCollection.
00744   UString s = args[0].toString(exec);
00745 
00746   // index-based lookup?
00747   bool ok;
00748   unsigned int u = s.toULong(&ok);
00749   if (ok)
00750     return getDOMNode(exec,list.item(u));
00751 
00752   // try lookup by name
00753   // ### NodeList::namedItem() would be cool to have
00754   // ### do we need to support the same two arg overload as in HTMLCollection?
00755   Value result = tryGet(exec, Identifier(s));
00756 
00757   if (result.isValid())
00758     return result;
00759 
00760   return Undefined();
00761 }
00762 
00763 // Not a prototype class currently, but should probably be converted to one
00764 Value DOMNodeListProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
00765 {
00766   KJS_CHECK_THIS( KJS::DOMNodeList, thisObj );
00767   DOM::NodeList list = static_cast<DOMNodeList *>(thisObj.imp())->nodeList();
00768   switch (id) {
00769   case KJS::DOMNodeList::Item:
00770     return getDOMNode(exec, list.item(args[0].toInt32(exec)));
00771   case KJS::DOMNodeList::NamedItem:
00772   {
00773     // Not a real namedItem implementation like the one HTMLCollection has.
00774     // This is only an IE extension...
00775     DOM::HTMLElement e;
00776     unsigned long len = list.length();
00777     DOM::DOMString s = args[0].toString(exec).string();
00778 
00779     for ( unsigned long i = 0; i < len; i++ )
00780     {
00781       e = list.item( i );
00782       if ( !e.isNull() && (
00783              e.id() == s || static_cast<ElementImpl *>(e.handle())->getAttribute(ATTR_NAME) == s )
00784       )
00785       {
00786         return getDOMNode(exec, e );
00787       }
00788     }
00789     return Null(); // see HTMLCollection::NamedItem implementation
00790   }
00791   default:
00792     return Undefined();
00793   }
00794 }
00795 
00796 // -------------------------------------------------------------------------
00797 
00798 const ClassInfo DOMAttr::info = { "Attr", &DOMNode::info, &DOMAttrTable, 0 };
00799 
00800 /* Source for DOMAttrTable.
00801 @begin DOMAttrTable 5
00802   name      DOMAttr::Name       DontDelete|ReadOnly
00803   specified DOMAttr::Specified  DontDelete|ReadOnly
00804   value     DOMAttr::ValueProperty  DontDelete
00805   ownerElement  DOMAttr::OwnerElement   DontDelete|ReadOnly
00806 @end
00807 */
00808 Value DOMAttr::tryGet(ExecState *exec, const Identifier &propertyName) const
00809 {
00810 #ifdef KJS_VERBOSE
00811   kdDebug(6070) << "DOMAttr::tryGet " << propertyName.qstring() << endl;
00812 #endif
00813   return DOMObjectLookupGetValue<DOMAttr,DOMNode>(exec, propertyName,
00814                                                   &DOMAttrTable, this );
00815 }
00816 
00817 Value DOMAttr::getValueProperty(ExecState *exec, int token) const
00818 {
00819   switch (token) {
00820   case Name:
00821     return String(static_cast<DOM::Attr>(node).name());
00822   case Specified:
00823     return Boolean(static_cast<DOM::Attr>(node).specified());
00824   case ValueProperty:
00825     return String(static_cast<DOM::Attr>(node).value());
00826   case OwnerElement: // DOM2
00827     return getDOMNode(exec,static_cast<DOM::Attr>(node).ownerElement());
00828   }
00829   return Value(); // not reached
00830 }
00831 
00832 void DOMAttr::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
00833 {
00834 #ifdef KJS_VERBOSE
00835   kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl;
00836 #endif
00837   DOMObjectLookupPut<DOMAttr,DOMNode>(exec, propertyName, value, attr,
00838                                       &DOMAttrTable, this );
00839 }
00840 
00841 void DOMAttr::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/)
00842 {
00843   switch (token) {
00844   case ValueProperty:
00845     static_cast<DOM::Attr>(node).setValue(value.toString(exec).string());
00846     return;
00847   default:
00848     kdDebug(6070) << "WARNING: DOMAttr::putValueProperty unhandled token " << token << endl;
00849   }
00850 }
00851 
00852 // -------------------------------------------------------------------------
00853 
00854 /* Source for DOMDocumentProtoTable.
00855 @begin DOMDocumentProtoTable 23
00856   createElement   DOMDocument::CreateElement                   DontDelete|Function 1
00857   createDocumentFragment DOMDocument::CreateDocumentFragment   DontDelete|Function 1
00858   createTextNode  DOMDocument::CreateTextNode                  DontDelete|Function 1
00859   createComment   DOMDocument::CreateComment                   DontDelete|Function 1
00860   createCDATASection DOMDocument::CreateCDATASection           DontDelete|Function 1
00861   createProcessingInstruction DOMDocument::CreateProcessingInstruction DontDelete|Function 1
00862   createAttribute DOMDocument::CreateAttribute                 DontDelete|Function 1
00863   createEntityReference DOMDocument::CreateEntityReference     DontDelete|Function 1
00864   getElementsByTagName  DOMDocument::GetElementsByTagName      DontDelete|Function 1
00865   importNode           DOMDocument::ImportNode                 DontDelete|Function 2
00866   createElementNS      DOMDocument::CreateElementNS            DontDelete|Function 2
00867   createAttributeNS    DOMDocument::CreateAttributeNS          DontDelete|Function 2
00868   getElementsByTagNameNS  DOMDocument::GetElementsByTagNameNS  DontDelete|Function 2
00869   getElementById     DOMDocument::GetElementById               DontDelete|Function 1
00870   createRange        DOMDocument::CreateRange                  DontDelete|Function 0
00871   createNodeIterator DOMDocument::CreateNodeIterator           DontDelete|Function 3
00872   createTreeWalker   DOMDocument::CreateTreeWalker             DontDelete|Function 4
00873   createEvent        DOMDocument::CreateEvent                  DontDelete|Function 1
00874   getOverrideStyle   DOMDocument::GetOverrideStyle             DontDelete|Function 2
00875   abort              DOMDocument::Abort                        DontDelete|Function 0
00876   load               DOMDocument::Load                         DontDelete|Function 1
00877   loadXML            DOMDocument::LoadXML                      DontDelete|Function 2
00878 @end
00879 */
00880 IMPLEMENT_PROTOFUNC_DOM(DOMDocumentProtoFunc)
00881 PUBLIC_IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMDocumentProto, "DOMDocument", DOMDocumentProtoFunc, DOMNodeProto)
00882 
00883 IMPLEMENT_PSEUDO_CONSTRUCTOR(DocumentPseudoCtor, "Document", DOMDocumentProto)
00884 
00885 const ClassInfo DOMDocument::info = { "Document", &DOMNode::info, &DOMDocumentTable, 0 };
00886 
00887 /* Source for DOMDocumentTable.
00888 @begin DOMDocumentTable 4
00889   doctype         DOMDocument::DocType                         DontDelete|ReadOnly
00890   implementation  DOMDocument::Implementation                  DontDelete|ReadOnly
00891   characterSet    DOMDocument::CharacterSet                    DontDelete|ReadOnly
00892   documentElement DOMDocument::DocumentElement                 DontDelete|ReadOnly
00893   styleSheets     DOMDocument::StyleSheets                     DontDelete|ReadOnly
00894   preferredStylesheetSet  DOMDocument::PreferredStylesheetSet  DontDelete|ReadOnly
00895   selectedStylesheetSet  DOMDocument::SelectedStylesheetSet    DontDelete
00896   readyState      DOMDocument::ReadyState                      DontDelete|ReadOnly
00897   defaultView     DOMDocument::DefaultView                     DontDelete|ReadOnly
00898   async           DOMDocument::Async                           DontDelete
00899 @end
00900 */
00901 
00902 DOMDocument::DOMDocument(ExecState *exec, const DOM::Document& d)
00903   : DOMNode(DOMDocumentProto::self(exec), d) { }
00904 
00905 DOMDocument::DOMDocument(const Object& proto, const DOM::Document& d)
00906   : DOMNode(proto, d) { }
00907 
00908 DOMDocument::~DOMDocument()
00909 {
00910   ScriptInterpreter::forgetDOMObject(node.handle());
00911 }
00912 
00913 Value DOMDocument::tryGet(ExecState *exec, const Identifier &propertyName) const
00914 {
00915 #ifdef KJS_VERBOSE
00916   kdDebug(6070) << "DOMDocument::tryGet " << propertyName.qstring() << endl;
00917 #endif
00918   return DOMObjectLookupGetValue<DOMDocument, DOMNode>(
00919     exec, propertyName, &DOMDocumentTable, this);
00920 }
00921 
00922 Value DOMDocument::getValueProperty(ExecState *exec, int token) const
00923 {
00924   DOM::Document doc = static_cast<DOM::Document>(node);
00925 
00926   switch(token) {
00927   case DocType:
00928     return getDOMNode(exec,doc.doctype());
00929   case Implementation:
00930     return getDOMDOMImplementation(exec,doc.implementation());
00931   case DocumentElement:
00932     return getDOMNode(exec,doc.documentElement());
00933   case CharacterSet: {
00934     DOM::DocumentImpl* docImpl = static_cast<DOM::DocumentImpl*>(doc.handle());
00935     return String(docImpl->part()->encoding());
00936   }
00937   case StyleSheets:
00938     //kdDebug() << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets" << endl;
00939     return getDOMStyleSheetList(exec, doc.styleSheets(), doc);
00940   case DOMDocument::DefaultView: // DOM2
00941     {
00942     KHTMLView *view = node.handle()->getDocument()->view();
00943     if (view)
00944         return Window::retrieve(view->part());
00945     return getDOMAbstractView(exec, doc.defaultView());
00946     }
00947   case PreferredStylesheetSet:
00948     return String(doc.preferredStylesheetSet());
00949   case SelectedStylesheetSet:
00950     return String(doc.selectedStylesheetSet());
00951   case ReadyState:
00952     {
00953     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
00954     if ( docimpl && docimpl->view() )
00955     {
00956       KHTMLPart* part = docimpl->view()->part();
00957       if ( part ) {
00958         if (part->d->m_bComplete) return String("complete");
00959         if (docimpl->parsing()) return String("loading");
00960         return String("loaded");
00961         // What does the interactive value mean ?
00962         // Missing support for "uninitialized"
00963       }
00964     }
00965     return Undefined();
00966     }
00967   case Async:
00968     return Boolean(doc.async());
00969   default:
00970     kdDebug(6070) << "WARNING: DOMDocument::getValueProperty unhandled token " << token << endl;
00971     return Value();
00972   }
00973 }
00974 
00975 void DOMDocument::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
00976 {
00977 #ifdef KJS_VERBOSE
00978   kdDebug(6070) << "DOMDocument::tryPut " << propertyName.qstring() << endl;
00979 #endif
00980   DOMObjectLookupPut<DOMDocument,DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this );
00981 }
00982 
00983 void DOMDocument::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/)
00984 {
00985   DOM::Document doc = static_cast<DOM::Document>(node);
00986   switch (token) {
00987     case SelectedStylesheetSet: {
00988       doc.setSelectedStylesheetSet(value.toString(exec).string());
00989       break;
00990     }
00991     case Async: {
00992       doc.setAsync(value.toBoolean(exec));
00993       break;
00994     }
00995   }
00996 }
00997 
00998 Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
00999 {
01000   KJS_CHECK_THIS( KJS::DOMDocument, thisObj );
01001   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
01002   DOM::Document doc = static_cast<DOM::Document>(node);
01003   String str = args[0].toString(exec);
01004   DOM::DOMString s = str.value().string();
01005 
01006   switch(id) {
01007   case DOMDocument::CreateElement:
01008     return getDOMNode(exec,doc.createElement(s));
01009   case DOMDocument::CreateDocumentFragment:
01010     return getDOMNode(exec,doc.createDocumentFragment());
01011   case DOMDocument::CreateTextNode:
01012     return getDOMNode(exec,doc.createTextNode(s));
01013   case DOMDocument::CreateComment:
01014     return getDOMNode(exec,doc.createComment(s));
01015   case DOMDocument::CreateCDATASection:
01016     return getDOMNode(exec,doc.createCDATASection(s));  /* TODO: okay ? */
01017   case DOMDocument::CreateProcessingInstruction:
01018     return getDOMNode(exec,doc.createProcessingInstruction(args[0].toString(exec).string(),
01019                                                                  args[1].toString(exec).string()));
01020   case DOMDocument::CreateAttribute:
01021     return getDOMNode(exec,doc.createAttribute(s));
01022   case DOMDocument::CreateEntityReference:
01023     return getDOMNode(exec,doc.createEntityReference(args[0].toString(exec).string()));
01024   case DOMDocument::GetElementsByTagName:
01025     return getDOMNodeList(exec,doc.getElementsByTagName(s));
01026   case DOMDocument::ImportNode: // DOM2
01027     return getDOMNode(exec,doc.importNode(toNode(args[0]), args[1].toBoolean(exec)));
01028   case DOMDocument::CreateElementNS: // DOM2
01029     return getDOMNode(exec,doc.createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
01030   case DOMDocument::CreateAttributeNS: // DOM2
01031     return getDOMNode(exec,doc.createAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01032   case DOMDocument::GetElementsByTagNameNS: // DOM2
01033     return getDOMNodeList(exec,doc.getElementsByTagNameNS(args[0].toString(exec).string(),
01034                                                           args[1].toString(exec).string()));
01035   case DOMDocument::GetElementById:
01036 #ifdef KJS_VERBOSE
01037   kdDebug(6070) << "DOMDocument::GetElementById looking for " << args[0].toString(exec).string() << endl;
01038 #endif
01039     return getDOMNode(exec,doc.getElementById(args[0].toString(exec).string()));
01040   case DOMDocument::CreateRange:
01041     return getDOMRange(exec,doc.createRange());
01042   case DOMDocument::CreateNodeIterator:
01043     if (args[2].isA(NullType)) {
01044         DOM::NodeFilter filter;
01045         return getDOMNodeIterator(exec,
01046                                   doc.createNodeIterator(toNode(args[0]),
01047                                                          (long unsigned int)(args[1].toNumber(exec)),
01048                                                          filter,args[3].toBoolean(exec)));
01049     }
01050     else {
01051       Object obj = Object::dynamicCast(args[2]);
01052       if (obj.isValid())
01053       {
01054         DOM::CustomNodeFilter *customFilter = new JSNodeFilter(obj);
01055         DOM::NodeFilter filter = DOM::NodeFilter::createCustom(customFilter);
01056         return getDOMNodeIterator(exec,
01057           doc.createNodeIterator(
01058             toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)),
01059             filter,args[3].toBoolean(exec)));
01060       }// else?
01061     }
01062   case DOMDocument::CreateTreeWalker:
01063     return getDOMTreeWalker(exec,doc.createTreeWalker(toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)),
01064              toNodeFilter(args[2]),args[3].toBoolean(exec)));
01065   case DOMDocument::CreateEvent:
01066     return getDOMEvent(exec,doc.createEvent(s));
01067   case DOMDocument::GetOverrideStyle: {
01068     DOM::Node arg0 = toNode(args[0]);
01069     if (arg0.nodeType() != DOM::Node::ELEMENT_NODE)
01070       return Undefined(); // throw exception?
01071     else
01072       return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string()));
01073   }
01074   case DOMDocument::Abort:
01075     doc.abort();
01076     break;
01077   case DOMDocument::Load: {
01078     Window* active = Window::retrieveActive(exec);
01079     // Complete the URL using the "active part" (running interpreter). We do this for the security
01080     // check and to make sure we load exactly the same url as we have verified to be safe
01081     KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart *>(active->part());
01082     if (khtmlpart) {
01083       // Security: only allow documents to be loaded from the same host
01084       QString dstUrl = khtmlpart->htmlDocument().completeURL(s).string();
01085       KParts::ReadOnlyPart *part = static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part();
01086       if (part->url().host() == KURL(dstUrl).host()) {
01087     kdDebug(6070) << "JavaScript: access granted for document.load() of " << dstUrl << endl;
01088     doc.load(dstUrl);
01089       }
01090       else {
01091     kdDebug(6070) << "JavaScript: access denied for document.load() of " << dstUrl << endl;
01092       }
01093     }
01094     break;
01095   }
01096   case DOMDocument::LoadXML:
01097     doc.loadXML(s);
01098     break;
01099   default:
01100     break;
01101   }
01102 
01103   return Undefined();
01104 }
01105 
01106 // -------------------------------------------------------------------------
01107 
01108 /* Source for DOMElementProtoTable.
01109 @begin DOMElementProtoTable 17
01110   getAttribute      DOMElement::GetAttribute    DontDelete|Function 1
01111   setAttribute      DOMElement::SetAttribute    DontDelete|Function 2
01112   removeAttribute   DOMElement::RemoveAttribute DontDelete|Function 1
01113   getAttributeNode  DOMElement::GetAttributeNode    DontDelete|Function 1
01114   setAttributeNode  DOMElement::SetAttributeNode    DontDelete|Function 2
01115   removeAttributeNode   DOMElement::RemoveAttributeNode DontDelete|Function 1
01116   getElementsByTagName  DOMElement::GetElementsByTagName    DontDelete|Function 1
01117   hasAttribute      DOMElement::HasAttribute    DontDelete|Function 1
01118   getAttributeNS    DOMElement::GetAttributeNS  DontDelete|Function 2
01119   setAttributeNS    DOMElement::SetAttributeNS  DontDelete|Function 3
01120   removeAttributeNS DOMElement::RemoveAttributeNS   DontDelete|Function 2
01121   getAttributeNodeNS    DOMElement::GetAttributeNodeNS  DontDelete|Function 2
01122   setAttributeNodeNS    DOMElement::SetAttributeNodeNS  DontDelete|Function 1
01123   getElementsByTagNameNS DOMElement::GetElementsByTagNameNS DontDelete|Function 2
01124   hasAttributeNS    DOMElement::HasAttributeNS  DontDelete|Function 2
01125 @end
01126 */
01127 DEFINE_PROTOTYPE("DOMElement",DOMElementProto)
01128 IMPLEMENT_PROTOFUNC_DOM(DOMElementProtoFunc)
01129 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMElementProto,DOMElementProtoFunc,DOMNodeProto)
01130 
01131 IMPLEMENT_PSEUDO_CONSTRUCTOR(ElementPseudoCtor, "Element", DOMElementProto)
01132 
01133 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 };
01134 /* Source for DOMElementTable.
01135 @begin DOMElementTable 3
01136   tagName   DOMElement::TagName                         DontDelete|ReadOnly
01137   style     DOMElement::Style                           DontDelete|ReadOnly
01138 @end
01139 */
01140 DOMElement::DOMElement(ExecState *exec, const DOM::Element& e)
01141   : DOMNode(DOMElementProto::self(exec), e) { }
01142 
01143 DOMElement::DOMElement(const Object& proto, const DOM::Element& e)
01144   : DOMNode(proto, e) { }
01145 
01146 Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const
01147 {
01148 #ifdef KJS_VERBOSE
01149   kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl;
01150 #endif
01151   DOM::Element element = static_cast<DOM::Element>(node);
01152 
01153   const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName);
01154   if (entry)
01155   {
01156     switch( entry->value ) {
01157     case TagName:
01158       return String(element.tagName());
01159     case Style:
01160       return getDOMCSSStyleDeclaration(exec,element.style());
01161     default:
01162       kdDebug(6070) << "WARNING: Unhandled token in DOMElement::tryGet : " << entry->value << endl;
01163       break;
01164     }
01165   }
01166   // We have to check in DOMNode before giving access to attributes, otherwise
01167   // onload="..." would make onload return the string (attribute value) instead of
01168   // the listener object (function).
01169   if (DOMNode::hasProperty(exec, propertyName))
01170     return DOMNode::tryGet(exec, propertyName);
01171 
01172   DOM::DOMString attr = element.getAttribute( propertyName.string() );
01173   // Give access to attributes
01174   if ( !attr.isNull() )
01175     return String( attr );
01176 
01177   return Undefined();
01178 }
01179 
01180 Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01181 {
01182   KJS_CHECK_THIS( KJS::DOMNode, thisObj ); // node should be enough here, given the cast
01183   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
01184   DOM::Element element = static_cast<DOM::Element>(node);
01185 
01186   switch(id) {
01187     case DOMElement::GetAttribute:
01191       return getString(element.getAttribute(args[0].toString(exec).string()));
01192     case DOMElement::SetAttribute:
01193       element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string());
01194       return Undefined();
01195     case DOMElement::RemoveAttribute:
01196       element.removeAttribute(args[0].toString(exec).string());
01197       return Undefined();
01198     case DOMElement::GetAttributeNode:
01199       return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string()));
01200     case DOMElement::SetAttributeNode:
01201       return getDOMNode(exec,element.setAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01202     case DOMElement::RemoveAttributeNode:
01203       return getDOMNode(exec,element.removeAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01204     case DOMElement::GetElementsByTagName:
01205       return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string()));
01206     case DOMElement::HasAttribute: // DOM2
01207       return Boolean(element.hasAttribute(args[0].toString(exec).string()));
01208     case DOMElement::GetAttributeNS: // DOM2
01209       return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01210     case DOMElement::SetAttributeNS: // DOM2
01211       element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string());
01212       return Undefined();
01213     case DOMElement::RemoveAttributeNS: // DOM2
01214       element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string());
01215       return Undefined();
01216     case DOMElement::GetAttributeNodeNS: // DOM2
01217       return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01218     case DOMElement::SetAttributeNodeNS: // DOM2
01219       return getDOMNode(exec,element.setAttributeNodeNS((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01220     case DOMElement::GetElementsByTagNameNS: // DOM2
01221       return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01222     case DOMElement::HasAttributeNS: // DOM2
01223       return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01224   default:
01225     return Undefined();
01226   }
01227 }
01228 
01229 // -------------------------------------------------------------------------
01230 
01231 /* Source for DOMDOMImplementationProtoTable.
01232 @begin DOMDOMImplementationProtoTable 5
01233   hasFeature        DOMDOMImplementation::HasFeature        DontDelete|Function 2
01234   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet   DontDelete|Function 2
01235 # DOM2
01236   createDocumentType    DOMDOMImplementation::CreateDocumentType    DontDelete|Function 3
01237   createDocument    DOMDOMImplementation::CreateDocument        DontDelete|Function 3
01238   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
01239 @end
01240 */
01241 DEFINE_PROTOTYPE("DOMImplementation",DOMDOMImplementationProto)
01242 IMPLEMENT_PROTOFUNC_DOM(DOMDOMImplementationProtoFunc)
01243 IMPLEMENT_PROTOTYPE(DOMDOMImplementationProto,DOMDOMImplementationProtoFunc)
01244 
01245 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 };
01246 
01247 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i)
01248   : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { }
01249 
01250 DOMDOMImplementation::~DOMDOMImplementation()
01251 {
01252   ScriptInterpreter::forgetDOMObject(implementation.handle());
01253 }
01254 
01255 Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01256 {
01257   KJS_CHECK_THIS( KJS::DOMDOMImplementation, thisObj );
01258   DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation();
01259 
01260   switch(id) {
01261   case DOMDOMImplementation::HasFeature:
01262     return Boolean(implementation.hasFeature(args[0].toString(exec).string(),args[1].toString(exec).string()));
01263   case DOMDOMImplementation::CreateDocumentType: // DOM2
01264     return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()));
01265   case DOMDOMImplementation::CreateDocument: { // DOM2
01266     // Initially set the URL to document of the creator... this is so that it resides in the same
01267     // host/domain for security checks. The URL will be updated if Document.load() is called.
01268     KHTMLPart *part = ::qt_cast<KHTMLPart*>(static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part());
01269     if (part) {
01270       Document doc = implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2]));
01271       KURL url = static_cast<DocumentImpl*>(part->document().handle())->URL();
01272       static_cast<DocumentImpl*>(doc.handle())->setURL(url.url());
01273       return getDOMNode(exec,doc);
01274     }
01275     break;
01276   }
01277   case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
01278     return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string()));
01279   case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
01280     return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string()));
01281   default:
01282     break;
01283   }
01284   return Undefined();
01285 }
01286 
01287 // -------------------------------------------------------------------------
01288 
01289 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 };
01290 
01291 /* Source for DOMDocumentTypeTable.
01292 @begin DOMDocumentTypeTable 6
01293   name          DOMDocumentType::Name       DontDelete|ReadOnly
01294   entities      DOMDocumentType::Entities   DontDelete|ReadOnly
01295   notations     DOMDocumentType::Notations  DontDelete|ReadOnly
01296 # DOM2
01297   publicId      DOMDocumentType::PublicId   DontDelete|ReadOnly
01298   systemId      DOMDocumentType::SystemId   DontDelete|ReadOnly
01299   internalSubset    DOMDocumentType::InternalSubset DontDelete|ReadOnly
01300 @end
01301 */
01302 DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType& dt)
01303   : DOMNode( /*### no proto yet*/exec, dt ) { }
01304 
01305 Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const
01306 {
01307 #ifdef KJS_VERBOSE
01308   kdDebug(6070) << "DOMDocumentType::tryGet " << propertyName.qstring() << endl;
01309 #endif
01310   return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this);
01311 }
01312 
01313 Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const
01314 {
01315   DOM::DocumentType type = static_cast<DOM::DocumentType>(node);
01316   switch (token) {
01317   case Name:
01318     return String(type.name());
01319   case Entities:
01320     return getDOMNamedNodeMap(exec,type.entities());
01321   case Notations:
01322     return getDOMNamedNodeMap(exec,type.notations());
01323   case PublicId: // DOM2
01324     return String(type.publicId());
01325   case SystemId: // DOM2
01326     return String(type.systemId());
01327   case InternalSubset: // DOM2
01328     return getString(type.internalSubset()); // can be null, see domts/level2/core/internalSubset01.html
01329   default:
01330     kdDebug(6070) << "WARNING: DOMDocumentType::getValueProperty unhandled token " << token << endl;
01331     return Value();
01332   }
01333 }
01334 
01335 // -------------------------------------------------------------------------
01336 
01337 /* Source for DOMNamedNodeMapProtoTable.
01338 @begin DOMNamedNodeMapProtoTable 7
01339   getNamedItem      DOMNamedNodeMap::GetNamedItem       DontDelete|Function 1
01340   setNamedItem      DOMNamedNodeMap::SetNamedItem       DontDelete|Function 1
01341   removeNamedItem   DOMNamedNodeMap::RemoveNamedItem    DontDelete|Function 1
01342   item          DOMNamedNodeMap::Item           DontDelete|Function 1
01343 # DOM2
01344   getNamedItemNS    DOMNamedNodeMap::GetNamedItemNS     DontDelete|Function 2
01345   setNamedItemNS    DOMNamedNodeMap::SetNamedItemNS     DontDelete|Function 1
01346   removeNamedItemNS DOMNamedNodeMap::RemoveNamedItemNS  DontDelete|Function 2
01347 @end
01348 @begin DOMNamedNodeMapTable 7
01349   length        DOMNamedNodeMap::Length         DontDelete|Function 1
01350 @end
01351 */
01352 DEFINE_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto)
01353 IMPLEMENT_PROTOFUNC_DOM(DOMNamedNodeMapProtoFunc)
01354 IMPLEMENT_PROTOTYPE(DOMNamedNodeMapProto,DOMNamedNodeMapProtoFunc)
01355 
01356 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, &DOMNamedNodeMapTable, 0 };
01357 
01358 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m)
01359   : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { }
01360 
01361 DOMNamedNodeMap::~DOMNamedNodeMap()
01362 {
01363   ScriptInterpreter::forgetDOMObject(map.handle());
01364 }
01365 
01366 bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const
01367 {
01368   // ## missing? array index
01369   return DOMObject::hasProperty(exec, p);
01370 }
01371 
01372 Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const
01373 {
01374   if (p == lengthPropertyName)
01375     return Number(map.length());
01376 
01377   // array index ?
01378   bool ok;
01379   long unsigned int idx = p.toULong(&ok);
01380   if (ok)
01381     return getDOMNode(exec,map.item(idx));
01382 
01383   // Anything else (including functions, defined in the prototype)
01384   return DOMObject::tryGet(exec, p);
01385 }
01386 
01387 Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01388 {
01389   KJS_CHECK_THIS( KJS::DOMNamedNodeMap, thisObj );
01390   DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap();
01391 
01392   switch(id) {
01393     case DOMNamedNodeMap::GetNamedItem:
01394       return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string()));
01395     case DOMNamedNodeMap::SetNamedItem:
01396       return getDOMNode(exec, map.setNamedItem((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01397     case DOMNamedNodeMap::RemoveNamedItem:
01398       return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string()));
01399     case DOMNamedNodeMap::Item:
01400       return getDOMNode(exec, map.item(args[0].toInt32(exec)));
01401     case DOMNamedNodeMap::GetNamedItemNS: // DOM2
01402       return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01403     case DOMNamedNodeMap::SetNamedItemNS: // DOM2
01404       return getDOMNode(exec, map.setNamedItemNS(toNode(args[0])));
01405     case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2
01406       return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01407     default:
01408       break;
01409   }
01410 
01411   return Undefined();
01412 }
01413 
01414 // -------------------------------------------------------------------------
01415 
01416 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 };
01417 
01418 /* Source for DOMProcessingInstructionTable.
01419 @begin DOMProcessingInstructionTable 3
01420   target    DOMProcessingInstruction::Target    DontDelete|ReadOnly
01421   data      DOMProcessingInstruction::Data      DontDelete
01422   sheet     DOMProcessingInstruction::Sheet     DontDelete|ReadOnly
01423 @end
01424 */
01425 Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const
01426 {
01427   return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this);
01428 }
01429 
01430 Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
01431 {
01432   switch (token) {
01433   case Target:
01434     return String(static_cast<DOM::ProcessingInstruction>(node).target());
01435   case Data:
01436     return String(static_cast<DOM::ProcessingInstruction>(node).data());
01437   case Sheet:
01438     return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet());
01439   default:
01440     kdDebug(6070) << "WARNING: DOMProcessingInstruction::getValueProperty unhandled token " << token << endl;
01441     return Value();
01442   }
01443 }
01444 
01445 void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
01446 {
01447   // Not worth using the hashtable for this one ;)
01448   if (propertyName == "data")
01449     static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string());
01450   else
01451     DOMNode::tryPut(exec, propertyName,value,attr);
01452 }
01453 
01454 // -------------------------------------------------------------------------
01455 
01456 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 };
01457 
01458 /* Source for DOMNotationTable.
01459 @begin DOMNotationTable 2
01460   publicId      DOMNotation::PublicId   DontDelete|ReadOnly
01461   systemId      DOMNotation::SystemId   DontDelete|ReadOnly
01462 @end
01463 */
01464 Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const
01465 {
01466   return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this);
01467 }
01468 
01469 Value DOMNotation::getValueProperty(ExecState *, int token) const
01470 {
01471   switch (token) {
01472   case PublicId:
01473     return String(static_cast<DOM::Notation>(node).publicId());
01474   case SystemId:
01475     return String(static_cast<DOM::Notation>(node).systemId());
01476   default:
01477     kdDebug(6070) << "WARNING: DOMNotation::getValueProperty unhandled token " << token << endl;
01478     return Value();
01479   }
01480 }
01481 
01482 // -------------------------------------------------------------------------
01483 
01484 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 };
01485 
01486 /* Source for DOMEntityTable.
01487 @begin DOMEntityTable 2
01488   publicId      DOMEntity::PublicId     DontDelete|ReadOnly
01489   systemId      DOMEntity::SystemId     DontDelete|ReadOnly
01490   notationName      DOMEntity::NotationName DontDelete|ReadOnly
01491 @end
01492 */
01493 Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const
01494 {
01495   return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this);
01496 }
01497 
01498 Value DOMEntity::getValueProperty(ExecState *, int token) const
01499 {
01500   switch (token) {
01501   case PublicId:
01502     return String(static_cast<DOM::Entity>(node).publicId());
01503   case SystemId:
01504     return String(static_cast<DOM::Entity>(node).systemId());
01505   case NotationName:
01506     return String(static_cast<DOM::Entity>(node).notationName());
01507   default:
01508     kdDebug(6070) << "WARNING: DOMEntity::getValueProperty unhandled token " << token << endl;
01509     return Value();
01510   }
01511 }
01512 
01513 // -------------------------------------------------------------------------
01514 
01515 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::Node& n)
01516 {
01517   // Check to see if the currently executing interpreter is allowed to access the specified node
01518   if (n.isNull())
01519     return true;
01520   KHTMLView *view = n.handle()->getDocument()->view();
01521   Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L;
01522   if ( !win || !win->isSafeScript(exec) )
01523     return false;
01524   return true;
01525 }
01526 
01527 Value KJS::getDOMNode(ExecState *exec, const DOM::Node& n)
01528 {
01529   DOMObject *ret = 0;
01530   if (n.isNull())
01531     return Null();
01532   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter());
01533   if ((ret = interp->getDOMObject(n.handle())))
01534     return Value(ret);
01535 
01536   switch (n.nodeType()) {
01537     case DOM::Node::ELEMENT_NODE:
01538       if (static_cast<DOM::Element>(n).isHTMLElement())
01539         ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n));
01540       else
01541         ret = new DOMElement(exec, static_cast<DOM::Element>(n));
01542       break;
01543     case DOM::Node::ATTRIBUTE_NODE:
01544       ret = new DOMAttr(exec, static_cast<DOM::Attr>(n));
01545       break;
01546     case DOM::Node::TEXT_NODE:
01547     case DOM::Node::CDATA_SECTION_NODE:
01548       ret = new DOMText(exec, static_cast<DOM::Text>(n));
01549       break;
01550     case DOM::Node::ENTITY_REFERENCE_NODE:
01551       ret = new DOMNode(exec, n);
01552       break;
01553     case DOM::Node::ENTITY_NODE:
01554       ret = new DOMEntity(exec, static_cast<DOM::Entity>(n));
01555       break;
01556     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
01557       ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n));
01558       break;
01559     case DOM::Node::COMMENT_NODE:
01560       ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n));
01561       break;
01562     case DOM::Node::DOCUMENT_NODE:
01563       if (static_cast<DOM::Document>(n).isHTMLDocument())
01564         ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n));
01565       else
01566         ret = new DOMDocument(exec, static_cast<DOM::Document>(n));
01567       break;
01568     case DOM::Node::DOCUMENT_TYPE_NODE:
01569       ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n));
01570       break;
01571     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
01572       ret = new DOMNode(exec, n);
01573       break;
01574     case DOM::Node::NOTATION_NODE:
01575       ret = new DOMNotation(exec, static_cast<DOM::Notation>(n));
01576       break;
01577     default:
01578       ret = new DOMNode(exec, n);
01579   }
01580   interp->putDOMObject(n.handle(),ret);
01581 
01582   return Value(ret);
01583 }
01584 
01585 Value KJS::getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m)
01586 {
01587   return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m));
01588 }
01589 
01590 Value KJS::getDOMNodeList(ExecState *exec, const DOM::NodeList& l)
01591 {
01592   return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l));
01593 }
01594 
01595 Value KJS::getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i)
01596 {
01597   return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i));
01598 }
01599 
01600 // -------------------------------------------------------------------------
01601 IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(NodeConstructor, "NodeConstructor", DOMNodeProto, DOMNodeConstants)
01602 // -------------------------------------------------------------------------
01603 
01604 const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 };
01605 
01606 /* Source for DOMExceptionConstructorTable.
01607 @begin DOMExceptionConstructorTable 15
01608   INDEX_SIZE_ERR        DOM::DOMException::INDEX_SIZE_ERR       DontDelete|ReadOnly
01609   DOMSTRING_SIZE_ERR        DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
01610   HIERARCHY_REQUEST_ERR     DOM::DOMException::HIERARCHY_REQUEST_ERR    DontDelete|ReadOnly
01611   WRONG_DOCUMENT_ERR        DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
01612   INVALID_CHARACTER_ERR     DOM::DOMException::INVALID_CHARACTER_ERR    DontDelete|ReadOnly
01613   NO_DATA_ALLOWED_ERR       DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
01614   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
01615   NOT_FOUND_ERR         DOM::DOMException::NOT_FOUND_ERR        DontDelete|ReadOnly
01616   NOT_SUPPORTED_ERR     DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
01617   INUSE_ATTRIBUTE_ERR       DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
01618   INVALID_STATE_ERR     DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
01619   SYNTAX_ERR            DOM::DOMException::SYNTAX_ERR       DontDelete|ReadOnly
01620   INVALID_MODIFICATION_ERR  DOM::DOMException::INVALID_MODIFICATION_ERR DontDelete|ReadOnly
01621   NAMESPACE_ERR         DOM::DOMException::NAMESPACE_ERR        DontDelete|ReadOnly
01622   INVALID_ACCESS_ERR        DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
01623 @end
01624 */
01625 
01626 DOMExceptionConstructor::DOMExceptionConstructor(ExecState* exec)
01627   : DOMObject(exec->interpreter()->builtinObjectPrototype())
01628 {
01629 }
01630 
01631 Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
01632 {
01633   return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this);
01634 }
01635 
01636 Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const
01637 {
01638   // We use the token as the value to return directly
01639   return Number((unsigned int)token);
01640 #if 0
01641   switch (token) {
01642   case INDEX_SIZE_ERR:
01643     return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR);
01644   case DOMSTRING_SIZE_ERR:
01645     return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR);
01646   case HIERARCHY_REQUEST_ERR:
01647     return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR);
01648   case WRONG_DOCUMENT_ERR:
01649     return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR);
01650   case INVALID_CHARACTER_ERR:
01651     return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR);
01652   case NO_DATA_ALLOWED_ERR:
01653     return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR);
01654   case NO_MODIFICATION_ALLOWED_ERR:
01655     return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR);
01656   case NOT_FOUND_ERR:
01657     return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR);
01658   case NOT_SUPPORTED_ERR:
01659     return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR);
01660   case INUSE_ATTRIBUTE_ERR:
01661     return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR);
01662   case INVALID_STATE_ERR:
01663     return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR);
01664   case SYNTAX_ERR:
01665     return Number((unsigned int)DOM::DOMException::SYNTAX_ERR);
01666   case INVALID_MODIFICATION_ERR:
01667     return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR);
01668   case NAMESPACE_ERR:
01669     return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR);
01670   case INVALID_ACCESS_ERR:
01671     return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR);
01672   default:
01673     kdDebug(6070) << "WARNING: DOMExceptionConstructor::getValueProperty unhandled token " << token << endl;
01674     return Value();
01675   }
01676 #endif
01677 }
01678 
01679 Object KJS::getDOMExceptionConstructor(ExecState *exec)
01680 {
01681   return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]");
01682 }
01683 
01684 // -------------------------------------------------------------------------
01685 
01686 /* Source for DOMNamedNodesCollection.
01687 @begin DOMNamedNodesCollectionTable 1
01688   length        KJS::DOMNamedNodesCollection::Length        DontDelete|ReadOnly
01689 @end
01690 */
01691 const ClassInfo KJS::DOMNamedNodesCollection::info = { "DOMNamedNodesCollection", 0, &DOMNamedNodesCollectionTable, 0 };
01692 
01693 // Such a collection is usually very short-lived, it only exists
01694 // for constructs like document.forms.<name>[1],
01695 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
01696 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *exec, const QValueList<DOM::Node>& nodes )
01697   : DOMObject(exec->interpreter()->builtinObjectPrototype()),
01698   m_nodes(nodes)
01699 {
01700   // Maybe we should ref (and deref in the dtor) the nodes, though ?
01701 }
01702 
01703 Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const
01704 {
01705   kdDebug(6070) << k_funcinfo << propertyName.ascii() << endl;
01706   if (propertyName == lengthPropertyName)
01707     return Number(m_nodes.count());
01708   // index?
01709   bool ok;
01710   unsigned int u = propertyName.toULong(&ok);
01711   if (ok && u < m_nodes.count()) {
01712     DOM::Node node = m_nodes[u];
01713     return getDOMNode(exec,node);
01714   }
01715   return DOMObject::tryGet(exec,propertyName);
01716 }
01717 
01718 // -------------------------------------------------------------------------
01719 
01720 const ClassInfo DOMCharacterData::info = { "CharacterImp",
01721                       &DOMNode::info, &DOMCharacterDataTable, 0 };
01722 /*
01723 @begin DOMCharacterDataTable 2
01724   data      DOMCharacterData::Data      DontDelete
01725   length    DOMCharacterData::Length    DontDelete|ReadOnly
01726 @end
01727 @begin DOMCharacterDataProtoTable 7
01728   substringData DOMCharacterData::SubstringData DontDelete|Function 2
01729   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
01730   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
01731   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
01732   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
01733 @end
01734 */
01735 DEFINE_PROTOTYPE("DOMCharacterData",DOMCharacterDataProto)
01736 IMPLEMENT_PROTOFUNC_DOM(DOMCharacterDataProtoFunc)
01737 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMCharacterDataProto,DOMCharacterDataProtoFunc, DOMNodeProto)
01738 
01739 DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData& d)
01740  : DOMNode(DOMCharacterDataProto::self(exec), d) {}
01741 
01742 DOMCharacterData::DOMCharacterData(const Object& proto, const DOM::CharacterData& d)
01743  : DOMNode(proto, d) {}
01744 
01745 Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const
01746 {
01747 #ifdef KJS_VERBOSE
01748   kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl;
01749 #endif
01750   return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this);
01751 }
01752 
01753 Value DOMCharacterData::getValueProperty(ExecState *, int token) const
01754 {
01755   DOM::CharacterData data = static_cast<DOM::CharacterData>(node);
01756   switch (token) {
01757   case Data:
01758     return String(data.data());
01759   case Length:
01760     return Number(data.length());
01761  default:
01762    kdDebug(6070) << "WARNING: Unhandled token in DOMCharacterData::getValueProperty : " << token << endl;
01763    return Value();
01764   }
01765 }
01766 
01767 void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
01768 {
01769   if (propertyName == "data")
01770     static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string());
01771   else
01772     DOMNode::tryPut(exec, propertyName,value,attr);
01773 }
01774 
01775 Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01776 {
01777   KJS_CHECK_THIS( KJS::DOMCharacterData, thisObj );
01778   DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData();
01779   switch(id) {
01780     case DOMCharacterData::SubstringData:
01781       return String(data.substringData(args[0].toInteger(exec),args[1].toInteger(exec)));
01782     case DOMCharacterData::AppendData:
01783       data.appendData(args[0].toString(exec).string());
01784       return Undefined();
01785       break;
01786     case DOMCharacterData::InsertData:
01787       data.insertData(args[0].toInteger(exec),args[1].toString(exec).string());
01788       return  Undefined();
01789       break;
01790     case DOMCharacterData::DeleteData:
01791       data.deleteData(args[0].toInteger(exec),args[1].toInteger(exec));
01792       return  Undefined();
01793       break;
01794     case DOMCharacterData::ReplaceData:
01795       data.replaceData(args[0].toInteger(exec),args[1].toInteger(exec),args[2].toString(exec).string());
01796       return Undefined();
01797     default:
01798       break;
01799   }
01800   return Undefined();
01801 }
01802 
01803 // -------------------------------------------------------------------------
01804 
01805 const ClassInfo DOMText::info = { "Text",
01806                  &DOMCharacterData::info, 0, 0 };
01807 /*
01808 @begin DOMTextProtoTable 1
01809   splitText DOMText::SplitText  DontDelete|Function 1
01810 @end
01811 */
01812 DEFINE_PROTOTYPE("DOMText",DOMTextProto)
01813 IMPLEMENT_PROTOFUNC_DOM(DOMTextProtoFunc)
01814 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMTextProto,DOMTextProtoFunc,DOMCharacterDataProto)
01815 
01816 DOMText::DOMText(ExecState *exec, const DOM::Text& t)
01817   : DOMCharacterData(DOMTextProto::self(exec), t) { }
01818 
01819 Value DOMText::tryGet(ExecState *exec, const Identifier &p) const
01820 {
01821   if (p.isEmpty())
01822     return Undefined(); // ### TODO
01823   else
01824     return DOMCharacterData::tryGet(exec, p);
01825 }
01826 
01827 Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01828 {
01829   KJS_CHECK_THIS( KJS::DOMText, thisObj );
01830   DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText();
01831   switch(id) {
01832     case DOMText::SplitText:
01833       return getDOMNode(exec,text.splitText(args[0].toInteger(exec)));
01834     default:
01835       break;
01836   }
01837   return Undefined();
01838 }
KDE Home | KDE Accessibility Home | Description of Access Keys