Signed-off-by: Paul Gofman pgofman@codeweavers.com --- v2: - define _remove argument as BSTR (and remove multiple arguments tests).
dlls/mshtml/htmlelem.c | 57 +++++++++++++++++++++++----- dlls/mshtml/mshtml_private_iface.idl | 2 + dlls/mshtml/tests/dom.js | 43 +++++++++++++++++++++ 3 files changed, 93 insertions(+), 9 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index fd9ef686381..9ad538d2b00 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6515,14 +6515,15 @@ static const WCHAR *find_token(const WCHAR *list, const WCHAR *token, unsigned i return NULL; }
-static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, BSTR token) +static HRESULT WINAPI token_list_add_remove(IWineDOMTokenList *iface, BSTR token, BOOL remove) { struct token_list *token_list = impl_from_IWineDOMTokenList(iface); unsigned int i, len, old_len, new_len; + const WCHAR *old_pos; BSTR new, old; HRESULT hr;
- TRACE("iface %p, token %s.\n", iface, debugstr_w(token)); + TRACE("iface %p, token %s, remove %#x.\n", iface, debugstr_w(token), remove);
len = token ? lstrlenW(token) : 0; if (!len) @@ -6543,14 +6544,33 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, BSTR token)
TRACE("old %s.\n", debugstr_w(old));
- if (find_token(old, token, len)) + if (((old_pos = find_token(old, token, len)) && !remove) + || (!old_pos && remove)) { SysFreeString(old); return S_OK; }
old_len = old ? lstrlenW(old) : 0; - new_len = old_len + len + !!old_len; + if (remove) + { + while (old_pos != old && iswspace(old_pos[-1])) + { + --old_pos; + ++len; + } + while (iswspace(old_pos[len])) + ++len; + + if (old_pos != old && old_pos[len]) + --len; + + new_len = old_len - len; + } + else + { + new_len = old_len + len + !!old_len; + }
if (!(new = SysAllocStringLen(NULL, new_len))) { @@ -6559,11 +6579,19 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, BSTR token) return E_OUTOFMEMORY; }
- 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; + if (remove) + { + memcpy(new, old, sizeof(*new) * (old_pos - old)); + memcpy(new + (old_pos - old), old_pos + len, sizeof(*new) * (old_len - (old_pos - old) - len + 1)); + } + else + { + 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);
@@ -6574,6 +6602,16 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, BSTR token) return hr; }
+static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, BSTR token) +{ + return token_list_add_remove(iface, token, FALSE); +} + +static HRESULT WINAPI token_list_remove(IWineDOMTokenList *iface, BSTR token) +{ + return token_list_add_remove(iface, token, TRUE); +} + static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_QueryInterface, token_list_AddRef, @@ -6583,6 +6621,7 @@ static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_GetIDsOfNames, token_list_Invoke, token_list_add, + token_list_remove, };
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 8a2c9463dca..491f4afb0b6 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -113,6 +113,8 @@ interface IWineDOMTokenList : IDispatch { [id(1)] HRESULT add([in] BSTR token); + [id(2)] + HRESULT remove([in] BSTR token); }
} /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index ccbb3d8b69d..0085b40efed 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -562,4 +562,47 @@ sync_test("classList", function() { exception = true; } ok(exception, "Expected exception for classList.add("e f")"); + + classList.remove("e"); + ok(elem.className === "a b c 4", "remove: expected className 'a b c 4', got " + elem.className); + + exception = false + try + { + classList.remove("e f"); + } + catch(e) + { + exception = true; + } + ok(exception, "remove: expected exception for classList.remove("e f")"); + + exception = false + try + { + classList.remove(""); + } + catch(e) + { + exception = true; + } + ok(exception, "remove: expected exception for classList.remove("")"); + + classList.remove("d"); + ok(elem.className === "a b c 4", "remove: expected className 'a b c 4', got " + elem.className); + + classList.remove("c"); + ok(elem.className === "a b 4", "remove: expected className 'a b 4', got " + elem.className); + + classList.remove(4); + ok(elem.className === "a b", "remove: expected className 'a b', got " + elem.className); + + classList.remove('a'); + ok(elem.className === "b", "remove: expected className 'b', got " + elem.className); + + classList.remove("a"); + ok(elem.className === "b", "remove (2): expected className 'b', got " + elem.className); + + classList.remove("b"); + ok(elem.className === "", "remove: expected className '', got " + elem.className); });