Reviewed by Darin.
[WebKit-https.git] / WebCore / khtml / ecma / kjs_dom.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <khtmlview.h>
23 #include "xml/dom2_eventsimpl.h"
24 #include "rendering/render_canvas.h"
25 #include "xml/dom_nodeimpl.h"
26 #include "xml/dom_docimpl.h"
27 #include <kdebug.h>
28 #include <khtml_part.h>
29
30 #include "kjs_dom.h"
31 #include "kjs_html.h"
32 #include "kjs_css.h"
33 #include "kjs_range.h"
34 #include "kjs_traversal.h"
35 #include "kjs_events.h"
36 #include "kjs_views.h"
37 #include "kjs_window.h"
38 #include "dom/dom_exception.h"
39 #include "kjs_dom.lut.h"
40 #include "khtmlpart_p.h"
41
42 #include "html_objectimpl.h"
43
44 #if APPLE_CHANGES
45 #include <JavaScriptCore/runtime_object.h>
46 #endif
47
48 using namespace KJS;
49
50 using DOM::DOMException;
51 using DOM::NodeFilter;
52
53 // -------------------------------------------------------------------------
54 /* Source for DOMNodeProtoTable. Use "make hashtables" to regenerate.
55 @begin DOMNodeProtoTable 13
56   insertBefore  DOMNode::InsertBefore   DontDelete|Function 2
57   replaceChild  DOMNode::ReplaceChild   DontDelete|Function 2
58   removeChild   DOMNode::RemoveChild    DontDelete|Function 1
59   appendChild   DOMNode::AppendChild    DontDelete|Function 1
60   hasAttributes DOMNode::HasAttributes  DontDelete|Function 0
61   hasChildNodes DOMNode::HasChildNodes  DontDelete|Function 0
62   cloneNode     DOMNode::CloneNode      DontDelete|Function 1
63 # DOM2
64   normalize     DOMNode::Normalize      DontDelete|Function 0
65   isSupported   DOMNode::IsSupported    DontDelete|Function 2
66 # from the EventTarget interface
67   addEventListener      DOMNode::AddEventListener       DontDelete|Function 3
68   removeEventListener   DOMNode::RemoveEventListener    DontDelete|Function 3
69   dispatchEvent         DOMNode::DispatchEvent  DontDelete|Function 1
70   contains      DOMNode::Contains               DontDelete|Function 1
71 # "DOM level 0" (from Gecko DOM reference; also in WinIE)
72   item          DOMNode::Item           DontDelete|Function 1
73 @end
74 */
75 DEFINE_PROTOTYPE("DOMNode",DOMNodeProto)
76 IMPLEMENT_PROTOFUNC(DOMNodeProtoFunc)
77 IMPLEMENT_PROTOTYPE(DOMNodeProto,DOMNodeProtoFunc)
78
79 const ClassInfo DOMNode::info = { "Node", 0, &DOMNodeTable, 0 };
80
81 DOMNode::DOMNode(ExecState *exec, const DOM::Node &n)
82   : DOMObject(DOMNodeProto::self(exec)), node(n)
83 {
84 }
85
86 DOMNode::DOMNode(const Object &proto, const DOM::Node &n)
87   : DOMObject(proto), node(n)
88 {
89 }
90
91 bool DOMNode::toBoolean(ExecState *) const
92 {
93     return !node.isNull();
94 }
95
96 /* Source for DOMNodeTable. Use "make hashtables" to regenerate.
97 @begin DOMNodeTable 67
98   nodeName      DOMNode::NodeName       DontDelete|ReadOnly
99   nodeValue     DOMNode::NodeValue      DontDelete
100   nodeType      DOMNode::NodeType       DontDelete|ReadOnly
101   parentNode    DOMNode::ParentNode     DontDelete|ReadOnly
102   parentElement DOMNode::ParentElement  DontDelete|ReadOnly
103   childNodes    DOMNode::ChildNodes     DontDelete|ReadOnly
104   firstChild    DOMNode::FirstChild     DontDelete|ReadOnly
105   lastChild     DOMNode::LastChild      DontDelete|ReadOnly
106   previousSibling  DOMNode::PreviousSibling DontDelete|ReadOnly
107   nextSibling   DOMNode::NextSibling    DontDelete|ReadOnly
108   attributes    DOMNode::Attributes     DontDelete|ReadOnly
109   namespaceURI  DOMNode::NamespaceURI   DontDelete|ReadOnly
110 # DOM2
111   prefix        DOMNode::Prefix         DontDelete
112   localName     DOMNode::LocalName      DontDelete|ReadOnly
113   ownerDocument DOMNode::OwnerDocument  DontDelete|ReadOnly
114 #
115   onabort       DOMNode::OnAbort                DontDelete
116   onblur        DOMNode::OnBlur                 DontDelete
117   onchange      DOMNode::OnChange               DontDelete
118   onclick       DOMNode::OnClick                DontDelete
119   oncontextmenu DOMNode::OnContextMenu          DontDelete
120   ondblclick    DOMNode::OnDblClick             DontDelete
121   onbeforecut   DOMNode::OnBeforeCut            DontDelete
122   oncut         DOMNode::OnCut                  DontDelete
123   onbeforecopy  DOMNode::OnBeforeCopy           DontDelete
124   oncopy        DOMNode::OnCopy                 DontDelete
125   onbeforepaste DOMNode::OnBeforePaste          DontDelete
126   onpaste       DOMNode::OnPaste                DontDelete
127   ondrag        DOMNode::OnDrag                 DontDelete
128   ondragdrop    DOMNode::OnDragDrop             DontDelete
129   ondragend     DOMNode::OnDragEnd              DontDelete
130   ondragenter   DOMNode::OnDragEnter            DontDelete
131   ondragleave   DOMNode::OnDragLeave            DontDelete
132   ondragover    DOMNode::OnDragOver             DontDelete
133   ondragstart   DOMNode::OnDragStart            DontDelete
134   ondrop        DOMNode::OnDrop                 DontDelete
135   onerror       DOMNode::OnError                DontDelete
136   onfocus       DOMNode::OnFocus                DontDelete
137   oninput       DOMNode::OnInput                DontDelete
138   onkeydown     DOMNode::OnKeyDown              DontDelete
139   onkeypress    DOMNode::OnKeyPress             DontDelete
140   onkeyup       DOMNode::OnKeyUp                DontDelete
141   onload        DOMNode::OnLoad                 DontDelete
142   onmousedown   DOMNode::OnMouseDown            DontDelete
143   onmousemove   DOMNode::OnMouseMove            DontDelete
144   onmouseout    DOMNode::OnMouseOut             DontDelete
145   onmouseover   DOMNode::OnMouseOver            DontDelete
146   onmouseup     DOMNode::OnMouseUp              DontDelete
147   onmove        DOMNode::OnMove                 DontDelete
148   onreset       DOMNode::OnReset                DontDelete
149   onresize      DOMNode::OnResize               DontDelete
150   onscroll      DOMNode::OnScroll               DontDelete
151   onsearch      DOMNode::OnSearch               DontDelete
152   onselect      DOMNode::OnSelect               DontDelete
153   onselectstart DOMNode::OnSelectStart          DontDelete
154   onsubmit      DOMNode::OnSubmit               DontDelete
155   onunload      DOMNode::OnUnload               DontDelete
156 # IE extensions
157   offsetLeft    DOMNode::OffsetLeft             DontDelete|ReadOnly
158   offsetTop     DOMNode::OffsetTop              DontDelete|ReadOnly
159   offsetWidth   DOMNode::OffsetWidth            DontDelete|ReadOnly
160   offsetHeight  DOMNode::OffsetHeight           DontDelete|ReadOnly
161   offsetParent  DOMNode::OffsetParent           DontDelete|ReadOnly
162   clientWidth   DOMNode::ClientWidth            DontDelete|ReadOnly
163   clientHeight  DOMNode::ClientHeight           DontDelete|ReadOnly
164   scrollLeft    DOMNode::ScrollLeft             DontDelete
165   scrollTop     DOMNode::ScrollTop              DontDelete
166   scrollWidth   DOMNode::ScrollWidth            DontDelete|ReadOnly
167   scrollHeight  DOMNode::ScrollHeight           DontDelete|ReadOnly
168 @end
169 */
170 Value DOMNode::tryGet(ExecState *exec, const Identifier &propertyName) const
171 {
172 #ifdef KJS_VERBOSE
173   kdDebug(6070) << "DOMNode::tryGet " << propertyName.qstring() << endl;
174 #endif
175   return DOMObjectLookupGetValue<DOMNode, DOMObject>(exec, propertyName, &DOMNodeTable, this);
176 }
177
178 Value DOMNode::getValueProperty(ExecState *exec, int token) const
179 {
180   switch (token) {
181   case NodeName:
182     return getStringOrNull(node.nodeName());
183   case NodeValue:
184     return getStringOrNull(node.nodeValue());
185   case NodeType:
186     return Number((unsigned int)node.nodeType());
187   case ParentNode:
188     return getDOMNode(exec,node.parentNode());
189   case ParentElement: // IE only apparently
190     return getDOMNode(exec,node.parentNode());
191   case ChildNodes:
192     return getDOMNodeList(exec,node.childNodes());
193   case FirstChild:
194     return getDOMNode(exec,node.firstChild());
195   case LastChild:
196     return getDOMNode(exec,node.lastChild());
197   case PreviousSibling:
198     return getDOMNode(exec,node.previousSibling());
199   case NextSibling:
200     return getDOMNode(exec,node.nextSibling());
201   case Attributes:
202     return getDOMNamedNodeMap(exec,node.attributes());
203   case NamespaceURI:
204     return getStringOrNull(node.namespaceURI());
205   case Prefix:
206     return getStringOrNull(node.prefix());
207   case LocalName:
208     return getStringOrNull(node.localName());
209   case OwnerDocument:
210     return getDOMNode(exec,node.ownerDocument());
211   case OnAbort:
212     return getListener(DOM::EventImpl::ABORT_EVENT);
213   case OnBlur:
214     return getListener(DOM::EventImpl::BLUR_EVENT);
215   case OnChange:
216     return getListener(DOM::EventImpl::CHANGE_EVENT);
217   case OnClick:
218     return getListener(DOM::EventImpl::KHTML_CLICK_EVENT);
219   case OnContextMenu:
220     return getListener(DOM::EventImpl::CONTEXTMENU_EVENT);
221   case OnDblClick:
222     return getListener(DOM::EventImpl::KHTML_DBLCLICK_EVENT);
223   case OnDragDrop:
224     return getListener(DOM::EventImpl::KHTML_DRAGDROP_EVENT);
225   case OnError:
226     return getListener(DOM::EventImpl::KHTML_ERROR_EVENT);
227   case OnFocus:
228     return getListener(DOM::EventImpl::FOCUS_EVENT);
229   case OnInput:
230     return getListener(DOM::EventImpl::INPUT_EVENT);
231   case OnKeyDown:
232     return getListener(DOM::EventImpl::KEYDOWN_EVENT);
233   case OnKeyPress:
234     return getListener(DOM::EventImpl::KEYPRESS_EVENT);
235   case OnKeyUp:
236     return getListener(DOM::EventImpl::KEYUP_EVENT);
237   case OnLoad:
238     return getListener(DOM::EventImpl::LOAD_EVENT);
239   case OnMouseDown:
240     return getListener(DOM::EventImpl::MOUSEDOWN_EVENT);
241   case OnMouseMove:
242     return getListener(DOM::EventImpl::MOUSEMOVE_EVENT);
243   case OnMouseOut:
244     return getListener(DOM::EventImpl::MOUSEOUT_EVENT);
245   case OnMouseOver:
246     return getListener(DOM::EventImpl::MOUSEOVER_EVENT);
247   case OnMouseUp:
248     return getListener(DOM::EventImpl::MOUSEUP_EVENT);      
249   case OnBeforeCut:
250     return getListener(DOM::EventImpl::BEFORECUT_EVENT);
251   case OnCut:
252     return getListener(DOM::EventImpl::CUT_EVENT);
253   case OnBeforeCopy:
254     return getListener(DOM::EventImpl::BEFORECOPY_EVENT);
255   case OnCopy:
256     return getListener(DOM::EventImpl::COPY_EVENT);
257   case OnBeforePaste:
258     return getListener(DOM::EventImpl::BEFOREPASTE_EVENT);
259   case OnPaste:
260     return getListener(DOM::EventImpl::PASTE_EVENT);
261   case OnDragEnter:
262     return getListener(DOM::EventImpl::DRAGENTER_EVENT);
263   case OnDragOver:
264     return getListener(DOM::EventImpl::DRAGOVER_EVENT);
265   case OnDragLeave:
266     return getListener(DOM::EventImpl::DRAGLEAVE_EVENT);
267   case OnDrop:
268     return getListener(DOM::EventImpl::DROP_EVENT);
269   case OnDragStart:
270     return getListener(DOM::EventImpl::DRAGSTART_EVENT);
271   case OnDrag:
272     return getListener(DOM::EventImpl::DRAG_EVENT);
273   case OnDragEnd:
274     return getListener(DOM::EventImpl::DRAGEND_EVENT);
275   case OnMove:
276     return getListener(DOM::EventImpl::KHTML_MOVE_EVENT);
277   case OnReset:
278     return getListener(DOM::EventImpl::RESET_EVENT);
279   case OnResize:
280     return getListener(DOM::EventImpl::RESIZE_EVENT);
281   case OnScroll:
282     return getListener(DOM::EventImpl::SCROLL_EVENT);
283 #if APPLE_CHANGES
284   case OnSearch:
285     return getListener(DOM::EventImpl::SEARCH_EVENT);
286 #endif
287   case OnSelect:
288     return getListener(DOM::EventImpl::SELECT_EVENT);
289   case OnSelectStart:
290     return getListener(DOM::EventImpl::SELECTSTART_EVENT);
291   case OnSubmit:
292     return getListener(DOM::EventImpl::SUBMIT_EVENT);
293   case OnUnload:
294     return getListener(DOM::EventImpl::UNLOAD_EVENT);
295   default:
296     // no DOM standard, found in IE only
297
298     // Make sure our layout is up to date before we allow a query on these attributes.
299     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
300     if (docimpl) {
301       docimpl->updateLayout();
302     }
303
304     khtml::RenderObject *rend = node.handle()->renderer();
305
306     switch (token) {
307     case OffsetLeft:
308       return rend ? static_cast<Value>(Number(rend->offsetLeft())) : Value(Undefined());
309     case OffsetTop:
310       return rend ? static_cast<Value>(Number(rend->offsetTop())) : Value(Undefined());
311     case OffsetWidth:
312       return rend ? static_cast<Value>(Number(rend->offsetWidth()) ) : Value(Undefined());
313     case OffsetHeight:
314       return rend ? static_cast<Value>(Number(rend->offsetHeight() ) ) : Value(Undefined());
315     case OffsetParent: {
316       khtml::RenderObject* par = rend ? rend->offsetParent() : 0;
317       return getDOMNode(exec, par ? par->element() : 0);
318     }
319     case ClientWidth:
320       return rend ? static_cast<Value>(Number(rend->clientWidth()) ) : Value(Undefined());
321     case ClientHeight:
322       return rend ? static_cast<Value>(Number(rend->clientHeight()) ) : Value(Undefined());
323     case ScrollWidth:
324         return rend ? static_cast<Value>(Number(rend->scrollWidth()) ) : Value(Undefined());
325     case ScrollHeight:
326         return rend ? static_cast<Value>(Number(rend->scrollHeight()) ) : Value(Undefined());
327     case ScrollLeft:
328       return Number(rend && rend->layer() ? rend->layer()->scrollXOffset() : 0);
329     case ScrollTop:
330       return Number(rend && rend->layer() ? rend->layer()->scrollYOffset() : 0);
331     default:
332       kdWarning() << "Unhandled token in DOMNode::getValueProperty : " << token << endl;
333       break;
334     }
335   }
336
337   return Value();
338 }
339
340 void DOMNode::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
341 {
342 #ifdef KJS_VERBOSE
343   kdDebug(6070) << "DOMNode::tryPut " << propertyName.qstring() << endl;
344 #endif
345   DOMObjectLookupPut<DOMNode,DOMObject>(exec, propertyName, value, attr,
346                                         &DOMNodeTable, this );
347 }
348
349 void DOMNode::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
350 {
351   switch (token) {
352   case NodeValue:
353     node.setNodeValue(value.toString(exec).string());
354     break;
355   case Prefix:
356     node.setPrefix(value.toString(exec).string());
357     break;
358   case OnAbort:
359     setListener(exec,DOM::EventImpl::ABORT_EVENT,value);
360     break;
361   case OnBlur:
362     setListener(exec,DOM::EventImpl::BLUR_EVENT,value);
363     break;
364   case OnChange:
365     setListener(exec,DOM::EventImpl::CHANGE_EVENT,value);
366     break;
367   case OnClick:
368     setListener(exec,DOM::EventImpl::KHTML_CLICK_EVENT,value);
369     break;
370   case OnContextMenu:
371     setListener(exec,DOM::EventImpl::CONTEXTMENU_EVENT,value);
372     break;
373   case OnDblClick:
374     setListener(exec,DOM::EventImpl::KHTML_DBLCLICK_EVENT,value);
375     break;
376   case OnDragDrop:
377     setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value);
378     break;
379   case OnError:
380     setListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT,value);
381     break;
382   case OnFocus:
383     setListener(exec,DOM::EventImpl::FOCUS_EVENT,value);
384     break;
385   case OnInput:
386     setListener(exec,DOM::EventImpl::INPUT_EVENT,value);
387     break;
388   case OnKeyDown:
389     setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value);
390     break;
391   case OnKeyPress:
392     setListener(exec,DOM::EventImpl::KEYPRESS_EVENT,value);
393     break;
394   case OnKeyUp:
395     setListener(exec,DOM::EventImpl::KEYUP_EVENT,value);
396     break;
397   case OnLoad:
398     setListener(exec,DOM::EventImpl::LOAD_EVENT,value);
399     break;
400   case OnMouseDown:
401     setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value);
402     break;
403   case OnMouseMove:
404     setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value);
405     break;
406   case OnMouseOut:
407     setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value);
408     break;
409   case OnMouseOver:
410     setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value);
411     break;
412   case OnMouseUp:
413     setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value);
414     break;
415   case OnBeforeCut:
416     setListener(exec,DOM::EventImpl::BEFORECUT_EVENT,value);
417     break;
418   case OnCut:
419     setListener(exec,DOM::EventImpl::CUT_EVENT,value);
420     break;
421   case OnBeforeCopy:
422     setListener(exec,DOM::EventImpl::BEFORECOPY_EVENT,value);
423     break;
424   case OnCopy:
425     setListener(exec,DOM::EventImpl::COPY_EVENT,value);
426     break;
427   case OnBeforePaste:
428     setListener(exec,DOM::EventImpl::BEFOREPASTE_EVENT,value);
429     break;
430   case OnPaste:
431     setListener(exec,DOM::EventImpl::PASTE_EVENT,value);
432     break;
433   case OnDragEnter:
434     setListener(exec,DOM::EventImpl::DRAGENTER_EVENT,value);
435     break;
436   case OnDragOver:
437     setListener(exec,DOM::EventImpl::DRAGOVER_EVENT,value);
438     break;
439   case OnDragLeave:
440     setListener(exec,DOM::EventImpl::DRAGLEAVE_EVENT,value);
441     break;
442   case OnDrop:
443     setListener(exec,DOM::EventImpl::DROP_EVENT,value);
444     break;
445   case OnDragStart:
446     setListener(exec,DOM::EventImpl::DRAGSTART_EVENT,value);
447     break;
448   case OnDrag:
449     setListener(exec,DOM::EventImpl::DRAG_EVENT,value);
450     break;
451   case OnDragEnd:
452     setListener(exec,DOM::EventImpl::DRAGEND_EVENT,value);
453     break;
454   case OnMove:
455     setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value);
456     break;
457   case OnReset:
458     setListener(exec,DOM::EventImpl::RESET_EVENT,value);
459     break;
460   case OnResize:
461     setListener(exec,DOM::EventImpl::RESIZE_EVENT,value);
462     break;
463   case OnScroll:
464     setListener(exec,DOM::EventImpl::SCROLL_EVENT,value);
465 #if APPLE_CHANGES
466   case OnSearch:
467     setListener(exec,DOM::EventImpl::SEARCH_EVENT,value);
468     break;
469 #endif
470   case OnSelect:
471     setListener(exec,DOM::EventImpl::SELECT_EVENT,value);
472     break;
473   case OnSelectStart:
474     setListener(exec,DOM::EventImpl::SELECTSTART_EVENT,value);
475     break;
476   case OnSubmit:
477     setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value);
478     break;
479   case OnUnload:
480     setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value);
481     break;
482   case ScrollTop: {
483     khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
484     if (rend && rend->hasOverflowClip())
485         rend->layer()->scrollToYOffset(value.toInt32(exec));
486     break;
487   }
488   case ScrollLeft: {
489     khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
490     if (rend && rend->hasOverflowClip())
491       rend->layer()->scrollToXOffset(value.toInt32(exec));
492     break;
493   }
494   default:
495     kdWarning() << "DOMNode::putValue unhandled token " << token << endl;
496   }
497 }
498
499 Value DOMNode::toPrimitive(ExecState *exec, Type /*preferred*/) const
500 {
501   if (node.isNull())
502     return Null();
503
504   return String(toString(exec));
505 }
506
507 UString DOMNode::toString(ExecState *) const
508 {
509   if (node.isNull())
510     return "null";
511   UString s;
512
513   DOM::Element e = node;
514   if ( !e.isNull() ) {
515     s = UString(e.nodeName().string());
516   } else
517     s = className(); // fallback
518
519   return "[object " + s + "]";
520 }
521
522 void DOMNode::setListener(ExecState *exec, int eventId, Value func) const
523 {
524   node.handle()->setHTMLEventListener(eventId,Window::retrieveActive(exec)->getJSEventListener(func,true));
525 }
526
527 Value DOMNode::getListener(int eventId) const
528 {
529     DOM::EventListener *listener = node.handle()->getHTMLEventListener(eventId);
530     JSEventListener *jsListener = static_cast<JSEventListener*>(listener);
531     if ( jsListener && jsListener->listenerObjImp() )
532         return jsListener->listenerObj();
533     else
534         return Null();
535 }
536
537 void DOMNode::pushEventHandlerScope(ExecState *, ScopeChain &) const
538 {
539 }
540
541 Value DOMNodeProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
542 {
543   if (!thisObj.inherits(&DOMNode::info)) {
544     Object err = Error::create(exec,TypeError);
545     exec->setException(err);
546     return err;
547   }
548   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
549   switch (id) {
550     case DOMNode::HasAttributes:
551       return Boolean(node.hasAttributes());
552     case DOMNode::HasChildNodes:
553       return Boolean(node.hasChildNodes());
554     case DOMNode::CloneNode:
555       return getDOMNode(exec,node.cloneNode(args[0].toBoolean(exec)));
556     case DOMNode::Normalize:
557       node.normalize();
558       return Undefined();
559     case DOMNode::IsSupported:
560       return Boolean(node.isSupported(args[0].toString(exec).string(),args[1].toString(exec).string()));
561     case DOMNode::AddEventListener: {
562         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
563         if (listener)
564             node.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
565         return Undefined();
566     }
567     case DOMNode::RemoveEventListener: {
568         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
569         if (listener)
570             node.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
571         return Undefined();
572     }
573     case DOMNode::DispatchEvent:
574       return Boolean(node.dispatchEvent(toEvent(args[0])));
575     case DOMNode::AppendChild:
576       return getDOMNode(exec,node.appendChild(toNode(args[0])));
577     case DOMNode::RemoveChild:
578       return getDOMNode(exec,node.removeChild(toNode(args[0])));
579     case DOMNode::InsertBefore:
580       return getDOMNode(exec,node.insertBefore(toNode(args[0]), toNode(args[1])));
581     case DOMNode::ReplaceChild:
582       return getDOMNode(exec,node.replaceChild(toNode(args[0]), toNode(args[1])));
583     case DOMNode::Contains:
584     {
585         int exceptioncode=0;
586         DOM::Node other = toNode(args[0]);
587         if (!other.isNull() && node.nodeType()==DOM::Node::ELEMENT_NODE)
588         {
589             DOM::NodeBaseImpl *impl = static_cast<DOM::NodeBaseImpl *>(node.handle());
590             bool retval = !impl->checkNoOwner(other.handle(),exceptioncode);
591             return Boolean(retval && exceptioncode == 0);
592         }
593         return Undefined();
594     }
595     case DOMNode::Item:
596       return getDOMNode(exec, node.childNodes().item(static_cast<unsigned long>(args[0].toNumber(exec))));
597   }
598
599   return Undefined();
600 }
601
602 // -------------------------------------------------------------------------
603
604 const ClassInfo DOMNodeList::info = { "NodeList", 0, 0, 0 };
605
606 DOMNodeList::~DOMNodeList()
607 {
608   ScriptInterpreter::forgetDOMObject(list.handle());
609 }
610
611 Value DOMNodeList::toPrimitive(ExecState *exec, Type /*preferred*/) const
612 {
613   if (list.isNull())
614     return Null();
615
616   return String(toString(exec));
617 }
618
619
620
621 // We have to implement hasProperty since we don't use a hashtable for 'length' and 'item'
622 // ## this breaks "for (..in..)" though.
623 bool DOMNodeList::hasProperty(ExecState *exec, const Identifier &p) const
624 {
625   if (p == lengthPropertyName || p == "item")
626     return true;
627   return ObjectImp::hasProperty(exec, p);
628 }
629
630 Value DOMNodeList::tryGet(ExecState *exec, const Identifier &p) const
631 {
632 #ifdef KJS_VERBOSE
633   kdDebug(6070) << "DOMNodeList::tryGet " << p.ascii() << endl;
634 #endif
635   Value result;
636
637   if (p == lengthPropertyName)
638     result = Number(list.length());
639   else if (p == "item") {
640     // No need for a complete hashtable for a single func, but we still want
641     // to use the caching feature of lookupOrCreateFunction.
642     result = lookupOrCreateFunction<DOMNodeListFunc>(exec, p, this, DOMNodeListFunc::Item, 1, DontDelete|Function);
643     //result = new DOMNodeListFunc(exec, DOMNodeListFunc::Item, 1);
644   }
645   else {
646     // array index ?
647     bool ok;
648     long unsigned int idx = p.toULong(&ok);
649     if (ok)
650       result = getDOMNode(exec,list.item(idx));
651     else {
652       DOM::HTMLElement e;
653       unsigned long l = list.length();
654       bool found = false;
655
656       for ( unsigned long i = 0; i < l; i++ )
657         if ( ( e = list.item( i ) ).id() == p.string() ) {
658           result = getDOMNode(exec, list.item( i ) );
659           found = true;
660           break;
661         }
662
663       if ( !found )
664         result = ObjectImp::get(exec, p);
665     }
666   }
667
668   return result;
669 }
670
671 // Need to support both get and call, so that list[0] and list(0) work.
672 Value DOMNodeList::call(ExecState *exec, Object &thisObj, const List &args)
673 {
674   // This code duplication is necessary, DOMNodeList isn't a DOMFunction
675   Value val;
676   try {
677     val = tryCall(exec, thisObj, args);
678   }
679   // pity there's no way to distinguish between these in JS code
680   catch (...) {
681     Object err = Error::create(exec, GeneralError, "Exception from DOMNodeList");
682     exec->setException(err);
683   }
684   return val;
685 }
686
687 Value DOMNodeList::tryCall(ExecState *exec, Object &, const List &args)
688 {
689   // Do not use thisObj here. See HTMLCollection.
690   UString s = args[0].toString(exec);
691   bool ok;
692   unsigned int u = s.toULong(&ok);
693   if (ok)
694     return getDOMNode(exec,list.item(u));
695
696   kdWarning() << "KJS::DOMNodeList::tryCall " << s.qstring() << " not implemented" << endl;
697   return Undefined();
698 }
699
700 DOMNodeListFunc::DOMNodeListFunc(ExecState *exec, int i, int len)
701   : DOMFunction(), id(i)
702 {
703   Value protect(this);
704   put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum);
705 }
706
707 // Not a prototype class currently, but should probably be converted to one
708 Value DOMNodeListFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
709 {
710   if (!thisObj.inherits(&KJS::DOMNodeList::info)) {
711     Object err = Error::create(exec,TypeError);
712     exec->setException(err);
713     return err;
714   }
715   DOM::NodeList list = static_cast<DOMNodeList *>(thisObj.imp())->nodeList();
716   Value result;
717
718   if (id == Item)
719     result = getDOMNode(exec, list.item(args[0].toInt32(exec)));
720   return result;
721 }
722
723 // -------------------------------------------------------------------------
724
725 const ClassInfo DOMAttr::info = { "Attr", &DOMNode::info, &DOMAttrTable, 0 };
726
727 /* Source for DOMAttrTable. Use "make hashtables" to regenerate.
728 @begin DOMAttrTable 5
729   name          DOMAttr::Name           DontDelete|ReadOnly
730   specified     DOMAttr::Specified      DontDelete|ReadOnly
731   value         DOMAttr::ValueProperty  DontDelete|ReadOnly
732   ownerElement  DOMAttr::OwnerElement   DontDelete|ReadOnly
733 @end
734 */
735 Value DOMAttr::tryGet(ExecState *exec, const Identifier &propertyName) const
736 {
737 #ifdef KJS_VERBOSE
738   kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl;
739 #endif
740   return DOMObjectLookupGetValue<DOMAttr,DOMNode>(exec, propertyName,
741                                                   &DOMAttrTable, this );
742 }
743
744 Value DOMAttr::getValueProperty(ExecState *exec, int token) const
745 {
746   switch (token) {
747   case Name:
748     return getStringOrNull(static_cast<DOM::Attr>(node).name());
749   case Specified:
750     return Boolean(static_cast<DOM::Attr>(node).specified());
751   case ValueProperty:
752     return getStringOrNull(static_cast<DOM::Attr>(node).value());
753   case OwnerElement: // DOM2
754     return getDOMNode(exec,static_cast<DOM::Attr>(node).ownerElement());
755   }
756   return Value(); // not reached
757 }
758
759 void DOMAttr::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
760 {
761 #ifdef KJS_VERBOSE
762   kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl;
763 #endif
764   DOMObjectLookupPut<DOMAttr,DOMNode>(exec, propertyName, value, attr,
765                                       &DOMAttrTable, this );
766 }
767
768 void DOMAttr::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
769 {
770   switch (token) {
771   case ValueProperty:
772     static_cast<DOM::Attr>(node).setValue(value.toString(exec).string());
773     return;
774   default:
775     kdWarning() << "DOMAttr::putValue unhandled token " << token << endl;
776   }
777 }
778
779 // -------------------------------------------------------------------------
780
781 /* Source for DOMDocumentProtoTable. Use "make hashtables" to regenerate.
782 @begin DOMDocumentProtoTable 29
783   createElement   DOMDocument::CreateElement                   DontDelete|Function 1
784   createDocumentFragment DOMDocument::CreateDocumentFragment   DontDelete|Function 1
785   createTextNode  DOMDocument::CreateTextNode                  DontDelete|Function 1
786   createComment   DOMDocument::CreateComment                   DontDelete|Function 1
787   createCDATASection DOMDocument::CreateCDATASection           DontDelete|Function 1
788   createProcessingInstruction DOMDocument::CreateProcessingInstruction DontDelete|Function 1
789   createAttribute DOMDocument::CreateAttribute                 DontDelete|Function 1
790   createEntityReference DOMDocument::CreateEntityReference     DontDelete|Function 1
791   getElementsByTagName  DOMDocument::GetElementsByTagName      DontDelete|Function 1
792   importNode           DOMDocument::ImportNode                 DontDelete|Function 2
793   createElementNS      DOMDocument::CreateElementNS            DontDelete|Function 2
794   createAttributeNS    DOMDocument::CreateAttributeNS          DontDelete|Function 2
795   getElementsByTagNameNS  DOMDocument::GetElementsByTagNameNS  DontDelete|Function 2
796   getElementById     DOMDocument::GetElementById               DontDelete|Function 1
797   createRange        DOMDocument::CreateRange                  DontDelete|Function 0
798   createNodeIterator DOMDocument::CreateNodeIterator           DontDelete|Function 3
799   createTreeWalker   DOMDocument::CreateTreeWalker             DontDelete|Function 4
800   createEvent        DOMDocument::CreateEvent                  DontDelete|Function 1
801   getOverrideStyle   DOMDocument::GetOverrideStyle             DontDelete|Function 2
802   execCommand        DOMDocument::ExecCommand                  DontDelete|Function 3
803   queryCommandEnabled DOMDocument::QueryCommandEnabled         DontDelete|Function 1
804   queryCommandIndeterm DOMDocument::QueryCommandIndeterm       DontDelete|Function 1
805   queryCommandState DOMDocument::QueryCommandState             DontDelete|Function 1
806   queryCommandSupported DOMDocument::QueryCommandSupported     DontDelete|Function 1
807   queryCommandValue DOMDocument::QueryCommandValue             DontDelete|Function 1
808 @end
809 */
810 DEFINE_PROTOTYPE("DOMDocument", DOMDocumentProto)
811 IMPLEMENT_PROTOFUNC(DOMDocumentProtoFunc)
812 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMDocumentProto, DOMDocumentProtoFunc, DOMNodeProto)
813
814 const ClassInfo DOMDocument::info = { "Document", &DOMNode::info, &DOMDocumentTable, 0 };
815
816 /* Source for DOMDocumentTable. Use "make hashtables" to regenerate.
817 @begin DOMDocumentTable 4
818   doctype         DOMDocument::DocType                         DontDelete|ReadOnly
819   implementation  DOMDocument::Implementation                  DontDelete|ReadOnly
820   documentElement DOMDocument::DocumentElement                 DontDelete|ReadOnly
821   styleSheets     DOMDocument::StyleSheets                     DontDelete|ReadOnly
822   preferredStylesheetSet  DOMDocument::PreferredStylesheetSet  DontDelete|ReadOnly
823   selectedStylesheetSet  DOMDocument::SelectedStylesheetSet    DontDelete
824   readyState      DOMDocument::ReadyState                      DontDelete|ReadOnly
825   defaultView        DOMDocument::DefaultView                  DontDelete|ReadOnly
826 @end
827 */
828
829 DOMDocument::DOMDocument(ExecState *exec, const DOM::Document &d)
830   : DOMNode(DOMDocumentProto::self(exec), d) { }
831
832 DOMDocument::DOMDocument(const Object &proto, const DOM::Document &d)
833   : DOMNode(proto, d) { }
834
835 DOMDocument::~DOMDocument()
836 {
837   ScriptInterpreter::forgetDOMObject(node.handle());
838 }
839
840 Value DOMDocument::tryGet(ExecState *exec, const Identifier &propertyName) const
841 {
842 #ifdef KJS_VERBOSE
843   kdDebug(6070) << "DOMDocument::tryGet " << propertyName.qstring() << endl;
844 #endif
845   return DOMObjectLookupGetValue<DOMDocument, DOMNode>(
846     exec, propertyName, &DOMDocumentTable, this);
847 }
848
849 Value DOMDocument::getValueProperty(ExecState *exec, int token) const
850 {
851   DOM::Document doc = static_cast<DOM::Document>(node);
852
853   switch(token) {
854   case DocType:
855     return getDOMNode(exec,doc.doctype());
856   case Implementation:
857     return getDOMDOMImplementation(exec,doc.implementation());
858   case DocumentElement:
859     return getDOMNode(exec,doc.documentElement());
860   case StyleSheets:
861     //kdDebug() << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets" << endl;
862     return getDOMStyleSheetList(exec, doc.styleSheets(), doc);
863   case PreferredStylesheetSet:
864     return getStringOrNull(doc.preferredStylesheetSet());
865   case SelectedStylesheetSet:
866     return getStringOrNull(doc.selectedStylesheetSet());
867   case ReadyState:
868     {
869     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
870     if ( docimpl )
871     {
872       KHTMLPart* part = docimpl->part();
873       if ( part ) {
874         if (part->d->m_bComplete) return String("complete");
875         if (docimpl->parsing()) return String("loading");
876         return String("loaded");
877         // What does the interactive value mean ?
878         // Missing support for "uninitialized"
879       }
880     }
881     return Undefined();
882     }
883   case DOMDocument::DefaultView: // DOM2
884     return getDOMAbstractView(exec,doc.defaultView());
885   default:
886     kdWarning() << "DOMDocument::getValueProperty unhandled token " << token << endl;
887     return Value();
888   }
889 }
890
891 void DOMDocument::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
892 {
893 #ifdef KJS_VERBOSE
894   kdDebug(6070) << "DOMDocument::tryPut " << propertyName.qstring() << endl;
895 #endif
896   DOMObjectLookupPut<DOMDocument,DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this );
897 }
898
899 void DOMDocument::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
900 {
901   DOM::Document doc = static_cast<DOM::Document>(node);
902   switch (token) {
903     case SelectedStylesheetSet: {
904       doc.setSelectedStylesheetSet(value.toString(exec).string());
905       break;
906     }
907   }
908 }
909
910 Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
911 {
912   if (!thisObj.inherits(&KJS::DOMNode::info)) {
913     Object err = Error::create(exec,TypeError);
914     exec->setException(err);
915     return err;
916   }
917   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
918   DOM::Document doc = static_cast<DOM::Document>(node);
919   String str = args[0].toString(exec);
920   DOM::DOMString s = str.value().string();
921
922   switch(id) {
923   case DOMDocument::CreateElement:
924     return getDOMNode(exec,doc.createElement(s));
925   case DOMDocument::CreateDocumentFragment:
926     return getDOMNode(exec,doc.createDocumentFragment());
927   case DOMDocument::CreateTextNode:
928     return getDOMNode(exec,doc.createTextNode(s));
929   case DOMDocument::CreateComment:
930     return getDOMNode(exec,doc.createComment(s));
931   case DOMDocument::CreateCDATASection:
932     return getDOMNode(exec,doc.createCDATASection(s));  /* TODO: okay ? */
933   case DOMDocument::CreateProcessingInstruction:
934     return getDOMNode(exec,doc.createProcessingInstruction(args[0].toString(exec).string(),
935                                                                  args[1].toString(exec).string()));
936   case DOMDocument::CreateAttribute:
937     return getDOMNode(exec,doc.createAttribute(s));
938   case DOMDocument::CreateEntityReference:
939     return getDOMNode(exec,doc.createEntityReference(args[0].toString(exec).string()));
940   case DOMDocument::GetElementsByTagName:
941     return getDOMNodeList(exec,doc.getElementsByTagName(s));
942   case DOMDocument::ImportNode: // DOM2
943     return getDOMNode(exec,doc.importNode(toNode(args[0]), args[1].toBoolean(exec)));
944   case DOMDocument::CreateElementNS: // DOM2
945     return getDOMNode(exec,doc.createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
946   case DOMDocument::CreateAttributeNS: // DOM2
947     return getDOMNode(exec,doc.createAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
948   case DOMDocument::GetElementsByTagNameNS: // DOM2
949     return getDOMNodeList(exec,doc.getElementsByTagNameNS(args[0].toString(exec).string(),
950                                                           args[1].toString(exec).string()));
951   case DOMDocument::GetElementById:
952     return getDOMNode(exec,doc.getElementById(args[0].toString(exec).string()));
953   case DOMDocument::CreateRange:
954     return getDOMRange(exec,doc.createRange());
955   case DOMDocument::CreateNodeIterator: {
956     NodeFilter filter;
957     if (!args[2].isA(NullType)) {
958         Object obj = Object::dynamicCast(args[2]);
959         if (!obj.isNull())
960             filter = NodeFilter(new JSNodeFilterCondition(obj));
961     }
962     return getDOMNodeIterator(exec, doc.createNodeIterator(toNode(args[0]), (long unsigned int)(args[1].toNumber(exec)), filter, args[3].toBoolean(exec)));
963   }
964   case DOMDocument::CreateTreeWalker: {
965     NodeFilter filter;
966     if (!args[2].isA(NullType)) {
967         Object obj = Object::dynamicCast(args[2]);
968         if (!obj.isNull())
969             filter = NodeFilter(new JSNodeFilterCondition(obj));
970     }
971     return getDOMTreeWalker(exec, doc.createTreeWalker(toNode(args[0]), (long unsigned int)(args[1].toNumber(exec)), filter, args[3].toBoolean(exec)));
972   }
973   case DOMDocument::CreateEvent:
974     return getDOMEvent(exec,doc.createEvent(s));
975   case DOMDocument::GetOverrideStyle: {
976     DOM::Node arg0 = toNode(args[0]);
977     if (arg0.nodeType() != DOM::Node::ELEMENT_NODE)
978       return Undefined(); // throw exception?
979     else
980       return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string()));
981   }
982   case DOMDocument::ExecCommand: {
983     return Boolean(doc.execCommand(args[0].toString(exec).string(), args[1].toBoolean(exec), args[2].toString(exec).string()));
984   }
985   case DOMDocument::QueryCommandEnabled: {
986     return Boolean(doc.queryCommandEnabled(args[0].toString(exec).string()));
987   }
988   case DOMDocument::QueryCommandIndeterm: {
989     return Boolean(doc.queryCommandIndeterm(args[0].toString(exec).string()));
990   }
991   case DOMDocument::QueryCommandState: {
992     return Boolean(doc.queryCommandState(args[0].toString(exec).string()));
993   }
994   case DOMDocument::QueryCommandSupported: {
995     return Boolean(doc.queryCommandSupported(args[0].toString(exec).string()));
996   }
997   case DOMDocument::QueryCommandValue: {
998     DOM::DOMString commandValue(doc.queryCommandValue(args[0].toString(exec).string()));
999     // Method returns null DOMString to signal command is unsupported.
1000     // Micorsoft documentation for this method says:
1001     // "If not supported [for a command identifier], this method returns a Boolean set to false."
1002     if (commandValue.isNull())
1003         return Boolean(false);
1004     else 
1005         return String(commandValue);
1006   }
1007   default:
1008     break;
1009   }
1010
1011   return Undefined();
1012 }
1013
1014 // -------------------------------------------------------------------------
1015
1016 /* Source for DOMElementProtoTable. Use "make hashtables" to regenerate.
1017 @begin DOMElementProtoTable 17
1018   getAttribute          DOMElement::GetAttribute        DontDelete|Function 1
1019   setAttribute          DOMElement::SetAttribute        DontDelete|Function 2
1020   removeAttribute       DOMElement::RemoveAttribute     DontDelete|Function 1
1021   getAttributeNode      DOMElement::GetAttributeNode    DontDelete|Function 1
1022   setAttributeNode      DOMElement::SetAttributeNode    DontDelete|Function 2
1023   removeAttributeNode   DOMElement::RemoveAttributeNode DontDelete|Function 1
1024   getElementsByTagName  DOMElement::GetElementsByTagName        DontDelete|Function 1
1025   hasAttribute          DOMElement::HasAttribute        DontDelete|Function 1
1026   getAttributeNS        DOMElement::GetAttributeNS      DontDelete|Function 2
1027   setAttributeNS        DOMElement::SetAttributeNS      DontDelete|Function 3
1028   removeAttributeNS     DOMElement::RemoveAttributeNS   DontDelete|Function 2
1029   getAttributeNodeNS    DOMElement::GetAttributeNodeNS  DontDelete|Function 2
1030   setAttributeNodeNS    DOMElement::SetAttributeNodeNS  DontDelete|Function 1
1031   getElementsByTagNameNS DOMElement::GetElementsByTagNameNS     DontDelete|Function 2
1032   hasAttributeNS        DOMElement::HasAttributeNS      DontDelete|Function 2
1033 @end
1034 */
1035 DEFINE_PROTOTYPE("DOMElement",DOMElementProto)
1036 IMPLEMENT_PROTOFUNC(DOMElementProtoFunc)
1037 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMElementProto,DOMElementProtoFunc,DOMNodeProto)
1038
1039 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 };
1040 /* Source for DOMElementTable. Use "make hashtables" to regenerate.
1041 @begin DOMElementTable 3
1042   tagName       DOMElement::TagName                         DontDelete|ReadOnly
1043   style         DOMElement::Style                           DontDelete|ReadOnly
1044 @end
1045 */
1046 DOMElement::DOMElement(ExecState *exec, const DOM::Element &e)
1047   : DOMNode(DOMElementProto::self(exec), e) { }
1048
1049 DOMElement::DOMElement(const Object &proto, const DOM::Element &e)
1050   : DOMNode(proto, e) { }
1051
1052 Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const
1053 {
1054 #ifdef KJS_VERBOSE
1055   kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl;
1056 #endif
1057   DOM::Element element = static_cast<DOM::Element>(node);
1058
1059   const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName);
1060   if (entry)
1061   {
1062     switch( entry->value ) {
1063     case TagName:
1064       return getStringOrNull(element.tagName());
1065     case Style:
1066       return getDOMCSSStyleDeclaration(exec,element.style());
1067     default:
1068       kdWarning() << "Unhandled token in DOMElement::tryGet : " << entry->value << endl;
1069       break;
1070     }
1071   }
1072   // We have to check in DOMNode before giving access to attributes, otherwise
1073   // onload="..." would make onload return the string (attribute value) instead of
1074   // the listener object (function).
1075   if (DOMNode::hasProperty(exec, propertyName))
1076     return DOMNode::tryGet(exec, propertyName);
1077
1078   DOM::DOMString attr = element.getAttribute( propertyName.string() );
1079   // Give access to attributes
1080   if ( !attr.isNull() )
1081     return getStringOrNull( attr );
1082
1083   return Undefined();
1084 }
1085
1086 Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1087 {
1088   if (!thisObj.inherits(&KJS::DOMNode::info)) { // node should be enough here, given the cast
1089     Object err = Error::create(exec,TypeError);
1090     exec->setException(err);
1091     return err;
1092   }
1093   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
1094   DOM::Element element = static_cast<DOM::Element>(node);
1095
1096   switch(id) {
1097     case DOMElement::GetAttribute:
1098       // getString should be used here, since if the attribute isn't present at all, you should
1099       // return null and not "".
1100       return getStringOrNull(element.getAttribute(args[0].toString(exec).string()));
1101     case DOMElement::SetAttribute:
1102       element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string());
1103       return Undefined();
1104     case DOMElement::RemoveAttribute:
1105       element.removeAttribute(args[0].toString(exec).string());
1106       return Undefined();
1107     case DOMElement::GetAttributeNode:
1108       return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string()));
1109     case DOMElement::SetAttributeNode:
1110       return getDOMNode(exec,element.setAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1111     case DOMElement::RemoveAttributeNode:
1112       return getDOMNode(exec,element.removeAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1113     case DOMElement::GetElementsByTagName:
1114       return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string()));
1115     case DOMElement::HasAttribute: // DOM2
1116       return Boolean(element.hasAttribute(args[0].toString(exec).string()));
1117     case DOMElement::GetAttributeNS: // DOM2
1118       return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1119     case DOMElement::SetAttributeNS: // DOM2
1120       element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string());
1121       return Undefined();
1122     case DOMElement::RemoveAttributeNS: // DOM2
1123       element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string());
1124       return Undefined();
1125     case DOMElement::GetAttributeNodeNS: // DOM2
1126       return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1127     case DOMElement::SetAttributeNodeNS: // DOM2
1128       return getDOMNode(exec,element.setAttributeNodeNS((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1129     case DOMElement::GetElementsByTagNameNS: // DOM2
1130       return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1131     case DOMElement::HasAttributeNS: // DOM2
1132       return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1133   default:
1134     return Undefined();
1135   }
1136 }
1137
1138 // -------------------------------------------------------------------------
1139
1140 /* Source for DOMDOMImplementationProtoTable. Use "make hashtables" to regenerate.
1141 @begin DOMDOMImplementationProtoTable 5
1142   hasFeature            DOMDOMImplementation::HasFeature                DontDelete|Function 2
1143 # DOM2
1144   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet       DontDelete|Function 2
1145   createDocumentType    DOMDOMImplementation::CreateDocumentType        DontDelete|Function 3
1146   createDocument        DOMDOMImplementation::CreateDocument            DontDelete|Function 3
1147   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
1148 @end
1149 */
1150 DEFINE_PROTOTYPE("DOMImplementation",DOMDOMImplementationProto)
1151 IMPLEMENT_PROTOFUNC(DOMDOMImplementationProtoFunc)
1152 IMPLEMENT_PROTOTYPE(DOMDOMImplementationProto,DOMDOMImplementationProtoFunc)
1153
1154 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 };
1155
1156 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1157   : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { }
1158
1159 DOMDOMImplementation::~DOMDOMImplementation()
1160 {
1161   ScriptInterpreter::forgetDOMObject(implementation.handle());
1162 }
1163
1164 Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1165 {
1166   if (!thisObj.inherits(&KJS::DOMDOMImplementation::info)) {
1167     Object err = Error::create(exec,TypeError);
1168     exec->setException(err);
1169     return err;
1170   }
1171   DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation();
1172
1173   switch(id) {
1174   case DOMDOMImplementation::HasFeature:
1175     return Boolean(implementation.hasFeature(args[0].toString(exec).string(),args[1].toString(exec).string()));
1176   case DOMDOMImplementation::CreateDocumentType: // DOM2
1177     return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()));
1178   case DOMDOMImplementation::CreateDocument: // DOM2
1179     return getDOMNode(exec,implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2])));
1180   case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
1181     return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string()));
1182   case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
1183     return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string()));
1184   default:
1185     break;
1186   }
1187   return Undefined();
1188 }
1189
1190 // -------------------------------------------------------------------------
1191
1192 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 };
1193
1194 /* Source for DOMDocumentTypeTable. Use "make hashtables" to regenerate.
1195 @begin DOMDocumentTypeTable 6
1196   name                  DOMDocumentType::Name           DontDelete|ReadOnly
1197   entities              DOMDocumentType::Entities       DontDelete|ReadOnly
1198   notations             DOMDocumentType::Notations      DontDelete|ReadOnly
1199 # DOM2
1200   publicId              DOMDocumentType::PublicId       DontDelete|ReadOnly
1201   systemId              DOMDocumentType::SystemId       DontDelete|ReadOnly
1202   internalSubset        DOMDocumentType::InternalSubset DontDelete|ReadOnly
1203 @end
1204 */
1205 DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType &dt)
1206   : DOMNode( /*### no proto yet*/exec, dt ) { }
1207
1208 Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const
1209 {
1210   return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this);
1211 }
1212
1213 Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const
1214 {
1215   DOM::DocumentType type = static_cast<DOM::DocumentType>(node);
1216   switch (token) {
1217   case Name:
1218     return getStringOrNull(type.name());
1219   case Entities:
1220     return getDOMNamedNodeMap(exec,type.entities());
1221   case Notations:
1222     return getDOMNamedNodeMap(exec,type.notations());
1223   case PublicId: // DOM2
1224     return getStringOrNull(type.publicId());
1225   case SystemId: // DOM2
1226     return getStringOrNull(type.systemId());
1227   case InternalSubset: // DOM2
1228     return getStringOrNull(type.internalSubset());
1229   default:
1230     kdWarning() << "DOMDocumentType::getValueProperty unhandled token " << token << endl;
1231     return Value();
1232   }
1233 }
1234
1235 // -------------------------------------------------------------------------
1236
1237 /* Source for DOMNamedNodeMapProtoTable. Use "make hashtables" to regenerate.
1238 @begin DOMNamedNodeMapProtoTable 7
1239   getNamedItem          DOMNamedNodeMap::GetNamedItem           DontDelete|Function 1
1240   setNamedItem          DOMNamedNodeMap::SetNamedItem           DontDelete|Function 1
1241   removeNamedItem       DOMNamedNodeMap::RemoveNamedItem        DontDelete|Function 1
1242   item                  DOMNamedNodeMap::Item                   DontDelete|Function 1
1243 # DOM2
1244   getNamedItemNS        DOMNamedNodeMap::GetNamedItemNS         DontDelete|Function 2
1245   setNamedItemNS        DOMNamedNodeMap::SetNamedItemNS         DontDelete|Function 1
1246   removeNamedItemNS     DOMNamedNodeMap::RemoveNamedItemNS      DontDelete|Function 2
1247 @end
1248 */
1249 DEFINE_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto)
1250 IMPLEMENT_PROTOFUNC(DOMNamedNodeMapProtoFunc)
1251 IMPLEMENT_PROTOTYPE(DOMNamedNodeMapProto,DOMNamedNodeMapProtoFunc)
1252
1253 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, 0, 0 };
1254
1255 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1256   : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { }
1257
1258 DOMNamedNodeMap::~DOMNamedNodeMap()
1259 {
1260   ScriptInterpreter::forgetDOMObject(map.handle());
1261 }
1262
1263 // We have to implement hasProperty since we don't use a hashtable for 'length'
1264 // ## this breaks "for (..in..)" though.
1265 bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const
1266 {
1267   if (p == lengthPropertyName)
1268     return true;
1269   return DOMObject::hasProperty(exec, p);
1270 }
1271
1272 Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const
1273 {
1274   if (p == lengthPropertyName)
1275     return Number(map.length());
1276
1277   // array index ?
1278   bool ok;
1279   long unsigned int idx = p.toULong(&ok);
1280   if (ok)
1281     return getDOMNode(exec,map.item(idx));
1282
1283   // Anything else (including functions, defined in the prototype)
1284   return DOMObject::tryGet(exec, p);
1285 }
1286
1287 Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1288 {
1289   if (!thisObj.inherits(&KJS::DOMNamedNodeMap::info)) {
1290     Object err = Error::create(exec,TypeError);
1291     exec->setException(err);
1292     return err;
1293   }
1294   DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap();
1295
1296   switch(id) {
1297     case DOMNamedNodeMap::GetNamedItem:
1298       return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string()));
1299     case DOMNamedNodeMap::SetNamedItem:
1300       return getDOMNode(exec, map.setNamedItem((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1301     case DOMNamedNodeMap::RemoveNamedItem:
1302       return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string()));
1303     case DOMNamedNodeMap::Item:
1304       return getDOMNode(exec, map.item(args[0].toInt32(exec)));
1305     case DOMNamedNodeMap::GetNamedItemNS: // DOM2
1306       return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1307     case DOMNamedNodeMap::SetNamedItemNS: // DOM2
1308       return getDOMNode(exec, map.setNamedItemNS(toNode(args[0])));
1309     case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2
1310       return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1311     default:
1312       break;
1313   }
1314
1315   return Undefined();
1316 }
1317
1318 // -------------------------------------------------------------------------
1319
1320 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 };
1321
1322 /* Source for DOMProcessingInstructionTable. Use "make hashtables" to regenerate.
1323 @begin DOMProcessingInstructionTable 3
1324   target        DOMProcessingInstruction::Target        DontDelete|ReadOnly
1325   data          DOMProcessingInstruction::Data          DontDelete
1326   sheet         DOMProcessingInstruction::Sheet         DontDelete|ReadOnly
1327 @end
1328 */
1329 Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const
1330 {
1331   return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this);
1332 }
1333
1334 Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
1335 {
1336   switch (token) {
1337   case Target:
1338     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).target());
1339   case Data:
1340     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).data());
1341   case Sheet:
1342     return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet());
1343   default:
1344     kdWarning() << "DOMProcessingInstruction::getValueProperty unhandled token " << token << endl;
1345     return Value();
1346   }
1347 }
1348
1349 void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1350 {
1351   // Not worth using the hashtable for this one ;)
1352   if (propertyName == "data")
1353     static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string());
1354   else
1355     DOMNode::tryPut(exec, propertyName,value,attr);
1356 }
1357
1358 // -------------------------------------------------------------------------
1359
1360 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 };
1361
1362 /* Source for DOMNotationTable. Use "make hashtables" to regenerate.
1363 @begin DOMNotationTable 2
1364   publicId              DOMNotation::PublicId   DontDelete|ReadOnly
1365   systemId              DOMNotation::SystemId   DontDelete|ReadOnly
1366 @end
1367 */
1368 Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const
1369 {
1370   return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this);
1371 }
1372
1373 Value DOMNotation::getValueProperty(ExecState *, int token) const
1374 {
1375   switch (token) {
1376   case PublicId:
1377     return getStringOrNull(static_cast<DOM::Notation>(node).publicId());
1378   case SystemId:
1379     return getStringOrNull(static_cast<DOM::Notation>(node).systemId());
1380   default:
1381     kdWarning() << "DOMNotation::getValueProperty unhandled token " << token << endl;
1382     return Value();
1383   }
1384 }
1385
1386 // -------------------------------------------------------------------------
1387
1388 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 };
1389
1390 /* Source for DOMEntityTable. Use "make hashtables" to regenerate.
1391 @begin DOMEntityTable 2
1392   publicId              DOMEntity::PublicId             DontDelete|ReadOnly
1393   systemId              DOMEntity::SystemId             DontDelete|ReadOnly
1394   notationName          DOMEntity::NotationName DontDelete|ReadOnly
1395 @end
1396 */
1397 Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const
1398 {
1399   return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this);
1400 }
1401
1402 Value DOMEntity::getValueProperty(ExecState *, int token) const
1403 {
1404   switch (token) {
1405   case PublicId:
1406     return getStringOrNull(static_cast<DOM::Entity>(node).publicId());
1407   case SystemId:
1408     return getStringOrNull(static_cast<DOM::Entity>(node).systemId());
1409   case NotationName:
1410     return getStringOrNull(static_cast<DOM::Entity>(node).notationName());
1411   default:
1412     kdWarning() << "DOMEntity::getValueProperty unhandled token " << token << endl;
1413     return Value();
1414   }
1415 }
1416
1417 // -------------------------------------------------------------------------
1418
1419 Value KJS::getDOMDocumentNode(ExecState *exec, const DOM::Document &n)
1420 {
1421   DOMDocument *ret = 0;
1422   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1423
1424   if ((ret = static_cast<DOMDocument *>(interp->getDOMObject(n.handle()))))
1425     return Value(ret);
1426
1427   if (n.isHTMLDocument())
1428     ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n));
1429   else
1430     ret = new DOMDocument(exec, n);
1431
1432   Value val(ret);
1433   
1434   // Make sure the document is kept around by the window object, and works right with the
1435   // back/forward cache.
1436   if (n.view()) {
1437     static Identifier documentIdentifier("document");
1438     Window::retrieveWindow(n.view()->part())->putDirect(documentIdentifier, ret, DontDelete|ReadOnly);
1439   }
1440
1441   interp->putDOMObject(n.handle(), ret);
1442
1443   return val;
1444 }
1445
1446 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::Node& n)
1447 {
1448   if (!n.handle()) 
1449     return false;
1450
1451   // Check to see if the currently executing interpreter is allowed to access the specified node
1452   KHTMLPart *part = n.handle()->getDocument()->part();
1453   Window* win = part ? Window::retrieveWindow(part) : 0L;
1454   if ( !win || !win->isSafeScript(exec) )
1455     return false;
1456   return true;
1457 }
1458
1459
1460 Value KJS::getDOMNode(ExecState *exec, const DOM::Node &n)
1461 {
1462   DOMObject *ret = 0;
1463   if (n.isNull())
1464     return Null();
1465   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1466   DOM::NodeImpl *doc = n.ownerDocument().handle();
1467
1468   if ((ret = interp->getDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle())))
1469     return Value(ret);
1470
1471   switch (n.nodeType()) {
1472     case DOM::Node::ELEMENT_NODE:
1473       if (static_cast<DOM::Element>(n).isHTMLElement())
1474         ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n));
1475       else
1476         ret = new DOMElement(exec, static_cast<DOM::Element>(n));
1477       break;
1478     case DOM::Node::ATTRIBUTE_NODE:
1479       ret = new DOMAttr(exec, static_cast<DOM::Attr>(n));
1480       break;
1481     case DOM::Node::TEXT_NODE:
1482     case DOM::Node::CDATA_SECTION_NODE:
1483       ret = new DOMText(exec, static_cast<DOM::Text>(n));
1484       break;
1485     case DOM::Node::ENTITY_REFERENCE_NODE:
1486       ret = new DOMNode(exec, n);
1487       break;
1488     case DOM::Node::ENTITY_NODE:
1489       ret = new DOMEntity(exec, static_cast<DOM::Entity>(n));
1490       break;
1491     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
1492       ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n));
1493       break;
1494     case DOM::Node::COMMENT_NODE:
1495       ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n));
1496       break;
1497     case DOM::Node::DOCUMENT_NODE:
1498       // we don't want to cache the document itself in the per-document dictionary
1499       return getDOMDocumentNode(exec, static_cast<DOM::Document>(n));
1500     case DOM::Node::DOCUMENT_TYPE_NODE:
1501       ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n));
1502       break;
1503     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
1504       ret = new DOMNode(exec, n);
1505       break;
1506     case DOM::Node::NOTATION_NODE:
1507       ret = new DOMNotation(exec, static_cast<DOM::Notation>(n));
1508       break;
1509     default:
1510       ret = new DOMNode(exec, n);
1511   }
1512
1513   interp->putDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle(), ret);
1514
1515   return Value(ret);
1516 }
1517
1518 Value KJS::getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1519 {
1520   return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m));
1521 }
1522
1523 Value KJS::getRuntimeObject(ExecState *exec, const DOM::Node &node)
1524 {
1525     DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node);
1526     DOM::HTMLAppletElementImpl *appletElement = static_cast<DOM::HTMLAppletElementImpl *>(element.handle());
1527     
1528     if (appletElement->getAppletInstance()) {
1529         // The instance is owned by the applet element.
1530         RuntimeObjectImp *appletImp = new RuntimeObjectImp(appletElement->getAppletInstance(), false);
1531         return Value(appletImp);
1532     }
1533     return Undefined();
1534 }
1535
1536 Value KJS::getDOMNodeList(ExecState *exec, const DOM::NodeList &l)
1537 {
1538   return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l));
1539 }
1540
1541 Value KJS::getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1542 {
1543   return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i));
1544 }
1545
1546 // -------------------------------------------------------------------------
1547
1548 const ClassInfo NodeConstructor::info = { "NodeConstructor", 0, &NodeConstructorTable, 0 };
1549 /* Source for NodeConstructorTable. Use "make hashtables" to regenerate.
1550 @begin NodeConstructorTable 11
1551   ELEMENT_NODE          DOM::Node::ELEMENT_NODE         DontDelete|ReadOnly
1552   ATTRIBUTE_NODE        DOM::Node::ATTRIBUTE_NODE               DontDelete|ReadOnly
1553   TEXT_NODE             DOM::Node::TEXT_NODE            DontDelete|ReadOnly
1554   CDATA_SECTION_NODE    DOM::Node::CDATA_SECTION_NODE   DontDelete|ReadOnly
1555   ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE        DontDelete|ReadOnly
1556   ENTITY_NODE           DOM::Node::ENTITY_NODE          DontDelete|ReadOnly
1557   PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly
1558   COMMENT_NODE          DOM::Node::COMMENT_NODE         DontDelete|ReadOnly
1559   DOCUMENT_NODE         DOM::Node::DOCUMENT_NODE                DontDelete|ReadOnly
1560   DOCUMENT_TYPE_NODE    DOM::Node::DOCUMENT_TYPE_NODE   DontDelete|ReadOnly
1561   DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE      DontDelete|ReadOnly
1562   NOTATION_NODE         DOM::Node::NOTATION_NODE                DontDelete|ReadOnly
1563 @end
1564 */
1565 Value NodeConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1566 {
1567   return DOMObjectLookupGetValue<NodeConstructor, DOMObject>(exec, propertyName, &NodeConstructorTable, this);
1568 }
1569
1570 Value NodeConstructor::getValueProperty(ExecState *, int token) const
1571 {
1572   // We use the token as the value to return directly
1573   return Number((unsigned int)token);
1574 #if 0
1575   switch (token) {
1576   case ELEMENT_NODE:
1577     return Number((unsigned int)DOM::Node::ELEMENT_NODE);
1578   case ATTRIBUTE_NODE:
1579     return Number((unsigned int)DOM::Node::ATTRIBUTE_NODE);
1580   case TEXT_NODE:
1581     return Number((unsigned int)DOM::Node::TEXT_NODE);
1582   case CDATA_SECTION_NODE:
1583     return Number((unsigned int)DOM::Node::CDATA_SECTION_NODE);
1584   case ENTITY_REFERENCE_NODE:
1585     return Number((unsigned int)DOM::Node::ENTITY_REFERENCE_NODE);
1586   case ENTITY_NODE:
1587     return Number((unsigned int)DOM::Node::ENTITY_NODE);
1588   case PROCESSING_INSTRUCTION_NODE:
1589     return Number((unsigned int)DOM::Node::PROCESSING_INSTRUCTION_NODE);
1590   case COMMENT_NODE:
1591     return Number((unsigned int)DOM::Node::COMMENT_NODE);
1592   case DOCUMENT_NODE:
1593     return Number((unsigned int)DOM::Node::DOCUMENT_NODE);
1594   case DOCUMENT_TYPE_NODE:
1595     return Number((unsigned int)DOM::Node::DOCUMENT_TYPE_NODE);
1596   case DOCUMENT_FRAGMENT_NODE:
1597     return Number((unsigned int)DOM::Node::DOCUMENT_FRAGMENT_NODE);
1598   case NOTATION_NODE:
1599     return Number((unsigned int)DOM::Node::NOTATION_NODE);
1600   default:
1601     kdWarning() << "NodeConstructor::getValueProperty unhandled token " << token << endl;
1602     return Value();
1603   }
1604 #endif
1605 }
1606
1607 Object KJS::getNodeConstructor(ExecState *exec)
1608 {
1609   return Object(cacheGlobalObject<NodeConstructor>(exec, "[[node.constructor]]"));
1610 }
1611
1612 // -------------------------------------------------------------------------
1613
1614 const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 };
1615
1616 /* Source for DOMExceptionConstructorTable. Use "make hashtables" to regenerate.
1617 @begin DOMExceptionConstructorTable 15
1618   INDEX_SIZE_ERR                DOM::DOMException::INDEX_SIZE_ERR               DontDelete|ReadOnly
1619   DOMSTRING_SIZE_ERR            DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
1620   HIERARCHY_REQUEST_ERR         DOM::DOMException::HIERARCHY_REQUEST_ERR        DontDelete|ReadOnly
1621   WRONG_DOCUMENT_ERR            DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
1622   INVALID_CHARACTER_ERR         DOM::DOMException::INVALID_CHARACTER_ERR        DontDelete|ReadOnly
1623   NO_DATA_ALLOWED_ERR           DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
1624   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
1625   NOT_FOUND_ERR                 DOM::DOMException::NOT_FOUND_ERR                DontDelete|ReadOnly
1626   NOT_SUPPORTED_ERR             DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
1627   INUSE_ATTRIBUTE_ERR           DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
1628   INVALID_STATE_ERR             DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
1629   SYNTAX_ERR                    DOM::DOMException::SYNTAX_ERR           DontDelete|ReadOnly
1630   INVALID_MODIFICATION_ERR      DOM::DOMException::INVALID_MODIFICATION_ERR     DontDelete|ReadOnly
1631   NAMESPACE_ERR                 DOM::DOMException::NAMESPACE_ERR                DontDelete|ReadOnly
1632   INVALID_ACCESS_ERR            DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
1633 @end
1634 */
1635
1636 Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1637 {
1638   return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this);
1639 }
1640
1641 Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const
1642 {
1643   // We use the token as the value to return directly
1644   return Number((unsigned int)token);
1645 #if 0
1646   switch (token) {
1647   case INDEX_SIZE_ERR:
1648     return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR);
1649   case DOMSTRING_SIZE_ERR:
1650     return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR);
1651   case HIERARCHY_REQUEST_ERR:
1652     return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR);
1653   case WRONG_DOCUMENT_ERR:
1654     return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR);
1655   case INVALID_CHARACTER_ERR:
1656     return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR);
1657   case NO_DATA_ALLOWED_ERR:
1658     return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR);
1659   case NO_MODIFICATION_ALLOWED_ERR:
1660     return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR);
1661   case NOT_FOUND_ERR:
1662     return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR);
1663   case NOT_SUPPORTED_ERR:
1664     return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR);
1665   case INUSE_ATTRIBUTE_ERR:
1666     return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR);
1667   case INVALID_STATE_ERR:
1668     return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR);
1669   case SYNTAX_ERR:
1670     return Number((unsigned int)DOM::DOMException::SYNTAX_ERR);
1671   case INVALID_MODIFICATION_ERR:
1672     return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR);
1673   case NAMESPACE_ERR:
1674     return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR);
1675   case INVALID_ACCESS_ERR:
1676     return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR);
1677   default:
1678     kdWarning() << "DOMExceptionConstructor::getValueProperty unhandled token " << token << endl;
1679     return Value();
1680   }
1681 #endif
1682 }
1683
1684 Object KJS::getDOMExceptionConstructor(ExecState *exec)
1685 {
1686   return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]");
1687 }
1688
1689 // -------------------------------------------------------------------------
1690
1691 // Such a collection is usually very short-lived, it only exists
1692 // for constructs like document.forms.<name>[1],
1693 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
1694 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *, const QValueList<DOM::Node>& nodes )
1695   : DOMObject(), m_nodes(nodes)
1696 {
1697   // Maybe we should ref (and deref in the dtor) the nodes, though ?
1698 }
1699
1700 Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const
1701 {
1702   if (propertyName == lengthPropertyName)
1703     return Number(m_nodes.count());
1704   // index?
1705   bool ok;
1706   unsigned int u = propertyName.toULong(&ok);
1707   if (ok && u < m_nodes.count()) {
1708     DOM::Node node = m_nodes[u];
1709     return getDOMNode(exec,node);
1710   }
1711   // For IE compatibility, we need to be able to look up elements in a
1712   // document.formName.name result by id as well as be index.
1713
1714   if (!ok) {
1715     for (QValueListConstIterator<DOM::Node> it = m_nodes.begin(); it != m_nodes.end(); it++) {
1716       DOM::Node node = *it;
1717       DOM::NamedNodeMap attributes = node.attributes();
1718       if (attributes.isNull()) {
1719         continue;
1720       }
1721
1722       DOM::Node idAttr = attributes.getNamedItem("id");
1723       if (idAttr.isNull()) {
1724         continue;
1725       }
1726
1727       if (idAttr.nodeValue() == propertyName.string()) {
1728         return getDOMNode(exec,node);
1729       }
1730     }
1731   }
1732
1733   return DOMObject::tryGet(exec,propertyName);
1734 }
1735
1736 // -------------------------------------------------------------------------
1737
1738 const ClassInfo DOMCharacterData::info = { "CharacterImp",
1739                                           &DOMNode::info, &DOMCharacterDataTable, 0 };
1740 /*
1741 @begin DOMCharacterDataTable 2
1742   data          DOMCharacterData::Data          DontDelete
1743   length        DOMCharacterData::Length        DontDelete|ReadOnly
1744 @end
1745 @begin DOMCharacterDataProtoTable 7
1746   substringData DOMCharacterData::SubstringData DontDelete|Function 2
1747   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
1748   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
1749   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
1750   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
1751 @end
1752 */
1753 DEFINE_PROTOTYPE("DOMCharacterData",DOMCharacterDataProto)
1754 IMPLEMENT_PROTOFUNC(DOMCharacterDataProtoFunc)
1755 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMCharacterDataProto,DOMCharacterDataProtoFunc, DOMNodeProto)
1756
1757 DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData &d)
1758  : DOMNode(DOMCharacterDataProto::self(exec), d) {}
1759
1760 DOMCharacterData::DOMCharacterData(const Object &proto, const DOM::CharacterData &d)
1761  : DOMNode(proto, d) {}
1762
1763 Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const
1764 {
1765 #ifdef KJS_VERBOSE
1766   kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl;
1767 #endif
1768   return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this);
1769 }
1770
1771 Value DOMCharacterData::getValueProperty(ExecState *, int token) const
1772 {
1773   DOM::CharacterData data = static_cast<DOM::CharacterData>(node);
1774   switch (token) {
1775   case Data:
1776     return String(data.data());
1777   case Length:
1778     return Number(data.length());
1779  default:
1780    kdWarning() << "Unhandled token in DOMCharacterData::getValueProperty : " << token << endl;
1781    return Value();
1782   }
1783 }
1784
1785 void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1786 {
1787   if (propertyName == "data")
1788     static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string());
1789   else
1790     DOMNode::tryPut(exec, propertyName,value,attr);
1791 }
1792
1793 Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1794 {
1795   if (!thisObj.inherits(&KJS::DOMCharacterData::info)) {
1796     Object err = Error::create(exec,TypeError);
1797     exec->setException(err);
1798     return err;
1799   }
1800   DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData();
1801   switch(id) {
1802     case DOMCharacterData::SubstringData: {
1803       const int count = args[1].toInt32(exec);
1804       if (count < 0)
1805         throw DOMException(DOMException::INDEX_SIZE_ERR);
1806       return getStringOrNull(data.substringData(args[0].toInt32(exec), count));
1807     }
1808     case DOMCharacterData::AppendData:
1809       data.appendData(args[0].toString(exec).string());
1810       return Undefined();
1811     case DOMCharacterData::InsertData:
1812       data.insertData(args[0].toInt32(exec), args[1].toString(exec).string());
1813       return Undefined();
1814     case DOMCharacterData::DeleteData: {
1815       const int count = args[1].toInt32(exec);
1816       if (count < 0)
1817         throw DOMException(DOMException::INDEX_SIZE_ERR);
1818       data.deleteData(args[0].toInt32(exec), count);
1819       return Undefined();
1820     }
1821     case DOMCharacterData::ReplaceData: {
1822       const int count = args[1].toInt32(exec);
1823       if (count < 0)
1824         throw DOMException(DOMException::INDEX_SIZE_ERR);
1825       data.replaceData(args[0].toInt32(exec), count, args[2].toString(exec).string());
1826       return Undefined();
1827     }
1828     default:
1829       return Undefined();
1830   }
1831 }
1832
1833 // -------------------------------------------------------------------------
1834
1835 const ClassInfo DOMText::info = { "Text",
1836                                  &DOMCharacterData::info, 0, 0 };
1837 /*
1838 @begin DOMTextProtoTable 1
1839   splitText     DOMText::SplitText      DontDelete|Function 1
1840 @end
1841 */
1842 DEFINE_PROTOTYPE("DOMText",DOMTextProto)
1843 IMPLEMENT_PROTOFUNC(DOMTextProtoFunc)
1844 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMTextProto,DOMTextProtoFunc,DOMCharacterDataProto)
1845
1846 DOMText::DOMText(ExecState *exec, const DOM::Text &t)
1847   : DOMCharacterData(DOMTextProto::self(exec), t) { }
1848
1849 Value DOMText::tryGet(ExecState *exec, const Identifier &p) const
1850 {
1851   if (p == "")
1852     return Undefined(); // ### TODO
1853   else
1854     return DOMCharacterData::tryGet(exec, p);
1855 }
1856
1857 Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1858 {
1859   if (!thisObj.inherits(&KJS::DOMText::info)) {
1860     Object err = Error::create(exec,TypeError);
1861     exec->setException(err);
1862     return err;
1863   }
1864   DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText();
1865   switch(id) {
1866     case DOMText::SplitText:
1867       return getDOMNode(exec,text.splitText(args[0].toInt32(exec)));
1868       break;
1869     default:
1870       return Undefined();
1871   }
1872 }
1873