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     if (docImpl->part())
00936       return String(docImpl->part()->encoding());
00937     else
00938       return Undefined();
00939   }
00940   case StyleSheets:
00941     //kdDebug() << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets" << endl;
00942     return getDOMStyleSheetList(exec, doc.styleSheets(), doc);
00943   case DOMDocument::DefaultView: // DOM2
00944     {
00945     KHTMLView *view = node.handle()->getDocument()->view();
00946     if (view)
00947         return Window::retrieve(view->part());
00948     return getDOMAbstractView(exec, doc.defaultView());
00949     }
00950   case PreferredStylesheetSet:
00951     return String(doc.preferredStylesheetSet());
00952   case SelectedStylesheetSet:
00953     return String(doc.selectedStylesheetSet());
00954   case ReadyState:
00955     {
00956     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
00957     if ( docimpl && docimpl->view() )
00958     {
00959       KHTMLPart* part = docimpl->view()->part();
00960       if ( part ) {
00961         if (part->d->m_bComplete) return String("complete");
00962         if (docimpl->parsing()) return String("loading");
00963         return String("loaded");
00964         // What does the interactive value mean ?
00965         // Missing support for "uninitialized"
00966       }
00967     }
00968     return Undefined();
00969     }
00970   case Async:
00971     return Boolean(doc.async());
00972   default:
00973     kdDebug(6070) << "WARNING: DOMDocument::getValueProperty unhandled token " << token << endl;
00974     return Value();
00975   }
00976 }
00977 
00978 void DOMDocument::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
00979 {
00980 #ifdef KJS_VERBOSE
00981   kdDebug(6070) << "DOMDocument::tryPut " << propertyName.qstring() << endl;
00982 #endif
00983   DOMObjectLookupPut<DOMDocument,DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this );
00984 }
00985 
00986 void DOMDocument::putValueProperty(ExecState *exec, int token, const Value& value, int /*attr*/)
00987 {
00988   DOM::Document doc = static_cast<DOM::Document>(node);
00989   switch (token) {
00990     case SelectedStylesheetSet: {
00991       doc.setSelectedStylesheetSet(value.toString(exec).string());
00992       break;
00993     }
00994     case Async: {
00995       doc.setAsync(value.toBoolean(exec));
00996       break;
00997     }
00998   }
00999 }
01000 
01001 Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01002 {
01003   KJS_CHECK_THIS( KJS::DOMDocument, thisObj );
01004   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
01005   DOM::Document doc = static_cast<DOM::Document>(node);
01006   String str = args[0].toString(exec);
01007   DOM::DOMString s = str.value().string();
01008 
01009   switch(id) {
01010   case DOMDocument::CreateElement:
01011     return getDOMNode(exec,doc.createElement(s));
01012   case DOMDocument::CreateDocumentFragment:
01013     return getDOMNode(exec,doc.createDocumentFragment());
01014   case DOMDocument::CreateTextNode:
01015     return getDOMNode(exec,doc.createTextNode(s));
01016   case DOMDocument::CreateComment:
01017     return getDOMNode(exec,doc.createComment(s));
01018   case DOMDocument::CreateCDATASection:
01019     return getDOMNode(exec,doc.createCDATASection(s));  /* TODO: okay ? */
01020   case DOMDocument::CreateProcessingInstruction:
01021     return getDOMNode(exec,doc.createProcessingInstruction(args[0].toString(exec).string(),
01022                                                                  args[1].toString(exec).string()));
01023   case DOMDocument::CreateAttribute:
01024     return getDOMNode(exec,doc.createAttribute(s));
01025   case DOMDocument::CreateEntityReference:
01026     return getDOMNode(exec,doc.createEntityReference(args[0].toString(exec).string()));
01027   case DOMDocument::GetElementsByTagName:
01028     return getDOMNodeList(exec,doc.getElementsByTagName(s));
01029   case DOMDocument::ImportNode: // DOM2
01030     return getDOMNode(exec,doc.importNode(toNode(args[0]), args[1].toBoolean(exec)));
01031   case DOMDocument::CreateElementNS: // DOM2
01032     return getDOMNode(exec,doc.createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
01033   case DOMDocument::CreateAttributeNS: // DOM2
01034     return getDOMNode(exec,doc.createAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01035   case DOMDocument::GetElementsByTagNameNS: // DOM2
01036     return getDOMNodeList(exec,doc.getElementsByTagNameNS(args[0].toString(exec).string(),
01037                                                           args[1].toString(exec).string()));
01038   case DOMDocument::GetElementById:
01039 #ifdef KJS_VERBOSE
01040   kdDebug(6070) << "DOMDocument::GetElementById looking for " << args[0].toString(exec).string() << endl;
01041 #endif
01042     return getDOMNode(exec,doc.getElementById(args[0].toString(exec).string()));
01043   case DOMDocument::CreateRange:
01044     return getDOMRange(exec,doc.createRange());
01045   case DOMDocument::CreateNodeIterator:
01046     if (args[2].isA(NullType)) {
01047         DOM::NodeFilter filter;
01048         return getDOMNodeIterator(exec,
01049                                   doc.createNodeIterator(toNode(args[0]),
01050                                                          (long unsigned int)(args[1].toNumber(exec)),
01051                                                          filter,args[3].toBoolean(exec)));
01052     }
01053     else {
01054       Object obj = Object::dynamicCast(args[2]);
01055       if (obj.isValid())
01056       {
01057         DOM::CustomNodeFilter *customFilter = new JSNodeFilter(obj);
01058         DOM::NodeFilter filter = DOM::NodeFilter::createCustom(customFilter);
01059         return getDOMNodeIterator(exec,
01060           doc.createNodeIterator(
01061             toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)),
01062             filter,args[3].toBoolean(exec)));
01063       }// else?
01064     }
01065   case DOMDocument::CreateTreeWalker:
01066     return getDOMTreeWalker(exec,doc.createTreeWalker(toNode(args[0]),(long unsigned int)(args[1].toNumber(exec)),
01067              toNodeFilter(args[2]),args[3].toBoolean(exec)));
01068   case DOMDocument::CreateEvent:
01069     return getDOMEvent(exec,doc.createEvent(s));
01070   case DOMDocument::GetOverrideStyle: {
01071     DOM::Node arg0 = toNode(args[0]);
01072     if (arg0.nodeType() != DOM::Node::ELEMENT_NODE)
01073       return Undefined(); // throw exception?
01074     else
01075       return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string()));
01076   }
01077   case DOMDocument::Abort:
01078     doc.abort();
01079     break;
01080   case DOMDocument::Load: {
01081     Window* active = Window::retrieveActive(exec);
01082     // Complete the URL using the "active part" (running interpreter). We do this for the security
01083     // check and to make sure we load exactly the same url as we have verified to be safe
01084     KHTMLPart *khtmlpart = ::qt_cast<KHTMLPart *>(active->part());
01085     if (khtmlpart) {
01086       // Security: only allow documents to be loaded from the same host
01087       QString dstUrl = khtmlpart->htmlDocument().completeURL(s).string();
01088       KParts::ReadOnlyPart *part = static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part();
01089       if (part->url().host() == KURL(dstUrl).host()) {
01090     kdDebug(6070) << "JavaScript: access granted for document.load() of " << dstUrl << endl;
01091     doc.load(dstUrl);
01092       }
01093       else {
01094     kdDebug(6070) << "JavaScript: access denied for document.load() of " << dstUrl << endl;
01095       }
01096     }
01097     break;
01098   }
01099   case DOMDocument::LoadXML:
01100     doc.loadXML(s);
01101     break;
01102   default:
01103     break;
01104   }
01105 
01106   return Undefined();
01107 }
01108 
01109 // -------------------------------------------------------------------------
01110 
01111 /* Source for DOMElementProtoTable.
01112 @begin DOMElementProtoTable 17
01113   getAttribute      DOMElement::GetAttribute    DontDelete|Function 1
01114   setAttribute      DOMElement::SetAttribute    DontDelete|Function 2
01115   removeAttribute   DOMElement::RemoveAttribute DontDelete|Function 1
01116   getAttributeNode  DOMElement::GetAttributeNode    DontDelete|Function 1
01117   setAttributeNode  DOMElement::SetAttributeNode    DontDelete|Function 2
01118   removeAttributeNode   DOMElement::RemoveAttributeNode DontDelete|Function 1
01119   getElementsByTagName  DOMElement::GetElementsByTagName    DontDelete|Function 1
01120   hasAttribute      DOMElement::HasAttribute    DontDelete|Function 1
01121   getAttributeNS    DOMElement::GetAttributeNS  DontDelete|Function 2
01122   setAttributeNS    DOMElement::SetAttributeNS  DontDelete|Function 3
01123   removeAttributeNS DOMElement::RemoveAttributeNS   DontDelete|Function 2
01124   getAttributeNodeNS    DOMElement::GetAttributeNodeNS  DontDelete|Function 2
01125   setAttributeNodeNS    DOMElement::SetAttributeNodeNS  DontDelete|Function 1
01126   getElementsByTagNameNS DOMElement::GetElementsByTagNameNS DontDelete|Function 2
01127   hasAttributeNS    DOMElement::HasAttributeNS  DontDelete|Function 2
01128 @end
01129 */
01130 DEFINE_PROTOTYPE("DOMElement",DOMElementProto)
01131 IMPLEMENT_PROTOFUNC_DOM(DOMElementProtoFunc)
01132 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMElementProto,DOMElementProtoFunc,DOMNodeProto)
01133 
01134 IMPLEMENT_PSEUDO_CONSTRUCTOR(ElementPseudoCtor, "Element", DOMElementProto)
01135 
01136 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 };
01137 /* Source for DOMElementTable.
01138 @begin DOMElementTable 3
01139   tagName   DOMElement::TagName                         DontDelete|ReadOnly
01140   style     DOMElement::Style                           DontDelete|ReadOnly
01141 @end
01142 */
01143 DOMElement::DOMElement(ExecState *exec, const DOM::Element& e)
01144   : DOMNode(DOMElementProto::self(exec), e) { }
01145 
01146 DOMElement::DOMElement(const Object& proto, const DOM::Element& e)
01147   : DOMNode(proto, e) { }
01148 
01149 Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const
01150 {
01151 #ifdef KJS_VERBOSE
01152   kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl;
01153 #endif
01154   DOM::Element element = static_cast<DOM::Element>(node);
01155 
01156   const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName);
01157   if (entry)
01158   {
01159     switch( entry->value ) {
01160     case TagName:
01161       return String(element.tagName());
01162     case Style:
01163       return getDOMCSSStyleDeclaration(exec,element.style());
01164     default:
01165       kdDebug(6070) << "WARNING: Unhandled token in DOMElement::tryGet : " << entry->value << endl;
01166       break;
01167     }
01168   }
01169   // We have to check in DOMNode before giving access to attributes, otherwise
01170   // onload="..." would make onload return the string (attribute value) instead of
01171   // the listener object (function).
01172   if (DOMNode::hasProperty(exec, propertyName))
01173     return DOMNode::tryGet(exec, propertyName);
01174 
01175   DOM::DOMString attr = element.getAttribute( propertyName.string() );
01176   // Give access to attributes
01177   if ( !attr.isNull() )
01178     return String( attr );
01179 
01180   return Undefined();
01181 }
01182 
01183 Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01184 {
01185   KJS_CHECK_THIS( KJS::DOMNode, thisObj ); // node should be enough here, given the cast
01186   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
01187   DOM::Element element = static_cast<DOM::Element>(node);
01188 
01189   switch(id) {
01190     case DOMElement::GetAttribute:
01194       return getString(element.getAttribute(args[0].toString(exec).string()));
01195     case DOMElement::SetAttribute:
01196       element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string());
01197       return Undefined();
01198     case DOMElement::RemoveAttribute:
01199       element.removeAttribute(args[0].toString(exec).string());
01200       return Undefined();
01201     case DOMElement::GetAttributeNode:
01202       return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string()));
01203     case DOMElement::SetAttributeNode:
01204       return getDOMNode(exec,element.setAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01205     case DOMElement::RemoveAttributeNode:
01206       return getDOMNode(exec,element.removeAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01207     case DOMElement::GetElementsByTagName:
01208       return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string()));
01209     case DOMElement::HasAttribute: // DOM2
01210       return Boolean(element.hasAttribute(args[0].toString(exec).string()));
01211     case DOMElement::GetAttributeNS: // DOM2
01212       return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01213     case DOMElement::SetAttributeNS: // DOM2
01214       element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string());
01215       return Undefined();
01216     case DOMElement::RemoveAttributeNS: // DOM2
01217       element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string());
01218       return Undefined();
01219     case DOMElement::GetAttributeNodeNS: // DOM2
01220       return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01221     case DOMElement::SetAttributeNodeNS: // DOM2
01222       return getDOMNode(exec,element.setAttributeNodeNS((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01223     case DOMElement::GetElementsByTagNameNS: // DOM2
01224       return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01225     case DOMElement::HasAttributeNS: // DOM2
01226       return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01227   default:
01228     return Undefined();
01229   }
01230 }
01231 
01232 // -------------------------------------------------------------------------
01233 
01234 /* Source for DOMDOMImplementationProtoTable.
01235 @begin DOMDOMImplementationProtoTable 5
01236   hasFeature        DOMDOMImplementation::HasFeature        DontDelete|Function 2
01237   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet   DontDelete|Function 2
01238 # DOM2
01239   createDocumentType    DOMDOMImplementation::CreateDocumentType    DontDelete|Function 3
01240   createDocument    DOMDOMImplementation::CreateDocument        DontDelete|Function 3
01241   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
01242 @end
01243 */
01244 DEFINE_PROTOTYPE("DOMImplementation",DOMDOMImplementationProto)
01245 IMPLEMENT_PROTOFUNC_DOM(DOMDOMImplementationProtoFunc)
01246 IMPLEMENT_PROTOTYPE(DOMDOMImplementationProto,DOMDOMImplementationProtoFunc)
01247 
01248 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 };
01249 
01250 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i)
01251   : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { }
01252 
01253 DOMDOMImplementation::~DOMDOMImplementation()
01254 {
01255   ScriptInterpreter::forgetDOMObject(implementation.handle());
01256 }
01257 
01258 Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01259 {
01260   KJS_CHECK_THIS( KJS::DOMDOMImplementation, thisObj );
01261   DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation();
01262 
01263   switch(id) {
01264   case DOMDOMImplementation::HasFeature:
01265     return Boolean(implementation.hasFeature(args[0].toString(exec).string(),args[1].toString(exec).string()));
01266   case DOMDOMImplementation::CreateDocumentType: // DOM2
01267     return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()));
01268   case DOMDOMImplementation::CreateDocument: { // DOM2
01269     // Initially set the URL to document of the creator... this is so that it resides in the same
01270     // host/domain for security checks. The URL will be updated if Document.load() is called.
01271     KHTMLPart *part = ::qt_cast<KHTMLPart*>(static_cast<KJS::ScriptInterpreter*>(exec->interpreter())->part());
01272     if (part) {
01273       Document doc = implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2]));
01274       KURL url = static_cast<DocumentImpl*>(part->document().handle())->URL();
01275       static_cast<DocumentImpl*>(doc.handle())->setURL(url.url());
01276       return getDOMNode(exec,doc);
01277     }
01278     break;
01279   }
01280   case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
01281     return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string()));
01282   case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
01283     return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string()));
01284   default:
01285     break;
01286   }
01287   return Undefined();
01288 }
01289 
01290 // -------------------------------------------------------------------------
01291 
01292 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 };
01293 
01294 /* Source for DOMDocumentTypeTable.
01295 @begin DOMDocumentTypeTable 6
01296   name          DOMDocumentType::Name       DontDelete|ReadOnly
01297   entities      DOMDocumentType::Entities   DontDelete|ReadOnly
01298   notations     DOMDocumentType::Notations  DontDelete|ReadOnly
01299 # DOM2
01300   publicId      DOMDocumentType::PublicId   DontDelete|ReadOnly
01301   systemId      DOMDocumentType::SystemId   DontDelete|ReadOnly
01302   internalSubset    DOMDocumentType::InternalSubset DontDelete|ReadOnly
01303 @end
01304 */
01305 DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType& dt)
01306   : DOMNode( /*### no proto yet*/exec, dt ) { }
01307 
01308 Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const
01309 {
01310 #ifdef KJS_VERBOSE
01311   kdDebug(6070) << "DOMDocumentType::tryGet " << propertyName.qstring() << endl;
01312 #endif
01313   return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this);
01314 }
01315 
01316 Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const
01317 {
01318   DOM::DocumentType type = static_cast<DOM::DocumentType>(node);
01319   switch (token) {
01320   case Name:
01321     return String(type.name());
01322   case Entities:
01323     return getDOMNamedNodeMap(exec,type.entities());
01324   case Notations:
01325     return getDOMNamedNodeMap(exec,type.notations());
01326   case PublicId: // DOM2
01327     return String(type.publicId());
01328   case SystemId: // DOM2
01329     return String(type.systemId());
01330   case InternalSubset: // DOM2
01331     return getString(type.internalSubset()); // can be null, see domts/level2/core/internalSubset01.html
01332   default:
01333     kdDebug(6070) << "WARNING: DOMDocumentType::getValueProperty unhandled token " << token << endl;
01334     return Value();
01335   }
01336 }
01337 
01338 // -------------------------------------------------------------------------
01339 
01340 /* Source for DOMNamedNodeMapProtoTable.
01341 @begin DOMNamedNodeMapProtoTable 7
01342   getNamedItem      DOMNamedNodeMap::GetNamedItem       DontDelete|Function 1
01343   setNamedItem      DOMNamedNodeMap::SetNamedItem       DontDelete|Function 1
01344   removeNamedItem   DOMNamedNodeMap::RemoveNamedItem    DontDelete|Function 1
01345   item          DOMNamedNodeMap::Item           DontDelete|Function 1
01346 # DOM2
01347   getNamedItemNS    DOMNamedNodeMap::GetNamedItemNS     DontDelete|Function 2
01348   setNamedItemNS    DOMNamedNodeMap::SetNamedItemNS     DontDelete|Function 1
01349   removeNamedItemNS DOMNamedNodeMap::RemoveNamedItemNS  DontDelete|Function 2
01350 @end
01351 @begin DOMNamedNodeMapTable 7
01352   length        DOMNamedNodeMap::Length         DontDelete|Function 1
01353 @end
01354 */
01355 DEFINE_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto)
01356 IMPLEMENT_PROTOFUNC_DOM(DOMNamedNodeMapProtoFunc)
01357 IMPLEMENT_PROTOTYPE(DOMNamedNodeMapProto,DOMNamedNodeMapProtoFunc)
01358 
01359 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, &DOMNamedNodeMapTable, 0 };
01360 
01361 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m)
01362   : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { }
01363 
01364 DOMNamedNodeMap::~DOMNamedNodeMap()
01365 {
01366   ScriptInterpreter::forgetDOMObject(map.handle());
01367 }
01368 
01369 bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const
01370 {
01371   // ## missing? array index
01372   return DOMObject::hasProperty(exec, p);
01373 }
01374 
01375 Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const
01376 {
01377   if (p == lengthPropertyName)
01378     return Number(map.length());
01379 
01380   // array index ?
01381   bool ok;
01382   long unsigned int idx = p.toULong(&ok);
01383   if (ok)
01384     return getDOMNode(exec,map.item(idx));
01385 
01386   // Anything else (including functions, defined in the prototype)
01387   return DOMObject::tryGet(exec, p);
01388 }
01389 
01390 Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01391 {
01392   KJS_CHECK_THIS( KJS::DOMNamedNodeMap, thisObj );
01393   DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap();
01394 
01395   switch(id) {
01396     case DOMNamedNodeMap::GetNamedItem:
01397       return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string()));
01398     case DOMNamedNodeMap::SetNamedItem:
01399       return getDOMNode(exec, map.setNamedItem((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
01400     case DOMNamedNodeMap::RemoveNamedItem:
01401       return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string()));
01402     case DOMNamedNodeMap::Item:
01403       return getDOMNode(exec, map.item(args[0].toInt32(exec)));
01404     case DOMNamedNodeMap::GetNamedItemNS: // DOM2
01405       return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01406     case DOMNamedNodeMap::SetNamedItemNS: // DOM2
01407       return getDOMNode(exec, map.setNamedItemNS(toNode(args[0])));
01408     case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2
01409       return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
01410     default:
01411       break;
01412   }
01413 
01414   return Undefined();
01415 }
01416 
01417 // -------------------------------------------------------------------------
01418 
01419 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 };
01420 
01421 /* Source for DOMProcessingInstructionTable.
01422 @begin DOMProcessingInstructionTable 3
01423   target    DOMProcessingInstruction::Target    DontDelete|ReadOnly
01424   data      DOMProcessingInstruction::Data      DontDelete
01425   sheet     DOMProcessingInstruction::Sheet     DontDelete|ReadOnly
01426 @end
01427 */
01428 Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const
01429 {
01430   return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this);
01431 }
01432 
01433 Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
01434 {
01435   switch (token) {
01436   case Target:
01437     return String(static_cast<DOM::ProcessingInstruction>(node).target());
01438   case Data:
01439     return String(static_cast<DOM::ProcessingInstruction>(node).data());
01440   case Sheet:
01441     return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet());
01442   default:
01443     kdDebug(6070) << "WARNING: DOMProcessingInstruction::getValueProperty unhandled token " << token << endl;
01444     return Value();
01445   }
01446 }
01447 
01448 void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
01449 {
01450   // Not worth using the hashtable for this one ;)
01451   if (propertyName == "data")
01452     static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string());
01453   else
01454     DOMNode::tryPut(exec, propertyName,value,attr);
01455 }
01456 
01457 // -------------------------------------------------------------------------
01458 
01459 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 };
01460 
01461 /* Source for DOMNotationTable.
01462 @begin DOMNotationTable 2
01463   publicId      DOMNotation::PublicId   DontDelete|ReadOnly
01464   systemId      DOMNotation::SystemId   DontDelete|ReadOnly
01465 @end
01466 */
01467 Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const
01468 {
01469   return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this);
01470 }
01471 
01472 Value DOMNotation::getValueProperty(ExecState *, int token) const
01473 {
01474   switch (token) {
01475   case PublicId:
01476     return String(static_cast<DOM::Notation>(node).publicId());
01477   case SystemId:
01478     return String(static_cast<DOM::Notation>(node).systemId());
01479   default:
01480     kdDebug(6070) << "WARNING: DOMNotation::getValueProperty unhandled token " << token << endl;
01481     return Value();
01482   }
01483 }
01484 
01485 // -------------------------------------------------------------------------
01486 
01487 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 };
01488 
01489 /* Source for DOMEntityTable.
01490 @begin DOMEntityTable 2
01491   publicId      DOMEntity::PublicId     DontDelete|ReadOnly
01492   systemId      DOMEntity::SystemId     DontDelete|ReadOnly
01493   notationName      DOMEntity::NotationName DontDelete|ReadOnly
01494 @end
01495 */
01496 Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const
01497 {
01498   return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this);
01499 }
01500 
01501 Value DOMEntity::getValueProperty(ExecState *, int token) const
01502 {
01503   switch (token) {
01504   case PublicId:
01505     return String(static_cast<DOM::Entity>(node).publicId());
01506   case SystemId:
01507     return String(static_cast<DOM::Entity>(node).systemId());
01508   case NotationName:
01509     return String(static_cast<DOM::Entity>(node).notationName());
01510   default:
01511     kdDebug(6070) << "WARNING: DOMEntity::getValueProperty unhandled token " << token << endl;
01512     return Value();
01513   }
01514 }
01515 
01516 // -------------------------------------------------------------------------
01517 
01518 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::Node& n)
01519 {
01520   // Check to see if the currently executing interpreter is allowed to access the specified node
01521   if (n.isNull())
01522     return true;
01523   KHTMLView *view = n.handle()->getDocument()->view();
01524   Window* win = view && view->part() ? Window::retrieveWindow(view->part()) : 0L;
01525   if ( !win || !win->isSafeScript(exec) )
01526     return false;
01527   return true;
01528 }
01529 
01530 Value KJS::getDOMNode(ExecState *exec, const DOM::Node& n)
01531 {
01532   DOMObject *ret = 0;
01533   if (n.isNull())
01534     return Null();
01535   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->interpreter());
01536   if ((ret = interp->getDOMObject(n.handle())))
01537     return Value(ret);
01538 
01539   switch (n.nodeType()) {
01540     case DOM::Node::ELEMENT_NODE:
01541       if (static_cast<DOM::Element>(n).isHTMLElement())
01542         ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n));
01543       else
01544         ret = new DOMElement(exec, static_cast<DOM::Element>(n));
01545       break;
01546     case DOM::Node::ATTRIBUTE_NODE:
01547       ret = new DOMAttr(exec, static_cast<DOM::Attr>(n));
01548       break;
01549     case DOM::Node::TEXT_NODE:
01550     case DOM::Node::CDATA_SECTION_NODE:
01551       ret = new DOMText(exec, static_cast<DOM::Text>(n));
01552       break;
01553     case DOM::Node::ENTITY_REFERENCE_NODE:
01554       ret = new DOMNode(exec, n);
01555       break;
01556     case DOM::Node::ENTITY_NODE:
01557       ret = new DOMEntity(exec, static_cast<DOM::Entity>(n));
01558       break;
01559     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
01560       ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n));
01561       break;
01562     case DOM::Node::COMMENT_NODE:
01563       ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n));
01564       break;
01565     case DOM::Node::DOCUMENT_NODE:
01566       if (static_cast<DOM::Document>(n).isHTMLDocument())
01567         ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n));
01568       else
01569         ret = new DOMDocument(exec, static_cast<DOM::Document>(n));
01570       break;
01571     case DOM::Node::DOCUMENT_TYPE_NODE:
01572       ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n));
01573       break;
01574     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
01575       ret = new DOMNode(exec, n);
01576       break;
01577     case DOM::Node::NOTATION_NODE:
01578       ret = new DOMNotation(exec, static_cast<DOM::Notation>(n));
01579       break;
01580     default:
01581       ret = new DOMNode(exec, n);
01582   }
01583   interp->putDOMObject(n.handle(),ret);
01584 
01585   return Value(ret);
01586 }
01587 
01588 Value KJS::getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap& m)
01589 {
01590   return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m));
01591 }
01592 
01593 Value KJS::getDOMNodeList(ExecState *exec, const DOM::NodeList& l)
01594 {
01595   return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l));
01596 }
01597 
01598 Value KJS::getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation& i)
01599 {
01600   return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i));
01601 }
01602 
01603 // -------------------------------------------------------------------------
01604 IMPLEMENT_PSEUDO_CONSTRUCTOR_WITH_PARENT(NodeConstructor, "NodeConstructor", DOMNodeProto, DOMNodeConstants)
01605 // -------------------------------------------------------------------------
01606 
01607 const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 };
01608 
01609 /* Source for DOMExceptionConstructorTable.
01610 @begin DOMExceptionConstructorTable 15
01611   INDEX_SIZE_ERR        DOM::DOMException::INDEX_SIZE_ERR       DontDelete|ReadOnly
01612   DOMSTRING_SIZE_ERR        DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
01613   HIERARCHY_REQUEST_ERR     DOM::DOMException::HIERARCHY_REQUEST_ERR    DontDelete|ReadOnly
01614   WRONG_DOCUMENT_ERR        DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
01615   INVALID_CHARACTER_ERR     DOM::DOMException::INVALID_CHARACTER_ERR    DontDelete|ReadOnly
01616   NO_DATA_ALLOWED_ERR       DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
01617   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
01618   NOT_FOUND_ERR         DOM::DOMException::NOT_FOUND_ERR        DontDelete|ReadOnly
01619   NOT_SUPPORTED_ERR     DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
01620   INUSE_ATTRIBUTE_ERR       DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
01621   INVALID_STATE_ERR     DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
01622   SYNTAX_ERR            DOM::DOMException::SYNTAX_ERR       DontDelete|ReadOnly
01623   INVALID_MODIFICATION_ERR  DOM::DOMException::INVALID_MODIFICATION_ERR DontDelete|ReadOnly
01624   NAMESPACE_ERR         DOM::DOMException::NAMESPACE_ERR        DontDelete|ReadOnly
01625   INVALID_ACCESS_ERR        DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
01626 @end
01627 */
01628 
01629 DOMExceptionConstructor::DOMExceptionConstructor(ExecState* exec)
01630   : DOMObject(exec->interpreter()->builtinObjectPrototype())
01631 {
01632 }
01633 
01634 Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
01635 {
01636   return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this);
01637 }
01638 
01639 Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const
01640 {
01641   // We use the token as the value to return directly
01642   return Number((unsigned int)token);
01643 #if 0
01644   switch (token) {
01645   case INDEX_SIZE_ERR:
01646     return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR);
01647   case DOMSTRING_SIZE_ERR:
01648     return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR);
01649   case HIERARCHY_REQUEST_ERR:
01650     return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR);
01651   case WRONG_DOCUMENT_ERR:
01652     return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR);
01653   case INVALID_CHARACTER_ERR:
01654     return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR);
01655   case NO_DATA_ALLOWED_ERR:
01656     return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR);
01657   case NO_MODIFICATION_ALLOWED_ERR:
01658     return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR);
01659   case NOT_FOUND_ERR:
01660     return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR);
01661   case NOT_SUPPORTED_ERR:
01662     return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR);
01663   case INUSE_ATTRIBUTE_ERR:
01664     return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR);
01665   case INVALID_STATE_ERR:
01666     return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR);
01667   case SYNTAX_ERR:
01668     return Number((unsigned int)DOM::DOMException::SYNTAX_ERR);
01669   case INVALID_MODIFICATION_ERR:
01670     return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR);
01671   case NAMESPACE_ERR:
01672     return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR);
01673   case INVALID_ACCESS_ERR:
01674     return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR);
01675   default:
01676     kdDebug(6070) << "WARNING: DOMExceptionConstructor::getValueProperty unhandled token " << token << endl;
01677     return Value();
01678   }
01679 #endif
01680 }
01681 
01682 Object KJS::getDOMExceptionConstructor(ExecState *exec)
01683 {
01684   return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]");
01685 }
01686 
01687 // -------------------------------------------------------------------------
01688 
01689 /* Source for DOMNamedNodesCollection.
01690 @begin DOMNamedNodesCollectionTable 1
01691   length        KJS::DOMNamedNodesCollection::Length        DontDelete|ReadOnly
01692 @end
01693 */
01694 const ClassInfo KJS::DOMNamedNodesCollection::info = { "DOMNamedNodesCollection", 0, &DOMNamedNodesCollectionTable, 0 };
01695 
01696 // Such a collection is usually very short-lived, it only exists
01697 // for constructs like document.forms.<name>[1],
01698 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
01699 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *exec, const QValueList<DOM::Node>& nodes )
01700   : DOMObject(exec->interpreter()->builtinObjectPrototype()),
01701   m_nodes(nodes)
01702 {
01703   // Maybe we should ref (and deref in the dtor) the nodes, though ?
01704 }
01705 
01706 Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const
01707 {
01708   kdDebug(6070) << k_funcinfo << propertyName.ascii() << endl;
01709   if (propertyName == lengthPropertyName)
01710     return Number(m_nodes.count());
01711   // index?
01712   bool ok;
01713   unsigned int u = propertyName.toULong(&ok);
01714   if (ok && u < m_nodes.count()) {
01715     DOM::Node node = m_nodes[u];
01716     return getDOMNode(exec,node);
01717   }
01718   return DOMObject::tryGet(exec,propertyName);
01719 }
01720 
01721 // -------------------------------------------------------------------------
01722 
01723 const ClassInfo DOMCharacterData::info = { "CharacterImp",
01724                       &DOMNode::info, &DOMCharacterDataTable, 0 };
01725 /*
01726 @begin DOMCharacterDataTable 2
01727   data      DOMCharacterData::Data      DontDelete
01728   length    DOMCharacterData::Length    DontDelete|ReadOnly
01729 @end
01730 @begin DOMCharacterDataProtoTable 7
01731   substringData DOMCharacterData::SubstringData DontDelete|Function 2
01732   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
01733   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
01734   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
01735   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
01736 @end
01737 */
01738 DEFINE_PROTOTYPE("DOMCharacterData",DOMCharacterDataProto)
01739 IMPLEMENT_PROTOFUNC_DOM(DOMCharacterDataProtoFunc)
01740 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMCharacterDataProto,DOMCharacterDataProtoFunc, DOMNodeProto)
01741 
01742 DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData& d)
01743  : DOMNode(DOMCharacterDataProto::self(exec), d) {}
01744 
01745 DOMCharacterData::DOMCharacterData(const Object& proto, const DOM::CharacterData& d)
01746  : DOMNode(proto, d) {}
01747 
01748 Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const
01749 {
01750 #ifdef KJS_VERBOSE
01751   kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl;
01752 #endif
01753   return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this);
01754 }
01755 
01756 Value DOMCharacterData::getValueProperty(ExecState *, int token) const
01757 {
01758   DOM::CharacterData data = static_cast<DOM::CharacterData>(node);
01759   switch (token) {
01760   case Data:
01761     return String(data.data());
01762   case Length:
01763     return Number(data.length());
01764  default:
01765    kdDebug(6070) << "WARNING: Unhandled token in DOMCharacterData::getValueProperty : " << token << endl;
01766    return Value();
01767   }
01768 }
01769 
01770 void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
01771 {
01772   if (propertyName == "data")
01773     static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string());
01774   else
01775     DOMNode::tryPut(exec, propertyName,value,attr);
01776 }
01777 
01778 Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01779 {
01780   KJS_CHECK_THIS( KJS::DOMCharacterData, thisObj );
01781   DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData();
01782   switch(id) {
01783     case DOMCharacterData::SubstringData:
01784       return String(data.substringData(args[0].toInteger(exec),args[1].toInteger(exec)));
01785     case DOMCharacterData::AppendData:
01786       data.appendData(args[0].toString(exec).string());
01787       return Undefined();
01788       break;
01789     case DOMCharacterData::InsertData:
01790       data.insertData(args[0].toInteger(exec),args[1].toString(exec).string());
01791       return  Undefined();
01792       break;
01793     case DOMCharacterData::DeleteData:
01794       data.deleteData(args[0].toInteger(exec),args[1].toInteger(exec));
01795       return  Undefined();
01796       break;
01797     case DOMCharacterData::ReplaceData:
01798       data.replaceData(args[0].toInteger(exec),args[1].toInteger(exec),args[2].toString(exec).string());
01799       return Undefined();
01800     default:
01801       break;
01802   }
01803   return Undefined();
01804 }
01805 
01806 // -------------------------------------------------------------------------
01807 
01808 const ClassInfo DOMText::info = { "Text",
01809                  &DOMCharacterData::info, 0, 0 };
01810 /*
01811 @begin DOMTextProtoTable 1
01812   splitText DOMText::SplitText  DontDelete|Function 1
01813 @end
01814 */
01815 DEFINE_PROTOTYPE("DOMText",DOMTextProto)
01816 IMPLEMENT_PROTOFUNC_DOM(DOMTextProtoFunc)
01817 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMTextProto,DOMTextProtoFunc,DOMCharacterDataProto)
01818 
01819 DOMText::DOMText(ExecState *exec, const DOM::Text& t)
01820   : DOMCharacterData(DOMTextProto::self(exec), t) { }
01821 
01822 Value DOMText::tryGet(ExecState *exec, const Identifier &p) const
01823 {
01824   if (p.isEmpty())
01825     return Undefined(); // ### TODO
01826   else
01827     return DOMCharacterData::tryGet(exec, p);
01828 }
01829 
01830 Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01831 {
01832   KJS_CHECK_THIS( KJS::DOMText, thisObj );
01833   DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText();
01834   switch(id) {
01835     case DOMText::SplitText:
01836       return getDOMNode(exec,text.splitText(args[0].toInteger(exec)));
01837     default:
01838       break;
01839   }
01840   return Undefined();
01841 }
KDE Home | KDE Accessibility Home | Description of Access Keys