WebCore:
[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::Node node = list.itemById(p.string());
657
658       if (!node.isNull()) {
659         result = getDOMNode(exec, node);
660       } else {
661         result = ObjectImp::get(exec, p);
662       }
663     }
664   }
665
666   return result;
667 }
668
669 // Need to support both get and call, so that list[0] and list(0) work.
670 Value DOMNodeList::call(ExecState *exec, Object &thisObj, const List &args)
671 {
672   // This code duplication is necessary, DOMNodeList isn't a DOMFunction
673   Value val;
674   try {
675     val = tryCall(exec, thisObj, args);
676   }
677   // pity there's no way to distinguish between these in JS code
678   catch (...) {
679     Object err = Error::create(exec, GeneralError, "Exception from DOMNodeList");
680     exec->setException(err);
681   }
682   return val;
683 }
684
685 Value DOMNodeList::tryCall(ExecState *exec, Object &, const List &args)
686 {
687   // Do not use thisObj here. See HTMLCollection.
688   UString s = args[0].toString(exec);
689   bool ok;
690   unsigned int u = s.toULong(&ok);
691   if (ok)
692     return getDOMNode(exec,list.item(u));
693
694   kdWarning() << "KJS::DOMNodeList::tryCall " << s.qstring() << " not implemented" << endl;
695   return Undefined();
696 }
697
698 DOMNodeListFunc::DOMNodeListFunc(ExecState *exec, int i, int len)
699   : DOMFunction(), id(i)
700 {
701   Value protect(this);
702   put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum);
703 }
704
705 // Not a prototype class currently, but should probably be converted to one
706 Value DOMNodeListFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
707 {
708   if (!thisObj.inherits(&KJS::DOMNodeList::info)) {
709     Object err = Error::create(exec,TypeError);
710     exec->setException(err);
711     return err;
712   }
713   DOM::NodeList list = static_cast<DOMNodeList *>(thisObj.imp())->nodeList();
714   Value result;
715
716   if (id == Item)
717     result = getDOMNode(exec, list.item(args[0].toInt32(exec)));
718   return result;
719 }
720
721 // -------------------------------------------------------------------------
722
723 const ClassInfo DOMAttr::info = { "Attr", &DOMNode::info, &DOMAttrTable, 0 };
724
725 /* Source for DOMAttrTable. Use "make hashtables" to regenerate.
726 @begin DOMAttrTable 5
727   name          DOMAttr::Name           DontDelete|ReadOnly
728   specified     DOMAttr::Specified      DontDelete|ReadOnly
729   value         DOMAttr::ValueProperty  DontDelete|ReadOnly
730   ownerElement  DOMAttr::OwnerElement   DontDelete|ReadOnly
731 @end
732 */
733 Value DOMAttr::tryGet(ExecState *exec, const Identifier &propertyName) const
734 {
735 #ifdef KJS_VERBOSE
736   kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl;
737 #endif
738   return DOMObjectLookupGetValue<DOMAttr,DOMNode>(exec, propertyName,
739                                                   &DOMAttrTable, this );
740 }
741
742 Value DOMAttr::getValueProperty(ExecState *exec, int token) const
743 {
744   switch (token) {
745   case Name:
746     return getStringOrNull(static_cast<DOM::Attr>(node).name());
747   case Specified:
748     return Boolean(static_cast<DOM::Attr>(node).specified());
749   case ValueProperty:
750     return getStringOrNull(static_cast<DOM::Attr>(node).value());
751   case OwnerElement: // DOM2
752     return getDOMNode(exec,static_cast<DOM::Attr>(node).ownerElement());
753   }
754   return Value(); // not reached
755 }
756
757 void DOMAttr::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
758 {
759 #ifdef KJS_VERBOSE
760   kdDebug(6070) << "DOMAttr::tryPut " << propertyName.qstring() << endl;
761 #endif
762   DOMObjectLookupPut<DOMAttr,DOMNode>(exec, propertyName, value, attr,
763                                       &DOMAttrTable, this );
764 }
765
766 void DOMAttr::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
767 {
768   switch (token) {
769   case ValueProperty:
770     static_cast<DOM::Attr>(node).setValue(value.toString(exec).string());
771     return;
772   default:
773     kdWarning() << "DOMAttr::putValue unhandled token " << token << endl;
774   }
775 }
776
777 // -------------------------------------------------------------------------
778
779 /* Source for DOMDocumentProtoTable. Use "make hashtables" to regenerate.
780 @begin DOMDocumentProtoTable 29
781   createElement   DOMDocument::CreateElement                   DontDelete|Function 1
782   createDocumentFragment DOMDocument::CreateDocumentFragment   DontDelete|Function 1
783   createTextNode  DOMDocument::CreateTextNode                  DontDelete|Function 1
784   createComment   DOMDocument::CreateComment                   DontDelete|Function 1
785   createCDATASection DOMDocument::CreateCDATASection           DontDelete|Function 1
786   createProcessingInstruction DOMDocument::CreateProcessingInstruction DontDelete|Function 1
787   createAttribute DOMDocument::CreateAttribute                 DontDelete|Function 1
788   createEntityReference DOMDocument::CreateEntityReference     DontDelete|Function 1
789   getElementsByTagName  DOMDocument::GetElementsByTagName      DontDelete|Function 1
790   importNode           DOMDocument::ImportNode                 DontDelete|Function 2
791   createElementNS      DOMDocument::CreateElementNS            DontDelete|Function 2
792   createAttributeNS    DOMDocument::CreateAttributeNS          DontDelete|Function 2
793   getElementsByTagNameNS  DOMDocument::GetElementsByTagNameNS  DontDelete|Function 2
794   getElementById     DOMDocument::GetElementById               DontDelete|Function 1
795   createRange        DOMDocument::CreateRange                  DontDelete|Function 0
796   createNodeIterator DOMDocument::CreateNodeIterator           DontDelete|Function 3
797   createTreeWalker   DOMDocument::CreateTreeWalker             DontDelete|Function 4
798   createEvent        DOMDocument::CreateEvent                  DontDelete|Function 1
799   getOverrideStyle   DOMDocument::GetOverrideStyle             DontDelete|Function 2
800   execCommand        DOMDocument::ExecCommand                  DontDelete|Function 3
801   queryCommandEnabled DOMDocument::QueryCommandEnabled         DontDelete|Function 1
802   queryCommandIndeterm DOMDocument::QueryCommandIndeterm       DontDelete|Function 1
803   queryCommandState DOMDocument::QueryCommandState             DontDelete|Function 1
804   queryCommandSupported DOMDocument::QueryCommandSupported     DontDelete|Function 1
805   queryCommandValue DOMDocument::QueryCommandValue             DontDelete|Function 1
806 @end
807 */
808 DEFINE_PROTOTYPE("DOMDocument", DOMDocumentProto)
809 IMPLEMENT_PROTOFUNC(DOMDocumentProtoFunc)
810 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMDocumentProto, DOMDocumentProtoFunc, DOMNodeProto)
811
812 const ClassInfo DOMDocument::info = { "Document", &DOMNode::info, &DOMDocumentTable, 0 };
813
814 /* Source for DOMDocumentTable. Use "make hashtables" to regenerate.
815 @begin DOMDocumentTable 4
816   doctype         DOMDocument::DocType                         DontDelete|ReadOnly
817   implementation  DOMDocument::Implementation                  DontDelete|ReadOnly
818   documentElement DOMDocument::DocumentElement                 DontDelete|ReadOnly
819   styleSheets     DOMDocument::StyleSheets                     DontDelete|ReadOnly
820   preferredStylesheetSet  DOMDocument::PreferredStylesheetSet  DontDelete|ReadOnly
821   selectedStylesheetSet  DOMDocument::SelectedStylesheetSet    DontDelete
822   readyState      DOMDocument::ReadyState                      DontDelete|ReadOnly
823   defaultView        DOMDocument::DefaultView                  DontDelete|ReadOnly
824 @end
825 */
826
827 DOMDocument::DOMDocument(ExecState *exec, const DOM::Document &d)
828   : DOMNode(DOMDocumentProto::self(exec), d) { }
829
830 DOMDocument::DOMDocument(const Object &proto, const DOM::Document &d)
831   : DOMNode(proto, d) { }
832
833 DOMDocument::~DOMDocument()
834 {
835   ScriptInterpreter::forgetDOMObject(node.handle());
836 }
837
838 Value DOMDocument::tryGet(ExecState *exec, const Identifier &propertyName) const
839 {
840 #ifdef KJS_VERBOSE
841   kdDebug(6070) << "DOMDocument::tryGet " << propertyName.qstring() << endl;
842 #endif
843   return DOMObjectLookupGetValue<DOMDocument, DOMNode>(
844     exec, propertyName, &DOMDocumentTable, this);
845 }
846
847 Value DOMDocument::getValueProperty(ExecState *exec, int token) const
848 {
849   DOM::Document doc = static_cast<DOM::Document>(node);
850
851   switch(token) {
852   case DocType:
853     return getDOMNode(exec,doc.doctype());
854   case Implementation:
855     return getDOMDOMImplementation(exec,doc.implementation());
856   case DocumentElement:
857     return getDOMNode(exec,doc.documentElement());
858   case StyleSheets:
859     //kdDebug() << "DOMDocument::StyleSheets, returning " << doc.styleSheets().length() << " stylesheets" << endl;
860     return getDOMStyleSheetList(exec, doc.styleSheets(), doc);
861   case PreferredStylesheetSet:
862     return getStringOrNull(doc.preferredStylesheetSet());
863   case SelectedStylesheetSet:
864     return getStringOrNull(doc.selectedStylesheetSet());
865   case ReadyState:
866     {
867     DOM::DocumentImpl* docimpl = node.handle()->getDocument();
868     if ( docimpl )
869     {
870       KHTMLPart* part = docimpl->part();
871       if ( part ) {
872         if (part->d->m_bComplete) return String("complete");
873         if (docimpl->parsing()) return String("loading");
874         return String("loaded");
875         // What does the interactive value mean ?
876         // Missing support for "uninitialized"
877       }
878     }
879     return Undefined();
880     }
881   case DOMDocument::DefaultView: // DOM2
882     return getDOMAbstractView(exec,doc.defaultView());
883   default:
884     kdWarning() << "DOMDocument::getValueProperty unhandled token " << token << endl;
885     return Value();
886   }
887 }
888
889 void DOMDocument::tryPut(ExecState *exec, const Identifier& propertyName, const Value& value, int attr)
890 {
891 #ifdef KJS_VERBOSE
892   kdDebug(6070) << "DOMDocument::tryPut " << propertyName.qstring() << endl;
893 #endif
894   DOMObjectLookupPut<DOMDocument,DOMNode>(exec, propertyName, value, attr, &DOMDocumentTable, this );
895 }
896
897 void DOMDocument::putValue(ExecState *exec, int token, const Value& value, int /*attr*/)
898 {
899   DOM::Document doc = static_cast<DOM::Document>(node);
900   switch (token) {
901     case SelectedStylesheetSet: {
902       doc.setSelectedStylesheetSet(value.toString(exec).string());
903       break;
904     }
905   }
906 }
907
908 Value DOMDocumentProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
909 {
910   if (!thisObj.inherits(&KJS::DOMNode::info)) {
911     Object err = Error::create(exec,TypeError);
912     exec->setException(err);
913     return err;
914   }
915   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
916   DOM::Document doc = static_cast<DOM::Document>(node);
917   String str = args[0].toString(exec);
918   DOM::DOMString s = str.value().string();
919
920   switch(id) {
921   case DOMDocument::CreateElement:
922     return getDOMNode(exec,doc.createElement(s));
923   case DOMDocument::CreateDocumentFragment:
924     return getDOMNode(exec,doc.createDocumentFragment());
925   case DOMDocument::CreateTextNode:
926     return getDOMNode(exec,doc.createTextNode(s));
927   case DOMDocument::CreateComment:
928     return getDOMNode(exec,doc.createComment(s));
929   case DOMDocument::CreateCDATASection:
930     return getDOMNode(exec,doc.createCDATASection(s));  /* TODO: okay ? */
931   case DOMDocument::CreateProcessingInstruction:
932     return getDOMNode(exec,doc.createProcessingInstruction(args[0].toString(exec).string(),
933                                                                  args[1].toString(exec).string()));
934   case DOMDocument::CreateAttribute:
935     return getDOMNode(exec,doc.createAttribute(s));
936   case DOMDocument::CreateEntityReference:
937     return getDOMNode(exec,doc.createEntityReference(args[0].toString(exec).string()));
938   case DOMDocument::GetElementsByTagName:
939     return getDOMNodeList(exec,doc.getElementsByTagName(s));
940   case DOMDocument::ImportNode: // DOM2
941     return getDOMNode(exec,doc.importNode(toNode(args[0]), args[1].toBoolean(exec)));
942   case DOMDocument::CreateElementNS: // DOM2
943     return getDOMNode(exec,doc.createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
944   case DOMDocument::CreateAttributeNS: // DOM2
945     return getDOMNode(exec,doc.createAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
946   case DOMDocument::GetElementsByTagNameNS: // DOM2
947     return getDOMNodeList(exec,doc.getElementsByTagNameNS(args[0].toString(exec).string(),
948                                                           args[1].toString(exec).string()));
949   case DOMDocument::GetElementById:
950 #if APPLE_CHANGES
951     {
952         DOM::Element node = doc.getElementById(args[0].toString(exec).string());
953         if (!node.isNull()) {
954             Value domValue = getDOMNode(exec, node);
955             ObjectImp *imp = static_cast<ObjectImp *>(domValue.imp());
956             if (!imp->forwardingScriptMessage() && (node.handle()->id() == ID_APPLET || node.handle()->id() == ID_EMBED || node.handle()->id() == ID_OBJECT)) {
957                 Value v = getRuntimeObject(exec,node,domValue);
958                 if (!v.isNull())
959                     return v;
960             }
961             return domValue;
962         }
963     }
964 #else  
965     return getDOMNode(exec,doc.getElementById(args[0].toString(exec).string()));
966 #endif
967   case DOMDocument::CreateRange:
968     return getDOMRange(exec,doc.createRange());
969   case DOMDocument::CreateNodeIterator: {
970     NodeFilter filter;
971     if (!args[2].isA(NullType)) {
972         Object obj = Object::dynamicCast(args[2]);
973         if (!obj.isNull())
974             filter = NodeFilter(new JSNodeFilterCondition(obj));
975     }
976     return getDOMNodeIterator(exec, doc.createNodeIterator(toNode(args[0]), (long unsigned int)(args[1].toNumber(exec)), filter, args[3].toBoolean(exec)));
977   }
978   case DOMDocument::CreateTreeWalker: {
979     NodeFilter filter;
980     if (!args[2].isA(NullType)) {
981         Object obj = Object::dynamicCast(args[2]);
982         if (!obj.isNull())
983             filter = NodeFilter(new JSNodeFilterCondition(obj));
984     }
985     return getDOMTreeWalker(exec, doc.createTreeWalker(toNode(args[0]), (long unsigned int)(args[1].toNumber(exec)), filter, args[3].toBoolean(exec)));
986   }
987   case DOMDocument::CreateEvent:
988     return getDOMEvent(exec,doc.createEvent(s));
989   case DOMDocument::GetOverrideStyle: {
990     DOM::Node arg0 = toNode(args[0]);
991     if (arg0.nodeType() != DOM::Node::ELEMENT_NODE)
992       return Undefined(); // throw exception?
993     else
994       return getDOMCSSStyleDeclaration(exec,doc.getOverrideStyle(static_cast<DOM::Element>(arg0),args[1].toString(exec).string()));
995   }
996   case DOMDocument::ExecCommand: {
997     return Boolean(doc.execCommand(args[0].toString(exec).string(), args[1].toBoolean(exec), args[2].toString(exec).string()));
998   }
999   case DOMDocument::QueryCommandEnabled: {
1000     return Boolean(doc.queryCommandEnabled(args[0].toString(exec).string()));
1001   }
1002   case DOMDocument::QueryCommandIndeterm: {
1003     return Boolean(doc.queryCommandIndeterm(args[0].toString(exec).string()));
1004   }
1005   case DOMDocument::QueryCommandState: {
1006     return Boolean(doc.queryCommandState(args[0].toString(exec).string()));
1007   }
1008   case DOMDocument::QueryCommandSupported: {
1009     return Boolean(doc.queryCommandSupported(args[0].toString(exec).string()));
1010   }
1011   case DOMDocument::QueryCommandValue: {
1012     DOM::DOMString commandValue(doc.queryCommandValue(args[0].toString(exec).string()));
1013     // Method returns null DOMString to signal command is unsupported.
1014     // Micorsoft documentation for this method says:
1015     // "If not supported [for a command identifier], this method returns a Boolean set to false."
1016     if (commandValue.isNull())
1017         return Boolean(false);
1018     else 
1019         return String(commandValue);
1020   }
1021   default:
1022     break;
1023   }
1024
1025   return Undefined();
1026 }
1027
1028 // -------------------------------------------------------------------------
1029
1030 /* Source for DOMElementProtoTable. Use "make hashtables" to regenerate.
1031 @begin DOMElementProtoTable 17
1032   getAttribute          DOMElement::GetAttribute        DontDelete|Function 1
1033   setAttribute          DOMElement::SetAttribute        DontDelete|Function 2
1034   removeAttribute       DOMElement::RemoveAttribute     DontDelete|Function 1
1035   getAttributeNode      DOMElement::GetAttributeNode    DontDelete|Function 1
1036   setAttributeNode      DOMElement::SetAttributeNode    DontDelete|Function 2
1037   removeAttributeNode   DOMElement::RemoveAttributeNode DontDelete|Function 1
1038   getElementsByTagName  DOMElement::GetElementsByTagName        DontDelete|Function 1
1039   hasAttribute          DOMElement::HasAttribute        DontDelete|Function 1
1040   getAttributeNS        DOMElement::GetAttributeNS      DontDelete|Function 2
1041   setAttributeNS        DOMElement::SetAttributeNS      DontDelete|Function 3
1042   removeAttributeNS     DOMElement::RemoveAttributeNS   DontDelete|Function 2
1043   getAttributeNodeNS    DOMElement::GetAttributeNodeNS  DontDelete|Function 2
1044   setAttributeNodeNS    DOMElement::SetAttributeNodeNS  DontDelete|Function 1
1045   getElementsByTagNameNS DOMElement::GetElementsByTagNameNS     DontDelete|Function 2
1046   hasAttributeNS        DOMElement::HasAttributeNS      DontDelete|Function 2
1047 # extension for Safari RSS
1048   scrollByLines         DOMElement::ScrollByLines       DontDelete|Function 1
1049   scrollByPages         DOMElement::ScrollByPages       DontDelete|Function 1
1050
1051 @end
1052 */
1053 DEFINE_PROTOTYPE("DOMElement",DOMElementProto)
1054 IMPLEMENT_PROTOFUNC(DOMElementProtoFunc)
1055 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMElementProto,DOMElementProtoFunc,DOMNodeProto)
1056
1057 const ClassInfo DOMElement::info = { "Element", &DOMNode::info, &DOMElementTable, 0 };
1058 /* Source for DOMElementTable. Use "make hashtables" to regenerate.
1059 @begin DOMElementTable 3
1060   tagName       DOMElement::TagName                         DontDelete|ReadOnly
1061   style         DOMElement::Style                           DontDelete|ReadOnly
1062 @end
1063 */
1064 DOMElement::DOMElement(ExecState *exec, const DOM::Element &e)
1065   : DOMNode(DOMElementProto::self(exec), e) { }
1066
1067 DOMElement::DOMElement(const Object &proto, const DOM::Element &e)
1068   : DOMNode(proto, e) { }
1069
1070 Value DOMElement::tryGet(ExecState *exec, const Identifier &propertyName) const
1071 {
1072 #ifdef KJS_VERBOSE
1073   kdDebug(6070) << "DOMElement::tryGet " << propertyName.qstring() << endl;
1074 #endif
1075   DOM::Element element = static_cast<DOM::Element>(node);
1076
1077   const HashEntry* entry = Lookup::findEntry(&DOMElementTable, propertyName);
1078   if (entry)
1079   {
1080     switch( entry->value ) {
1081     case TagName:
1082       return getStringOrNull(element.tagName());
1083     case Style:
1084       return getDOMCSSStyleDeclaration(exec,element.style());
1085     default:
1086       kdWarning() << "Unhandled token in DOMElement::tryGet : " << entry->value << endl;
1087       break;
1088     }
1089   }
1090   // We have to check in DOMNode before giving access to attributes, otherwise
1091   // onload="..." would make onload return the string (attribute value) instead of
1092   // the listener object (function).
1093   if (DOMNode::hasProperty(exec, propertyName))
1094     return DOMNode::tryGet(exec, propertyName);
1095
1096   DOM::DOMString attr = element.getAttribute( propertyName.string() );
1097   // Give access to attributes
1098   if ( !attr.isNull() )
1099     return getStringOrNull( attr );
1100
1101   return Undefined();
1102 }
1103
1104 Value DOMElementProtoFunc::tryCall(ExecState *exec, Object &to, const List &args)
1105 {
1106   Object thisObj;
1107
1108   if (to.classInfo() == &KJS::RuntimeObjectImp::info) {
1109     KJS::RuntimeObjectImp *imp = static_cast<KJS::RuntimeObjectImp *>(to.imp());
1110     thisObj = imp->fallbackObject().toObject(exec);
1111   }
1112   else {
1113     thisObj = to;
1114   }
1115   
1116   if (!thisObj.inherits(&KJS::DOMNode::info)) { // node should be enough here, given the cast
1117     Object err = Error::create(exec,TypeError);
1118     exec->setException(err);
1119     return err;
1120   }
1121   DOM::Node node = static_cast<DOMNode *>( thisObj.imp() )->toNode();
1122   DOM::Element element = static_cast<DOM::Element>(node);
1123
1124   switch(id) {
1125     case DOMElement::GetAttribute:
1126       // getString should be used here, since if the attribute isn't present at all, you should
1127       // return null and not "".
1128       return getStringOrNull(element.getAttribute(args[0].toString(exec).string()));
1129     case DOMElement::SetAttribute:
1130       element.setAttribute(args[0].toString(exec).string(),args[1].toString(exec).string());
1131       return Undefined();
1132     case DOMElement::RemoveAttribute:
1133       element.removeAttribute(args[0].toString(exec).string());
1134       return Undefined();
1135     case DOMElement::GetAttributeNode:
1136       return getDOMNode(exec,element.getAttributeNode(args[0].toString(exec).string()));
1137     case DOMElement::SetAttributeNode:
1138       return getDOMNode(exec,element.setAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1139     case DOMElement::RemoveAttributeNode:
1140       return getDOMNode(exec,element.removeAttributeNode((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1141     case DOMElement::GetElementsByTagName:
1142       return getDOMNodeList(exec,element.getElementsByTagName(args[0].toString(exec).string()));
1143     case DOMElement::HasAttribute: // DOM2
1144       return Boolean(element.hasAttribute(args[0].toString(exec).string()));
1145     case DOMElement::GetAttributeNS: // DOM2
1146       return String(element.getAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1147     case DOMElement::SetAttributeNS: // DOM2
1148       element.setAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string());
1149       return Undefined();
1150     case DOMElement::RemoveAttributeNS: // DOM2
1151       element.removeAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string());
1152       return Undefined();
1153     case DOMElement::GetAttributeNodeNS: // DOM2
1154       return getDOMNode(exec,element.getAttributeNodeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1155     case DOMElement::SetAttributeNodeNS: // DOM2
1156       return getDOMNode(exec,element.setAttributeNodeNS((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1157     case DOMElement::GetElementsByTagNameNS: // DOM2
1158       return getDOMNodeList(exec,element.getElementsByTagNameNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1159     case DOMElement::HasAttributeNS: // DOM2
1160       return Boolean(element.hasAttributeNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1161     case DOMElement::ScrollByLines:
1162     case DOMElement::ScrollByPages:
1163     {
1164         DOM::DocumentImpl* docimpl = node.handle()->getDocument();
1165         if (docimpl) {
1166             docimpl->updateLayoutIgnorePendingStylesheets();
1167         }            
1168         khtml::RenderObject *rend = node.handle() ? node.handle()->renderer() : 0L;
1169         if (rend && rend->hasOverflowClip()) {
1170             KWQScrollDirection direction = KWQScrollDown;
1171             int multiplier = args[0].toInt32(exec);
1172             if (multiplier < 0) {
1173                 direction = KWQScrollUp;
1174                 multiplier = -multiplier;
1175             }
1176             KWQScrollGranularity granularity = id == DOMElement::ScrollByLines ? KWQScrollLine : KWQScrollPage;
1177             rend->layer()->scroll(direction, granularity, multiplier);
1178         }
1179         return Undefined();
1180         
1181     }
1182   default:
1183     return Undefined();
1184   }
1185 }
1186
1187 // -------------------------------------------------------------------------
1188
1189 /* Source for DOMDOMImplementationProtoTable. Use "make hashtables" to regenerate.
1190 @begin DOMDOMImplementationProtoTable 5
1191   hasFeature            DOMDOMImplementation::HasFeature                DontDelete|Function 2
1192 # DOM2
1193   createCSSStyleSheet   DOMDOMImplementation::CreateCSSStyleSheet       DontDelete|Function 2
1194   createDocumentType    DOMDOMImplementation::CreateDocumentType        DontDelete|Function 3
1195   createDocument        DOMDOMImplementation::CreateDocument            DontDelete|Function 3
1196   createHTMLDocument    DOMDOMImplementation::CreateHTMLDocument        DontDelete|Function 1
1197 @end
1198 */
1199 DEFINE_PROTOTYPE("DOMImplementation",DOMDOMImplementationProto)
1200 IMPLEMENT_PROTOFUNC(DOMDOMImplementationProtoFunc)
1201 IMPLEMENT_PROTOTYPE(DOMDOMImplementationProto,DOMDOMImplementationProtoFunc)
1202
1203 const ClassInfo DOMDOMImplementation::info = { "DOMImplementation", 0, 0, 0 };
1204
1205 DOMDOMImplementation::DOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1206   : DOMObject(DOMDOMImplementationProto::self(exec)), implementation(i) { }
1207
1208 DOMDOMImplementation::~DOMDOMImplementation()
1209 {
1210   ScriptInterpreter::forgetDOMObject(implementation.handle());
1211 }
1212
1213 Value DOMDOMImplementationProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1214 {
1215   if (!thisObj.inherits(&KJS::DOMDOMImplementation::info)) {
1216     Object err = Error::create(exec,TypeError);
1217     exec->setException(err);
1218     return err;
1219   }
1220   DOM::DOMImplementation implementation = static_cast<DOMDOMImplementation *>( thisObj.imp() )->toImplementation();
1221
1222   switch(id) {
1223   case DOMDOMImplementation::HasFeature:
1224     return Boolean(implementation.hasFeature(args[0].toString(exec).string(),
1225         (args[1].type() != UndefinedType && args[1].type() != NullType) ? args[1].toString(exec).string() : DOMString()));
1226   case DOMDOMImplementation::CreateDocumentType: // DOM2
1227     return getDOMNode(exec,implementation.createDocumentType(args[0].toString(exec).string(),args[1].toString(exec).string(),args[2].toString(exec).string()));
1228   case DOMDOMImplementation::CreateDocument: // DOM2
1229     return getDOMNode(exec,implementation.createDocument(args[0].toString(exec).string(),args[1].toString(exec).string(),toNode(args[2])));
1230   case DOMDOMImplementation::CreateCSSStyleSheet: // DOM2
1231     return getDOMStyleSheet(exec,implementation.createCSSStyleSheet(args[0].toString(exec).string(),args[1].toString(exec).string()));
1232   case DOMDOMImplementation::CreateHTMLDocument: // DOM2-HTML
1233     return getDOMNode(exec, implementation.createHTMLDocument(args[0].toString(exec).string()));
1234   default:
1235     break;
1236   }
1237   return Undefined();
1238 }
1239
1240 // -------------------------------------------------------------------------
1241
1242 const ClassInfo DOMDocumentType::info = { "DocumentType", &DOMNode::info, &DOMDocumentTypeTable, 0 };
1243
1244 /* Source for DOMDocumentTypeTable. Use "make hashtables" to regenerate.
1245 @begin DOMDocumentTypeTable 6
1246   name                  DOMDocumentType::Name           DontDelete|ReadOnly
1247   entities              DOMDocumentType::Entities       DontDelete|ReadOnly
1248   notations             DOMDocumentType::Notations      DontDelete|ReadOnly
1249 # DOM2
1250   publicId              DOMDocumentType::PublicId       DontDelete|ReadOnly
1251   systemId              DOMDocumentType::SystemId       DontDelete|ReadOnly
1252   internalSubset        DOMDocumentType::InternalSubset DontDelete|ReadOnly
1253 @end
1254 */
1255 DOMDocumentType::DOMDocumentType(ExecState *exec, const DOM::DocumentType &dt)
1256   : DOMNode( /*### no proto yet*/exec, dt ) { }
1257
1258 Value DOMDocumentType::tryGet(ExecState *exec, const Identifier &propertyName) const
1259 {
1260   return DOMObjectLookupGetValue<DOMDocumentType, DOMNode>(exec, propertyName, &DOMDocumentTypeTable, this);
1261 }
1262
1263 Value DOMDocumentType::getValueProperty(ExecState *exec, int token) const
1264 {
1265   DOM::DocumentType type = static_cast<DOM::DocumentType>(node);
1266   switch (token) {
1267   case Name:
1268     return getStringOrNull(type.name());
1269   case Entities:
1270     return getDOMNamedNodeMap(exec,type.entities());
1271   case Notations:
1272     return getDOMNamedNodeMap(exec,type.notations());
1273   case PublicId: // DOM2
1274     return getStringOrNull(type.publicId());
1275   case SystemId: // DOM2
1276     return getStringOrNull(type.systemId());
1277   case InternalSubset: // DOM2
1278     return getStringOrNull(type.internalSubset());
1279   default:
1280     kdWarning() << "DOMDocumentType::getValueProperty unhandled token " << token << endl;
1281     return Value();
1282   }
1283 }
1284
1285 // -------------------------------------------------------------------------
1286
1287 /* Source for DOMNamedNodeMapProtoTable. Use "make hashtables" to regenerate.
1288 @begin DOMNamedNodeMapProtoTable 7
1289   getNamedItem          DOMNamedNodeMap::GetNamedItem           DontDelete|Function 1
1290   setNamedItem          DOMNamedNodeMap::SetNamedItem           DontDelete|Function 1
1291   removeNamedItem       DOMNamedNodeMap::RemoveNamedItem        DontDelete|Function 1
1292   item                  DOMNamedNodeMap::Item                   DontDelete|Function 1
1293 # DOM2
1294   getNamedItemNS        DOMNamedNodeMap::GetNamedItemNS         DontDelete|Function 2
1295   setNamedItemNS        DOMNamedNodeMap::SetNamedItemNS         DontDelete|Function 1
1296   removeNamedItemNS     DOMNamedNodeMap::RemoveNamedItemNS      DontDelete|Function 2
1297 @end
1298 */
1299 DEFINE_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto)
1300 IMPLEMENT_PROTOFUNC(DOMNamedNodeMapProtoFunc)
1301 IMPLEMENT_PROTOTYPE(DOMNamedNodeMapProto,DOMNamedNodeMapProtoFunc)
1302
1303 const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, 0, 0 };
1304
1305 DOMNamedNodeMap::DOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1306   : DOMObject(DOMNamedNodeMapProto::self(exec)), map(m) { }
1307
1308 DOMNamedNodeMap::~DOMNamedNodeMap()
1309 {
1310   ScriptInterpreter::forgetDOMObject(map.handle());
1311 }
1312
1313 // We have to implement hasProperty since we don't use a hashtable for 'length'
1314 // ## this breaks "for (..in..)" though.
1315 bool DOMNamedNodeMap::hasProperty(ExecState *exec, const Identifier &p) const
1316 {
1317   if (p == lengthPropertyName)
1318     return true;
1319   return DOMObject::hasProperty(exec, p);
1320 }
1321
1322 Value DOMNamedNodeMap::tryGet(ExecState* exec, const Identifier &p) const
1323 {
1324   if (p == lengthPropertyName)
1325     return Number(map.length());
1326
1327   // array index ?
1328   bool ok;
1329   long unsigned int idx = p.toULong(&ok);
1330   if (ok)
1331     return getDOMNode(exec,map.item(idx));
1332
1333   // Anything else (including functions, defined in the prototype)
1334   return DOMObject::tryGet(exec, p);
1335 }
1336
1337 Value DOMNamedNodeMapProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1338 {
1339   if (!thisObj.inherits(&KJS::DOMNamedNodeMap::info)) {
1340     Object err = Error::create(exec,TypeError);
1341     exec->setException(err);
1342     return err;
1343   }
1344   DOM::NamedNodeMap map = static_cast<DOMNamedNodeMap *>(thisObj.imp())->toMap();
1345
1346   switch(id) {
1347     case DOMNamedNodeMap::GetNamedItem:
1348       return getDOMNode(exec, map.getNamedItem(args[0].toString(exec).string()));
1349     case DOMNamedNodeMap::SetNamedItem:
1350       return getDOMNode(exec, map.setNamedItem((new DOMNode(exec,KJS::toNode(args[0])))->toNode()));
1351     case DOMNamedNodeMap::RemoveNamedItem:
1352       return getDOMNode(exec, map.removeNamedItem(args[0].toString(exec).string()));
1353     case DOMNamedNodeMap::Item:
1354       return getDOMNode(exec, map.item(args[0].toInt32(exec)));
1355     case DOMNamedNodeMap::GetNamedItemNS: // DOM2
1356       return getDOMNode(exec, map.getNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1357     case DOMNamedNodeMap::SetNamedItemNS: // DOM2
1358       return getDOMNode(exec, map.setNamedItemNS(toNode(args[0])));
1359     case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2
1360       return getDOMNode(exec, map.removeNamedItemNS(args[0].toString(exec).string(),args[1].toString(exec).string()));
1361     default:
1362       break;
1363   }
1364
1365   return Undefined();
1366 }
1367
1368 // -------------------------------------------------------------------------
1369
1370 const ClassInfo DOMProcessingInstruction::info = { "ProcessingInstruction", &DOMNode::info, &DOMProcessingInstructionTable, 0 };
1371
1372 /* Source for DOMProcessingInstructionTable. Use "make hashtables" to regenerate.
1373 @begin DOMProcessingInstructionTable 3
1374   target        DOMProcessingInstruction::Target        DontDelete|ReadOnly
1375   data          DOMProcessingInstruction::Data          DontDelete
1376   sheet         DOMProcessingInstruction::Sheet         DontDelete|ReadOnly
1377 @end
1378 */
1379 Value DOMProcessingInstruction::tryGet(ExecState *exec, const Identifier &propertyName) const
1380 {
1381   return DOMObjectLookupGetValue<DOMProcessingInstruction, DOMNode>(exec, propertyName, &DOMProcessingInstructionTable, this);
1382 }
1383
1384 Value DOMProcessingInstruction::getValueProperty(ExecState *exec, int token) const
1385 {
1386   switch (token) {
1387   case Target:
1388     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).target());
1389   case Data:
1390     return getStringOrNull(static_cast<DOM::ProcessingInstruction>(node).data());
1391   case Sheet:
1392     return getDOMStyleSheet(exec,static_cast<DOM::ProcessingInstruction>(node).sheet());
1393   default:
1394     kdWarning() << "DOMProcessingInstruction::getValueProperty unhandled token " << token << endl;
1395     return Value();
1396   }
1397 }
1398
1399 void DOMProcessingInstruction::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1400 {
1401   // Not worth using the hashtable for this one ;)
1402   if (propertyName == "data")
1403     static_cast<DOM::ProcessingInstruction>(node).setData(value.toString(exec).string());
1404   else
1405     DOMNode::tryPut(exec, propertyName,value,attr);
1406 }
1407
1408 // -------------------------------------------------------------------------
1409
1410 const ClassInfo DOMNotation::info = { "Notation", &DOMNode::info, &DOMNotationTable, 0 };
1411
1412 /* Source for DOMNotationTable. Use "make hashtables" to regenerate.
1413 @begin DOMNotationTable 2
1414   publicId              DOMNotation::PublicId   DontDelete|ReadOnly
1415   systemId              DOMNotation::SystemId   DontDelete|ReadOnly
1416 @end
1417 */
1418 Value DOMNotation::tryGet(ExecState *exec, const Identifier &propertyName) const
1419 {
1420   return DOMObjectLookupGetValue<DOMNotation, DOMNode>(exec, propertyName, &DOMNotationTable, this);
1421 }
1422
1423 Value DOMNotation::getValueProperty(ExecState *, int token) const
1424 {
1425   switch (token) {
1426   case PublicId:
1427     return getStringOrNull(static_cast<DOM::Notation>(node).publicId());
1428   case SystemId:
1429     return getStringOrNull(static_cast<DOM::Notation>(node).systemId());
1430   default:
1431     kdWarning() << "DOMNotation::getValueProperty unhandled token " << token << endl;
1432     return Value();
1433   }
1434 }
1435
1436 // -------------------------------------------------------------------------
1437
1438 const ClassInfo DOMEntity::info = { "Entity", &DOMNode::info, 0, 0 };
1439
1440 /* Source for DOMEntityTable. Use "make hashtables" to regenerate.
1441 @begin DOMEntityTable 2
1442   publicId              DOMEntity::PublicId             DontDelete|ReadOnly
1443   systemId              DOMEntity::SystemId             DontDelete|ReadOnly
1444   notationName          DOMEntity::NotationName DontDelete|ReadOnly
1445 @end
1446 */
1447 Value DOMEntity::tryGet(ExecState *exec, const Identifier &propertyName) const
1448 {
1449   return DOMObjectLookupGetValue<DOMEntity, DOMNode>(exec, propertyName, &DOMEntityTable, this);
1450 }
1451
1452 Value DOMEntity::getValueProperty(ExecState *, int token) const
1453 {
1454   switch (token) {
1455   case PublicId:
1456     return getStringOrNull(static_cast<DOM::Entity>(node).publicId());
1457   case SystemId:
1458     return getStringOrNull(static_cast<DOM::Entity>(node).systemId());
1459   case NotationName:
1460     return getStringOrNull(static_cast<DOM::Entity>(node).notationName());
1461   default:
1462     kdWarning() << "DOMEntity::getValueProperty unhandled token " << token << endl;
1463     return Value();
1464   }
1465 }
1466
1467 // -------------------------------------------------------------------------
1468
1469 Value KJS::getDOMDocumentNode(ExecState *exec, const DOM::Document &n)
1470 {
1471   DOMDocument *ret = 0;
1472   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1473
1474   if ((ret = static_cast<DOMDocument *>(interp->getDOMObject(n.handle()))))
1475     return Value(ret);
1476
1477   if (n.isHTMLDocument())
1478     ret = new HTMLDocument(exec, static_cast<DOM::HTMLDocument>(n));
1479   else
1480     ret = new DOMDocument(exec, n);
1481
1482   Value val(ret);
1483   
1484   // Make sure the document is kept around by the window object, and works right with the
1485   // back/forward cache.
1486   if (n.view()) {
1487     static Identifier documentIdentifier("document");
1488     Window::retrieveWindow(n.view()->part())->putDirect(documentIdentifier, ret, DontDelete|ReadOnly);
1489   }
1490
1491   interp->putDOMObject(n.handle(), ret);
1492
1493   return val;
1494 }
1495
1496 bool KJS::checkNodeSecurity(ExecState *exec, const DOM::Node& n)
1497 {
1498   if (!n.handle()) 
1499     return false;
1500
1501   // Check to see if the currently executing interpreter is allowed to access the specified node
1502   KHTMLPart *part = n.handle()->getDocument()->part();
1503   Window* win = part ? Window::retrieveWindow(part) : 0L;
1504   if ( !win || !win->isSafeScript(exec) )
1505     return false;
1506   return true;
1507 }
1508
1509
1510 Value KJS::getDOMNode(ExecState *exec, const DOM::Node &n)
1511 {
1512   DOMObject *ret = 0;
1513   if (n.isNull())
1514     return Null();
1515   ScriptInterpreter* interp = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter());
1516   DOM::NodeImpl *doc = n.ownerDocument().handle();
1517
1518   if ((ret = interp->getDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle())))
1519     return Value(ret);
1520
1521   switch (n.nodeType()) {
1522     case DOM::Node::ELEMENT_NODE:
1523       if (static_cast<DOM::Element>(n).isHTMLElement())
1524         ret = new HTMLElement(exec, static_cast<DOM::HTMLElement>(n));
1525       else
1526         ret = new DOMElement(exec, static_cast<DOM::Element>(n));
1527       break;
1528     case DOM::Node::ATTRIBUTE_NODE:
1529       ret = new DOMAttr(exec, static_cast<DOM::Attr>(n));
1530       break;
1531     case DOM::Node::TEXT_NODE:
1532     case DOM::Node::CDATA_SECTION_NODE:
1533       ret = new DOMText(exec, static_cast<DOM::Text>(n));
1534       break;
1535     case DOM::Node::ENTITY_REFERENCE_NODE:
1536       ret = new DOMNode(exec, n);
1537       break;
1538     case DOM::Node::ENTITY_NODE:
1539       ret = new DOMEntity(exec, static_cast<DOM::Entity>(n));
1540       break;
1541     case DOM::Node::PROCESSING_INSTRUCTION_NODE:
1542       ret = new DOMProcessingInstruction(exec, static_cast<DOM::ProcessingInstruction>(n));
1543       break;
1544     case DOM::Node::COMMENT_NODE:
1545       ret = new DOMCharacterData(exec, static_cast<DOM::CharacterData>(n));
1546       break;
1547     case DOM::Node::DOCUMENT_NODE:
1548       // we don't want to cache the document itself in the per-document dictionary
1549       return getDOMDocumentNode(exec, static_cast<DOM::Document>(n));
1550     case DOM::Node::DOCUMENT_TYPE_NODE:
1551       ret = new DOMDocumentType(exec, static_cast<DOM::DocumentType>(n));
1552       break;
1553     case DOM::Node::DOCUMENT_FRAGMENT_NODE:
1554       ret = new DOMNode(exec, n);
1555       break;
1556     case DOM::Node::NOTATION_NODE:
1557       ret = new DOMNotation(exec, static_cast<DOM::Notation>(n));
1558       break;
1559     default:
1560       ret = new DOMNode(exec, n);
1561   }
1562
1563   interp->putDOMObjectForDocument(static_cast<DOM::DocumentImpl *>(doc), n.handle(), ret);
1564
1565   return Value(ret);
1566 }
1567
1568 Value KJS::getDOMNamedNodeMap(ExecState *exec, const DOM::NamedNodeMap &m)
1569 {
1570   return Value(cacheDOMObject<DOM::NamedNodeMap, KJS::DOMNamedNodeMap>(exec, m));
1571 }
1572
1573 Value KJS::getRuntimeObject(ExecState *exec, const DOM::Node &node, const Value &fallback)
1574 {
1575     DOM::HTMLElement element = static_cast<DOM::HTMLElement>(node);
1576
1577     if (!node.isNull()) {
1578         if (node.handle()->id() == ID_APPLET) {
1579             DOM::HTMLAppletElementImpl *appletElement = static_cast<DOM::HTMLAppletElementImpl *>(element.handle());
1580             
1581             if (appletElement->getAppletInstance()) {
1582                 // The instance is owned by the applet element.
1583                 RuntimeObjectImp *appletImp = new RuntimeObjectImp(appletElement->getAppletInstance(), fallback, false);
1584                 return Value(appletImp);
1585             }
1586         }
1587         else if (node.handle()->id() == ID_EMBED) {
1588             DOM::HTMLEmbedElementImpl *embedElement = static_cast<DOM::HTMLEmbedElementImpl *>(element.handle());
1589             
1590             if (embedElement->getEmbedInstance()) {
1591                 RuntimeObjectImp *runtimeImp = new RuntimeObjectImp(embedElement->getEmbedInstance(), fallback, false);
1592                 return Value(runtimeImp);
1593             }
1594         }
1595         else if (node.handle()->id() == ID_OBJECT) {
1596             DOM::HTMLObjectElementImpl *objectElement = static_cast<DOM::HTMLObjectElementImpl *>(element.handle());
1597             
1598             if (objectElement->getObjectInstance()) {
1599                 RuntimeObjectImp *runtimeImp = new RuntimeObjectImp(objectElement->getObjectInstance(), fallback, false);
1600                 return Value(runtimeImp);
1601             }
1602         }
1603     }
1604     
1605     // If we don't have a runtime object return the a Value that reports isNull() == true.
1606     return Value();
1607 }
1608
1609 Value KJS::getDOMNodeList(ExecState *exec, const DOM::NodeList &l)
1610 {
1611   return Value(cacheDOMObject<DOM::NodeList, KJS::DOMNodeList>(exec, l));
1612 }
1613
1614 Value KJS::getDOMDOMImplementation(ExecState *exec, const DOM::DOMImplementation &i)
1615 {
1616   return Value(cacheDOMObject<DOM::DOMImplementation, KJS::DOMDOMImplementation>(exec, i));
1617 }
1618
1619 // -------------------------------------------------------------------------
1620
1621 const ClassInfo NodeConstructor::info = { "NodeConstructor", 0, &NodeConstructorTable, 0 };
1622 /* Source for NodeConstructorTable. Use "make hashtables" to regenerate.
1623 @begin NodeConstructorTable 11
1624   ELEMENT_NODE          DOM::Node::ELEMENT_NODE         DontDelete|ReadOnly
1625   ATTRIBUTE_NODE        DOM::Node::ATTRIBUTE_NODE               DontDelete|ReadOnly
1626   TEXT_NODE             DOM::Node::TEXT_NODE            DontDelete|ReadOnly
1627   CDATA_SECTION_NODE    DOM::Node::CDATA_SECTION_NODE   DontDelete|ReadOnly
1628   ENTITY_REFERENCE_NODE DOM::Node::ENTITY_REFERENCE_NODE        DontDelete|ReadOnly
1629   ENTITY_NODE           DOM::Node::ENTITY_NODE          DontDelete|ReadOnly
1630   PROCESSING_INSTRUCTION_NODE DOM::Node::PROCESSING_INSTRUCTION_NODE DontDelete|ReadOnly
1631   COMMENT_NODE          DOM::Node::COMMENT_NODE         DontDelete|ReadOnly
1632   DOCUMENT_NODE         DOM::Node::DOCUMENT_NODE                DontDelete|ReadOnly
1633   DOCUMENT_TYPE_NODE    DOM::Node::DOCUMENT_TYPE_NODE   DontDelete|ReadOnly
1634   DOCUMENT_FRAGMENT_NODE DOM::Node::DOCUMENT_FRAGMENT_NODE      DontDelete|ReadOnly
1635   NOTATION_NODE         DOM::Node::NOTATION_NODE                DontDelete|ReadOnly
1636 @end
1637 */
1638 Value NodeConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1639 {
1640   return DOMObjectLookupGetValue<NodeConstructor, DOMObject>(exec, propertyName, &NodeConstructorTable, this);
1641 }
1642
1643 Value NodeConstructor::getValueProperty(ExecState *, int token) const
1644 {
1645   // We use the token as the value to return directly
1646   return Number((unsigned int)token);
1647 #if 0
1648   switch (token) {
1649   case ELEMENT_NODE:
1650     return Number((unsigned int)DOM::Node::ELEMENT_NODE);
1651   case ATTRIBUTE_NODE:
1652     return Number((unsigned int)DOM::Node::ATTRIBUTE_NODE);
1653   case TEXT_NODE:
1654     return Number((unsigned int)DOM::Node::TEXT_NODE);
1655   case CDATA_SECTION_NODE:
1656     return Number((unsigned int)DOM::Node::CDATA_SECTION_NODE);
1657   case ENTITY_REFERENCE_NODE:
1658     return Number((unsigned int)DOM::Node::ENTITY_REFERENCE_NODE);
1659   case ENTITY_NODE:
1660     return Number((unsigned int)DOM::Node::ENTITY_NODE);
1661   case PROCESSING_INSTRUCTION_NODE:
1662     return Number((unsigned int)DOM::Node::PROCESSING_INSTRUCTION_NODE);
1663   case COMMENT_NODE:
1664     return Number((unsigned int)DOM::Node::COMMENT_NODE);
1665   case DOCUMENT_NODE:
1666     return Number((unsigned int)DOM::Node::DOCUMENT_NODE);
1667   case DOCUMENT_TYPE_NODE:
1668     return Number((unsigned int)DOM::Node::DOCUMENT_TYPE_NODE);
1669   case DOCUMENT_FRAGMENT_NODE:
1670     return Number((unsigned int)DOM::Node::DOCUMENT_FRAGMENT_NODE);
1671   case NOTATION_NODE:
1672     return Number((unsigned int)DOM::Node::NOTATION_NODE);
1673   default:
1674     kdWarning() << "NodeConstructor::getValueProperty unhandled token " << token << endl;
1675     return Value();
1676   }
1677 #endif
1678 }
1679
1680 Object KJS::getNodeConstructor(ExecState *exec)
1681 {
1682   return Object(cacheGlobalObject<NodeConstructor>(exec, "[[node.constructor]]"));
1683 }
1684
1685 // -------------------------------------------------------------------------
1686
1687 const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 };
1688
1689 /* Source for DOMExceptionConstructorTable. Use "make hashtables" to regenerate.
1690 @begin DOMExceptionConstructorTable 15
1691   INDEX_SIZE_ERR                DOM::DOMException::INDEX_SIZE_ERR               DontDelete|ReadOnly
1692   DOMSTRING_SIZE_ERR            DOM::DOMException::DOMSTRING_SIZE_ERR   DontDelete|ReadOnly
1693   HIERARCHY_REQUEST_ERR         DOM::DOMException::HIERARCHY_REQUEST_ERR        DontDelete|ReadOnly
1694   WRONG_DOCUMENT_ERR            DOM::DOMException::WRONG_DOCUMENT_ERR   DontDelete|ReadOnly
1695   INVALID_CHARACTER_ERR         DOM::DOMException::INVALID_CHARACTER_ERR        DontDelete|ReadOnly
1696   NO_DATA_ALLOWED_ERR           DOM::DOMException::NO_DATA_ALLOWED_ERR  DontDelete|ReadOnly
1697   NO_MODIFICATION_ALLOWED_ERR   DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR  DontDelete|ReadOnly
1698   NOT_FOUND_ERR                 DOM::DOMException::NOT_FOUND_ERR                DontDelete|ReadOnly
1699   NOT_SUPPORTED_ERR             DOM::DOMException::NOT_SUPPORTED_ERR    DontDelete|ReadOnly
1700   INUSE_ATTRIBUTE_ERR           DOM::DOMException::INUSE_ATTRIBUTE_ERR  DontDelete|ReadOnly
1701   INVALID_STATE_ERR             DOM::DOMException::INVALID_STATE_ERR    DontDelete|ReadOnly
1702   SYNTAX_ERR                    DOM::DOMException::SYNTAX_ERR           DontDelete|ReadOnly
1703   INVALID_MODIFICATION_ERR      DOM::DOMException::INVALID_MODIFICATION_ERR     DontDelete|ReadOnly
1704   NAMESPACE_ERR                 DOM::DOMException::NAMESPACE_ERR                DontDelete|ReadOnly
1705   INVALID_ACCESS_ERR            DOM::DOMException::INVALID_ACCESS_ERR   DontDelete|ReadOnly
1706 @end
1707 */
1708
1709 Value DOMExceptionConstructor::tryGet(ExecState *exec, const Identifier &propertyName) const
1710 {
1711   return DOMObjectLookupGetValue<DOMExceptionConstructor, DOMObject>(exec, propertyName, &DOMExceptionConstructorTable, this);
1712 }
1713
1714 Value DOMExceptionConstructor::getValueProperty(ExecState *, int token) const
1715 {
1716   // We use the token as the value to return directly
1717   return Number((unsigned int)token);
1718 #if 0
1719   switch (token) {
1720   case INDEX_SIZE_ERR:
1721     return Number((unsigned int)DOM::DOMException::INDEX_SIZE_ERR);
1722   case DOMSTRING_SIZE_ERR:
1723     return Number((unsigned int)DOM::DOMException::DOMSTRING_SIZE_ERR);
1724   case HIERARCHY_REQUEST_ERR:
1725     return Number((unsigned int)DOM::DOMException::HIERARCHY_REQUEST_ERR);
1726   case WRONG_DOCUMENT_ERR:
1727     return Number((unsigned int)DOM::DOMException::WRONG_DOCUMENT_ERR);
1728   case INVALID_CHARACTER_ERR:
1729     return Number((unsigned int)DOM::DOMException::INVALID_CHARACTER_ERR);
1730   case NO_DATA_ALLOWED_ERR:
1731     return Number((unsigned int)DOM::DOMException::NO_DATA_ALLOWED_ERR);
1732   case NO_MODIFICATION_ALLOWED_ERR:
1733     return Number((unsigned int)DOM::DOMException::NO_MODIFICATION_ALLOWED_ERR);
1734   case NOT_FOUND_ERR:
1735     return Number((unsigned int)DOM::DOMException::NOT_FOUND_ERR);
1736   case NOT_SUPPORTED_ERR:
1737     return Number((unsigned int)DOM::DOMException::NOT_SUPPORTED_ERR);
1738   case INUSE_ATTRIBUTE_ERR:
1739     return Number((unsigned int)DOM::DOMException::INUSE_ATTRIBUTE_ERR);
1740   case INVALID_STATE_ERR:
1741     return Number((unsigned int)DOM::DOMException::INVALID_STATE_ERR);
1742   case SYNTAX_ERR:
1743     return Number((unsigned int)DOM::DOMException::SYNTAX_ERR);
1744   case INVALID_MODIFICATION_ERR:
1745     return Number((unsigned int)DOM::DOMException::INVALID_MODIFICATION_ERR);
1746   case NAMESPACE_ERR:
1747     return Number((unsigned int)DOM::DOMException::NAMESPACE_ERR);
1748   case INVALID_ACCESS_ERR:
1749     return Number((unsigned int)DOM::DOMException::INVALID_ACCESS_ERR);
1750   default:
1751     kdWarning() << "DOMExceptionConstructor::getValueProperty unhandled token " << token << endl;
1752     return Value();
1753   }
1754 #endif
1755 }
1756
1757 Object KJS::getDOMExceptionConstructor(ExecState *exec)
1758 {
1759   return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]");
1760 }
1761
1762 // -------------------------------------------------------------------------
1763
1764 // Such a collection is usually very short-lived, it only exists
1765 // for constructs like document.forms.<name>[1],
1766 // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David)
1767 DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState *, const QValueList<DOM::Node>& nodes )
1768   : DOMObject(), m_nodes(nodes)
1769 {
1770   // Maybe we should ref (and deref in the dtor) the nodes, though ?
1771 }
1772
1773 Value DOMNamedNodesCollection::tryGet(ExecState *exec, const Identifier &propertyName) const
1774 {
1775   if (propertyName == lengthPropertyName)
1776     return Number(m_nodes.count());
1777   // index?
1778   bool ok;
1779   unsigned int u = propertyName.toULong(&ok);
1780   if (ok && u < m_nodes.count()) {
1781     DOM::Node node = m_nodes[u];
1782     return getDOMNode(exec,node);
1783   }
1784   // For IE compatibility, we need to be able to look up elements in a
1785   // document.formName.name result by id as well as be index.
1786
1787   if (!ok) {
1788     for (QValueListConstIterator<DOM::Node> it = m_nodes.begin(); it != m_nodes.end(); it++) {
1789       DOM::Node node = *it;
1790       DOM::NamedNodeMap attributes = node.attributes();
1791       if (attributes.isNull()) {
1792         continue;
1793       }
1794
1795       DOM::Node idAttr = attributes.getNamedItem("id");
1796       if (idAttr.isNull()) {
1797         continue;
1798       }
1799
1800       if (idAttr.nodeValue() == propertyName.string()) {
1801         return getDOMNode(exec,node);
1802       }
1803     }
1804   }
1805
1806   return DOMObject::tryGet(exec,propertyName);
1807 }
1808
1809 // -------------------------------------------------------------------------
1810
1811 const ClassInfo DOMCharacterData::info = { "CharacterImp",
1812                                           &DOMNode::info, &DOMCharacterDataTable, 0 };
1813 /*
1814 @begin DOMCharacterDataTable 2
1815   data          DOMCharacterData::Data          DontDelete
1816   length        DOMCharacterData::Length        DontDelete|ReadOnly
1817 @end
1818 @begin DOMCharacterDataProtoTable 7
1819   substringData DOMCharacterData::SubstringData DontDelete|Function 2
1820   appendData    DOMCharacterData::AppendData    DontDelete|Function 1
1821   insertData    DOMCharacterData::InsertData    DontDelete|Function 2
1822   deleteData    DOMCharacterData::DeleteData    DontDelete|Function 2
1823   replaceData   DOMCharacterData::ReplaceData   DontDelete|Function 2
1824 @end
1825 */
1826 DEFINE_PROTOTYPE("DOMCharacterData",DOMCharacterDataProto)
1827 IMPLEMENT_PROTOFUNC(DOMCharacterDataProtoFunc)
1828 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMCharacterDataProto,DOMCharacterDataProtoFunc, DOMNodeProto)
1829
1830 DOMCharacterData::DOMCharacterData(ExecState *exec, const DOM::CharacterData &d)
1831  : DOMNode(DOMCharacterDataProto::self(exec), d) {}
1832
1833 DOMCharacterData::DOMCharacterData(const Object &proto, const DOM::CharacterData &d)
1834  : DOMNode(proto, d) {}
1835
1836 Value DOMCharacterData::tryGet(ExecState *exec, const Identifier &p) const
1837 {
1838 #ifdef KJS_VERBOSE
1839   kdDebug(6070)<<"DOMCharacterData::tryGet "<<p.string().string()<<endl;
1840 #endif
1841   return DOMObjectLookupGetValue<DOMCharacterData,DOMNode>(exec,p,&DOMCharacterDataTable,this);
1842 }
1843
1844 Value DOMCharacterData::getValueProperty(ExecState *, int token) const
1845 {
1846   DOM::CharacterData data = static_cast<DOM::CharacterData>(node);
1847   switch (token) {
1848   case Data:
1849     return String(data.data());
1850   case Length:
1851     return Number(data.length());
1852  default:
1853    kdWarning() << "Unhandled token in DOMCharacterData::getValueProperty : " << token << endl;
1854    return Value();
1855   }
1856 }
1857
1858 void DOMCharacterData::tryPut(ExecState *exec, const Identifier &propertyName, const Value& value, int attr)
1859 {
1860   if (propertyName == "data")
1861     static_cast<DOM::CharacterData>(node).setData(value.toString(exec).string());
1862   else
1863     DOMNode::tryPut(exec, propertyName,value,attr);
1864 }
1865
1866 Value DOMCharacterDataProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1867 {
1868   if (!thisObj.inherits(&KJS::DOMCharacterData::info)) {
1869     Object err = Error::create(exec,TypeError);
1870     exec->setException(err);
1871     return err;
1872   }
1873   DOM::CharacterData data = static_cast<DOMCharacterData *>(thisObj.imp())->toData();
1874   switch(id) {
1875     case DOMCharacterData::SubstringData: {
1876       const int count = args[1].toInt32(exec);
1877       if (count < 0)
1878         throw DOMException(DOMException::INDEX_SIZE_ERR);
1879       return getStringOrNull(data.substringData(args[0].toInt32(exec), count));
1880     }
1881     case DOMCharacterData::AppendData:
1882       data.appendData(args[0].toString(exec).string());
1883       return Undefined();
1884     case DOMCharacterData::InsertData:
1885       data.insertData(args[0].toInt32(exec), args[1].toString(exec).string());
1886       return Undefined();
1887     case DOMCharacterData::DeleteData: {
1888       const int count = args[1].toInt32(exec);
1889       if (count < 0)
1890         throw DOMException(DOMException::INDEX_SIZE_ERR);
1891       data.deleteData(args[0].toInt32(exec), count);
1892       return Undefined();
1893     }
1894     case DOMCharacterData::ReplaceData: {
1895       const int count = args[1].toInt32(exec);
1896       if (count < 0)
1897         throw DOMException(DOMException::INDEX_SIZE_ERR);
1898       data.replaceData(args[0].toInt32(exec), count, args[2].toString(exec).string());
1899       return Undefined();
1900     }
1901     default:
1902       return Undefined();
1903   }
1904 }
1905
1906 // -------------------------------------------------------------------------
1907
1908 const ClassInfo DOMText::info = { "Text",
1909                                  &DOMCharacterData::info, 0, 0 };
1910 /*
1911 @begin DOMTextProtoTable 1
1912   splitText     DOMText::SplitText      DontDelete|Function 1
1913 @end
1914 */
1915 DEFINE_PROTOTYPE("DOMText",DOMTextProto)
1916 IMPLEMENT_PROTOFUNC(DOMTextProtoFunc)
1917 IMPLEMENT_PROTOTYPE_WITH_PARENT(DOMTextProto,DOMTextProtoFunc,DOMCharacterDataProto)
1918
1919 DOMText::DOMText(ExecState *exec, const DOM::Text &t)
1920   : DOMCharacterData(DOMTextProto::self(exec), t) { }
1921
1922 Value DOMText::tryGet(ExecState *exec, const Identifier &p) const
1923 {
1924   if (p == "")
1925     return Undefined(); // ### TODO
1926   else
1927     return DOMCharacterData::tryGet(exec, p);
1928 }
1929
1930 Value DOMTextProtoFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1931 {
1932   if (!thisObj.inherits(&KJS::DOMText::info)) {
1933     Object err = Error::create(exec,TypeError);
1934     exec->setException(err);
1935     return err;
1936   }
1937   DOM::Text text = static_cast<DOMText *>(thisObj.imp())->toText();
1938   switch(id) {
1939     case DOMText::SplitText:
1940       return getDOMNode(exec,text.splitText(args[0].toInt32(exec)));
1941       break;
1942     default:
1943       return Undefined();
1944   }
1945 }
1946