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