From: <asa...@us...> - 2012-12-29 09:03:26
|
Revision: 7920 http://sourceforge.net/p/htmlunit/code/7920 Author: asashour Date: 2012-12-29 09:03:23 +0000 (Sat, 29 Dec 2012) Log Message: ----------- More CSS3 selectors Modified Paths: -------------- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSSelectorTest.java Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java 2012-12-29 07:44:37 UTC (rev 7919) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java 2012-12-29 09:03:23 UTC (rev 7920) @@ -131,7 +131,9 @@ private String uri_; private static final Collection<String> PSEUDO_CLASSES = Arrays.asList("link", "visited", "hover", "active", - "focus", "target", "lang", "disabled", "checked", "indeterminated", "root", "nth-child()"); + "focus", "target", "lang", "disabled", "enabled", "checked", "indeterminated", "root", + "nth-child()", "nth-last-child()", "nth-of-type()", "nth-last-of-type()", + "first-child", "last-child", "first-of-type", "last-of-type", "only-child", "only-of-type", "empty"); /** * Creates a new empty stylesheet. @@ -546,6 +548,40 @@ return (element instanceof HtmlCheckBoxInput && ((HtmlCheckBoxInput) element).isChecked()) || (element instanceof HtmlRadioButtonInput && ((HtmlRadioButtonInput) element).isChecked()); } + else if ("first-child".equals(value)) { + for (DomNode n = element.getPreviousSibling(); n != null; n = n.getPreviousSibling()) { + if (n instanceof DomElement) { + return false; + } + } + return true; + } + else if ("last-child".equals(value)) { + for (DomNode n = element.getNextSibling(); n != null; n = n.getNextSibling()) { + if (n instanceof DomElement) { + return false; + } + } + return true; + } + else if ("first-of-type".equals(value)) { + final String type = element.getNodeName(); + for (DomNode n = element.getPreviousSibling(); n != null; n = n.getPreviousSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + return false; + } + } + return true; + } + else if ("last-of-type".equals(value)) { + final String type = element.getNodeName(); + for (DomNode n = element.getNextSibling(); n != null; n = n.getNextSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + return false; + } + } + return true; + } else if (value.startsWith("nth-child(")) { final String nth = value.substring(value.indexOf('(') + 1, value.length() - 1); int index = 0; @@ -556,6 +592,65 @@ } return getNth(nth, index); } + else if (value.startsWith("nth-last-child(")) { + final String nth = value.substring(value.indexOf('(') + 1, value.length() - 1); + int index = 0; + for (DomNode n = element; n != null; n = n.getNextSibling()) { + if (n instanceof DomElement) { + index++; + } + } + return getNth(nth, index); + } + else if (value.startsWith("nth-of-type(")) { + final String type = element.getNodeName(); + final String nth = value.substring(value.indexOf('(') + 1, value.length() - 1); + int index = 0; + for (DomNode n = element; n != null; n = n.getPreviousSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + index++; + } + } + return getNth(nth, index); + } + else if (value.startsWith("nth-last-of-type(")) { + final String type = element.getNodeName(); + final String nth = value.substring(value.indexOf('(') + 1, value.length() - 1); + int index = 0; + for (DomNode n = element; n != null; n = n.getNextSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + index++; + } + } + return getNth(nth, index); + } + else if ("only-child".equals(value)) { + for (DomNode n = element.getPreviousSibling(); n != null; n = n.getPreviousSibling()) { + if (n instanceof DomElement) { + return false; + } + } + for (DomNode n = element.getNextSibling(); n != null; n = n.getNextSibling()) { + if (n instanceof DomElement) { + return false; + } + } + return true; + } + else if ("only-of-type".equals(value)) { + final String type = element.getNodeName(); + for (DomNode n = element.getPreviousSibling(); n != null; n = n.getPreviousSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + return false; + } + } + for (DomNode n = element.getNextSibling(); n != null; n = n.getNextSibling()) { + if (n instanceof DomElement && n.getNodeName().equals(type)) { + return false; + } + } + return true; + } return false; } Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSSelectorTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSSelectorTest.java 2012-12-29 07:44:37 UTC (rev 7919) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSSelectorTest.java 2012-12-29 09:03:23 UTC (rev 7920) @@ -281,4 +281,246 @@ loadPageWithAlerts2(html); } + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "li3", IE8 = { }) + @NotYetImplemented(IE8) + public void nth_last_child() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('li:nth-last-child(1)')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<ul>\n" + + " <li id='li1'></li>\n" + + " <li id='li2'></li>\n" + + " <li id='li3'></li>\n" + + "</ul>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id3", IE8 = { }) + @NotYetImplemented(IE8) + public void nth_of_type() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('p:nth-of-type(2)')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <h1 id='id11'></h1>\n" + + " <p id='id2'></p>\n" + + " <p id='id3'></p>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id3", IE8 = { }) + @NotYetImplemented(IE8) + public void nth_last_of_type() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('p:nth-last-of-type(1)')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <h1 id='id1'></h1>\n" + + " <p id='id2'></p>\n" + + " <p id='id3'></p>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "li1", IE8 = { }) + @NotYetImplemented(IE8) + public void first_child() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('li:first-child')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<ul>\n" + + " <li id='li1'></li>\n" + + " <li id='li2'></li>\n" + + " <li id='li3'></li>\n" + + "</ul>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "li3", IE8 = { }) + @NotYetImplemented(IE8) + public void last_child() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('li:last-child')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<ul>\n" + + " <li id='li1'></li>\n" + + " <li id='li2'></li>\n" + + " <li id='li3'></li>\n" + + "</ul>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id2", IE8 = { }) + @NotYetImplemented(IE8) + public void first_of_type() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('p:first-of-type')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <h1 id='id1'></h1>\n" + + " <p id='id2'></p>\n" + + " <h1 id='id3'></h1>\n" + + " <p id='id4'></p>\n" + + " <h1 id='id5'></h1>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id4", IE8 = { }) + @NotYetImplemented(IE8) + public void last_of_type() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('p:last-of-type')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <h1 id='id1'></h1>\n" + + " <p id='id2'></p>\n" + + " <h1 id='id3'></h1>\n" + + " <p id='id4'></p>\n" + + " <h1 id='id5'></h1>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id3", IE8 = { }) + @NotYetImplemented(IE8) + public void only_child() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('h1:only-child')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <h1 id='id1'></h1>\n" + + " <p id='id2'></p>\n" + + "</section>\n" + + "<section>\n" + + " <h1 id='id3'></h1>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + + /** + * @throws Exception if an error occurs + */ + @Test + @Alerts(DEFAULT = "id3", IE8 = { }) + @NotYetImplemented(IE8) + public void only_of_type() throws Exception { + final String html + = HtmlPageTest.STANDARDS_MODE_PREFIX_ + "<html><head><title>First</title><script>\n" + + "function test() {\n" + + " if (document.querySelectorAll) {\n" + + " alert(document.querySelectorAll('p:only-of-type')[0].id);\n" + + " }\n" + + "}\n" + + "</script></head>\n" + + "<body onload='test()'>\n" + + "<section>\n" + + " <p id='id1'></p>\n" + + " <p id='id2'></p>\n" + + "</section>\n" + + "<section>\n" + + " <p id='id3'></p>\n" + + "</section>\n" + + "</body></html>"; + + loadPageWithAlerts2(html); + } + } |