Fixed: <rdar://problem/3774243> page up/down, arrow up/down, etc in Safari RSS shoul...
[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 # extension for Safari RSS
1038   scrollByLines         DOMElement::ScrollByLines       DontDelete|Function 1
1039   scrollByPages         DOMElement::ScrollByPages       DontDelete|Function 1
1040
1041 @end
1042 */
1043 DEFINE_PROTOTYPE("DOMElement",DOMElementProto)
1044 IMPLEMENT_PROTOFUNC(DOMElementProtoFunc)
1045 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMElementProto,DOMElementProtoFunc,DOMNodeProto)
1046
1047 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 };
1048 /* Source for DOMElementTable. Use "make hashtables" to regenerate.
1049 @begin DOMElementTable 3
1050   tagName       DOMElement::TagName                         DontDelete|ReadOnly
1051   style         DOMElement::Style                           DontDelete|ReadOnly
1052 @end
1053 */
1054 DOMElement::DOMElement(ExecState *exec, const DOM::Element &e)
1055   : DOMNode(DOMElementProto::self(exec), e) { }
1056
1057 DOMElement::DOMElement(const Object &proto, const DOM::Element &e)
1058   : DOMNode(proto, e) { }
1059
1060 Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const
1061 {
1062 #ifdef KJS_VERBOSE
1063   kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl;
1064 #endif
1065   DOM::Element element = static_cast<DOM::Element>(node);
1066
1067   const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName);
1068   if (entry)
1069   {
1070     switch( entry->value ) {
1071     case TagName:
1072       return getStringOrNull(element.tagName());
1073     case Style:
1074       return getDOMCSSStyleDeclaration(exec,element.style());
1075     default:
1076       kdWarning() << "Unhandled token in DOMElement::tryGet : " << entry->value << endl;
1077       break;
1078     }
1079   }
1080   // We have to check in DOMNode before giving access to attributes, otherwise
1081   // onload="..." would make onload return the string (attribute value) instead of
1082   // the listener object (function).
1083   if (DOMNode::hasProperty(exec, propertyName))
1084     return DOMNode::tryGet(exec, propertyName);
1085
1086   DOM::DOMString attr = element.getAttribute( propertyName.string() );
1087   // Give access to attributes
1088   if ( !attr.isNull() )
1089     return getStringOrNull( attr );
1090
1091   return Undefined();
1092 }
1093
1094 Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1095 {
1096   if (!thisObj.inherits(&KJS::DOMNode::info)) { // node should be enough here, given the cast
1097     Object err = Error::create(exec,TypeError);
1098     exec->setException(err);
1099     return err;
1100   }
1101   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
1102   DOM::Element element = static_cast<DOM::Element>(node);
1103
1104   switch(id) {
1105     case DOMElement::GetAttribute:
1106       // getString should be used here, since if the attribute isn't present at all, you should
1107       // return null and not "".
1108       return getStringOrNull(element.getAttribute(args[0].toString(exec).string()));
1109     case DOMElement::SetAttribute:
1110       element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string());
1111       return Undefined();
1112     case DOMElement::RemoveAttribute:
1113       element.removeAttribute(args[0].toString(exec).string());
1114       return Undefined();
1115     case DOMElement::GetAttributeNode:
1116       return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string()));
1117     case DOMElement::SetAttributeNode:
1118       return getDOMNode(exec,element.setAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1119     case DOMElement::RemoveAttributeNode:
1120       return getDOMNode(exec,element.removeAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1121     case DOMElement::GetElementsByTagName:
1122       return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string()));
1123     case DOMElement::HasAttribute: // DOM2
1124       return Boolean(element.hasAttribute(args[0].toString(exec).string()));
1125     case DOMElement::GetAttributeNS: // DOM2
1126       return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1127     case DOMElement::SetAttributeNS: // DOM2
1128       element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string());
1129       return Undefined();
1130     case DOMElement::RemoveAttributeNS: // DOM2
1131       element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string());
1132       return Undefined();
1133     case DOMElement::GetAttributeNodeNS: // DOM2
1134       return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1135     case DOMElement::SetAttributeNodeNS: // DOM2
1136       return getDOMNode(exec,element.setAttributeNodeNS((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1137     case DOMElement::GetElementsByTagNameNS: // DOM2
1138       return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1139     case DOMElement::HasAttributeNS: // DOM2
1140       return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1141     case DOMElement::ScrollByLines:
1142     case DOMElement::ScrollByPages:
1143     {
1144         DOM::DocumentImpl* docimpl = node.handle()->getDocument();
1145         if (docimpl) {
1146             docimpl->updateLayoutIgnorePendingStylesheets();
1147         }            
1148         khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
1149         if (rend && rend->hasOverflowClip()) {
1150             KWQScrollDirection direction = KWQScrollDown;
1151             int multiplier = args[0].toInt32(exec);
1152             if (multiplier < 0) {
1153                 direction = KWQScrollUp;
1154                 multiplier = -multiplier;
1155             }
1156             KWQScrollGranularity granularity = id == DOMElement::ScrollByLines ? KWQScrollLine : KWQScrollPage;
1157             rend->layer()->scroll(direction, granularity, multiplier);
1158         }
1159         return Undefined();
1160         
1161     }
1162   default:
1163     return Undefined();
1164   }
1165 }
1166
1167 // -------------------------------------------------------------------------
1168
1169 /* Source for DOMDOMImplementationProtoTable. Use "make hashtables" to regenerate.
1170 @begin DOMDOMImplementationProtoTable 5
1171   hasFeature            DOMDOMImplementation::HasFeature                DontDelete|Function 2
1172 # DOM2
1173   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet       DontDelete|Function 2
1174   createDocumentType    DOMDOMImplementation::CreateDocumentType        DontDelete|Function 3
1175   createDocument        DOMDOMImplementation::CreateDocument            DontDelete|Function 3
1176   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
1177 @end
1178 */
1179 DEFINE_PROTOTYPE("DOMImplementation",DOMDOMImplementationProto)
1180 IMPLEMENT_PROTOFUNC(DOMDOMImplementationProtoFunc)
1181 IMPLEMENT_PROTOTYPE(DOMDOMImplementationProto,DOMDOMImplementationProtoFunc)
1182
1183 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 };
1184
1185 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1186   : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { }
1187
1188 DOMDOMImplementation::~DOMDOMImplementation()
1189 {
1190   ScriptInterpreter::forgetDOMObject(implementation.handle());
1191 }
1192
1193 Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1194 {
1195   if (!thisObj.inherits(&KJS::DOMDOMImplementation::info)) {
1196     Object err = Error::create(exec,TypeError);
1197     exec->setException(err);
1198     return err;
1199   }
1200   DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation();
1201
1202   switch(id) {
1203   case DOMDOMImplementation::HasFeature:
1204     return Boolean(implementation.hasFeature(args[0].toString(exec).string(),
1205         (args[1].type() != UndefinedType && args[1].type() != NullType) ? args[1].toString(exec).string() : DOMString()));
1206   case DOMDOMImplementation::CreateDocumentType: // DOM2
1207     return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()));
1208   case DOMDOMImplementation::CreateDocument: // DOM2
1209     return getDOMNode(exec,implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2])));
1210   case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
1211     return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string()));
1212   case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
1213     return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string()));
1214   default:
1215     break;
1216   }
1217   return Undefined();
1218 }
1219
1220 // -------------------------------------------------------------------------
1221
1222 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 };
1223
1224 /* Source for DOMDocumentTypeTable. Use "make hashtables" to regenerate.
1225 @begin DOMDocumentTypeTable 6
1226   name                  DOMDocumentType::Name           DontDelete|ReadOnly
1227   entities              DOMDocumentType::Entities       DontDelete|ReadOnly
1228   notations             DOMDocumentType::Notations      DontDelete|ReadOnly
1229 # DOM2
1230   publicId              DOMDocumentType::PublicId       DontDelete|ReadOnly
1231   systemId              DOMDocumentType::SystemId       DontDelete|ReadOnly
1232   internalSubset        DOMDocumentType::InternalSubset DontDelete|ReadOnly
1233 @end
1234 */
1235 DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType &dt)
1236   : DOMNode( /*### no proto yet*/exec, dt ) { }
1237
1238 Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const
1239 {
1240   return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this);
1241 }
1242
1243 Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const
1244 {
1245   DOM::DocumentType type = static_cast<DOM::DocumentType>(node);
1246   switch (token) {
1247   case Name:
1248     return getStringOrNull(type.name());
1249   case Entities:
1250     return getDOMNamedNodeMap(exec,type.entities());
1251   case Notations:
1252     return getDOMNamedNodeMap(exec,type.notations());
1253   case PublicId: // DOM2
1254     return getStringOrNull(type.publicId());
1255   case SystemId: // DOM2
1256     return getStringOrNull(type.systemId());
1257   case InternalSubset: // DOM2
1258     return getStringOrNull(type.internalSubset());
1259   default:
1260     kdWarning() << "DOMDocumentType::getValueProperty unhandled token " << token << endl;
1261     return Value();
1262   }
1263 }
1264
1265 // -------------------------------------------------------------------------
1266
1267 /* Source for DOMNamedNodeMapProtoTable. Use "make hashtables" to regenerate.
1268 @begin DOMNamedNodeMapProtoTable 7
1269   getNamedItem          DOMNamedNodeMap::GetNamedItem           DontDelete|Function 1
1270   setNamedItem          DOMNamedNodeMap::SetNamedItem           DontDelete|Function 1
1271   removeNamedItem       DOMNamedNodeMap::RemoveNamedItem        DontDelete|Function 1
1272   item                  DOMNamedNodeMap::Item                   DontDelete|Function 1
1273 # DOM2
1274   getNamedItemNS        DOMNamedNodeMap::GetNamedItemNS         DontDelete|Function 2
1275   setNamedItemNS        DOMNamedNodeMap::SetNamedItemNS         DontDelete|Function 1
1276   removeNamedItemNS     DOMNamedNodeMap::RemoveNamedItemNS      DontDelete|Function 2
1277 @end
1278 */
1279 DEFINE_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto)
1280 IMPLEMENT_PROTOFUNC(DOMNamedNodeMapProtoFunc)
1281 IMPLEMENT_PROTOTYPE(DOMNamedNodeMapProto,DOMNamedNodeMapProtoFunc)
1282
1283 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, 0, 0 };
1284
1285 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1286   : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { }
1287
1288 DOMNamedNodeMap::~DOMNamedNodeMap()
1289 {
1290   ScriptInterpreter::forgetDOMObject(map.handle());
1291 }
1292
1293 // We have to implement hasProperty since we don't use a hashtable for 'length'
1294 // ## this breaks "for (..in..)" though.
1295 bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const
1296 {
1297   if (p == lengthPropertyName)
1298     return true;
1299   return DOMObject::hasProperty(exec, p);
1300 }
1301
1302 Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const
1303 {
1304   if (p == lengthPropertyName)
1305     return Number(map.length());
1306
1307   // array index ?
1308   bool ok;
1309   long unsigned int idx = p.toULong(&ok);
1310   if (ok)
1311     return getDOMNode(exec,map.item(idx));
1312
1313   // Anything else (including functions, defined in the prototype)
1314   return DOMObject::tryGet(exec, p);
1315 }
1316
1317 Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1318 {
1319   if (!thisObj.inherits(&KJS::DOMNamedNodeMap::info)) {
1320     Object err = Error::create(exec,TypeError);
1321     exec->setException(err);
1322     return err;
1323   }
1324   DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap();
1325
1326   switch(id) {
1327     case DOMNamedNodeMap::GetNamedItem:
1328       return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string()));
1329     case DOMNamedNodeMap::SetNamedItem:
1330       return getDOMNode(exec, map.setNamedItem((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1331     case DOMNamedNodeMap::RemoveNamedItem:
1332       return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string()));
1333     case DOMNamedNodeMap::Item:
1334       return getDOMNode(exec, map.item(args[0].toInt32(exec)));
1335     case DOMNamedNodeMap::GetNamedItemNS: // DOM2
1336       return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1337     case DOMNamedNodeMap::SetNamedItemNS: // DOM2
1338       return getDOMNode(exec, map.setNamedItemNS(toNode(args[0])));
1339     case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2
1340       return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1341     default:
1342       break;
1343   }
1344
1345   return Undefined();
1346 }
1347
1348 // -------------------------------------------------------------------------
1349
1350 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 };
1351
1352 /* Source for DOMProcessingInstructionTable. Use "make hashtables" to regenerate.
1353 @begin DOMProcessingInstructionTable 3
1354   target        DOMProcessingInstruction::Target        DontDelete|ReadOnly
1355   data          DOMProcessingInstruction::Data          DontDelete
1356   sheet         DOMProcessingInstruction::Sheet         DontDelete|ReadOnly
1357 @end
1358 */
1359 Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const
1360 {
1361   return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this);
1362 }
1363
1364 Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
1365 {
1366   switch (token) {
1367   case Target:
1368     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).target());
1369   case Data:
1370     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).data());
1371   case Sheet:
1372     return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet());
1373   default:
1374     kdWarning() << "DOMProcessingInstruction::getValueProperty unhandled token " << token << endl;
1375     return Value();
1376   }
1377 }
1378
1379 void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1380 {
1381   // Not worth using the hashtable for this one ;)
1382   if (propertyName == "data")
1383     static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string());
1384   else
1385     DOMNode::tryPut(exec, propertyName,value,attr);
1386 }
1387
1388 // -------------------------------------------------------------------------
1389
1390 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 };
1391
1392 /* Source for DOMNotationTable. Use "make hashtables" to regenerate.
1393 @begin DOMNotationTable 2
1394   publicId              DOMNotation::PublicId   DontDelete|ReadOnly
1395   systemId              DOMNotation::SystemId   DontDelete|ReadOnly
1396 @end
1397 */
1398 Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const
1399 {
1400   return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this);
1401 }
1402
1403 Value DOMNotation::getValueProperty(ExecState *, int token) const
1404 {
1405   switch (token) {
1406   case PublicId:
1407     return getStringOrNull(static_cast<DOM::Notation>(node).publicId());
1408   case SystemId:
1409     return getStringOrNull(static_cast<DOM::Notation>(node).systemId());
1410   default:
1411     kdWarning() << "DOMNotation::getValueProperty unhandled token " << token << endl;
1412     return Value();
1413   }
1414 }
1415
1416 // -------------------------------------------------------------------------
1417
1418 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 };
1419
1420 /* Source for DOMEntityTable. Use "make hashtables" to regenerate.
1421 @begin DOMEntityTable 2
1422   publicId              DOMEntity::PublicId             DontDelete|ReadOnly
1423   systemId              DOMEntity::SystemId             DontDelete|ReadOnly
1424   notationName          DOMEntity::NotationName DontDelete|ReadOnly
1425 @end
1426 */
1427 Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const
1428 {
1429   return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this);
1430 }
1431
1432 Value DOMEntity::getValueProperty(ExecState *, int token) const
1433 {
1434   switch (token) {
1435   case PublicId:
1436     return getStringOrNull(static_cast<DOM::Entity>(node).publicId());
1437   case SystemId:
1438     return getStringOrNull(static_cast<DOM::Entity>(node).systemId());
1439   case NotationName:
1440     return getStringOrNull(static_cast<DOM::Entity>(node).notationName());
1441   default:
1442     kdWarning() << "DOMEntity::getValueProperty unhandled token " << token << endl;
1443     return Value();
1444   }
1445 }
1446
1447 // -------------------------------------------------------------------------
1448
1449 Value KJS::getDOMDocumentNode(ExecState *exec, const DOM::Document &n)
1450 {
1451   DOMDocument *ret = 0;
1452   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1453
1454   if ((ret = static_cast<DOMDocument *>(interp->getDOMObject(n.handle()))))
1455     return Value(ret);
1456
1457   if (n.isHTMLDocument())
1458     ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n));
1459   else
1460     ret = new DOMDocument(exec, n);
1461
1462   Value val(ret);
1463   
1464   // Make sure the document is kept around by the window object, and works right with the
1465   // back/forward cache.
1466   if (n.view()) {
1467     static Identifier documentIdentifier("document");
1468     Window::retrieveWindow(n.view()->part())->putDirect(documentIdentifier, ret, DontDelete|ReadOnly);
1469   }
1470
1471   interp->putDOMObject(n.handle(), ret);
1472
1473   return val;
1474 }
1475
1476 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::Node& n)
1477 {
1478   if (!n.handle()) 
1479     return false;
1480
1481   // Check to see if the currently executing interpreter is allowed to access the specified node
1482   KHTMLPart *part = n.handle()->getDocument()->part();
1483   Window* win = part ? Window::retrieveWindow(part) : 0L;
1484   if ( !win || !win->isSafeScript(exec) )
1485     return false;
1486   return true;
1487 }
1488
1489
1490 Value KJS::getDOMNode(ExecState *exec, const DOM::Node &n)
1491 {
1492   DOMObject *ret = 0;
1493   if (n.isNull())
1494     return Null();
1495   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1496   DOM::NodeImpl *doc = n.ownerDocument().handle();
1497
1498   if ((ret = interp->getDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle())))
1499     return Value(ret);
1500
1501   switch (n.nodeType()) {
1502     case DOM::Node::ELEMENT_NODE:
1503       if (static_cast<DOM::Element>(n).isHTMLElement())
1504         ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n));
1505       else
1506         ret = new DOMElement(exec, static_cast<DOM::Element>(n));
1507       break;
1508     case DOM::Node::ATTRIBUTE_NODE:
1509       ret = new DOMAttr(exec, static_cast<DOM::Attr>(n));
1510       break;
1511     case DOM::Node::TEXT_NODE:
1512     case DOM::Node::CDATA_SECTION_NODE:
1513       ret = new DOMText(exec, static_cast<DOM::Text>(n));
1514       break;
1515     case DOM::Node::ENTITY_REFERENCE_NODE:
1516       ret = new DOMNode(exec, n);
1517       break;
1518     case DOM::Node::ENTITY_NODE:
1519       ret = new DOMEntity(exec, static_cast<DOM::Entity>(n));
1520       break;
1521     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
1522       ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n));
1523       break;
1524     case DOM::Node::COMMENT_NODE:
1525       ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n));
1526       break;
1527     case DOM::Node::DOCUMENT_NODE:
1528       // we don't want to cache the document itself in the per-document dictionary
1529       return getDOMDocumentNode(exec, static_cast<DOM::Document>(n));
1530     case DOM::Node::DOCUMENT_TYPE_NODE:
1531       ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n));
1532       break;
1533     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
1534       ret = new DOMNode(exec, n);
1535       break;
1536     case DOM::Node::NOTATION_NODE:
1537       ret = new DOMNotation(exec, static_cast<DOM::Notation>(n));
1538       break;
1539     default:
1540       ret = new DOMNode(exec, n);
1541   }
1542
1543   interp->putDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle(), ret);
1544
1545   return Value(ret);
1546 }
1547
1548 Value KJS::getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1549 {
1550   return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m));
1551 }
1552
1553 Value KJS::getRuntimeObject(ExecState *exec, const DOM::Node &node)
1554 {
1555     DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node);
1556
1557     if (!node.isNull()) {
1558         if (node.handle()->id() == ID_APPLET) {
1559             DOM::HTMLAppletElementImpl *appletElement = static_cast<DOM::HTMLAppletElementImpl *>(element.handle());
1560             
1561             if (appletElement->getAppletInstance()) {
1562                 // The instance is owned by the applet element.
1563                 RuntimeObjectImp *appletImp = new RuntimeObjectImp(appletElement->getAppletInstance(), false);
1564                 return Value(appletImp);
1565             }
1566         }
1567         else if (node.handle()->id() == ID_EMBED) {
1568             DOM::HTMLEmbedElementImpl *embedElement = static_cast<DOM::HTMLEmbedElementImpl *>(element.handle());
1569             
1570             if (embedElement->getEmbedInstance()) {
1571                 RuntimeObjectImp *runtimeImp = new RuntimeObjectImp(embedElement->getEmbedInstance(), false);
1572                 return Value(runtimeImp);
1573             }
1574         }
1575     }
1576     return Undefined();
1577 }
1578
1579 Value KJS::getDOMNodeList(ExecState *exec, const DOM::NodeList &l)
1580 {
1581   return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l));
1582 }
1583
1584 Value KJS::getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1585 {
1586   return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i));
1587 }
1588
1589 // -------------------------------------------------------------------------
1590
1591 const ClassInfo NodeConstructor::info = { "NodeConstructor", 0, &NodeConstructorTable, 0 };
1592 /* Source for NodeConstructorTable. Use "make hashtables" to regenerate.
1593 @begin NodeConstructorTable 11
1594   ELEMENT_NODE          DOM::Node::ELEMENT_NODE         DontDelete|ReadOnly
1595   ATTRIBUTE_NODE        DOM::Node::ATTRIBUTE_NODE               DontDelete|ReadOnly
1596   TEXT_NODE             DOM::Node::TEXT_NODE            DontDelete|ReadOnly
1597   CDATA_SECTION_NODE    DOM::Node::CDATA_SECTION_NODE   DontDelete|ReadOnly
1598   ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE        DontDelete|ReadOnly
1599   ENTITY_NODE           DOM::Node::ENTITY_NODE          DontDelete|ReadOnly
1600   PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly
1601   COMMENT_NODE          DOM::Node::COMMENT_NODE         DontDelete|ReadOnly
1602   DOCUMENT_NODE         DOM::Node::DOCUMENT_NODE                DontDelete|ReadOnly
1603   DOCUMENT_TYPE_NODE    DOM::Node::DOCUMENT_TYPE_NODE   DontDelete|ReadOnly
1604   DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE      DontDelete|ReadOnly
1605   NOTATION_NODE         DOM::Node::NOTATION_NODE                DontDelete|ReadOnly
1606 @end
1607 */
1608 Value NodeConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1609 {
1610   return DOMObjectLookupGetValue<NodeConstructor, DOMObject>(exec, propertyName, &NodeConstructorTable, this);
1611 }
1612
1613 Value NodeConstructor::getValueProperty(ExecState *, int token) const
1614 {
1615   // We use the token as the value to return directly
1616   return Number((unsigned int)token);
1617 #if 0
1618   switch (token) {
1619   case ELEMENT_NODE:
1620     return Number((unsigned int)DOM::Node::ELEMENT_NODE);
1621   case ATTRIBUTE_NODE:
1622     return Number((unsigned int)DOM::Node::ATTRIBUTE_NODE);
1623   case TEXT_NODE:
1624     return Number((unsigned int)DOM::Node::TEXT_NODE);
1625   case CDATA_SECTION_NODE:
1626     return Number((unsigned int)DOM::Node::CDATA_SECTION_NODE);
1627   case ENTITY_REFERENCE_NODE:
1628     return Number((unsigned int)DOM::Node::ENTITY_REFERENCE_NODE);
1629   case ENTITY_NODE:
1630     return Number((unsigned int)DOM::Node::ENTITY_NODE);
1631   case PROCESSING_INSTRUCTION_NODE:
1632     return Number((unsigned int)DOM::Node::PROCESSING_INSTRUCTION_NODE);
1633   case COMMENT_NODE:
1634     return Number((unsigned int)DOM::Node::COMMENT_NODE);
1635   case DOCUMENT_NODE:
1636     return Number((unsigned int)DOM::Node::DOCUMENT_NODE);
1637   case DOCUMENT_TYPE_NODE:
1638     return Number((unsigned int)DOM::Node::DOCUMENT_TYPE_NODE);
1639   case DOCUMENT_FRAGMENT_NODE:
1640     return Number((unsigned int)DOM::Node::DOCUMENT_FRAGMENT_NODE);
1641   case NOTATION_NODE:
1642     return Number((unsigned int)DOM::Node::NOTATION_NODE);
1643   default:
1644     kdWarning() << "NodeConstructor::getValueProperty unhandled token " << token << endl;
1645     return Value();
1646   }
1647 #endif
1648 }
1649
1650 Object KJS::getNodeConstructor(ExecState *exec)
1651 {
1652   return Object(cacheGlobalObject<NodeConstructor>(exec, "[[node.constructor]]"));
1653 }
1654
1655 // -------------------------------------------------------------------------
1656
1657 const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 };
1658
1659 /* Source for DOMExceptionConstructorTable. Use "make hashtables" to regenerate.
1660 @begin DOMExceptionConstructorTable 15
1661   INDEX_SIZE_ERR                DOM::DOMException::INDEX_SIZE_ERR               DontDelete|ReadOnly
1662   DOMSTRING_SIZE_ERR            DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
1663   HIERARCHY_REQUEST_ERR         DOM::DOMException::HIERARCHY_REQUEST_ERR        DontDelete|ReadOnly
1664   WRONG_DOCUMENT_ERR            DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
1665   INVALID_CHARACTER_ERR         DOM::DOMException::INVALID_CHARACTER_ERR        DontDelete|ReadOnly
1666   NO_DATA_ALLOWED_ERR           DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
1667   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
1668   NOT_FOUND_ERR                 DOM::DOMException::NOT_FOUND_ERR                DontDelete|ReadOnly
1669   NOT_SUPPORTED_ERR             DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
1670   INUSE_ATTRIBUTE_ERR           DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
1671   INVALID_STATE_ERR             DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
1672   SYNTAX_ERR                    DOM::DOMException::SYNTAX_ERR           DontDelete|ReadOnly
1673   INVALID_MODIFICATION_ERR      DOM::DOMException::INVALID_MODIFICATION_ERR     DontDelete|ReadOnly
1674   NAMESPACE_ERR                 DOM::DOMException::NAMESPACE_ERR                DontDelete|ReadOnly
1675   INVALID_ACCESS_ERR            DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
1676 @end
1677 */
1678
1679 Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1680 {
1681   return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this);
1682 }
1683
1684 Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const
1685 {
1686   // We use the token as the value to return directly
1687   return Number((unsigned int)token);
1688 #if 0
1689   switch (token) {
1690   case INDEX_SIZE_ERR:
1691     return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR);
1692   case DOMSTRING_SIZE_ERR:
1693     return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR);
1694   case HIERARCHY_REQUEST_ERR:
1695     return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR);
1696   case WRONG_DOCUMENT_ERR:
1697     return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR);
1698   case INVALID_CHARACTER_ERR:
1699     return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR);
1700   case NO_DATA_ALLOWED_ERR:
1701     return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR);
1702   case NO_MODIFICATION_ALLOWED_ERR:
1703     return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR);
1704   case NOT_FOUND_ERR:
1705     return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR);
1706   case NOT_SUPPORTED_ERR:
1707     return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR);
1708   case INUSE_ATTRIBUTE_ERR:
1709     return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR);
1710   case INVALID_STATE_ERR:
1711     return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR);
1712   case SYNTAX_ERR:
1713     return Number((unsigned int)DOM::DOMException::SYNTAX_ERR);
1714   case INVALID_MODIFICATION_ERR:
1715     return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR);
1716   case NAMESPACE_ERR:
1717     return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR);
1718   case INVALID_ACCESS_ERR:
1719     return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR);
1720   default:
1721     kdWarning() << "DOMExceptionConstructor::getValueProperty unhandled token " << token << endl;
1722     return Value();
1723   }
1724 #endif
1725 }
1726
1727 Object KJS::getDOMExceptionConstructor(ExecState *exec)
1728 {
1729   return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]");
1730 }
1731
1732 // -------------------------------------------------------------------------
1733
1734 // Such a collection is usually very short-lived, it only exists
1735 // for constructs like document.forms.<name>[1],
1736 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
1737 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *, const QValueList<DOM::Node>& nodes )
1738   : DOMObject(), m_nodes(nodes)
1739 {
1740   // Maybe we should ref (and deref in the dtor) the nodes, though ?
1741 }
1742
1743 Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const
1744 {
1745   if (propertyName == lengthPropertyName)
1746     return Number(m_nodes.count());
1747   // index?
1748   bool ok;
1749   unsigned int u = propertyName.toULong(&ok);
1750   if (ok && u < m_nodes.count()) {
1751     DOM::Node node = m_nodes[u];
1752     return getDOMNode(exec,node);
1753   }
1754   // For IE compatibility, we need to be able to look up elements in a
1755   // document.formName.name result by id as well as be index.
1756
1757   if (!ok) {
1758     for (QValueListConstIterator<DOM::Node> it = m_nodes.begin(); it != m_nodes.end(); it++) {
1759       DOM::Node node = *it;
1760       DOM::NamedNodeMap attributes = node.attributes();
1761       if (attributes.isNull()) {
1762         continue;
1763       }
1764
1765       DOM::Node idAttr = attributes.getNamedItem("id");
1766       if (idAttr.isNull()) {
1767         continue;
1768       }
1769
1770       if (idAttr.nodeValue() == propertyName.string()) {
1771         return getDOMNode(exec,node);
1772       }
1773     }
1774   }
1775
1776   return DOMObject::tryGet(exec,propertyName);
1777 }
1778
1779 // -------------------------------------------------------------------------
1780
1781 const ClassInfo DOMCharacterData::info = { "CharacterImp",
1782                                           &DOMNode::info, &DOMCharacterDataTable, 0 };
1783 /*
1784 @begin DOMCharacterDataTable 2
1785   data          DOMCharacterData::Data          DontDelete
1786   length        DOMCharacterData::Length        DontDelete|ReadOnly
1787 @end
1788 @begin DOMCharacterDataProtoTable 7
1789   substringData DOMCharacterData::SubstringData DontDelete|Function 2
1790   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
1791   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
1792   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
1793   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
1794 @end
1795 */
1796 DEFINE_PROTOTYPE("DOMCharacterData",DOMCharacterDataProto)
1797 IMPLEMENT_PROTOFUNC(DOMCharacterDataProtoFunc)
1798 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMCharacterDataProto,DOMCharacterDataProtoFunc, DOMNodeProto)
1799
1800 DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData &d)
1801  : DOMNode(DOMCharacterDataProto::self(exec), d) {}
1802
1803 DOMCharacterData::DOMCharacterData(const Object &proto, const DOM::CharacterData &d)
1804  : DOMNode(proto, d) {}
1805
1806 Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const
1807 {
1808 #ifdef KJS_VERBOSE
1809   kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl;
1810 #endif
1811   return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this);
1812 }
1813
1814 Value DOMCharacterData::getValueProperty(ExecState *, int token) const
1815 {
1816   DOM::CharacterData data = static_cast<DOM::CharacterData>(node);
1817   switch (token) {
1818   case Data:
1819     return String(data.data());
1820   case Length:
1821     return Number(data.length());
1822  default:
1823    kdWarning() << "Unhandled token in DOMCharacterData::getValueProperty : " << token << endl;
1824    return Value();
1825   }
1826 }
1827
1828 void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1829 {
1830   if (propertyName == "data")
1831     static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string());
1832   else
1833     DOMNode::tryPut(exec, propertyName,value,attr);
1834 }
1835
1836 Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1837 {
1838   if (!thisObj.inherits(&KJS::DOMCharacterData::info)) {
1839     Object err = Error::create(exec,TypeError);
1840     exec->setException(err);
1841     return err;
1842   }
1843   DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData();
1844   switch(id) {
1845     case DOMCharacterData::SubstringData: {
1846       const int count = args[1].toInt32(exec);
1847       if (count < 0)
1848         throw DOMException(DOMException::INDEX_SIZE_ERR);
1849       return getStringOrNull(data.substringData(args[0].toInt32(exec), count));
1850     }
1851     case DOMCharacterData::AppendData:
1852       data.appendData(args[0].toString(exec).string());
1853       return Undefined();
1854     case DOMCharacterData::InsertData:
1855       data.insertData(args[0].toInt32(exec), args[1].toString(exec).string());
1856       return Undefined();
1857     case DOMCharacterData::DeleteData: {
1858       const int count = args[1].toInt32(exec);
1859       if (count < 0)
1860         throw DOMException(DOMException::INDEX_SIZE_ERR);
1861       data.deleteData(args[0].toInt32(exec), count);
1862       return Undefined();
1863     }
1864     case DOMCharacterData::ReplaceData: {
1865       const int count = args[1].toInt32(exec);
1866       if (count < 0)
1867         throw DOMException(DOMException::INDEX_SIZE_ERR);
1868       data.replaceData(args[0].toInt32(exec), count, args[2].toString(exec).string());
1869       return Undefined();
1870     }
1871     default:
1872       return Undefined();
1873   }
1874 }
1875
1876 // -------------------------------------------------------------------------
1877
1878 const ClassInfo DOMText::info = { "Text",
1879                                  &DOMCharacterData::info, 0, 0 };
1880 /*
1881 @begin DOMTextProtoTable 1
1882   splitText     DOMText::SplitText      DontDelete|Function 1
1883 @end
1884 */
1885 DEFINE_PROTOTYPE("DOMText",DOMTextProto)
1886 IMPLEMENT_PROTOFUNC(DOMTextProtoFunc)
1887 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMTextProto,DOMTextProtoFunc,DOMCharacterDataProto)
1888
1889 DOMText::DOMText(ExecState *exec, const DOM::Text &t)
1890   : DOMCharacterData(DOMTextProto::self(exec), t) { }
1891
1892 Value DOMText::tryGet(ExecState *exec, const Identifier &p) const
1893 {
1894   if (p == "")
1895     return Undefined(); // ### TODO
1896   else
1897     return DOMCharacterData::tryGet(exec, p);
1898 }
1899
1900 Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1901 {
1902   if (!thisObj.inherits(&KJS::DOMText::info)) {
1903     Object err = Error::create(exec,TypeError);
1904     exec->setException(err);
1905     return err;
1906   }
1907   DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText();
1908   switch(id) {
1909     case DOMText::SplitText:
1910       return getDOMNode(exec,text.splitText(args[0].toInt32(exec)));
1911       break;
1912     default:
1913       return Undefined();
1914   }
1915 }
1916