| /* |
| * This file is part of the KDE libraries |
| * Copyright (C) 2000 Harri Porten (porten@kde.org) |
| * Copyright (C) 2006 Jon Shier (jshier@iastate.edu) |
| * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| #include "kjs_dom.h" |
| |
| #include "CDATASection.h" |
| #include "Comment.h" |
| #include "DOMImplementation.h" |
| #include "DocumentFragment.h" |
| #include "DocumentType.h" |
| #include "Element.h" |
| #include "Entity.h" |
| #include "Event.h" |
| #include "EventListener.h" |
| #include "EventNames.h" |
| #include "ExceptionCode.h" |
| #include "Frame.h" |
| #include "HTMLDocument.h" |
| #include "HTMLNames.h" |
| #include "HTMLPlugInElement.h" |
| #include "JSAttr.h" |
| #include "JSCharacterData.h" |
| #include "JSDOMImplementation.h" |
| #include "JSDocumentFragment.h" |
| #include "JSDocumentType.h" |
| #include "JSElement.h" |
| #include "JSEntity.h" |
| #include "JSHTMLDocument.h" |
| #include "JSHTMLElementWrapperFactory.h" |
| #include "JSNode.h" |
| #include "JSNotation.h" |
| #include "JSProcessingInstruction.h" |
| #include "JSRange.h" |
| #include "JSText.h" |
| #include "Settings.h" |
| #include "NamedNodeMap.h" |
| #include "Notation.h" |
| #include "ProcessingInstruction.h" |
| #include "Range.h" |
| #include "RenderView.h" |
| #include "kjs_css.h" |
| #include "kjs_events.h" |
| #include "kjs_traversal.h" |
| #include "kjs_window.h" |
| |
| #if SVG_SUPPORT |
| #include "JSSVGElementWrapperFactory.h" |
| #include "SVGElement.h" |
| #endif |
| |
| #if __APPLE__ |
| #include <JavaScriptCore/runtime_object.h> |
| #endif |
| |
| using namespace WebCore; |
| using namespace HTMLNames; |
| using namespace EventNames; |
| |
| #include "kjs_dom.lut.h" |
| |
| namespace KJS { |
| |
| // ------------------------------------------------------------------------- |
| /* Source for DOMNodeProtoTable. Use "make hashtables" to regenerate. |
| @begin DOMNodeProtoTable 25 |
| insertBefore DOMNode::InsertBefore DontDelete|Function 2 |
| replaceChild DOMNode::ReplaceChild DontDelete|Function 2 |
| removeChild DOMNode::RemoveChild DontDelete|Function 1 |
| appendChild DOMNode::AppendChild DontDelete|Function 1 |
| hasAttributes DOMNode::HasAttributes DontDelete|Function 0 |
| hasChildNodes DOMNode::HasChildNodes DontDelete|Function 0 |
| cloneNode DOMNode::CloneNode DontDelete|Function 1 |
| # DOM2 |
| normalize DOMNode::Normalize DontDelete|Function 0 |
| isSupported DOMNode::IsSupported DontDelete|Function 2 |
| # DOM3 |
| isSameNode DOMNode::IsSameNode DontDelete|Function 1 |
| isEqualNode DOMNode::IsEqualNode DontDelete|Function 1 |
| isDefaultNamespace DOMNode::IsDefaultNamespace DontDelete|Function 1 |
| lookupNamespaceURI DOMNode::LookupNamespaceURI DontDelete|Function 1 |
| lookupPrefix DOMNode::LookupPrefix DontDelete|Function 1 |
| # "DOM level 0" (from Gecko DOM reference; also in WinIE) |
| item DOMNode::Item DontDelete|Function 1 |
| @end |
| */ |
| KJS_IMPLEMENT_PROTOFUNC(DOMNodeProtoFunc) |
| KJS_IMPLEMENT_PROTOTYPE("DOMNode", DOMNodeProto, DOMNodeProtoFunc) |
| |
| const ClassInfo DOMNode::info = { "Node", 0, &DOMNodeTable, 0 }; |
| |
| DOMNode::DOMNode(ExecState* exec, Node* n) |
| : m_impl(n) |
| { |
| setPrototype(DOMNodeProto::self(exec)); |
| } |
| |
| DOMNode::DOMNode(Node* n) |
| : m_impl(n) |
| { |
| } |
| |
| DOMNode::~DOMNode() |
| { |
| ScriptInterpreter::forgetDOMNodeForDocument(m_impl->document(), m_impl.get()); |
| } |
| |
| void DOMNode::mark() |
| { |
| assert(!marked()); |
| |
| Node* node = m_impl.get(); |
| |
| // Nodes in the document are kept alive by ScriptInterpreter::mark, |
| // so we have no special responsibilities and can just call the base class here. |
| if (node->inDocument()) { |
| DOMObject::mark(); |
| return; |
| } |
| |
| // This is a node outside the document, so find the root of the tree it is in, |
| // and start marking from there. |
| Node* root = node; |
| for (Node* current = m_impl.get(); current; current = current->parentNode()) { |
| root = current; |
| } |
| |
| static HashSet<Node*> markingRoots; |
| |
| // If we're already marking this tree, then we can simply mark this wrapper |
| // by calling the base class; our caller is iterating the tree. |
| if (markingRoots.contains(root)) { |
| DOMObject::mark(); |
| return; |
| } |
| |
| // Mark the whole tree; use the global set of roots to avoid reentering. |
| markingRoots.add(root); |
| for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) { |
| DOMNode *wrapper = ScriptInterpreter::getDOMNodeForDocument(m_impl->document(), nodeToMark); |
| if (wrapper) { |
| if (!wrapper->marked()) |
| wrapper->mark(); |
| } else if (nodeToMark == node) { |
| // This is the case where the map from the document to wrappers has |
| // been cleared out, but a wrapper is being marked. For now, we'll |
| // let the rest of the tree of wrappers get collected, because we have |
| // no good way of finding them. Later we should test behavior of other |
| // browsers and see if we need to preserve other wrappers in this case. |
| if (!marked()) |
| mark(); |
| } |
| } |
| markingRoots.remove(root); |
| |
| // Double check that we actually ended up marked. This assert caught problems in the past. |
| assert(marked()); |
| } |
| |
| bool DOMNode::toBoolean(ExecState* ) const |
| { |
| return m_impl; |
| } |
| |
| /* Source for DOMNodeTable. Use "make hashtables" to regenerate. |
| @begin DOMNodeTable 25 |
| nodeName DOMNode::NodeName DontDelete|ReadOnly |
| nodeValue DOMNode::NodeValue DontDelete |
| nodeType DOMNode::NodeType DontDelete|ReadOnly |
| parentNode DOMNode::ParentNode DontDelete|ReadOnly |
| parentElement DOMNode::ParentElement DontDelete|ReadOnly |
| childNodes DOMNode::ChildNodes DontDelete|ReadOnly |
| firstChild DOMNode::FirstChild DontDelete|ReadOnly |
| lastChild DOMNode::LastChild DontDelete|ReadOnly |
| previousSibling DOMNode::PreviousSibling DontDelete|ReadOnly |
| nextSibling DOMNode::NextSibling DontDelete|ReadOnly |
| attributes DOMNode::Attributes DontDelete|ReadOnly |
| namespaceURI DOMNode::NamespaceURI DontDelete|ReadOnly |
| # DOM2 |
| prefix DOMNode::Prefix DontDelete |
| localName DOMNode::LocalName DontDelete|ReadOnly |
| ownerDocument DOMNode::OwnerDocument DontDelete|ReadOnly |
| # DOM3 |
| textContent DOMNode::TextContent DontDelete |
| @end |
| */ |
| bool DOMNode::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| return getStaticValueSlot<DOMNode, DOMObject>(exec, &DOMNodeTable, this, propertyName, slot); |
| } |
| |
| JSValue* DOMNode::getValueProperty(ExecState* exec, int token) const |
| { |
| Node& node = *m_impl; |
| switch (token) { |
| case NodeName: |
| return jsStringOrNull(node.nodeName()); |
| case NodeValue: |
| return jsStringOrNull(node.nodeValue()); |
| case NodeType: |
| return jsNumber(node.nodeType()); |
| case ParentNode: |
| case ParentElement: // IE only apparently |
| return toJS(exec,node.parentNode()); |
| case ChildNodes: |
| return toJS(exec,node.childNodes().get()); |
| case FirstChild: |
| return toJS(exec,node.firstChild()); |
| case LastChild: |
| return toJS(exec,node.lastChild()); |
| case PreviousSibling: |
| return toJS(exec,node.previousSibling()); |
| case NextSibling: |
| return toJS(exec,node.nextSibling()); |
| case Attributes: |
| return toJS(exec,node.attributes()); |
| case NamespaceURI: |
| return jsStringOrNull(node.namespaceURI()); |
| case Prefix: |
| return jsStringOrNull(node.prefix()); |
| case LocalName: |
| return jsStringOrNull(node.localName()); |
| case OwnerDocument: |
| return toJS(exec,node.ownerDocument()); |
| case TextContent: |
| return jsStringOrNull(node.textContent()); |
| } |
| |
| return jsUndefined(); |
| } |
| |
| void DOMNode::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr) |
| { |
| lookupPut<DOMNode,DOMObject>(exec, propertyName, value, attr, &DOMNodeTable, this); |
| } |
| |
| void DOMNode::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/) |
| { |
| DOMExceptionTranslator exception(exec); |
| Node& node = *m_impl; |
| switch (token) { |
| case NodeValue: |
| node.setNodeValue(value->toString(exec), exception); |
| break; |
| case Prefix: |
| node.setPrefix(value->toString(exec), exception); |
| break; |
| case TextContent: |
| node.setTextContent(valueToStringWithNullCheck(exec, value), exception); |
| break; |
| } |
| } |
| |
| JSValue* DOMNode::toPrimitive(ExecState* exec, JSType) const |
| { |
| if (!m_impl) |
| return jsNull(); |
| |
| return jsString(toString(exec)); |
| } |
| |
| UString DOMNode::toString(ExecState* ) const |
| { |
| if (!m_impl) |
| return "null"; |
| return "[object " + (m_impl->isElementNode() ? UString(m_impl->nodeName()) : className()) + "]"; |
| } |
| |
| JSValue* DOMNodeProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args) |
| { |
| if (!thisObj->inherits(&DOMNode::info)) |
| return throwError(exec, TypeError); |
| DOMExceptionTranslator exception(exec); |
| Node& node = *static_cast<DOMNode*>(thisObj)->impl(); |
| switch (id) { |
| case DOMNode::HasAttributes: |
| return jsBoolean(node.hasAttributes()); |
| case DOMNode::HasChildNodes: |
| return jsBoolean(node.hasChildNodes()); |
| case DOMNode::CloneNode: |
| return toJS(exec,node.cloneNode(args[0]->toBoolean(exec))); |
| case DOMNode::Normalize: |
| node.normalize(); |
| return jsUndefined(); |
| case DOMNode::IsSupported: |
| return jsBoolean(node.isSupported(args[0]->toString(exec), |
| valueToStringWithNullCheck(exec, args[1]))); |
| case DOMNode::IsSameNode: |
| return jsBoolean(node.isSameNode(toNode(args[0]))); |
| case DOMNode::IsEqualNode: |
| return jsBoolean(node.isEqualNode(toNode(args[0]))); |
| case DOMNode::IsDefaultNamespace: |
| return jsBoolean(node.isDefaultNamespace(valueToStringWithNullCheck(exec, args[0]))); |
| case DOMNode::LookupNamespaceURI: |
| return jsStringOrNull(node.lookupNamespaceURI(valueToStringWithNullCheck(exec, args[0]))); |
| case DOMNode::LookupPrefix: |
| return jsStringOrNull(node.lookupPrefix(valueToStringWithNullCheck(exec, args[0]))); |
| case DOMNode::AppendChild: |
| if (node.appendChild(toNode(args[0]), exception)) |
| return args[0]; |
| return jsNull(); |
| case DOMNode::RemoveChild: |
| if (node.removeChild(toNode(args[0]), exception)) |
| return args[0]; |
| return jsNull(); |
| case DOMNode::InsertBefore: |
| if (node.insertBefore(toNode(args[0]), toNode(args[1]), exception)) |
| return args[0]; |
| return jsNull(); |
| case DOMNode::ReplaceChild: |
| if (node.replaceChild(toNode(args[0]), toNode(args[1]), exception)) |
| return args[1]; |
| return jsNull(); |
| case DOMNode::Item: |
| return thisObj->get(exec, args[0]->toInt32(exec)); |
| } |
| |
| return jsUndefined(); |
| } |
| |
| EventTargetNode *toEventTargetNode(JSValue* val) |
| { |
| if (!val || !val->isObject(&DOMEventTargetNode::info)) |
| return 0; |
| return static_cast<EventTargetNode*>(static_cast<DOMEventTargetNode*>(val)->impl()); |
| } |
| |
| Node* toNode(JSValue* val) |
| { |
| if (!val || !val->isObject(&DOMNode::info)) |
| return 0; |
| return static_cast<DOMNode*>(val)->impl(); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| /* Source for DOMEventTargetNodeTable |
| @begin DOMEventTargetNodeTable 50 |
| onabort DOMEventTargetNode::OnAbort DontDelete |
| onblur DOMEventTargetNode::OnBlur DontDelete |
| onchange DOMEventTargetNode::OnChange DontDelete |
| onclick DOMEventTargetNode::OnClick DontDelete |
| oncontextmenu DOMEventTargetNode::OnContextMenu DontDelete |
| ondblclick DOMEventTargetNode::OnDblClick DontDelete |
| onbeforecut DOMEventTargetNode::OnBeforeCut DontDelete |
| oncut DOMEventTargetNode::OnCut DontDelete |
| onbeforecopy DOMEventTargetNode::OnBeforeCopy DontDelete |
| oncopy DOMEventTargetNode::OnCopy DontDelete |
| onbeforepaste DOMEventTargetNode::OnBeforePaste DontDelete |
| onpaste DOMEventTargetNode::OnPaste DontDelete |
| ondrag DOMEventTargetNode::OnDrag DontDelete |
| ondragdrop DOMEventTargetNode::OnDragDrop DontDelete |
| ondragend DOMEventTargetNode::OnDragEnd DontDelete |
| ondragenter DOMEventTargetNode::OnDragEnter DontDelete |
| ondragleave DOMEventTargetNode::OnDragLeave DontDelete |
| ondragover DOMEventTargetNode::OnDragOver DontDelete |
| ondragstart DOMEventTargetNode::OnDragStart DontDelete |
| ondrop DOMEventTargetNode::OnDrop DontDelete |
| onerror DOMEventTargetNode::OnError DontDelete |
| onfocus DOMEventTargetNode::OnFocus DontDelete |
| oninput DOMEventTargetNode::OnInput DontDelete |
| onkeydown DOMEventTargetNode::OnKeyDown DontDelete |
| onkeypress DOMEventTargetNode::OnKeyPress DontDelete |
| onkeyup DOMEventTargetNode::OnKeyUp DontDelete |
| onload DOMEventTargetNode::OnLoad DontDelete |
| onmousedown DOMEventTargetNode::OnMouseDown DontDelete |
| onmousemove DOMEventTargetNode::OnMouseMove DontDelete |
| onmouseout DOMEventTargetNode::OnMouseOut DontDelete |
| onmouseover DOMEventTargetNode::OnMouseOver DontDelete |
| onmouseup DOMEventTargetNode::OnMouseUp DontDelete |
| onmousewheel DOMEventTargetNode::OnMouseWheel DontDelete |
| onmove DOMEventTargetNode::OnMove DontDelete |
| onreset DOMEventTargetNode::OnReset DontDelete |
| onresize DOMEventTargetNode::OnResize DontDelete |
| onscroll DOMEventTargetNode::OnScroll DontDelete |
| onsearch DOMEventTargetNode::OnSearch DontDelete |
| onselect DOMEventTargetNode::OnSelect DontDelete |
| onselectstart DOMEventTargetNode::OnSelectStart DontDelete |
| onsubmit DOMEventTargetNode::OnSubmit DontDelete |
| onunload DOMEventTargetNode::OnUnload DontDelete |
| @end |
| */ |
| |
| DOMEventTargetNode::DOMEventTargetNode(ExecState* exec, Node* n) |
| : JSNode(exec, n) |
| { |
| setPrototype(DOMEventTargetNodeProto::self(exec)); |
| } |
| |
| bool DOMEventTargetNode::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| return getStaticValueSlot<DOMEventTargetNode, DOMNode>(exec, &DOMEventTargetNodeTable, this, propertyName, slot); |
| } |
| |
| JSValue* DOMEventTargetNode::getValueProperty(ExecState* exec, int token) const |
| { |
| switch (token) { |
| case OnAbort: |
| return getListener(abortEvent); |
| case OnBlur: |
| return getListener(blurEvent); |
| case OnChange: |
| return getListener(changeEvent); |
| case OnClick: |
| return getListener(clickEvent); |
| case OnContextMenu: |
| return getListener(contextmenuEvent); |
| case OnDblClick: |
| return getListener(dblclickEvent); |
| case OnDragDrop: |
| return getListener(khtmlDragdropEvent); |
| case OnError: |
| return getListener(errorEvent); |
| case OnFocus: |
| return getListener(focusEvent); |
| case OnInput: |
| return getListener(inputEvent); |
| case OnKeyDown: |
| return getListener(keydownEvent); |
| case OnKeyPress: |
| return getListener(keypressEvent); |
| case OnKeyUp: |
| return getListener(keyupEvent); |
| case OnLoad: |
| return getListener(loadEvent); |
| case OnMouseDown: |
| return getListener(mousedownEvent); |
| case OnMouseMove: |
| return getListener(mousemoveEvent); |
| case OnMouseOut: |
| return getListener(mouseoutEvent); |
| case OnMouseOver: |
| return getListener(mouseoverEvent); |
| case OnMouseUp: |
| return getListener(mouseupEvent); |
| case OnMouseWheel: |
| return getListener(mousewheelEvent); |
| case OnBeforeCut: |
| return getListener(beforecutEvent); |
| case OnCut: |
| return getListener(cutEvent); |
| case OnBeforeCopy: |
| return getListener(beforecopyEvent); |
| case OnCopy: |
| return getListener(copyEvent); |
| case OnBeforePaste: |
| return getListener(beforepasteEvent); |
| case OnPaste: |
| return getListener(pasteEvent); |
| case OnDragEnter: |
| return getListener(dragenterEvent); |
| case OnDragOver: |
| return getListener(dragoverEvent); |
| case OnDragLeave: |
| return getListener(dragleaveEvent); |
| case OnDrop: |
| return getListener(dropEvent); |
| case OnDragStart: |
| return getListener(dragstartEvent); |
| case OnDrag: |
| return getListener(dragEvent); |
| case OnDragEnd: |
| return getListener(dragendEvent); |
| case OnMove: |
| return getListener(khtmlMoveEvent); |
| case OnReset: |
| return getListener(resetEvent); |
| case OnResize: |
| return getListener(resizeEvent); |
| case OnScroll: |
| return getListener(scrollEvent); |
| case OnSearch: |
| return getListener(searchEvent); |
| case OnSelect: |
| return getListener(selectEvent); |
| case OnSelectStart: |
| return getListener(selectstartEvent); |
| case OnSubmit: |
| return getListener(submitEvent); |
| case OnUnload: |
| return getListener(unloadEvent); |
| } |
| |
| return jsUndefined(); |
| } |
| |
| void DOMEventTargetNode::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr) |
| { |
| lookupPut<DOMEventTargetNode, DOMNode>(exec, propertyName, value, attr, &DOMEventTargetNodeTable, this); |
| } |
| |
| void DOMEventTargetNode::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/) |
| { |
| switch (token) { |
| case OnAbort: |
| setListener(exec, abortEvent, value); |
| break; |
| case OnBlur: |
| setListener(exec, blurEvent, value); |
| break; |
| case OnChange: |
| setListener(exec, changeEvent, value); |
| break; |
| case OnClick: |
| setListener(exec, clickEvent, value); |
| break; |
| case OnContextMenu: |
| setListener(exec, contextmenuEvent, value); |
| break; |
| case OnDblClick: |
| setListener(exec, dblclickEvent, value); |
| break; |
| case OnDragDrop: |
| setListener(exec, khtmlDragdropEvent, value); |
| break; |
| case OnError: |
| setListener(exec, errorEvent, value); |
| break; |
| case OnFocus: |
| setListener(exec, focusEvent, value); |
| break; |
| case OnInput: |
| setListener(exec, inputEvent, value); |
| break; |
| case OnKeyDown: |
| setListener(exec, keydownEvent, value); |
| break; |
| case OnKeyPress: |
| setListener(exec, keypressEvent, value); |
| break; |
| case OnKeyUp: |
| setListener(exec, keyupEvent, value); |
| break; |
| case OnLoad: |
| setListener(exec, loadEvent, value); |
| break; |
| case OnMouseDown: |
| setListener(exec, mousedownEvent, value); |
| break; |
| case OnMouseMove: |
| setListener(exec, mousemoveEvent, value); |
| break; |
| case OnMouseOut: |
| setListener(exec, mouseoutEvent, value); |
| break; |
| case OnMouseOver: |
| setListener(exec, mouseoverEvent, value); |
| break; |
| case OnMouseUp: |
| setListener(exec, mouseupEvent, value); |
| break; |
| case OnMouseWheel: |
| setListener(exec, mousewheelEvent, value); |
| break; |
| case OnBeforeCut: |
| setListener(exec, beforecutEvent, value); |
| break; |
| case OnCut: |
| setListener(exec, cutEvent, value); |
| break; |
| case OnBeforeCopy: |
| setListener(exec, beforecopyEvent, value); |
| break; |
| case OnCopy: |
| setListener(exec, copyEvent, value); |
| break; |
| case OnBeforePaste: |
| setListener(exec, beforepasteEvent, value); |
| break; |
| case OnPaste: |
| setListener(exec, pasteEvent, value); |
| break; |
| case OnDragEnter: |
| setListener(exec, dragenterEvent, value); |
| break; |
| case OnDragOver: |
| setListener(exec, dragoverEvent, value); |
| break; |
| case OnDragLeave: |
| setListener(exec, dragleaveEvent, value); |
| break; |
| case OnDrop: |
| setListener(exec, dropEvent, value); |
| break; |
| case OnDragStart: |
| setListener(exec, dragstartEvent, value); |
| break; |
| case OnDrag: |
| setListener(exec, dragEvent, value); |
| break; |
| case OnDragEnd: |
| setListener(exec, dragendEvent, value); |
| break; |
| case OnMove: |
| setListener(exec, khtmlMoveEvent, value); |
| break; |
| case OnReset: |
| setListener(exec, resetEvent, value); |
| break; |
| case OnResize: |
| setListener(exec, resizeEvent, value); |
| break; |
| case OnScroll: |
| setListener(exec, scrollEvent, value); |
| break; |
| case OnSearch: |
| setListener(exec, searchEvent, value); |
| break; |
| case OnSelect: |
| setListener(exec, selectEvent, value); |
| break; |
| case OnSelectStart: |
| setListener(exec, selectstartEvent, value); |
| break; |
| case OnSubmit: |
| setListener(exec, submitEvent, value); |
| break; |
| case OnUnload: |
| setListener(exec, unloadEvent, value); |
| break; |
| } |
| } |
| |
| void DOMEventTargetNode::setListener(ExecState* exec, const AtomicString &eventType, JSValue* func) const |
| { |
| EventTargetNodeCast(impl())->setHTMLEventListener(eventType, Window::retrieveActive(exec)->getJSEventListener(func, true)); |
| } |
| |
| JSValue* DOMEventTargetNode::getListener(const AtomicString &eventType) const |
| { |
| EventListener *listener = EventTargetNodeCast(impl())->getHTMLEventListener(eventType); |
| JSEventListener *jsListener = static_cast<JSEventListener*>(listener); |
| if (jsListener && jsListener->listenerObj()) |
| return jsListener->listenerObj(); |
| else |
| return jsNull(); |
| } |
| |
| void DOMEventTargetNode::pushEventHandlerScope(ExecState*, ScopeChain &) const |
| { |
| } |
| |
| /* |
| @begin DOMEventTargetNodeProtoTable 5 |
| # from the EventTarget interface |
| addEventListener DOMEventTargetNode::AddEventListener DontDelete|Function 3 |
| removeEventListener DOMEventTargetNode::RemoveEventListener DontDelete|Function 3 |
| dispatchEvent DOMEventTargetNode::DispatchEvent DontDelete|Function 1 |
| @end |
| */ |
| |
| KJS_IMPLEMENT_PROTOFUNC(DOMEventTargetNodeProtoFunc) |
| KJS_IMPLEMENT_PROTOTYPE("DOMEventTargetNode", DOMEventTargetNodeProto, DOMEventTargetNodeProtoFunc) |
| |
| JSValue* DOMEventTargetNodeProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args) |
| { |
| if (!thisObj->inherits(&DOMEventTargetNode::info)) |
| return throwError(exec, TypeError); |
| DOMExceptionTranslator exception(exec); |
| DOMEventTargetNode* DOMNode = static_cast<DOMEventTargetNode*>(thisObj); |
| EventTargetNode* node = static_cast<EventTargetNode*>(DOMNode->impl()); |
| switch (id) { |
| case DOMEventTargetNode::AddEventListener: { |
| JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); |
| if (listener) |
| node->addEventListener(args[0]->toString(exec), listener,args[2]->toBoolean(exec)); |
| return jsUndefined(); |
| } |
| case DOMEventTargetNode::RemoveEventListener: { |
| JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]); |
| if (listener) |
| node->removeEventListener(args[0]->toString(exec), listener,args[2]->toBoolean(exec)); |
| return jsUndefined(); |
| } |
| case DOMEventTargetNode::DispatchEvent: |
| return jsBoolean(node->dispatchEvent(toEvent(args[0]), exception)); |
| } |
| |
| return jsUndefined(); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| /* |
| @begin DOMNodeListTable 2 |
| length DOMNodeList::Length DontDelete|ReadOnly |
| item DOMNodeList::Item DontDelete|Function 1 |
| @end |
| */ |
| |
| KJS_IMPLEMENT_PROTOFUNC(DOMNodeListFunc) |
| |
| const ClassInfo DOMNodeList::info = { "NodeList", 0, &DOMNodeListTable, 0 }; |
| |
| DOMNodeList::DOMNodeList(ExecState* exec, NodeList *l) |
| : m_impl(l) |
| { |
| setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); |
| } |
| |
| DOMNodeList::~DOMNodeList() |
| { |
| ScriptInterpreter::forgetDOMObject(m_impl.get()); |
| } |
| |
| JSValue* DOMNodeList::toPrimitive(ExecState* exec, JSType) const |
| { |
| if (!m_impl) |
| return jsNull(); |
| |
| return jsString(toString(exec)); |
| } |
| |
| JSValue* DOMNodeList::getValueProperty(ExecState* exec, int token) const |
| { |
| assert(token == Length); |
| return jsNumber(m_impl->length()); |
| } |
| |
| JSValue* DOMNodeList::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNodeList *thisObj = static_cast<DOMNodeList*>(slot.slotBase()); |
| return toJS(exec, thisObj->m_impl->item(slot.index())); |
| } |
| |
| JSValue* DOMNodeList::nameGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNodeList *thisObj = static_cast<DOMNodeList*>(slot.slotBase()); |
| return toJS(exec, thisObj->m_impl->itemWithName(propertyName)); |
| } |
| |
| bool DOMNodeList::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| const HashEntry* entry = Lookup::findEntry(&DOMNodeListTable, propertyName); |
| |
| if (entry) { |
| if (entry->attr & Function) |
| slot.setStaticEntry(this, entry, staticFunctionGetter<DOMNodeListFunc>); |
| else |
| slot.setStaticEntry(this, entry, staticValueGetter<DOMNodeList>); |
| return true; |
| } |
| |
| // array index ? |
| bool ok; |
| unsigned idx = propertyName.toUInt32(&ok); |
| if (ok && idx < m_impl->length()) { |
| slot.setCustomIndex(this, idx, indexGetter); |
| return true; |
| } else if (m_impl->itemWithName(String(propertyName).impl())) { |
| slot.setCustom(this, nameGetter); |
| return true; |
| } |
| |
| return DOMObject::getOwnPropertySlot(exec, propertyName, slot); |
| } |
| |
| // Need to support both get and call, so that list[0] and list(0) work. |
| JSValue* DOMNodeList::callAsFunction(ExecState* exec, JSObject*, const List &args) |
| { |
| // Do not use thisObj here. See JSHTMLCollection. |
| UString s = args[0]->toString(exec); |
| bool ok; |
| unsigned int u = s.toUInt32(&ok); |
| if (ok) |
| return toJS(exec, m_impl->item(u)); |
| |
| return jsUndefined(); |
| } |
| |
| // Not a prototype class currently, but should probably be converted to one |
| JSValue* DOMNodeListFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args) |
| { |
| if (!thisObj->inherits(&KJS::DOMNodeList::info)) |
| return throwError(exec, TypeError); |
| NodeList &list = *static_cast<DOMNodeList*>(thisObj)->impl(); |
| |
| if (id == DOMNodeList::Item) |
| return toJS(exec, list.item(args[0]->toInt32(exec))); |
| |
| return jsUndefined(); |
| } |
| |
| Attr* toAttr(JSValue* val, bool& ok) |
| { |
| if (!val || !val->isObject(&JSAttr::info)) { |
| ok = false; |
| return 0; |
| } |
| |
| ok = true; |
| return static_cast<Attr*>(static_cast<DOMNode*>(val)->impl()); |
| } |
| |
| Element* toElement(JSValue* val) |
| { |
| if (!val || !val->isObject(&JSElement::info)) |
| return 0; |
| return static_cast<Element*>(static_cast<JSElement*>(val)->impl()); |
| } |
| |
| DocumentType* toDocumentType(JSValue* val) |
| { |
| if (!val || !val->isObject(&JSDocumentType::info)) |
| return 0; |
| return static_cast<DocumentType*>(static_cast<DOMNode*>(val)->impl()); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| /* Source for DOMNamedNodeMapProtoTable. Use "make hashtables" to regenerate. |
| @begin DOMNamedNodeMapProtoTable 10 |
| getNamedItem DOMNamedNodeMap::GetNamedItem DontDelete|Function 1 |
| setNamedItem DOMNamedNodeMap::SetNamedItem DontDelete|Function 1 |
| removeNamedItem DOMNamedNodeMap::RemoveNamedItem DontDelete|Function 1 |
| item DOMNamedNodeMap::Item DontDelete|Function 1 |
| # DOM2 |
| getNamedItemNS DOMNamedNodeMap::GetNamedItemNS DontDelete|Function 2 |
| setNamedItemNS DOMNamedNodeMap::SetNamedItemNS DontDelete|Function 1 |
| removeNamedItemNS DOMNamedNodeMap::RemoveNamedItemNS DontDelete|Function 2 |
| @end |
| */ |
| KJS_DEFINE_PROTOTYPE(DOMNamedNodeMapProto) |
| KJS_IMPLEMENT_PROTOFUNC(DOMNamedNodeMapProtoFunc) |
| KJS_IMPLEMENT_PROTOTYPE("NamedNodeMap", DOMNamedNodeMapProto, DOMNamedNodeMapProtoFunc) |
| |
| const ClassInfo DOMNamedNodeMap::info = { "NamedNodeMap", 0, 0, 0 }; |
| |
| DOMNamedNodeMap::DOMNamedNodeMap(ExecState* exec, NamedNodeMap* m) |
| : m_impl(m) |
| { |
| setPrototype(DOMNamedNodeMapProto::self(exec)); |
| } |
| |
| DOMNamedNodeMap::~DOMNamedNodeMap() |
| { |
| ScriptInterpreter::forgetDOMObject(m_impl.get()); |
| } |
| |
| JSValue* DOMNamedNodeMap::lengthGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNamedNodeMap* thisObj = static_cast<DOMNamedNodeMap*>(slot.slotBase()); |
| return jsNumber(thisObj->m_impl->length()); |
| } |
| |
| JSValue* DOMNamedNodeMap::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNamedNodeMap* thisObj = static_cast<DOMNamedNodeMap*>(slot.slotBase()); |
| return toJS(exec, thisObj->m_impl->item(slot.index())); |
| } |
| |
| JSValue* DOMNamedNodeMap::nameGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNamedNodeMap* thisObj = static_cast<DOMNamedNodeMap*>(slot.slotBase()); |
| return toJS(exec, thisObj->m_impl->getNamedItem(propertyName)); |
| } |
| |
| bool DOMNamedNodeMap::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| if (propertyName == lengthPropertyName) { |
| slot.setCustom(this, lengthGetter); |
| return true; |
| } else { |
| // Look in the prototype (for functions) before assuming it's an item's name |
| JSValue* proto = prototype(); |
| if (proto->isObject() && static_cast<JSObject*>(proto)->hasProperty(exec, propertyName)) |
| return false; |
| |
| // name or index ? |
| bool ok; |
| unsigned idx = propertyName.toUInt32(&ok); |
| if (ok && idx < m_impl->length()) { |
| slot.setCustomIndex(this, idx, indexGetter); |
| return true; |
| } |
| |
| if (m_impl->getNamedItem(propertyName)) { |
| slot.setCustom(this, nameGetter); |
| return true; |
| } |
| } |
| |
| return DOMObject::getOwnPropertySlot(exec, propertyName, slot); |
| } |
| |
| JSValue* DOMNamedNodeMapProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args) |
| { |
| if (!thisObj->inherits(&KJS::DOMNamedNodeMap::info)) |
| return throwError(exec, TypeError); |
| DOMExceptionTranslator exception(exec); |
| NamedNodeMap &map = *static_cast<DOMNamedNodeMap*>(thisObj)->impl(); |
| switch (id) { |
| case DOMNamedNodeMap::GetNamedItem: |
| return toJS(exec, map.getNamedItem(args[0]->toString(exec))); |
| case DOMNamedNodeMap::SetNamedItem: |
| return toJS(exec, map.setNamedItem(toNode(args[0]), exception).get()); |
| case DOMNamedNodeMap::RemoveNamedItem: |
| return toJS(exec, map.removeNamedItem(args[0]->toString(exec), exception).get()); |
| case DOMNamedNodeMap::Item: |
| return toJS(exec, map.item(args[0]->toInt32(exec))); |
| case DOMNamedNodeMap::GetNamedItemNS: // DOM2 |
| return toJS(exec, map.getNamedItemNS(valueToStringWithNullCheck(exec, args[0]), args[1]->toString(exec))); |
| case DOMNamedNodeMap::SetNamedItemNS: // DOM2 |
| return toJS(exec, map.setNamedItemNS(toNode(args[0]), exception).get()); |
| case DOMNamedNodeMap::RemoveNamedItemNS: // DOM2 |
| return toJS(exec, map.removeNamedItemNS(valueToStringWithNullCheck(exec, args[0]), args[1]->toString(exec), exception).get()); |
| } |
| return jsUndefined(); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| JSValue* toJS(ExecState* exec, Document *n) |
| { |
| if (!n) |
| return jsNull(); |
| |
| JSDocument* ret = 0; |
| ScriptInterpreter* interp = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter()); |
| |
| if ((ret = static_cast<JSDocument*>(interp->getDOMObject(n)))) |
| return ret; |
| |
| if (n->isHTMLDocument()) |
| ret = new WebCore::JSHTMLDocument(exec, static_cast<HTMLDocument*>(n)); |
| else |
| ret = new JSDocument(exec, n); |
| |
| // Make sure the document is kept around by the window object, and works right with the |
| // back/forward cache. |
| if (n->frame()) |
| Window::retrieveWindow(n->frame())->putDirect("document", ret, DontDelete|ReadOnly); |
| |
| interp->putDOMObject(n, ret); |
| |
| return ret; |
| } |
| |
| bool checkNodeSecurity(ExecState* exec, Node* n) |
| { |
| if (!n) |
| return false; |
| |
| // Check to see if the currently executing interpreter is allowed to access the specified node |
| Window* win = Window::retrieveWindow(n->document()->frame()); |
| return win && win->isSafeScript(exec); |
| } |
| |
| JSValue* toJS(ExecState* exec, PassRefPtr<Node> node) |
| { |
| Node* n = node.get(); |
| DOMNode* ret = 0; |
| if (!n) |
| return jsNull(); |
| ScriptInterpreter* interp = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter()); |
| Document* doc = n->document(); |
| |
| if ((ret = interp->getDOMNodeForDocument(doc, n))) |
| return ret; |
| |
| switch (n->nodeType()) { |
| case Node::ELEMENT_NODE: |
| if (n->isHTMLElement()) |
| ret = createJSHTMLWrapper(exec, static_pointer_cast<HTMLElement>(node)); |
| #if SVG_SUPPORT |
| else if (n->isSVGElement()) |
| ret = createJSSVGWrapper(exec, static_pointer_cast<SVGElement>(node)); |
| #endif |
| else |
| ret = new JSElement(exec, static_cast<Element*>(n)); |
| break; |
| case Node::ATTRIBUTE_NODE: |
| ret = new JSAttr(exec, static_cast<Attr*>(n)); |
| break; |
| case Node::TEXT_NODE: |
| case Node::CDATA_SECTION_NODE: |
| ret = new JSText(exec, static_cast<Text*>(n)); |
| break; |
| case Node::ENTITY_NODE: |
| ret = new JSEntity(exec, static_cast<Entity*>(n)); |
| break; |
| case Node::PROCESSING_INSTRUCTION_NODE: |
| ret = new JSProcessingInstruction(exec, static_cast<ProcessingInstruction*>(n)); |
| break; |
| case Node::COMMENT_NODE: |
| ret = new JSCharacterData(exec, static_cast<CharacterData*>(n)); |
| break; |
| case Node::DOCUMENT_NODE: |
| // we don't want to cache the document itself in the per-document dictionary |
| return toJS(exec, static_cast<Document*>(n)); |
| case Node::DOCUMENT_TYPE_NODE: |
| ret = new JSDocumentType(exec, static_cast<DocumentType*>(n)); |
| break; |
| case Node::NOTATION_NODE: |
| ret = new JSNotation(exec, static_cast<Notation*>(n)); |
| break; |
| case Node::DOCUMENT_FRAGMENT_NODE: |
| ret = new JSDocumentFragment(exec, static_cast<DocumentFragment*>(n)); |
| break; |
| case Node::ENTITY_REFERENCE_NODE: |
| default: |
| ret = new JSNode(exec, n); |
| } |
| |
| interp->putDOMNodeForDocument(doc, n, ret); |
| |
| return ret; |
| } |
| |
| JSValue* toJS(ExecState* exec, NamedNodeMap* m) |
| { |
| return cacheDOMObject<NamedNodeMap, DOMNamedNodeMap>(exec, m); |
| } |
| |
| JSValue* getRuntimeObject(ExecState* exec, Node* n) |
| { |
| if (!n) |
| return 0; |
| |
| #if __APPLE__ |
| if (n->hasTagName(objectTag) || n->hasTagName(embedTag) || n->hasTagName(appletTag)) { |
| HTMLPlugInElement* plugInElement = static_cast<HTMLPlugInElement*>(n); |
| if (plugInElement->getInstance()) |
| // The instance is owned by the PlugIn element. |
| return new RuntimeObjectImp(plugInElement->getInstance()); |
| } |
| #endif |
| |
| // If we don't have a runtime object return 0. |
| return 0; |
| } |
| |
| JSValue* toJS(ExecState* exec, PassRefPtr<NodeList> l) |
| { |
| return cacheDOMObject<NodeList, DOMNodeList>(exec, l.get()); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| const ClassInfo DOMExceptionConstructor::info = { "DOMExceptionConstructor", 0, 0, 0 }; |
| |
| /* Source for DOMExceptionConstructorTable. Use "make hashtables" to regenerate. |
| @begin DOMExceptionConstructorTable 15 |
| INDEX_SIZE_ERR WebCore::INDEX_SIZE_ERR DontDelete|ReadOnly |
| DOMSTRING_SIZE_ERR WebCore::DOMSTRING_SIZE_ERR DontDelete|ReadOnly |
| HIERARCHY_REQUEST_ERR WebCore::HIERARCHY_REQUEST_ERR DontDelete|ReadOnly |
| WRONG_DOCUMENT_ERR WebCore::WRONG_DOCUMENT_ERR DontDelete|ReadOnly |
| INVALID_CHARACTER_ERR WebCore::INVALID_CHARACTER_ERR DontDelete|ReadOnly |
| NO_DATA_ALLOWED_ERR WebCore::NO_DATA_ALLOWED_ERR DontDelete|ReadOnly |
| NO_MODIFICATION_ALLOWED_ERR WebCore::NO_MODIFICATION_ALLOWED_ERR DontDelete|ReadOnly |
| NOT_FOUND_ERR WebCore::NOT_FOUND_ERR DontDelete|ReadOnly |
| NOT_SUPPORTED_ERR WebCore::NOT_SUPPORTED_ERR DontDelete|ReadOnly |
| INUSE_ATTRIBUTE_ERR WebCore::INUSE_ATTRIBUTE_ERR DontDelete|ReadOnly |
| INVALID_STATE_ERR WebCore::INVALID_STATE_ERR DontDelete|ReadOnly |
| SYNTAX_ERR WebCore::SYNTAX_ERR DontDelete|ReadOnly |
| INVALID_MODIFICATION_ERR WebCore::INVALID_MODIFICATION_ERR DontDelete|ReadOnly |
| NAMESPACE_ERR WebCore::NAMESPACE_ERR DontDelete|ReadOnly |
| INVALID_ACCESS_ERR WebCore::INVALID_ACCESS_ERR DontDelete|ReadOnly |
| @end |
| */ |
| |
| DOMExceptionConstructor::DOMExceptionConstructor(ExecState* exec) |
| { |
| setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); |
| } |
| |
| bool DOMExceptionConstructor::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| return getStaticValueSlot<DOMExceptionConstructor, DOMObject>(exec, &DOMExceptionConstructorTable, this, propertyName, slot); |
| } |
| |
| JSValue* DOMExceptionConstructor::getValueProperty(ExecState*, int token) const |
| { |
| // We use the token as the value to return directly |
| return jsNumber(token); |
| } |
| |
| JSObject* getDOMExceptionConstructor(ExecState* exec) |
| { |
| return cacheGlobalObject<DOMExceptionConstructor>(exec, "[[DOMException.constructor]]"); |
| } |
| |
| // ------------------------------------------------------------------------- |
| |
| const ClassInfo DOMNamedNodesCollection::info = { "Collection", 0, 0, 0 }; |
| |
| // Such a collection is usually very short-lived, it only exists |
| // for constructs like document.forms.<name>[1], |
| // so it shouldn't be a problem that it's storing all the nodes (with the same name). (David) |
| DOMNamedNodesCollection::DOMNamedNodesCollection(ExecState* exec, const DeprecatedValueList< RefPtr<Node> >& nodes ) |
| : m_nodes(nodes) |
| { |
| setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); |
| } |
| |
| JSValue* DOMNamedNodesCollection::lengthGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNamedNodesCollection *thisObj = static_cast<DOMNamedNodesCollection*>(slot.slotBase()); |
| return jsNumber(thisObj->m_nodes.count()); |
| } |
| |
| JSValue* DOMNamedNodesCollection::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot) |
| { |
| DOMNamedNodesCollection *thisObj = static_cast<DOMNamedNodesCollection*>(slot.slotBase()); |
| return toJS(exec, thisObj->m_nodes[slot.index()].get()); |
| } |
| |
| bool DOMNamedNodesCollection::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
| { |
| if (propertyName == lengthPropertyName) { |
| slot.setCustom(this, lengthGetter); |
| return true; |
| } |
| |
| // array index ? |
| bool ok; |
| unsigned idx = propertyName.toUInt32(&ok); |
| if (ok && idx < m_nodes.count()) { |
| slot.setCustomIndex(this, idx, indexGetter); |
| return true; |
| } |
| |
| // For IE compatibility, we need to be able to look up elements in a |
| // document.formName.name result by id as well as be index. |
| |
| AtomicString atomicPropertyName = propertyName; |
| DeprecatedValueListConstIterator< RefPtr<Node> > end = m_nodes.end(); |
| int i = 0; |
| for (DeprecatedValueListConstIterator< RefPtr<Node> > it = m_nodes.begin(); it != end; ++it, ++i) { |
| Node* node = (*it).get(); |
| if (node->hasAttributes() && node->attributes()->id() == atomicPropertyName) { |
| slot.setCustomIndex(this, i, indexGetter); |
| return true; |
| } |
| } |
| |
| return DOMObject::getOwnPropertySlot(exec, propertyName, slot); |
| } |
| |
| } // namespace |