From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/htmlattr.c | 2 + dlls/mshtml/htmlelem.c | 73 ++++++++++++++++++++++++++++--- dlls/mshtml/tests/documentmode.js | 3 ++ dlls/mshtml/tests/dom.js | 53 +++++++++++++++++++++- 4 files changed, 123 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 9b1544d06f0..0816ccefdbe 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -609,6 +609,8 @@ static const dispex_static_data_vtbl_t HTMLDOMAttribute_dispex_vtbl = {
static void HTMLDOMAttribute_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { + if(mode >= COMPAT_MODE_IE9) + HTMLDOMNode_init_dispex_info(info, mode); if(mode >= COMPAT_MODE_IE8) dispex_info_add_interface(info, IHTMLDOMAttribute3_tid, NULL); } diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 5df5029aed6..fe57bc0dfef 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -8465,6 +8465,46 @@ static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, const WCHA
TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(name), flags, dispid);
+ if(dispex_compat_mode(&This->dispex) >= COMPAT_MODE_IE9) { + nsIDOMAttr *nsattr, *iter; + UINT32 length, i; + nsAString nsstr; + nsresult nsres; + + if(!This->dom_attrs) + return DISP_E_UNKNOWNNAME; + nsIDOMMozNamedAttrMap_GetLength(This->dom_attrs, &length); + + if(name[0] >= '0' && name[0] <= '9') { + WCHAR *end_ptr; + i = wcstoul(name, &end_ptr, 10); + if(!*end_ptr) { + if(i < length) { + *dispid = MSHTML_DISPID_CUSTOM_MIN + i; + return S_OK; + } + } + } + + nsAString_Init(&nsstr, name); + nsres = nsIDOMMozNamedAttrMap_GetNamedItem(This->dom_attrs, &nsstr, &nsattr); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres) || !nsattr) + return DISP_E_UNKNOWNNAME; + + for(i = 0; i < length; i++) { + nsres = nsIDOMMozNamedAttrMap_Item(This->dom_attrs, i, &iter); + assert(nsres == NS_OK); + nsIDOMAttr_Release(iter); + if(iter == nsattr) + break; + } + + assert(i < length); + *dispid = MSHTML_DISPID_CUSTOM_MIN + i; + return S_OK; + } + hres = get_attr_dispid_by_name(This, name, dispid); if(FAILED(hres)) return hres; @@ -8494,6 +8534,20 @@ static HRESULT HTMLAttributeCollection_invoke(DispatchEx *dispex, DISPID id, LCI
pos = id-MSHTML_DISPID_CUSTOM_MIN;
+ if(dispex_compat_mode(&This->dispex) >= COMPAT_MODE_IE9) { + IHTMLDOMAttribute2 *attr; + HRESULT hres; + + hres = IHTMLAttributeCollection4_item(&This->IHTMLAttributeCollection4_iface, pos, &attr); + if(FAILED(hres)) + return hres; + if(!attr) + return DISP_E_MEMBERNOTFOUND; + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch *)attr; + return S_OK; + } + LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) { if(!pos) { IHTMLDOMAttribute_AddRef(&iter->IHTMLDOMAttribute_iface); @@ -8524,18 +8578,23 @@ static const dispex_static_data_vtbl_t HTMLAttributeCollection_dispex_vtbl = { .invoke = HTMLAttributeCollection_invoke, };
-const tid_t NamedNodeMap_iface_tids[] = { - IHTMLAttributeCollection_tid, - IHTMLAttributeCollection2_tid, - IHTMLAttributeCollection3_tid, - 0 -}; +static void NamedNodeMap_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode >= COMPAT_MODE_IE9) { + dispex_info_add_interface(info, IHTMLAttributeCollection4_tid, NULL); + }else if(mode == COMPAT_MODE_IE8) { + dispex_info_add_interface(info, IHTMLAttributeCollection3_tid, NULL); + }else { + dispex_info_add_interface(info, IHTMLAttributeCollection_tid, NULL); + dispex_info_add_interface(info, IHTMLAttributeCollection2_tid, NULL); + } +}
dispex_static_data_t NamedNodeMap_dispex = { .id = OBJID_NamedNodeMap, .vtbl = &HTMLAttributeCollection_dispex_vtbl, .disp_tid = DispHTMLAttributeCollection_tid, - .iface_tids = NamedNodeMap_iface_tids, + .init_info = NamedNodeMap_init_dispex_info, };
HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index e231c4c090c..fe272f0f08a 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -3923,6 +3923,7 @@ sync_test("prototype props", function() { test_own_props(constr.prototype, name, props, todos, flaky); }
+ check(Attr, [ "expando", "name", "ownerElement", "specified", "value" ]); check(CharacterData, [ "appendData", "data", "deleteData", "insertData", "length", "replaceData", "substringData" ]); check(Comment, [ "text" ]); check(CSSStyleDeclaration, [ @@ -4222,6 +4223,8 @@ sync_test("prototype props", function() { "posHeight", "posLeft", "posRight", "posTop", "posWidth", "textDecorationBlink", "textDecorationLineThrough", "textDecorationNone", "textDecorationOverline", "textDecorationUnderline" ]); + check(NamedNodeMap, [ "getNamedItem", "getNamedItemNS", "item", "length", "removeNamedItem", "removeNamedItemNS", + "setNamedItem", "setNamedItemNS" ]); check(Node, [ "ATTRIBUTE_NODE", "CDATA_SECTION_NODE", "COMMENT_NODE", "DOCUMENT_FRAGMENT_NODE", "DOCUMENT_NODE", "DOCUMENT_POSITION_CONTAINED_BY", "DOCUMENT_POSITION_CONTAINS", "DOCUMENT_POSITION_DISCONNECTED", diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index 1ca70c5726d..bd7af124167 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -1044,12 +1044,63 @@ sync_test("importNode", function() { sync_test("attributeNode", function() { document.body.innerHTML = '<div id="test" attr="wine"></div>'; var elem = document.getElementById("test"); - var attr = elem.attributes[0]; + var attr, clone, prev, ret;
+ attr = elem.attributes["id"]; ok(attr.ownerDocument === document, "ownerDocument = " + attr.ownerDocument); ok(attr.ownerElement === elem, "ownerElement = " + attr.ownerElement); + ok(attr.specified === true, "attr.specified = " + attr.expando); + ok(attr.expando === false, "attr.expando = " + attr.expando); + ok(attr.value === "test", "attr.value = " + attr.value); + ok(attr.name === "id", "attr.name = " + attr.name); + + clone = attr.cloneNode(true); + ok(clone.ownerDocument === document, "ownerDocument = " + clone.ownerDocument); + ok(clone.ownerElement === null, "ownerElement = " + clone.ownerElement); + ok(clone.specified === true, "clone.specified = " + clone.expando); + ok(clone.expando === false, "clone.expando = " + clone.expando); + ok(clone.value === "test", "clone.value = " + clone.value); + ok(clone.name === "id", "clone.name = " + clone.name); + + ok(elem.getAttributeNode("id") === attr, 'elem.getAttributeNode("id") = ' + elem.getAttributeNode("id")); + ok(elem.attributes.getNamedItem("id") === attr, "unexpected id named item"); + ok(elem.getAttributeNode("nonexistent") === null, + 'elem.getAttributeNode("nonexistent") = ' + elem.getAttributeNode("nonexistent")); + ok(elem.attributes.getNamedItem("nonexistent") === null, + 'elem.attributes.getNamedItem("nonexistent") = ' + elem.attributes.getNamedItem("nonexistent")); + ok(elem.attributes.length === 2, "elem.attributes.length = " + elem.attributes.length); + ok(elem.attributes[0] == attr || elem.attributes[1] === attr, "attr not found in elem.attributes"); + ok(elem.attributes.item(0) == attr || elem.attributes.item(1) === attr, "attr not found in items"); + ok(elem.attributes.item(2) == null, "item(2) = " + elem.attributes.item(2)); + prev = attr;
attr = document.createAttribute("id"); ok(attr.ownerDocument === document, "detached attr ownerDocument = " + attr.ownerDocument); ok(attr.ownerElement === null, "detached attr ownerElement = " + attr.ownerElement); + ok(attr.specified === true, "attr.specified = " + attr.specified); + ok(attr.expando === false, "attr.expando = " + attr.expando); + ok(attr.value === "", "attr.value = " + attr.value); + ok(attr.name === "id", "attr.name = " + attr.name); + attr.value = "new"; + + ret = elem.setAttributeNode(attr); + ok(ret === prev, "ret != prev"); + ok(elem.getAttributeNode("id") === attr, "unexpected id attr"); + ok(elem.getAttribute("id") === "new", "unexpected id attr value " + elem.getAttribute("id")); + + attr = document.createAttribute("test"); + attr.value = "test"; + ret = elem.setAttributeNode(attr); + ok(ret === null, "ret != null"); + ok(elem.attributes.length === 3, "elem.attributes.length = " + elem.attributes.length); + ok(elem.getAttributeNode("test") === attr, "unexpected test attr"); + ok(elem.attributes.getNamedItem("test") === attr, "unexpected test named item"); + ok(elem.getAttribute("test") === "test", "unexpected test attr value " + elem.getAttribute("id")); + ok(elem.attributes.item(3) == null, "item(3) = " + elem.attributes.item(3)); + + attr = elem.getAttributeNode("style"); + ok(attr === null, "found style attribute node"); + attr = elem.attributes.getNamedItem("style"); + ok(attr === null, "found style attribute named item"); + ok(!("style" in elem.attributes), "found style in attribute collection " + elem.attributes["style"]); });