- From: Travis Leithead <travis.leithead@microsoft.com>
- Date: Thu, 24 Nov 2011 22:23:25 +0000
- To: Robin Berjon <robin@berjon.com>
- CC: "public-device-apis@w3.org" <public-device-apis@w3.org>, Adrian Bateman <adrianba@microsoft.com>
- Message-ID: <9768D477C67135458BF978A45BCF9B38381BB8F6@TK5EX14MBXW602.wingroup.windeploy.ntde>
Today is Thanksgiving [1] in the US, where we remember and are thankful for all the blessings in our lives. One thing I am grateful for is ReSpec which helps make many W3C spec-editor's lives easier. Thanks Robin! I've noticed that in IE9+ when viewing specs that utilize ReSpec (for example, the Contacts API [2]), I would get the following error (see also attached screenshot): "Processing error: TypeError: Object doesn't support property or method 'evaluate'". [cid:image003.jpg@01CCAAB4.A188E400] 'evaluate', of course, is the API used to execute XPath queries on the DOM using the W3C DOM Level 3 XPath WG Note [3]. Until such time as IE implements XPath support, I'd love to see ReSpec work as well on IE9+ as any other modern web browser. To that end, I wrote up a quick-and-dirty patch (below and attached) that adds the specific XPath support that ReSpec needs for browsers without 'evaluate' support. I've tested it on IE9+ and it seems to work. Older versions of IE would require many more shims, and since most of us here at Microsoft are using the most current versions of IE, I didn't bother making it work for IE < 9. The patch can simply be dropped in at the bottom of the http://dev.w3.org/2009/dap/ReSpec.js/js/respec.js file with no side-effects for UAs that have existing XPath support. I hope you'll accept this patch to give your IE9+ users a reason to also be thankful for ReSpec! -Travis [1] http://en.wikipedia.org/wiki/Thanksgiving [2] http://w3c-test.org/dap/contacts/ [3] http://www.w3.org/TR/DOM-Level-3-XPath/ ----Patch contents---- // ReSpec XPath substitute JS workaround for UA's without DOM L3 XPath support // By Travis Leithead (travil AT microsoft dotcom) // (select APIs and behaviors specifically for ReSpec's usage of DOM L3 XPath; no more an no less) // For IE, requires v.9+ (function () { if (!document.evaluate) { ////////////////////////////////////// // interface XPathResult ////////////////////////////////////// // Augments a generic JS Array to appear to be an XPathResult (thus allowing [] notation to work) window.XPathResult = function (list) { list.snapshotLength = list.length; list.snapshotItem = function (index) { return this[index]; }; return list; } window.XPathResult.prototype.ORDERED_NODE_SNAPSHOT_TYPE = 7; window.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7; ////////////////////////////////////// // interface XPathEvaluator ////////////////////////////////////// // Not exposed to the window (not needed) function XPathEvaluator(assignee) { var findElementsContainingContextNode = function (element, contextNode) { var allUpList = document.querySelectorAll(element); var resultSet = []; for (var i = 0, len = allUpList.length; i < len; i++) { if (allUpList[i].compareDocumentPosition(contextNode) & 16) resultSet.push(allUpList[i]); } return resultSet; } var allTextCache = null; var buildTextCacheUnderBody = function () { if (allTextCache == null) { var iter = document.createNodeIterator(document.body, 4, function () { return 1; }, false); allTextCache = []; while (n = iter.nextNode()) { allTextCache.push(n); } } // Note: no cache invalidation for dynamic updates... } var getAllTextNodesUnderContext = function (contextNode) { buildTextCacheUnderBody(); var candidates = []; for (var i = 0, len = allTextCache.length; i < len; i++) { if (allTextCache[i].compareDocumentPosition(contextNode) & 8) candidates.push(allTextCache[i]); } return candidates; } var findAncestorsOfContextNode = function (element, contextNode) { var allUpList = document.querySelectorAll(element); var candidates = []; for (var i = 0, len = allUpList.length; i < len; i++) { if (allUpList[i].compareDocumentPosition(contextNode) & 16) candidates.push(allUpList[i]); } return candidates; } var findSpecificChildrenOfContextNode = function (contextNode, selector) { // element.querySelectorAll(":scope > "+elementType) var allUpList = contextNode.querySelectorAll(selector); // Limit to children only... var candidates = []; for (var i = 0, len = allUpList.length; i < len; i++) { if (allUpList[i].parentNode == contextNode) candidates.push(allUpList[i]); } return candidates; } assignee.evaluate = function (xPathExpression, contextNode, resolverCallback, type, result) { // "ancestor::x:section|ancestor::section", sec if (xPathExpression == "ancestor::x:section|ancestor::section") // e.g., "section :scope" (but matching section) return XPathResult(findElementsContainingContextNode("section", contextNode)); else if (xPathExpression == "./x:section|./section") // e.g., ":scope > section" return XPathResult(findSpecificChildrenOfContextNode(contextNode, "section")); else if (xPathExpression == "./x:section[not(@class='introductory')]|./section[not(@class='introductory')]") // e.g., ":scope > section:not([class='introductory'])" return XPathResult(findSpecificChildrenOfContextNode(contextNode, "section:not([class='introductory'])")); else if (xPathExpression == ".//text()") // Not possible via Selectors API. Note that ":contains("...") can be used to find particular element containers of text return XPathResult(getAllTextNodesUnderContext(contextNode)); else if ((xPathExpression == "ancestor::abbr") || (xPathExpression == "ancestor::acronym")) // e.g., "abbr :scope, acronym :scope" (but match the element, not the scope) return XPathResult(findAncestorsOfContextNode((xPathExpression == "ancestor::abbr") ? "abbr" : "acronym", contextNode)); else if (xPathExpression == "./dt") // e.g., ":scope > dt" return XPathResult(findSpecificChildrenOfContextNode(contextNode, "dt")); else if (xPathExpression == "dl[@class='parameters']") return XPathResult(contextNode.querySelectorAll("dl[class='parameters']")); else if (xPathExpression == "*[@class='exception']") return XPathResult(contextNode.querySelectorAll("[class='exception']")); else // Anything else (not supported) return XPathResult([]); }; } // Document implements XPathExpression if (window.Document) { XPathEvaluator(Document.prototype); } else // no prototype hierarchy support (or Document doesn't exist) XPathEvaluator(window.document); } })();
Attachments
- image/jpeg attachment: image003.jpg
- text/plain attachment: reSpecXPathShim.js.txt
Received on Thursday, 24 November 2011 22:24:04 UTC