Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Side by Side Diff: Source/devtools/front_end/DOMPresentationUtils.js

Issue 75253002: DevTools: [Elements] Implement "Copy CSS Path" context menu item for elements (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: More comments addressed, __proto__ bug fixed Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> 4 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
5 * Copyright (C) 2009 Joseph Pecoraro 5 * Copyright (C) 2009 Joseph Pecoraro
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 10 *
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 else 151 else
152 description = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)", offsetWidth, offsetHeight, naturalWidth, naturalHeight); 152 description = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)", offsetWidth, offsetHeight, naturalWidth, naturalHeight);
153 } 153 }
154 154
155 container.createChild("tr").createChild("td", "image-container").appendC hild(imageElement); 155 container.createChild("tr").createChild("td", "image-container").appendC hild(imageElement);
156 if (description) 156 if (description)
157 container.createChild("tr").createChild("td").createChild("span", "d escription").textContent = description; 157 container.createChild("tr").createChild("td").createChild("span", "d escription").textContent = description;
158 userCallback(container); 158 userCallback(container);
159 } 159 }
160 } 160 }
161
162 /**
163 * @param {!WebInspector.DOMNode} node
164 * @param {boolean=} optimized
165 */
166 WebInspector.DOMPresentationUtils.cssPathValue = function(node, optimized)
167 {
168 if (node.nodeType() !== Node.ELEMENT_NODE)
169 return null;
170
171 var id = node.getAttribute("id");
172 if (optimized) {
173 if (id)
174 return new WebInspector.DOMNodePathStep(idSelector(id), true);
175 var nodeNameLower = node.nodeName().toLowerCase();
176 if (nodeNameLower === "body" || nodeNameLower === "head" || nodeNameLowe r === "html")
177 return new WebInspector.DOMNodePathStep(node.nodeNameInCorrectCase() , true);
178 }
179 var nodeName = node.nodeNameInCorrectCase();
180
181 if (id)
182 return new WebInspector.DOMNodePathStep(nodeName + idSelector(id), true) ;
183 var parent = node.parentNode;
184 if (!parent || parent.nodeType() === Node.DOCUMENT_NODE)
185 return new WebInspector.DOMNodePathStep(nodeName, true);
186
187 /**
188 * @param {WebInspector.DOMNode} node
189 * @return {Array.<string>}
190 */
191 function prefixedElementClassNames(node)
192 {
193 var classAttribute = node.getAttribute("class");
194 if (!classAttribute)
195 return [];
196
197 return classAttribute.split(/\s+/g).filter(Boolean).map(function(name) {
198 // The prefix is required to store "__proto__" in a object-based map .
199 return "$" + name;
200 });
201 }
202
203 /**
204 * @param {string} id
205 * @return {string}
206 */
207 function idSelector(id)
208 {
209 return "#" + escapeIdentifierIfNeeded(id);
210 }
211
212 /**
213 * @param {string} ident
214 * @return {string}
215 */
216 function escapeIdentifierIfNeeded(ident)
217 {
218 if (isCSSIdentifier(ident))
219 return ident;
220 var shouldEscapeFirst = /^(?:[0-9]|-[0-9-]?)/.test(ident);
221 var lastIndex = ident.length - 1;
222 return ident.replace(/./g, function(c, i) {
223 return ((shouldEscapeFirst && i === 0) || !isCSSIdentChar(c)) ? esca peAsciiChar(c, i === lastIndex) : c;
224 });
225 }
226
227 /**
228 * @param {string} c
229 * @param {boolean} isLast
230 * @return {string}
231 */
232 function escapeAsciiChar(c, isLast)
233 {
234 return "\\" + toHexByte(c) + (isLast ? "" : " ");
235 }
236
237 /**
238 * @param {string} c
239 */
240 function toHexByte(c)
241 {
242 var hexByte = c.charCodeAt(0).toString(16);
243 if (hexByte.length === 1)
244 hexByte = "0" + hexByte;
245 return hexByte;
246 }
247
248 /**
249 * @param {string} c
250 * @return {boolean}
251 */
252 function isCSSIdentChar(c)
253 {
254 if (/[a-zA-Z0-9_-]/.test(c))
255 return true;
256 return c.charCodeAt(0) >= 0xA0;
257 }
258
259 /**
260 * @param {string} value
261 * @return {boolean}
262 */
263 function isCSSIdentifier(value)
264 {
265 return /^-?[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value);
266 }
267
268 var prefixedOwnClassNamesArray = prefixedElementClassNames(node);
269 var needsClassNames = false;
270 var needsNthChild = false;
271 var ownIndex = -1;
272 var siblings = parent.children();
273 for (var i = 0; (ownIndex === -1 || !needsNthChild) && i < siblings.length; ++i) {
274 var sibling = siblings[i];
275 if (sibling === node) {
276 ownIndex = i;
277 continue;
278 }
279 if (needsNthChild)
280 continue;
281 if (sibling.nodeNameInCorrectCase() !== nodeName)
282 continue;
283
284 needsClassNames = true;
285 var ownClassNames = prefixedOwnClassNamesArray.keySet();
286 var ownClassNameCount = 0;
287 for (var name in ownClassNames)
288 ++ownClassNameCount;
289 if (ownClassNameCount === 0) {
290 needsNthChild = true;
291 continue;
292 }
293 var siblingClassNamesArray = prefixedElementClassNames(sibling);
294 for (var j = 0; j < siblingClassNamesArray.length; ++j) {
295 var siblingClass = siblingClassNamesArray[j];
296 if (!ownClassNames.hasOwnProperty(siblingClass))
297 continue;
298 delete ownClassNames[siblingClass];
299 if (!--ownClassNameCount) {
300 needsNthChild = true;
301 break;
302 }
303 }
304 }
305
306 var result = nodeName;
307 if (needsNthChild) {
308 result += ":nth-child(" + (ownIndex + 1) + ")";
309 } else if (needsClassNames) {
310 for (var prefixedName in prefixedOwnClassNamesArray.keySet())
311 result += "." + escapeIdentifierIfNeeded(prefixedName.substr(1));
312 }
313
314 return new WebInspector.DOMNodePathStep(result, false);
315 }
316
317 /**
318 * @constructor
319 * @param {string} value
320 * @param {boolean} optimized
321 */
322 WebInspector.DOMNodePathStep = function(value, optimized)
323 {
324 this.value = value;
325 this.optimized = optimized;
326 }
327
328 WebInspector.DOMNodePathStep.prototype = {
329 /**
330 * @return {string}
331 */
332 toString: function()
333 {
334 return this.value;
335 }
336 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698