diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f10fff0b9b..6d91355cbf 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -8,6 +8,10 @@
+
+ DOMTokenList.toggle() now honors the optional force argument: a true value only adds the token
+ and a false value only removes it, matching the DOM standard.
+
Content-Security-Policy: XMLHttpRequest supports the connect-src directive (with default-src as fallback);
the request url and all redirect targets are checked, blocked requests fail with a network error.
diff --git a/src/main/java/org/htmlunit/javascript/host/dom/DOMTokenList.java b/src/main/java/org/htmlunit/javascript/host/dom/DOMTokenList.java
index 9756656fba..217efa5a4e 100644
--- a/src/main/java/org/htmlunit/javascript/host/dom/DOMTokenList.java
+++ b/src/main/java/org/htmlunit/javascript/host/dom/DOMTokenList.java
@@ -277,10 +277,12 @@ public boolean replace(final String oldToken, final String newToken) {
/**
* Toggles the token, adding or removing it.
* @param token the token to add or remove
+ * @param force if {@code true}, only adds the token; if {@code false}, only removes it;
+ * if not specified, the token is toggled
* @return whether the string now contains the token or not
*/
@JsxFunction
- public boolean toggle(final String token) {
+ public boolean toggle(final String token, final Object force) {
if (org.htmlunit.util.StringUtils.isEmptyOrNull(token)) {
throw JavaScriptEngine.asJavaScriptException(
getWindow(),
@@ -295,15 +297,18 @@ public boolean toggle(final String token) {
}
final List parts = split(getValue());
- if (parts.contains(token)) {
+ final boolean present = parts.contains(token);
+ final boolean add = JavaScriptEngine.isUndefined(force) ? !present : JavaScriptEngine.toBoolean(force);
+
+ if (add && !present) {
+ parts.add(token);
+ updateAttribute(String.join(" ", parts));
+ }
+ else if (!add && present) {
parts.remove(token);
updateAttribute(String.join(" ", parts));
- return false;
}
-
- parts.add(token);
- updateAttribute(String.join(" ", parts));
- return true;
+ return add;
}
/**
diff --git a/src/test/java/org/htmlunit/javascript/host/dom/DOMTokenListTest.java b/src/test/java/org/htmlunit/javascript/host/dom/DOMTokenListTest.java
index b4a065097d..d67c4ba3ab 100644
--- a/src/test/java/org/htmlunit/javascript/host/dom/DOMTokenListTest.java
+++ b/src/test/java/org/htmlunit/javascript/host/dom/DOMTokenListTest.java
@@ -1760,6 +1760,85 @@ public void toggleNotDefined() throws Exception {
toggle(null, "a");
}
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts({"a", "1", "true", "2", "a\\sb",
+ "",
+ "class\\schanged\\sold:\\sa"})
+ public void toggleForceTrueAdds() throws Exception {
+ toggle("a", "b", "true");
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts({"a\\sb", "2", "true", "2", "a\\sb",
+ ""})
+ public void toggleForceTrueKeeps() throws Exception {
+ toggle("a b", "b", "true");
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts({"a\\sb", "2", "false", "1", "a",
+ "",
+ "class\\schanged\\sold:\\sa\\sb"})
+ public void toggleForceFalseRemoves() throws Exception {
+ toggle("a b", "b", "false");
+ }
+
+ /**
+ * @throws Exception if the test fails
+ */
+ @Test
+ @Alerts({"a", "1", "false", "1", "a",
+ ""})
+ public void toggleForceFalseKeeps() throws Exception {
+ toggle("a", "b", "false");
+ }
+
+ private void toggle(final String in, final String token, final String force) throws Exception {
+ final String html = DOCTYPE_HTML
+ + "\n"
+ + "\n"
+ + "\n"
+ + " \n"
+ + "";
+
+ loadPageVerifyTitle2(html);
+ }
+
private void toggle(final String in, final String token) throws Exception {
String html = DOCTYPE_HTML
+ "\n"