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

Side by Side Diff: chrome/resources/Inspector/utilities.js

Issue 334023: Remove Inspector directory in prep for ref build rev. (Closed) Base URL: http://src.chromium.org/svn/trunk/deps/reference_builds/
Patch Set: Created 11 years, 2 months 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
« no previous file with comments | « chrome/resources/Inspector/treeoutline.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 Object.type = function(obj, win)
30 {
31 if (obj === null)
32 return "null";
33
34 var type = typeof obj;
35 if (type !== "object" && type !== "function")
36 return type;
37
38 win = win || window;
39
40 if (obj instanceof win.String)
41 return "string";
42 if (obj instanceof win.Array)
43 return "array";
44 if (obj instanceof win.Boolean)
45 return "boolean";
46 if (obj instanceof win.Number)
47 return "number";
48 if (obj instanceof win.Date)
49 return "date";
50 if (obj instanceof win.RegExp)
51 return "regexp";
52 if (obj instanceof win.Error)
53 return "error";
54 return type;
55 }
56
57 Object.hasProperties = function(obj)
58 {
59 if (typeof obj === "undefined" || typeof obj === "null")
60 return false;
61 for (var name in obj)
62 return true;
63 return false;
64 }
65
66 Object.describe = function(obj, abbreviated)
67 {
68 var type1 = Object.type(obj);
69 var type2 = Object.prototype.toString.call(obj).replace(/^\[object (.*)\]$/i , "$1");
70
71 switch (type1) {
72 case "object":
73 return type2;
74 case "array":
75 return "[" + obj.toString() + "]";
76 case "string":
77 if (obj.length > 100)
78 return "\"" + obj.substring(0, 100) + "\u2026\"";
79 return "\"" + obj + "\"";
80 case "function":
81 var objectText = String(obj);
82 if (!/^function /.test(objectText))
83 objectText = (type2 == "object") ? type1 : type2;
84 else if (abbreviated)
85 objectText = /.*/.exec(obj)[0].replace(/ +$/g, "");
86 return objectText;
87 case "regexp":
88 return String(obj).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1);
89 default:
90 return String(obj);
91 }
92 }
93
94 Object.sortedProperties = function(obj)
95 {
96 var properties = [];
97 for (var prop in obj)
98 properties.push(prop);
99 properties.sort();
100 return properties;
101 }
102
103 Function.prototype.bind = function(thisObject)
104 {
105 var func = this;
106 var args = Array.prototype.slice.call(arguments, 1);
107 return function() { return func.apply(thisObject, args.concat(Array.prototyp e.slice.call(arguments, 0))) };
108 }
109
110 Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, di rection)
111 {
112 var startNode;
113 var startOffset = 0;
114 var endNode;
115 var endOffset = 0;
116
117 if (!stayWithinNode)
118 stayWithinNode = this;
119
120 if (!direction || direction === "backward" || direction === "both") {
121 var node = this;
122 while (node) {
123 if (node === stayWithinNode) {
124 if (!startNode)
125 startNode = stayWithinNode;
126 break;
127 }
128
129 if (node.nodeType === Node.TEXT_NODE) {
130 var start = (node === this ? (offset - 1) : (node.nodeValue.leng th - 1));
131 for (var i = start; i >= 0; --i) {
132 if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
133 startNode = node;
134 startOffset = i + 1;
135 break;
136 }
137 }
138 }
139
140 if (startNode)
141 break;
142
143 node = node.traversePreviousNode(false, stayWithinNode);
144 }
145
146 if (!startNode) {
147 startNode = stayWithinNode;
148 startOffset = 0;
149 }
150 } else {
151 startNode = this;
152 startOffset = offset;
153 }
154
155 if (!direction || direction === "forward" || direction === "both") {
156 node = this;
157 while (node) {
158 if (node === stayWithinNode) {
159 if (!endNode)
160 endNode = stayWithinNode;
161 break;
162 }
163
164 if (node.nodeType === Node.TEXT_NODE) {
165 var start = (node === this ? offset : 0);
166 for (var i = start; i < node.nodeValue.length; ++i) {
167 if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
168 endNode = node;
169 endOffset = i;
170 break;
171 }
172 }
173 }
174
175 if (endNode)
176 break;
177
178 node = node.traverseNextNode(false, stayWithinNode);
179 }
180
181 if (!endNode) {
182 endNode = stayWithinNode;
183 endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinN ode.nodeValue.length : stayWithinNode.childNodes.length;
184 }
185 } else {
186 endNode = this;
187 endOffset = offset;
188 }
189
190 var result = this.ownerDocument.createRange();
191 result.setStart(startNode, startOffset);
192 result.setEnd(endNode, endOffset);
193
194 return result;
195 }
196
197 Element.prototype.removeStyleClass = function(className)
198 {
199 // Test for the simple case before using a RegExp.
200 if (this.className === className) {
201 this.className = "";
202 return;
203 }
204
205 this.removeMatchingStyleClasses(className.escapeForRegExp());
206 }
207
208 Element.prototype.removeMatchingStyleClasses = function(classNameRegex)
209 {
210 var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)");
211 if (regex.test(this.className))
212 this.className = this.className.replace(regex, " ");
213 }
214
215 Element.prototype.addStyleClass = function(className)
216 {
217 if (className && !this.hasStyleClass(className))
218 this.className += (this.className.length ? " " + className : className);
219 }
220
221 Element.prototype.hasStyleClass = function(className)
222 {
223 if (!className)
224 return false;
225 // Test for the simple case before using a RegExp.
226 if (this.className === className)
227 return true;
228 var regex = new RegExp("(^|\\s)" + className.escapeForRegExp() + "($|\\s)");
229 return regex.test(this.className);
230 }
231
232 Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray)
233 {
234 for (var node = this; node && !objectsAreSame(node, this.ownerDocument); nod e = node.parentNode)
235 for (var i = 0; i < nameArray.length; ++i)
236 if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase())
237 return node;
238 return null;
239 }
240
241 Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName)
242 {
243 return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]);
244 }
245
246 Node.prototype.enclosingNodeOrSelfWithClass = function(className)
247 {
248 for (var node = this; node && !objectsAreSame(node, this.ownerDocument); nod e = node.parentNode)
249 if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className) )
250 return node;
251 return null;
252 }
253
254 Node.prototype.enclosingNodeWithClass = function(className)
255 {
256 if (!this.parentNode)
257 return null;
258 return this.parentNode.enclosingNodeOrSelfWithClass(className);
259 }
260
261 Element.prototype.query = function(query)
262 {
263 return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDE RED_NODE_TYPE, null).singleNodeValue;
264 }
265
266 Element.prototype.removeChildren = function()
267 {
268 while (this.firstChild)
269 this.removeChild(this.firstChild);
270 }
271
272 Element.prototype.isInsertionCaretInside = function()
273 {
274 var selection = window.getSelection();
275 if (!selection.rangeCount || !selection.isCollapsed)
276 return false;
277 var selectionRange = selection.getRangeAt(0);
278 return selectionRange.startContainer === this || selectionRange.startContain er.isDescendant(this);
279 }
280
281 Element.prototype.__defineGetter__("totalOffsetLeft", function()
282 {
283 var total = 0;
284 for (var element = this; element; element = element.offsetParent)
285 total += element.offsetLeft;
286 return total;
287 });
288
289 Element.prototype.__defineGetter__("totalOffsetTop", function()
290 {
291 var total = 0;
292 for (var element = this; element; element = element.offsetParent)
293 total += element.offsetTop;
294 return total;
295 });
296
297 Element.prototype.firstChildSkippingWhitespace = firstChildSkippingWhitespace;
298 Element.prototype.lastChildSkippingWhitespace = lastChildSkippingWhitespace;
299
300 Node.prototype.isWhitespace = isNodeWhitespace;
301 Node.prototype.nodeTypeName = nodeTypeName;
302 Node.prototype.displayName = nodeDisplayName;
303 Node.prototype.contentPreview = nodeContentPreview;
304 Node.prototype.isAncestor = isAncestorNode;
305 Node.prototype.isDescendant = isDescendantNode;
306 Node.prototype.firstCommonAncestor = firstCommonNodeAncestor;
307 Node.prototype.nextSiblingSkippingWhitespace = nextSiblingSkippingWhitespace;
308 Node.prototype.previousSiblingSkippingWhitespace = previousSiblingSkippingWhites pace;
309 Node.prototype.traverseNextNode = traverseNextNode;
310 Node.prototype.traversePreviousNode = traversePreviousNode;
311 Node.prototype.onlyTextChild = onlyTextChild;
312
313 String.prototype.hasSubstring = function(string, caseInsensitive)
314 {
315 if (!caseInsensitive)
316 return this.indexOf(string) !== -1;
317 return this.match(new RegExp(string.escapeForRegExp(), "i"));
318 }
319
320 String.prototype.escapeCharacters = function(chars)
321 {
322 var foundChar = false;
323 for (var i = 0; i < chars.length; ++i) {
324 if (this.indexOf(chars.charAt(i)) !== -1) {
325 foundChar = true;
326 break;
327 }
328 }
329
330 if (!foundChar)
331 return this;
332
333 var result = "";
334 for (var i = 0; i < this.length; ++i) {
335 if (chars.indexOf(this.charAt(i)) !== -1)
336 result += "\\";
337 result += this.charAt(i);
338 }
339
340 return result;
341 }
342
343 String.prototype.escapeForRegExp = function()
344 {
345 return this.escapeCharacters("^[]{}()\\.$*+?|");
346 }
347
348 String.prototype.escapeHTML = function()
349 {
350 return this.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt; ");
351 }
352
353 String.prototype.collapseWhitespace = function()
354 {
355 return this.replace(/[\s\xA0]+/g, " ");
356 }
357
358 String.prototype.trimLeadingWhitespace = function()
359 {
360 return this.replace(/^[\s\xA0]+/g, "");
361 }
362
363 String.prototype.trimTrailingWhitespace = function()
364 {
365 return this.replace(/[\s\xA0]+$/g, "");
366 }
367
368 String.prototype.trimWhitespace = function()
369 {
370 return this.replace(/^[\s\xA0]+|[\s\xA0]+$/g, "");
371 }
372
373 String.prototype.trimURL = function(baseURLDomain)
374 {
375 var result = this.replace(new RegExp("^http[s]?:\/\/", "i"), "");
376 if (baseURLDomain)
377 result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp() , "i"), "");
378 return result;
379 }
380
381 function getStyleTextWithShorthands(style)
382 {
383 var cssText = "";
384 var foundProperties = {};
385 for (var i = 0; i < style.length; ++i) {
386 var individualProperty = style[i];
387 var shorthandProperty = style.getPropertyShorthand(individualProperty);
388 var propertyName = (shorthandProperty || individualProperty);
389
390 if (propertyName in foundProperties)
391 continue;
392
393 if (shorthandProperty) {
394 var value = getShorthandValue(style, shorthandProperty);
395 var priority = getShorthandPriority(style, shorthandProperty);
396 } else {
397 var value = style.getPropertyValue(individualProperty);
398 var priority = style.getPropertyPriority(individualProperty);
399 }
400
401 foundProperties[propertyName] = true;
402
403 cssText += propertyName + ": " + value;
404 if (priority)
405 cssText += " !" + priority;
406 cssText += "; ";
407 }
408
409 return cssText;
410 }
411
412 function getShorthandValue(style, shorthandProperty)
413 {
414 var value = style.getPropertyValue(shorthandProperty);
415 if (!value) {
416 // Some shorthands (like border) return a null value, so compute a short hand value.
417 // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed.
418
419 var foundProperties = {};
420 for (var i = 0; i < style.length; ++i) {
421 var individualProperty = style[i];
422 if (individualProperty in foundProperties || style.getPropertyShorth and(individualProperty) !== shorthandProperty)
423 continue;
424
425 var individualValue = style.getPropertyValue(individualProperty);
426 if (style.isPropertyImplicit(individualProperty) || individualValue === "initial")
427 continue;
428
429 foundProperties[individualProperty] = true;
430
431 if (!value)
432 value = "";
433 else if (value.length)
434 value += " ";
435 value += individualValue;
436 }
437 }
438 return value;
439 }
440
441 function getShorthandPriority(style, shorthandProperty)
442 {
443 var priority = style.getPropertyPriority(shorthandProperty);
444 if (!priority) {
445 for (var i = 0; i < style.length; ++i) {
446 var individualProperty = style[i];
447 if (style.getPropertyShorthand(individualProperty) !== shorthandProp erty)
448 continue;
449 priority = style.getPropertyPriority(individualProperty);
450 break;
451 }
452 }
453 return priority;
454 }
455
456 function getLonghandProperties(style, shorthandProperty)
457 {
458 var properties = [];
459 var foundProperties = {};
460
461 for (var i = 0; i < style.length; ++i) {
462 var individualProperty = style[i];
463 if (individualProperty in foundProperties || style.getPropertyShorthand( individualProperty) !== shorthandProperty)
464 continue;
465 foundProperties[individualProperty] = true;
466 properties.push(individualProperty);
467 }
468
469 return properties;
470 }
471
472 function getUniqueStyleProperties(style)
473 {
474 var properties = [];
475 var foundProperties = {};
476
477 for (var i = 0; i < style.length; ++i) {
478 var property = style[i];
479 if (property in foundProperties)
480 continue;
481 foundProperties[property] = true;
482 properties.push(property);
483 }
484
485 return properties;
486 }
487
488 function isNodeWhitespace()
489 {
490 if (!this || this.nodeType !== Node.TEXT_NODE)
491 return false;
492 if (!this.nodeValue.length)
493 return true;
494 return this.nodeValue.match(/^[\s\xA0]+$/);
495 }
496
497 function nodeTypeName()
498 {
499 if (!this)
500 return "(unknown)";
501
502 switch (this.nodeType) {
503 case Node.ELEMENT_NODE: return "Element";
504 case Node.ATTRIBUTE_NODE: return "Attribute";
505 case Node.TEXT_NODE: return "Text";
506 case Node.CDATA_SECTION_NODE: return "Character Data";
507 case Node.ENTITY_REFERENCE_NODE: return "Entity Reference";
508 case Node.ENTITY_NODE: return "Entity";
509 case Node.PROCESSING_INSTRUCTION_NODE: return "Processing Instruction";
510 case Node.COMMENT_NODE: return "Comment";
511 case Node.DOCUMENT_NODE: return "Document";
512 case Node.DOCUMENT_TYPE_NODE: return "Document Type";
513 case Node.DOCUMENT_FRAGMENT_NODE: return "Document Fragment";
514 case Node.NOTATION_NODE: return "Notation";
515 }
516
517 return "(unknown)";
518 }
519
520 function nodeDisplayName()
521 {
522 if (!this)
523 return "";
524
525 switch (this.nodeType) {
526 case Node.DOCUMENT_NODE:
527 return "Document";
528
529 case Node.ELEMENT_NODE:
530 var name = "<" + this.nodeName.toLowerCase();
531
532 if (this.hasAttributes()) {
533 var value = this.getAttribute("id");
534 if (value)
535 name += " id=\"" + value + "\"";
536 value = this.getAttribute("class");
537 if (value)
538 name += " class=\"" + value + "\"";
539 if (this.nodeName.toLowerCase() === "a") {
540 value = this.getAttribute("name");
541 if (value)
542 name += " name=\"" + value + "\"";
543 value = this.getAttribute("href");
544 if (value)
545 name += " href=\"" + value + "\"";
546 } else if (this.nodeName.toLowerCase() === "img") {
547 value = this.getAttribute("src");
548 if (value)
549 name += " src=\"" + value + "\"";
550 } else if (this.nodeName.toLowerCase() === "iframe") {
551 value = this.getAttribute("src");
552 if (value)
553 name += " src=\"" + value + "\"";
554 } else if (this.nodeName.toLowerCase() === "input") {
555 value = this.getAttribute("name");
556 if (value)
557 name += " name=\"" + value + "\"";
558 value = this.getAttribute("type");
559 if (value)
560 name += " type=\"" + value + "\"";
561 } else if (this.nodeName.toLowerCase() === "form") {
562 value = this.getAttribute("action");
563 if (value)
564 name += " action=\"" + value + "\"";
565 }
566 }
567
568 return name + ">";
569
570 case Node.TEXT_NODE:
571 if (isNodeWhitespace.call(this))
572 return "(whitespace)";
573 return "\"" + this.nodeValue + "\"";
574
575 case Node.COMMENT_NODE:
576 return "<!--" + this.nodeValue + "-->";
577
578 case Node.DOCUMENT_TYPE_NODE:
579 var docType = "<!DOCTYPE " + this.nodeName;
580 if (this.publicId) {
581 docType += " PUBLIC \"" + this.publicId + "\"";
582 if (this.systemId)
583 docType += " \"" + this.systemId + "\"";
584 } else if (this.systemId)
585 docType += " SYSTEM \"" + this.systemId + "\"";
586 if (this.internalSubset)
587 docType += " [" + this.internalSubset + "]";
588 return docType + ">";
589 }
590
591 return this.nodeName.toLowerCase().collapseWhitespace();
592 }
593
594 function nodeContentPreview()
595 {
596 if (!this || !this.hasChildNodes || !this.hasChildNodes())
597 return "";
598
599 var limit = 0;
600 var preview = "";
601
602 // always skip whitespace here
603 var currentNode = traverseNextNode.call(this, true, this);
604 while (currentNode) {
605 if (currentNode.nodeType === Node.TEXT_NODE)
606 preview += currentNode.nodeValue.escapeHTML();
607 else
608 preview += nodeDisplayName.call(currentNode).escapeHTML();
609
610 currentNode = traverseNextNode.call(currentNode, true, this);
611
612 if (++limit > 4) {
613 preview += "&#x2026;"; // ellipsis
614 break;
615 }
616 }
617
618 return preview.collapseWhitespace();
619 }
620
621 function objectsAreSame(a, b)
622 {
623 // FIXME: Make this more generic so is works with any wrapped object, not ju st nodes.
624 // This function is used to compare nodes that might be JSInspectedObjectWra ppers, since
625 // JavaScript equality is not true for JSInspectedObjectWrappers of the same node wrapped
626 // with different global ExecStates, we use isSameNode to compare them.
627 if (a === b)
628 return true;
629 if (!a || !b)
630 return false;
631 if (a.isSameNode && b.isSameNode)
632 return a.isSameNode(b);
633 return false;
634 }
635
636 function isAncestorNode(ancestor)
637 {
638 if (!this || !ancestor)
639 return false;
640
641 var currentNode = ancestor.parentNode;
642 while (currentNode) {
643 if (objectsAreSame(this, currentNode))
644 return true;
645 currentNode = currentNode.parentNode;
646 }
647
648 return false;
649 }
650
651 function isDescendantNode(descendant)
652 {
653 return isAncestorNode.call(descendant, this);
654 }
655
656 function firstCommonNodeAncestor(node)
657 {
658 if (!this || !node)
659 return;
660
661 var node1 = this.parentNode;
662 var node2 = node.parentNode;
663
664 if ((!node1 || !node2) || !objectsAreSame(node1, node2))
665 return null;
666
667 while (node1 && node2) {
668 if (!node1.parentNode || !node2.parentNode)
669 break;
670 if (!objectsAreSame(node1, node2))
671 break;
672
673 node1 = node1.parentNode;
674 node2 = node2.parentNode;
675 }
676
677 return node1;
678 }
679
680 function nextSiblingSkippingWhitespace()
681 {
682 if (!this)
683 return;
684 var node = this.nextSibling;
685 while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(nod e))
686 node = node.nextSibling;
687 return node;
688 }
689
690 function previousSiblingSkippingWhitespace()
691 {
692 if (!this)
693 return;
694 var node = this.previousSibling;
695 while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(nod e))
696 node = node.previousSibling;
697 return node;
698 }
699
700 function firstChildSkippingWhitespace()
701 {
702 if (!this)
703 return;
704 var node = this.firstChild;
705 while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(nod e))
706 node = nextSiblingSkippingWhitespace.call(node);
707 return node;
708 }
709
710 function lastChildSkippingWhitespace()
711 {
712 if (!this)
713 return;
714 var node = this.lastChild;
715 while (node && node.nodeType === Node.TEXT_NODE && isNodeWhitespace.call(nod e))
716 node = previousSiblingSkippingWhitespace.call(node);
717 return node;
718 }
719
720 function traverseNextNode(skipWhitespace, stayWithin)
721 {
722 if (!this)
723 return;
724
725 var node = skipWhitespace ? firstChildSkippingWhitespace.call(this) : this.f irstChild;
726 if (node)
727 return node;
728
729 if (stayWithin && objectsAreSame(this, stayWithin))
730 return null;
731
732 node = skipWhitespace ? nextSiblingSkippingWhitespace.call(this) : this.next Sibling;
733 if (node)
734 return node;
735
736 node = this;
737 while (node && !(skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling) && (!stayWithin || !node.parentNode || !objectsAreSame(node.p arentNode, stayWithin)))
738 node = node.parentNode;
739 if (!node)
740 return null;
741
742 return skipWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.next Sibling;
743 }
744
745 function traversePreviousNode(skipWhitespace, stayWithin)
746 {
747 if (!this)
748 return;
749 if (stayWithin && objectsAreSame(this, stayWithin))
750 return null;
751 var node = skipWhitespace ? previousSiblingSkippingWhitespace.call(this) : t his.previousSibling;
752 while (node && (skipWhitespace ? lastChildSkippingWhitespace.call(node) : no de.lastChild) )
753 node = skipWhitespace ? lastChildSkippingWhitespace.call(node) : node.la stChild;
754 if (node)
755 return node;
756 return this.parentNode;
757 }
758
759 function onlyTextChild(ignoreWhitespace)
760 {
761 if (!this)
762 return null;
763
764 var firstChild = ignoreWhitespace ? firstChildSkippingWhitespace.call(this) : this.firstChild;
765 if (!firstChild || firstChild.nodeType !== Node.TEXT_NODE)
766 return null;
767
768 var sibling = ignoreWhitespace ? nextSiblingSkippingWhitespace.call(firstChi ld) : firstChild.nextSibling;
769 return sibling ? null : firstChild;
770 }
771
772 function nodeTitleInfo(hasChildren, linkify)
773 {
774 var info = {title: "", hasChildren: hasChildren};
775
776 switch (this.nodeType) {
777 case Node.DOCUMENT_NODE:
778 info.title = "Document";
779 break;
780
781 case Node.ELEMENT_NODE:
782 info.title = "<span class=\"webkit-html-tag\">&lt;" + this.nodeName. toLowerCase().escapeHTML();
783
784 if (this.hasAttributes()) {
785 for (var i = 0; i < this.attributes.length; ++i) {
786 var attr = this.attributes[i];
787 info.title += " <span class=\"webkit-html-attribute\"><span class=\"webkit-html-attribute-name\">" + attr.name.escapeHTML() + "</span>=&#820 3;\"";
788
789 var value = attr.value;
790 if (linkify && (attr.name === "src" || attr.name === "href") ) {
791 var value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B") ;
792 info.title += linkify(attr.value, value, "webkit-html-at tribute-value", this.nodeName.toLowerCase() == "a");
793 } else {
794 var value = value.escapeHTML();
795 value = value.replace(/([\/;:\)\]\}])/g, "$1&#8203;");
796 info.title += "<span class=\"webkit-html-attribute-value \">" + value + "</span>";
797 }
798 info.title += "\"</span>";
799 }
800 }
801 info.title += "&gt;</span>&#8203;";
802
803 // If this element only has a single child that is a text node,
804 // just show that text and the closing tag inline rather than
805 // create a subtree for them
806
807 var textChild = onlyTextChild.call(this, Preferences.ignoreWhitespac e);
808 var showInlineText = textChild && textChild.textContent.length < Pre ferences.maxInlineTextChildLength;
809
810 if (showInlineText) {
811 info.title += "<span class=\"webkit-html-text-node\">" + textChi ld.nodeValue.escapeHTML() + "</span>&#8203;<span class=\"webkit-html-tag\">&lt;/ " + this.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
812 info.hasChildren = false;
813 }
814 break;
815
816 case Node.TEXT_NODE:
817 if (isNodeWhitespace.call(this))
818 info.title = "(whitespace)";
819 else
820 info.title = "\"<span class=\"webkit-html-text-node\">" + this.n odeValue.escapeHTML() + "</span>\"";
821 break
822
823 case Node.COMMENT_NODE:
824 info.title = "<span class=\"webkit-html-comment\">&lt;!--" + this.no deValue.escapeHTML() + "--&gt;</span>";
825 break;
826
827 case Node.DOCUMENT_TYPE_NODE:
828 info.title = "<span class=\"webkit-html-doctype\">&lt;!DOCTYPE " + t his.nodeName;
829 if (this.publicId) {
830 info.title += " PUBLIC \"" + this.publicId + "\"";
831 if (this.systemId)
832 info.title += " \"" + this.systemId + "\"";
833 } else if (this.systemId)
834 info.title += " SYSTEM \"" + this.systemId + "\"";
835 if (this.internalSubset)
836 info.title += " [" + this.internalSubset + "]";
837 info.title += "&gt;</span>";
838 break;
839 default:
840 info.title = this.nodeName.toLowerCase().collapseWhitespace().escape HTML();
841 }
842
843 return info;
844 }
845
846 function getDocumentForNode(node) {
847 return node.nodeType == Node.DOCUMENT_NODE ? node : node.ownerDocument;
848 }
849
850 function parentNodeOrFrameElement(node) {
851 var parent = node.parentNode;
852 if (parent)
853 return parent;
854
855 return getDocumentForNode(node).defaultView.frameElement;
856 }
857
858 function isAncestorIncludingParentFrames(a, b) {
859 if (objectsAreSame(a, b))
860 return false;
861 for (var node = b; node; node = getDocumentForNode(node).defaultView.frameEl ement)
862 if (objectsAreSame(a, node) || isAncestorNode.call(a, node))
863 return true;
864 return false;
865 }
866
867 Number.secondsToString = function(seconds, formatterFunction, higherResolution)
868 {
869 if (!formatterFunction)
870 formatterFunction = String.sprintf;
871
872 var ms = seconds * 1000;
873 if (higherResolution && ms < 1000)
874 return formatterFunction("%.3fms", ms);
875 else if (ms < 1000)
876 return formatterFunction("%.0fms", ms);
877
878 if (seconds < 60)
879 return formatterFunction("%.2fs", seconds);
880
881 var minutes = seconds / 60;
882 if (minutes < 60)
883 return formatterFunction("%.1fmin", minutes);
884
885 var hours = minutes / 60;
886 if (hours < 24)
887 return formatterFunction("%.1fhrs", hours);
888
889 var days = hours / 24;
890 return formatterFunction("%.1f days", days);
891 }
892
893 Number.bytesToString = function(bytes, formatterFunction)
894 {
895 if (!formatterFunction)
896 formatterFunction = String.sprintf;
897
898 if (bytes < 1024)
899 return formatterFunction("%.0fB", bytes);
900
901 var kilobytes = bytes / 1024;
902 if (kilobytes < 1024)
903 return formatterFunction("%.2fKB", kilobytes);
904
905 var megabytes = kilobytes / 1024;
906 return formatterFunction("%.3fMB", megabytes);
907 }
908
909 Number.constrain = function(num, min, max)
910 {
911 if (num < min)
912 num = min;
913 else if (num > max)
914 num = max;
915 return num;
916 }
917
918 HTMLTextAreaElement.prototype.moveCursorToEnd = function()
919 {
920 var length = this.value.length;
921 this.setSelectionRange(length, length);
922 }
923
924 Array.prototype.remove = function(value, onlyFirst)
925 {
926 if (onlyFirst) {
927 var index = this.indexOf(value);
928 if (index !== -1)
929 this.splice(index, 1);
930 return;
931 }
932
933 var length = this.length;
934 for (var i = 0; i < length; ++i) {
935 if (this[i] === value)
936 this.splice(i, 1);
937 }
938 }
939
940 String.sprintf = function(format)
941 {
942 return String.vsprintf(format, Array.prototype.slice.call(arguments, 1));
943 }
944
945 String.tokenizeFormatString = function(format)
946 {
947 var tokens = [];
948 var substitutionIndex = 0;
949
950 function addStringToken(str)
951 {
952 tokens.push({ type: "string", value: str });
953 }
954
955 function addSpecifierToken(specifier, precision, substitutionIndex)
956 {
957 tokens.push({ type: "specifier", specifier: specifier, precision: precis ion, substitutionIndex: substitutionIndex });
958 }
959
960 var index = 0;
961 for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; pre centIndex = format.indexOf("%", index)) {
962 addStringToken(format.substring(index, precentIndex));
963 index = precentIndex + 1;
964
965 if (format[index] === "%") {
966 addStringToken("%");
967 ++index;
968 continue;
969 }
970
971 if (!isNaN(format[index])) {
972 // The first character is a number, it might be a substitution index .
973 var number = parseInt(format.substring(index));
974 while (!isNaN(format[index]))
975 ++index;
976 // If the number is greater than zero and ends with a "$",
977 // then this is a substitution index.
978 if (number > 0 && format[index] === "$") {
979 substitutionIndex = (number - 1);
980 ++index;
981 }
982 }
983
984 var precision = -1;
985 if (format[index] === ".") {
986 // This is a precision specifier. If no digit follows the ".",
987 // then the precision should be zero.
988 ++index;
989 precision = parseInt(format.substring(index));
990 if (isNaN(precision))
991 precision = 0;
992 while (!isNaN(format[index]))
993 ++index;
994 }
995
996 addSpecifierToken(format[index], precision, substitutionIndex);
997
998 ++substitutionIndex;
999 ++index;
1000 }
1001
1002 addStringToken(format.substring(index));
1003
1004 return tokens;
1005 }
1006
1007 String.standardFormatters = {
1008 d: function(substitution)
1009 {
1010 substitution = parseInt(substitution);
1011 return !isNaN(substitution) ? substitution : 0;
1012 },
1013
1014 f: function(substitution, token)
1015 {
1016 substitution = parseFloat(substitution);
1017 if (substitution && token.precision > -1)
1018 substitution = substitution.toFixed(token.precision);
1019 return !isNaN(substitution) ? substitution : (token.precision > -1 ? Num ber(0).toFixed(token.precision) : 0);
1020 },
1021
1022 s: function(substitution)
1023 {
1024 return substitution;
1025 },
1026 };
1027
1028 String.vsprintf = function(format, substitutions)
1029 {
1030 return String.format(format, substitutions, String.standardFormatters, "", f unction(a, b) { return a + b; }).formattedResult;
1031 }
1032
1033 String.format = function(format, substitutions, formatters, initialValue, append )
1034 {
1035 if (!format || !substitutions || !substitutions.length)
1036 return { formattedResult: append(initialValue, format), unusedSubstituti ons: substitutions };
1037
1038 function prettyFunctionName()
1039 {
1040 return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")";
1041 }
1042
1043 function warn(msg)
1044 {
1045 console.warn(prettyFunctionName() + ": " + msg);
1046 }
1047
1048 function error(msg)
1049 {
1050 console.error(prettyFunctionName() + ": " + msg);
1051 }
1052
1053 var result = initialValue;
1054 var tokens = String.tokenizeFormatString(format);
1055 var usedSubstitutionIndexes = {};
1056
1057 for (var i = 0; i < tokens.length; ++i) {
1058 var token = tokens[i];
1059
1060 if (token.type === "string") {
1061 result = append(result, token.value);
1062 continue;
1063 }
1064
1065 if (token.type !== "specifier") {
1066 error("Unknown token type \"" + token.type + "\" found.");
1067 continue;
1068 }
1069
1070 if (token.substitutionIndex >= substitutions.length) {
1071 // If there are not enough substitutions for the current substitutio nIndex
1072 // just output the format specifier literally and move on.
1073 error("not enough substitution arguments. Had " + substitutions.leng th + " but needed " + (token.substitutionIndex + 1) + ", so substitution was ski pped.");
1074 result = append(result, "%" + (token.precision > -1 ? token.precisio n : "") + token.specifier);
1075 continue;
1076 }
1077
1078 usedSubstitutionIndexes[token.substitutionIndex] = true;
1079
1080 if (!(token.specifier in formatters)) {
1081 // Encountered an unsupported format character, treat as a string.
1082 warn("unsupported format character \u201C" + token.specifier + "\u20 1D. Treating as a string.");
1083 result = append(result, substitutions[token.substitutionIndex]);
1084 continue;
1085 }
1086
1087 result = append(result, formatters[token.specifier](substitutions[token. substitutionIndex], token));
1088 }
1089
1090 var unusedSubstitutions = [];
1091 for (var i = 0; i < substitutions.length; ++i) {
1092 if (i in usedSubstitutionIndexes)
1093 continue;
1094 unusedSubstitutions.push(substitutions[i]);
1095 }
1096
1097 return { formattedResult: result, unusedSubstitutions: unusedSubstitutions } ;
1098 }
OLDNEW
« no previous file with comments | « chrome/resources/Inspector/treeoutline.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698