From: <rb...@us...> - 2013-03-24 15:07:13
|
Revision: 8196 http://sourceforge.net/p/htmlunit/code/8196 Author: rbri Date: 2013-03-24 15:07:09 +0000 (Sun, 24 Mar 2013) Log Message: ----------- first step fixing DOMTokenList Modified Paths: -------------- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenList.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenListTest.java Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenList.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenList.java 2013-03-23 17:45:02 UTC (rev 8195) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenList.java 2013-03-24 15:07:09 UTC (rev 8196) @@ -14,11 +14,15 @@ */ package com.gargoylesoftware.htmlunit.javascript.host.dom; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import net.sourceforge.htmlunit.corejs.javascript.Context; + +import org.apache.commons.lang3.StringUtils; + import com.gargoylesoftware.htmlunit.html.DomAttr; +import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable; import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass; import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction; @@ -30,10 +34,12 @@ * * @version $Revision$ * @author Ahmed Ashour + * @author Ronald Brill */ @JsxClass public final class DOMTokenList extends SimpleScriptable { + private static final String WHITESPACE_CHARS = " \t\r\n\u000C"; private String attributeName_; /** @@ -61,7 +67,7 @@ @JsxGetter public int getLength() { final String value = getDefaultValue(null); - return value.split(" ").length; + return StringUtils.split(value, WHITESPACE_CHARS).length; } /** @@ -84,8 +90,12 @@ @JsxFunction public void add(final String token) { if (!contains(token)) { - final DomAttr attr = (DomAttr) getDomNodeOrDie().getAttributes().getNamedItem(attributeName_); - attr.setValue(attr.getValue() + ' ' + token); + String value = getDefaultValue(null); + if (value.length() != 0 && !isWhitespache(value.charAt(value.length() - 1))) { + value = value + " "; + } + value = value + token; + updateAttribute(value); } } @@ -95,20 +105,36 @@ */ @JsxFunction public void remove(final String token) { - if (contains(token)) { - final DomAttr attr = (DomAttr) getDomNodeOrDie().getAttributes().getNamedItem(attributeName_); - if (attr != null) { - final List<String> values = new ArrayList<String>(Arrays.asList(attr.getValue().split(" "))); - values.remove(token); - final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < values.size(); i++) { - builder.append(values.get(i)); - if (i < values.size() - 1) { - builder.append(' '); - } - } - attr.setValue(builder.toString()); + if (StringUtils.isEmpty(token)) { + throw Context.reportRuntimeError("Empty imput not allowed"); + } + if (StringUtils.containsAny(token, WHITESPACE_CHARS)) { + throw Context.reportRuntimeError("Empty imput not allowed"); + } + String value = getDefaultValue(null); + int pos = position(value, token); + while (pos != -1) { + int from = pos; + int to = pos + token.length(); + + while (from > 0 && isWhitespache(value.charAt(from - 1))) { + from = from - 1; } + while (to < value.length() - 1 && isWhitespache(value.charAt(to))) { + to = to + 1; + } + + final StringBuilder result = new StringBuilder(); + if (from > 0) { + result.append(value.substring(0, from)); + result.append(" "); + } + result.append(value.substring(to)); + + value = result.toString(); + updateAttribute(value); + + pos = position(value, token); } } @@ -134,12 +160,13 @@ */ @JsxFunction public boolean contains(final String token) { - final DomAttr attr = (DomAttr) getDomNodeOrDie().getAttributes().getNamedItem(attributeName_); - if (attr != null) { - final List<String> values = Arrays.asList(attr.getValue().split(" ")); - return values.contains(token); + if (StringUtils.isEmpty(token)) { + throw Context.reportRuntimeError("Empty imput not allowed"); } - return false; + if (StringUtils.containsAny(token, WHITESPACE_CHARS)) { + throw Context.reportRuntimeError("Empty imput not allowed"); + } + return position(getDefaultValue(null), token) > -1; } /** @@ -149,13 +176,47 @@ */ @JsxFunction public Object item(final int index) { - final DomAttr attr = (DomAttr) getDomNodeOrDie().getAttributes().getNamedItem(attributeName_); - if (attr != null) { - final List<String> values = Arrays.asList(attr.getValue().split(" ")); - if (index < values.size()) { - return values.get(index); - } + if (index < 0) { + return null; } + final String value = getDefaultValue(null); + final List<String> values = Arrays.asList(StringUtils.split(value, WHITESPACE_CHARS)); + if (index < values.size()) { + return values.get(index); + } return null; } + + private void updateAttribute(final String value) { + final HtmlElement domNode = (HtmlElement) getDomNodeOrDie(); + DomAttr attr = (DomAttr) domNode.getAttributes().getNamedItem(attributeName_); + if (null == attr) { + attr = domNode.getPage().createAttribute(attributeName_); + domNode.setAttributeNode(attr); + } + attr.setValue(value); + } + + private int position(final String value, final String token) { + final int pos = value.indexOf(token); + if (pos < 0) { + return -1; + } + + // whitespace before + if (pos != 0 && !isWhitespache(value.charAt(pos - 1))) { + return -1; + } + + // whitespace after + final int end = pos + token.length(); + if (end != value.length() && !isWhitespache(value.charAt(end))) { + return -1; + } + return pos; + } + + private boolean isWhitespache(final int ch) { + return WHITESPACE_CHARS.indexOf(ch) > -1; + } } Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenListTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenListTest.java 2013-03-23 17:45:02 UTC (rev 8195) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/dom/DOMTokenListTest.java 2013-03-24 15:07:09 UTC (rev 8196) @@ -19,8 +19,6 @@ import com.gargoylesoftware.htmlunit.BrowserRunner; import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts; -import com.gargoylesoftware.htmlunit.BrowserRunner.Browser; -import com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented; import com.gargoylesoftware.htmlunit.WebDriverTestCase; /** @@ -64,7 +62,6 @@ */ @Test @Alerts(FF = { "0", "null", "false", "# removed", "" }) - @NotYetImplemented(Browser.FF) public void noAttribute() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -89,7 +86,6 @@ */ @Test @Alerts(FF = { "0", "undefined", "1", "#" }) - @NotYetImplemented(Browser.FF) public void noAttributeAdd() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -113,7 +109,6 @@ */ @Test @Alerts(FF = { "0", "true", "1", "#" }) - @NotYetImplemented(Browser.FF) public void noAttributeToggle() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -137,7 +132,6 @@ */ @Test @Alerts(FF = { "3", "0", "3", "8" }) - @NotYetImplemented(Browser.FF) public void length() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -168,7 +162,6 @@ */ @Test @Alerts(FF = { "a", "b", "c", "d", "\u000B", "e", "f", "g", "null", "null", "null" }) - @NotYetImplemented(Browser.FF) public void item() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -194,8 +187,7 @@ * @throws Exception if the test fails */ @Test - @Alerts(FF = { "exception", "true", "false" }) - @NotYetImplemented(Browser.FF) + @Alerts(FF = { "exception", "exception", "true", "false" }) public void contains() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -205,6 +197,9 @@ + " try {\n" + " list.contains('ab\te');\n" + " } catch(e) { alert('exception');}\n" + + " try {\n" + + " list.contains('');\n" + + " } catch(e) { alert('exception');}\n" + " alert(list.contains('c'));\n" + " alert(list.contains('xyz'));\n" + " }\n" @@ -220,8 +215,34 @@ * @throws Exception if the test fails */ @Test + @Alerts(FF = { "true", "true", "true", "true" }) + public void containsBorderCheck() throws Exception { + final String html + = "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " var list = document.getElementById('d1').classList;\n" + + " if (list) {\n" + + " alert(list.contains('a'));\n" + + " alert(list.contains('d'));\n" + + + " list = document.getElementById('d2').classList;\n" + + " alert(list.contains('a'));\n" + + " alert(list.contains('d'));\n" + + " }\n" + + "}\n" + + "</script></head><body onload='test()'>\n" + + " <div id='d1' class='a \t c \n d'></div>\n" + + " <div id='d2' class=' a \t c \n d\r'></div>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if the test fails + */ + @Test @Alerts(FF = { "exception", "exception", "3", "4", "true" }) - @NotYetImplemented(Browser.FF) public void add() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -252,7 +273,6 @@ */ @Test @Alerts(FF = { "1", "2", "a \t #" }) - @NotYetImplemented(Browser.FF) public void addWhitespaceAtEnd() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -301,7 +321,6 @@ */ @Test @Alerts(FF = { "exception", "exception", "3", "3", "2", "false" }) - @NotYetImplemented(Browser.FF) public void remove() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -334,7 +353,6 @@ */ @Test @Alerts(FF = { "3", "1", "false" }) - @NotYetImplemented(Browser.FF) public void removeDuplicated() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -359,7 +377,6 @@ */ @Test @Alerts(FF = { "a \t c \n d e", "4", "3", "a d e" }) - @NotYetImplemented(Browser.FF) public void removeWhitespace() throws Exception { final String html = "<html><head><title>First</title><script>\n" @@ -386,7 +403,6 @@ */ @Test @Alerts(FF = { "exception", "exception", "2", "true", "false", "1", "false", "true", "2", "true" }) - @NotYetImplemented(Browser.FF) public void toggle() throws Exception { final String html = "<html><head><title>First</title><script>\n" |