Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlelem.c | 98 ++++++++++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 63 ++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index de69e2f..503a287 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -355,6 +355,98 @@ static inline HTMLElement *impl_from_IHTMLElement(IHTMLElement *iface) return CONTAINING_RECORD(iface, HTMLElement, IHTMLElement_iface); }
+static HRESULT create_nselem_parse(HTMLDocumentNode *doc, const WCHAR *tag, nsIDOMElement **ret) +{ + WCHAR *p = wcschr(tag + 1, '>'); + nsIDOMHTMLCollection *nscol; + UINT32 i, name_len, length; + nsIDOMHTMLElement *nshtml; + HRESULT hres = E_FAIL; + nsresult nsres; + nsAString str; + + if(!p || p[1] || wcschr(tag + 1, '<')) + return E_FAIL; + if(!doc->nsdoc) { + WARN("NULL nsdoc\n"); + return E_UNEXPECTED; + } + + /* Ignore the > or /> end token */ + length = p - tag - (p[-1] == '/'); + + /* Get the tag name using HTML whitespace rules */ + name_len = length - 1; + for(i = 1; i < length; i++) { + if((tag[i] >= 0x09 && tag[i] <= 0x0d) || tag[i] == ' ') { + name_len = i - 1; + break; + } + } + if(!name_len) + return E_FAIL; + + /* Create a temporary html element and parse it there */ + nsAString_InitDepend(&str, L"HTML"); + nsres = nsIDOMHTMLDocument_CreateElement(doc->nsdoc, &str, (nsIDOMElement**)&nshtml); + nsAString_Finish(&str); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + + if(name_len == 4 && !wcsnicmp(tag + 1, L"HTML", 4)) { + FIXME("Returning <html> element with no attributes\n"); + *ret = (nsIDOMElement*)nshtml; + return S_OK; + } + + nsAString_InitDepend(&str, tag); + nsres = nsIDOMHTMLElement_SetInnerHTML(nshtml, &str); + nsAString_Finish(&str); + if(NS_FAILED(nsres)) { + hres = map_nsresult(nsres); + goto fail; + } + + /* Get the element and remove it from the temporary */ + if(!(p = heap_alloc((name_len + 1) * sizeof(WCHAR)))) + hres = E_OUTOFMEMORY; + else { + memcpy(p, tag + 1, name_len * sizeof(WCHAR)); + p[name_len] = '\0'; + nsAString_InitDepend(&str, p); + nsres = nsIDOMHTMLElement_GetElementsByTagName(nshtml, &str, &nscol); + nsAString_Finish(&str); + heap_free(p); + if(NS_FAILED(nsres)) + goto fail; + + length = 0; + nsres = nsIDOMHTMLCollection_GetLength(nscol, &length); + if(NS_SUCCEEDED(nsres) && length == 1) { + nsIDOMNode *nsnode, *nsparent, *tmp; + + nsIDOMHTMLCollection_Item(nscol, 0, &nsnode); + nsres = nsIDOMNode_GetParentNode(nsnode, &nsparent); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIDOMNode_RemoveChild(nsparent, nsnode, &tmp); + nsIDOMNode_Release(nsparent); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIDOMNode_QueryInterface(tmp, &IID_nsIDOMElement, (void**)ret); + nsIDOMNode_Release(tmp); + if(NS_SUCCEEDED(nsres)) + hres = S_OK; + } + } + nsIDOMNode_Release(nsnode); + } + nsIDOMHTMLCollection_Release(nscol); + } + +fail: + nsIDOMHTMLElement_Release(nshtml); + return hres; +} + HRESULT create_nselem(HTMLDocumentNode *doc, const WCHAR *tag, nsIDOMElement **ret) { nsAString tag_str; @@ -385,7 +477,11 @@ HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **re if(!doc->nsdoc) doc = doc->node.doc;
- hres = create_nselem(doc, tag, &nselem); + /* IE8 and below allow creating elements with attributes, such as <div class="a"> */ + if(tag[0] == '<' && dispex_compat_mode(&doc->node.event_target.dispex) <= COMPAT_MODE_IE8) + hres = create_nselem_parse(doc, tag, &nselem); + else + hres = create_nselem(doc, tag, &nselem); if(FAILED(hres)) return hres;
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 02a5f5f..69f4796 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -488,6 +488,69 @@ sync_test("style_props", function() { } });
+sync_test("createElement_inline_attr", function() { + var v = document.documentMode, e, s; + + if(v < 9) { + s = document.createElement("<div>").tagName; + ok(s === "DIV", "<div>.tagName returned " + s); + s = document.createElement("<div >").tagName; + ok(s === "DIV", "<div >.tagName returned " + s); + s = document.createElement("<div/>").tagName; + ok(s === "DIV", "<div/>.tagName returned " + s); + e = 0; + try { + document.createElement("<div"); + }catch(ex) { + e = ex.number; + } + ok(e === 0x4005 - 0x80000000, "<div e = " + e); + e = 0; + try { + document.createElement("<div test=1"); + }catch(ex) { + e = ex.number; + } + ok(e === 0x4005 - 0x80000000, "<div test=1 e = " + e); + + var tags = [ "div", "head", "body", "title" ]; + + for(var i = 0; i < tags.length; i++) { + e = document.createElement("<" + tags[i] + " test='a"' abcd=""b"">"); + ok(e.tagName === tags[i].toUpperCase(), "<" + tags[i] + " test="a" abcd="b">.tagName returned " + e.tagName); + todo_wine_if(v == 8). + ok(e.test === "a"", "<" + tags[i] + " test='a"' abcd=""b"">.test returned " + e.test); + todo_wine_if(v == 8). + ok(e.abcd === ""b"", "<" + tags[i] + " test='a"' abcd=""b"">.abcd returned " + e.abcd); + } + }else { + s = ""; + e = 0; + try { + document.createElement("<div>"); + }catch(ex) { + s = ex.toString(); + e = ex.number; + } + todo_wine. + ok(e === undefined, "<div> e = " + e); + todo_wine. + ok(s === "InvalidCharacterError", "<div> s = " + s); + s = ""; + e = 0; + try { + document.createElement("<div test="a">"); + }catch(ex) { + s = ex.toString(); + e = ex.number; + } + todo_wine. + ok(e === undefined, "<div test="a"> e = " + e); + todo_wine. + ok(s === "InvalidCharacterError", "<div test="a"> s = " + s); + } +}); + sync_test("JS objs", function() { var g = window;