Guest User

Untitled

a guest
Jun 27th, 2016
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.18 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2015 Pavel Savshenko
  3. * Copyright (C) 2011 Google Inc. All rights reserved.
  4. * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  5. * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
  6. * Copyright (C) 2009 Joseph Pecoraro
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  18. * its contributors may be used to endorse or promote products derived
  19. * from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  22. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  24. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  25. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  26. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  28. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  30. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32.  
  33. var UTILS = {};
  34. UTILS.cssPath = function(node, optimized)
  35. {
  36. if (node.nodeType !== Node.ELEMENT_NODE)
  37. return "";
  38. var steps = [];
  39. var contextNode = node;
  40. while (contextNode) {
  41. var step = UTILS._cssPathStep(contextNode, !!optimized, contextNode === node);
  42. if (!step)
  43. break; // Error - bail out early.
  44. steps.push(step);
  45. if (step.optimized)
  46. break;
  47. contextNode = contextNode.parentNode;
  48. }
  49. steps.reverse();
  50. return steps.join(" > ");
  51. }
  52. UTILS._cssPathStep = function(node, optimized, isTargetNode)
  53. {
  54. if (node.nodeType !== Node.ELEMENT_NODE)
  55. return null;
  56.  
  57. var id = node.getAttribute("id");
  58. if (optimized) {
  59. if (id)
  60. return new UTILS.DOMNodePathStep(idSelector(id), true);
  61. var nodeNameLower = node.nodeName.toLowerCase();
  62. if (nodeNameLower === "body" || nodeNameLower === "head" || nodeNameLower === "html")
  63. return new UTILS.DOMNodePathStep(node.nodeName.toLowerCase(), true);
  64. }
  65. var nodeName = node.nodeName.toLowerCase();
  66.  
  67. if (id)
  68. return new UTILS.DOMNodePathStep(nodeName.toLowerCase() + idSelector(id), true);
  69. var parent = node.parentNode;
  70. if (!parent || parent.nodeType === Node.DOCUMENT_NODE)
  71. return new UTILS.DOMNodePathStep(nodeName.toLowerCase(), true);
  72.  
  73. /**
  74. * @param {UTILS.DOMNode} node
  75. * @return {Array.<string>}
  76. */
  77. function prefixedElementClassNames(node)
  78. {
  79. var classAttribute = node.getAttribute("class");
  80. if (!classAttribute)
  81. return [];
  82.  
  83. return classAttribute.split(/\s+/g).filter(Boolean).map(function(name) {
  84. // The prefix is required to store "__proto__" in a object-based map.
  85. return "$" + name;
  86. });
  87. }
  88.  
  89. /**
  90. * @param {string} id
  91. * @return {string}
  92. */
  93. function idSelector(id)
  94. {
  95. return "#" + escapeIdentifierIfNeeded(id);
  96. }
  97.  
  98. /**
  99. * @param {string} ident
  100. * @return {string}
  101. */
  102. function escapeIdentifierIfNeeded(ident)
  103. {
  104. if (isCSSIdentifier(ident))
  105. return ident;
  106. var shouldEscapeFirst = /^(?:[0-9]|-[0-9-]?)/.test(ident);
  107. var lastIndex = ident.length - 1;
  108. return ident.replace(/./g, function(c, i) {
  109. return ((shouldEscapeFirst && i === 0) || !isCSSIdentChar(c)) ? escapeAsciiChar(c, i === lastIndex) : c;
  110. });
  111. }
  112.  
  113. /**
  114. * @param {string} c
  115. * @param {boolean} isLast
  116. * @return {string}
  117. */
  118. function escapeAsciiChar(c, isLast)
  119. {
  120. return "\\" + toHexByte(c) + (isLast ? "" : " ");
  121. }
  122.  
  123. /**
  124. * @param {string} c
  125. */
  126. function toHexByte(c)
  127. {
  128. var hexByte = c.charCodeAt(0).toString(16);
  129. if (hexByte.length === 1)
  130. hexByte = "0" + hexByte;
  131. return hexByte;
  132. }
  133.  
  134. /**
  135. * @param {string} c
  136. * @return {boolean}
  137. */
  138. function isCSSIdentChar(c)
  139. {
  140. if (/[a-zA-Z0-9_-]/.test(c))
  141. return true;
  142. return c.charCodeAt(0) >= 0xA0;
  143. }
  144.  
  145. /**
  146. * @param {string} value
  147. * @return {boolean}
  148. */
  149. function isCSSIdentifier(value)
  150. {
  151. return /^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value);
  152. }
  153.  
  154. var prefixedOwnClassNamesArray = prefixedElementClassNames(node);
  155. var needsClassNames = false;
  156. var needsNthChild = false;
  157. var ownIndex = -1;
  158. var siblings = parent.children;
  159. for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.length; ++i) {
  160. var sibling = siblings[i];
  161. if (sibling === node) {
  162. ownIndex = i;
  163. continue;
  164. }
  165. if (needsNthChild)
  166. continue;
  167. if (sibling.nodeName.toLowerCase() !== nodeName.toLowerCase())
  168. continue;
  169.  
  170. needsClassNames = true;
  171. var ownClassNames = prefixedOwnClassNamesArray;
  172. var ownClassNameCount = 0;
  173. for (var name in ownClassNames)
  174. ++ownClassNameCount;
  175. if (ownClassNameCount === 0) {
  176. needsNthChild = true;
  177. continue;
  178. }
  179. var siblingClassNamesArray = prefixedElementClassNames(sibling);
  180. for (var j = 0; j < siblingClassNamesArray.length; ++j) {
  181. var siblingClass = siblingClassNamesArray[j];
  182. if (ownClassNames.indexOf(siblingClass))
  183. continue;
  184. delete ownClassNames[siblingClass];
  185. if (!--ownClassNameCount) {
  186. needsNthChild = true;
  187. break;
  188. }
  189. }
  190. }
  191.  
  192. var result = nodeName.toLowerCase();
  193. if (isTargetNode && nodeName.toLowerCase() === "input" && node.getAttribute("type") && !node.getAttribute("id") && !node.getAttribute("class"))
  194. result += "[type=\"" + node.getAttribute("type") + "\"]";
  195. if (needsNthChild) {
  196. result += ":nth-child(" + (ownIndex + 1) + ")";
  197. } else if (needsClassNames) {
  198. for (var prefixedName in prefixedOwnClassNamesArray)
  199. // for (var prefixedName in prefixedOwnClassNamesArray.keySet())
  200. result += "." + escapeIdentifierIfNeeded(prefixedOwnClassNamesArray[prefixedName].substr(1));
  201. }
  202.  
  203. return new UTILS.DOMNodePathStep(result, false);
  204. }
  205.  
  206. /**
  207. * @constructor
  208. * @param {string} value
  209. * @param {boolean} optimized
  210. */
  211. UTILS.DOMNodePathStep = function(value, optimized)
  212. {
  213. this.value = value;
  214. this.optimized = optimized || false;
  215. }
  216.  
  217. UTILS.DOMNodePathStep.prototype = {
  218. /**
  219. * @return {string}
  220. */
  221. toString: function()
  222. {
  223. return this.value;
  224. }
  225. }
Add Comment
Please, Sign In to add comment