Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/htmlelem.c | 127 +++++++++++++++++++++++++++ dlls/mshtml/mshtml_private_iface.idl | 2 + dlls/mshtml/tests/dom.js | 50 +++++++++++ 3 files changed, 179 insertions(+)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 5bb3f1eaf15..b5b0daa2539 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6490,6 +6490,132 @@ static HRESULT WINAPI token_list_Invoke(IWineDOMTokenList *iface, DISPID dispIdM pDispParams, pVarResult, pExcepInfo, puArgErr); }
+static const WCHAR *find_token(const WCHAR *list, const WCHAR *token, unsigned int token_len) +{ + const WCHAR *ptr, *next; + + if (!list || !token) + return NULL; + + ptr = list; + while (*ptr) + { + while (iswspace(*ptr)) + ++ptr; + if (!*ptr) + break; + next = ptr + 1; + while (*next && !iswspace(*next)) + ++next; + + if (next - ptr == token_len && !wcsncmp(ptr, token, token_len)) + return ptr; + ptr = next; + } + return NULL; +} + +static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_array) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + unsigned int i, len, old_len, new_len; + WCHAR *token, *old, *new; + VARIANT *var, tmp; + HRESULT hr; + + TRACE("iface %p, token_array %p.\n", iface, token_array); + + hr = SafeArrayAccessData(token_array, (void**)&var); + if(FAILED(hr)) { + WARN("SafeArrayAccessData failed: %08x\n", hr); + return hr; + } + + if (!token_array->rgsabound[0].cElements) + { + FIXME("No arguments given."); + SafeArrayUnaccessData(token_array); + return E_INVALIDARG; + } + + if(V_VT(var) != VT_BSTR) + { + hr = VariantChangeTypeEx(&tmp, var, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR); + if(FAILED(hr)) + { + WARN("Could not convert %s to string\n", debugstr_variant(var)); + SafeArrayUnaccessData(token_array); + return hr; + } + token = V_BSTR(&tmp); + } + else + { + token = V_BSTR(var); + } + + if (token_array->rgsabound[0].cElements > 1) + WARN("%u tokens given, using first one only.\n", token_array->rgsabound[0].cElements); + + len = lstrlenW(token); + if (!len) + { + WARN("Empty token.\n"); + hr = E_INVALIDARG; + goto done; + } + + for (i = 0; i < len; ++i) + if (iswspace(token[i])) + { + WARN("Token has spaces.\n"); + hr = E_INVALIDARG; + goto done; + } + + if (FAILED(hr = IHTMLElement_get_className(token_list->element, &old))) + goto done; + + TRACE("old %s.\n", debugstr_w(old)); + + if (find_token(old, token, len)) + { + SysFreeString(old); + hr = S_OK; + goto done; + } + + old_len = old ? lstrlenW(old) : 0; + new_len = old_len + len + !!old_len; + + if (!(new = heap_alloc(sizeof(*new) * (new_len + 1)))) + { + ERR("No memory.\n"); + SysFreeString(old); + hr = E_OUTOFMEMORY; + goto done; + } + + memcpy(new, old, sizeof(*new) * old_len); + if (old_len) + new[old_len++]= L' '; + memcpy(new + old_len, token, sizeof(*new) * len); + new[old_len + len] = 0; + + SysFreeString(old); + + TRACE("new %s.\n", debugstr_w(new)); + + hr = IHTMLElement_put_className(token_list->element, new); + heap_free(new); +done: + SafeArrayUnaccessData(token_array); + if(V_VT(var) != VT_BSTR) + VariantClear(&tmp); + + return hr; +} + static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_QueryInterface, token_list_AddRef, @@ -6498,6 +6624,7 @@ static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_GetTypeInfo, token_list_GetIDsOfNames, token_list_Invoke, + token_list_add, };
static const tid_t token_list_iface_tids[] = { diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 1764b0a8c9d..b50d2f9502b 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -111,6 +111,8 @@ interface IWineHTMLElementPrivate : IDispatch ] interface IWineDOMTokenList : IDispatch { + [vararg, id(1)] + HRESULT add([in] SAFEARRAY(VARIANT) token); }
} /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index f54cb0f7088..ae6d49da26c 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -512,4 +512,54 @@ sync_test("hasAttribute", function() { sync_test("classList", function() { var elem = document.createElement("div"); var classList = elem.classList; + + classList.add("a"); + ok(elem.className === "a", "Expected className 'a', got " + elem.className); + + classList.add("b"); + ok(elem.className === "a b", "Expected className 'a b', got " + elem.className); + + classList.add("c", "d"); + ok(elem.className === "a b c", "Expected className 'a b c', got " + elem.className); + + classList.add(4); + ok(elem.className === "a b c 4", "Expected className 'a b c 4', got " + elem.className); + + classList.add("c", "d"); + ok(elem.className === "a b c 4", "(2) Expected className 'a b c 4', got " + elem.className); + + var exception = false + + try + { + classList.add(); + } + catch(e) + { + exception = true; + } + ok(exception && elem.className === "a b c 4", "Expected exception, className 'a b c 4', got exception " + + exception + ", className" + elem.className); + + exception = false + try + { + classList.add(""); + } + catch(e) + { + exception = true; + } + ok(exception, "Expected exception for classList.add("")"); + + exception = false + try + { + classList.add("e f"); + } + catch(e) + { + exception = true; + } + ok(exception, "Expected exception for classList.add("e f")"); });