PageRenderTime 357ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 4ms

/node_modules/node-inspector/front-end/devtools.js

https://bitbucket.org/E_lexy/jmonitor
JavaScript | 18673 lines | 15945 code | 2253 blank | 475 comment | 1502 complexity | a4c4924773b2b5e2f953e62c60f1ad5e MD5 | raw file
Possible License(s): MIT, Apache-2.0, BSD-3-Clause
  1. String.prototype.hasSubstring = function(string, caseInsensitive)
  2. {
  3. if (!caseInsensitive)
  4. return this.indexOf(string) !== -1;
  5. return this.match(new RegExp(string.escapeForRegExp(), "i"));
  6. }
  7. String.prototype.findAll = function(string)
  8. {
  9. var matches = [];
  10. var i = this.indexOf(string);
  11. while (i !== -1) {
  12. matches.push(i);
  13. i = this.indexOf(string, i + string.length);
  14. }
  15. return matches;
  16. }
  17. String.prototype.lineEndings = function()
  18. {
  19. if (!this._lineEndings) {
  20. this._lineEndings = this.findAll("\n");
  21. this._lineEndings.push(this.length);
  22. }
  23. return this._lineEndings;
  24. }
  25. String.prototype.escapeCharacters = function(chars)
  26. {
  27. var foundChar = false;
  28. for (var i = 0; i < chars.length; ++i) {
  29. if (this.indexOf(chars.charAt(i)) !== -1) {
  30. foundChar = true;
  31. break;
  32. }
  33. }
  34. if (!foundChar)
  35. return this;
  36. var result = "";
  37. for (var i = 0; i < this.length; ++i) {
  38. if (chars.indexOf(this.charAt(i)) !== -1)
  39. result += "\\";
  40. result += this.charAt(i);
  41. }
  42. return result;
  43. }
  44. String.prototype.escapeForRegExp = function()
  45. {
  46. return this.escapeCharacters("^[]{}()\\.$*+?|");
  47. }
  48. String.prototype.escapeHTML = function()
  49. {
  50. return this.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
  51. }
  52. String.prototype.collapseWhitespace = function()
  53. {
  54. return this.replace(/[\s\xA0]+/g, " ");
  55. }
  56. String.prototype.trimMiddle = function(maxLength)
  57. {
  58. if (this.length <= maxLength)
  59. return this;
  60. var leftHalf = maxLength >> 1;
  61. var rightHalf = maxLength - leftHalf - 1;
  62. return this.substr(0, leftHalf) + "\u2026" + this.substr(this.length - rightHalf, rightHalf);
  63. }
  64. String.prototype.trimEnd = function(maxLength)
  65. {
  66. if (this.length <= maxLength)
  67. return this;
  68. return this.substr(0, maxLength - 1) + "\u2026";
  69. }
  70. String.prototype.trimURL = function(baseURLDomain)
  71. {
  72. var result = this.replace(/^(https|http|file):\/\//i, "");
  73. if (baseURLDomain)
  74. result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), "");
  75. return result;
  76. }
  77. String.prototype.removeURLFragment = function()
  78. {
  79. var fragmentIndex = this.indexOf("#");
  80. if (fragmentIndex == -1)
  81. fragmentIndex = this.length;
  82. return this.substring(0, fragmentIndex);
  83. }
  84. String.prototype.startsWith = function(substring)
  85. {
  86. return !this.lastIndexOf(substring, 0);
  87. }
  88. String.prototype.endsWith = function(substring)
  89. {
  90. return this.indexOf(substring, this.length - substring.length) !== -1;
  91. }
  92. Number.constrain = function(num, min, max)
  93. {
  94. if (num < min)
  95. num = min;
  96. else if (num > max)
  97. num = max;
  98. return num;
  99. }
  100. Date.prototype.toISO8601Compact = function()
  101. {
  102. function leadZero(x)
  103. {
  104. return x > 9 ? '' + x : '0' + x
  105. }
  106. return this.getFullYear() +
  107. leadZero(this.getMonth() + 1) +
  108. leadZero(this.getDate()) + 'T' +
  109. leadZero(this.getHours()) +
  110. leadZero(this.getMinutes()) +
  111. leadZero(this.getSeconds());
  112. }
  113. Object.defineProperty(Array.prototype, "remove",
  114. {
  115. value: function(value, onlyFirst)
  116. {
  117. if (onlyFirst) {
  118. var index = this.indexOf(value);
  119. if (index !== -1)
  120. this.splice(index, 1);
  121. return;
  122. }
  123. var length = this.length;
  124. for (var i = 0; i < length; ++i) {
  125. if (this[i] === value)
  126. this.splice(i, 1);
  127. }
  128. }
  129. });
  130. Object.defineProperty(Array.prototype, "keySet",
  131. {
  132. value: function()
  133. {
  134. var keys = {};
  135. for (var i = 0; i < this.length; ++i)
  136. keys[this[i]] = true;
  137. return keys;
  138. }
  139. });
  140. Object.defineProperty(Array.prototype, "upperBound",
  141. {
  142. value: function(value)
  143. {
  144. var first = 0;
  145. var count = this.length;
  146. while (count > 0) {
  147. var step = count >> 1;
  148. var middle = first + step;
  149. if (value >= this[middle]) {
  150. first = middle + 1;
  151. count -= step + 1;
  152. } else
  153. count = step;
  154. }
  155. return first;
  156. }
  157. });
  158. Object.defineProperty(Uint32Array.prototype, "sort", {
  159. value: Array.prototype.sort
  160. });
  161. (function() {
  162. var partition = {
  163. value: function(comparator, left, right, pivotIndex)
  164. {
  165. function swap(array, i1, i2)
  166. {
  167. var temp = array[i1];
  168. array[i1] = array[i2];
  169. array[i2] = temp;
  170. }
  171. var pivotValue = this[pivotIndex];
  172. swap(this, right, pivotIndex);
  173. var storeIndex = left;
  174. for (var i = left; i < right; ++i) {
  175. if (comparator(this[i], pivotValue) < 0) {
  176. swap(this, storeIndex, i);
  177. ++storeIndex;
  178. }
  179. }
  180. swap(this, right, storeIndex);
  181. return storeIndex;
  182. }
  183. };
  184. Object.defineProperty(Array.prototype, "partition", partition);
  185. Object.defineProperty(Uint32Array.prototype, "partition", partition);
  186. var sortRange = {
  187. value: function(comparator, leftBound, rightBound, k)
  188. {
  189. function quickSortFirstK(array, comparator, left, right, k)
  190. {
  191. if (right <= left)
  192. return;
  193. var pivotIndex = Math.floor(Math.random() * (right - left)) + left;
  194. var pivotNewIndex = array.partition(comparator, left, right, pivotIndex);
  195. quickSortFirstK(array, comparator, left, pivotNewIndex - 1, k);
  196. if (pivotNewIndex < left + k - 1)
  197. quickSortFirstK(array, comparator, pivotNewIndex + 1, right, k);
  198. }
  199. if (leftBound === 0 && rightBound === (this.length - 1) && k === this.length)
  200. this.sort(comparator);
  201. else
  202. quickSortFirstK(this, comparator, leftBound, rightBound, k);
  203. return this;
  204. }
  205. }
  206. Object.defineProperty(Array.prototype, "sortRange", sortRange);
  207. Object.defineProperty(Uint32Array.prototype, "sortRange", sortRange);
  208. })();
  209. Object.defineProperty(Array.prototype, "qselect",
  210. {
  211. value: function(k, comparator)
  212. {
  213. if (k < 0 || k >= this.length)
  214. return;
  215. if (!comparator)
  216. comparator = function(a, b) { return a - b; }
  217. var low = 0;
  218. var high = this.length - 1;
  219. for (;;) {
  220. var pivotPosition = this.partition(comparator, low, high, Math.floor((high + low) / 2));
  221. if (pivotPosition === k)
  222. return this[k];
  223. else if (pivotPosition > k)
  224. high = pivotPosition - 1;
  225. else
  226. low = pivotPosition + 1;
  227. }
  228. }
  229. });
  230. function binarySearch(object, array, comparator)
  231. {
  232. var first = 0;
  233. var last = array.length - 1;
  234. while (first <= last) {
  235. var mid = (first + last) >> 1;
  236. var c = comparator(object, array[mid]);
  237. if (c > 0)
  238. first = mid + 1;
  239. else if (c < 0)
  240. last = mid - 1;
  241. else
  242. return mid;
  243. }
  244. return -(first + 1);
  245. }
  246. Object.defineProperty(Array.prototype, "binaryIndexOf",
  247. {
  248. value: function(value, comparator)
  249. {
  250. var result = binarySearch(value, this, comparator);
  251. return result >= 0 ? result : -1;
  252. }
  253. });
  254. function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction)
  255. {
  256. var index = binarySearch(anObject, aList, aFunction);
  257. if (index < 0)
  258. return -index - 1;
  259. else {
  260. while (index > 0 && aFunction(anObject, aList[index - 1]) === 0)
  261. index--;
  262. return index;
  263. }
  264. }
  265. Array.diff = function(left, right)
  266. {
  267. var o = left;
  268. var n = right;
  269. var ns = {};
  270. var os = {};
  271. for (var i = 0; i < n.length; i++) {
  272. if (ns[n[i]] == null)
  273. ns[n[i]] = { rows: [], o: null };
  274. ns[n[i]].rows.push(i);
  275. }
  276. for (var i = 0; i < o.length; i++) {
  277. if (os[o[i]] == null)
  278. os[o[i]] = { rows: [], n: null };
  279. os[o[i]].rows.push(i);
  280. }
  281. for (var i in ns) {
  282. if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
  283. n[ns[i].rows[0]] = { text: n[ns[i].rows[0]], row: os[i].rows[0] };
  284. o[os[i].rows[0]] = { text: o[os[i].rows[0]], row: ns[i].rows[0] };
  285. }
  286. }
  287. for (var i = 0; i < n.length - 1; i++) {
  288. if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) {
  289. n[i + 1] = { text: n[i + 1], row: n[i].row + 1 };
  290. o[n[i].row + 1] = { text: o[n[i].row + 1], row: i + 1 };
  291. }
  292. }
  293. for (var i = n.length - 1; i > 0; i--) {
  294. if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
  295. n[i - 1] == o[n[i].row - 1]) {
  296. n[i - 1] = { text: n[i - 1], row: n[i].row - 1 };
  297. o[n[i].row - 1] = { text: o[n[i].row - 1], row: i - 1 };
  298. }
  299. }
  300. return { left: o, right: n };
  301. }
  302. Array.convert = function(list)
  303. {
  304. return Array.prototype.slice.call(list);
  305. }
  306. String.sprintf = function(format, var_arg)
  307. {
  308. return String.vsprintf(format, Array.prototype.slice.call(arguments, 1));
  309. }
  310. String.tokenizeFormatString = function(format, formatters)
  311. {
  312. var tokens = [];
  313. var substitutionIndex = 0;
  314. function addStringToken(str)
  315. {
  316. tokens.push({ type: "string", value: str });
  317. }
  318. function addSpecifierToken(specifier, precision, substitutionIndex)
  319. {
  320. tokens.push({ type: "specifier", specifier: specifier, precision: precision, substitutionIndex: substitutionIndex });
  321. }
  322. function isDigit(c)
  323. {
  324. return !!/[0-9]/.exec(c);
  325. }
  326. var index = 0;
  327. for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; precentIndex = format.indexOf("%", index)) {
  328. addStringToken(format.substring(index, precentIndex));
  329. index = precentIndex + 1;
  330. if (isDigit(format[index])) {
  331. var number = parseInt(format.substring(index), 10);
  332. while (isDigit(format[index]))
  333. ++index;
  334. if (number > 0 && format[index] === "$") {
  335. substitutionIndex = (number - 1);
  336. ++index;
  337. }
  338. }
  339. var precision = -1;
  340. if (format[index] === ".") {
  341. ++index;
  342. precision = parseInt(format.substring(index), 10);
  343. if (isNaN(precision))
  344. precision = 0;
  345. while (isDigit(format[index]))
  346. ++index;
  347. }
  348. if (!(format[index] in formatters)) {
  349. addStringToken(format.substring(precentIndex, index + 1));
  350. ++index;
  351. continue;
  352. }
  353. addSpecifierToken(format[index], precision, substitutionIndex);
  354. ++substitutionIndex;
  355. ++index;
  356. }
  357. addStringToken(format.substring(index));
  358. return tokens;
  359. }
  360. String.standardFormatters = {
  361. d: function(substitution)
  362. {
  363. return !isNaN(substitution) ? substitution : 0;
  364. },
  365. f: function(substitution, token)
  366. {
  367. if (substitution && token.precision > -1)
  368. substitution = substitution.toFixed(token.precision);
  369. return !isNaN(substitution) ? substitution : (token.precision > -1 ? Number(0).toFixed(token.precision) : 0);
  370. },
  371. s: function(substitution)
  372. {
  373. return substitution;
  374. }
  375. }
  376. String.vsprintf = function(format, substitutions)
  377. {
  378. return String.format(format, substitutions, String.standardFormatters, "", function(a, b) { return a + b; }).formattedResult;
  379. }
  380. String.format = function(format, substitutions, formatters, initialValue, append)
  381. {
  382. if (!format || !substitutions || !substitutions.length)
  383. return { formattedResult: append(initialValue, format), unusedSubstitutions: substitutions };
  384. function prettyFunctionName()
  385. {
  386. return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")";
  387. }
  388. function warn(msg)
  389. {
  390. console.warn(prettyFunctionName() + ": " + msg);
  391. }
  392. function error(msg)
  393. {
  394. console.error(prettyFunctionName() + ": " + msg);
  395. }
  396. var result = initialValue;
  397. var tokens = String.tokenizeFormatString(format, formatters);
  398. var usedSubstitutionIndexes = {};
  399. for (var i = 0; i < tokens.length; ++i) {
  400. var token = tokens[i];
  401. if (token.type === "string") {
  402. result = append(result, token.value);
  403. continue;
  404. }
  405. if (token.type !== "specifier") {
  406. error("Unknown token type \"" + token.type + "\" found.");
  407. continue;
  408. }
  409. if (token.substitutionIndex >= substitutions.length) {
  410. error("not enough substitution arguments. Had " + substitutions.length + " but needed " + (token.substitutionIndex + 1) + ", so substitution was skipped.");
  411. result = append(result, "%" + (token.precision > -1 ? token.precision : "") + token.specifier);
  412. continue;
  413. }
  414. usedSubstitutionIndexes[token.substitutionIndex] = true;
  415. if (!(token.specifier in formatters)) {
  416. warn("unsupported format character \u201C" + token.specifier + "\u201D. Treating as a string.");
  417. result = append(result, substitutions[token.substitutionIndex]);
  418. continue;
  419. }
  420. result = append(result, formatters[token.specifier](substitutions[token.substitutionIndex], token));
  421. }
  422. var unusedSubstitutions = [];
  423. for (var i = 0; i < substitutions.length; ++i) {
  424. if (i in usedSubstitutionIndexes)
  425. continue;
  426. unusedSubstitutions.push(substitutions[i]);
  427. }
  428. return { formattedResult: result, unusedSubstitutions: unusedSubstitutions };
  429. }
  430. function createSearchRegex(query, caseSensitive, isRegex)
  431. {
  432. var regexFlags = caseSensitive ? "g" : "gi";
  433. var regexObject;
  434. if (isRegex) {
  435. try {
  436. regexObject = new RegExp(query, regexFlags);
  437. } catch (e) {
  438. }
  439. }
  440. if (!regexObject)
  441. regexObject = createPlainTextSearchRegex(query, regexFlags);
  442. return regexObject;
  443. }
  444. function createPlainTextSearchRegex(query, flags)
  445. {
  446. var regexSpecialCharacters = "[](){}+-*.,?\\^$|";
  447. var regex = "";
  448. for (var i = 0; i < query.length; ++i) {
  449. var c = query.charAt(i);
  450. if (regexSpecialCharacters.indexOf(c) != -1)
  451. regex += "\\";
  452. regex += c;
  453. }
  454. return new RegExp(regex, flags || "");
  455. }
  456. function countRegexMatches(regex, content)
  457. {
  458. var text = content;
  459. var result = 0;
  460. var match;
  461. while (text && (match = regex.exec(text))) {
  462. if (match[0].length > 0)
  463. ++result;
  464. text = text.substring(match.index + 1);
  465. }
  466. return result;
  467. }
  468. function numberToStringWithSpacesPadding(value, symbolsCount)
  469. {
  470. var numberString = value.toString();
  471. var paddingLength = Math.max(0, symbolsCount - numberString.length);
  472. var paddingString = Array(paddingLength + 1).join("\u00a0");
  473. return paddingString + numberString;
  474. }
  475. function TextDiff()
  476. {
  477. this.added = [];
  478. this.removed = [];
  479. this.changed = [];
  480. }
  481. TextDiff.compute = function(baseContent, newContent)
  482. {
  483. var oldLines = baseContent.split(/\r?\n/);
  484. var newLines = newContent.split(/\r?\n/);
  485. var diff = Array.diff(oldLines, newLines);
  486. var diffData = new TextDiff();
  487. var offset = 0;
  488. var right = diff.right;
  489. for (var i = 0; i < right.length; ++i) {
  490. if (typeof right[i] === "string") {
  491. if (right.length > i + 1 && right[i + 1].row === i + 1 - offset)
  492. diffData.changed.push(i);
  493. else {
  494. diffData.added.push(i);
  495. offset++;
  496. }
  497. } else
  498. offset = i - right[i].row;
  499. }
  500. return diffData;
  501. }
  502. var Map = function()
  503. {
  504. this._map = {};
  505. }
  506. Map._lastObjectIdentifier = 0;
  507. Map.prototype = {
  508. put: function(key, value)
  509. {
  510. var objectIdentifier = key.__identifier;
  511. if (!objectIdentifier) {
  512. objectIdentifier = ++Map._lastObjectIdentifier;
  513. key.__identifier = objectIdentifier;
  514. }
  515. this._map[objectIdentifier] = value;
  516. },
  517. remove: function(key)
  518. {
  519. var result = this._map[key.__identifier];
  520. delete this._map[key.__identifier];
  521. return result;
  522. },
  523. values: function()
  524. {
  525. var result = [];
  526. for (var objectIdentifier in this._map)
  527. result.push(this._map[objectIdentifier]);
  528. return result;
  529. },
  530. get: function(key)
  531. {
  532. return this._map[key.__identifier];
  533. },
  534. clear: function()
  535. {
  536. this._map = {};
  537. }
  538. }
  539. Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, direction)
  540. {
  541. var startNode;
  542. var startOffset = 0;
  543. var endNode;
  544. var endOffset = 0;
  545. if (!stayWithinNode)
  546. stayWithinNode = this;
  547. if (!direction || direction === "backward" || direction === "both") {
  548. var node = this;
  549. while (node) {
  550. if (node === stayWithinNode) {
  551. if (!startNode)
  552. startNode = stayWithinNode;
  553. break;
  554. }
  555. if (node.nodeType === Node.TEXT_NODE) {
  556. var start = (node === this ? (offset - 1) : (node.nodeValue.length - 1));
  557. for (var i = start; i >= 0; --i) {
  558. if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
  559. startNode = node;
  560. startOffset = i + 1;
  561. break;
  562. }
  563. }
  564. }
  565. if (startNode)
  566. break;
  567. node = node.traversePreviousNode(stayWithinNode);
  568. }
  569. if (!startNode) {
  570. startNode = stayWithinNode;
  571. startOffset = 0;
  572. }
  573. } else {
  574. startNode = this;
  575. startOffset = offset;
  576. }
  577. if (!direction || direction === "forward" || direction === "both") {
  578. node = this;
  579. while (node) {
  580. if (node === stayWithinNode) {
  581. if (!endNode)
  582. endNode = stayWithinNode;
  583. break;
  584. }
  585. if (node.nodeType === Node.TEXT_NODE) {
  586. var start = (node === this ? offset : 0);
  587. for (var i = start; i < node.nodeValue.length; ++i) {
  588. if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
  589. endNode = node;
  590. endOffset = i;
  591. break;
  592. }
  593. }
  594. }
  595. if (endNode)
  596. break;
  597. node = node.traverseNextNode(stayWithinNode);
  598. }
  599. if (!endNode) {
  600. endNode = stayWithinNode;
  601. endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinNode.nodeValue.length : stayWithinNode.childNodes.length;
  602. }
  603. } else {
  604. endNode = this;
  605. endOffset = offset;
  606. }
  607. var result = this.ownerDocument.createRange();
  608. result.setStart(startNode, startOffset);
  609. result.setEnd(endNode, endOffset);
  610. return result;
  611. }
  612. Node.prototype.traverseNextTextNode = function(stayWithin)
  613. {
  614. var node = this.traverseNextNode(stayWithin);
  615. if (!node)
  616. return;
  617. while (node && node.nodeType !== Node.TEXT_NODE)
  618. node = node.traverseNextNode(stayWithin);
  619. return node;
  620. }
  621. Node.prototype.rangeBoundaryForOffset = function(offset)
  622. {
  623. var node = this.traverseNextTextNode(this);
  624. while (node && offset > node.nodeValue.length) {
  625. offset -= node.nodeValue.length;
  626. node = node.traverseNextTextNode(this);
  627. }
  628. if (!node)
  629. return { container: this, offset: 0 };
  630. return { container: node, offset: offset };
  631. }
  632. Element.prototype.removeStyleClass = function(className)
  633. {
  634. this.classList.remove(className);
  635. }
  636. Element.prototype.removeMatchingStyleClasses = function(classNameRegex)
  637. {
  638. var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)");
  639. if (regex.test(this.className))
  640. this.className = this.className.replace(regex, " ");
  641. }
  642. Element.prototype.addStyleClass = function(className)
  643. {
  644. this.classList.add(className);
  645. }
  646. Element.prototype.hasStyleClass = function(className)
  647. {
  648. return this.classList.contains(className);
  649. }
  650. Element.prototype.positionAt = function(x, y)
  651. {
  652. this.style.left = x + "px";
  653. this.style.top = y + "px";
  654. }
  655. Element.prototype.pruneEmptyTextNodes = function()
  656. {
  657. var sibling = this.firstChild;
  658. while (sibling) {
  659. var nextSibling = sibling.nextSibling;
  660. if (sibling.nodeType === this.TEXT_NODE && sibling.nodeValue === "")
  661. this.removeChild(sibling);
  662. sibling = nextSibling;
  663. }
  664. }
  665. Element.prototype.isScrolledToBottom = function()
  666. {
  667. return this.scrollTop + this.clientHeight === this.scrollHeight;
  668. }
  669. Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray)
  670. {
  671. for (var node = this; node && node !== this.ownerDocument; node = node.parentNode)
  672. for (var i = 0; i < nameArray.length; ++i)
  673. if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase())
  674. return node;
  675. return null;
  676. }
  677. Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName)
  678. {
  679. return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]);
  680. }
  681. Node.prototype.enclosingNodeOrSelfWithClass = function(className)
  682. {
  683. for (var node = this; node && node !== this.ownerDocument; node = node.parentNode)
  684. if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className))
  685. return node;
  686. return null;
  687. }
  688. Node.prototype.enclosingNodeWithClass = function(className)
  689. {
  690. if (!this.parentNode)
  691. return null;
  692. return this.parentNode.enclosingNodeOrSelfWithClass(className);
  693. }
  694. Element.prototype.query = function(query)
  695. {
  696. return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  697. }
  698. Element.prototype.removeChildren = function()
  699. {
  700. if (this.firstChild)
  701. this.textContent = "";
  702. }
  703. Element.prototype.isInsertionCaretInside = function()
  704. {
  705. var selection = window.getSelection();
  706. if (!selection.rangeCount || !selection.isCollapsed)
  707. return false;
  708. var selectionRange = selection.getRangeAt(0);
  709. return selectionRange.startContainer.isSelfOrDescendant(this);
  710. }
  711. Element.prototype.createChild = function(elementName, className)
  712. {
  713. var element = this.ownerDocument.createElement(elementName);
  714. if (className)
  715. element.className = className;
  716. this.appendChild(element);
  717. return element;
  718. }
  719. DocumentFragment.prototype.createChild = Element.prototype.createChild;
  720. Element.prototype.totalOffsetLeft = function()
  721. {
  722. return this.totalOffset().left;
  723. }
  724. Element.prototype.totalOffsetTop = function()
  725. {
  726. return this.totalOffset().top;
  727. }
  728. Element.prototype.totalOffset = function()
  729. {
  730. var totalLeft = 0;
  731. var totalTop = 0;
  732. for (var element = this; element; element = element.offsetParent) {
  733. totalLeft += element.offsetLeft;
  734. totalTop += element.offsetTop;
  735. if (this !== element) {
  736. totalLeft += element.clientLeft - element.scrollLeft;
  737. totalTop += element.clientTop - element.scrollTop;
  738. }
  739. }
  740. return { left: totalLeft, top: totalTop };
  741. }
  742. Element.prototype.scrollOffset = function()
  743. {
  744. var curLeft = 0;
  745. var curTop = 0;
  746. for (var element = this; element; element = element.scrollParent) {
  747. curLeft += element.scrollLeft;
  748. curTop += element.scrollTop;
  749. }
  750. return { left: curLeft, top: curTop };
  751. }
  752. function AnchorBox(x, y, width, height)
  753. {
  754. this.x = x || 0;
  755. this.y = y || 0;
  756. this.width = width || 0;
  757. this.height = height || 0;
  758. }
  759. Element.prototype.offsetRelativeToWindow = function(targetWindow)
  760. {
  761. var elementOffset = new AnchorBox();
  762. var curElement = this;
  763. var curWindow = this.ownerDocument.defaultView;
  764. while (curWindow && curElement) {
  765. elementOffset.x += curElement.totalOffsetLeft();
  766. elementOffset.y += curElement.totalOffsetTop();
  767. if (curWindow === targetWindow)
  768. break;
  769. curElement = curWindow.frameElement;
  770. curWindow = curWindow.parent;
  771. }
  772. return elementOffset;
  773. }
  774. Element.prototype.boxInWindow = function(targetWindow)
  775. {
  776. targetWindow = targetWindow || this.ownerDocument.defaultView;
  777. var anchorBox = this.offsetRelativeToWindow(window);
  778. anchorBox.width = Math.min(this.offsetWidth, window.innerWidth - anchorBox.x);
  779. anchorBox.height = Math.min(this.offsetHeight, window.innerHeight - anchorBox.y);
  780. return anchorBox;
  781. }
  782. Element.prototype.setTextAndTitle = function(text)
  783. {
  784. this.textContent = text;
  785. this.title = text;
  786. }
  787. KeyboardEvent.prototype.__defineGetter__("data", function()
  788. {
  789. switch (this.type) {
  790. case "keypress":
  791. if (!this.ctrlKey && !this.metaKey)
  792. return String.fromCharCode(this.charCode);
  793. else
  794. return "";
  795. case "keydown":
  796. case "keyup":
  797. if (!this.ctrlKey && !this.metaKey && !this.altKey)
  798. return String.fromCharCode(this.which);
  799. else
  800. return "";
  801. }
  802. });
  803. Event.prototype.consume = function(preventDefault)
  804. {
  805. this.stopImmediatePropagation();
  806. if (preventDefault)
  807. this.preventDefault();
  808. this.handled = true;
  809. }
  810. Text.prototype.select = function(start, end)
  811. {
  812. start = start || 0;
  813. end = end || this.textContent.length;
  814. if (start < 0)
  815. start = end + start;
  816. var selection = this.ownerDocument.defaultView.getSelection();
  817. selection.removeAllRanges();
  818. var range = this.ownerDocument.createRange();
  819. range.setStart(this, start);
  820. range.setEnd(this, end);
  821. selection.addRange(range);
  822. return this;
  823. }
  824. Element.prototype.selectionLeftOffset = function()
  825. {
  826. var selection = window.getSelection();
  827. if (!selection.containsNode(this, true))
  828. return null;
  829. var leftOffset = selection.anchorOffset;
  830. var node = selection.anchorNode;
  831. while (node !== this) {
  832. while (node.previousSibling) {
  833. node = node.previousSibling;
  834. leftOffset += node.textContent.length;
  835. }
  836. node = node.parentNode;
  837. }
  838. return leftOffset;
  839. }
  840. Node.prototype.isAncestor = function(node)
  841. {
  842. if (!node)
  843. return false;
  844. var currentNode = node.parentNode;
  845. while (currentNode) {
  846. if (this === currentNode)
  847. return true;
  848. currentNode = currentNode.parentNode;
  849. }
  850. return false;
  851. }
  852. Node.prototype.isDescendant = function(descendant)
  853. {
  854. return !!descendant && descendant.isAncestor(this);
  855. }
  856. Node.prototype.isSelfOrAncestor = function(node)
  857. {
  858. return !!node && (node === this || this.isAncestor(node));
  859. }
  860. Node.prototype.isSelfOrDescendant = function(node)
  861. {
  862. return !!node && (node === this || this.isDescendant(node));
  863. }
  864. Node.prototype.traverseNextNode = function(stayWithin)
  865. {
  866. var node = this.firstChild;
  867. if (node)
  868. return node;
  869. if (stayWithin && this === stayWithin)
  870. return null;
  871. node = this.nextSibling;
  872. if (node)
  873. return node;
  874. node = this;
  875. while (node && !node.nextSibling && (!stayWithin || !node.parentNode || node.parentNode !== stayWithin))
  876. node = node.parentNode;
  877. if (!node)
  878. return null;
  879. return node.nextSibling;
  880. }
  881. Node.prototype.traversePreviousNode = function(stayWithin)
  882. {
  883. if (stayWithin && this === stayWithin)
  884. return null;
  885. var node = this.previousSibling;
  886. while (node && node.lastChild)
  887. node = node.lastChild;
  888. if (node)
  889. return node;
  890. return this.parentNode;
  891. }
  892. HTMLTextAreaElement.prototype.moveCursorToEnd = function()
  893. {
  894. var length = this.value.length;
  895. this.setSelectionRange(length, length);
  896. }
  897. function isEnterKey(event) {
  898. return event.keyCode !== 229 && event.keyIdentifier === "Enter";
  899. }
  900. function consumeEvent(e)
  901. {
  902. e.consume();
  903. }
  904. function TreeOutline(listNode, nonFocusable)
  905. {
  906. this.children = [];
  907. this.selectedTreeElement = null;
  908. this._childrenListNode = listNode;
  909. this.childrenListElement = this._childrenListNode;
  910. this._childrenListNode.removeChildren();
  911. this.expandTreeElementsWhenArrowing = false;
  912. this.root = true;
  913. this.hasChildren = false;
  914. this.expanded = true;
  915. this.selected = false;
  916. this.treeOutline = this;
  917. this.comparator = null;
  918. this.searchable = false;
  919. this.searchInputElement = null;
  920. this.setFocusable(!nonFocusable);
  921. this._childrenListNode.addEventListener("keydown", this._treeKeyDown.bind(this), true);
  922. this._childrenListNode.addEventListener("keypress", this._treeKeyPress.bind(this), true);
  923. this._treeElementsMap = new Map();
  924. this._expandedStateMap = new Map();
  925. }
  926. TreeOutline.prototype.setFocusable = function(focusable)
  927. {
  928. if (focusable)
  929. this._childrenListNode.setAttribute("tabIndex", 0);
  930. else
  931. this._childrenListNode.removeAttribute("tabIndex");
  932. }
  933. TreeOutline.prototype.appendChild = function(child)
  934. {
  935. var insertionIndex;
  936. if (this.treeOutline.comparator)
  937. insertionIndex = insertionIndexForObjectInListSortedByFunction(child, this.children, this.treeOutline.comparator);
  938. else
  939. insertionIndex = this.children.length;
  940. this.insertChild(child, insertionIndex);
  941. }
  942. TreeOutline.prototype.insertChild = function(child, index)
  943. {
  944. if (!child)
  945. throw("child can't be undefined or null");
  946. var previousChild = (index > 0 ? this.children[index - 1] : null);
  947. if (previousChild) {
  948. previousChild.nextSibling = child;
  949. child.previousSibling = previousChild;
  950. } else {
  951. child.previousSibling = null;
  952. }
  953. var nextChild = this.children[index];
  954. if (nextChild) {
  955. nextChild.previousSibling = child;
  956. child.nextSibling = nextChild;
  957. } else {
  958. child.nextSibling = null;
  959. }
  960. this.children.splice(index, 0, child);
  961. this.hasChildren = true;
  962. child.parent = this;
  963. child.treeOutline = this.treeOutline;
  964. child.treeOutline._rememberTreeElement(child);
  965. var current = child.children[0];
  966. while (current) {
  967. current.treeOutline = this.treeOutline;
  968. current.treeOutline._rememberTreeElement(current);
  969. current = current.traverseNextTreeElement(false, child, true);
  970. }
  971. if (child.hasChildren && typeof(child.treeOutline._expandedStateMap.get(child.representedObject)) !== "undefined")
  972. child.expanded = child.treeOutline._expandedStateMap.get(child.representedObject);
  973. if (!this._childrenListNode) {
  974. this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol");
  975. this._childrenListNode.parentTreeElement = this;
  976. this._childrenListNode.classList.add("children");
  977. if (this.hidden)
  978. this._childrenListNode.classList.add("hidden");
  979. }
  980. child._attach();
  981. if (this.treeOutline.onadd)
  982. this.treeOutline.onadd(child);
  983. }
  984. TreeOutline.prototype.removeChildAtIndex = function(childIndex)
  985. {
  986. if (childIndex < 0 || childIndex >= this.children.length)
  987. throw("childIndex out of range");
  988. var child = this.children[childIndex];
  989. this.children.splice(childIndex, 1);
  990. var parent = child.parent;
  991. if (child.deselect()) {
  992. if (child.previousSibling)
  993. child.previousSibling.select();
  994. else if (child.nextSibling)
  995. child.nextSibling.select();
  996. else
  997. parent.select();
  998. }
  999. if (child.previousSibling)
  1000. child.previousSibling.nextSibling = child.nextSibling;
  1001. if (child.nextSibling)
  1002. child.nextSibling.previousSibling = child.previousSibling;
  1003. if (child.treeOutline) {
  1004. child.treeOutline._forgetTreeElement(child);
  1005. child.treeOutline._forgetChildrenRecursive(child);
  1006. }
  1007. child._detach();
  1008. child.treeOutline = null;
  1009. child.parent = null;
  1010. child.nextSibling = null;
  1011. child.previousSibling = null;
  1012. }
  1013. TreeOutline.prototype.removeChild = function(child)
  1014. {
  1015. if (!child)
  1016. throw("child can't be undefined or null");
  1017. var childIndex = this.children.indexOf(child);
  1018. if (childIndex === -1)
  1019. throw("child not found in this node's children");
  1020. this.removeChildAtIndex.call(this, childIndex);
  1021. }
  1022. TreeOutline.prototype.removeChildren = function()
  1023. {
  1024. for (var i = 0; i < this.children.length; ++i) {
  1025. var child = this.children[i];
  1026. child.deselect();
  1027. if (child.treeOutline) {
  1028. child.treeOutline._forgetTreeElement(child);
  1029. child.treeOutline._forgetChildrenRecursive(child);
  1030. }
  1031. child._detach();
  1032. child.treeOutline = null;
  1033. child.parent = null;
  1034. child.nextSibling = null;
  1035. child.previousSibling = null;
  1036. }
  1037. this.children = [];
  1038. }
  1039. TreeOutline.prototype._rememberTreeElement = function(element)
  1040. {
  1041. if (!this._treeElementsMap.get(element.representedObject))
  1042. this._treeElementsMap.put(element.representedObject, []);
  1043. var elements = this._treeElementsMap.get(element.representedObject);
  1044. if (elements.indexOf(element) !== -1)
  1045. return;
  1046. elements.push(element);
  1047. }
  1048. TreeOutline.prototype._forgetTreeElement = function(element)
  1049. {
  1050. if (this._treeElementsMap.get(element.representedObject))
  1051. this._treeElementsMap.get(element.representedObject).remove(element, true);
  1052. }
  1053. TreeOutline.prototype._forgetChildrenRecursive = function(parentElement)
  1054. {
  1055. var child = parentElement.children[0];
  1056. while (child) {
  1057. this._forgetTreeElement(child);
  1058. child = child.traverseNextTreeElement(false, parentElement, true);
  1059. }
  1060. }
  1061. TreeOutline.prototype.getCachedTreeElement = function(representedObject)
  1062. {
  1063. if (!representedObject)
  1064. return null;
  1065. var elements = this._treeElementsMap.get(representedObject);
  1066. if (elements && elements.length)
  1067. return elements[0];
  1068. return null;
  1069. }
  1070. TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor, getParent)
  1071. {
  1072. if (!representedObject)
  1073. return null;
  1074. var cachedElement = this.getCachedTreeElement(representedObject);
  1075. if (cachedElement)
  1076. return cachedElement;
  1077. var item;
  1078. var found = false;
  1079. for (var i = 0; i < this.children.length; ++i) {
  1080. item = this.children[i];
  1081. if (item.representedObject === representedObject || isAncestor(item.representedObject, representedObject)) {
  1082. found = true;
  1083. break;
  1084. }
  1085. }
  1086. if (!found)
  1087. return null;
  1088. var ancestors = [];
  1089. var currentObject = representedObject;
  1090. while (currentObject) {
  1091. ancestors.unshift(currentObject);
  1092. if (currentObject === item.representedObject)
  1093. break;
  1094. currentObject = getParent(currentObject);
  1095. }
  1096. for (var i = 0; i < ancestors.length; ++i) {
  1097. if (ancestors[i] === representedObject)
  1098. continue;
  1099. item = this.findTreeElement(ancestors[i], isAncestor, getParent);
  1100. if (item)
  1101. item.onpopulate();
  1102. }
  1103. return this.getCachedTreeElement(representedObject);
  1104. }
  1105. TreeOutline.prototype._treeElementDidChange = function(treeElement)
  1106. {
  1107. if (treeElement.treeOutline !== this)
  1108. return;
  1109. if (this.onchange)
  1110. this.onchange(treeElement);
  1111. }
  1112. TreeOutline.prototype.treeElementFromPoint = function(x, y)
  1113. {
  1114. var node = this._childrenListNode.ownerDocument.elementFromPoint(x, y);
  1115. if (!node)
  1116. return null;
  1117. var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(["ol", "li"]);
  1118. if (listNode)
  1119. return listNode.parentTreeElement || listNode.treeElement;
  1120. return null;
  1121. }
  1122. TreeOutline.prototype._treeKeyPress = function(event)
  1123. {
  1124. if (!this.searchable || WebInspector.isBeingEdited(this._childrenListNode))
  1125. return;
  1126. var searchText = String.fromCharCode(event.charCode);
  1127. if (searchText.trim() !== searchText)
  1128. return;
  1129. this._startSearch(searchText);
  1130. event.consume(true);
  1131. }
  1132. TreeOutline.prototype._treeKeyDown = function(event)
  1133. {
  1134. if (event.target !== this._childrenListNode)
  1135. return;
  1136. if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey)
  1137. return;
  1138. var handled = false;
  1139. var nextSelectedElement;
  1140. if (event.keyIdentifier === "Up" && !event.altKey) {
  1141. nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true);
  1142. while (nextSelectedElement && !nextSelectedElement.selectable)
  1143. nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing);
  1144. handled = nextSelectedElement ? true : false;
  1145. } else if (event.keyIdentifier === "Down" && !event.altKey) {
  1146. nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true);
  1147. while (nextSelectedElement && !nextSelectedElement.selectable)
  1148. nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing);
  1149. handled = nextSelectedElement ? true : false;
  1150. } else if (event.keyIdentifier === "Left") {
  1151. if (this.selectedTreeElement.expanded) {
  1152. if (event.altKey)
  1153. this.selectedTreeElement.collapseRecursively();
  1154. else
  1155. this.selectedTreeElement.collapse();
  1156. handled = true;
  1157. } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) {
  1158. handled = true;
  1159. if (this.selectedTreeElement.parent.selectable) {
  1160. nextSelectedElement = this.selectedTreeElement.parent;
  1161. while (nextSelectedElement && !nextSelectedElement.selectable)
  1162. nextSelectedElement = nextSelectedElement.parent;
  1163. handled = nextSelectedElement ? true : false;
  1164. } else if (this.selectedTreeElement.parent)
  1165. this.selectedTreeElement.parent.collapse();
  1166. }
  1167. } else if (event.keyIdentifier === "Right") {
  1168. if (!this.selectedTreeElement.revealed()) {
  1169. this.selectedTreeElement.reveal();
  1170. handled = true;
  1171. } else if (this.selectedTreeElement.hasChildren) {
  1172. handled = true;
  1173. if (this.selectedTreeElement.expanded) {
  1174. nextSelectedElement = this.selectedTreeElement.children[0];
  1175. while (nextSelectedElement && !nextSelectedElement.selectable)
  1176. nextSelectedElement = nextSelectedElement.nextSibling;
  1177. handled = nextSelectedElement ? true : false;
  1178. } else {
  1179. if (event.altKey)
  1180. this.selectedTreeElement.expandRecursively();
  1181. else
  1182. this.selectedTreeElement.expand();
  1183. }
  1184. }
  1185. } else if (event.keyCode === 8 || event.keyCode === 46 ) {
  1186. if (this.selectedTreeElement.ondelete)
  1187. handled = this.selectedTreeElement.ondelete();
  1188. } else if (isEnterKey(event)) {
  1189. if (this.selectedTreeElement.onenter)
  1190. handled = this.selectedTreeElement.onenter();
  1191. } else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) {
  1192. if (this.selectedTreeElement.onspace)
  1193. handled = this.selectedTreeElement.onspace();
  1194. }
  1195. if (nextSelectedElement) {
  1196. nextSelectedElement.reveal();
  1197. nextSelectedElement.select(false, true);
  1198. }
  1199. if (handled)
  1200. event.consume(true);
  1201. }
  1202. TreeOutline.prototype.expand = function()
  1203. {
  1204. }
  1205. TreeOutline.prototype.collapse = function()
  1206. {
  1207. }
  1208. TreeOutline.prototype.revealed = function()
  1209. {
  1210. return true;
  1211. }
  1212. TreeOutline.prototype.reveal = function()
  1213. {
  1214. }
  1215. TreeOutline.prototype.select = function()
  1216. {
  1217. }
  1218. TreeOutline.prototype.revealAndSelect = function(omitFocus)
  1219. {
  1220. }
  1221. TreeOutline.prototype._startSearch = function(searchText)
  1222. {
  1223. if (!this.searchInputElement || !this.searchable)
  1224. return;
  1225. this._searching = true;
  1226. if (this.searchStarted)
  1227. this.searchStarted();
  1228. this.searchInputElement.value = searchText;
  1229. function focusSearchInput()
  1230. {
  1231. this.searchInputElement.focus();
  1232. }
  1233. window.setTimeout(focusSearchInput.bind(this), 0);
  1234. this._searchTextChanged();
  1235. this._boundSearchTextChanged = this._searchTextChanged.bind(this);
  1236. this.searchInputElement.addEventListener("paste", this._boundSearchTextChanged);
  1237. this.searchInputElement.addEventListener("cut", this._boundSearchTextChanged);
  1238. this.searchInputElement.addEventListener("keypress", this._boundSearchTextChanged);
  1239. this._boundSearchInputKeyDown = this._searchInputKeyDown.bind(this);
  1240. this.searchInputElement.addEventListener("keydown", this._boundSearchInputKeyDown);
  1241. this._boundSearchInputBlur = this._searchInputBlur.bind(this);
  1242. this.searchInputElement.addEventListener("blur", this._boundSearchInputBlur);
  1243. }
  1244. TreeOutline.prototype._searchTextChanged = function()
  1245. {
  1246. function updateSearch()
  1247. {
  1248. var nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.selectedTreeElement, false);
  1249. if (!nextSelectedElement)
  1250. nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.children[0], false);
  1251. this._showSearchMatchElement(nextSelectedElement);
  1252. }
  1253. window.setTimeout(updateSearch.bind(this), 0);
  1254. }
  1255. TreeOutline.prototype._showSearchMatchElement = function(treeElement)
  1256. {
  1257. this._currentSearchMatchElement = treeElement;
  1258. if (treeElement) {
  1259. this._childrenListNode.classList.add("search-match-found");
  1260. this._childrenListNode.classList.remove("search-match-not-found");
  1261. treeElement.revealAndSelect(true);
  1262. } else {
  1263. this._childrenListNode.classList.remove("search-match-found");
  1264. this._childrenListNode.classList.add("search-match-not-found");
  1265. }
  1266. }
  1267. TreeOutline.prototype._searchInputKeyDown = function(event)
  1268. {
  1269. if (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey)
  1270. return;
  1271. var handled = false;
  1272. var nextSelectedElement;
  1273. if (event.keyIdentifier === "Down") {
  1274. nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.selectedTreeElement, true);
  1275. handled = true;
  1276. } else if (event.keyIdentifier === "Up") {
  1277. nextSelectedElement = this._previousSearchMatch(this.searchInputElement.value, this.selectedTreeElement);
  1278. handled = true;
  1279. } else if (event.keyCode === 27 ) {
  1280. this._searchFinished();
  1281. handled = true;
  1282. } else if (isEnterKey(event)) {
  1283. var lastSearchMatchElement = this._currentSearchMatchElement;
  1284. this._searchFinished();
  1285. if (lastSearchMatchElement && lastSearchMatchElement.onenter)
  1286. lastSearchMatchElement.onenter();
  1287. handled = true;
  1288. }
  1289. if (nextSelectedElement)
  1290. this._showSearchMatchElement(nextSelectedElement);
  1291. if (handled)
  1292. event.consume(true);
  1293. else
  1294. window.setTimeout(this._boundSearchTextChanged, 0);
  1295. }
  1296. TreeOutline.prototype._nextSearchMatch = function(searchText, startTreeElement, skipStartTreeElement)
  1297. {
  1298. var currentTreeElement = startTreeElement;
  1299. var skipCurrentTreeElement = skipStartTreeElement;
  1300. while (currentTreeElement && (skipCurrentTreeElement || !currentTreeElement.matchesSearchText || !currentTreeElement.matchesSearchText(searchText))) {
  1301. currentTreeElement = currentTreeElement.traverseNextTreeElement(true, null, true);
  1302. skipCurrentTreeElement = false;
  1303. }
  1304. return currentTreeElement;
  1305. }
  1306. TreeOutline.prototype._previousSearchMatch = function(searchText, startTreeElement)
  1307. {
  1308. var currentTreeElement = startTreeElement;
  1309. var skipCurrentTreeElement = true;
  1310. while (currentTreeElement && (skipCurrentTreeElement || !currentTreeElement.matchesSearchText || !currentTreeElement.matchesSearchText(searchText))) {
  1311. currentTreeElement = currentTreeElement.traversePreviousTreeElement(true, true);
  1312. skipCurrentTreeElement = false;
  1313. }
  1314. return currentTreeElement;
  1315. }
  1316. TreeOutline.prototype._searchInputBlur = function(event)
  1317. {
  1318. this._searchFinished();
  1319. }
  1320. TreeOutline.prototype._searchFinished = function()
  1321. {
  1322. if (!this._searching)
  1323. return;
  1324. delete this._searching;
  1325. this._childrenListNode.classList.remove("search-match-found");
  1326. this._childrenListNode.classList.remove("search-match-not-found");
  1327. delete this._currentSearchMatchElement;
  1328. this.searchInputElement.value = "";
  1329. this.searchInputElement.removeEventListener("paste", this._boundSearchTextChanged);
  1330. this.searchInputElement.removeEventListener("cut", this._boundSearchTextChanged);
  1331. delete this._boundSearchTextChanged;
  1332. this.searchInputElement.removeEventListener("keydown", this._boundSearchInputKeyDown);
  1333. delete this._boundSearchInputKeyDown;
  1334. this.searchInputElement.removeEventListener("blur", this._boundSearchInputBlur);
  1335. delete this._boundSearchInputBlur;
  1336. if (this.searchFinished)
  1337. this.searchFinished();
  1338. this.treeOutline._childrenListNode.focus();
  1339. }
  1340. TreeOutline.prototype.stopSearch = function()
  1341. {
  1342. this._searchFinished();
  1343. }
  1344. function TreeElement(title, representedObject, hasChildren)
  1345. {
  1346. this._title = title;
  1347. this.representedObject = (representedObject || {});
  1348. this._hidden = false;
  1349. this._selectable = true;
  1350. this.expanded = false;
  1351. this.selected = false;
  1352. this.hasChildren = hasChildren;
  1353. this.children = [];
  1354. this.treeOutline = null;
  1355. this.parent = null;
  1356. this.previousSibling = null;
  1357. this.nextSibling = null;
  1358. this._listItemNode = null;
  1359. }
  1360. TreeElement.prototype = {
  1361. arrowToggleWidth: 10,
  1362. get selectable() {
  1363. if (this._hidden)
  1364. return false;
  1365. return this._selectable;
  1366. },
  1367. set selectable(x) {
  1368. this._selectable = x;
  1369. },
  1370. get listItemElement() {
  1371. return this._listItemNode;
  1372. },
  1373. get childrenListElement() {
  1374. return this._childrenListNode;
  1375. },
  1376. get title() {
  1377. return this._title;
  1378. },
  1379. set title(x) {
  1380. this._title = x;
  1381. this._setListItemNodeContent();
  1382. this.didChange();
  1383. },
  1384. get tooltip() {
  1385. return this._tooltip;
  1386. },
  1387. set tooltip(x) {
  1388. this._tooltip = x;
  1389. if (this._listItemNode)
  1390. this._listItemNode.title = x ? x : "";
  1391. this.didChange();
  1392. },
  1393. get hasChildren() {
  1394. return this._hasChildren;
  1395. },
  1396. set hasChildren(x) {
  1397. if (this._hasChildren === x)
  1398. return;
  1399. this._hasChildren = x;
  1400. if (!this._listItemNode)
  1401. return;
  1402. if (x)
  1403. this._listItemNode.classList.add("parent");
  1404. else {
  1405. this._listItemNode.classList.remove("parent");
  1406. this.collapse();
  1407. }
  1408. this.didChange();
  1409. },
  1410. get hidden() {
  1411. return this._hidden;
  1412. },
  1413. set hidden(x) {
  1414. if (this._hidden === x)
  1415. return;
  1416. this._hidden = x;
  1417. if (x) {
  1418. if (this._listItemNode)
  1419. this._listItemNode.classList.add("hidden");
  1420. if (this._childrenListNode)
  1421. this._childrenListNode.classList.add("hidden");
  1422. } else {
  1423. if (this._listItemNode)
  1424. this._listItemNode.classList.remove("hidden");
  1425. if (this._childrenListNode)
  1426. this._childrenListNode.classList.remove("hidden");
  1427. }
  1428. },
  1429. get shouldRefreshChildren() {
  1430. return this._shouldRefreshChildren;
  1431. },
  1432. set shouldRefreshChildren(x) {
  1433. this._shouldRefreshChildren = x;
  1434. if (x && this.expanded)
  1435. this.expand();
  1436. },
  1437. _fireDidChange: function()
  1438. {
  1439. delete this._didChangeTimeoutIdentifier;
  1440. if (this.treeOutline)
  1441. this.treeOutline._treeElementDidChange(this);
  1442. },
  1443. didChange: function()
  1444. {
  1445. if (!this.treeOutline)
  1446. return;
  1447. if (!this._didChangeTimeoutIdentifier)
  1448. this._didChangeTimeoutIdentifier = setTimeout(this._fireDidChange.bind(this), 0);
  1449. },
  1450. _setListItemNodeContent: function()
  1451. {
  1452. if (!this._listItemNode)
  1453. return;
  1454. if (typeof this._title === "string")
  1455. this._listItemNode.textContent = this._title;
  1456. else {
  1457. this._listItemNode.removeChildren();
  1458. if (this._title)
  1459. this._listItemNode.appendChild(this._title);
  1460. }
  1461. }
  1462. }
  1463. TreeElement.prototype.appendChild = TreeOutline.prototype.appendChild;
  1464. TreeElement.prototype.insertChild = TreeOutline.prototype.insertChild;
  1465. TreeElement.prototype.removeChild = TreeOutline.prototype.removeChild;
  1466. TreeElement.prototype.removeChildAtIndex = TreeOutline.prototype.removeChildAtIndex;
  1467. TreeElement.prototype.removeChildren = TreeOutline.prototype.removeChildren;
  1468. TreeElement.prototype._attach = function()
  1469. {
  1470. if (!this._listItemNode || this.parent._shouldRefreshChildren) {
  1471. if (this._listItemNode && this._listItemNode.parentNode)
  1472. this._listItemNode.parentNode.removeChild(this._listItemNode);
  1473. this._listItemNode = this.treeOutline._childrenListNode.ownerDocument.createElement("li");
  1474. this._listItemNode.treeElement = this;
  1475. this._setListItemNodeContent();
  1476. this._listItemNode.title = this._tooltip ? this._tooltip : "";
  1477. if (this.hidden)
  1478. this._listItemNode.classList.add("hidden");
  1479. if (this.hasChildren)
  1480. this._listItemNode.classList.add("parent");
  1481. if (this.expanded)
  1482. this._listItemNode.classList.add("expanded");
  1483. if (this.selected)
  1484. this._listItemNode.classList.add("selected");
  1485. this._listItemNode.addEventListener("mousedown", TreeElement.treeElementMouseDown, false);
  1486. this._listItemNode.addEventListener("click", TreeElement.treeElementToggled, false);
  1487. this._listItemNode.addEventListener("dblclick", TreeElement.treeElementDoubleClicked, false);
  1488. if (this.onattach)
  1489. this.onattach(this);
  1490. }
  1491. var nextSibling = null;
  1492. if (this.nextSibling && this.nextSibling._listItemNode && this.nextSibling._listItemNode.parentNode === this.parent._childrenListNode)
  1493. nextSibling = this.nextSibling._listItemNode;
  1494. this.parent._childrenListNode.insertBefore(this._listItemNode, nextSibling);
  1495. if (this._childrenListNode)
  1496. this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling);
  1497. if (this.selected)
  1498. this.select();
  1499. if (this.expanded)
  1500. this.expand();
  1501. }
  1502. TreeElement.prototype._detach = function()
  1503. {
  1504. if (this._listItemNode && this._listItemNode.parentNode)
  1505. this._listItemNode.parentNode.removeChild(this._listItemNode);
  1506. if (this._childrenListNode && this._childrenListNode.parentNode)
  1507. this._childrenListNode.parentNode.removeChild(this._childrenListNode);
  1508. }
  1509. TreeElement.treeElementMouseDown = function(event)
  1510. {
  1511. var element = event.currentTarget;
  1512. if (!element || !element.treeElement || !element.treeElement.selectable)
  1513. return;
  1514. if (element.treeElement.isEventWithinDisclosureTriangle(event))
  1515. return;
  1516. element.treeElement.selectOnMouseDown(event);
  1517. }
  1518. TreeElement.treeElementToggled = function(event)
  1519. {
  1520. var element = event.currentTarget;
  1521. if (!element || !element.treeElement)
  1522. return;
  1523. var toggleOnClick = element.treeElement.toggleOnClick && !element.treeElement.selectable;
  1524. var isInTriangle = element.treeElement.isEventWithinDisclosureTriangle(event);
  1525. if (!toggleOnClick && !isInTriangle)
  1526. return;
  1527. if (element.treeElement.expanded) {
  1528. if (event.altKey)
  1529. element.treeElement.collapseRecursively();
  1530. else
  1531. element.treeElement.collapse();
  1532. } else {
  1533. if (event.altKey)
  1534. element.treeElement.expandRecursively();
  1535. else
  1536. element.treeElement.expand();
  1537. }
  1538. event.consume();
  1539. }
  1540. TreeElement.treeElementDoubleClicked = function(event)
  1541. {
  1542. var element = event.currentTarget;
  1543. if (!element || !element.treeElement)
  1544. return;
  1545. if (element.treeElement.ondblclick) {
  1546. var handled = element.treeElement.ondblclick.call(element.treeElement, event);
  1547. if (handled)
  1548. return;
  1549. } else if (element.treeElement.hasChildren && !element.treeElement.expanded)
  1550. element.treeElement.expand();
  1551. }
  1552. TreeElement.prototype.collapse = function()
  1553. {
  1554. if (this._listItemNode)
  1555. this._listItemNode.classList.remove("expanded");
  1556. if (this._childrenListNode)
  1557. this._childrenListNode.classList.remove("expanded");
  1558. this.expanded = false;
  1559. if (this.treeOutline)
  1560. this.treeOutline._expandedStateMap.put(this.representedObject, false);
  1561. if (this.oncollapse)
  1562. this.oncollapse(this);
  1563. }
  1564. TreeElement.prototype.collapseRecursively = function()
  1565. {
  1566. var item = this;
  1567. while (item) {
  1568. if (item.expanded)
  1569. item.collapse();
  1570. item = item.traverseNextTreeElement(false, this, true);
  1571. }
  1572. }
  1573. TreeElement.prototype.expand = function()
  1574. {
  1575. if (!this.hasChildren || (this.expanded && !this._shouldRefreshChildren && this._childrenListNode))
  1576. return;
  1577. this.expanded = true;
  1578. if (this.treeOutline)
  1579. this.treeOutline._expandedStateMap.put(this.representedObject, true);
  1580. if (this.treeOutline && (!this._childrenListNode || this._shouldRefreshChildren)) {
  1581. if (this._childrenListNode && this._childrenListNode.parentNode)
  1582. this._childrenListNode.parentNode.removeChild(this._childrenListNode);
  1583. this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol");
  1584. this._childrenListNode.parentTreeElement = this;
  1585. this._childrenListNode.classList.add("children");
  1586. if (this.hidden)
  1587. this._childrenListNode.classList.add("hidden");
  1588. this.onpopulate();
  1589. for (var i = 0; i < this.children.length; ++i)
  1590. this.children[i]._attach();
  1591. delete this._shouldRefreshChildren;
  1592. }
  1593. if (this._listItemNode) {
  1594. this._listItemNode.classList.add("expanded");
  1595. if (this._childrenListNode && this._childrenListNode.parentNode != this._listItemNode.parentNode)
  1596. this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling);
  1597. }
  1598. if (this._childrenListNode)
  1599. this._childrenListNode.classList.add("expanded");
  1600. if (this.onexpand)
  1601. this.onexpand(this);
  1602. }
  1603. TreeElement.prototype.expandRecursively = function(maxDepth)
  1604. {
  1605. var item = this;
  1606. var info = {};
  1607. var depth = 0;
  1608. if (typeof maxDepth === "undefined" || typeof maxDepth === "null")
  1609. maxDepth = 3;
  1610. while (item) {
  1611. if (depth < maxDepth)
  1612. item.expand();
  1613. item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info);
  1614. depth += info.depthChange;
  1615. }
  1616. }
  1617. TreeElement.prototype.hasAncestor = function(ancestor) {
  1618. if (!ancestor)
  1619. return false;
  1620. var currentNode = this.parent;
  1621. while (currentNode) {
  1622. if (ancestor === currentNode)
  1623. return true;
  1624. currentNode = currentNode.parent;
  1625. }
  1626. return false;
  1627. }
  1628. TreeElement.prototype.reveal = function()
  1629. {
  1630. var currentAncestor = this.parent;
  1631. while (currentAncestor && !currentAncestor.root) {
  1632. if (!currentAncestor.expanded)
  1633. currentAncestor.expand();
  1634. currentAncestor = currentAncestor.parent;
  1635. }
  1636. if (this.onreveal)
  1637. this.onreveal(this);
  1638. }
  1639. TreeElement.prototype.revealed = function()
  1640. {
  1641. var currentAncestor = this.parent;
  1642. while (currentAncestor && !currentAncestor.root) {
  1643. if (!currentAncestor.expanded)
  1644. return false;
  1645. currentAncestor = currentAncestor.parent;
  1646. }
  1647. return true;
  1648. }
  1649. TreeElement.prototype.selectOnMouseDown = function(event)
  1650. {
  1651. if (this.select(false, true))
  1652. event.consume(true);
  1653. }
  1654. TreeElement.prototype.select = function(omitFocus, selectedByUser)
  1655. {
  1656. if (!this.treeOutline || !this.selectable || this.selected)
  1657. return false;
  1658. if (this.treeOutline.selectedTreeElement)
  1659. this.treeOutline.selectedTreeElement.deselect();
  1660. this.selected = true;
  1661. if(!omitFocus)
  1662. this.treeOutline._childrenListNode.focus();
  1663. if (!this.treeOutline)
  1664. return false;
  1665. this.treeOutline.selectedTreeElement = this;
  1666. if (this._listItemNode)
  1667. this._listItemNode.classList.add("selected");
  1668. if (this.onselect)
  1669. return this.onselect(this, selectedByUser);
  1670. return false;
  1671. }
  1672. TreeElement.prototype.revealAndSelect = function(omitFocus)
  1673. {
  1674. this.reveal();
  1675. this.select(omitFocus);
  1676. }
  1677. TreeElement.prototype.deselect = function(supressOnDeselect)
  1678. {
  1679. if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected)
  1680. return false;
  1681. this.selected = false;
  1682. this.treeOutline.selectedTreeElement = null;
  1683. if (this._listItemNode)
  1684. this._listItemNode.classList.remove("selected");
  1685. if (this.ondeselect && !supressOnDeselect)
  1686. this.ondeselect(this);
  1687. return true;
  1688. }
  1689. TreeElement.prototype.onpopulate = function()
  1690. {
  1691. }
  1692. TreeElement.prototype.traverseNextTreeElement = function(skipUnrevealed, stayWithin, dontPopulate, info)
  1693. {
  1694. if (!dontPopulate && this.hasChildren)
  1695. this.onpopulate();
  1696. if (info)
  1697. info.depthChange = 0;
  1698. var element = skipUnrevealed ? (this.revealed() ? this.children[0] : null) : this.children[0];
  1699. if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) {
  1700. if (info)
  1701. info.depthChange = 1;
  1702. return element;
  1703. }
  1704. if (this === stayWithin)
  1705. return null;
  1706. element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling;
  1707. if (element)
  1708. return element;
  1709. element = this;
  1710. while (element && !element.root && !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) {
  1711. if (info)
  1712. info.depthChange -= 1;
  1713. element = element.parent;
  1714. }
  1715. if (!element)
  1716. return null;
  1717. return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling);
  1718. }
  1719. TreeElement.prototype.traversePreviousTreeElement = function(skipUnrevealed, dontPopulate)
  1720. {
  1721. var element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling;
  1722. if (!dontPopulate && element && element.hasChildren)
  1723. element.onpopulate();
  1724. while (element && (skipUnrevealed ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1])) {
  1725. if (!dontPopulate && element.hasChildren)
  1726. element.onpopulate();
  1727. element = (skipUnrevealed ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1]);
  1728. }
  1729. if (element)
  1730. return element;
  1731. if (!this.parent || this.parent.root)
  1732. return null;
  1733. return this.parent;
  1734. }
  1735. TreeElement.prototype.isEventWithinDisclosureTriangle = function(event)
  1736. {
  1737. var computedLeftPadding = window.getComputedStyle(this._listItemNode).getPropertyCSSValue("padding-left").getFloatValue(CSSPrimitiveValue.CSS_PX);
  1738. var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding;
  1739. return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren;
  1740. }
  1741. var WebInspector = {
  1742. _createPanels: function()
  1743. {
  1744. this.panels = {};
  1745. WebInspector.inspectorView = new WebInspector.InspectorView();
  1746. var parentElement = document.getElementById("main");
  1747. WebInspector.inspectorView.show(parentElement);
  1748. WebInspector.inspectorView.addEventListener(WebInspector.InspectorView.Events.PanelSelected, this._panelSelected, this);
  1749. if (WebInspector.WorkerManager.isWorkerFrontend()) {
  1750. this.panels.scripts = new WebInspector.ScriptsPanel();
  1751. this.panels.timeline = new WebInspector.TimelinePanel();
  1752. this.panels.profiles = new WebInspector.ProfilesPanel();
  1753. this.panels.console = new WebInspector.ConsolePanel();
  1754. return;
  1755. }
  1756. var hiddenPanels = (InspectorFrontendHost.hiddenPanels() || "").split(',');
  1757. if (hiddenPanels.indexOf("elements") === -1)
  1758. this.panels.elements = new WebInspector.ElementsPanel();
  1759. if (hiddenPanels.indexOf("resources") === -1)
  1760. this.panels.resources = new WebInspector.ResourcesPanel();
  1761. if (hiddenPanels.indexOf("network") === -1)
  1762. this.panels.network = new WebInspector.NetworkPanel();
  1763. if (hiddenPanels.indexOf("scripts") === -1)
  1764. this.panels.scripts = new WebInspector.ScriptsPanel();
  1765. if (hiddenPanels.indexOf("timeline") === -1)
  1766. this.panels.timeline = new WebInspector.TimelinePanel();
  1767. if (hiddenPanels.indexOf("profiles") === -1)
  1768. this.panels.profiles = new WebInspector.ProfilesPanel();
  1769. if (hiddenPanels.indexOf("audits") === -1)
  1770. this.panels.audits = new WebInspector.AuditsPanel();
  1771. if (hiddenPanels.indexOf("console") === -1)
  1772. this.panels.console = new WebInspector.ConsolePanel();
  1773. },
  1774. _panelSelected: function()
  1775. {
  1776. this._toggleConsoleButton.disabled = WebInspector.inspectorView.currentPanel() === WebInspector.panels.console;
  1777. },
  1778. _createGlobalStatusBarItems: function()
  1779. {
  1780. this._dockToggleButton = new WebInspector.StatusBarButton(this._dockButtonTitle(), "dock-status-bar-item");
  1781. this._dockToggleButton.addEventListener("click", this._toggleAttach.bind(this), false);
  1782. this._dockToggleButton.toggled = !this.attached;
  1783. WebInspector.updateDockToggleButton();
  1784. var anchoredStatusBar = document.getElementById("anchored-status-bar-items");
  1785. anchoredStatusBar.appendChild(this._dockToggleButton.element);
  1786. this._toggleConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Show console."), "console-status-bar-item");
  1787. this._toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false);
  1788. anchoredStatusBar.appendChild(this._toggleConsoleButton.element);
  1789. if (this.panels.elements)
  1790. anchoredStatusBar.appendChild(this.panels.elements.nodeSearchButton.element);
  1791. anchoredStatusBar.appendChild(this.settingsController.statusBarItem);
  1792. },
  1793. _dockButtonTitle: function()
  1794. {
  1795. return this.attached ? WebInspector.UIString("Undock into separate window.") : WebInspector.UIString("Dock to main window.");
  1796. },
  1797. _toggleAttach: function()
  1798. {
  1799. if (!this._attached) {
  1800. InspectorFrontendHost.requestAttachWindow();
  1801. WebInspector.userMetrics.WindowDocked.record();
  1802. } else {
  1803. InspectorFrontendHost.requestDetachWindow();
  1804. WebInspector.userMetrics.WindowUndocked.record();
  1805. }
  1806. },
  1807. _toggleConsoleButtonClicked: function()
  1808. {
  1809. if (this._toggleConsoleButton.disabled)
  1810. return;
  1811. this._toggleConsoleButton.toggled = !this._toggleConsoleButton.toggled;
  1812. var animationType = window.event && window.event.shiftKey ? WebInspector.Drawer.AnimationType.Slow : WebInspector.Drawer.AnimationType.Normal;
  1813. if (this._toggleConsoleButton.toggled) {
  1814. this._toggleConsoleButton.title = WebInspector.UIString("Hide console.");
  1815. this.drawer.show(this.consoleView, animationType);
  1816. this._consoleWasShown = true;
  1817. } else {
  1818. this._toggleConsoleButton.title = WebInspector.UIString("Show console.");
  1819. this.drawer.hide(animationType);
  1820. delete this._consoleWasShown;
  1821. }
  1822. },
  1823. closeDrawerView: function()
  1824. {
  1825. if (!this._consoleWasShown)
  1826. this.drawer.hide(WebInspector.Drawer.AnimationType.Immediately);
  1827. else
  1828. this._toggleConsoleButtonClicked();
  1829. },
  1830. showViewInDrawer: function(view)
  1831. {
  1832. this._toggleConsoleButton.title = WebInspector.UIString("Hide console.");
  1833. this._toggleConsoleButton.toggled = false;
  1834. this.drawer.show(view, WebInspector.Drawer.AnimationType.Immediately);
  1835. },
  1836. get attached()
  1837. {
  1838. return this._attached;
  1839. },
  1840. set attached(x)
  1841. {
  1842. if (this._attached === x)
  1843. return;
  1844. this._attached = x;
  1845. if (this._dockToggleButton) {
  1846. this._dockToggleButton.title = this._dockButtonTitle();
  1847. this._dockToggleButton.toggled = !x;
  1848. }
  1849. if (x)
  1850. document.body.removeStyleClass("detached");
  1851. else
  1852. document.body.addStyleClass("detached");
  1853. this._setCompactMode(x && !WebInspector.settings.dockToRight.get());
  1854. },
  1855. isCompactMode: function()
  1856. {
  1857. return this.attached && !WebInspector.settings.dockToRight.get();
  1858. },
  1859. _setCompactMode: function(x)
  1860. {
  1861. var body = document.body;
  1862. if (x)
  1863. body.addStyleClass("compact");
  1864. else
  1865. body.removeStyleClass("compact");
  1866. if (WebInspector.toolbar)
  1867. WebInspector.toolbar.compact = x;
  1868. if (WebInspector.searchController)
  1869. WebInspector.searchController.updateSearchLabel();
  1870. if (WebInspector.drawer)
  1871. WebInspector.drawer.resize();
  1872. },
  1873. _updateErrorAndWarningCounts: function()
  1874. {
  1875. var errorWarningElement = document.getElementById("error-warning-count");
  1876. if (!errorWarningElement)
  1877. return;
  1878. var errors = WebInspector.console.errors;
  1879. var warnings = WebInspector.console.warnings;
  1880. if (!errors && !warnings) {
  1881. errorWarningElement.addStyleClass("hidden");
  1882. return;
  1883. }
  1884. errorWarningElement.removeStyleClass("hidden");
  1885. errorWarningElement.removeChildren();
  1886. if (errors) {
  1887. var errorImageElement = document.createElement("img");
  1888. errorImageElement.id = "error-count-img";
  1889. errorWarningElement.appendChild(errorImageElement);
  1890. var errorElement = document.createElement("span");
  1891. errorElement.id = "error-count";
  1892. errorElement.textContent = errors;
  1893. errorWarningElement.appendChild(errorElement);
  1894. }
  1895. if (warnings) {
  1896. var warningsImageElement = document.createElement("img");
  1897. warningsImageElement.id = "warning-count-img";
  1898. errorWarningElement.appendChild(warningsImageElement);
  1899. var warningsElement = document.createElement("span");
  1900. warningsElement.id = "warning-count";
  1901. warningsElement.textContent = warnings;
  1902. errorWarningElement.appendChild(warningsElement);
  1903. }
  1904. if (errors) {
  1905. if (warnings) {
  1906. if (errors == 1) {
  1907. if (warnings == 1)
  1908. errorWarningElement.title = WebInspector.UIString("%d error, %d warning", errors, warnings);
  1909. else
  1910. errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", errors, warnings);
  1911. } else if (warnings == 1)
  1912. errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", errors, warnings);
  1913. else
  1914. errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", errors, warnings);
  1915. } else if (errors == 1)
  1916. errorWarningElement.title = WebInspector.UIString("%d error", errors);
  1917. else
  1918. errorWarningElement.title = WebInspector.UIString("%d errors", errors);
  1919. } else if (warnings == 1)
  1920. errorWarningElement.title = WebInspector.UIString("%d warning", warnings);
  1921. else if (warnings)
  1922. errorWarningElement.title = WebInspector.UIString("%d warnings", warnings);
  1923. else
  1924. errorWarningElement.title = null;
  1925. },
  1926. networkRequestById: function(requestId)
  1927. {
  1928. return this.panels.network.requestById(requestId);
  1929. },
  1930. get inspectedPageDomain()
  1931. {
  1932. var parsedURL = WebInspector.inspectedPageURL && WebInspector.inspectedPageURL.asParsedURL();
  1933. return parsedURL ? parsedURL.host : "";
  1934. },
  1935. _initializeCapability: function(name, callback, error, result)
  1936. {
  1937. Capabilities[name] = result;
  1938. if (callback)
  1939. callback();
  1940. },
  1941. _zoomIn: function()
  1942. {
  1943. ++this._zoomLevel;
  1944. this._requestZoom();
  1945. },
  1946. _zoomOut: function()
  1947. {
  1948. --this._zoomLevel;
  1949. this._requestZoom();
  1950. },
  1951. _resetZoom: function()
  1952. {
  1953. this._zoomLevel = 0;
  1954. this._requestZoom();
  1955. },
  1956. _requestZoom: function()
  1957. {
  1958. WebInspector.settings.zoomLevel.set(this._zoomLevel);
  1959. InspectorFrontendHost.setZoomFactor(Math.pow(1.2, this._zoomLevel));
  1960. }
  1961. }
  1962. WebInspector.Events = {
  1963. InspectorClosing: "InspectorClosing"
  1964. }
  1965. {(function parseQueryParameters()
  1966. {
  1967. WebInspector.queryParamsObject = {};
  1968. var queryParams = window.location.search;
  1969. if (!queryParams)
  1970. return;
  1971. var params = queryParams.substring(1).split("&");
  1972. for (var i = 0; i < params.length; ++i) {
  1973. var pair = params[i].split("=");
  1974. WebInspector.queryParamsObject[pair[0]] = pair[1];
  1975. }
  1976. })();}
  1977. WebInspector.loaded = function()
  1978. {
  1979. InspectorBackend.loadFromJSONIfNeeded();
  1980. var ws;
  1981. if ("ws" in WebInspector.queryParamsObject)
  1982. ws = "ws://" + WebInspector.queryParamsObject.ws;
  1983. else if ("page" in WebInspector.queryParamsObject) {
  1984. var page = WebInspector.queryParamsObject.page;
  1985. var host = "host" in WebInspector.queryParamsObject ? WebInspector.queryParamsObject.host : window.location.host;
  1986. ws = "ws://" + host + "/devtools/page/" + page;
  1987. }
  1988. if (ws) {
  1989. WebInspector.socket = new WebSocket(ws);
  1990. WebInspector.socket.onmessage = function(message) { InspectorBackend.dispatch(message.data); }
  1991. WebInspector.socket.onerror = function(error) { console.error(error); }
  1992. WebInspector.socket.onopen = function() {
  1993. InspectorFrontendHost.sendMessageToBackend = WebInspector.socket.send.bind(WebInspector.socket);
  1994. WebInspector.doLoadedDone();
  1995. }
  1996. return;
  1997. }
  1998. WebInspector.doLoadedDone();
  1999. }
  2000. WebInspector.doLoadedDone = function()
  2001. {
  2002. WebInspector.installPortStyles();
  2003. if (WebInspector.socket)
  2004. document.body.addStyleClass("remote");
  2005. if (WebInspector.queryParamsObject.toolbarColor && WebInspector.queryParamsObject.textColor)
  2006. WebInspector.setToolbarColors(WebInspector.queryParamsObject.toolbarColor, WebInspector.queryParamsObject.textColor);
  2007. InspectorFrontendHost.loaded();
  2008. WebInspector.WorkerManager.loaded();
  2009. DebuggerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "debuggerCausesRecompilation", null));
  2010. DebuggerAgent.supportsNativeBreakpoints(WebInspector._initializeCapability.bind(WebInspector, "nativeInstrumentationEnabled", null));
  2011. ProfilerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "profilerCausesRecompilation", null));
  2012. ProfilerAgent.isSampling(WebInspector._initializeCapability.bind(WebInspector, "samplingCPUProfiler", null));
  2013. ProfilerAgent.hasHeapProfiler(WebInspector._initializeCapability.bind(WebInspector, "heapProfilerPresent", null));
  2014. TimelineAgent.supportsFrameInstrumentation(WebInspector._initializeCapability.bind(WebInspector, "timelineSupportsFrameInstrumentation", null));
  2015. PageAgent.canOverrideDeviceMetrics(WebInspector._initializeCapability.bind(WebInspector, "canOverrideDeviceMetrics", WebInspector._doLoadedDoneWithCapabilities.bind(WebInspector)));
  2016. }
  2017. WebInspector._doLoadedDoneWithCapabilities = function()
  2018. {
  2019. WebInspector.shortcutsScreen = new WebInspector.ShortcutsScreen();
  2020. this._registerShortcuts();
  2021. WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
  2022. WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel"));
  2023. this.console = new WebInspector.ConsoleModel();
  2024. this.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._updateErrorAndWarningCounts, this);
  2025. this.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this);
  2026. this.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._updateErrorAndWarningCounts, this);
  2027. this.debuggerModel = new WebInspector.DebuggerModel();
  2028. this.scriptSnippetModel = new WebInspector.ScriptSnippetModel();
  2029. this.breakpointManager = new WebInspector.BreakpointManager(WebInspector.settings.breakpoints, this.debuggerModel);
  2030. this.drawer = new WebInspector.Drawer();
  2031. this.consoleView = new WebInspector.ConsoleView(WebInspector.WorkerManager.isWorkerFrontend());
  2032. this.networkManager = new WebInspector.NetworkManager();
  2033. this.resourceTreeModel = new WebInspector.ResourceTreeModel(this.networkManager);
  2034. this.networkLog = new WebInspector.NetworkLog();
  2035. this.domAgent = new WebInspector.DOMAgent();
  2036. this.javaScriptContextManager = new WebInspector.JavaScriptContextManager(this.resourceTreeModel, this.consoleView);
  2037. InspectorBackend.registerInspectorDispatcher(this);
  2038. this.cssModel = new WebInspector.CSSStyleModel();
  2039. this.timelineManager = new WebInspector.TimelineManager();
  2040. this.userAgentSupport = new WebInspector.UserAgentSupport();
  2041. InspectorBackend.registerDatabaseDispatcher(new WebInspector.DatabaseDispatcher());
  2042. InspectorBackend.registerDOMStorageDispatcher(new WebInspector.DOMStorageDispatcher());
  2043. this.searchController = new WebInspector.SearchController();
  2044. this.advancedSearchController = new WebInspector.AdvancedSearchController();
  2045. this.settingsController = new WebInspector.SettingsController();
  2046. if (Capabilities.nativeInstrumentationEnabled)
  2047. this.domBreakpointsSidebarPane = new WebInspector.DOMBreakpointsSidebarPane();
  2048. this._zoomLevel = WebInspector.settings.zoomLevel.get();
  2049. if (this._zoomLevel)
  2050. this._requestZoom();
  2051. WebInspector.CSSCompletions.requestCSSNameCompletions();
  2052. this._createPanels();
  2053. this._createGlobalStatusBarItems();
  2054. this.toolbar = new WebInspector.Toolbar();
  2055. WebInspector._installDockToRight();
  2056. for (var panelName in this.panels)
  2057. this.addPanel(this.panels[panelName]);
  2058. this.addMainEventListeners(document);
  2059. window.addEventListener("resize", this.windowResize.bind(this), true);
  2060. var errorWarningCount = document.getElementById("error-warning-count");
  2061. errorWarningCount.addEventListener("click", this.showConsole.bind(this), false);
  2062. this._updateErrorAndWarningCounts();
  2063. var autoselectPanel = WebInspector.UIString("a panel chosen automatically");
  2064. var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel);
  2065. this.openAnchorLocationRegistry = new WebInspector.HandlerRegistry(openAnchorLocationSetting);
  2066. this.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; });
  2067. this.extensionServer.initExtensions();
  2068. this.console.enableAgent();
  2069. function showInitialPanel()
  2070. {
  2071. if (!WebInspector.inspectorView.currentPanel())
  2072. WebInspector.showPanel(WebInspector.settings.lastActivePanel.get());
  2073. }
  2074. InspectorAgent.enable(showInitialPanel);
  2075. DatabaseAgent.enable();
  2076. DOMStorageAgent.enable();
  2077. if (WebInspector.settings.showPaintRects.get())
  2078. PageAgent.setShowPaintRects(true);
  2079. if (WebInspector.settings.javaScriptDisabled.get())
  2080. PageAgent.setScriptExecutionDisabled(true);
  2081. this.domAgent._emulateTouchEventsChanged();
  2082. WebInspector.WorkerManager.loadCompleted();
  2083. InspectorFrontendAPI.loadCompleted();
  2084. }
  2085. WebInspector._installDockToRight = function()
  2086. {
  2087. WebInspector.settings.dockToRight.set(WebInspector.queryParamsObject.dockSide === "right");
  2088. if (WebInspector.settings.dockToRight.get())
  2089. document.body.addStyleClass("dock-to-right");
  2090. if (WebInspector.attached)
  2091. WebInspector._setCompactMode(!WebInspector.settings.dockToRight.get());
  2092. WebInspector.settings.dockToRight.addChangeListener(listener.bind(this));
  2093. function listener(event)
  2094. {
  2095. var value = WebInspector.settings.dockToRight.get();
  2096. if (value) {
  2097. InspectorFrontendHost.requestSetDockSide("right");
  2098. document.body.addStyleClass("dock-to-right");
  2099. } else {
  2100. InspectorFrontendHost.requestSetDockSide("bottom");
  2101. document.body.removeStyleClass("dock-to-right");
  2102. }
  2103. if (WebInspector.attached)
  2104. WebInspector._setCompactMode(!value);
  2105. }
  2106. }
  2107. WebInspector.addPanel = function(panel)
  2108. {
  2109. WebInspector.inspectorView.addPanel(panel);
  2110. }
  2111. var windowLoaded = function()
  2112. {
  2113. var localizedStringsURL = InspectorFrontendHost.localizedStringsURL();
  2114. if (localizedStringsURL) {
  2115. var localizedStringsScriptElement = document.createElement("script");
  2116. localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false);
  2117. localizedStringsScriptElement.type = "text/javascript";
  2118. localizedStringsScriptElement.src = localizedStringsURL;
  2119. document.head.appendChild(localizedStringsScriptElement);
  2120. } else
  2121. WebInspector.loaded();
  2122. WebInspector.setAttachedWindow(WebInspector.queryParamsObject.docked === "true");
  2123. window.removeEventListener("DOMContentLoaded", windowLoaded, false);
  2124. delete windowLoaded;
  2125. };
  2126. window.addEventListener("DOMContentLoaded", windowLoaded, false);
  2127. var messagesToDispatch = [];
  2128. WebInspector.dispatchQueueIsEmpty = function() {
  2129. return messagesToDispatch.length == 0;
  2130. }
  2131. WebInspector.dispatch = function(message) {
  2132. messagesToDispatch.push(message);
  2133. setTimeout(function() {
  2134. InspectorBackend.dispatch(messagesToDispatch.shift());
  2135. }, 0);
  2136. }
  2137. WebInspector.dispatchMessageFromBackend = function(messageObject)
  2138. {
  2139. WebInspector.dispatch(messageObject);
  2140. }
  2141. WebInspector.windowResize = function(event)
  2142. {
  2143. WebInspector.inspectorView.doResize();
  2144. WebInspector.drawer.resize();
  2145. WebInspector.toolbar.resize();
  2146. }
  2147. WebInspector.setAttachedWindow = function(attached)
  2148. {
  2149. this.attached = attached;
  2150. WebInspector.updateDockToggleButton();
  2151. }
  2152. WebInspector.setDockingUnavailable = function(unavailable)
  2153. {
  2154. this._isDockingUnavailable = unavailable;
  2155. WebInspector.updateDockToggleButton();
  2156. }
  2157. WebInspector.updateDockToggleButton = function()
  2158. {
  2159. if (!this._dockToggleButton)
  2160. return;
  2161. this._dockToggleButton.disabled = this.attached ? false : this._isDockingUnavailable;
  2162. }
  2163. WebInspector.close = function(event)
  2164. {
  2165. if (this._isClosing)
  2166. return;
  2167. this._isClosing = true;
  2168. this.notifications.dispatchEventToListeners(WebInspector.Events.InspectorClosing);
  2169. InspectorFrontendHost.closeWindow();
  2170. }
  2171. WebInspector.documentClick = function(event)
  2172. {
  2173. var anchor = event.target.enclosingNodeOrSelfWithNodeName("a");
  2174. if (!anchor || anchor.target === "_blank")
  2175. return;
  2176. event.consume(true);
  2177. function followLink()
  2178. {
  2179. if (WebInspector.isBeingEdited(event.target) || WebInspector._showAnchorLocation(anchor))
  2180. return;
  2181. const profileMatch = WebInspector.ProfileType.URLRegExp.exec(anchor.href);
  2182. if (profileMatch) {
  2183. WebInspector.showProfileForURL(anchor.href);
  2184. return;
  2185. }
  2186. var parsedURL = anchor.href.asParsedURL();
  2187. if (parsedURL && parsedURL.scheme === "webkit-link-action") {
  2188. if (parsedURL.host === "show-panel") {
  2189. var panel = parsedURL.path.substring(1);
  2190. if (WebInspector.panels[panel])
  2191. WebInspector.showPanel(panel);
  2192. }
  2193. return;
  2194. }
  2195. WebInspector.showPanel("resources");
  2196. }
  2197. if (WebInspector.followLinkTimeout)
  2198. clearTimeout(WebInspector.followLinkTimeout);
  2199. if (anchor.preventFollowOnDoubleClick) {
  2200. if (event.detail === 1)
  2201. WebInspector.followLinkTimeout = setTimeout(followLink, 333);
  2202. return;
  2203. }
  2204. followLink();
  2205. }
  2206. WebInspector.openResource = function(resourceURL, inResourcesPanel)
  2207. {
  2208. var resource = WebInspector.resourceForURL(resourceURL);
  2209. if (inResourcesPanel && resource) {
  2210. WebInspector.showPanel("resources");
  2211. WebInspector.panels.resources.showResource(resource);
  2212. } else
  2213. InspectorFrontendHost.openInNewTab(resourceURL);
  2214. }
  2215. WebInspector.openRequestInNetworkPanel = function(request)
  2216. {
  2217. WebInspector.showPanel("network");
  2218. WebInspector.panels.network.revealAndHighlightRequest(request);
  2219. }
  2220. WebInspector._registerShortcuts = function()
  2221. {
  2222. var shortcut = WebInspector.KeyboardShortcut;
  2223. var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("All Panels"));
  2224. var keys = [
  2225. shortcut.shortcutToString("]", shortcut.Modifiers.CtrlOrMeta),
  2226. shortcut.shortcutToString("[", shortcut.Modifiers.CtrlOrMeta)
  2227. ];
  2228. section.addRelatedKeys(keys, WebInspector.UIString("Go to the panel to the left/right"));
  2229. var keys = [
  2230. shortcut.shortcutToString("[", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt),
  2231. shortcut.shortcutToString("]", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt)
  2232. ];
  2233. section.addRelatedKeys(keys, WebInspector.UIString("Go back/forward in panel history"));
  2234. section.addKey(shortcut.shortcutToString(shortcut.Keys.Esc), WebInspector.UIString("Toggle console"));
  2235. section.addKey(shortcut.shortcutToString("f", shortcut.Modifiers.CtrlOrMeta), WebInspector.UIString("Search"));
  2236. var advancedSearchShortcut = WebInspector.AdvancedSearchController.createShortcut();
  2237. section.addKey(advancedSearchShortcut.name, WebInspector.UIString("Search across all sources"));
  2238. if (WebInspector.isMac()) {
  2239. keys = [
  2240. shortcut.shortcutToString("g", shortcut.Modifiers.Meta),
  2241. shortcut.shortcutToString("g", shortcut.Modifiers.Meta | shortcut.Modifiers.Shift)
  2242. ];
  2243. section.addRelatedKeys(keys, WebInspector.UIString("Find next/previous"));
  2244. }
  2245. var goToShortcut = WebInspector.GoToLineDialog.createShortcut();
  2246. section.addKey(goToShortcut.name, WebInspector.UIString("Go to line"));
  2247. }
  2248. WebInspector.documentKeyDown = function(event)
  2249. {
  2250. const helpKey = WebInspector.isMac() ? "U+003F" : "U+00BF";
  2251. if (event.keyIdentifier === "F1" ||
  2252. (event.keyIdentifier === helpKey && event.shiftKey && (!WebInspector.isBeingEdited(event.target) || event.metaKey))) {
  2253. WebInspector.shortcutsScreen.showModal();
  2254. event.consume(true);
  2255. return;
  2256. }
  2257. if (WebInspector.currentFocusElement() && WebInspector.currentFocusElement().handleKeyEvent) {
  2258. WebInspector.currentFocusElement().handleKeyEvent(event);
  2259. if (event.handled) {
  2260. event.consume(true);
  2261. return;
  2262. }
  2263. }
  2264. if (WebInspector.inspectorView.currentPanel()) {
  2265. WebInspector.inspectorView.currentPanel().handleShortcut(event);
  2266. if (event.handled) {
  2267. event.consume(true);
  2268. return;
  2269. }
  2270. }
  2271. WebInspector.searchController.handleShortcut(event);
  2272. WebInspector.advancedSearchController.handleShortcut(event);
  2273. if (event.handled) {
  2274. event.consume(true);
  2275. return;
  2276. }
  2277. var isMac = WebInspector.isMac();
  2278. switch (event.keyIdentifier) {
  2279. case "U+0052":
  2280. if ((event.metaKey && isMac) || (event.ctrlKey && !isMac)) {
  2281. PageAgent.reload(event.shiftKey);
  2282. event.consume(true);
  2283. }
  2284. break;
  2285. case "F5":
  2286. if (!isMac) {
  2287. PageAgent.reload(event.ctrlKey || event.shiftKey);
  2288. event.consume(true);
  2289. }
  2290. break;
  2291. }
  2292. var isValidZoomShortcut = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) &&
  2293. !event.shiftKey &&
  2294. !event.altKey &&
  2295. !InspectorFrontendHost.isStub;
  2296. switch (event.keyCode) {
  2297. case 107:
  2298. case 187:
  2299. if (isValidZoomShortcut) {
  2300. WebInspector._zoomIn();
  2301. event.consume(true);
  2302. }
  2303. break;
  2304. case 109:
  2305. case 189:
  2306. if (isValidZoomShortcut) {
  2307. WebInspector._zoomOut();
  2308. event.consume(true);
  2309. }
  2310. break;
  2311. case 48:
  2312. if (isValidZoomShortcut) {
  2313. WebInspector._resetZoom();
  2314. event.consume(true);
  2315. }
  2316. break;
  2317. }
  2318. }
  2319. WebInspector.postDocumentKeyDown = function(event)
  2320. {
  2321. if (event.handled)
  2322. return;
  2323. if (event.keyIdentifier === "U+001B") {
  2324. if (!this._toggleConsoleButton.toggled && WebInspector.drawer.visible)
  2325. this.closeDrawerView();
  2326. else
  2327. this._toggleConsoleButtonClicked();
  2328. }
  2329. }
  2330. WebInspector.documentCanCopy = function(event)
  2331. {
  2332. if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent)
  2333. event.preventDefault();
  2334. }
  2335. WebInspector.documentCopy = function(event)
  2336. {
  2337. if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent)
  2338. WebInspector.inspectorView.currentPanel().handleCopyEvent(event);
  2339. WebInspector.documentCopyEventFired(event);
  2340. }
  2341. WebInspector.documentCopyEventFired = function(event)
  2342. {
  2343. }
  2344. WebInspector.contextMenuEventFired = function(event)
  2345. {
  2346. if (event.handled || event.target.hasStyleClass("popup-glasspane"))
  2347. event.preventDefault();
  2348. }
  2349. WebInspector.toggleSearchingForNode = function()
  2350. {
  2351. if (this.panels.elements) {
  2352. this.showPanel("elements");
  2353. this.panels.elements.toggleSearchingForNode();
  2354. }
  2355. }
  2356. WebInspector.showConsole = function()
  2357. {
  2358. if (WebInspector._toggleConsoleButton && !WebInspector._toggleConsoleButton.toggled)
  2359. WebInspector._toggleConsoleButtonClicked();
  2360. }
  2361. WebInspector.showPanel = function(panel)
  2362. {
  2363. if (!(panel in this.panels)) {
  2364. if (WebInspector.WorkerManager.isWorkerFrontend())
  2365. panel = "scripts";
  2366. else
  2367. panel = "elements";
  2368. }
  2369. WebInspector.inspectorView.setCurrentPanel(this.panels[panel]);
  2370. }
  2371. WebInspector.bringToFront = function()
  2372. {
  2373. InspectorFrontendHost.bringToFront();
  2374. }
  2375. WebInspector.didCreateWorker = function()
  2376. {
  2377. var workersPane = WebInspector.panels.scripts.sidebarPanes.workers;
  2378. if (workersPane)
  2379. workersPane.addWorker.apply(workersPane, arguments);
  2380. }
  2381. WebInspector.didDestroyWorker = function()
  2382. {
  2383. var workersPane = WebInspector.panels.scripts.sidebarPanes.workers;
  2384. if (workersPane)
  2385. workersPane.removeWorker.apply(workersPane, arguments);
  2386. }
  2387. WebInspector.log = function(message, messageLevel, showConsole)
  2388. {
  2389. var self = this;
  2390. function isLogAvailable()
  2391. {
  2392. return WebInspector.ConsoleMessage && WebInspector.RemoteObject && self.console;
  2393. }
  2394. function flushQueue()
  2395. {
  2396. var queued = WebInspector.log.queued;
  2397. if (!queued)
  2398. return;
  2399. for (var i = 0; i < queued.length; ++i)
  2400. logMessage(queued[i]);
  2401. delete WebInspector.log.queued;
  2402. }
  2403. function flushQueueIfAvailable()
  2404. {
  2405. if (!isLogAvailable())
  2406. return;
  2407. clearInterval(WebInspector.log.interval);
  2408. delete WebInspector.log.interval;
  2409. flushQueue();
  2410. }
  2411. function logMessage(message)
  2412. {
  2413. var msg = WebInspector.ConsoleMessage.create(
  2414. WebInspector.ConsoleMessage.MessageSource.Other,
  2415. messageLevel || WebInspector.ConsoleMessage.MessageLevel.Debug,
  2416. message);
  2417. self.console.addMessage(msg);
  2418. if (showConsole)
  2419. WebInspector.showConsole();
  2420. }
  2421. if (!isLogAvailable()) {
  2422. if (!WebInspector.log.queued)
  2423. WebInspector.log.queued = [];
  2424. WebInspector.log.queued.push(message);
  2425. if (!WebInspector.log.interval)
  2426. WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000);
  2427. return;
  2428. }
  2429. flushQueue();
  2430. logMessage(message);
  2431. }
  2432. WebInspector.inspect = function(payload, hints)
  2433. {
  2434. var object = WebInspector.RemoteObject.fromPayload(payload);
  2435. if (object.subtype === "node") {
  2436. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.elements);
  2437. object.pushNodeToFrontend(WebInspector.updateFocusedNode.bind(WebInspector), object.release.bind(object));
  2438. return;
  2439. }
  2440. if (hints.databaseId) {
  2441. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.resources);
  2442. WebInspector.panels.resources.selectDatabase(hints.databaseId);
  2443. } else if (hints.domStorageId) {
  2444. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.resources);
  2445. WebInspector.panels.resources.selectDOMStorage(hints.domStorageId);
  2446. }
  2447. object.release();
  2448. }
  2449. WebInspector.updateFocusedNode = function(nodeId)
  2450. {
  2451. this.panels.elements.revealAndSelectNode(nodeId);
  2452. }
  2453. WebInspector.populateResourceContextMenu = function(contextMenu, url, preferredLineNumber)
  2454. {
  2455. var registry = WebInspector.openAnchorLocationRegistry;
  2456. for (var i = 1; i < registry.handlerNames.length; ++i) {
  2457. var handler = registry.handlerNames[i];
  2458. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open using %s" : "Open Using %s", handler),
  2459. registry.dispatchToHandler.bind(registry, handler, { url: url, preferredLineNumber: preferredLineNumber }));
  2460. }
  2461. }
  2462. WebInspector._showAnchorLocation = function(anchor)
  2463. {
  2464. if (WebInspector.openAnchorLocationRegistry.dispatch({ url: anchor.href, lineNumber: anchor.lineNumber}))
  2465. return true;
  2466. var preferedPanel = this.panels[anchor.preferredPanel || "resources"];
  2467. if (WebInspector._showAnchorLocationInPanel(anchor, preferedPanel))
  2468. return true;
  2469. if (preferedPanel !== this.panels.resources && WebInspector._showAnchorLocationInPanel(anchor, this.panels.resources))
  2470. return true;
  2471. return false;
  2472. }
  2473. WebInspector._showAnchorLocationInPanel = function(anchor, panel)
  2474. {
  2475. if (!panel || !panel.canShowAnchorLocation(anchor))
  2476. return false;
  2477. if (anchor.hasStyleClass("webkit-html-external-link")) {
  2478. anchor.removeStyleClass("webkit-html-external-link");
  2479. anchor.addStyleClass("webkit-html-resource-link");
  2480. }
  2481. this.showPanelForAnchorNavigation(panel);
  2482. panel.showAnchorLocation(anchor);
  2483. return true;
  2484. }
  2485. WebInspector.showPanelForAnchorNavigation = function(panel)
  2486. {
  2487. WebInspector.searchController.disableSearchUntilExplicitAction();
  2488. WebInspector.inspectorView.setCurrentPanel(panel);
  2489. }
  2490. WebInspector.showProfileForURL = function(url)
  2491. {
  2492. WebInspector.showPanel("profiles");
  2493. WebInspector.panels.profiles.showProfileForURL(url);
  2494. }
  2495. WebInspector.evaluateInConsole = function(expression, showResultOnly)
  2496. {
  2497. this.showConsole();
  2498. this.consoleView.evaluateUsingTextPrompt(expression, showResultOnly);
  2499. }
  2500. WebInspector.addMainEventListeners = function(doc)
  2501. {
  2502. doc.addEventListener("keydown", this.documentKeyDown.bind(this), true);
  2503. doc.addEventListener("keydown", this.postDocumentKeyDown.bind(this), false);
  2504. doc.addEventListener("beforecopy", this.documentCanCopy.bind(this), true);
  2505. doc.addEventListener("copy", this.documentCopy.bind(this), true);
  2506. doc.addEventListener("contextmenu", this.contextMenuEventFired.bind(this), true);
  2507. doc.addEventListener("click", this.documentClick.bind(this), true);
  2508. }
  2509. WebInspector.frontendReused = function()
  2510. {
  2511. this.resourceTreeModel.frontendReused();
  2512. }
  2513. WebInspector._toolbarItemClicked = function(event)
  2514. {
  2515. var toolbarItem = event.currentTarget;
  2516. WebInspector.inspectorView.setCurrentPanel(toolbarItem.panel);
  2517. }
  2518. WebInspector.elementDragStart = function(element, dividerDrag, elementDragEnd, event, cursor)
  2519. {
  2520. if (WebInspector._elementDraggingEventListener || WebInspector._elementEndDraggingEventListener)
  2521. WebInspector.elementDragEnd(event);
  2522. if (element) {
  2523. if (WebInspector._elementDraggingGlassPane)
  2524. WebInspector._elementDraggingGlassPane.parentElement.removeChild(WebInspector._elementDraggingGlassPane);
  2525. var glassPane = document.createElement("div");
  2526. glassPane.style.cssText = "position:absolute;top:0;bottom:0;left:0;right:0;opacity:0;z-index:1";
  2527. glassPane.id = "glass-pane-for-drag";
  2528. element.ownerDocument.body.appendChild(glassPane);
  2529. WebInspector._elementDraggingGlassPane = glassPane;
  2530. }
  2531. WebInspector._elementDraggingEventListener = dividerDrag;
  2532. WebInspector._elementEndDraggingEventListener = elementDragEnd;
  2533. var targetDocument = event.target.ownerDocument;
  2534. targetDocument.addEventListener("mousemove", dividerDrag, true);
  2535. targetDocument.addEventListener("mouseup", elementDragEnd, true);
  2536. targetDocument.body.style.cursor = cursor;
  2537. event.preventDefault();
  2538. }
  2539. WebInspector.elementDragEnd = function(event)
  2540. {
  2541. var targetDocument = event.target.ownerDocument;
  2542. targetDocument.removeEventListener("mousemove", WebInspector._elementDraggingEventListener, true);
  2543. targetDocument.removeEventListener("mouseup", WebInspector._elementEndDraggingEventListener, true);
  2544. targetDocument.body.style.removeProperty("cursor");
  2545. if (WebInspector._elementDraggingGlassPane)
  2546. WebInspector._elementDraggingGlassPane.parentElement.removeChild(WebInspector._elementDraggingGlassPane);
  2547. delete WebInspector._elementDraggingGlassPane;
  2548. delete WebInspector._elementDraggingEventListener;
  2549. delete WebInspector._elementEndDraggingEventListener;
  2550. event.preventDefault();
  2551. }
  2552. WebInspector.animateStyle = function(animations, duration, callback)
  2553. {
  2554. var interval;
  2555. var complete = 0;
  2556. var hasCompleted = false;
  2557. const intervalDuration = (1000 / 30);
  2558. const animationsLength = animations.length;
  2559. const propertyUnit = {opacity: ""};
  2560. const defaultUnit = "px";
  2561. function cubicInOut(t, b, c, d)
  2562. {
  2563. if ((t/=d/2) < 1) return c/2*t*t*t + b;
  2564. return c/2*((t-=2)*t*t + 2) + b;
  2565. }
  2566. for (var i = 0; i < animationsLength; ++i) {
  2567. var animation = animations[i];
  2568. var element = null, start = null, end = null, key = null;
  2569. for (key in animation) {
  2570. if (key === "element")
  2571. element = animation[key];
  2572. else if (key === "start")
  2573. start = animation[key];
  2574. else if (key === "end")
  2575. end = animation[key];
  2576. }
  2577. if (!element || !end)
  2578. continue;
  2579. if (!start) {
  2580. var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element);
  2581. start = {};
  2582. for (key in end)
  2583. start[key] = parseInt(computedStyle.getPropertyValue(key), 10);
  2584. animation.start = start;
  2585. } else
  2586. for (key in start)
  2587. element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
  2588. }
  2589. function animateLoop()
  2590. {
  2591. if (hasCompleted)
  2592. return;
  2593. complete += intervalDuration;
  2594. var next = complete + intervalDuration;
  2595. for (var i = 0; i < animationsLength; ++i) {
  2596. var animation = animations[i];
  2597. var element = animation.element;
  2598. var start = animation.start;
  2599. var end = animation.end;
  2600. if (!element || !end)
  2601. continue;
  2602. var style = element.style;
  2603. for (key in end) {
  2604. var endValue = end[key];
  2605. if (next < duration) {
  2606. var startValue = start[key];
  2607. var newValue = cubicInOut(complete, startValue, endValue - startValue, duration);
  2608. style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
  2609. } else
  2610. style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit));
  2611. }
  2612. }
  2613. if (complete >= duration) {
  2614. hasCompleted = true;
  2615. clearInterval(interval);
  2616. if (callback)
  2617. callback();
  2618. }
  2619. }
  2620. function forceComplete()
  2621. {
  2622. if (hasCompleted)
  2623. return;
  2624. complete = duration;
  2625. animateLoop();
  2626. }
  2627. function cancel()
  2628. {
  2629. hasCompleted = true;
  2630. clearInterval(interval);
  2631. }
  2632. interval = setInterval(animateLoop, intervalDuration);
  2633. return {
  2634. cancel: cancel,
  2635. forceComplete: forceComplete
  2636. };
  2637. }
  2638. WebInspector.isBeingEdited = function(element)
  2639. {
  2640. if (element.hasStyleClass("text-prompt") || element.nodeName === "INPUT")
  2641. return true;
  2642. if (!WebInspector.__editingCount)
  2643. return false;
  2644. while (element) {
  2645. if (element.__editing)
  2646. return true;
  2647. element = element.parentElement;
  2648. }
  2649. return false;
  2650. }
  2651. WebInspector.markBeingEdited = function(element, value)
  2652. {
  2653. if (value) {
  2654. if (element.__editing)
  2655. return false;
  2656. element.__editing = true;
  2657. WebInspector.__editingCount = (WebInspector.__editingCount || 0) + 1;
  2658. } else {
  2659. if (!element.__editing)
  2660. return false;
  2661. delete element.__editing;
  2662. --WebInspector.__editingCount;
  2663. }
  2664. return true;
  2665. }
  2666. WebInspector.EditingConfig = function(commitHandler, cancelHandler, context)
  2667. {
  2668. this.commitHandler = commitHandler;
  2669. this.cancelHandler = cancelHandler
  2670. this.context = context;
  2671. this.pasteHandler;
  2672. this.multiline;
  2673. this.customFinishHandler;
  2674. }
  2675. WebInspector.EditingConfig.prototype = {
  2676. setPasteHandler: function(pasteHandler)
  2677. {
  2678. this.pasteHandler = pasteHandler;
  2679. },
  2680. setMultiline: function(multiline)
  2681. {
  2682. this.multiline = multiline;
  2683. },
  2684. setCustomFinishHandler: function(customFinishHandler)
  2685. {
  2686. this.customFinishHandler = customFinishHandler;
  2687. }
  2688. }
  2689. WebInspector.startEditing = function(element, config)
  2690. {
  2691. if (!WebInspector.markBeingEdited(element, true))
  2692. return null;
  2693. config = config || new WebInspector.EditingConfig(function() {}, function() {});
  2694. var committedCallback = config.commitHandler;
  2695. var cancelledCallback = config.cancelHandler;
  2696. var pasteCallback = config.pasteHandler;
  2697. var context = config.context;
  2698. var oldText = getContent(element);
  2699. var moveDirection = "";
  2700. element.addStyleClass("editing");
  2701. var oldTabIndex = element.getAttribute("tabIndex");
  2702. if (typeof oldTabIndex !== "number" || oldTabIndex < 0)
  2703. element.tabIndex = 0;
  2704. function blurEventListener() {
  2705. editingCommitted.call(element);
  2706. }
  2707. function getContent(element) {
  2708. if (element.tagName === "INPUT" && element.type === "text")
  2709. return element.value;
  2710. else
  2711. return element.textContent;
  2712. }
  2713. function cleanUpAfterEditing()
  2714. {
  2715. WebInspector.markBeingEdited(element, false);
  2716. this.removeStyleClass("editing");
  2717. if (typeof oldTabIndex !== "number")
  2718. element.removeAttribute("tabIndex");
  2719. else
  2720. this.tabIndex = oldTabIndex;
  2721. this.scrollTop = 0;
  2722. this.scrollLeft = 0;
  2723. element.removeEventListener("blur", blurEventListener, false);
  2724. element.removeEventListener("keydown", keyDownEventListener, true);
  2725. if (pasteCallback)
  2726. element.removeEventListener("paste", pasteEventListener, true);
  2727. WebInspector.restoreFocusFromElement(element);
  2728. }
  2729. function editingCancelled()
  2730. {
  2731. if (this.tagName === "INPUT" && this.type === "text")
  2732. this.value = oldText;
  2733. else
  2734. this.textContent = oldText;
  2735. cleanUpAfterEditing.call(this);
  2736. cancelledCallback(this, context);
  2737. }
  2738. function editingCommitted()
  2739. {
  2740. cleanUpAfterEditing.call(this);
  2741. committedCallback(this, getContent(this), oldText, context, moveDirection);
  2742. }
  2743. function defaultFinishHandler(event)
  2744. {
  2745. var isMetaOrCtrl = WebInspector.isMac() ?
  2746. event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey :
  2747. event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey;
  2748. if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl))
  2749. return "commit";
  2750. else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B")
  2751. return "cancel";
  2752. else if (event.keyIdentifier === "U+0009")
  2753. return "move-" + (event.shiftKey ? "backward" : "forward");
  2754. }
  2755. function handleEditingResult(result, event)
  2756. {
  2757. if (result === "commit") {
  2758. editingCommitted.call(element);
  2759. event.consume(true);
  2760. } else if (result === "cancel") {
  2761. editingCancelled.call(element);
  2762. event.consume(true);
  2763. } else if (result && result.startsWith("move-")) {
  2764. moveDirection = result.substring(5);
  2765. if (event.keyIdentifier !== "U+0009")
  2766. blurEventListener();
  2767. }
  2768. }
  2769. function pasteEventListener(event)
  2770. {
  2771. var result = pasteCallback(event);
  2772. handleEditingResult(result, event);
  2773. }
  2774. function keyDownEventListener(event)
  2775. {
  2776. var handler = config.customFinishHandler || defaultFinishHandler;
  2777. var result = handler(event);
  2778. handleEditingResult(result, event);
  2779. }
  2780. element.addEventListener("blur", blurEventListener, false);
  2781. element.addEventListener("keydown", keyDownEventListener, true);
  2782. if (pasteCallback)
  2783. element.addEventListener("paste", pasteEventListener, true);
  2784. WebInspector.setCurrentFocusElement(element);
  2785. return {
  2786. cancel: editingCancelled.bind(element),
  2787. commit: editingCommitted.bind(element)
  2788. };
  2789. }
  2790. Number.secondsToString = function(seconds, higherResolution)
  2791. {
  2792. if (seconds === 0)
  2793. return "0";
  2794. var ms = seconds * 1000;
  2795. if (higherResolution && ms < 1000)
  2796. return WebInspector.UIString("%.3fms", ms);
  2797. else if (ms < 1000)
  2798. return WebInspector.UIString("%.0fms", ms);
  2799. if (seconds < 60)
  2800. return WebInspector.UIString("%.2fs", seconds);
  2801. var minutes = seconds / 60;
  2802. if (minutes < 60)
  2803. return WebInspector.UIString("%.1fmin", minutes);
  2804. var hours = minutes / 60;
  2805. if (hours < 24)
  2806. return WebInspector.UIString("%.1fhrs", hours);
  2807. var days = hours / 24;
  2808. return WebInspector.UIString("%.1f days", days);
  2809. }
  2810. Number.bytesToString = function(bytes, higherResolution)
  2811. {
  2812. if (typeof higherResolution === "undefined")
  2813. higherResolution = true;
  2814. if (bytes < 1024)
  2815. return WebInspector.UIString("%.0fB", bytes);
  2816. var kilobytes = bytes / 1024;
  2817. if (higherResolution && kilobytes < 1024)
  2818. return WebInspector.UIString("%.2fKB", kilobytes);
  2819. else if (kilobytes < 1024)
  2820. return WebInspector.UIString("%.0fKB", kilobytes);
  2821. var megabytes = kilobytes / 1024;
  2822. if (higherResolution)
  2823. return WebInspector.UIString("%.2fMB", megabytes);
  2824. else
  2825. return WebInspector.UIString("%.0fMB", megabytes);
  2826. }
  2827. Number.withThousandsSeparator = function(num)
  2828. {
  2829. var str = num + "";
  2830. var re = /(\d+)(\d{3})/;
  2831. while (str.match(re))
  2832. str = str.replace(re, "$1\u2009$2");
  2833. return str;
  2834. }
  2835. WebInspector._missingLocalizedStrings = {};
  2836. WebInspector.UIString = function(string, vararg)
  2837. {
  2838. if (Preferences.localizeUI) {
  2839. if (window.localizedStrings && string in window.localizedStrings)
  2840. string = window.localizedStrings[string];
  2841. else {
  2842. if (!(string in WebInspector._missingLocalizedStrings)) {
  2843. console.warn("Localized string \"" + string + "\" not found.");
  2844. WebInspector._missingLocalizedStrings[string] = true;
  2845. }
  2846. if (Preferences.showMissingLocalizedStrings)
  2847. string += " (not localized)";
  2848. }
  2849. }
  2850. return String.vsprintf(string, Array.prototype.slice.call(arguments, 1));
  2851. }
  2852. WebInspector.useLowerCaseMenuTitles = function()
  2853. {
  2854. return WebInspector.platform() === "windows" && Preferences.useLowerCaseMenuTitlesOnWindows;
  2855. }
  2856. WebInspector.formatLocalized = function(format, substitutions, formatters, initialValue, append)
  2857. {
  2858. return String.format(WebInspector.UIString(format), substitutions, formatters, initialValue, append);
  2859. }
  2860. WebInspector.openLinkExternallyLabel = function()
  2861. {
  2862. return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open link in new tab" : "Open Link in New Tab");
  2863. }
  2864. WebInspector.openInNetworkPanelLabel = function()
  2865. {
  2866. return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open in network panel" : "Open in Network Panel");
  2867. }
  2868. WebInspector.copyLinkAddressLabel = function()
  2869. {
  2870. return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy link address" : "Copy Link Address");
  2871. }
  2872. WebInspector.platform = function()
  2873. {
  2874. if (!WebInspector._platform)
  2875. WebInspector._platform = InspectorFrontendHost.platform();
  2876. return WebInspector._platform;
  2877. }
  2878. WebInspector.isMac = function()
  2879. {
  2880. if (typeof WebInspector._isMac === "undefined")
  2881. WebInspector._isMac = WebInspector.platform() === "mac";
  2882. return WebInspector._isMac;
  2883. }
  2884. WebInspector.PlatformFlavor = {
  2885. WindowsVista: "windows-vista",
  2886. MacTiger: "mac-tiger",
  2887. MacLeopard: "mac-leopard",
  2888. MacSnowLeopard: "mac-snowleopard"
  2889. }
  2890. WebInspector.platformFlavor = function()
  2891. {
  2892. function detectFlavor()
  2893. {
  2894. const userAgent = navigator.userAgent;
  2895. if (WebInspector.platform() === "windows") {
  2896. var match = userAgent.match(/Windows NT (\d+)\.(?:\d+)/);
  2897. if (match && match[1] >= 6)
  2898. return WebInspector.PlatformFlavor.WindowsVista;
  2899. return null;
  2900. } else if (WebInspector.platform() === "mac") {
  2901. var match = userAgent.match(/Mac OS X\s*(?:(\d+)_(\d+))?/);
  2902. if (!match || match[1] != 10)
  2903. return WebInspector.PlatformFlavor.MacSnowLeopard;
  2904. switch (Number(match[2])) {
  2905. case 4:
  2906. return WebInspector.PlatformFlavor.MacTiger;
  2907. case 5:
  2908. return WebInspector.PlatformFlavor.MacLeopard;
  2909. case 6:
  2910. default:
  2911. return WebInspector.PlatformFlavor.MacSnowLeopard;
  2912. }
  2913. }
  2914. }
  2915. if (!WebInspector._platformFlavor)
  2916. WebInspector._platformFlavor = detectFlavor();
  2917. return WebInspector._platformFlavor;
  2918. }
  2919. WebInspector.port = function()
  2920. {
  2921. if (!WebInspector._port)
  2922. WebInspector._port = InspectorFrontendHost.port();
  2923. return WebInspector._port;
  2924. }
  2925. WebInspector.installPortStyles = function()
  2926. {
  2927. var platform = WebInspector.platform();
  2928. document.body.addStyleClass("platform-" + platform);
  2929. var flavor = WebInspector.platformFlavor();
  2930. if (flavor)
  2931. document.body.addStyleClass("platform-" + flavor);
  2932. var port = WebInspector.port();
  2933. document.body.addStyleClass("port-" + port);
  2934. }
  2935. WebInspector._windowFocused = function(event)
  2936. {
  2937. if (event.target.document.nodeType === Node.DOCUMENT_NODE)
  2938. document.body.removeStyleClass("inactive");
  2939. }
  2940. WebInspector._windowBlurred = function(event)
  2941. {
  2942. if (event.target.document.nodeType === Node.DOCUMENT_NODE)
  2943. document.body.addStyleClass("inactive");
  2944. }
  2945. WebInspector.previousFocusElement = function()
  2946. {
  2947. return WebInspector._previousFocusElement;
  2948. }
  2949. WebInspector.currentFocusElement = function()
  2950. {
  2951. return WebInspector._currentFocusElement;
  2952. }
  2953. WebInspector._focusChanged = function(event)
  2954. {
  2955. WebInspector.setCurrentFocusElement(event.target);
  2956. }
  2957. WebInspector._textInputTypes = ["text", "search", "tel", "url", "email", "password"].keySet();
  2958. WebInspector._isTextEditingElement = function(element)
  2959. {
  2960. if (element instanceof HTMLInputElement)
  2961. return element.type in WebInspector._textInputTypes;
  2962. if (element instanceof HTMLTextAreaElement)
  2963. return true;
  2964. return false;
  2965. }
  2966. WebInspector.setCurrentFocusElement = function(x)
  2967. {
  2968. if (WebInspector._currentFocusElement !== x)
  2969. WebInspector._previousFocusElement = WebInspector._currentFocusElement;
  2970. WebInspector._currentFocusElement = x;
  2971. if (WebInspector._currentFocusElement) {
  2972. WebInspector._currentFocusElement.focus();
  2973. var selection = window.getSelection();
  2974. if (!WebInspector._isTextEditingElement(WebInspector._currentFocusElement) && selection.isCollapsed && !WebInspector._currentFocusElement.isInsertionCaretInside()) {
  2975. var selectionRange = WebInspector._currentFocusElement.ownerDocument.createRange();
  2976. selectionRange.setStart(WebInspector._currentFocusElement, 0);
  2977. selectionRange.setEnd(WebInspector._currentFocusElement, 0);
  2978. selection.removeAllRanges();
  2979. selection.addRange(selectionRange);
  2980. }
  2981. } else if (WebInspector._previousFocusElement)
  2982. WebInspector._previousFocusElement.blur();
  2983. }
  2984. WebInspector.restoreFocusFromElement = function(element)
  2985. {
  2986. if (element && element.isSelfOrAncestor(WebInspector.currentFocusElement()))
  2987. WebInspector.setCurrentFocusElement(WebInspector.previousFocusElement());
  2988. }
  2989. WebInspector.setToolbarColors = function(backgroundColor, color)
  2990. {
  2991. if (!WebInspector._themeStyleElement) {
  2992. WebInspector._themeStyleElement = document.createElement("style");
  2993. document.head.appendChild(WebInspector._themeStyleElement);
  2994. }
  2995. WebInspector._themeStyleElement.textContent =
  2996. "#toolbar {\
  2997. background-image: none !important;\
  2998. background-color: " + backgroundColor + " !important;\
  2999. }\
  3000. \
  3001. .toolbar-label {\
  3002. color: " + color + " !important;\
  3003. text-shadow: none;\
  3004. }";
  3005. }
  3006. WebInspector.resetToolbarColors = function()
  3007. {
  3008. if (WebInspector._themeStyleElement)
  3009. WebInspector._themeStyleElement.textContent = "";
  3010. }
  3011. WebInspector.highlightSearchResult = function(element, offset, length, domChanges)
  3012. {
  3013. var result = WebInspector.highlightSearchResults(element, [{offset: offset, length: length }], domChanges);
  3014. return result.length ? result[0] : null;
  3015. }
  3016. WebInspector.highlightSearchResults = function(element, resultRanges, changes)
  3017. {
  3018. return WebInspector.highlightRangesWithStyleClass(element, resultRanges, "webkit-search-result", changes);
  3019. }
  3020. WebInspector.highlightRangesWithStyleClass = function(element, resultRanges, styleClass, changes)
  3021. {
  3022. changes = changes || [];
  3023. var highlightNodes = [];
  3024. var lineText = element.textContent;
  3025. var ownerDocument = element.ownerDocument;
  3026. var textNodeSnapshot = ownerDocument.evaluate(".//text()", element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  3027. var snapshotLength = textNodeSnapshot.snapshotLength;
  3028. if (snapshotLength === 0)
  3029. return highlightNodes;
  3030. var nodeRanges = [];
  3031. var rangeEndOffset = 0;
  3032. for (var i = 0; i < snapshotLength; ++i) {
  3033. var range = {};
  3034. range.offset = rangeEndOffset;
  3035. range.length = textNodeSnapshot.snapshotItem(i).textContent.length;
  3036. rangeEndOffset = range.offset + range.length;
  3037. nodeRanges.push(range);
  3038. }
  3039. var startIndex = 0;
  3040. for (var i = 0; i < resultRanges.length; ++i) {
  3041. var startOffset = resultRanges[i].offset;
  3042. var endOffset = startOffset + resultRanges[i].length;
  3043. while (startIndex < snapshotLength && nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= startOffset)
  3044. startIndex++;
  3045. var endIndex = startIndex;
  3046. while (endIndex < snapshotLength && nodeRanges[endIndex].offset + nodeRanges[endIndex].length < endOffset)
  3047. endIndex++;
  3048. if (endIndex === snapshotLength)
  3049. break;
  3050. var highlightNode = ownerDocument.createElement("span");
  3051. highlightNode.className = styleClass;
  3052. highlightNode.textContent = lineText.substring(startOffset, endOffset);
  3053. var lastTextNode = textNodeSnapshot.snapshotItem(endIndex);
  3054. var lastText = lastTextNode.textContent;
  3055. lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[endIndex].offset);
  3056. changes.push({ node: lastTextNode, type: "changed", oldText: lastText, newText: lastTextNode.textContent });
  3057. if (startIndex === endIndex) {
  3058. lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode);
  3059. changes.push({ node: highlightNode, type: "added", nextSibling: lastTextNode, parent: lastTextNode.parentElement });
  3060. highlightNodes.push(highlightNode);
  3061. var prefixNode = ownerDocument.createTextNode(lastText.substring(0, startOffset - nodeRanges[startIndex].offset));
  3062. lastTextNode.parentElement.insertBefore(prefixNode, highlightNode);
  3063. changes.push({ node: prefixNode, type: "added", nextSibling: highlightNode, parent: lastTextNode.parentElement });
  3064. } else {
  3065. var firstTextNode = textNodeSnapshot.snapshotItem(startIndex);
  3066. var firstText = firstTextNode.textContent;
  3067. var anchorElement = firstTextNode.nextSibling;
  3068. firstTextNode.parentElement.insertBefore(highlightNode, anchorElement);
  3069. changes.push({ node: highlightNode, type: "added", nextSibling: anchorElement, parent: firstTextNode.parentElement });
  3070. highlightNodes.push(highlightNode);
  3071. firstTextNode.textContent = firstText.substring(0, startOffset - nodeRanges[startIndex].offset);
  3072. changes.push({ node: firstTextNode, type: "changed", oldText: firstText, newText: firstTextNode.textContent });
  3073. for (var j = startIndex + 1; j < endIndex; j++) {
  3074. var textNode = textNodeSnapshot.snapshotItem(j);
  3075. var text = textNode.textContent;
  3076. textNode.textContent = "";
  3077. changes.push({ node: textNode, type: "changed", oldText: text, newText: textNode.textContent });
  3078. }
  3079. }
  3080. startIndex = endIndex;
  3081. nodeRanges[startIndex].offset = endOffset;
  3082. nodeRanges[startIndex].length = lastTextNode.textContent.length;
  3083. }
  3084. return highlightNodes;
  3085. }
  3086. WebInspector.applyDomChanges = function(domChanges)
  3087. {
  3088. for (var i = 0, size = domChanges.length; i < size; ++i) {
  3089. var entry = domChanges[i];
  3090. switch (entry.type) {
  3091. case "added":
  3092. entry.parent.insertBefore(entry.node, entry.nextSibling);
  3093. break;
  3094. case "changed":
  3095. entry.node.textContent = entry.newText;
  3096. break;
  3097. }
  3098. }
  3099. }
  3100. WebInspector.revertDomChanges = function(domChanges)
  3101. {
  3102. for (var i = domChanges.length - 1; i >= 0; --i) {
  3103. var entry = domChanges[i];
  3104. switch (entry.type) {
  3105. case "added":
  3106. if (entry.node.parentElement)
  3107. entry.node.parentElement.removeChild(entry.node);
  3108. break;
  3109. case "changed":
  3110. entry.node.textContent = entry.oldText;
  3111. break;
  3112. }
  3113. }
  3114. }
  3115. WebInspector.populateHrefContextMenu = function(contextMenu, contextNode, event)
  3116. {
  3117. var anchorElement = event.target.enclosingNodeOrSelfWithClass("webkit-html-resource-link") || event.target.enclosingNodeOrSelfWithClass("webkit-html-external-link");
  3118. if (!anchorElement)
  3119. return false;
  3120. var resourceURL = WebInspector.resourceURLForRelatedNode(contextNode, anchorElement.href);
  3121. if (!resourceURL)
  3122. return false;
  3123. contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, resourceURL, false));
  3124. if (WebInspector.resourceForURL(resourceURL))
  3125. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open link in Resources panel" : "Open Link in Resources Panel"), WebInspector.openResource.bind(null, resourceURL, true));
  3126. contextMenu.appendItem(WebInspector.copyLinkAddressLabel(), InspectorFrontendHost.copyText.bind(InspectorFrontendHost, resourceURL));
  3127. return true;
  3128. }
  3129. ;(function() {
  3130. function windowLoaded()
  3131. {
  3132. window.addEventListener("focus", WebInspector._windowFocused, false);
  3133. window.addEventListener("blur", WebInspector._windowBlurred, false);
  3134. document.addEventListener("focus", WebInspector._focusChanged.bind(this), true);
  3135. window.removeEventListener("DOMContentLoaded", windowLoaded, false);
  3136. }
  3137. window.addEventListener("DOMContentLoaded", windowLoaded, false);
  3138. })();
  3139. function InspectorBackendClass()
  3140. {
  3141. this._lastCallbackId = 1;
  3142. this._pendingResponsesCount = 0;
  3143. this._callbacks = {};
  3144. this._domainDispatchers = {};
  3145. this._eventArgs = {};
  3146. this._replyArgs = {};
  3147. this.dumpInspectorTimeStats = false;
  3148. this.dumpInspectorProtocolMessages = false;
  3149. this._initialized = false;
  3150. }
  3151. InspectorBackendClass.prototype = {
  3152. _wrap: function(callback, method)
  3153. {
  3154. var callbackId = this._lastCallbackId++;
  3155. if (!callback)
  3156. callback = function() {};
  3157. this._callbacks[callbackId] = callback;
  3158. callback.methodName = method;
  3159. if (this.dumpInspectorTimeStats)
  3160. callback.sendRequestTime = Date.now();
  3161. return callbackId;
  3162. },
  3163. registerCommand: function(method, signature, replyArgs)
  3164. {
  3165. var domainAndMethod = method.split(".");
  3166. var agentName = domainAndMethod[0] + "Agent";
  3167. if (!window[agentName])
  3168. window[agentName] = {};
  3169. window[agentName][domainAndMethod[1]] = this._sendMessageToBackend.bind(this, method, signature);
  3170. window[agentName][domainAndMethod[1]]["invoke"] = this._invoke.bind(this, method, signature);
  3171. this._replyArgs[method] = replyArgs;
  3172. this._initialized = true;
  3173. },
  3174. registerEvent: function(eventName, params)
  3175. {
  3176. this._eventArgs[eventName] = params;
  3177. this._initialized = true;
  3178. },
  3179. _invoke: function(method, signature, args, callback)
  3180. {
  3181. this._wrapCallbackAndSendMessageObject(method, args, callback);
  3182. },
  3183. _sendMessageToBackend: function(method, signature, vararg)
  3184. {
  3185. var args = Array.prototype.slice.call(arguments, 2);
  3186. var callback = (args.length && typeof args[args.length - 1] === "function") ? args.pop() : null;
  3187. var params = {};
  3188. var hasParams = false;
  3189. for (var i = 0; i < signature.length; ++i) {
  3190. var param = signature[i];
  3191. var paramName = param["name"];
  3192. var typeName = param["type"];
  3193. var optionalFlag = param["optional"];
  3194. if (!args.length && !optionalFlag) {
  3195. console.error("Protocol Error: Invalid number of arguments for method '" + method + "' call. It must have the following arguments '" + JSON.stringify(signature) + "'.");
  3196. return;
  3197. }
  3198. var value = args.shift();
  3199. if (optionalFlag && typeof value === "undefined") {
  3200. continue;
  3201. }
  3202. if (typeof value !== typeName) {
  3203. console.error("Protocol Error: Invalid type of argument '" + paramName + "' for method '" + method + "' call. It must be '" + typeName + "' but it is '" + typeof value + "'.");
  3204. return;
  3205. }
  3206. params[paramName] = value;
  3207. hasParams = true;
  3208. }
  3209. if (args.length === 1 && !callback) {
  3210. if (typeof args[0] !== "undefined") {
  3211. console.error("Protocol Error: Optional callback argument for method '" + method + "' call must be a function but its type is '" + typeof args[0] + "'.");
  3212. return;
  3213. }
  3214. }
  3215. this._wrapCallbackAndSendMessageObject(method, hasParams ? params : null, callback);
  3216. },
  3217. _wrapCallbackAndSendMessageObject: function(method, params, callback)
  3218. {
  3219. var messageObject = {};
  3220. messageObject.method = method;
  3221. if (params)
  3222. messageObject.params = params;
  3223. messageObject.id = this._wrap(callback, method);
  3224. if (this.dumpInspectorProtocolMessages)
  3225. console.log("frontend: " + JSON.stringify(messageObject));
  3226. ++this._pendingResponsesCount;
  3227. this.sendMessageObjectToBackend(messageObject);
  3228. },
  3229. sendMessageObjectToBackend: function(messageObject)
  3230. {
  3231. var message = JSON.stringify(messageObject);
  3232. InspectorFrontendHost.sendMessageToBackend(message);
  3233. },
  3234. registerDomainDispatcher: function(domain, dispatcher)
  3235. {
  3236. this._domainDispatchers[domain] = dispatcher;
  3237. },
  3238. dispatch: function(message)
  3239. {
  3240. if (this.dumpInspectorProtocolMessages)
  3241. console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
  3242. var messageObject = (typeof message === "string") ? JSON.parse(message) : message;
  3243. if ("id" in messageObject) {
  3244. if (messageObject.error) {
  3245. if (messageObject.error.code !== -32000)
  3246. this.reportProtocolError(messageObject);
  3247. }
  3248. var callback = this._callbacks[messageObject.id];
  3249. if (callback) {
  3250. var argumentsArray = [];
  3251. if (messageObject.result) {
  3252. var paramNames = this._replyArgs[callback.methodName];
  3253. if (paramNames) {
  3254. for (var i = 0; i < paramNames.length; ++i)
  3255. argumentsArray.push(messageObject.result[paramNames[i]]);
  3256. }
  3257. }
  3258. var processingStartTime;
  3259. if (this.dumpInspectorTimeStats && callback.methodName)
  3260. processingStartTime = Date.now();
  3261. argumentsArray.unshift(messageObject.error ? messageObject.error.message : null);
  3262. callback.apply(null, argumentsArray);
  3263. --this._pendingResponsesCount;
  3264. delete this._callbacks[messageObject.id];
  3265. if (this.dumpInspectorTimeStats && callback.methodName)
  3266. console.log("time-stats: " + callback.methodName + " = " + (processingStartTime - callback.sendRequestTime) + " + " + (Date.now() - processingStartTime));
  3267. }
  3268. if (this._scripts && !this._pendingResponsesCount)
  3269. this.runAfterPendingDispatches();
  3270. return;
  3271. } else {
  3272. var method = messageObject.method.split(".");
  3273. var domainName = method[0];
  3274. var functionName = method[1];
  3275. if (!(domainName in this._domainDispatchers)) {
  3276. console.error("Protocol Error: the message is for non-existing domain '" + domainName + "'");
  3277. return;
  3278. }
  3279. var dispatcher = this._domainDispatchers[domainName];
  3280. if (!(functionName in dispatcher)) {
  3281. console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.method + "'");
  3282. return;
  3283. }
  3284. if (!this._eventArgs[messageObject.method]) {
  3285. console.error("Protocol Error: Attempted to dispatch an unspecified method '" + messageObject.method + "'");
  3286. return;
  3287. }
  3288. var params = [];
  3289. if (messageObject.params) {
  3290. var paramNames = this._eventArgs[messageObject.method];
  3291. for (var i = 0; i < paramNames.length; ++i)
  3292. params.push(messageObject.params[paramNames[i]]);
  3293. }
  3294. var processingStartTime;
  3295. if (this.dumpInspectorTimeStats)
  3296. processingStartTime = Date.now();
  3297. dispatcher[functionName].apply(dispatcher, params);
  3298. if (this.dumpInspectorTimeStats)
  3299. console.log("time-stats: " + messageObject.method + " = " + (Date.now() - processingStartTime));
  3300. }
  3301. },
  3302. reportProtocolError: function(messageObject)
  3303. {
  3304. console.error("Request with id = " + messageObject.id + " failed. " + messageObject.error);
  3305. },
  3306. runAfterPendingDispatches: function(script)
  3307. {
  3308. if (!this._scripts)
  3309. this._scripts = [];
  3310. if (script)
  3311. this._scripts.push(script);
  3312. if (!this._pendingResponsesCount) {
  3313. var scripts = this._scripts;
  3314. this._scripts = []
  3315. for (var id = 0; id < scripts.length; ++id)
  3316. scripts[id].call(this);
  3317. }
  3318. },
  3319. loadFromJSONIfNeeded: function()
  3320. {
  3321. if (this._initialized)
  3322. return;
  3323. var xhr = new XMLHttpRequest();
  3324. xhr.open("GET", "../Inspector.json", false);
  3325. xhr.send(null);
  3326. var schema = JSON.parse(xhr.responseText);
  3327. var jsTypes = { integer: "number", array: "object" };
  3328. var rawTypes = {};
  3329. var domains = schema["domains"];
  3330. for (var i = 0; i < domains.length; ++i) {
  3331. var domain = domains[i];
  3332. for (var j = 0; domain.types && j < domain.types.length; ++j) {
  3333. var type = domain.types[j];
  3334. rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type;
  3335. }
  3336. }
  3337. var result = [];
  3338. for (var i = 0; i < domains.length; ++i) {
  3339. var domain = domains[i];
  3340. var commands = domain["commands"] || [];
  3341. for (var j = 0; j < commands.length; ++j) {
  3342. var command = commands[j];
  3343. var parameters = command["parameters"];
  3344. var paramsText = [];
  3345. for (var k = 0; parameters && k < parameters.length; ++k) {
  3346. var parameter = parameters[k];
  3347. var type;
  3348. if (parameter.type)
  3349. type = jsTypes[parameter.type] || parameter.type;
  3350. else {
  3351. var ref = parameter["$ref"];
  3352. if (ref.indexOf(".") !== -1)
  3353. type = rawTypes[ref];
  3354. else
  3355. type = rawTypes[domain.domain + "." + ref];
  3356. }
  3357. var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}";
  3358. paramsText.push(text);
  3359. }
  3360. var returnsText = [];
  3361. var returns = command["returns"] || [];
  3362. for (var k = 0; k < returns.length; ++k) {
  3363. var parameter = returns[k];
  3364. returnsText.push("\"" + parameter.name + "\"");
  3365. }
  3366. result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "]);");
  3367. }
  3368. for (var j = 0; domain.events && j < domain.events.length; ++j) {
  3369. var event = domain.events[j];
  3370. var paramsText = [];
  3371. for (var k = 0; event.parameters && k < event.parameters.length; ++k) {
  3372. var parameter = event.parameters[k];
  3373. paramsText.push("\"" + parameter.name + "\"");
  3374. }
  3375. result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);");
  3376. }
  3377. result.push("InspectorBackend.register" + domain.domain + "Dispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"" + domain.domain + "\");");
  3378. }
  3379. eval(result.join("\n"));
  3380. }
  3381. }
  3382. InspectorBackend = new InspectorBackendClass();
  3383. InspectorBackend.registerInspectorDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Inspector");
  3384. InspectorBackend.registerEvent("Inspector.evaluateForTestInFrontend", ["testCallId", "script"]);
  3385. InspectorBackend.registerEvent("Inspector.inspect", ["object", "hints"]);
  3386. InspectorBackend.registerEvent("Inspector.didCreateWorker", ["id", "url", "isShared"]);
  3387. InspectorBackend.registerEvent("Inspector.didDestroyWorker", ["id"]);
  3388. InspectorBackend.registerCommand("Inspector.enable", [], []);
  3389. InspectorBackend.registerCommand("Inspector.disable", [], []);
  3390. InspectorBackend.registerMemoryDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Memory");
  3391. InspectorBackend.registerCommand("Memory.getDOMNodeCount", [], ["domGroups", "strings"]);
  3392. InspectorBackend.registerPageDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Page");
  3393. InspectorBackend.registerEvent("Page.domContentEventFired", ["timestamp"]);
  3394. InspectorBackend.registerEvent("Page.loadEventFired", ["timestamp"]);
  3395. InspectorBackend.registerEvent("Page.frameNavigated", ["frame"]);
  3396. InspectorBackend.registerEvent("Page.frameDetached", ["frameId"]);
  3397. InspectorBackend.registerCommand("Page.enable", [], []);
  3398. InspectorBackend.registerCommand("Page.disable", [], []);
  3399. InspectorBackend.registerCommand("Page.addScriptToEvaluateOnLoad", [{"name": "scriptSource", "type": "string", "optional": false}], ["identifier"]);
  3400. InspectorBackend.registerCommand("Page.removeScriptToEvaluateOnLoad", [{"name": "identifier", "type": "string", "optional": false}], []);
  3401. InspectorBackend.registerCommand("Page.reload", [{"name": "ignoreCache", "type": "boolean", "optional": true}, {"name": "scriptToEvaluateOnLoad", "type": "string", "optional": true}], []);
  3402. InspectorBackend.registerCommand("Page.navigate", [{"name": "url", "type": "string", "optional": false}], []);
  3403. InspectorBackend.registerCommand("Page.getCookies", [], ["cookies", "cookiesString"]);
  3404. InspectorBackend.registerCommand("Page.deleteCookie", [{"name": "cookieName", "type": "string", "optional": false}, {"name": "domain", "type": "string", "optional": false}], []);
  3405. InspectorBackend.registerCommand("Page.getResourceTree", [], ["frameTree"]);
  3406. InspectorBackend.registerCommand("Page.getResourceContent", [{"name": "frameId", "type": "string", "optional": false}, {"name": "url", "type": "string", "optional": false}], ["content", "base64Encoded"]);
  3407. InspectorBackend.registerCommand("Page.searchInResource", [{"name": "frameId", "type": "string", "optional": false}, {"name": "url", "type": "string", "optional": false}, {"name": "query", "type": "string", "optional": false}, {"name": "caseSensitive", "type": "boolean", "optional": true}, {"name": "isRegex", "type": "boolean", "optional": true}], ["result"]);
  3408. InspectorBackend.registerCommand("Page.searchInResources", [{"name": "text", "type": "string", "optional": false}, {"name": "caseSensitive", "type": "boolean", "optional": true}, {"name": "isRegex", "type": "boolean", "optional": true}], ["result"]);
  3409. InspectorBackend.registerCommand("Page.setDocumentContent", [{"name": "frameId", "type": "string", "optional": false}, {"name": "html", "type": "string", "optional": false}], []);
  3410. InspectorBackend.registerCommand("Page.canOverrideDeviceMetrics", [], ["result"]);
  3411. InspectorBackend.registerCommand("Page.setDeviceMetricsOverride", [{"name": "width", "type": "number", "optional": false}, {"name": "height", "type": "number", "optional": false}, {"name": "fontScaleFactor", "type": "number", "optional": false}, {"name": "fitWindow", "type": "boolean", "optional": false}], []);
  3412. InspectorBackend.registerCommand("Page.setShowPaintRects", [{"name": "result", "type": "boolean", "optional": false}], []);
  3413. InspectorBackend.registerCommand("Page.getScriptExecutionStatus", [], ["result"]);
  3414. InspectorBackend.registerCommand("Page.setScriptExecutionDisabled", [{"name": "value", "type": "boolean", "optional": false}], []);
  3415. InspectorBackend.registerRuntimeDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Runtime");
  3416. InspectorBackend.registerEvent("Runtime.isolatedContextCreated", ["context"]);
  3417. InspectorBackend.registerCommand("Runtime.evaluate", [{"name": "expression", "type": "string", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}, {"name": "includeCommandLineAPI", "type": "boolean", "optional": true}, {"name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true}, {"name": "contextId", "type": "number", "optional": true}, {"name": "returnByValue", "type": "boolean", "optional": true}], ["result", "wasThrown"]);
  3418. InspectorBackend.registerCommand("Runtime.callFunctionOn", [{"name": "objectId", "type": "string", "optional": false}, {"name": "functionDeclaration", "type": "string", "optional": false}, {"name": "arguments", "type": "object", "optional": true}, {"name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true}, {"name": "returnByValue", "type": "boolean", "optional": true}], ["result", "wasThrown"]);
  3419. InspectorBackend.registerCommand("Runtime.getProperties", [{"name": "objectId", "type": "string", "optional": false}, {"name": "ownProperties", "type": "boolean", "optional": true}], ["result"]);
  3420. InspectorBackend.registerCommand("Runtime.releaseObject", [{"name": "objectId", "type": "string", "optional": false}], []);
  3421. InspectorBackend.registerCommand("Runtime.releaseObjectGroup", [{"name": "objectGroup", "type": "string", "optional": false}], []);
  3422. InspectorBackend.registerCommand("Runtime.run", [], []);
  3423. InspectorBackend.registerCommand("Runtime.setReportExecutionContextCreation", [{"name": "enabled", "type": "boolean", "optional": false}], []);
  3424. InspectorBackend.registerConsoleDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Console");
  3425. InspectorBackend.registerEvent("Console.messageAdded", ["message"]);
  3426. InspectorBackend.registerEvent("Console.messageRepeatCountUpdated", ["count"]);
  3427. InspectorBackend.registerEvent("Console.messagesCleared", []);
  3428. InspectorBackend.registerCommand("Console.enable", [], []);
  3429. InspectorBackend.registerCommand("Console.disable", [], []);
  3430. InspectorBackend.registerCommand("Console.clearMessages", [], []);
  3431. InspectorBackend.registerCommand("Console.setMonitoringXHREnabled", [{"name": "enabled", "type": "boolean", "optional": false}], []);
  3432. InspectorBackend.registerCommand("Console.addInspectedNode", [{"name": "nodeId", "type": "number", "optional": false}], []);
  3433. InspectorBackend.registerCommand("Console.addInspectedHeapObject", [{"name": "heapObjectId", "type": "number", "optional": false}], []);
  3434. InspectorBackend.registerNetworkDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Network");
  3435. InspectorBackend.registerEvent("Network.requestWillBeSent", ["requestId", "frameId", "loaderId", "documentURL", "request", "timestamp", "initiator", "redirectResponse"]);
  3436. InspectorBackend.registerEvent("Network.requestServedFromCache", ["requestId"]);
  3437. InspectorBackend.registerEvent("Network.responseReceived", ["requestId", "frameId", "loaderId", "timestamp", "type", "response"]);
  3438. InspectorBackend.registerEvent("Network.dataReceived", ["requestId", "timestamp", "dataLength", "encodedDataLength"]);
  3439. InspectorBackend.registerEvent("Network.loadingFinished", ["requestId", "timestamp"]);
  3440. InspectorBackend.registerEvent("Network.loadingFailed", ["requestId", "timestamp", "errorText", "canceled"]);
  3441. InspectorBackend.registerEvent("Network.requestServedFromMemoryCache", ["requestId", "frameId", "loaderId", "documentURL", "timestamp", "initiator", "resource"]);
  3442. InspectorBackend.registerEvent("Network.webSocketWillSendHandshakeRequest", ["requestId", "timestamp", "request"]);
  3443. InspectorBackend.registerEvent("Network.webSocketHandshakeResponseReceived", ["requestId", "timestamp", "response"]);
  3444. InspectorBackend.registerEvent("Network.webSocketCreated", ["requestId", "url"]);
  3445. InspectorBackend.registerEvent("Network.webSocketClosed", ["requestId", "timestamp"]);
  3446. InspectorBackend.registerEvent("Network.webSocketFrameReceived", ["requestId", "timestamp", "response"]);
  3447. InspectorBackend.registerEvent("Network.webSocketFrameError", ["requestId", "timestamp", "errorMessage"]);
  3448. InspectorBackend.registerEvent("Network.webSocketFrameSent", ["requestId", "timestamp", "response"]);
  3449. InspectorBackend.registerCommand("Network.enable", [], []);
  3450. InspectorBackend.registerCommand("Network.disable", [], []);
  3451. InspectorBackend.registerCommand("Network.setUserAgentOverride", [{"name": "userAgent", "type": "string", "optional": false}], []);
  3452. InspectorBackend.registerCommand("Network.setExtraHTTPHeaders", [{"name": "headers", "type": "object", "optional": false}], []);
  3453. InspectorBackend.registerCommand("Network.getResponseBody", [{"name": "requestId", "type": "string", "optional": false}], ["body", "base64Encoded"]);
  3454. InspectorBackend.registerCommand("Network.canClearBrowserCache", [], ["result"]);
  3455. InspectorBackend.registerCommand("Network.clearBrowserCache", [], []);
  3456. InspectorBackend.registerCommand("Network.canClearBrowserCookies", [], ["result"]);
  3457. InspectorBackend.registerCommand("Network.clearBrowserCookies", [], []);
  3458. InspectorBackend.registerCommand("Network.setCacheDisabled", [{"name": "cacheDisabled", "type": "boolean", "optional": false}], []);
  3459. InspectorBackend.registerDatabaseDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Database");
  3460. InspectorBackend.registerEvent("Database.addDatabase", ["database"]);
  3461. InspectorBackend.registerEvent("Database.sqlTransactionSucceeded", ["transactionId", "columnNames", "values"]);
  3462. InspectorBackend.registerEvent("Database.sqlTransactionFailed", ["transactionId", "sqlError"]);
  3463. InspectorBackend.registerCommand("Database.enable", [], []);
  3464. InspectorBackend.registerCommand("Database.disable", [], []);
  3465. InspectorBackend.registerCommand("Database.getDatabaseTableNames", [{"name": "databaseId", "type": "string", "optional": false}], ["tableNames"]);
  3466. InspectorBackend.registerCommand("Database.executeSQL", [{"name": "databaseId", "type": "string", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["success", "transactionId"]);
  3467. InspectorBackend.registerIndexedDBDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "IndexedDB");
  3468. InspectorBackend.registerEvent("IndexedDB.databaseNamesLoaded", ["requestId", "securityOriginWithDatabaseNames"]);
  3469. InspectorBackend.registerEvent("IndexedDB.databaseLoaded", ["requestId", "databaseWithObjectStores"]);
  3470. InspectorBackend.registerEvent("IndexedDB.objectStoreDataLoaded", ["requestId", "objectStoreDataEntries", "hasMore"]);
  3471. InspectorBackend.registerEvent("IndexedDB.indexDataLoaded", ["requestId", "indexDataEntries", "hasMore"]);
  3472. InspectorBackend.registerCommand("IndexedDB.enable", [], []);
  3473. InspectorBackend.registerCommand("IndexedDB.disable", [], []);
  3474. InspectorBackend.registerCommand("IndexedDB.requestDatabaseNamesForFrame", [{"name": "requestId", "type": "number", "optional": false}, {"name": "frameId", "type": "string", "optional": false}], []);
  3475. InspectorBackend.registerCommand("IndexedDB.requestDatabase", [{"name": "requestId", "type": "number", "optional": false}, {"name": "frameId", "type": "string", "optional": false}, {"name": "databaseName", "type": "string", "optional": false}], []);
  3476. InspectorBackend.registerCommand("IndexedDB.requestData", [{"name": "requestId", "type": "number", "optional": false}, {"name": "frameId", "type": "string", "optional": false}, {"name": "databaseName", "type": "string", "optional": false}, {"name": "objectStoreName", "type": "string", "optional": false}, {"name": "indexName", "type": "string", "optional": false}, {"name": "skipCount", "type": "number", "optional": false}, {"name": "pageSize", "type": "number", "optional": false}, {"name": "keyRange", "type": "object", "optional": true}], []);
  3477. InspectorBackend.registerDOMStorageDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "DOMStorage");
  3478. InspectorBackend.registerEvent("DOMStorage.addDOMStorage", ["storage"]);
  3479. InspectorBackend.registerEvent("DOMStorage.updateDOMStorage", ["storageId"]);
  3480. InspectorBackend.registerCommand("DOMStorage.enable", [], []);
  3481. InspectorBackend.registerCommand("DOMStorage.disable", [], []);
  3482. InspectorBackend.registerCommand("DOMStorage.getDOMStorageEntries", [{"name": "storageId", "type": "string", "optional": false}], ["entries"]);
  3483. InspectorBackend.registerCommand("DOMStorage.setDOMStorageItem", [{"name": "storageId", "type": "string", "optional": false}, {"name": "key", "type": "string", "optional": false}, {"name": "value", "type": "string", "optional": false}], ["success"]);
  3484. InspectorBackend.registerCommand("DOMStorage.removeDOMStorageItem", [{"name": "storageId", "type": "string", "optional": false}, {"name": "key", "type": "string", "optional": false}], ["success"]);
  3485. InspectorBackend.registerApplicationCacheDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "ApplicationCache");
  3486. InspectorBackend.registerEvent("ApplicationCache.applicationCacheStatusUpdated", ["frameId", "manifestURL", "status"]);
  3487. InspectorBackend.registerEvent("ApplicationCache.networkStateUpdated", ["isNowOnline"]);
  3488. InspectorBackend.registerCommand("ApplicationCache.getFramesWithManifests", [], ["frameIds"]);
  3489. InspectorBackend.registerCommand("ApplicationCache.enable", [], []);
  3490. InspectorBackend.registerCommand("ApplicationCache.getManifestForFrame", [{"name": "frameId", "type": "string", "optional": false}], ["manifestURL"]);
  3491. InspectorBackend.registerCommand("ApplicationCache.getApplicationCacheForFrame", [{"name": "frameId", "type": "string", "optional": false}], ["applicationCache"]);
  3492. InspectorBackend.registerFileSystemDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "FileSystem");
  3493. InspectorBackend.registerCommand("FileSystem.enable", [], []);
  3494. InspectorBackend.registerCommand("FileSystem.disable", [], []);
  3495. InspectorBackend.registerDOMDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "DOM");
  3496. InspectorBackend.registerEvent("DOM.documentUpdated", []);
  3497. InspectorBackend.registerEvent("DOM.setChildNodes", ["parentId", "nodes"]);
  3498. InspectorBackend.registerEvent("DOM.attributeModified", ["nodeId", "name", "value"]);
  3499. InspectorBackend.registerEvent("DOM.attributeRemoved", ["nodeId", "name"]);
  3500. InspectorBackend.registerEvent("DOM.inlineStyleInvalidated", ["nodeIds"]);
  3501. InspectorBackend.registerEvent("DOM.characterDataModified", ["nodeId", "characterData"]);
  3502. InspectorBackend.registerEvent("DOM.childNodeCountUpdated", ["nodeId", "childNodeCount"]);
  3503. InspectorBackend.registerEvent("DOM.childNodeInserted", ["parentNodeId", "previousNodeId", "node"]);
  3504. InspectorBackend.registerEvent("DOM.childNodeRemoved", ["parentNodeId", "nodeId"]);
  3505. InspectorBackend.registerEvent("DOM.shadowRootPushed", ["hostId", "root"]);
  3506. InspectorBackend.registerEvent("DOM.shadowRootPopped", ["hostId", "rootId"]);
  3507. InspectorBackend.registerCommand("DOM.getDocument", [], ["root"]);
  3508. InspectorBackend.registerCommand("DOM.requestChildNodes", [{"name": "nodeId", "type": "number", "optional": false}], []);
  3509. InspectorBackend.registerCommand("DOM.querySelector", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["nodeId"]);
  3510. InspectorBackend.registerCommand("DOM.querySelectorAll", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["nodeIds"]);
  3511. InspectorBackend.registerCommand("DOM.setNodeName", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}], ["nodeId"]);
  3512. InspectorBackend.registerCommand("DOM.setNodeValue", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "value", "type": "string", "optional": false}], []);
  3513. InspectorBackend.registerCommand("DOM.removeNode", [{"name": "nodeId", "type": "number", "optional": false}], []);
  3514. InspectorBackend.registerCommand("DOM.setAttributeValue", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}, {"name": "value", "type": "string", "optional": false}], []);
  3515. InspectorBackend.registerCommand("DOM.setAttributesAsText", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "text", "type": "string", "optional": false}, {"name": "name", "type": "string", "optional": true}], []);
  3516. InspectorBackend.registerCommand("DOM.removeAttribute", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}], []);
  3517. InspectorBackend.registerCommand("DOM.getEventListenersForNode", [{"name": "nodeId", "type": "number", "optional": false}], ["listeners"]);
  3518. InspectorBackend.registerCommand("DOM.getOuterHTML", [{"name": "nodeId", "type": "number", "optional": false}], ["outerHTML"]);
  3519. InspectorBackend.registerCommand("DOM.setOuterHTML", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "outerHTML", "type": "string", "optional": false}], []);
  3520. InspectorBackend.registerCommand("DOM.performSearch", [{"name": "query", "type": "string", "optional": false}], ["searchId", "resultCount"]);
  3521. InspectorBackend.registerCommand("DOM.getSearchResults", [{"name": "searchId", "type": "string", "optional": false}, {"name": "fromIndex", "type": "number", "optional": false}, {"name": "toIndex", "type": "number", "optional": false}], ["nodeIds"]);
  3522. InspectorBackend.registerCommand("DOM.discardSearchResults", [{"name": "searchId", "type": "string", "optional": false}], []);
  3523. InspectorBackend.registerCommand("DOM.requestNode", [{"name": "objectId", "type": "string", "optional": false}], ["nodeId"]);
  3524. InspectorBackend.registerCommand("DOM.setInspectModeEnabled", [{"name": "enabled", "type": "boolean", "optional": false}, {"name": "highlightConfig", "type": "object", "optional": true}], []);
  3525. InspectorBackend.registerCommand("DOM.highlightRect", [{"name": "x", "type": "number", "optional": false}, {"name": "y", "type": "number", "optional": false}, {"name": "width", "type": "number", "optional": false}, {"name": "height", "type": "number", "optional": false}, {"name": "color", "type": "object", "optional": true}, {"name": "outlineColor", "type": "object", "optional": true}], []);
  3526. InspectorBackend.registerCommand("DOM.highlightNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "highlightConfig", "type": "object", "optional": false}], []);
  3527. InspectorBackend.registerCommand("DOM.hideHighlight", [], []);
  3528. InspectorBackend.registerCommand("DOM.highlightFrame", [{"name": "frameId", "type": "string", "optional": false}, {"name": "contentColor", "type": "object", "optional": true}, {"name": "contentOutlineColor", "type": "object", "optional": true}], []);
  3529. InspectorBackend.registerCommand("DOM.pushNodeByPathToFrontend", [{"name": "path", "type": "string", "optional": false}], ["nodeId"]);
  3530. InspectorBackend.registerCommand("DOM.resolveNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}], ["object"]);
  3531. InspectorBackend.registerCommand("DOM.getAttributes", [{"name": "nodeId", "type": "number", "optional": false}], ["attributes"]);
  3532. InspectorBackend.registerCommand("DOM.moveTo", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "targetNodeId", "type": "number", "optional": false}, {"name": "insertBeforeNodeId", "type": "number", "optional": true}], ["nodeId"]);
  3533. InspectorBackend.registerCommand("DOM.setTouchEmulationEnabled", [{"name": "enabled", "type": "boolean", "optional": false}], []);
  3534. InspectorBackend.registerCommand("DOM.undo", [], []);
  3535. InspectorBackend.registerCommand("DOM.redo", [], []);
  3536. InspectorBackend.registerCommand("DOM.markUndoableState", [], []);
  3537. InspectorBackend.registerCSSDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "CSS");
  3538. InspectorBackend.registerEvent("CSS.mediaQueryResultChanged", []);
  3539. InspectorBackend.registerEvent("CSS.styleSheetChanged", ["styleSheetId"]);
  3540. InspectorBackend.registerCommand("CSS.enable", [], []);
  3541. InspectorBackend.registerCommand("CSS.disable", [], []);
  3542. InspectorBackend.registerCommand("CSS.getMatchedStylesForNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "forcedPseudoClasses", "type": "object", "optional": true}, {"name": "includePseudo", "type": "boolean", "optional": true}, {"name": "includeInherited", "type": "boolean", "optional": true}], ["matchedCSSRules", "pseudoElements", "inherited"]);
  3543. InspectorBackend.registerCommand("CSS.getInlineStylesForNode", [{"name": "nodeId", "type": "number", "optional": false}], ["inlineStyle", "attributesStyle"]);
  3544. InspectorBackend.registerCommand("CSS.getComputedStyleForNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "forcedPseudoClasses", "type": "object", "optional": true}], ["computedStyle"]);
  3545. InspectorBackend.registerCommand("CSS.getAllStyleSheets", [], ["headers"]);
  3546. InspectorBackend.registerCommand("CSS.getStyleSheet", [{"name": "styleSheetId", "type": "string", "optional": false}], ["styleSheet"]);
  3547. InspectorBackend.registerCommand("CSS.getStyleSheetText", [{"name": "styleSheetId", "type": "string", "optional": false}], ["text"]);
  3548. InspectorBackend.registerCommand("CSS.setStyleSheetText", [{"name": "styleSheetId", "type": "string", "optional": false}, {"name": "text", "type": "string", "optional": false}], []);
  3549. InspectorBackend.registerCommand("CSS.setPropertyText", [{"name": "styleId", "type": "object", "optional": false}, {"name": "propertyIndex", "type": "number", "optional": false}, {"name": "text", "type": "string", "optional": false}, {"name": "overwrite", "type": "boolean", "optional": false}], ["style"]);
  3550. InspectorBackend.registerCommand("CSS.toggleProperty", [{"name": "styleId", "type": "object", "optional": false}, {"name": "propertyIndex", "type": "number", "optional": false}, {"name": "disable", "type": "boolean", "optional": false}], ["style"]);
  3551. InspectorBackend.registerCommand("CSS.setRuleSelector", [{"name": "ruleId", "type": "object", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["rule"]);
  3552. InspectorBackend.registerCommand("CSS.addRule", [{"name": "contextNodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["rule"]);
  3553. InspectorBackend.registerCommand("CSS.getSupportedCSSProperties", [], ["cssProperties"]);
  3554. InspectorBackend.registerCommand("CSS.startSelectorProfiler", [], []);
  3555. InspectorBackend.registerCommand("CSS.stopSelectorProfiler", [], ["profile"]);
  3556. InspectorBackend.registerTimelineDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Timeline");
  3557. InspectorBackend.registerEvent("Timeline.eventRecorded", ["record"]);
  3558. InspectorBackend.registerCommand("Timeline.start", [{"name": "maxCallStackDepth", "type": "number", "optional": true}], []);
  3559. InspectorBackend.registerCommand("Timeline.stop", [], []);
  3560. InspectorBackend.registerCommand("Timeline.setIncludeMemoryDetails", [{"name": "enabled", "type": "boolean", "optional": false}], []);
  3561. InspectorBackend.registerCommand("Timeline.supportsFrameInstrumentation", [], ["result"]);
  3562. InspectorBackend.registerDebuggerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Debugger");
  3563. InspectorBackend.registerEvent("Debugger.globalObjectCleared", []);
  3564. InspectorBackend.registerEvent("Debugger.scriptParsed", ["scriptId", "url", "startLine", "startColumn", "endLine", "endColumn", "isContentScript", "sourceMapURL"]);
  3565. InspectorBackend.registerEvent("Debugger.scriptFailedToParse", ["url", "scriptSource", "startLine", "errorLine", "errorMessage"]);
  3566. InspectorBackend.registerEvent("Debugger.breakpointResolved", ["breakpointId", "location"]);
  3567. InspectorBackend.registerEvent("Debugger.paused", ["callFrames", "reason", "data"]);
  3568. InspectorBackend.registerEvent("Debugger.resumed", []);
  3569. InspectorBackend.registerCommand("Debugger.causesRecompilation", [], ["result"]);
  3570. InspectorBackend.registerCommand("Debugger.supportsNativeBreakpoints", [], ["result"]);
  3571. InspectorBackend.registerCommand("Debugger.enable", [], []);
  3572. InspectorBackend.registerCommand("Debugger.disable", [], []);
  3573. InspectorBackend.registerCommand("Debugger.setBreakpointsActive", [{"name": "active", "type": "boolean", "optional": false}], []);
  3574. InspectorBackend.registerCommand("Debugger.setBreakpointByUrl", [{"name": "lineNumber", "type": "number", "optional": false}, {"name": "url", "type": "string", "optional": true}, {"name": "urlRegex", "type": "string", "optional": true}, {"name": "columnNumber", "type": "number", "optional": true}, {"name": "condition", "type": "string", "optional": true}], ["breakpointId", "locations"]);
  3575. InspectorBackend.registerCommand("Debugger.setBreakpoint", [{"name": "location", "type": "object", "optional": false}, {"name": "condition", "type": "string", "optional": true}], ["breakpointId", "actualLocation"]);
  3576. InspectorBackend.registerCommand("Debugger.removeBreakpoint", [{"name": "breakpointId", "type": "string", "optional": false}], []);
  3577. InspectorBackend.registerCommand("Debugger.continueToLocation", [{"name": "location", "type": "object", "optional": false}], []);
  3578. InspectorBackend.registerCommand("Debugger.stepOver", [], []);
  3579. InspectorBackend.registerCommand("Debugger.stepInto", [], []);
  3580. InspectorBackend.registerCommand("Debugger.stepOut", [], []);
  3581. InspectorBackend.registerCommand("Debugger.pause", [], []);
  3582. InspectorBackend.registerCommand("Debugger.resume", [], []);
  3583. InspectorBackend.registerCommand("Debugger.searchInContent", [{"name": "scriptId", "type": "string", "optional": false}, {"name": "query", "type": "string", "optional": false}, {"name": "caseSensitive", "type": "boolean", "optional": true}, {"name": "isRegex", "type": "boolean", "optional": true}], ["result"]);
  3584. InspectorBackend.registerCommand("Debugger.canSetScriptSource", [], ["result"]);
  3585. InspectorBackend.registerCommand("Debugger.setScriptSource", [{"name": "scriptId", "type": "string", "optional": false}, {"name": "scriptSource", "type": "string", "optional": false}, {"name": "preview", "type": "boolean", "optional": true}], ["callFrames", "result"]);
  3586. InspectorBackend.registerCommand("Debugger.getScriptSource", [{"name": "scriptId", "type": "string", "optional": false}], ["scriptSource"]);
  3587. InspectorBackend.registerCommand("Debugger.getFunctionDetails", [{"name": "functionId", "type": "string", "optional": false}], ["details"]);
  3588. InspectorBackend.registerCommand("Debugger.setPauseOnExceptions", [{"name": "state", "type": "string", "optional": false}], []);
  3589. InspectorBackend.registerCommand("Debugger.evaluateOnCallFrame", [{"name": "callFrameId", "type": "string", "optional": false}, {"name": "expression", "type": "string", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}, {"name": "includeCommandLineAPI", "type": "boolean", "optional": true}, {"name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true}, {"name": "returnByValue", "type": "boolean", "optional": true}], ["result", "wasThrown"]);
  3590. InspectorBackend.registerCommand("DOMDebugger.setDOMBreakpoint", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "type", "type": "string", "optional": false}], []);
  3591. InspectorBackend.registerCommand("DOMDebugger.removeDOMBreakpoint", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "type", "type": "string", "optional": false}], []);
  3592. InspectorBackend.registerCommand("DOMDebugger.setEventListenerBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []);
  3593. InspectorBackend.registerCommand("DOMDebugger.removeEventListenerBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []);
  3594. InspectorBackend.registerCommand("DOMDebugger.setInstrumentationBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []);
  3595. InspectorBackend.registerCommand("DOMDebugger.removeInstrumentationBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []);
  3596. InspectorBackend.registerCommand("DOMDebugger.setXHRBreakpoint", [{"name": "url", "type": "string", "optional": false}], []);
  3597. InspectorBackend.registerCommand("DOMDebugger.removeXHRBreakpoint", [{"name": "url", "type": "string", "optional": false}], []);
  3598. InspectorBackend.registerProfilerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Profiler");
  3599. InspectorBackend.registerEvent("Profiler.addProfileHeader", ["header"]);
  3600. InspectorBackend.registerEvent("Profiler.addHeapSnapshotChunk", ["uid", "chunk"]);
  3601. InspectorBackend.registerEvent("Profiler.finishHeapSnapshot", ["uid"]);
  3602. InspectorBackend.registerEvent("Profiler.setRecordingProfile", ["isProfiling"]);
  3603. InspectorBackend.registerEvent("Profiler.resetProfiles", []);
  3604. InspectorBackend.registerEvent("Profiler.reportHeapSnapshotProgress", ["done", "total"]);
  3605. InspectorBackend.registerCommand("Profiler.causesRecompilation", [], ["result"]);
  3606. InspectorBackend.registerCommand("Profiler.isSampling", [], ["result"]);
  3607. InspectorBackend.registerCommand("Profiler.hasHeapProfiler", [], ["result"]);
  3608. InspectorBackend.registerCommand("Profiler.enable", [], []);
  3609. InspectorBackend.registerCommand("Profiler.disable", [], []);
  3610. InspectorBackend.registerCommand("Profiler.start", [], []);
  3611. InspectorBackend.registerCommand("Profiler.stop", [], []);
  3612. InspectorBackend.registerCommand("Profiler.getProfileHeaders", [], ["headers"]);
  3613. InspectorBackend.registerCommand("Profiler.getProfile", [{"name": "type", "type": "string", "optional": false}, {"name": "uid", "type": "number", "optional": false}], ["profile"]);
  3614. InspectorBackend.registerCommand("Profiler.removeProfile", [{"name": "type", "type": "string", "optional": false}, {"name": "uid", "type": "number", "optional": false}], []);
  3615. InspectorBackend.registerCommand("Profiler.clearProfiles", [], []);
  3616. InspectorBackend.registerCommand("Profiler.takeHeapSnapshot", [], []);
  3617. InspectorBackend.registerCommand("Profiler.collectGarbage", [], []);
  3618. InspectorBackend.registerCommand("Profiler.getObjectByHeapObjectId", [{"name": "objectId", "type": "string", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}], ["result"]);
  3619. InspectorBackend.registerCommand("Profiler.getHeapObjectId", [{"name": "objectId", "type": "string", "optional": false}], ["heapSnapshotObjectId"]);
  3620. InspectorBackend.registerWorkerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Worker");
  3621. InspectorBackend.registerEvent("Worker.workerCreated", ["workerId", "url", "inspectorConnected"]);
  3622. InspectorBackend.registerEvent("Worker.workerTerminated", ["workerId"]);
  3623. InspectorBackend.registerEvent("Worker.dispatchMessageFromWorker", ["workerId", "message"]);
  3624. InspectorBackend.registerEvent("Worker.disconnectedFromWorker", []);
  3625. InspectorBackend.registerCommand("Worker.setWorkerInspectionEnabled", [{"name": "value", "type": "boolean", "optional": false}], []);
  3626. InspectorBackend.registerCommand("Worker.sendMessageToWorker", [{"name": "workerId", "type": "number", "optional": false}, {"name": "message", "type": "object", "optional": false}], []);
  3627. InspectorBackend.registerCommand("Worker.connectToWorker", [{"name": "workerId", "type": "number", "optional": false}], []);
  3628. InspectorBackend.registerCommand("Worker.disconnectFromWorker", [{"name": "workerId", "type": "number", "optional": false}], []);
  3629. InspectorBackend.registerCommand("Worker.setAutoconnectToWorkers", [{"name": "value", "type": "boolean", "optional": false}], []);
  3630. if (!window.InspectorExtensionRegistry) {
  3631. WebInspector.InspectorExtensionRegistryStub = function()
  3632. {
  3633. }
  3634. WebInspector.InspectorExtensionRegistryStub.prototype = {
  3635. getExtensionsAsync: function()
  3636. {
  3637. }
  3638. }
  3639. var InspectorExtensionRegistry = new WebInspector.InspectorExtensionRegistryStub();
  3640. }
  3641. InspectorFrontendAPI = {
  3642. _pendingCommands: [],
  3643. isDebuggingEnabled: function()
  3644. {
  3645. return WebInspector.panels.scripts.debuggingEnabled;
  3646. },
  3647. setDebuggingEnabled: function(enabled)
  3648. {
  3649. if (enabled) {
  3650. WebInspector.panels.scripts.enableDebugging();
  3651. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.scripts);
  3652. } else
  3653. WebInspector.panels.scripts.disableDebugging();
  3654. },
  3655. isTimelineProfilingEnabled: function()
  3656. {
  3657. return WebInspector.panels.timeline.timelineProfilingEnabled;
  3658. },
  3659. setTimelineProfilingEnabled: function(enabled)
  3660. {
  3661. WebInspector.panels.timeline.setTimelineProfilingEnabled(enabled);
  3662. },
  3663. isProfilingJavaScript: function()
  3664. {
  3665. return WebInspector.CPUProfileType.instance && WebInspector.CPUProfileType.instance.isRecordingProfile();
  3666. },
  3667. startProfilingJavaScript: function()
  3668. {
  3669. WebInspector.panels.profiles.enableProfiler();
  3670. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.profiles);
  3671. if (WebInspector.CPUProfileType.instance)
  3672. WebInspector.CPUProfileType.instance.startRecordingProfile();
  3673. },
  3674. stopProfilingJavaScript: function()
  3675. {
  3676. if (WebInspector.CPUProfileType.instance)
  3677. WebInspector.CPUProfileType.instance.stopRecordingProfile();
  3678. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.profiles);
  3679. },
  3680. setAttachedWindow: function(attached)
  3681. {
  3682. WebInspector.attached = attached;
  3683. },
  3684. showConsole: function()
  3685. {
  3686. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.console);
  3687. },
  3688. showMainResourceForFrame: function(frameId)
  3689. {
  3690. },
  3691. showResources: function()
  3692. {
  3693. WebInspector.inspectorView.setCurrentPanel(WebInspector.panels.resources);
  3694. },
  3695. setDockingUnavailable: function(unavailable)
  3696. {
  3697. WebInspector.setDockingUnavailable(unavailable);
  3698. },
  3699. enterInspectElementMode: function()
  3700. {
  3701. WebInspector.toggleSearchingForNode();
  3702. },
  3703. savedURL: function(url)
  3704. {
  3705. WebInspector.fileManager.savedURL(url);
  3706. },
  3707. appendedToURL: function(url)
  3708. {
  3709. WebInspector.fileManager.appendedToURL(url);
  3710. },
  3711. setToolbarColors: function(backgroundColor, color)
  3712. {
  3713. WebInspector.setToolbarColors(backgroundColor, color);
  3714. },
  3715. dispatch: function(signature)
  3716. {
  3717. if (WebInspector.panels) {
  3718. var methodName = signature.shift();
  3719. return InspectorFrontendAPI[methodName].apply(InspectorFrontendAPI, signature);
  3720. }
  3721. InspectorFrontendAPI._pendingCommands.push(signature);
  3722. },
  3723. loadCompleted: function()
  3724. {
  3725. for (var i = 0; i < InspectorFrontendAPI._pendingCommands.length; ++i)
  3726. InspectorFrontendAPI.dispatch(InspectorFrontendAPI._pendingCommands[i]);
  3727. InspectorFrontendAPI._pendingCommands = [];
  3728. }
  3729. }
  3730. WebInspector.Object = function() {
  3731. }
  3732. WebInspector.Object.prototype = {
  3733. addEventListener: function(eventType, listener, thisObject)
  3734. {
  3735. console.assert(listener);
  3736. if (!this._listeners)
  3737. this._listeners = {};
  3738. if (!this._listeners[eventType])
  3739. this._listeners[eventType] = [];
  3740. this._listeners[eventType].push({ thisObject: thisObject, listener: listener });
  3741. },
  3742. removeEventListener: function(eventType, listener, thisObject)
  3743. {
  3744. console.assert(listener);
  3745. if (!this._listeners || !this._listeners[eventType])
  3746. return;
  3747. var listeners = this._listeners[eventType];
  3748. for (var i = 0; i < listeners.length; ++i) {
  3749. if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
  3750. listeners.splice(i, 1);
  3751. else if (!listener && thisObject && listeners[i].thisObject === thisObject)
  3752. listeners.splice(i, 1);
  3753. }
  3754. if (!listeners.length)
  3755. delete this._listeners[eventType];
  3756. },
  3757. removeAllListeners: function()
  3758. {
  3759. delete this._listeners;
  3760. },
  3761. hasEventListeners: function(eventType)
  3762. {
  3763. if (!this._listeners || !this._listeners[eventType])
  3764. return false;
  3765. return true;
  3766. },
  3767. dispatchEventToListeners: function(eventType, eventData)
  3768. {
  3769. if (!this._listeners || !this._listeners[eventType])
  3770. return false;
  3771. var event = new WebInspector.Event(this, eventType, eventData);
  3772. var listeners = this._listeners[eventType].slice(0);
  3773. for (var i = 0; i < listeners.length; ++i) {
  3774. listeners[i].listener.call(listeners[i].thisObject, event);
  3775. if (event._stoppedPropagation)
  3776. break;
  3777. }
  3778. return event.defaultPrevented;
  3779. }
  3780. }
  3781. WebInspector.Event = function(target, type, data)
  3782. {
  3783. this.target = target;
  3784. this.type = type;
  3785. this.data = data;
  3786. this.defaultPrevented = false;
  3787. this._stoppedPropagation = false;
  3788. }
  3789. WebInspector.Event.prototype = {
  3790. stopPropagation: function()
  3791. {
  3792. this._stoppedPropagation = true;
  3793. },
  3794. preventDefault: function()
  3795. {
  3796. this.defaultPrevented = true;
  3797. },
  3798. consume: function(preventDefault)
  3799. {
  3800. this.stopPropagation();
  3801. if (preventDefault)
  3802. this.preventDefault();
  3803. }
  3804. }
  3805. WebInspector.notifications = new WebInspector.Object();
  3806. var Preferences = {
  3807. maxInlineTextChildLength: 80,
  3808. minConsoleHeight: 75,
  3809. minSidebarWidth: 100,
  3810. minElementsSidebarWidth: 200,
  3811. minScriptsSidebarWidth: 200,
  3812. styleRulesExpandedState: {},
  3813. showMissingLocalizedStrings: false,
  3814. useLowerCaseMenuTitlesOnWindows: false,
  3815. sharedWorkersDebugNote: undefined,
  3816. localizeUI: true,
  3817. exposeDisableCache: false,
  3818. exposeWorkersInspection: false,
  3819. applicationTitle: "Web Inspector - %s",
  3820. showHeapSnapshotObjectsHiddenProperties: false,
  3821. showDockToRight: false
  3822. }
  3823. var Capabilities = {
  3824. samplingCPUProfiler: false,
  3825. debuggerCausesRecompilation: true,
  3826. profilerCausesRecompilation: true,
  3827. nativeInstrumentationEnabled: false,
  3828. heapProfilerPresent: false,
  3829. canOverrideDeviceMetrics: false,
  3830. timelineSupportsFrameInstrumentation: false,
  3831. }
  3832. WebInspector.Settings = function()
  3833. {
  3834. this._eventSupport = new WebInspector.Object();
  3835. this.colorFormat = this.createSetting("colorFormat", "hex");
  3836. this.consoleHistory = this.createSetting("consoleHistory", []);
  3837. this.debuggerEnabled = this.createSetting("debuggerEnabled", false);
  3838. this.domWordWrap = this.createSetting("domWordWrap", true);
  3839. this.profilerEnabled = this.createSetting("profilerEnabled", false);
  3840. this.eventListenersFilter = this.createSetting("eventListenersFilter", "all");
  3841. this.lastActivePanel = this.createSetting("lastActivePanel", "elements");
  3842. this.lastViewedScriptFile = this.createSetting("lastViewedScriptFile", "application");
  3843. this.monitoringXHREnabled = this.createSetting("monitoringXHREnabled", false);
  3844. this.preserveConsoleLog = this.createSetting("preserveConsoleLog", false);
  3845. this.resourcesLargeRows = this.createSetting("resourcesLargeRows", true);
  3846. this.resourcesSortOptions = this.createSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"});
  3847. this.resourceViewTab = this.createSetting("resourceViewTab", "preview");
  3848. this.showInheritedComputedStyleProperties = this.createSetting("showInheritedComputedStyleProperties", false);
  3849. this.showUserAgentStyles = this.createSetting("showUserAgentStyles", true);
  3850. this.watchExpressions = this.createSetting("watchExpressions", []);
  3851. this.breakpoints = this.createSetting("breakpoints", []);
  3852. this.eventListenerBreakpoints = this.createSetting("eventListenerBreakpoints", []);
  3853. this.domBreakpoints = this.createSetting("domBreakpoints", []);
  3854. this.xhrBreakpoints = this.createSetting("xhrBreakpoints", []);
  3855. this.sourceMapsEnabled = this.createSetting("sourceMapsEnabled", false);
  3856. this.cacheDisabled = this.createSetting("cacheDisabled", false);
  3857. this.overrideUserAgent = this.createSetting("overrideUserAgent", "");
  3858. this.userAgent = this.createSetting("userAgent", "");
  3859. this.deviceMetrics = this.createSetting("deviceMetrics", "");
  3860. this.deviceFitWindow = this.createSetting("deviceFitWindow", false);
  3861. this.showScriptFolders = this.createSetting("showScriptFolders", true);
  3862. this.dockToRight = this.createSetting("dockToRight", false);
  3863. this.emulateTouchEvents = this.createSetting("emulateTouchEvents", false);
  3864. this.showPaintRects = this.createSetting("showPaintRects", false);
  3865. this.zoomLevel = this.createSetting("zoomLevel", 0);
  3866. this.savedURLs = this.createSetting("savedURLs", {});
  3867. this.javaScriptDisabled = this.createSetting("javaScriptDisabled", false);
  3868. if (this.breakpoints.get().length > 500000)
  3869. this.breakpoints.set([]);
  3870. }
  3871. WebInspector.Settings.prototype = {
  3872. createSetting: function(key, defaultValue)
  3873. {
  3874. return new WebInspector.Setting(key, defaultValue, this._eventSupport);
  3875. }
  3876. }
  3877. WebInspector.Setting = function(name, defaultValue, eventSupport)
  3878. {
  3879. this._name = name;
  3880. this._defaultValue = defaultValue;
  3881. this._eventSupport = eventSupport;
  3882. }
  3883. WebInspector.Setting.prototype = {
  3884. addChangeListener: function(listener, thisObject)
  3885. {
  3886. this._eventSupport.addEventListener(this._name, listener, thisObject);
  3887. },
  3888. removeChangeListener: function(listener, thisObject)
  3889. {
  3890. this._eventSupport.removeEventListener(this._name, listener, thisObject);
  3891. },
  3892. get name()
  3893. {
  3894. return this._name;
  3895. },
  3896. get: function()
  3897. {
  3898. if (typeof this._value !== "undefined")
  3899. return this._value;
  3900. this._value = this._defaultValue;
  3901. if (window.localStorage != null && this._name in window.localStorage) {
  3902. try {
  3903. this._value = JSON.parse(window.localStorage[this._name]);
  3904. } catch(e) {
  3905. window.localStorage.removeItem(this._name);
  3906. }
  3907. }
  3908. return this._value;
  3909. },
  3910. set: function(value)
  3911. {
  3912. this._value = value;
  3913. if (window.localStorage != null) {
  3914. try {
  3915. window.localStorage[this._name] = JSON.stringify(value);
  3916. } catch(e) {
  3917. console.error("Error saving setting with name:" + this._name);
  3918. }
  3919. }
  3920. this._eventSupport.dispatchEventToListeners(this._name, value);
  3921. }
  3922. }
  3923. WebInspector.ExperimentsSettings = function()
  3924. {
  3925. this._setting = WebInspector.settings.createSetting("experiments", {});
  3926. this._experiments = [];
  3927. this._enabledForTest = {};
  3928. this.showShadowDOM = this._createExperiment("showShadowDOM", "Show shadow DOM");
  3929. this.snippetsSupport = this._createExperiment("snippetsSupport", "Snippets support");
  3930. this.sourceCodePanel = this._createExperiment("sourceCodePanel", "Source Code panel");
  3931. this._cleanUpSetting();
  3932. }
  3933. WebInspector.ExperimentsSettings.prototype = {
  3934. get experiments()
  3935. {
  3936. return this._experiments.slice();
  3937. },
  3938. get experimentsEnabled()
  3939. {
  3940. return "experiments" in WebInspector.queryParamsObject;
  3941. },
  3942. _createExperiment: function(experimentName, experimentTitle)
  3943. {
  3944. var experiment = new WebInspector.Experiment(this, experimentName, experimentTitle);
  3945. this._experiments.push(experiment);
  3946. return experiment;
  3947. },
  3948. isEnabled: function(experimentName)
  3949. {
  3950. if (this._enabledForTest[experimentName])
  3951. return true;
  3952. if (!this.experimentsEnabled)
  3953. return false;
  3954. var experimentsSetting = this._setting.get();
  3955. return experimentsSetting[experimentName];
  3956. },
  3957. setEnabled: function(experimentName, enabled)
  3958. {
  3959. var experimentsSetting = this._setting.get();
  3960. experimentsSetting[experimentName] = enabled;
  3961. this._setting.set(experimentsSetting);
  3962. },
  3963. _enableForTest: function(experimentName)
  3964. {
  3965. this._enabledForTest[experimentName] = true;
  3966. },
  3967. _cleanUpSetting: function()
  3968. {
  3969. var experimentsSetting = this._setting.get();
  3970. var cleanedUpExperimentSetting = {};
  3971. for (var i = 0; i < this._experiments.length; ++i) {
  3972. var experimentName = this._experiments[i].name;
  3973. if (experimentsSetting[experimentName])
  3974. cleanedUpExperimentSetting[experimentName] = true;
  3975. }
  3976. this._setting.set(cleanedUpExperimentSetting);
  3977. }
  3978. }
  3979. WebInspector.Experiment = function(experimentsSettings, name, title)
  3980. {
  3981. this._name = name;
  3982. this._title = title;
  3983. this._experimentsSettings = experimentsSettings;
  3984. }
  3985. WebInspector.Experiment.prototype = {
  3986. get name()
  3987. {
  3988. return this._name;
  3989. },
  3990. get title()
  3991. {
  3992. return this._title;
  3993. },
  3994. isEnabled: function()
  3995. {
  3996. return this._experimentsSettings.isEnabled(this._name);
  3997. },
  3998. setEnabled: function(enabled)
  3999. {
  4000. return this._experimentsSettings.setEnabled(this._name, enabled);
  4001. },
  4002. enableForTest: function()
  4003. {
  4004. this._experimentsSettings._enableForTest(this._name);
  4005. }
  4006. }
  4007. WebInspector.settings = new WebInspector.Settings();
  4008. WebInspector.experimentsSettings = new WebInspector.ExperimentsSettings();
  4009. WebInspector.View = function()
  4010. {
  4011. this.element = document.createElement("div");
  4012. this.element.__view = this;
  4013. this._visible = true;
  4014. this._isRoot = false;
  4015. this._isShowing = false;
  4016. this._children = [];
  4017. this._hideOnDetach = false;
  4018. this._cssFiles = [];
  4019. }
  4020. WebInspector.View._cssFileToVisibleViewCount = {};
  4021. WebInspector.View._cssFileToStyleElement = {};
  4022. WebInspector.View.prototype = {
  4023. markAsRoot: function()
  4024. {
  4025. this._isRoot = true;
  4026. },
  4027. isShowing: function()
  4028. {
  4029. return this._isShowing;
  4030. },
  4031. setHideOnDetach: function()
  4032. {
  4033. this._hideOnDetach = true;
  4034. },
  4035. _parentIsShowing: function()
  4036. {
  4037. return this._isRoot || (this._parentView && this._parentView.isShowing());
  4038. },
  4039. _callOnVisibleChildren: function(method)
  4040. {
  4041. for (var i = 0; i < this._children.length; ++i)
  4042. if (this._children[i]._visible)
  4043. method.call(this._children[i]);
  4044. },
  4045. _processWillShow: function()
  4046. {
  4047. this._loadCSSIfNeeded();
  4048. this._callOnVisibleChildren(this._processWillShow);
  4049. },
  4050. _processWasShown: function()
  4051. {
  4052. this._isShowing = true;
  4053. this.restoreScrollPositions();
  4054. this.wasShown();
  4055. this.onResize();
  4056. this._callOnVisibleChildren(this._processWasShown);
  4057. },
  4058. _processWillHide: function()
  4059. {
  4060. this.storeScrollPositions();
  4061. this._callOnVisibleChildren(this._processWillHide);
  4062. this.willHide();
  4063. this._isShowing = false;
  4064. },
  4065. _processWasHidden: function()
  4066. {
  4067. this._disableCSSIfNeeded();
  4068. this._callOnVisibleChildren(this._processWasHidden);
  4069. },
  4070. _processOnResize: function()
  4071. {
  4072. if (!this.isShowing())
  4073. return;
  4074. this.onResize();
  4075. this._callOnVisibleChildren(this._processOnResize);
  4076. },
  4077. wasShown: function()
  4078. {
  4079. },
  4080. willHide: function()
  4081. {
  4082. },
  4083. onResize: function()
  4084. {
  4085. },
  4086. show: function(parentElement, insertBefore)
  4087. {
  4088. WebInspector.View._assert(parentElement, "Attempt to attach view with no parent element");
  4089. if (this.element.parentElement !== parentElement) {
  4090. var currentParent = parentElement;
  4091. while (currentParent && !currentParent.__view)
  4092. currentParent = currentParent.parentElement;
  4093. if (currentParent) {
  4094. this._parentView = currentParent.__view;
  4095. this._parentView._children.push(this);
  4096. this._isRoot = false;
  4097. } else
  4098. WebInspector.View._assert(this._isRoot, "Attempt to attach view to orphan node");
  4099. } else if (this._visible)
  4100. return;
  4101. this._visible = true;
  4102. if (this._parentIsShowing())
  4103. this._processWillShow();
  4104. this.element.addStyleClass("visible");
  4105. if (this.element.parentElement !== parentElement) {
  4106. WebInspector.View._incrementViewCounter(parentElement, this.element);
  4107. if (insertBefore)
  4108. WebInspector.View._originalInsertBefore.call(parentElement, this.element, insertBefore);
  4109. else
  4110. WebInspector.View._originalAppendChild.call(parentElement, this.element);
  4111. }
  4112. if (this._parentIsShowing())
  4113. this._processWasShown();
  4114. },
  4115. detach: function(overrideHideOnDetach)
  4116. {
  4117. var parentElement = this.element.parentElement;
  4118. if (!parentElement)
  4119. return;
  4120. if (this._parentIsShowing())
  4121. this._processWillHide();
  4122. if (this._hideOnDetach && !overrideHideOnDetach) {
  4123. this.element.removeStyleClass("visible");
  4124. this._visible = false;
  4125. if (this._parentIsShowing())
  4126. this._processWasHidden();
  4127. return;
  4128. }
  4129. WebInspector.View._decrementViewCounter(parentElement, this.element);
  4130. WebInspector.View._originalRemoveChild.call(parentElement, this.element);
  4131. this._visible = false;
  4132. if (this._parentIsShowing())
  4133. this._processWasHidden();
  4134. if (this._parentView) {
  4135. var childIndex = this._parentView._children.indexOf(this);
  4136. WebInspector.View._assert(childIndex >= 0, "Attempt to remove non-child view");
  4137. this._parentView._children.splice(childIndex, 1);
  4138. this._parentView = null;
  4139. } else
  4140. WebInspector.View._assert(this._isRoot, "Removing non-root view from DOM");
  4141. },
  4142. detachChildViews: function()
  4143. {
  4144. var children = this._children.slice();
  4145. for (var i = 0; i < children.length; ++i)
  4146. children[i].detach();
  4147. },
  4148. elementsToRestoreScrollPositionsFor: function()
  4149. {
  4150. return [this.element];
  4151. },
  4152. storeScrollPositions: function()
  4153. {
  4154. var elements = this.elementsToRestoreScrollPositionsFor();
  4155. for (var i = 0; i < elements.length; ++i) {
  4156. var container = elements[i];
  4157. container._scrollTop = container.scrollTop;
  4158. container._scrollLeft = container.scrollLeft;
  4159. }
  4160. },
  4161. restoreScrollPositions: function()
  4162. {
  4163. var elements = this.elementsToRestoreScrollPositionsFor();
  4164. for (var i = 0; i < elements.length; ++i) {
  4165. var container = elements[i];
  4166. if (container._scrollTop)
  4167. container.scrollTop = container._scrollTop;
  4168. if (container._scrollLeft)
  4169. container.scrollLeft = container._scrollLeft;
  4170. }
  4171. },
  4172. canHighlightLine: function()
  4173. {
  4174. return false;
  4175. },
  4176. highlightLine: function(line)
  4177. {
  4178. },
  4179. doResize: function()
  4180. {
  4181. this._processOnResize();
  4182. },
  4183. registerRequiredCSS: function(cssFile)
  4184. {
  4185. this._cssFiles.push(cssFile);
  4186. },
  4187. _loadCSSIfNeeded: function()
  4188. {
  4189. for (var i = 0; i < this._cssFiles.length; ++i) {
  4190. var cssFile = this._cssFiles[i];
  4191. var viewsWithCSSFile = WebInspector.View._cssFileToVisibleViewCount[cssFile];
  4192. WebInspector.View._cssFileToVisibleViewCount[cssFile] = (viewsWithCSSFile || 0) + 1;
  4193. if (!viewsWithCSSFile)
  4194. this._doLoadCSS(cssFile);
  4195. }
  4196. },
  4197. _doLoadCSS: function(cssFile)
  4198. {
  4199. var styleElement = WebInspector.View._cssFileToStyleElement[cssFile];
  4200. if (styleElement) {
  4201. styleElement.disabled = false;
  4202. return;
  4203. }
  4204. if (window.debugCSS) {
  4205. styleElement = document.createElement("link");
  4206. styleElement.rel = "stylesheet";
  4207. styleElement.type = "text/css";
  4208. styleElement.href = cssFile;
  4209. } else {
  4210. var xhr = new XMLHttpRequest();
  4211. xhr.open("GET", cssFile, false);
  4212. xhr.send(null);
  4213. styleElement = document.createElement("style");
  4214. styleElement.type = "text/css";
  4215. styleElement.textContent = xhr.responseText;
  4216. }
  4217. document.head.insertBefore(styleElement, document.head.firstChild);
  4218. WebInspector.View._cssFileToStyleElement[cssFile] = styleElement;
  4219. },
  4220. _disableCSSIfNeeded: function()
  4221. {
  4222. for (var i = 0; i < this._cssFiles.length; ++i) {
  4223. var cssFile = this._cssFiles[i];
  4224. var viewsWithCSSFile = WebInspector.View._cssFileToVisibleViewCount[cssFile];
  4225. viewsWithCSSFile--;
  4226. WebInspector.View._cssFileToVisibleViewCount[cssFile] = viewsWithCSSFile;
  4227. if (!viewsWithCSSFile)
  4228. this._doUnloadCSS(cssFile);
  4229. }
  4230. },
  4231. _doUnloadCSS: function(cssFile)
  4232. {
  4233. var styleElement = WebInspector.View._cssFileToStyleElement[cssFile];
  4234. styleElement.disabled = true;
  4235. },
  4236. printViewHierarchy: function()
  4237. {
  4238. var lines = [];
  4239. this._collectViewHierarchy("", lines);
  4240. console.log(lines.join("\n"));
  4241. },
  4242. _collectViewHierarchy: function(prefix, lines)
  4243. {
  4244. lines.push(prefix + "[" + this.element.className + "]" + (this._children.length ? " {" : ""));
  4245. for (var i = 0; i < this._children.length; ++i)
  4246. this._children[i]._collectViewHierarchy(prefix + " ", lines);
  4247. if (this._children.length)
  4248. lines.push(prefix + "}");
  4249. },
  4250. defaultFocusedElement: function()
  4251. {
  4252. return this._defaultFocusedElement || this.element;
  4253. },
  4254. setDefaultFocusedElement: function(element)
  4255. {
  4256. this._defaultFocusedElement = element;
  4257. },
  4258. focus: function()
  4259. {
  4260. var element = this.defaultFocusedElement();
  4261. if (!element || element.isAncestor(document.activeElement))
  4262. return;
  4263. WebInspector.setCurrentFocusElement(element);
  4264. }
  4265. }
  4266. WebInspector.View.prototype.__proto__ = WebInspector.Object.prototype;
  4267. WebInspector.View._originalAppendChild = Element.prototype.appendChild;
  4268. WebInspector.View._originalInsertBefore = Element.prototype.insertBefore;
  4269. WebInspector.View._originalRemoveChild = Element.prototype.removeChild;
  4270. WebInspector.View._originalRemoveChildren = Element.prototype.removeChildren;
  4271. WebInspector.View._incrementViewCounter = function(parentElement, childElement)
  4272. {
  4273. var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0);
  4274. if (!count)
  4275. return;
  4276. while (parentElement) {
  4277. parentElement.__viewCounter = (parentElement.__viewCounter || 0) + count;
  4278. parentElement = parentElement.parentElement;
  4279. }
  4280. }
  4281. WebInspector.View._decrementViewCounter = function(parentElement, childElement)
  4282. {
  4283. var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0);
  4284. if (!count)
  4285. return;
  4286. while (parentElement) {
  4287. parentElement.__viewCounter -= count;
  4288. parentElement = parentElement.parentElement;
  4289. }
  4290. }
  4291. WebInspector.View._assert = function(condition, message)
  4292. {
  4293. if (!condition) {
  4294. console.trace();
  4295. throw new Error(message);
  4296. }
  4297. }
  4298. Element.prototype.appendChild = function(child)
  4299. {
  4300. WebInspector.View._assert(!child.__view, "Attempt to add view via regular DOM operation.");
  4301. return WebInspector.View._originalAppendChild.call(this, child);
  4302. }
  4303. Element.prototype.insertBefore = function(child, anchor)
  4304. {
  4305. WebInspector.View._assert(!child.__view, "Attempt to add view via regular DOM operation.");
  4306. return WebInspector.View._originalInsertBefore.call(this, child, anchor);
  4307. }
  4308. Element.prototype.removeChild = function(child)
  4309. {
  4310. WebInspector.View._assert(!child.__viewCounter && !child.__view, "Attempt to remove element containing view via regular DOM operation");
  4311. return WebInspector.View._originalRemoveChild.call(this, child);
  4312. }
  4313. Element.prototype.removeChildren = function()
  4314. {
  4315. WebInspector.View._assert(!this.__viewCounter, "Attempt to remove element containing view via regular DOM operation");
  4316. WebInspector.View._originalRemoveChildren.call(this);
  4317. }
  4318. WebInspector.HelpScreen = function(title)
  4319. {
  4320. WebInspector.View.call(this);
  4321. this.registerRequiredCSS("helpScreen.css");
  4322. this.element.className = "help-window-outer";
  4323. this.element.addEventListener("keydown", this._onKeyDown.bind(this), false);
  4324. this.element.tabIndex = 0;
  4325. this.element.addEventListener("focus", this._onBlur.bind(this), false);
  4326. var mainWindow = this.element.createChild("div", "help-window-main");
  4327. var captionWindow = mainWindow.createChild("div", "help-window-caption");
  4328. var closeButton = captionWindow.createChild("button", "help-close-button");
  4329. this.contentElement = mainWindow.createChild("div", "help-content");
  4330. captionWindow.createChild("h1", "help-window-title").textContent = title;
  4331. closeButton.textContent = "\u2716";
  4332. closeButton.addEventListener("click", this.hide.bind(this), false);
  4333. }
  4334. WebInspector.HelpScreen._visibleScreen = null;
  4335. WebInspector.HelpScreen.prototype = {
  4336. showModal: function()
  4337. {
  4338. var visibleHelpScreen = WebInspector.HelpScreen._visibleScreen;
  4339. if (visibleHelpScreen === this)
  4340. return;
  4341. if (visibleHelpScreen)
  4342. visibleHelpScreen.hide();
  4343. WebInspector.HelpScreen._visibleScreen = this;
  4344. this.show(WebInspector.inspectorView.element);
  4345. this.focus();
  4346. },
  4347. hide: function()
  4348. {
  4349. if (!this.isShowing())
  4350. return;
  4351. WebInspector.HelpScreen._visibleScreen = null;
  4352. WebInspector.restoreFocusFromElement(this.element);
  4353. this.detach();
  4354. },
  4355. isClosingKey: function(keyCode)
  4356. {
  4357. return [
  4358. WebInspector.KeyboardShortcut.Keys.Enter.code,
  4359. WebInspector.KeyboardShortcut.Keys.Esc.code,
  4360. WebInspector.KeyboardShortcut.Keys.Space.code,
  4361. ].indexOf(keyCode) >= 0;
  4362. },
  4363. _onKeyDown: function(event)
  4364. {
  4365. if (this.isShowing() && this.isClosingKey(event.keyCode)) {
  4366. this.hide();
  4367. event.consume();
  4368. }
  4369. },
  4370. _onBlur: function(event)
  4371. {
  4372. if (this.isShowing() && !this.element.isSelfOrAncestor(event.target))
  4373. WebInspector.setCurrentFocusElement(this.element);
  4374. }
  4375. }
  4376. WebInspector.HelpScreen.prototype.__proto__ = WebInspector.View.prototype;
  4377. if (!window.InspectorFrontendHost) {
  4378. WebInspector.InspectorFrontendHostStub = function()
  4379. {
  4380. this._attachedWindowHeight = 0;
  4381. this.isStub = true;
  4382. WebInspector.documentCopyEventFired = this.documentCopy.bind(this);
  4383. }
  4384. WebInspector.InspectorFrontendHostStub.prototype = {
  4385. platform: function()
  4386. {
  4387. var match = navigator.userAgent.match(/Windows NT/);
  4388. if (match)
  4389. return "windows";
  4390. match = navigator.userAgent.match(/Mac OS X/);
  4391. if (match)
  4392. return "mac";
  4393. return "linux";
  4394. },
  4395. port: function()
  4396. {
  4397. return "unknown";
  4398. },
  4399. bringToFront: function()
  4400. {
  4401. this._windowVisible = true;
  4402. },
  4403. closeWindow: function()
  4404. {
  4405. this._windowVisible = false;
  4406. },
  4407. requestAttachWindow: function()
  4408. {
  4409. },
  4410. requestDetachWindow: function()
  4411. {
  4412. },
  4413. requestSetDockSide: function()
  4414. {
  4415. },
  4416. setAttachedWindowHeight: function(height)
  4417. {
  4418. },
  4419. moveWindowBy: function(x, y)
  4420. {
  4421. },
  4422. setInjectedScriptForOrigin: function(origin, script)
  4423. {
  4424. },
  4425. loaded: function()
  4426. {
  4427. },
  4428. localizedStringsURL: function()
  4429. {
  4430. return undefined;
  4431. },
  4432. hiddenPanels: function()
  4433. {
  4434. return "";
  4435. },
  4436. inspectedURLChanged: function(url)
  4437. {
  4438. document.title = WebInspector.UIString(Preferences.applicationTitle, url);
  4439. },
  4440. documentCopy: function(event)
  4441. {
  4442. if (!this._textToCopy)
  4443. return;
  4444. event.clipboardData.setData("text", this._textToCopy);
  4445. event.preventDefault();
  4446. delete this._textToCopy;
  4447. },
  4448. copyText: function(text)
  4449. {
  4450. this._textToCopy = text;
  4451. if (!document.execCommand("copy")) {
  4452. var screen = new WebInspector.ClipboardAccessDeniedScreen();
  4453. screen.showModal();
  4454. }
  4455. },
  4456. openInNewTab: function(url)
  4457. {
  4458. window.open(url, "_blank");
  4459. },
  4460. canSave: function()
  4461. {
  4462. return true;
  4463. },
  4464. save: function(url, content, forceSaveAs)
  4465. {
  4466. var builder = new WebKitBlobBuilder();
  4467. builder.append(content);
  4468. var blob = builder.getBlob("application/octet-stream");
  4469. var fr = new FileReader();
  4470. fr.onload = function(e) {
  4471. window.location = this.result;
  4472. }
  4473. fr.readAsDataURL(blob);
  4474. },
  4475. canAppend: function()
  4476. {
  4477. return false;
  4478. },
  4479. append: function(url, content)
  4480. {
  4481. },
  4482. sendMessageToBackend: function(message)
  4483. {
  4484. },
  4485. recordActionTaken: function(actionCode)
  4486. {
  4487. },
  4488. recordPanelShown: function(panelCode)
  4489. {
  4490. },
  4491. recordSettingChanged: function(settingCode)
  4492. {
  4493. },
  4494. loadResourceSynchronously: function(url)
  4495. {
  4496. return "";
  4497. },
  4498. setZoomFactor: function(zoom)
  4499. {
  4500. }
  4501. }
  4502. var InspectorFrontendHost = new WebInspector.InspectorFrontendHostStub();
  4503. Preferences.localizeUI = false;
  4504. WebInspector.clipboardAccessDeniedMessage = function()
  4505. {
  4506. return "";
  4507. }
  4508. WebInspector.ClipboardAccessDeniedScreen = function()
  4509. {
  4510. WebInspector.HelpScreen.call(this, WebInspector.UIString("Clipboard access is denied"));
  4511. var platformMessage = WebInspector.clipboardAccessDeniedMessage();
  4512. if (platformMessage) {
  4513. var p = this.contentElement.createChild("p");
  4514. p.addStyleClass("help-section");
  4515. p.textContent = platformMessage;
  4516. }
  4517. }
  4518. WebInspector.ClipboardAccessDeniedScreen.prototype.__proto__ = WebInspector.HelpScreen.prototype;
  4519. }
  4520. WebInspector.FileManager = function()
  4521. {
  4522. }
  4523. WebInspector.FileManager.EventTypes = {
  4524. SavedURL: "SavedURL",
  4525. AppendedToURL: "AppendedToURL"
  4526. }
  4527. WebInspector.FileManager.prototype = {
  4528. canSave: function()
  4529. {
  4530. return InspectorFrontendHost.canSave();
  4531. },
  4532. canAppend: function()
  4533. {
  4534. return InspectorFrontendHost.canSave() && ("append" in InspectorFrontendHost);
  4535. },
  4536. save: function(url, content, forceSaveAs)
  4537. {
  4538. var savedURLs = WebInspector.settings.savedURLs.get();
  4539. delete savedURLs[url];
  4540. WebInspector.settings.savedURLs.set(savedURLs);
  4541. InspectorFrontendHost.save(url, content, forceSaveAs);
  4542. },
  4543. savedURL: function(url)
  4544. {
  4545. var savedURLs = WebInspector.settings.savedURLs.get();
  4546. savedURLs[url] = true;
  4547. WebInspector.settings.savedURLs.set(savedURLs);
  4548. this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.SavedURL, url);
  4549. },
  4550. isURLSaved: function(url)
  4551. {
  4552. var savedURLs = WebInspector.settings.savedURLs.get();
  4553. return savedURLs[url];
  4554. },
  4555. append: function(url, content)
  4556. {
  4557. InspectorFrontendHost.append(url, content);
  4558. },
  4559. appendedToURL: function(url)
  4560. {
  4561. this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.AppendedToURL, url);
  4562. }
  4563. }
  4564. WebInspector.FileManager.prototype.__proto__ = WebInspector.Object.prototype;
  4565. WebInspector.fileManager = new WebInspector.FileManager();
  4566. WebInspector.Checkbox = function(label, className, tooltip)
  4567. {
  4568. this.element = document.createElement('label');
  4569. this._inputElement = document.createElement('input');
  4570. this._inputElement.type = "checkbox";
  4571. this.element.className = className;
  4572. this.element.appendChild(this._inputElement);
  4573. this.element.appendChild(document.createTextNode(label));
  4574. if (tooltip)
  4575. this.element.title = tooltip;
  4576. }
  4577. WebInspector.Checkbox.prototype = {
  4578. set checked(checked)
  4579. {
  4580. this._inputElement.checked = checked;
  4581. },
  4582. get checked()
  4583. {
  4584. return this._inputElement.checked;
  4585. },
  4586. addEventListener: function(listener)
  4587. {
  4588. function listenerWrapper(event)
  4589. {
  4590. if (listener)
  4591. listener(event);
  4592. event.consume();
  4593. return true;
  4594. }
  4595. this._inputElement.addEventListener("click", listenerWrapper, false);
  4596. this.element.addEventListener("click", listenerWrapper, false);
  4597. }
  4598. }
  4599. WebInspector.ContextMenu = function() {
  4600. this._items = [];
  4601. this._handlers = {};
  4602. }
  4603. WebInspector.ContextMenu.prototype = {
  4604. show: function(event)
  4605. {
  4606. while (this._items.length > 0 && !("id" in this._items[this._items.length - 1]))
  4607. this._items.splice(this._items.length - 1, 1);
  4608. if (this._items.length) {
  4609. WebInspector._contextMenu = this;
  4610. InspectorFrontendHost.showContextMenu(event, this._items);
  4611. }
  4612. event.consume();
  4613. },
  4614. appendItem: function(label, handler, disabled)
  4615. {
  4616. var id = this._items.length;
  4617. this._items.push({type: "item", id: id, label: label, enabled: !disabled});
  4618. this._handlers[id] = handler;
  4619. },
  4620. appendCheckboxItem: function(label, handler, checked, disabled)
  4621. {
  4622. var id = this._items.length;
  4623. this._items.push({type: "checkbox", id: id, label: label, checked: !!checked, enabled: !disabled});
  4624. this._handlers[id] = handler;
  4625. },
  4626. appendSeparator: function()
  4627. {
  4628. if (this._items.length === 0)
  4629. return;
  4630. if (!("id" in this._items[this._items.length - 1]))
  4631. return;
  4632. this._items.push({type: "separator"});
  4633. },
  4634. isEmpty: function()
  4635. {
  4636. return !this._items.length;
  4637. },
  4638. _itemSelected: function(id)
  4639. {
  4640. if (this._handlers[id])
  4641. this._handlers[id].call(this);
  4642. }
  4643. }
  4644. WebInspector.contextMenuItemSelected = function(id)
  4645. {
  4646. if (WebInspector._contextMenu)
  4647. WebInspector._contextMenu._itemSelected(id);
  4648. }
  4649. WebInspector.contextMenuCleared = function()
  4650. {
  4651. }
  4652. if (!InspectorFrontendHost.showContextMenu) {
  4653. WebInspector.SoftContextMenu = function(items)
  4654. {
  4655. this._items = items;
  4656. }
  4657. WebInspector.SoftContextMenu.prototype = {
  4658. show: function(event)
  4659. {
  4660. this._x = event.x;
  4661. this._y = event.y;
  4662. this._time = new Date().getTime();
  4663. var absoluteX = event.pageX;
  4664. var absoluteY = event.pageY;
  4665. var targetElement = event.target;
  4666. while (targetElement && window !== targetElement.ownerDocument.defaultView) {
  4667. var frameElement = targetElement.ownerDocument.defaultView.frameElement;
  4668. absoluteY += frameElement.totalOffsetTop();
  4669. absoluteX += frameElement.totalOffsetLeft();
  4670. targetElement = frameElement;
  4671. }
  4672. this._glassPaneElement = document.createElement("div");
  4673. this._glassPaneElement.className = "soft-context-menu-glass-pane";
  4674. this._glassPaneElement.tabIndex = 0;
  4675. this._glassPaneElement.addEventListener("mouseup", this._glassPaneMouseUp.bind(this), false);
  4676. this._contextMenuElement = document.createElement("div");
  4677. this._contextMenuElement.className = "soft-context-menu";
  4678. this._contextMenuElement.tabIndex = 0;
  4679. this._contextMenuElement.style.top = absoluteY + "px";
  4680. this._contextMenuElement.style.left = absoluteX + "px";
  4681. this._contextMenuElement.addEventListener("mousedown", this._discardMenu.bind(this), false);
  4682. this._contextMenuElement.addEventListener("keydown", this._menuKeyDown.bind(this), false);
  4683. this._contextMenuElement.addEventListener("blur", this._discardMenu.bind(this), false);
  4684. for (var i = 0; i < this._items.length; ++i)
  4685. this._contextMenuElement.appendChild(this._createMenuItem(this._items[i]));
  4686. this._glassPaneElement.appendChild(this._contextMenuElement);
  4687. document.body.appendChild(this._glassPaneElement);
  4688. this._contextMenuElement.focus();
  4689. if (document.body.offsetWidth < this._contextMenuElement.offsetLeft + this._contextMenuElement.offsetWidth)
  4690. this._contextMenuElement.style.left = (absoluteX - this._contextMenuElement.offsetWidth) + "px";
  4691. if (document.body.offsetHeight < this._contextMenuElement.offsetTop + this._contextMenuElement.offsetHeight)
  4692. this._contextMenuElement.style.top = (document.body.offsetHeight - this._contextMenuElement.offsetHeight) + "px";
  4693. event.consume(true);
  4694. },
  4695. _createMenuItem: function(item)
  4696. {
  4697. if (item.type === "separator")
  4698. return this._createSeparator();
  4699. var menuItemElement = document.createElement("div");
  4700. menuItemElement.className = "soft-context-menu-item";
  4701. var checkMarkElement = document.createElement("span");
  4702. checkMarkElement.textContent = "\u2713 ";
  4703. checkMarkElement.className = "soft-context-menu-item-checkmark";
  4704. if (!item.checked)
  4705. checkMarkElement.style.opacity = "0";
  4706. menuItemElement.appendChild(checkMarkElement);
  4707. menuItemElement.appendChild(document.createTextNode(item.label));
  4708. menuItemElement.addEventListener("mousedown", this._menuItemMouseDown.bind(this), false);
  4709. menuItemElement.addEventListener("mouseup", this._menuItemMouseUp.bind(this), false);
  4710. menuItemElement.addEventListener("mouseover", this._menuItemMouseOver.bind(this), false);
  4711. menuItemElement.addEventListener("mouseout", this._menuItemMouseOut.bind(this), false);
  4712. menuItemElement._actionId = item.id;
  4713. return menuItemElement;
  4714. },
  4715. _createSeparator: function()
  4716. {
  4717. var separatorElement = document.createElement("div");
  4718. separatorElement.className = "soft-context-menu-separator";
  4719. separatorElement._isSeparator = true;
  4720. return separatorElement;
  4721. },
  4722. _menuItemMouseDown: function(event)
  4723. {
  4724. event.consume(true);
  4725. },
  4726. _menuItemMouseUp: function(event)
  4727. {
  4728. this._triggerAction(event.target, event);
  4729. },
  4730. _triggerAction: function(menuItemElement, event)
  4731. {
  4732. this._discardMenu(event);
  4733. if (typeof menuItemElement._actionId !== "undefined") {
  4734. WebInspector.contextMenuItemSelected(menuItemElement._actionId);
  4735. delete menuItemElement._actionId;
  4736. }
  4737. },
  4738. _menuItemMouseOver: function(event)
  4739. {
  4740. this._highlightMenuItem(event.target);
  4741. },
  4742. _menuItemMouseOut: function(event)
  4743. {
  4744. this._highlightMenuItem(null);
  4745. },
  4746. _highlightMenuItem: function(menuItemElement)
  4747. {
  4748. if (this._highlightedMenuItemElement)
  4749. this._highlightedMenuItemElement.removeStyleClass("soft-context-menu-item-mouse-over");
  4750. this._highlightedMenuItemElement = menuItemElement;
  4751. if (this._highlightedMenuItemElement)
  4752. this._highlightedMenuItemElement.addStyleClass("soft-context-menu-item-mouse-over");
  4753. },
  4754. _highlightPrevious: function()
  4755. {
  4756. var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.previousSibling : this._contextMenuElement.lastChild;
  4757. while (menuItemElement && menuItemElement._isSeparator)
  4758. menuItemElement = menuItemElement.previousSibling;
  4759. if (menuItemElement)
  4760. this._highlightMenuItem(menuItemElement);
  4761. },
  4762. _highlightNext: function()
  4763. {
  4764. var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.nextSibling : this._contextMenuElement.firstChild;
  4765. while (menuItemElement && menuItemElement._isSeparator)
  4766. menuItemElement = menuItemElement.nextSibling;
  4767. if (menuItemElement)
  4768. this._highlightMenuItem(menuItemElement);
  4769. },
  4770. _menuKeyDown: function(event)
  4771. {
  4772. switch (event.keyIdentifier) {
  4773. case "Up":
  4774. this._highlightPrevious(); break;
  4775. case "Down":
  4776. this._highlightNext(); break;
  4777. case "U+001B":
  4778. this._discardMenu(event); break;
  4779. case "Enter":
  4780. if (!isEnterKey(event))
  4781. break;
  4782. case "U+0020":
  4783. if (this._highlightedMenuItemElement)
  4784. this._triggerAction(this._highlightedMenuItemElement, event);
  4785. break;
  4786. }
  4787. event.consume(true);
  4788. },
  4789. _glassPaneMouseUp: function(event)
  4790. {
  4791. if (event.x === this._x && event.y === this._y && new Date().getTime() - this._time < 300)
  4792. return;
  4793. this._discardMenu(event);
  4794. },
  4795. _discardMenu: function(event)
  4796. {
  4797. if (this._glassPaneElement) {
  4798. var glassPane = this._glassPaneElement;
  4799. delete this._glassPaneElement;
  4800. document.body.removeChild(glassPane);
  4801. event.consume(true);
  4802. }
  4803. }
  4804. }
  4805. InspectorFrontendHost.showContextMenu = function(event, items)
  4806. {
  4807. new WebInspector.SoftContextMenu(items).show(event);
  4808. }
  4809. }
  4810. WebInspector.KeyboardShortcut = function()
  4811. {
  4812. }
  4813. WebInspector.KeyboardShortcut.Modifiers = {
  4814. None: 0,
  4815. Shift: 1,
  4816. Ctrl: 2,
  4817. Alt: 4,
  4818. Meta: 8,
  4819. get CtrlOrMeta()
  4820. {
  4821. return WebInspector.isMac() ? this.Meta : this.Ctrl;
  4822. }
  4823. };
  4824. WebInspector.KeyboardShortcut.Keys = {
  4825. Backspace: { code: 8, name: "\u21a4" },
  4826. Tab: { code: 9, name: { mac: "\u21e5", other: "<Tab>" } },
  4827. Enter: { code: 13, name: { mac: "\u21a9", other: "<Enter>" } },
  4828. Esc: { code: 27, name: { mac: "\u238b", other: "<Esc>" } },
  4829. Space: { code: 32, name: "<Space>" },
  4830. PageUp: { code: 33, name: { mac: "\u21de", other: "<PageUp>" } },
  4831. PageDown: { code: 34, name: { mac: "\u21df", other: "<PageDown>" } },
  4832. End: { code: 35, name: { mac: "\u2197", other: "<End>" } },
  4833. Home: { code: 36, name: { mac: "\u2196", other: "<Home>" } },
  4834. Left: { code: 37, name: "<Left>" },
  4835. Up: { code: 38, name: "<Up>" },
  4836. Right: { code: 39, name: "<Right>" },
  4837. Down: { code: 40, name: "<Down>" },
  4838. Delete: { code: 46, name: "<Del>" },
  4839. Zero: { code: 48, name: "0" },
  4840. F1: { code: 112, name: "F1" },
  4841. F2: { code: 113, name: "F2" },
  4842. F3: { code: 114, name: "F3" },
  4843. F4: { code: 115, name: "F4" },
  4844. F5: { code: 116, name: "F5" },
  4845. F6: { code: 117, name: "F6" },
  4846. F7: { code: 118, name: "F7" },
  4847. F8: { code: 119, name: "F8" },
  4848. F9: { code: 120, name: "F9" },
  4849. F10: { code: 121, name: "F10" },
  4850. F11: { code: 122, name: "F11" },
  4851. F12: { code: 123, name: "F12" },
  4852. Semicolon: { code: 186, name: ";" },
  4853. Plus: { code: 187, name: "+" },
  4854. Comma: { code: 188, name: "," },
  4855. Minus: { code: 189, name: "-" },
  4856. Period: { code: 190, name: "." },
  4857. Slash: { code: 191, name: "/" },
  4858. Apostrophe: { code: 192, name: "`" },
  4859. SingleQuote: { code: 222, name: "\'" }
  4860. };
  4861. WebInspector.KeyboardShortcut.makeKey = function(keyCode, modifiers)
  4862. {
  4863. if (typeof keyCode === "string")
  4864. keyCode = keyCode.charCodeAt(0) - 32;
  4865. modifiers = modifiers || WebInspector.KeyboardShortcut.Modifiers.None;
  4866. return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, modifiers);
  4867. }
  4868. WebInspector.KeyboardShortcut.makeKeyFromEvent = function(keyboardEvent)
  4869. {
  4870. var modifiers = WebInspector.KeyboardShortcut.Modifiers.None;
  4871. if (keyboardEvent.shiftKey)
  4872. modifiers |= WebInspector.KeyboardShortcut.Modifiers.Shift;
  4873. if (keyboardEvent.ctrlKey)
  4874. modifiers |= WebInspector.KeyboardShortcut.Modifiers.Ctrl;
  4875. if (keyboardEvent.altKey)
  4876. modifiers |= WebInspector.KeyboardShortcut.Modifiers.Alt;
  4877. if (keyboardEvent.metaKey)
  4878. modifiers |= WebInspector.KeyboardShortcut.Modifiers.Meta;
  4879. return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyboardEvent.keyCode, modifiers);
  4880. }
  4881. WebInspector.KeyboardShortcut.eventHasCtrlOrMeta = function(event)
  4882. {
  4883. return WebInspector.isMac() ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey;
  4884. }
  4885. WebInspector.KeyboardShortcut.makeDescriptor = function(key, modifiers)
  4886. {
  4887. return {
  4888. key: WebInspector.KeyboardShortcut.makeKey(typeof key === "string" ? key : key.code, modifiers),
  4889. name: WebInspector.KeyboardShortcut.shortcutToString(key, modifiers)
  4890. };
  4891. }
  4892. WebInspector.KeyboardShortcut.shortcutToString = function(key, modifiers)
  4893. {
  4894. return WebInspector.KeyboardShortcut._modifiersToString(modifiers) + WebInspector.KeyboardShortcut._keyName(key);
  4895. }
  4896. WebInspector.KeyboardShortcut._keyName = function(key)
  4897. {
  4898. if (typeof key === "string")
  4899. return key.toUpperCase();
  4900. if (typeof key.name === "string")
  4901. return key.name;
  4902. return key.name[WebInspector.platform()] || key.name.other;
  4903. }
  4904. WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers = function(keyCode, modifiers)
  4905. {
  4906. return (keyCode & 255) | (modifiers << 8);
  4907. };
  4908. WebInspector.KeyboardShortcut._modifiersToString = function(modifiers)
  4909. {
  4910. const cmdKey = "\u2318";
  4911. const optKey = "\u2325";
  4912. const shiftKey = "\u21e7";
  4913. const ctrlKey = "\u2303";
  4914. var isMac = WebInspector.isMac();
  4915. var res = "";
  4916. if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Ctrl)
  4917. res += isMac ? ctrlKey : "<Ctrl> + ";
  4918. if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Alt)
  4919. res += isMac ? optKey : "<Alt> + ";
  4920. if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Shift)
  4921. res += isMac ? shiftKey : "<Shift> + ";
  4922. if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Meta)
  4923. res += isMac ? cmdKey : "<Win> + ";
  4924. return res;
  4925. };
  4926. WebInspector.TextPrompt = function(completions, stopCharacters)
  4927. {
  4928. this._proxyElement;
  4929. this._proxyElementDisplay = "inline-block";
  4930. this._loadCompletions = completions;
  4931. this._completionStopCharacters = stopCharacters;
  4932. this._suggestForceable = true;
  4933. }
  4934. WebInspector.TextPrompt.Events = {
  4935. ItemApplied: "text-prompt-item-applied",
  4936. ItemAccepted: "text-prompt-item-accepted"
  4937. };
  4938. WebInspector.TextPrompt.prototype = {
  4939. get proxyElement()
  4940. {
  4941. return this._proxyElement;
  4942. },
  4943. setSuggestForceable: function(x)
  4944. {
  4945. this._suggestForceable = x;
  4946. },
  4947. setSuggestBoxEnabled: function(className)
  4948. {
  4949. this._suggestBoxClassName = className;
  4950. },
  4951. renderAsBlock: function()
  4952. {
  4953. this._proxyElementDisplay = "block";
  4954. },
  4955. attach: function(element)
  4956. {
  4957. return this._attachInternal(element);
  4958. },
  4959. attachAndStartEditing: function(element, blurListener)
  4960. {
  4961. this._attachInternal(element);
  4962. this._startEditing(blurListener);
  4963. return this.proxyElement;
  4964. },
  4965. _attachInternal: function(element)
  4966. {
  4967. if (this.proxyElement)
  4968. throw "Cannot attach an attached TextPrompt";
  4969. this._element = element;
  4970. this._boundOnKeyDown = this.onKeyDown.bind(this);
  4971. this._boundSelectStart = this._selectStart.bind(this);
  4972. this._proxyElement = element.ownerDocument.createElement("span");
  4973. this._proxyElement.style.display = this._proxyElementDisplay;
  4974. element.parentElement.insertBefore(this.proxyElement, element);
  4975. this.proxyElement.appendChild(element);
  4976. this._element.addStyleClass("text-prompt");
  4977. this._element.addEventListener("keydown", this._boundOnKeyDown, false);
  4978. this._element.addEventListener("selectstart", this._boundSelectStart, false);
  4979. if (typeof this._suggestBoxClassName === "string")
  4980. this._suggestBox = new WebInspector.TextPrompt.SuggestBox(this, this._element, this._suggestBoxClassName);
  4981. return this.proxyElement;
  4982. },
  4983. detach: function()
  4984. {
  4985. this._removeFromElement();
  4986. this.proxyElement.parentElement.insertBefore(this._element, this.proxyElement);
  4987. this.proxyElement.parentElement.removeChild(this.proxyElement);
  4988. this._element.removeStyleClass("text-prompt");
  4989. this._element.removeEventListener("keydown", this._boundOnKeyDown, false);
  4990. this._element.removeEventListener("selectstart", this._boundSelectStart, false);
  4991. delete this._proxyElement;
  4992. WebInspector.restoreFocusFromElement(this._element);
  4993. },
  4994. get text()
  4995. {
  4996. return this._element.textContent;
  4997. },
  4998. set text(x)
  4999. {
  5000. this._removeSuggestionAids();
  5001. if (!x) {
  5002. this._element.removeChildren();
  5003. this._element.appendChild(document.createElement("br"));
  5004. } else
  5005. this._element.textContent = x;
  5006. this.moveCaretToEndOfPrompt();
  5007. this._element.scrollIntoView();
  5008. },
  5009. _removeFromElement: function()
  5010. {
  5011. this.clearAutoComplete(true);
  5012. this._element.removeEventListener("keydown", this._boundOnKeyDown, false);
  5013. this._element.removeEventListener("selectstart", this._boundSelectStart, false);
  5014. if (this._isEditing)
  5015. this._stopEditing();
  5016. if (this._suggestBox)
  5017. this._suggestBox.removeFromElement();
  5018. },
  5019. _startEditing: function(blurListener)
  5020. {
  5021. this._isEditing = true;
  5022. this._element.addStyleClass("editing");
  5023. if (blurListener) {
  5024. this._blurListener = blurListener;
  5025. this._element.addEventListener("blur", this._blurListener, false);
  5026. }
  5027. this._oldTabIndex = this._element.tabIndex;
  5028. if (this._element.tabIndex < 0)
  5029. this._element.tabIndex = 0;
  5030. WebInspector.setCurrentFocusElement(this._element);
  5031. },
  5032. _stopEditing: function()
  5033. {
  5034. this._element.tabIndex = this._oldTabIndex;
  5035. if (this._blurListener)
  5036. this._element.removeEventListener("blur", this._blurListener, false);
  5037. this._element.removeStyleClass("editing");
  5038. delete this._isEditing;
  5039. },
  5040. _removeSuggestionAids: function()
  5041. {
  5042. this.clearAutoComplete();
  5043. this.hideSuggestBox();
  5044. },
  5045. _selectStart: function(event)
  5046. {
  5047. if (this._selectionTimeout)
  5048. clearTimeout(this._selectionTimeout);
  5049. this._removeSuggestionAids();
  5050. function moveBackIfOutside()
  5051. {
  5052. delete this._selectionTimeout;
  5053. if (!this.isCaretInsidePrompt() && window.getSelection().isCollapsed) {
  5054. this.moveCaretToEndOfPrompt();
  5055. this.autoCompleteSoon();
  5056. }
  5057. }
  5058. this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
  5059. },
  5060. defaultKeyHandler: function(event, force)
  5061. {
  5062. this.clearAutoComplete();
  5063. this.autoCompleteSoon(force);
  5064. return false;
  5065. },
  5066. onKeyDown: function(event)
  5067. {
  5068. var handled = false;
  5069. var invokeDefault = true;
  5070. switch (event.keyIdentifier) {
  5071. case "Up":
  5072. handled = this.upKeyPressed(event);
  5073. break;
  5074. case "Down":
  5075. handled = this.downKeyPressed(event);
  5076. break;
  5077. case "PageUp":
  5078. handled = this.pageUpKeyPressed(event);
  5079. break;
  5080. case "PageDown":
  5081. handled = this.pageDownKeyPressed(event);
  5082. break;
  5083. case "U+0009":
  5084. handled = this.tabKeyPressed(event);
  5085. break;
  5086. case "Enter":
  5087. handled = this.enterKeyPressed(event);
  5088. break;
  5089. case "Left":
  5090. case "Home":
  5091. this._removeSuggestionAids();
  5092. invokeDefault = false;
  5093. break;
  5094. case "Right":
  5095. case "End":
  5096. if (this.isCaretAtEndOfPrompt())
  5097. handled = this.acceptAutoComplete();
  5098. else
  5099. this._removeSuggestionAids();
  5100. invokeDefault = false;
  5101. break;
  5102. case "U+001B":
  5103. if (this.isSuggestBoxVisible()) {
  5104. this._suggestBox.hide();
  5105. handled = true;
  5106. }
  5107. break;
  5108. case "U+0020":
  5109. if (this._suggestForceable && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
  5110. this.defaultKeyHandler(event, true);
  5111. handled = true;
  5112. }
  5113. break;
  5114. case "Alt":
  5115. case "Meta":
  5116. case "Shift":
  5117. case "Control":
  5118. invokeDefault = false;
  5119. break;
  5120. }
  5121. if (!handled && invokeDefault)
  5122. handled = this.defaultKeyHandler(event);
  5123. if (handled)
  5124. event.consume(true);
  5125. return handled;
  5126. },
  5127. acceptAutoComplete: function()
  5128. {
  5129. var result = false;
  5130. if (this.isSuggestBoxVisible())
  5131. result = this._suggestBox.acceptSuggestion();
  5132. if (!result)
  5133. result = this.acceptSuggestion();
  5134. return result;
  5135. },
  5136. clearAutoComplete: function(includeTimeout)
  5137. {
  5138. if (includeTimeout && this._completeTimeout) {
  5139. clearTimeout(this._completeTimeout);
  5140. delete this._completeTimeout;
  5141. }
  5142. delete this._waitingForCompletions;
  5143. if (!this.autoCompleteElement)
  5144. return;
  5145. if (this.autoCompleteElement.parentNode)
  5146. this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement);
  5147. delete this.autoCompleteElement;
  5148. if (!this._userEnteredRange || !this._userEnteredText)
  5149. return;
  5150. this._userEnteredRange.deleteContents();
  5151. this._element.pruneEmptyTextNodes();
  5152. var userTextNode = document.createTextNode(this._userEnteredText);
  5153. this._userEnteredRange.insertNode(userTextNode);
  5154. var selectionRange = document.createRange();
  5155. selectionRange.setStart(userTextNode, this._userEnteredText.length);
  5156. selectionRange.setEnd(userTextNode, this._userEnteredText.length);
  5157. var selection = window.getSelection();
  5158. selection.removeAllRanges();
  5159. selection.addRange(selectionRange);
  5160. delete this._userEnteredRange;
  5161. delete this._userEnteredText;
  5162. },
  5163. autoCompleteSoon: function(force)
  5164. {
  5165. var immediately = this.isSuggestBoxVisible() || force;
  5166. if (!this._completeTimeout)
  5167. this._completeTimeout = setTimeout(this.complete.bind(this, true, force), immediately ? 0 : 250);
  5168. },
  5169. complete: function(auto, force, reverse)
  5170. {
  5171. this.clearAutoComplete(true);
  5172. var selection = window.getSelection();
  5173. if (!selection.rangeCount)
  5174. return;
  5175. var selectionRange = selection.getRangeAt(0);
  5176. var isEmptyInput = selectionRange.commonAncestorContainer === this._element;
  5177. var shouldExit;
  5178. if (auto && isEmptyInput && !force)
  5179. shouldExit = true;
  5180. else if (!auto && !isEmptyInput && !selectionRange.commonAncestorContainer.isDescendant(this._element))
  5181. shouldExit = true;
  5182. else if (auto && !force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible())
  5183. shouldExit = true;
  5184. else if (!selection.isCollapsed)
  5185. shouldExit = true;
  5186. else if (!force) {
  5187. var wordSuffixRange = selectionRange.startContainer.rangeOfWord(selectionRange.endOffset, this._completionStopCharacters, this._element, "forward");
  5188. if (wordSuffixRange.toString().length)
  5189. shouldExit = true;
  5190. }
  5191. if (shouldExit) {
  5192. this.hideSuggestBox();
  5193. return;
  5194. }
  5195. var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this._completionStopCharacters, this._element, "backward");
  5196. this._waitingForCompletions = true;
  5197. this._loadCompletions(this, wordPrefixRange, force, this._completionsReady.bind(this, selection, auto, wordPrefixRange, !!reverse));
  5198. },
  5199. _boxForAnchorAtStart: function(selection, textRange)
  5200. {
  5201. var rangeCopy = selection.getRangeAt(0).cloneRange();
  5202. var anchorElement = document.createElement("span");
  5203. anchorElement.textContent = "\u200B";
  5204. textRange.insertNode(anchorElement);
  5205. var box = anchorElement.boxInWindow(window);
  5206. anchorElement.parentElement.removeChild(anchorElement);
  5207. selection.removeAllRanges();
  5208. selection.addRange(rangeCopy);
  5209. return box;
  5210. },
  5211. _buildCommonPrefix: function(completions, wordPrefixLength)
  5212. {
  5213. var commonPrefix = completions[0];
  5214. for (var i = 0; i < completions.length; ++i) {
  5215. var completion = completions[i];
  5216. var lastIndex = Math.min(commonPrefix.length, completion.length);
  5217. for (var j = wordPrefixLength; j < lastIndex; ++j) {
  5218. if (commonPrefix[j] !== completion[j]) {
  5219. commonPrefix = commonPrefix.substr(0, j);
  5220. break;
  5221. }
  5222. }
  5223. }
  5224. return commonPrefix;
  5225. },
  5226. _completionsReady: function(selection, auto, originalWordPrefixRange, reverse, completions)
  5227. {
  5228. if (!this._waitingForCompletions || !completions || !completions.length) {
  5229. this.hideSuggestBox();
  5230. return;
  5231. }
  5232. delete this._waitingForCompletions;
  5233. var selectionRange = selection.getRangeAt(0);
  5234. var fullWordRange = document.createRange();
  5235. fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset);
  5236. fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset);
  5237. if (originalWordPrefixRange.toString() + selectionRange.toString() != fullWordRange.toString())
  5238. return;
  5239. this._userEnteredRange = fullWordRange;
  5240. this._userEnteredText = fullWordRange.toString();
  5241. if (this._suggestBox)
  5242. this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), completions, !this.isCaretAtEndOfPrompt());
  5243. var wordPrefixLength = originalWordPrefixRange.toString().length;
  5244. if (auto) {
  5245. var completionText = completions[0];
  5246. var commonPrefix = this._buildCommonPrefix(completions, wordPrefixLength);
  5247. this._commonPrefix = commonPrefix;
  5248. } else {
  5249. if (completions.length === 1) {
  5250. var completionText = completions[0];
  5251. wordPrefixLength = completionText.length;
  5252. } else {
  5253. var commonPrefix = this._buildCommonPrefix(completions, wordPrefixLength);
  5254. wordPrefixLength = commonPrefix.length;
  5255. if (selection.isCollapsed)
  5256. var completionText = completions[0];
  5257. else {
  5258. var currentText = fullWordRange.toString();
  5259. var foundIndex = null;
  5260. for (var i = 0; i < completions.length; ++i) {
  5261. if (completions[i] === currentText)
  5262. foundIndex = i;
  5263. }
  5264. var nextIndex = foundIndex + (reverse ? -1 : 1);
  5265. if (foundIndex === null || nextIndex >= completions.length)
  5266. var completionText = completions[0];
  5267. else if (nextIndex < 0)
  5268. var completionText = completions[completions.length - 1];
  5269. else
  5270. var completionText = completions[nextIndex];
  5271. }
  5272. }
  5273. }
  5274. if (auto) {
  5275. if (this.isCaretAtEndOfPrompt()) {
  5276. this._userEnteredRange.deleteContents();
  5277. this._element.pruneEmptyTextNodes();
  5278. var finalSelectionRange = document.createRange();
  5279. var prefixText = completionText.substring(0, wordPrefixLength);
  5280. var suffixText = completionText.substring(wordPrefixLength);
  5281. var prefixTextNode = document.createTextNode(prefixText);
  5282. fullWordRange.insertNode(prefixTextNode);
  5283. this.autoCompleteElement = document.createElement("span");
  5284. this.autoCompleteElement.className = "auto-complete-text";
  5285. this.autoCompleteElement.textContent = suffixText;
  5286. prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling);
  5287. finalSelectionRange.setStart(prefixTextNode, wordPrefixLength);
  5288. finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength);
  5289. selection.removeAllRanges();
  5290. selection.addRange(finalSelectionRange);
  5291. }
  5292. } else
  5293. this.applySuggestion(completionText, completions.length > 1, originalWordPrefixRange);
  5294. },
  5295. _completeCommonPrefix: function()
  5296. {
  5297. if (!this.autoCompleteElement || !this._commonPrefix || !this._userEnteredText || !this._commonPrefix.startsWith(this._userEnteredText))
  5298. return;
  5299. if (!this.isSuggestBoxVisible()) {
  5300. this.acceptAutoComplete();
  5301. return;
  5302. }
  5303. this.autoCompleteElement.textContent = this._commonPrefix.substring(this._userEnteredText.length);
  5304. this.acceptSuggestion(true)
  5305. },
  5306. applySuggestion: function(completionText, isIntermediateSuggestion, originalPrefixRange)
  5307. {
  5308. var wordPrefixLength;
  5309. if (originalPrefixRange)
  5310. wordPrefixLength = originalPrefixRange.toString().length;
  5311. else
  5312. wordPrefixLength = this._userEnteredText ? this._userEnteredText.length : 0;
  5313. this._userEnteredRange.deleteContents();
  5314. this._element.pruneEmptyTextNodes();
  5315. var finalSelectionRange = document.createRange();
  5316. var completionTextNode = document.createTextNode(completionText);
  5317. this._userEnteredRange.insertNode(completionTextNode);
  5318. if (this.autoCompleteElement && this.autoCompleteElement.parentNode) {
  5319. this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement);
  5320. delete this.autoCompleteElement;
  5321. }
  5322. if (isIntermediateSuggestion)
  5323. finalSelectionRange.setStart(completionTextNode, wordPrefixLength);
  5324. else
  5325. finalSelectionRange.setStart(completionTextNode, completionText.length);
  5326. finalSelectionRange.setEnd(completionTextNode, completionText.length);
  5327. var selection = window.getSelection();
  5328. selection.removeAllRanges();
  5329. selection.addRange(finalSelectionRange);
  5330. if (isIntermediateSuggestion)
  5331. this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApplied, { itemText: completionText });
  5332. },
  5333. acceptSuggestion: function(prefixAccepted)
  5334. {
  5335. if (this._isAcceptingSuggestion)
  5336. return false;
  5337. if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode)
  5338. return false;
  5339. var text = this.autoCompleteElement.textContent;
  5340. var textNode = document.createTextNode(text);
  5341. this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement);
  5342. delete this.autoCompleteElement;
  5343. var finalSelectionRange = document.createRange();
  5344. finalSelectionRange.setStart(textNode, text.length);
  5345. finalSelectionRange.setEnd(textNode, text.length);
  5346. var selection = window.getSelection();
  5347. selection.removeAllRanges();
  5348. selection.addRange(finalSelectionRange);
  5349. if (!prefixAccepted) {
  5350. this.hideSuggestBox();
  5351. this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepted);
  5352. } else
  5353. this.autoCompleteSoon(true);
  5354. return true;
  5355. },
  5356. hideSuggestBox: function()
  5357. {
  5358. if (this.isSuggestBoxVisible())
  5359. this._suggestBox.hide();
  5360. },
  5361. isSuggestBoxVisible: function()
  5362. {
  5363. return this._suggestBox && this._suggestBox.visible;
  5364. },
  5365. isCaretInsidePrompt: function()
  5366. {
  5367. return this._element.isInsertionCaretInside();
  5368. },
  5369. isCaretAtEndOfPrompt: function()
  5370. {
  5371. var selection = window.getSelection();
  5372. if (!selection.rangeCount || !selection.isCollapsed)
  5373. return false;
  5374. var selectionRange = selection.getRangeAt(0);
  5375. var node = selectionRange.startContainer;
  5376. if (!node.isSelfOrDescendant(this._element))
  5377. return false;
  5378. if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length)
  5379. return false;
  5380. var foundNextText = false;
  5381. while (node) {
  5382. if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) {
  5383. if (foundNextText && (!this.autoCompleteElement || !this.autoCompleteElement.isAncestor(node)))
  5384. return false;
  5385. foundNextText = true;
  5386. }
  5387. node = node.traverseNextNode(this._element);
  5388. }
  5389. return true;
  5390. },
  5391. isCaretOnFirstLine: function()
  5392. {
  5393. var selection = window.getSelection();
  5394. var focusNode = selection.focusNode;
  5395. if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element)
  5396. return true;
  5397. if (focusNode.textContent.substring(0, selection.focusOffset).indexOf("\n") !== -1)
  5398. return false;
  5399. focusNode = focusNode.previousSibling;
  5400. while (focusNode) {
  5401. if (focusNode.nodeType !== Node.TEXT_NODE)
  5402. return true;
  5403. if (focusNode.textContent.indexOf("\n") !== -1)
  5404. return false;
  5405. focusNode = focusNode.previousSibling;
  5406. }
  5407. return true;
  5408. },
  5409. isCaretOnLastLine: function()
  5410. {
  5411. var selection = window.getSelection();
  5412. var focusNode = selection.focusNode;
  5413. if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element)
  5414. return true;
  5415. if (focusNode.textContent.substring(selection.focusOffset).indexOf("\n") !== -1)
  5416. return false;
  5417. focusNode = focusNode.nextSibling;
  5418. while (focusNode) {
  5419. if (focusNode.nodeType !== Node.TEXT_NODE)
  5420. return true;
  5421. if (focusNode.textContent.indexOf("\n") !== -1)
  5422. return false;
  5423. focusNode = focusNode.nextSibling;
  5424. }
  5425. return true;
  5426. },
  5427. moveCaretToEndOfPrompt: function()
  5428. {
  5429. var selection = window.getSelection();
  5430. var selectionRange = document.createRange();
  5431. var offset = this._element.childNodes.length;
  5432. selectionRange.setStart(this._element, offset);
  5433. selectionRange.setEnd(this._element, offset);
  5434. selection.removeAllRanges();
  5435. selection.addRange(selectionRange);
  5436. },
  5437. tabKeyPressed: function(event)
  5438. {
  5439. this._completeCommonPrefix();
  5440. return true;
  5441. },
  5442. enterKeyPressed: function(event)
  5443. {
  5444. if (this.isSuggestBoxVisible())
  5445. return this._suggestBox.enterKeyPressed(event);
  5446. return false;
  5447. },
  5448. upKeyPressed: function(event)
  5449. {
  5450. if (this.isSuggestBoxVisible())
  5451. return this._suggestBox.upKeyPressed(event);
  5452. return false;
  5453. },
  5454. downKeyPressed: function(event)
  5455. {
  5456. if (this.isSuggestBoxVisible())
  5457. return this._suggestBox.downKeyPressed(event);
  5458. return false;
  5459. },
  5460. pageUpKeyPressed: function(event)
  5461. {
  5462. if (this.isSuggestBoxVisible())
  5463. return this._suggestBox.pageUpKeyPressed(event);
  5464. return false;
  5465. },
  5466. pageDownKeyPressed: function(event)
  5467. {
  5468. if (this.isSuggestBoxVisible())
  5469. return this._suggestBox.pageDownKeyPressed(event);
  5470. return false;
  5471. },
  5472. }
  5473. WebInspector.TextPrompt.prototype.__proto__ = WebInspector.Object.prototype;
  5474. WebInspector.TextPromptWithHistory = function(completions, stopCharacters)
  5475. {
  5476. WebInspector.TextPrompt.call(this, completions, stopCharacters);
  5477. this._data = [];
  5478. this._historyOffset = 1;
  5479. this._coalesceHistoryDupes = true;
  5480. }
  5481. WebInspector.TextPromptWithHistory.prototype = {
  5482. get historyData()
  5483. {
  5484. return this._data;
  5485. },
  5486. setCoalesceHistoryDupes: function(x)
  5487. {
  5488. this._coalesceHistoryDupes = x;
  5489. },
  5490. setHistoryData: function(data)
  5491. {
  5492. this._data = [].concat(data);
  5493. this._historyOffset = 1;
  5494. },
  5495. pushHistoryItem: function(text)
  5496. {
  5497. if (this._uncommittedIsTop) {
  5498. this._data.pop();
  5499. delete this._uncommittedIsTop;
  5500. }
  5501. this._historyOffset = 1;
  5502. if (this._coalesceHistoryDupes && text === this._currentHistoryItem())
  5503. return;
  5504. this._data.push(text);
  5505. },
  5506. _pushCurrentText: function()
  5507. {
  5508. if (this._uncommittedIsTop)
  5509. this._data.pop();
  5510. this._uncommittedIsTop = true;
  5511. this.clearAutoComplete(true);
  5512. this._data.push(this.text);
  5513. },
  5514. _previous: function()
  5515. {
  5516. if (this._historyOffset > this._data.length)
  5517. return undefined;
  5518. if (this._historyOffset === 1)
  5519. this._pushCurrentText();
  5520. ++this._historyOffset;
  5521. return this._currentHistoryItem();
  5522. },
  5523. _next: function()
  5524. {
  5525. if (this._historyOffset === 1)
  5526. return undefined;
  5527. --this._historyOffset;
  5528. return this._currentHistoryItem();
  5529. },
  5530. _currentHistoryItem: function()
  5531. {
  5532. return this._data[this._data.length - this._historyOffset];
  5533. },
  5534. defaultKeyHandler: function(event, force)
  5535. {
  5536. var newText;
  5537. var isPrevious;
  5538. switch (event.keyIdentifier) {
  5539. case "Up":
  5540. if (!this.isCaretOnFirstLine())
  5541. break;
  5542. newText = this._previous();
  5543. isPrevious = true;
  5544. break;
  5545. case "Down":
  5546. if (!this.isCaretOnLastLine())
  5547. break;
  5548. newText = this._next();
  5549. break;
  5550. case "U+0050":
  5551. if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
  5552. newText = this._previous();
  5553. isPrevious = true;
  5554. }
  5555. break;
  5556. case "U+004E":
  5557. if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey)
  5558. newText = this._next();
  5559. break;
  5560. }
  5561. if (newText !== undefined) {
  5562. event.consume(true);
  5563. this.text = newText;
  5564. if (isPrevious) {
  5565. var firstNewlineIndex = this.text.indexOf("\n");
  5566. if (firstNewlineIndex === -1)
  5567. this.moveCaretToEndOfPrompt();
  5568. else {
  5569. var selection = window.getSelection();
  5570. var selectionRange = document.createRange();
  5571. selectionRange.setStart(this._element.firstChild, firstNewlineIndex);
  5572. selectionRange.setEnd(this._element.firstChild, firstNewlineIndex);
  5573. selection.removeAllRanges();
  5574. selection.addRange(selectionRange);
  5575. }
  5576. }
  5577. return true;
  5578. }
  5579. return WebInspector.TextPrompt.prototype.defaultKeyHandler.apply(this, arguments);
  5580. }
  5581. }
  5582. WebInspector.TextPromptWithHistory.prototype.__proto__ = WebInspector.TextPrompt.prototype;
  5583. WebInspector.TextPrompt.SuggestBox = function(textPrompt, inputElement, className)
  5584. {
  5585. this._textPrompt = textPrompt;
  5586. this._inputElement = inputElement;
  5587. this._selectedElement = null;
  5588. this._boundOnScroll = this._onscrollresize.bind(this, true);
  5589. this._boundOnResize = this._onscrollresize.bind(this, false);
  5590. window.addEventListener("scroll", this._boundOnScroll, true);
  5591. window.addEventListener("resize", this._boundOnResize, true);
  5592. this._bodyElement = inputElement.ownerDocument.body;
  5593. this._element = inputElement.ownerDocument.createElement("div");
  5594. this._element.className = "suggest-box " + (className || "");
  5595. this._element.addEventListener("mousedown", this._onboxmousedown.bind(this), true);
  5596. this.containerElement = this._element.createChild("div", "container");
  5597. this.contentElement = this.containerElement.createChild("div", "content");
  5598. }
  5599. WebInspector.TextPrompt.SuggestBox.prototype = {
  5600. get visible()
  5601. {
  5602. return !!this._element.parentElement;
  5603. },
  5604. get hasSelection()
  5605. {
  5606. return !!this._selectedElement;
  5607. },
  5608. _onscrollresize: function(isScroll, event)
  5609. {
  5610. if (isScroll && this._element.isAncestor(event.target) || !this.visible)
  5611. return;
  5612. this._updateBoxPositionWithExistingAnchor();
  5613. },
  5614. _updateBoxPositionWithExistingAnchor: function()
  5615. {
  5616. this._updateBoxPosition(this._anchorBox);
  5617. },
  5618. _updateBoxPosition: function(anchorBox)
  5619. {
  5620. this.contentElement.style.display = "inline-block";
  5621. document.body.appendChild(this.contentElement);
  5622. this.contentElement.positionAt(0, 0);
  5623. var contentWidth = this.contentElement.offsetWidth;
  5624. var contentHeight = this.contentElement.offsetHeight;
  5625. this.contentElement.style.display = "block";
  5626. this.containerElement.appendChild(this.contentElement);
  5627. this._anchorBox = anchorBox;
  5628. const spacer = 6;
  5629. const suggestBoxPaddingX = 21;
  5630. var maxWidth = document.body.offsetWidth - anchorBox.x - spacer;
  5631. var width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX;
  5632. var paddedWidth = contentWidth + suggestBoxPaddingX;
  5633. var boxX = anchorBox.x;
  5634. if (width < paddedWidth) {
  5635. maxWidth = document.body.offsetWidth - spacer;
  5636. width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX;
  5637. boxX = document.body.offsetWidth - width;
  5638. }
  5639. const suggestBoxPaddingY = 2;
  5640. var boxY;
  5641. var aboveHeight = anchorBox.y;
  5642. var underHeight = document.body.offsetHeight - anchorBox.y - anchorBox.height;
  5643. var maxHeight = Math.max(underHeight, aboveHeight) - spacer;
  5644. var height = Math.min(contentHeight, maxHeight - suggestBoxPaddingY) + suggestBoxPaddingY;
  5645. if (underHeight >= aboveHeight) {
  5646. boxY = anchorBox.y + anchorBox.height;
  5647. this._element.removeStyleClass("above-anchor");
  5648. this._element.addStyleClass("under-anchor");
  5649. } else {
  5650. boxY = anchorBox.y - height;
  5651. this._element.removeStyleClass("under-anchor");
  5652. this._element.addStyleClass("above-anchor");
  5653. }
  5654. this._element.positionAt(boxX, boxY);
  5655. this._element.style.width = width + "px";
  5656. this._element.style.height = height + "px";
  5657. },
  5658. _onboxmousedown: function(event)
  5659. {
  5660. event.preventDefault();
  5661. },
  5662. hide: function()
  5663. {
  5664. if (!this.visible)
  5665. return;
  5666. this._element.parentElement.removeChild(this._element);
  5667. delete this._selectedElement;
  5668. },
  5669. removeFromElement: function()
  5670. {
  5671. window.removeEventListener("scroll", this._boundOnScroll, true);
  5672. window.removeEventListener("resize", this._boundOnResize, true);
  5673. this.hide();
  5674. },
  5675. _applySuggestion: function(text, isIntermediateSuggestion)
  5676. {
  5677. if (!this.visible || !(text || this._selectedElement))
  5678. return false;
  5679. var suggestion = text || this._selectedElement.textContent;
  5680. if (!suggestion)
  5681. return false;
  5682. this._textPrompt.applySuggestion(suggestion, isIntermediateSuggestion);
  5683. return true;
  5684. },
  5685. acceptSuggestion: function(text)
  5686. {
  5687. var result = this._applySuggestion(text, false);
  5688. this.hide();
  5689. if (!result)
  5690. return false;
  5691. this._textPrompt.acceptSuggestion();
  5692. return true;
  5693. },
  5694. _onNextItem: function(event, isPageScroll)
  5695. {
  5696. var children = this.contentElement.childNodes;
  5697. if (!children.length)
  5698. return false;
  5699. if (!this._selectedElement)
  5700. this._selectedElement = this.contentElement.firstChild;
  5701. else {
  5702. if (!isPageScroll)
  5703. this._selectedElement = this._selectedElement.nextSibling || this.contentElement.firstChild;
  5704. else {
  5705. var candidate = this._selectedElement;
  5706. for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) {
  5707. if (candidate.nextSibling)
  5708. candidate = candidate.nextSibling;
  5709. else
  5710. break;
  5711. }
  5712. this._selectedElement = candidate;
  5713. }
  5714. }
  5715. this._updateSelection();
  5716. this._applySuggestion(undefined, true);
  5717. return true;
  5718. },
  5719. _onPreviousItem: function(event, isPageScroll)
  5720. {
  5721. var children = this.contentElement.childNodes;
  5722. if (!children.length)
  5723. return false;
  5724. if (!this._selectedElement)
  5725. this._selectedElement = this.contentElement.lastChild;
  5726. else {
  5727. if (!isPageScroll)
  5728. this._selectedElement = this._selectedElement.previousSibling || this.contentElement.lastChild;
  5729. else {
  5730. var candidate = this._selectedElement;
  5731. for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) {
  5732. if (candidate.previousSibling)
  5733. candidate = candidate.previousSibling;
  5734. else
  5735. break;
  5736. }
  5737. this._selectedElement = candidate;
  5738. }
  5739. }
  5740. this._updateSelection();
  5741. this._applySuggestion(undefined, true);
  5742. return true;
  5743. },
  5744. updateSuggestions: function(anchorBox, completions, canShowForSingleItem)
  5745. {
  5746. if (this._suggestTimeout) {
  5747. clearTimeout(this._suggestTimeout);
  5748. delete this._suggestTimeout;
  5749. }
  5750. this._completionsReady(anchorBox, completions, canShowForSingleItem);
  5751. },
  5752. _onItemMouseDown: function(text, event)
  5753. {
  5754. this.acceptSuggestion(text);
  5755. event.consume(true);
  5756. },
  5757. _createItemElement: function(prefix, text)
  5758. {
  5759. var element = document.createElement("div");
  5760. element.className = "suggest-box-content-item source-code";
  5761. element.tabIndex = -1;
  5762. if (prefix && prefix.length && !text.indexOf(prefix)) {
  5763. var prefixElement = element.createChild("span", "prefix");
  5764. prefixElement.textContent = prefix;
  5765. var suffixElement = element.createChild("span", "suffix");
  5766. suffixElement.textContent = text.substring(prefix.length);
  5767. } else {
  5768. var suffixElement = element.createChild("span", "suffix");
  5769. suffixElement.textContent = text;
  5770. }
  5771. element.addEventListener("mousedown", this._onItemMouseDown.bind(this, text), false);
  5772. return element;
  5773. },
  5774. _updateItems: function(items, canShowForSingleItem)
  5775. {
  5776. this.contentElement.removeChildren();
  5777. var userEnteredText = this._textPrompt._userEnteredText;
  5778. for (var i = 0; i < items.length; ++i) {
  5779. var item = items[i];
  5780. var currentItemElement = this._createItemElement(userEnteredText, item);
  5781. this.contentElement.appendChild(currentItemElement);
  5782. }
  5783. this._selectedElement = canShowForSingleItem ? this.contentElement.firstChild : null;
  5784. this._updateSelection();
  5785. },
  5786. _updateSelection: function()
  5787. {
  5788. for (var child = this.contentElement.firstChild; child; child = child.nextSibling) {
  5789. if (child !== this._selectedElement)
  5790. child.removeStyleClass("selected");
  5791. }
  5792. if (this._selectedElement) {
  5793. this._selectedElement.addStyleClass("selected");
  5794. this._selectedElement.scrollIntoViewIfNeeded(false);
  5795. }
  5796. },
  5797. _canShowBox: function(completions, canShowForSingleItem)
  5798. {
  5799. if (!completions || !completions.length)
  5800. return false;
  5801. if (completions.length > 1)
  5802. return true;
  5803. return canShowForSingleItem && completions[0] !== this._textPrompt._userEnteredText;
  5804. },
  5805. _rememberRowCountPerViewport: function()
  5806. {
  5807. if (!this.contentElement.firstChild)
  5808. return;
  5809. this._rowCountPerViewport = Math.floor(this.containerElement.offsetHeight / this.contentElement.firstChild.offsetHeight);
  5810. },
  5811. _completionsReady: function(anchorBox, completions, canShowForSingleItem)
  5812. {
  5813. if (this._canShowBox(completions, canShowForSingleItem)) {
  5814. this._updateItems(completions, canShowForSingleItem);
  5815. this._updateBoxPosition(anchorBox);
  5816. if (!this.visible)
  5817. this._bodyElement.appendChild(this._element);
  5818. this._rememberRowCountPerViewport();
  5819. } else
  5820. this.hide();
  5821. },
  5822. upKeyPressed: function(event)
  5823. {
  5824. return this._onPreviousItem(event, false);
  5825. },
  5826. downKeyPressed: function(event)
  5827. {
  5828. return this._onNextItem(event, false);
  5829. },
  5830. pageUpKeyPressed: function(event)
  5831. {
  5832. return this._onPreviousItem(event, true);
  5833. },
  5834. pageDownKeyPressed: function(event)
  5835. {
  5836. return this._onNextItem(event, true);
  5837. },
  5838. enterKeyPressed: function(event)
  5839. {
  5840. var hasSelectedItem = !!this._selectedElement;
  5841. this.acceptSuggestion();
  5842. return hasSelectedItem;
  5843. },
  5844. tabKeyPressed: function(event)
  5845. {
  5846. return this.enterKeyPressed(event);
  5847. }
  5848. }
  5849. WebInspector.Popover = function(popoverHelper)
  5850. {
  5851. this.element = document.createElement("div");
  5852. this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll";
  5853. this._popupArrowElement = document.createElement("div");
  5854. this._popupArrowElement.className = "arrow";
  5855. this.element.appendChild(this._popupArrowElement);
  5856. this._contentDiv = document.createElement("div");
  5857. this._contentDiv.className = "content";
  5858. this._visible = false;
  5859. this._popoverHelper = popoverHelper;
  5860. }
  5861. WebInspector.Popover.prototype = {
  5862. show: function(contentElement, anchor, preferredWidth, preferredHeight)
  5863. {
  5864. if (this._disposed)
  5865. return;
  5866. this.contentElement = contentElement;
  5867. if (WebInspector.Popover._popoverElement)
  5868. document.body.removeChild(WebInspector.Popover._popoverElement);
  5869. WebInspector.Popover._popoverElement = this.element;
  5870. this.contentElement.positionAt(0, 0);
  5871. document.body.appendChild(this.contentElement);
  5872. preferredWidth = preferredWidth || this.contentElement.offsetWidth;
  5873. preferredHeight = preferredHeight || this.contentElement.offsetHeight;
  5874. this._contentDiv.appendChild(this.contentElement);
  5875. this.element.appendChild(this._contentDiv);
  5876. document.body.appendChild(this.element);
  5877. this._positionElement(anchor, preferredWidth, preferredHeight);
  5878. this._visible = true;
  5879. if (this._popoverHelper)
  5880. contentElement.addEventListener("mousemove", this._popoverHelper._killHidePopoverTimer.bind(this._popoverHelper), true);
  5881. },
  5882. hide: function()
  5883. {
  5884. if (WebInspector.Popover._popoverElement) {
  5885. delete WebInspector.Popover._popoverElement;
  5886. document.body.removeChild(this.element);
  5887. }
  5888. this._visible = false;
  5889. },
  5890. get visible()
  5891. {
  5892. return this._visible;
  5893. },
  5894. get disposed()
  5895. {
  5896. return this._disposed;
  5897. },
  5898. dispose: function()
  5899. {
  5900. if (this.visible)
  5901. this.hide();
  5902. this._disposed = true;
  5903. },
  5904. setCanShrink: function(canShrink)
  5905. {
  5906. this._hasFixedHeight = !canShrink;
  5907. this._contentDiv.addStyleClass("fixed-height");
  5908. },
  5909. _positionElement: function(anchorElement, preferredWidth, preferredHeight)
  5910. {
  5911. const borderWidth = 25;
  5912. const scrollerWidth = this._hasFixedHeight ? 0 : 11;
  5913. const arrowHeight = 15;
  5914. const arrowOffset = 10;
  5915. const borderRadius = 10;
  5916. preferredWidth = Math.max(preferredWidth, 50);
  5917. const totalWidth = window.innerWidth;
  5918. const totalHeight = window.innerHeight;
  5919. var anchorBox = anchorElement.boxInWindow(window);
  5920. var newElementPosition = { x: 0, y: 0, width: preferredWidth + scrollerWidth, height: preferredHeight };
  5921. var verticalAlignment;
  5922. var roomAbove = anchorBox.y;
  5923. var roomBelow = totalHeight - anchorBox.y - anchorBox.height;
  5924. if (roomAbove > roomBelow) {
  5925. if (anchorBox.y > newElementPosition.height + arrowHeight + borderRadius)
  5926. newElementPosition.y = anchorBox.y - newElementPosition.height - arrowHeight;
  5927. else {
  5928. newElementPosition.y = borderRadius;
  5929. newElementPosition.height = anchorBox.y - borderRadius * 2 - arrowHeight;
  5930. if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
  5931. newElementPosition.y = borderRadius;
  5932. newElementPosition.height = preferredHeight;
  5933. }
  5934. }
  5935. verticalAlignment = "bottom";
  5936. } else {
  5937. newElementPosition.y = anchorBox.y + anchorBox.height + arrowHeight;
  5938. if (newElementPosition.y + newElementPosition.height + arrowHeight - borderWidth >= totalHeight) {
  5939. newElementPosition.height = totalHeight - anchorBox.y - anchorBox.height - borderRadius * 2 - arrowHeight;
  5940. if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
  5941. newElementPosition.y = totalHeight - preferredHeight - borderRadius;
  5942. newElementPosition.height = preferredHeight;
  5943. }
  5944. }
  5945. verticalAlignment = "top";
  5946. }
  5947. var horizontalAlignment;
  5948. if (anchorBox.x + newElementPosition.width < totalWidth) {
  5949. newElementPosition.x = Math.max(borderRadius, anchorBox.x - borderRadius - arrowOffset);
  5950. horizontalAlignment = "left";
  5951. } else if (newElementPosition.width + borderRadius * 2 < totalWidth) {
  5952. newElementPosition.x = totalWidth - newElementPosition.width - borderRadius;
  5953. horizontalAlignment = "right";
  5954. var arrowRightPosition = Math.max(0, totalWidth - anchorBox.x - anchorBox.width - borderRadius - arrowOffset);
  5955. arrowRightPosition += anchorBox.width / 2;
  5956. arrowRightPosition = Math.min(arrowRightPosition, newElementPosition.width - borderRadius - arrowOffset);
  5957. this._popupArrowElement.style.right = arrowRightPosition + "px";
  5958. } else {
  5959. newElementPosition.x = borderRadius;
  5960. newElementPosition.width = totalWidth - borderRadius * 2;
  5961. newElementPosition.height += scrollerWidth;
  5962. horizontalAlignment = "left";
  5963. if (verticalAlignment === "bottom")
  5964. newElementPosition.y -= scrollerWidth;
  5965. this._popupArrowElement.style.left = Math.max(0, anchorBox.x - borderRadius * 2 - arrowOffset) + "px";
  5966. this._popupArrowElement.style.left += anchorBox.width / 2;
  5967. }
  5968. this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll " + verticalAlignment + "-" + horizontalAlignment + "-arrow";
  5969. this.element.positionAt(newElementPosition.x - borderWidth, newElementPosition.y - borderWidth);
  5970. this.element.style.width = newElementPosition.width + borderWidth * 2 + "px";
  5971. this.element.style.height = newElementPosition.height + borderWidth * 2 + "px";
  5972. }
  5973. }
  5974. WebInspector.PopoverHelper = function(panelElement, getAnchor, showPopover, onHide, disableOnClick)
  5975. {
  5976. this._panelElement = panelElement;
  5977. this._getAnchor = getAnchor;
  5978. this._showPopover = showPopover;
  5979. this._onHide = onHide;
  5980. this._disableOnClick = !!disableOnClick;
  5981. panelElement.addEventListener("mousedown", this._mouseDown.bind(this), false);
  5982. panelElement.addEventListener("mousemove", this._mouseMove.bind(this), false);
  5983. panelElement.addEventListener("mouseout", this._mouseOut.bind(this), false);
  5984. this.setTimeout(1000);
  5985. }
  5986. WebInspector.PopoverHelper.prototype = {
  5987. setTimeout: function(timeout)
  5988. {
  5989. this._timeout = timeout;
  5990. },
  5991. _mouseDown: function(event)
  5992. {
  5993. if (this._disableOnClick)
  5994. this.hidePopover();
  5995. else {
  5996. this._killHidePopoverTimer();
  5997. this._handleMouseAction(event, true);
  5998. }
  5999. },
  6000. _mouseMove: function(event)
  6001. {
  6002. if (event.target.isSelfOrDescendant(this._hoverElement))
  6003. return;
  6004. this._startHidePopoverTimer();
  6005. this._handleMouseAction(event, false);
  6006. },
  6007. _mouseOut: function(event)
  6008. {
  6009. if (event.target === this._hoverElement)
  6010. this._startHidePopoverTimer();
  6011. },
  6012. _startHidePopoverTimer: function()
  6013. {
  6014. if (!this._popover || this._hidePopoverTimer)
  6015. return;
  6016. function doHide()
  6017. {
  6018. this._hidePopover();
  6019. delete this._hidePopoverTimer;
  6020. }
  6021. this._hidePopoverTimer = setTimeout(doHide.bind(this), this._timeout / 2);
  6022. },
  6023. _handleMouseAction: function(event, isMouseDown)
  6024. {
  6025. this._resetHoverTimer();
  6026. if (event.which && this._disableOnClick)
  6027. return;
  6028. this._hoverElement = this._getAnchor(event.target, event);
  6029. if (!this._hoverElement)
  6030. return;
  6031. const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout);
  6032. this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay);
  6033. },
  6034. _resetHoverTimer: function()
  6035. {
  6036. if (this._hoverTimer) {
  6037. clearTimeout(this._hoverTimer);
  6038. delete this._hoverTimer;
  6039. }
  6040. },
  6041. isPopoverVisible: function()
  6042. {
  6043. return !!this._popover;
  6044. },
  6045. hidePopover: function()
  6046. {
  6047. this._resetHoverTimer();
  6048. this._hidePopover();
  6049. },
  6050. _hidePopover: function()
  6051. {
  6052. if (!this._popover)
  6053. return;
  6054. if (this._onHide)
  6055. this._onHide();
  6056. this._popover.dispose();
  6057. delete this._popover;
  6058. this._hoverElement = null;
  6059. },
  6060. _mouseHover: function(element)
  6061. {
  6062. delete this._hoverTimer;
  6063. this._hidePopover();
  6064. this._popover = new WebInspector.Popover(this);
  6065. this._showPopover(element, this._popover);
  6066. },
  6067. _killHidePopoverTimer: function()
  6068. {
  6069. if (this._hidePopoverTimer) {
  6070. clearTimeout(this._hidePopoverTimer);
  6071. delete this._hidePopoverTimer;
  6072. this._resetHoverTimer();
  6073. }
  6074. }
  6075. }
  6076. WebInspector.Placard = function(title, subtitle)
  6077. {
  6078. this.element = document.createElement("div");
  6079. this.element.className = "placard";
  6080. this.element.placard = this;
  6081. this.titleElement = document.createElement("div");
  6082. this.titleElement.className = "title";
  6083. this.subtitleElement = document.createElement("div");
  6084. this.subtitleElement.className = "subtitle";
  6085. this.element.appendChild(this.subtitleElement);
  6086. this.element.appendChild(this.titleElement);
  6087. this.title = title;
  6088. this.subtitle = subtitle;
  6089. this.selected = false;
  6090. }
  6091. WebInspector.Placard.prototype = {
  6092. get title()
  6093. {
  6094. return this._title;
  6095. },
  6096. set title(x)
  6097. {
  6098. if (this._title === x)
  6099. return;
  6100. this._title = x;
  6101. this.titleElement.textContent = x;
  6102. },
  6103. get subtitle()
  6104. {
  6105. return this._subtitle;
  6106. },
  6107. set subtitle(x)
  6108. {
  6109. if (this._subtitle === x)
  6110. return;
  6111. this._subtitle = x;
  6112. this.subtitleElement.textContent = x;
  6113. },
  6114. get selected()
  6115. {
  6116. return this._selected;
  6117. },
  6118. set selected(x)
  6119. {
  6120. if (x)
  6121. this.select();
  6122. else
  6123. this.deselect();
  6124. },
  6125. select: function()
  6126. {
  6127. if (this._selected)
  6128. return;
  6129. this._selected = true;
  6130. this.element.addStyleClass("selected");
  6131. },
  6132. deselect: function()
  6133. {
  6134. if (!this._selected)
  6135. return;
  6136. this._selected = false;
  6137. this.element.removeStyleClass("selected");
  6138. },
  6139. toggleSelected: function()
  6140. {
  6141. this.selected = !this.selected;
  6142. },
  6143. discard: function()
  6144. {
  6145. }
  6146. }
  6147. WebInspector.TabbedPane = function()
  6148. {
  6149. WebInspector.View.call(this);
  6150. this.registerRequiredCSS("tabbedPane.css");
  6151. this.element.addStyleClass("tabbed-pane");
  6152. this._headerElement = this.element.createChild("div", "tabbed-pane-header");
  6153. this._headerContentsElement = this._headerElement.createChild("div", "tabbed-pane-header-contents");
  6154. this._tabsElement = this._headerContentsElement.createChild("div", "tabbed-pane-header-tabs");
  6155. this._contentElement = this.element.createChild("div", "tabbed-pane-content");
  6156. this._tabs = [];
  6157. this._tabsHistory = [];
  6158. this._tabsById = {};
  6159. this.element.addEventListener("click", this.focus.bind(this), false);
  6160. this._dropDownButton = this._createDropDownButton();
  6161. }
  6162. WebInspector.TabbedPane.EventTypes = {
  6163. TabSelected: "TabSelected",
  6164. TabClosed: "TabClosed"
  6165. }
  6166. WebInspector.TabbedPane.prototype = {
  6167. get visibleView()
  6168. {
  6169. return this._currentTab ? this._currentTab.view : null;
  6170. },
  6171. get selectedTabId()
  6172. {
  6173. return this._currentTab ? this._currentTab.id : null;
  6174. },
  6175. set shrinkableTabs(shrinkableTabs)
  6176. {
  6177. this._shrinkableTabs = shrinkableTabs;
  6178. },
  6179. set closeableTabs(closeableTabs)
  6180. {
  6181. this._closeableTabs = closeableTabs;
  6182. },
  6183. defaultFocusedElement: function()
  6184. {
  6185. return this.visibleView ? this.visibleView.defaultFocusedElement() : null;
  6186. },
  6187. appendTab: function(id, tabTitle, view, tabTooltip, userGesture)
  6188. {
  6189. var tab = new WebInspector.TabbedPaneTab(this, this._tabsElement, id, tabTitle, this._closeableTabs, view, tabTooltip);
  6190. this._tabsById[id] = tab;
  6191. this._tabs.push(tab);
  6192. this._tabsHistory.push(tab);
  6193. if (this._tabsHistory[0] === tab)
  6194. this.selectTab(tab.id, userGesture);
  6195. this._updateTabElements();
  6196. },
  6197. closeTab: function(id, userGesture)
  6198. {
  6199. this._innerCloseTab(id, userGesture);
  6200. this._updateTabElements();
  6201. if (this._tabsHistory.length)
  6202. this.selectTab(this._tabsHistory[0].id, userGesture);
  6203. },
  6204. _innerCloseTab: function(id, userGesture)
  6205. {
  6206. if (this._currentTab && this._currentTab.id === id)
  6207. this._hideCurrentTab();
  6208. var tab = this._tabsById[id];
  6209. delete this._tabsById[id];
  6210. this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1);
  6211. this._tabs.splice(this._tabs.indexOf(tab), 1);
  6212. if (tab._shown)
  6213. this._hideTabElement(tab);
  6214. var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture };
  6215. this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabClosed, eventData);
  6216. return true;
  6217. },
  6218. closeAllTabs: function(userGesture)
  6219. {
  6220. var tabs = this._tabs.slice();
  6221. for (var i = 0; i < tabs.length; ++i)
  6222. this._innerCloseTab(tabs[i].id, userGesture);
  6223. this._updateTabElements();
  6224. },
  6225. closeOtherTabs: function(id)
  6226. {
  6227. var tabs = this._tabs.slice();
  6228. for (var i = 0; i < tabs.length; ++i) {
  6229. if (tabs[i].id !== id)
  6230. this._innerCloseTab(tabs[i].id, true);
  6231. }
  6232. this._updateTabElements();
  6233. this.selectTab(id, true);
  6234. },
  6235. selectTab: function(id, userGesture)
  6236. {
  6237. var tab = this._tabsById[id];
  6238. if (!tab)
  6239. return;
  6240. if (this._currentTab && this._currentTab.id === id)
  6241. return;
  6242. this._hideCurrentTab();
  6243. this._showTab(tab);
  6244. this._currentTab = tab;
  6245. this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1);
  6246. this._tabsHistory.splice(0, 0, tab);
  6247. this._updateTabElements();
  6248. var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture };
  6249. this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabSelected, eventData);
  6250. return true;
  6251. },
  6252. lastOpenedTabIds: function(tabsCount)
  6253. {
  6254. function tabToTabId(tab) {
  6255. return tab.id;
  6256. }
  6257. return this._tabsHistory.slice(0, tabsCount).map(tabToTabId);
  6258. },
  6259. changeTabTitle: function(id, tabTitle)
  6260. {
  6261. var tab = this._tabsById[id];
  6262. tab.title = tabTitle;
  6263. this._updateTabElements();
  6264. },
  6265. changeTabView: function(id, view)
  6266. {
  6267. var tab = this._tabsById[id];
  6268. if (this._currentTab && this._currentTab.id === tab.id) {
  6269. this._hideTab(tab);
  6270. tab.view = view;
  6271. this._showTab(tab);
  6272. } else
  6273. tab.view = view;
  6274. },
  6275. changeTabTooltip: function(id, tabTooltip)
  6276. {
  6277. var tab = this._tabsById[id];
  6278. tab.tooltip = tabTooltip;
  6279. },
  6280. onResize: function()
  6281. {
  6282. this._updateTabElements();
  6283. },
  6284. _updateTabElements: function()
  6285. {
  6286. if (!this.isShowing())
  6287. return;
  6288. if (!this._tabs.length)
  6289. this._contentElement.addStyleClass("has-no-tabs");
  6290. else
  6291. this._contentElement.removeStyleClass("has-no-tabs");
  6292. if (!this._measuredDropDownButtonWidth)
  6293. this._measureDropDownButton();
  6294. if (this._shrinkableTabs)
  6295. this._updateWidths();
  6296. this._updateTabsDropDown();
  6297. },
  6298. _showTabElement: function(index, tab)
  6299. {
  6300. if (index >= this._tabsElement.children.length)
  6301. this._tabsElement.appendChild(tab.tabElement);
  6302. else
  6303. this._tabsElement.insertBefore(tab.tabElement, this._tabsElement.children[index]);
  6304. tab._shown = true;
  6305. },
  6306. _hideTabElement: function(tab)
  6307. {
  6308. this._tabsElement.removeChild(tab.tabElement);
  6309. tab._shown = false;
  6310. },
  6311. _createDropDownButton: function()
  6312. {
  6313. var dropDownContainer = document.createElement("div");
  6314. dropDownContainer.addStyleClass("tabbed-pane-header-tabs-drop-down-container");
  6315. var dropDownButton = dropDownContainer.createChild("div", "tabbed-pane-header-tabs-drop-down");
  6316. dropDownButton.appendChild(document.createTextNode("\u00bb"));
  6317. this._tabsSelect = dropDownButton.createChild("select", "tabbed-pane-header-tabs-drop-down-select");
  6318. this._tabsSelect.addEventListener("change", this._tabsSelectChanged.bind(this), false);
  6319. return dropDownContainer;
  6320. },
  6321. _updateTabsDropDown: function()
  6322. {
  6323. var tabsToShowIndexes = this._tabsToShowIndexes(this._tabs, this._tabsHistory, this._headerContentsElement.offsetWidth, this._measuredDropDownButtonWidth);
  6324. for (var i = 0; i < this._tabs.length; ++i) {
  6325. if (this._tabs[i]._shown && tabsToShowIndexes.indexOf(i) === -1)
  6326. this._hideTabElement(this._tabs[i]);
  6327. }
  6328. for (var i = 0; i < tabsToShowIndexes.length; ++i) {
  6329. var tab = this._tabs[tabsToShowIndexes[i]];
  6330. if (!tab._shown)
  6331. this._showTabElement(i, tab);
  6332. }
  6333. this._populateDropDownFromIndex();
  6334. },
  6335. _populateDropDownFromIndex: function()
  6336. {
  6337. if (this._dropDownButton.parentElement)
  6338. this._headerContentsElement.removeChild(this._dropDownButton);
  6339. this._tabsSelect.removeChildren();
  6340. var tabsToShow = [];
  6341. for (var i = 0; i < this._tabs.length; ++i) {
  6342. if (!this._tabs[i]._shown)
  6343. tabsToShow.push(this._tabs[i]);
  6344. continue;
  6345. }
  6346. function compareFunction(tab1, tab2)
  6347. {
  6348. return tab1.title.localeCompare(tab2.title);
  6349. }
  6350. tabsToShow.sort(compareFunction);
  6351. for (var i = 0; i < tabsToShow.length; ++i) {
  6352. var option = new Option(tabsToShow[i].title);
  6353. option.tab = tabsToShow[i];
  6354. this._tabsSelect.appendChild(option);
  6355. }
  6356. if (this._tabsSelect.options.length) {
  6357. this._headerContentsElement.appendChild(this._dropDownButton);
  6358. this._tabsSelect.selectedIndex = -1;
  6359. }
  6360. },
  6361. _tabsSelectChanged: function()
  6362. {
  6363. var options = this._tabsSelect.options;
  6364. var selectedOption = options[this._tabsSelect.selectedIndex];
  6365. this.selectTab(selectedOption.tab.id, true);
  6366. },
  6367. _measureDropDownButton: function()
  6368. {
  6369. this._dropDownButton.addStyleClass("measuring");
  6370. this._headerContentsElement.appendChild(this._dropDownButton);
  6371. this._measuredDropDownButtonWidth = this._dropDownButton.offsetWidth;
  6372. this._headerContentsElement.removeChild(this._dropDownButton);
  6373. this._dropDownButton.removeStyleClass("measuring");
  6374. },
  6375. _updateWidths: function()
  6376. {
  6377. var measuredWidths = [];
  6378. for (var tabId in this._tabs)
  6379. measuredWidths.push(this._tabs[tabId].measuredWidth);
  6380. var maxWidth = this._calculateMaxWidth(measuredWidths, this._headerContentsElement.offsetWidth);
  6381. for (var tabId in this._tabs) {
  6382. var tab = this._tabs[tabId];
  6383. tab.width = Math.min(tab.measuredWidth, maxWidth);
  6384. }
  6385. },
  6386. _calculateMaxWidth: function(measuredWidths, totalWidth)
  6387. {
  6388. if (!measuredWidths.length)
  6389. return 0;
  6390. measuredWidths.sort(function(x, y) { return x - y });
  6391. var totalMeasuredWidth = 0;
  6392. for (var i = 0; i < measuredWidths.length; ++i)
  6393. totalMeasuredWidth += measuredWidths[i];
  6394. if (totalWidth >= totalMeasuredWidth)
  6395. return measuredWidths[measuredWidths.length - 1];
  6396. var totalExtraWidth = 0;
  6397. for (var i = measuredWidths.length - 1; i > 0; --i) {
  6398. var extraWidth = measuredWidths[i] - measuredWidths[i - 1];
  6399. totalExtraWidth += (measuredWidths.length - i) * extraWidth;
  6400. if (totalWidth + totalExtraWidth >= totalMeasuredWidth)
  6401. return measuredWidths[i - 1] + (totalWidth + totalExtraWidth - totalMeasuredWidth) / (measuredWidths.length - i);
  6402. }
  6403. return totalWidth / measuredWidths.length;
  6404. },
  6405. _tabsToShowIndexes: function(tabsOrdered, tabsHistory, totalWidth, measuredDropDownButtonWidth)
  6406. {
  6407. var tabsToShowIndexes = [];
  6408. var totalTabsWidth = 0;
  6409. for (var i = 0; i < tabsHistory.length; ++i) {
  6410. totalTabsWidth += tabsHistory[i].width;
  6411. var minimalRequiredWidth = totalTabsWidth;
  6412. if (i !== tabsHistory.length - 1)
  6413. minimalRequiredWidth += measuredDropDownButtonWidth;
  6414. if (minimalRequiredWidth > totalWidth)
  6415. break;
  6416. tabsToShowIndexes.push(tabsOrdered.indexOf(tabsHistory[i]));
  6417. }
  6418. tabsToShowIndexes.sort(function(x, y) { return x - y });
  6419. return tabsToShowIndexes;
  6420. },
  6421. _hideCurrentTab: function()
  6422. {
  6423. if (!this._currentTab)
  6424. return;
  6425. this._hideTab(this._currentTab);
  6426. delete this._currentTab;
  6427. },
  6428. _showTab: function(tab)
  6429. {
  6430. tab.tabElement.addStyleClass("selected");
  6431. tab.view.show(this._contentElement);
  6432. },
  6433. _hideTab: function(tab)
  6434. {
  6435. tab.tabElement.removeStyleClass("selected");
  6436. tab.view.detach();
  6437. },
  6438. canHighlightLine: function()
  6439. {
  6440. return this._currentTab && this._currentTab.view && this._currentTab.view.canHighlightLine();
  6441. },
  6442. highlightLine: function(line)
  6443. {
  6444. if (this.canHighlightLine())
  6445. this._currentTab.view.highlightLine(line);
  6446. },
  6447. elementsToRestoreScrollPositionsFor: function()
  6448. {
  6449. return [ this._contentElement ];
  6450. },
  6451. _insertBefore: function(tab, index)
  6452. {
  6453. this._tabsElement.insertBefore(tab._tabElement, this._tabsElement.childNodes[index]);
  6454. var oldIndex = this._tabs.indexOf(tab);
  6455. this._tabs.splice(oldIndex, 1);
  6456. if (oldIndex < index)
  6457. --index;
  6458. this._tabs.splice(index, 0, tab);
  6459. }
  6460. }
  6461. WebInspector.TabbedPane.prototype.__proto__ = WebInspector.View.prototype;
  6462. WebInspector.TabbedPaneTab = function(tabbedPane, measureElement, id, title, closeable, view, tooltip)
  6463. {
  6464. this._closeable = closeable;
  6465. this._tabbedPane = tabbedPane;
  6466. this._measureElement = measureElement;
  6467. this._id = id;
  6468. this._title = title;
  6469. this._tooltip = tooltip;
  6470. this._view = view;
  6471. this._shown = false;
  6472. this._measuredWidth;
  6473. this._tabElement;
  6474. }
  6475. WebInspector.TabbedPaneTab.prototype = {
  6476. get id()
  6477. {
  6478. return this._id;
  6479. },
  6480. get title()
  6481. {
  6482. return this._title;
  6483. },
  6484. set title(title)
  6485. {
  6486. this._title = title;
  6487. if (this._titleElement)
  6488. this._titleElement.textContent = title;
  6489. delete this._measuredWidth;
  6490. },
  6491. get view()
  6492. {
  6493. return this._view;
  6494. },
  6495. set view(view)
  6496. {
  6497. this._view = view;
  6498. },
  6499. get tooltip()
  6500. {
  6501. return this._tooltip;
  6502. },
  6503. set tooltip(tooltip)
  6504. {
  6505. this._tooltip = tooltip;
  6506. if (this._titleElement)
  6507. this._titleElement.title = tooltip || "";
  6508. },
  6509. get tabElement()
  6510. {
  6511. if (typeof(this._tabElement) !== "undefined")
  6512. return this._tabElement;
  6513. this._createTabElement(false);
  6514. return this._tabElement;
  6515. },
  6516. get measuredWidth()
  6517. {
  6518. if (typeof(this._measuredWidth) !== "undefined")
  6519. return this._measuredWidth;
  6520. this._measure();
  6521. return this._measuredWidth;
  6522. },
  6523. get width()
  6524. {
  6525. return this._width || this.measuredWidth;
  6526. },
  6527. set width(width)
  6528. {
  6529. this.tabElement.style.width = width + "px";
  6530. this._width = width;
  6531. },
  6532. _createTabElement: function(measuring)
  6533. {
  6534. var tabElement = document.createElement("div");
  6535. tabElement.addStyleClass("tabbed-pane-header-tab");
  6536. tabElement.tabIndex = -1;
  6537. var titleElement = tabElement.createChild("span", "tabbed-pane-header-tab-title");
  6538. titleElement.textContent = this.title;
  6539. titleElement.title = this.tooltip || "";
  6540. if (!measuring)
  6541. this._titleElement = titleElement;
  6542. if (this._closeable) {
  6543. var closeButtonSpan = tabElement.createChild("span", "tabbed-pane-header-tab-close-button");
  6544. closeButtonSpan.textContent = "\u00D7";
  6545. }
  6546. if (measuring)
  6547. tabElement.addStyleClass("measuring");
  6548. else {
  6549. this._tabElement = tabElement;
  6550. tabElement.addEventListener("click", this._tabClicked.bind(this), false);
  6551. tabElement.addEventListener("mousedown", this._tabMouseDown.bind(this), false);
  6552. if (this._closeable) {
  6553. tabElement.addEventListener("contextmenu", this._tabContextMenu.bind(this), false);
  6554. tabElement.addEventListener("mousemove", this._tabMouseMove.bind(this), false);
  6555. }
  6556. }
  6557. return tabElement;
  6558. },
  6559. _measure: function()
  6560. {
  6561. var measuringTabElement = this._createTabElement(true);
  6562. this._measureElement.appendChild(measuringTabElement);
  6563. this._measuredWidth = measuringTabElement.offsetWidth;
  6564. this._measureElement.removeChild(measuringTabElement);
  6565. },
  6566. _tabClicked: function(event)
  6567. {
  6568. if (this._closeable && (event.button === 1 || event.target.hasStyleClass("tabbed-pane-header-tab-close-button")))
  6569. this._tabbedPane.closeTab(this.id, true);
  6570. },
  6571. _tabMouseDown: function(event)
  6572. {
  6573. if (event.target.hasStyleClass("tabbed-pane-header-tab-close-button") || event.button === 1)
  6574. return;
  6575. this._tabbedPane.selectTab(this.id, true);
  6576. this._dragStartX = event.pageX;
  6577. },
  6578. _tabContextMenu: function(event)
  6579. {
  6580. function close()
  6581. {
  6582. this._tabbedPane.closeTab(this.id, true);
  6583. }
  6584. function closeOthers()
  6585. {
  6586. this._tabbedPane.closeOtherTabs(this.id);
  6587. }
  6588. function closeAll()
  6589. {
  6590. this._tabbedPane.closeAllTabs(true);
  6591. }
  6592. var contextMenu = new WebInspector.ContextMenu();
  6593. contextMenu.appendItem(WebInspector.UIString("Close"), close.bind(this));
  6594. contextMenu.appendItem(WebInspector.UIString("Close Others"), closeOthers.bind(this));
  6595. contextMenu.appendItem(WebInspector.UIString("Close All"), closeAll.bind(this));
  6596. contextMenu.show(event);
  6597. },
  6598. _tabMouseMove: function(event)
  6599. {
  6600. if (isNaN(this._dragStartX))
  6601. return;
  6602. if (event.which !== 1)
  6603. return;
  6604. this._tabbedPane.selectTab(this.id, true);
  6605. WebInspector.elementDragStart(this._tabElement, this._tabDragging.bind(this), this._endTabDragging.bind(this), event, "pointer");
  6606. },
  6607. _tabDragging: function(event)
  6608. {
  6609. var tabElements = this._tabbedPane._tabsElement.childNodes;
  6610. for (var i = 0; i < tabElements.length; ++i) {
  6611. var tabElement = tabElements[i];
  6612. if (tabElement === this._tabElement)
  6613. continue;
  6614. var intersects = tabElement.offsetLeft + tabElement.clientWidth > this._tabElement.offsetLeft &&
  6615. this._tabElement.offsetLeft + this._tabElement.clientWidth > tabElement.offsetLeft;
  6616. if (!intersects)
  6617. continue;
  6618. if (Math.abs(event.pageX - this._dragStartX) < tabElement.clientWidth / 2 + 5)
  6619. break;
  6620. if (event.pageX - this._dragStartX > 0) {
  6621. tabElement = tabElement.nextSibling;
  6622. ++i;
  6623. }
  6624. var oldOffsetLeft = this._tabElement.offsetLeft;
  6625. this._tabbedPane._insertBefore(this, i);
  6626. this._dragStartX += this._tabElement.offsetLeft - oldOffsetLeft;
  6627. break;
  6628. }
  6629. if (!this._tabElement.previousSibling && event.pageX - this._dragStartX < 0) {
  6630. this._tabElement.style.setProperty("left", "0px");
  6631. return;
  6632. }
  6633. if (!this._tabElement.nextSibling && event.pageX - this._dragStartX > 0) {
  6634. this._tabElement.style.setProperty("left", "0px");
  6635. return;
  6636. }
  6637. this._tabElement.style.setProperty("position", "relative");
  6638. this._tabElement.style.setProperty("left", (event.pageX - this._dragStartX) + "px");
  6639. },
  6640. _endTabDragging: function(event)
  6641. {
  6642. this._tabElement.style.removeProperty("position");
  6643. this._tabElement.style.removeProperty("left");
  6644. delete this._dragStartX;
  6645. WebInspector.elementDragEnd(event);
  6646. }
  6647. }
  6648. WebInspector.Drawer = function()
  6649. {
  6650. this.element = document.getElementById("drawer");
  6651. this._savedHeight = 200;
  6652. this._mainElement = document.getElementById("main");
  6653. this._toolbarElement = document.getElementById("toolbar");
  6654. this._mainStatusBar = document.getElementById("main-status-bar");
  6655. this._mainStatusBar.addEventListener("mousedown", this._startStatusBarDragging.bind(this), true);
  6656. this._counters = document.getElementById("counters");
  6657. this._drawerContentsElement = document.createElement("div");
  6658. this._drawerContentsElement.id = "drawer-contents";
  6659. this._drawerContentsElement.className = "drawer-contents";
  6660. this.element.appendChild(this._drawerContentsElement);
  6661. this._drawerStatusBar = document.createElement("div");
  6662. this._drawerStatusBar.id = "drawer-status-bar";
  6663. this._drawerStatusBar.className = "status-bar";
  6664. this.element.appendChild(this._drawerStatusBar);
  6665. this._viewStatusBar = document.createElement("div");
  6666. this._drawerStatusBar.appendChild(this._viewStatusBar);
  6667. }
  6668. WebInspector.Drawer.AnimationType = {
  6669. Immediately: 0,
  6670. Normal: 1,
  6671. Slow: 2
  6672. }
  6673. WebInspector.Drawer.prototype = {
  6674. get visible()
  6675. {
  6676. return !!this._view;
  6677. },
  6678. _constrainHeight: function(height)
  6679. {
  6680. return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
  6681. },
  6682. show: function(view, animationType)
  6683. {
  6684. this.immediatelyFinishAnimation();
  6685. if (this._view && this._view.counterElement)
  6686. this._view.counterElement.parentNode.removeChild(this._view.counterElement);
  6687. var drawerWasVisible = this.visible;
  6688. if (this._view) {
  6689. this._view.detach();
  6690. this._drawerContentsElement.removeChildren();
  6691. }
  6692. this._view = view;
  6693. var statusBarItems = this._view.statusBarItems || [];
  6694. this._viewStatusBar.removeChildren();
  6695. for (var i = 0; i < statusBarItems.length; ++i)
  6696. this._viewStatusBar.appendChild(statusBarItems[i]);
  6697. if (this._view.counterElement)
  6698. this._counters.insertBefore(this._view.counterElement, this._counters.firstChild);
  6699. document.body.addStyleClass("drawer-visible");
  6700. this._view.markAsRoot();
  6701. this._view.show(this._drawerContentsElement);
  6702. if (drawerWasVisible)
  6703. return;
  6704. var anchoredItems = document.getElementById("anchored-status-bar-items");
  6705. var height = this._constrainHeight(this._savedHeight || this.element.offsetHeight);
  6706. var animations = [
  6707. {element: this.element, end: {height: height}},
  6708. {element: this._mainElement, end: {bottom: height}},
  6709. {element: this._mainStatusBar, start: {"padding-left": anchoredItems.offsetWidth - 1}, end: {"padding-left": 0}},
  6710. {element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}}
  6711. ];
  6712. this._drawerStatusBar.insertBefore(anchoredItems, this._drawerStatusBar.firstChild);
  6713. if (this._currentPanelCounters) {
  6714. var oldRight = this._drawerStatusBar.clientWidth - (this._counters.offsetLeft + this._currentPanelCounters.offsetWidth);
  6715. var newRight = WebInspector.Panel.counterRightMargin;
  6716. var rightPadding = (oldRight - newRight);
  6717. animations.push({element: this._currentPanelCounters, start: {"padding-right": rightPadding}, end: {"padding-right": 0}});
  6718. this._currentPanelCounters.parentNode.removeChild(this._currentPanelCounters);
  6719. this._mainStatusBar.appendChild(this._currentPanelCounters);
  6720. }
  6721. function animationFinished()
  6722. {
  6723. WebInspector.inspectorView.currentPanel().doResize();
  6724. if (this._view && this._view.afterShow)
  6725. this._view.afterShow();
  6726. delete this._currentAnimation;
  6727. if (this._currentPanelCounters)
  6728. this._currentPanelCounters.removeAttribute("style");
  6729. }
  6730. this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationFinished.bind(this));
  6731. if (animationType === WebInspector.Drawer.AnimationType.Immediately)
  6732. this._currentAnimation.forceComplete();
  6733. },
  6734. hide: function(animationType)
  6735. {
  6736. this.immediatelyFinishAnimation();
  6737. if (!this.visible)
  6738. return;
  6739. this._savedHeight = this.element.offsetHeight;
  6740. WebInspector.restoreFocusFromElement(this.element);
  6741. var anchoredItems = document.getElementById("anchored-status-bar-items");
  6742. this._mainStatusBar.style.setProperty("padding-left", (anchoredItems.offsetWidth - 1) + "px");
  6743. document.body.removeStyleClass("drawer-visible");
  6744. WebInspector.inspectorView.currentPanel().statusBarResized();
  6745. document.body.addStyleClass("drawer-visible");
  6746. var animations = [
  6747. {element: this._mainElement, end: {bottom: 0}},
  6748. {element: this._mainStatusBar, start: {"padding-left": 0}, end: {"padding-left": anchoredItems.offsetWidth - 1}},
  6749. {element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}}
  6750. ];
  6751. if (this._currentPanelCounters) {
  6752. var newRight = this._drawerStatusBar.clientWidth - this._counters.offsetLeft;
  6753. var oldRight = this._mainStatusBar.clientWidth - (this._currentPanelCounters.offsetLeft + this._currentPanelCounters.offsetWidth);
  6754. var rightPadding = (newRight - oldRight);
  6755. animations.push({element: this._currentPanelCounters, start: {"padding-right": 0}, end: {"padding-right": rightPadding}});
  6756. }
  6757. function animationFinished()
  6758. {
  6759. WebInspector.inspectorView.currentPanel().doResize();
  6760. this._mainStatusBar.insertBefore(anchoredItems, this._mainStatusBar.firstChild);
  6761. this._mainStatusBar.style.removeProperty("padding-left");
  6762. if (this._view.counterElement)
  6763. this._view.counterElement.parentNode.removeChild(this._view.counterElement);
  6764. if (this._currentPanelCounters) {
  6765. this._currentPanelCounters.setAttribute("style", null);
  6766. this._currentPanelCounters.parentNode.removeChild(this._currentPanelCounters);
  6767. this._counters.insertBefore(this._currentPanelCounters, this._counters.firstChild);
  6768. }
  6769. this._view.detach();
  6770. delete this._view;
  6771. this._drawerContentsElement.removeChildren();
  6772. document.body.removeStyleClass("drawer-visible");
  6773. delete this._currentAnimation;
  6774. }
  6775. this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationFinished.bind(this));
  6776. if (animationType === WebInspector.Drawer.AnimationType.Immediately)
  6777. this._currentAnimation.forceComplete();
  6778. },
  6779. resize: function()
  6780. {
  6781. if (!this.visible)
  6782. return;
  6783. this._view.storeScrollPositions();
  6784. var height = this._constrainHeight(parseInt(this.element.style.height, 10));
  6785. this._mainElement.style.bottom = height + "px";
  6786. this.element.style.height = height + "px";
  6787. this._view.doResize();
  6788. },
  6789. immediatelyFinishAnimation: function()
  6790. {
  6791. if (this._currentAnimation)
  6792. this._currentAnimation.forceComplete();
  6793. },
  6794. set currentPanelCounters(x)
  6795. {
  6796. if (!x) {
  6797. if (this._currentPanelCounters)
  6798. this._currentPanelCounters.parentElement.removeChild(this._currentPanelCounters);
  6799. delete this._currentPanelCounters;
  6800. return;
  6801. }
  6802. this._currentPanelCounters = x;
  6803. if (this.visible)
  6804. this._mainStatusBar.appendChild(x);
  6805. else
  6806. this._counters.insertBefore(x, this._counters.firstChild);
  6807. },
  6808. _animationDuration: function(animationType)
  6809. {
  6810. switch (animationType) {
  6811. case WebInspector.Drawer.AnimationType.Slow:
  6812. return 2000;
  6813. case WebInspector.Drawer.AnimationType.Normal:
  6814. return 250;
  6815. default:
  6816. return 0;
  6817. }
  6818. },
  6819. _startStatusBarDragging: function(event)
  6820. {
  6821. if (!this.visible || event.target !== this._mainStatusBar)
  6822. return;
  6823. this._view.storeScrollPositions();
  6824. WebInspector.elementDragStart(this._mainStatusBar, this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), event, "row-resize");
  6825. this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop();
  6826. event.consume();
  6827. },
  6828. _statusBarDragging: function(event)
  6829. {
  6830. var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
  6831. height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
  6832. this._mainElement.style.bottom = height + "px";
  6833. this.element.style.height = height + "px";
  6834. if (WebInspector.inspectorView.currentPanel())
  6835. WebInspector.inspectorView.currentPanel().doResize();
  6836. this._view.doResize();
  6837. event.consume(true);
  6838. },
  6839. _endStatusBarDragging: function(event)
  6840. {
  6841. WebInspector.elementDragEnd(event);
  6842. this._savedHeight = this.element.offsetHeight;
  6843. delete this._statusBarDragOffset;
  6844. event.consume();
  6845. }
  6846. }
  6847. WebInspector.drawer = null;
  6848. WebInspector.ConsoleModel = function()
  6849. {
  6850. this.messages = [];
  6851. this.warnings = 0;
  6852. this.errors = 0;
  6853. this._interruptRepeatCount = false;
  6854. InspectorBackend.registerConsoleDispatcher(new WebInspector.ConsoleDispatcher(this));
  6855. }
  6856. WebInspector.ConsoleModel.Events = {
  6857. ConsoleCleared: "console-cleared",
  6858. MessageAdded: "console-message-added",
  6859. RepeatCountUpdated: "repeat-count-updated"
  6860. }
  6861. WebInspector.ConsoleModel.prototype = {
  6862. enableAgent: function()
  6863. {
  6864. if (WebInspector.settings.monitoringXHREnabled.get())
  6865. ConsoleAgent.setMonitoringXHREnabled(true);
  6866. ConsoleAgent.enable();
  6867. },
  6868. addMessage: function(msg)
  6869. {
  6870. this.messages.push(msg);
  6871. this._previousMessage = msg;
  6872. this._incrementErrorWarningCount(msg);
  6873. this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.MessageAdded, msg);
  6874. this._interruptRepeatCount = false;
  6875. },
  6876. _incrementErrorWarningCount: function(msg)
  6877. {
  6878. switch (msg.level) {
  6879. case WebInspector.ConsoleMessage.MessageLevel.Warning:
  6880. this.warnings += msg.repeatDelta;
  6881. break;
  6882. case WebInspector.ConsoleMessage.MessageLevel.Error:
  6883. this.errors += msg.repeatDelta;
  6884. break;
  6885. }
  6886. },
  6887. requestClearMessages: function()
  6888. {
  6889. ConsoleAgent.clearMessages();
  6890. this.clearMessages();
  6891. },
  6892. clearMessages: function()
  6893. {
  6894. this.messages = [];
  6895. this.errors = 0;
  6896. this.warnings = 0;
  6897. this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.ConsoleCleared);
  6898. },
  6899. interruptRepeatCount: function()
  6900. {
  6901. this._interruptRepeatCount = true;
  6902. },
  6903. _messageRepeatCountUpdated: function(count)
  6904. {
  6905. var msg = this._previousMessage;
  6906. if (!msg)
  6907. return;
  6908. var prevRepeatCount = msg.totalRepeatCount;
  6909. if (!this._interruptRepeatCount) {
  6910. msg.repeatDelta = count - prevRepeatCount;
  6911. msg.repeatCount = msg.repeatCount + msg.repeatDelta;
  6912. msg.totalRepeatCount = count;
  6913. msg.updateRepeatCount();
  6914. this._incrementErrorWarningCount(msg);
  6915. this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.RepeatCountUpdated, msg);
  6916. } else {
  6917. var msgCopy = msg.clone();
  6918. msgCopy.totalRepeatCount = count;
  6919. msgCopy.repeatCount = (count - prevRepeatCount) || 1;
  6920. msgCopy.repeatDelta = msgCopy.repeatCount;
  6921. this.addMessage(msgCopy);
  6922. }
  6923. }
  6924. }
  6925. WebInspector.ConsoleModel.prototype.__proto__ = WebInspector.Object.prototype;
  6926. WebInspector.ConsoleMessage = function(source, level, url, line, repeatCount)
  6927. {
  6928. this.source = source;
  6929. this.level = level;
  6930. this.url = url || null;
  6931. this.line = line || 0;
  6932. repeatCount = repeatCount || 1;
  6933. this.repeatCount = repeatCount;
  6934. this.repeatDelta = repeatCount;
  6935. this.totalRepeatCount = repeatCount;
  6936. }
  6937. WebInspector.ConsoleMessage.prototype = {
  6938. isErrorOrWarning: function()
  6939. {
  6940. return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
  6941. },
  6942. updateRepeatCount: function()
  6943. {
  6944. },
  6945. clone: function()
  6946. {
  6947. }
  6948. }
  6949. WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, repeatCount, parameters, stackTrace, request)
  6950. {
  6951. }
  6952. WebInspector.ConsoleMessage.MessageSource = {
  6953. HTML: "html",
  6954. XML: "xml",
  6955. JS: "javascript",
  6956. Network: "network",
  6957. ConsoleAPI: "console-api",
  6958. Other: "other"
  6959. }
  6960. WebInspector.ConsoleMessage.MessageType = {
  6961. Log: "log",
  6962. Dir: "dir",
  6963. DirXML: "dirxml",
  6964. Trace: "trace",
  6965. StartGroup: "startGroup",
  6966. StartGroupCollapsed: "startGroupCollapsed",
  6967. EndGroup: "endGroup",
  6968. Assert: "assert",
  6969. Result: "result"
  6970. }
  6971. WebInspector.ConsoleMessage.MessageLevel = {
  6972. Tip: "tip",
  6973. Log: "log",
  6974. Warning: "warning",
  6975. Error: "error",
  6976. Debug: "debug"
  6977. }
  6978. WebInspector.ConsoleDispatcher = function(console)
  6979. {
  6980. this._console = console;
  6981. }
  6982. WebInspector.ConsoleDispatcher.prototype = {
  6983. messageAdded: function(payload)
  6984. {
  6985. var consoleMessage = WebInspector.ConsoleMessage.create(
  6986. payload.source,
  6987. payload.level,
  6988. payload.text,
  6989. payload.type,
  6990. payload.url,
  6991. payload.line,
  6992. payload.repeatCount,
  6993. payload.parameters,
  6994. payload.stackTrace,
  6995. payload.networkRequestId ? WebInspector.networkRequestById(payload.networkRequestId) : undefined);
  6996. this._console.addMessage(consoleMessage);
  6997. },
  6998. messageRepeatCountUpdated: function(count)
  6999. {
  7000. this._console._messageRepeatCountUpdated(count);
  7001. },
  7002. messagesCleared: function()
  7003. {
  7004. if (!WebInspector.settings.preserveConsoleLog.get())
  7005. this._console.clearMessages();
  7006. }
  7007. }
  7008. WebInspector.console = null;
  7009. WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, type, url, line, repeatCount, parameters, stackTrace, request)
  7010. {
  7011. WebInspector.ConsoleMessage.call(this, source, level, url, line, repeatCount);
  7012. this._linkifier = linkifier;
  7013. this.type = type || WebInspector.ConsoleMessage.MessageType.Log;
  7014. this._messageText = message;
  7015. this._parameters = parameters;
  7016. this._stackTrace = stackTrace;
  7017. this._request = request;
  7018. this._customFormatters = {
  7019. "object": this._formatParameterAsObject,
  7020. "array": this._formatParameterAsArray,
  7021. "node": this._formatParameterAsNode,
  7022. "string": this._formatParameterAsString
  7023. };
  7024. }
  7025. WebInspector.ConsoleMessageImpl.prototype = {
  7026. _formatMessage: function()
  7027. {
  7028. this._formattedMessage = document.createElement("span");
  7029. this._formattedMessage.className = "console-message-text source-code";
  7030. if (this.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) {
  7031. switch (this.type) {
  7032. case WebInspector.ConsoleMessage.MessageType.Trace:
  7033. this._messageElement = document.createTextNode("console.trace()");
  7034. break;
  7035. case WebInspector.ConsoleMessage.MessageType.Assert:
  7036. var args = [WebInspector.UIString("Assertion failed:")];
  7037. if (this._parameters)
  7038. args = args.concat(this._parameters);
  7039. this._messageElement = this._format(args);
  7040. break;
  7041. case WebInspector.ConsoleMessage.MessageType.Dir:
  7042. var obj = this._parameters ? this._parameters[0] : undefined;
  7043. var args = ["%O", obj];
  7044. this._messageElement = this._format(args);
  7045. break;
  7046. default:
  7047. var args = this._parameters || [this._messageText];
  7048. this._messageElement = this._format(args);
  7049. }
  7050. } else if (this.source === WebInspector.ConsoleMessage.MessageSource.Network) {
  7051. if (this._request) {
  7052. this._stackTrace = this._request.initiator.stackTrace;
  7053. if (this._request.initiator && this._request.initiator.url) {
  7054. this.url = this._request.initiator.url;
  7055. this.line = this._request.initiator.lineNumber;
  7056. }
  7057. this._messageElement = document.createElement("span");
  7058. if (this.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
  7059. this._messageElement.appendChild(document.createTextNode(this._request.requestMethod + " "));
  7060. this._messageElement.appendChild(WebInspector.linkifyRequestAsNode(this._request));
  7061. if (this._request.failed)
  7062. this._messageElement.appendChild(document.createTextNode(" " + this._request.localizedFailDescription));
  7063. else
  7064. this._messageElement.appendChild(document.createTextNode(" " + this._request.statusCode + " (" + this._request.statusText + ")"));
  7065. } else {
  7066. var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(this._messageText, WebInspector.linkifyRequestAsNode.bind(null, this._request, ""));
  7067. this._messageElement.appendChild(fragment);
  7068. }
  7069. } else {
  7070. if (this.url) {
  7071. var isExternal = !WebInspector.resourceForURL(this.url);
  7072. this._anchorElement = WebInspector.linkifyURLAsNode(this.url, this.url, "console-message-url", isExternal);
  7073. }
  7074. this._messageElement = this._format([this._messageText]);
  7075. }
  7076. } else {
  7077. var args = this._parameters || [this._messageText];
  7078. this._messageElement = this._format(args);
  7079. }
  7080. if (this.source !== WebInspector.ConsoleMessage.MessageSource.Network || this._request) {
  7081. if (this._stackTrace && this._stackTrace.length && this._stackTrace[0].url) {
  7082. this._anchorElement = this._linkifyCallFrame(this._stackTrace[0]);
  7083. } else if (this.url && this.url !== "undefined") {
  7084. this._anchorElement = this._linkifyLocation(this.url, this.line, 0);
  7085. }
  7086. }
  7087. this._formattedMessage.appendChild(this._messageElement);
  7088. if (this._anchorElement) {
  7089. this._formattedMessage.appendChild(document.createTextNode(" "));
  7090. this._formattedMessage.appendChild(this._anchorElement);
  7091. }
  7092. var dumpStackTrace = !!this._stackTrace && this._stackTrace.length && (this.source === WebInspector.ConsoleMessage.MessageSource.Network || this.level === WebInspector.ConsoleMessage.MessageLevel.Error || this.type === WebInspector.ConsoleMessage.MessageType.Trace);
  7093. if (dumpStackTrace) {
  7094. var ol = document.createElement("ol");
  7095. ol.className = "outline-disclosure";
  7096. var treeOutline = new TreeOutline(ol);
  7097. var content = this._formattedMessage;
  7098. var root = new TreeElement(content, null, true);
  7099. content.treeElementForTest = root;
  7100. treeOutline.appendChild(root);
  7101. if (this.type === WebInspector.ConsoleMessage.MessageType.Trace)
  7102. root.expand();
  7103. this._populateStackTraceTreeElement(root);
  7104. this._formattedMessage = ol;
  7105. }
  7106. this._message = this._messageElement.textContent;
  7107. },
  7108. get message()
  7109. {
  7110. var formattedMessage = this.formattedMessage;
  7111. return this._message;
  7112. },
  7113. get formattedMessage()
  7114. {
  7115. if (!this._formattedMessage)
  7116. this._formatMessage();
  7117. return this._formattedMessage;
  7118. },
  7119. _linkifyLocation: function(url, lineNumber, columnNumber)
  7120. {
  7121. lineNumber = lineNumber ? lineNumber - 1 : 0;
  7122. columnNumber = columnNumber ? columnNumber - 1 : 0;
  7123. return this._linkifier.linkifyLocation(url, lineNumber, columnNumber, "console-message-url");
  7124. },
  7125. _linkifyCallFrame: function(callFrame)
  7126. {
  7127. return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
  7128. },
  7129. isErrorOrWarning: function()
  7130. {
  7131. return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
  7132. },
  7133. _format: function(parameters)
  7134. {
  7135. var formattedResult = document.createElement("span");
  7136. if (!parameters.length)
  7137. return formattedResult;
  7138. for (var i = 0; i < parameters.length; ++i) {
  7139. if (parameters[i] instanceof WebInspector.RemoteObject)
  7140. continue;
  7141. if (typeof parameters[i] === "object")
  7142. parameters[i] = WebInspector.RemoteObject.fromPayload(parameters[i]);
  7143. else
  7144. parameters[i] = WebInspector.RemoteObject.fromPrimitiveValue(parameters[i]);
  7145. }
  7146. var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this.type !== WebInspector.ConsoleMessage.MessageType.Result;
  7147. if (shouldFormatMessage) {
  7148. var result = this._formatWithSubstitutionString(parameters, formattedResult);
  7149. parameters = result.unusedSubstitutions;
  7150. if (parameters.length)
  7151. formattedResult.appendChild(document.createTextNode(" "));
  7152. }
  7153. for (var i = 0; i < parameters.length; ++i) {
  7154. if (shouldFormatMessage && parameters[i].type === "string")
  7155. formattedResult.appendChild(document.createTextNode(parameters[i].description));
  7156. else
  7157. formattedResult.appendChild(this._formatParameter(parameters[i]));
  7158. if (i < parameters.length - 1)
  7159. formattedResult.appendChild(document.createTextNode(" "));
  7160. }
  7161. return formattedResult;
  7162. },
  7163. _formatParameter: function(output, forceObjectFormat)
  7164. {
  7165. var type;
  7166. if (forceObjectFormat)
  7167. type = "object";
  7168. else if (output instanceof WebInspector.RemoteObject)
  7169. type = output.subtype || output.type;
  7170. else
  7171. type = typeof output;
  7172. var formatter = this._customFormatters[type];
  7173. if (!formatter) {
  7174. formatter = this._formatParameterAsValue;
  7175. output = output.description;
  7176. }
  7177. var span = document.createElement("span");
  7178. span.className = "console-formatted-" + type + " source-code";
  7179. formatter.call(this, output, span);
  7180. return span;
  7181. },
  7182. _formatParameterAsValue: function(val, elem)
  7183. {
  7184. elem.appendChild(document.createTextNode(val));
  7185. },
  7186. _formatParameterAsObject: function(obj, elem)
  7187. {
  7188. var section = new WebInspector.ObjectPropertiesSection(obj, obj.description);
  7189. section.enableContextMenu();
  7190. elem.appendChild(section.element);
  7191. },
  7192. _formatParameterAsNode: function(object, elem)
  7193. {
  7194. function printNode(nodeId)
  7195. {
  7196. if (!nodeId) {
  7197. this._formatParameterAsObject(object, elem);
  7198. return;
  7199. }
  7200. var treeOutline = new WebInspector.ElementsTreeOutline(false, false, true);
  7201. treeOutline.setVisible(true);
  7202. treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId);
  7203. treeOutline.element.addStyleClass("outline-disclosure");
  7204. if (!treeOutline.children[0].hasChildren)
  7205. treeOutline.element.addStyleClass("single-node");
  7206. elem.appendChild(treeOutline.element);
  7207. treeOutline.element.treeElementForTest = treeOutline.children[0];
  7208. }
  7209. object.pushNodeToFrontend(printNode.bind(this));
  7210. },
  7211. _formatParameterAsArray: function(array, elem)
  7212. {
  7213. const maxFlatArrayLength = 100;
  7214. if (array.arrayLength() > maxFlatArrayLength)
  7215. this._formatParameterAsObject(array, elem);
  7216. else
  7217. array.getOwnProperties(this._printArray.bind(this, array, elem));
  7218. },
  7219. _formatParameterAsString: function(output, elem)
  7220. {
  7221. var span = document.createElement("span");
  7222. span.className = "console-formatted-string source-code";
  7223. span.appendChild(WebInspector.linkifyStringAsFragment(output.description));
  7224. elem.removeStyleClass("console-formatted-string");
  7225. elem.appendChild(document.createTextNode("\""));
  7226. elem.appendChild(span);
  7227. elem.appendChild(document.createTextNode("\""));
  7228. },
  7229. _printArray: function(array, elem, properties)
  7230. {
  7231. if (!properties)
  7232. return;
  7233. var elements = [];
  7234. for (var i = 0; i < properties.length; ++i) {
  7235. var property = properties[i];
  7236. var name = property.name;
  7237. if (!isNaN(name))
  7238. elements[name] = this._formatAsArrayEntry(property.value);
  7239. }
  7240. elem.appendChild(document.createTextNode("["));
  7241. var lastNonEmptyIndex = -1;
  7242. function appendUndefined(elem, index)
  7243. {
  7244. if (index - lastNonEmptyIndex <= 1)
  7245. return;
  7246. var span = elem.createChild(span, "console-formatted-undefined");
  7247. span.textContent = WebInspector.UIString("undefined × %d", index - lastNonEmptyIndex - 1);
  7248. }
  7249. var length = array.arrayLength();
  7250. for (var i = 0; i < length; ++i) {
  7251. var element = elements[i];
  7252. if (!element)
  7253. continue;
  7254. if (i - lastNonEmptyIndex > 1) {
  7255. appendUndefined(elem, i);
  7256. elem.appendChild(document.createTextNode(", "));
  7257. }
  7258. elem.appendChild(element);
  7259. lastNonEmptyIndex = i;
  7260. if (i < length - 1)
  7261. elem.appendChild(document.createTextNode(", "));
  7262. }
  7263. appendUndefined(elem, length);
  7264. elem.appendChild(document.createTextNode("]"));
  7265. },
  7266. _formatAsArrayEntry: function(output)
  7267. {
  7268. return this._formatParameter(output, output.subtype && output.subtype === "array");
  7269. },
  7270. _formatWithSubstitutionString: function(parameters, formattedResult)
  7271. {
  7272. var formatters = {}
  7273. function parameterFormatter(force, obj)
  7274. {
  7275. return this._formatParameter(obj, force);
  7276. }
  7277. function valueFormatter(obj)
  7278. {
  7279. return obj.description;
  7280. }
  7281. formatters.o = parameterFormatter.bind(this, false);
  7282. formatters.s = valueFormatter;
  7283. formatters.f = valueFormatter;
  7284. formatters.i = valueFormatter;
  7285. formatters.d = valueFormatter;
  7286. formatters.O = parameterFormatter.bind(this, true);
  7287. function append(a, b)
  7288. {
  7289. if (!(b instanceof Node))
  7290. a.appendChild(WebInspector.linkifyStringAsFragment(b.toString()));
  7291. else
  7292. a.appendChild(b);
  7293. return a;
  7294. }
  7295. return String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append);
  7296. },
  7297. clearHighlight: function()
  7298. {
  7299. if (!this._formattedMessage)
  7300. return;
  7301. var highlightedMessage = this._formattedMessage;
  7302. delete this._formattedMessage;
  7303. delete this._anchorElement;
  7304. delete this._messageElement;
  7305. this._formatMessage();
  7306. this._element.replaceChild(this._formattedMessage, highlightedMessage);
  7307. },
  7308. highlightSearchResults: function(regexObject)
  7309. {
  7310. if (!this._formattedMessage)
  7311. return;
  7312. this._highlightSearchResultsInElement(regexObject, this._messageElement);
  7313. if (this._anchorElement)
  7314. this._highlightSearchResultsInElement(regexObject, this._anchorElement);
  7315. this._element.scrollIntoViewIfNeeded();
  7316. },
  7317. _highlightSearchResultsInElement: function(regexObject, element)
  7318. {
  7319. regexObject.lastIndex = 0;
  7320. var text = element.textContent;
  7321. var match = regexObject.exec(text);
  7322. var offset = 0;
  7323. var matchRanges = [];
  7324. while (match) {
  7325. matchRanges.push({ offset: match.index, length: match[0].length });
  7326. match = regexObject.exec(text);
  7327. }
  7328. WebInspector.highlightSearchResults(element, matchRanges);
  7329. },
  7330. matchesRegex: function(regexObject)
  7331. {
  7332. return regexObject.test(this._message) || (this._anchorElement && regexObject.test(this._anchorElement.textContent));
  7333. },
  7334. toMessageElement: function()
  7335. {
  7336. if (this._element)
  7337. return this._element;
  7338. var element = document.createElement("div");
  7339. element.message = this;
  7340. element.className = "console-message";
  7341. this._element = element;
  7342. switch (this.level) {
  7343. case WebInspector.ConsoleMessage.MessageLevel.Tip:
  7344. element.addStyleClass("console-tip-level");
  7345. break;
  7346. case WebInspector.ConsoleMessage.MessageLevel.Log:
  7347. element.addStyleClass("console-log-level");
  7348. break;
  7349. case WebInspector.ConsoleMessage.MessageLevel.Debug:
  7350. element.addStyleClass("console-debug-level");
  7351. break;
  7352. case WebInspector.ConsoleMessage.MessageLevel.Warning:
  7353. element.addStyleClass("console-warning-level");
  7354. break;
  7355. case WebInspector.ConsoleMessage.MessageLevel.Error:
  7356. element.addStyleClass("console-error-level");
  7357. break;
  7358. }
  7359. if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
  7360. element.addStyleClass("console-group-title");
  7361. element.appendChild(this.formattedMessage);
  7362. if (this.repeatCount > 1)
  7363. this.updateRepeatCount();
  7364. return element;
  7365. },
  7366. _populateStackTraceTreeElement: function(parentTreeElement)
  7367. {
  7368. for (var i = 0; i < this._stackTrace.length; i++) {
  7369. var frame = this._stackTrace[i];
  7370. var content = document.createElement("div");
  7371. var messageTextElement = document.createElement("span");
  7372. messageTextElement.className = "console-message-text source-code";
  7373. var functionName = frame.functionName || WebInspector.UIString("(anonymous function)");
  7374. messageTextElement.appendChild(document.createTextNode(functionName));
  7375. content.appendChild(messageTextElement);
  7376. if (frame.url) {
  7377. content.appendChild(document.createTextNode(" "));
  7378. var urlElement = this._linkifyCallFrame(frame);
  7379. content.appendChild(urlElement);
  7380. }
  7381. var treeElement = new TreeElement(content);
  7382. parentTreeElement.appendChild(treeElement);
  7383. }
  7384. },
  7385. updateRepeatCount: function() {
  7386. if (!this.repeatCountElement) {
  7387. this.repeatCountElement = document.createElement("span");
  7388. this.repeatCountElement.className = "bubble";
  7389. this._element.insertBefore(this.repeatCountElement, this._element.firstChild);
  7390. this._element.addStyleClass("repeated-message");
  7391. }
  7392. this.repeatCountElement.textContent = this.repeatCount;
  7393. },
  7394. toString: function()
  7395. {
  7396. var sourceString;
  7397. switch (this.source) {
  7398. case WebInspector.ConsoleMessage.MessageSource.HTML:
  7399. sourceString = "HTML";
  7400. break;
  7401. case WebInspector.ConsoleMessage.MessageSource.XML:
  7402. sourceString = "XML";
  7403. break;
  7404. case WebInspector.ConsoleMessage.MessageSource.JS:
  7405. sourceString = "JS";
  7406. break;
  7407. case WebInspector.ConsoleMessage.MessageSource.Network:
  7408. sourceString = "Network";
  7409. break;
  7410. case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI:
  7411. sourceString = "ConsoleAPI";
  7412. break;
  7413. case WebInspector.ConsoleMessage.MessageSource.Other:
  7414. sourceString = "Other";
  7415. break;
  7416. }
  7417. var typeString;
  7418. switch (this.type) {
  7419. case WebInspector.ConsoleMessage.MessageType.Log:
  7420. typeString = "Log";
  7421. break;
  7422. case WebInspector.ConsoleMessage.MessageType.Dir:
  7423. typeString = "Dir";
  7424. break;
  7425. case WebInspector.ConsoleMessage.MessageType.DirXML:
  7426. typeString = "Dir XML";
  7427. break;
  7428. case WebInspector.ConsoleMessage.MessageType.Trace:
  7429. typeString = "Trace";
  7430. break;
  7431. case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed:
  7432. case WebInspector.ConsoleMessage.MessageType.StartGroup:
  7433. typeString = "Start Group";
  7434. break;
  7435. case WebInspector.ConsoleMessage.MessageType.EndGroup:
  7436. typeString = "End Group";
  7437. break;
  7438. case WebInspector.ConsoleMessage.MessageType.Assert:
  7439. typeString = "Assert";
  7440. break;
  7441. case WebInspector.ConsoleMessage.MessageType.Result:
  7442. typeString = "Result";
  7443. break;
  7444. }
  7445. var levelString;
  7446. switch (this.level) {
  7447. case WebInspector.ConsoleMessage.MessageLevel.Tip:
  7448. levelString = "Tip";
  7449. break;
  7450. case WebInspector.ConsoleMessage.MessageLevel.Log:
  7451. levelString = "Log";
  7452. break;
  7453. case WebInspector.ConsoleMessage.MessageLevel.Warning:
  7454. levelString = "Warning";
  7455. break;
  7456. case WebInspector.ConsoleMessage.MessageLevel.Debug:
  7457. levelString = "Debug";
  7458. break;
  7459. case WebInspector.ConsoleMessage.MessageLevel.Error:
  7460. levelString = "Error";
  7461. break;
  7462. }
  7463. return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
  7464. },
  7465. get text()
  7466. {
  7467. return this._messageText;
  7468. },
  7469. location: function()
  7470. {
  7471. var lineNumber = this.stackTrace ? this.stackTrace[0].lineNumber - 1 : this.line - 1;
  7472. var columnNumber = this.stackTrace && this.stackTrace[0].columnNumber ? this.stackTrace[0].columnNumber - 1 : 0;
  7473. return WebInspector.debuggerModel.createRawLocationByURL(this.url, lineNumber, columnNumber);
  7474. },
  7475. isEqual: function(msg)
  7476. {
  7477. if (!msg)
  7478. return false;
  7479. if (this._stackTrace) {
  7480. if (!msg._stackTrace)
  7481. return false;
  7482. var l = this._stackTrace;
  7483. var r = msg._stackTrace;
  7484. for (var i = 0; i < l.length; i++) {
  7485. if (l[i].url !== r[i].url ||
  7486. l[i].functionName !== r[i].functionName ||
  7487. l[i].lineNumber !== r[i].lineNumber ||
  7488. l[i].columnNumber !== r[i].columnNumber)
  7489. return false;
  7490. }
  7491. }
  7492. return (this.source === msg.source)
  7493. && (this.type === msg.type)
  7494. && (this.level === msg.level)
  7495. && (this.line === msg.line)
  7496. && (this.url === msg.url)
  7497. && (this.message === msg.message)
  7498. && (this._request === msg._request);
  7499. },
  7500. get stackTrace()
  7501. {
  7502. return this._stackTrace;
  7503. },
  7504. clone: function()
  7505. {
  7506. return WebInspector.ConsoleMessage.create(this.source, this.level, this._messageText, this.type, this.url, this.line, this.repeatCount, this._parameters, this._stackTrace, this._request);
  7507. }
  7508. }
  7509. WebInspector.ConsoleMessageImpl.prototype.__proto__ = WebInspector.ConsoleMessage.prototype;
  7510. const ExpressionStopCharacters = " =:[({;,!+-*/&|^<>";
  7511. WebInspector.ConsoleView = function(hideContextSelector)
  7512. {
  7513. WebInspector.View.call(this);
  7514. this.element.id = "console-view";
  7515. this.messages = [];
  7516. this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear console log."), "clear-status-bar-item");
  7517. this._clearConsoleButton.addEventListener("click", this._requestClearMessages, this);
  7518. this._contextSelectElement = document.createElement("select");
  7519. this._contextSelectElement.id = "console-context";
  7520. this._contextSelectElement.className = "status-bar-item";
  7521. this._contextSelectElement.addEventListener("change", this._updateIsolatedWorldSelector.bind(this), false);
  7522. this._isolatedWorldSelectElement = document.createElement("select");
  7523. this._isolatedWorldSelectElement.id = "console-context";
  7524. this._isolatedWorldSelectElement.className = "status-bar-item";
  7525. if (hideContextSelector) {
  7526. this._contextSelectElement.addStyleClass("hidden");
  7527. this._isolatedWorldSelectElement.addStyleClass("hidden");
  7528. }
  7529. this.messagesElement = document.createElement("div");
  7530. this.messagesElement.id = "console-messages";
  7531. this.messagesElement.className = "monospace";
  7532. this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
  7533. this.element.appendChild(this.messagesElement);
  7534. this._scrolledToBottom = true;
  7535. this.promptElement = document.createElement("div");
  7536. this.promptElement.id = "console-prompt";
  7537. this.promptElement.className = "source-code";
  7538. this.promptElement.spellcheck = false;
  7539. this.messagesElement.appendChild(this.promptElement);
  7540. this.messagesElement.appendChild(document.createElement("br"));
  7541. this.topGroup = new WebInspector.ConsoleGroup(null);
  7542. this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
  7543. this.currentGroup = this.topGroup;
  7544. this._filterBarElement = document.createElement("div");
  7545. this._filterBarElement.id = "console-filter";
  7546. this._filterBarElement.className = "scope-bar status-bar-item";
  7547. function createDividerElement() {
  7548. var dividerElement = document.createElement("div");
  7549. dividerElement.addStyleClass("scope-bar-divider");
  7550. this._filterBarElement.appendChild(dividerElement);
  7551. }
  7552. var updateFilterHandler = this._updateFilter.bind(this);
  7553. function createFilterElement(category, label) {
  7554. var categoryElement = document.createElement("li");
  7555. categoryElement.category = category;
  7556. categoryElement.className = category;
  7557. categoryElement.addEventListener("click", updateFilterHandler, false);
  7558. categoryElement.textContent = label;
  7559. this._filterBarElement.appendChild(categoryElement);
  7560. return categoryElement;
  7561. }
  7562. this.allElement = createFilterElement.call(this, "all", WebInspector.UIString("All"));
  7563. createDividerElement.call(this);
  7564. this.errorElement = createFilterElement.call(this, "errors", WebInspector.UIString("Errors"));
  7565. this.warningElement = createFilterElement.call(this, "warnings", WebInspector.UIString("Warnings"));
  7566. this.logElement = createFilterElement.call(this, "logs", WebInspector.UIString("Logs"));
  7567. this.filter(this.allElement, false);
  7568. this._registerShortcuts();
  7569. this.registerRequiredCSS("textPrompt.css");
  7570. this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
  7571. WebInspector.settings.monitoringXHREnabled.addChangeListener(this._monitoringXHREnabledSettingChanged.bind(this));
  7572. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
  7573. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
  7574. this._linkifier = new WebInspector.Linkifier();
  7575. this.prompt = new WebInspector.TextPromptWithHistory(this.completionsForTextPrompt.bind(this), ExpressionStopCharacters + ".");
  7576. this.prompt.setSuggestBoxEnabled("generic-suggest");
  7577. this.prompt.renderAsBlock();
  7578. this.prompt.attach(this.promptElement);
  7579. this.prompt.proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), false);
  7580. this.prompt.setHistoryData(WebInspector.settings.consoleHistory.get());
  7581. }
  7582. WebInspector.ConsoleView.Events = {
  7583. ConsoleCleared: "console-cleared",
  7584. EntryAdded: "console-entry-added",
  7585. }
  7586. WebInspector.ConsoleView.prototype = {
  7587. get statusBarItems()
  7588. {
  7589. return [this._clearConsoleButton.element, this._contextSelectElement, this._isolatedWorldSelectElement, this._filterBarElement];
  7590. },
  7591. addContext: function(context)
  7592. {
  7593. var option = document.createElement("option");
  7594. option.text = context.displayName;
  7595. option.title = context.url;
  7596. option._context = context;
  7597. context._consoleOption = option;
  7598. this._contextSelectElement.appendChild(option);
  7599. context.addEventListener(WebInspector.FrameEvaluationContext.EventTypes.Updated, this._contextUpdated, this);
  7600. context.addEventListener(WebInspector.FrameEvaluationContext.EventTypes.AddedExecutionContext, this._addedExecutionContext, this);
  7601. this._updateIsolatedWorldSelector();
  7602. },
  7603. removeContext: function(context)
  7604. {
  7605. this._contextSelectElement.removeChild(context._consoleOption);
  7606. this._updateIsolatedWorldSelector();
  7607. },
  7608. _updateIsolatedWorldSelector: function()
  7609. {
  7610. var context = this._currentEvaluationContext();
  7611. if (!context) {
  7612. this._isolatedWorldSelectElement.addStyleClass("hidden");
  7613. return;
  7614. }
  7615. var isolatedContexts = context.isolatedContexts();
  7616. if (!isolatedContexts.length) {
  7617. this._isolatedWorldSelectElement.addStyleClass("hidden");
  7618. return;
  7619. }
  7620. this._isolatedWorldSelectElement.removeStyleClass("hidden");
  7621. this._isolatedWorldSelectElement.removeChildren();
  7622. this._appendIsolatedContextOption(context.mainWorldContext());
  7623. for (var i = 0; i < isolatedContexts.length; i++)
  7624. this._appendIsolatedContextOption(isolatedContexts[i]);
  7625. },
  7626. _appendIsolatedContextOption: function(isolatedContext)
  7627. {
  7628. if (!isolatedContext)
  7629. return;
  7630. var option = document.createElement("option");
  7631. option.text = isolatedContext.name;
  7632. option.title = isolatedContext.id;
  7633. option._executionContextId = isolatedContext.id;
  7634. this._isolatedWorldSelectElement.appendChild(option);
  7635. },
  7636. _contextUpdated: function(event)
  7637. {
  7638. var context = event.data;
  7639. var option = context._consoleOption;
  7640. option.text = context.displayName;
  7641. option.title = context.url;
  7642. },
  7643. _addedExecutionContext: function(event)
  7644. {
  7645. var context = event.data;
  7646. if (context === this._currentEvaluationContext())
  7647. this._updateIsolatedWorldSelector();
  7648. },
  7649. _currentEvaluationContextId: function()
  7650. {
  7651. var result = this._currentIsolatedContextId();
  7652. if (result !== undefined)
  7653. return result;
  7654. var context = this._currentEvaluationContext();
  7655. if (context && context.mainWorldContext())
  7656. return context.mainWorldContext().id;
  7657. return undefined;
  7658. },
  7659. _currentEvaluationContext: function()
  7660. {
  7661. if (this._contextSelectElement.selectedIndex === -1)
  7662. return undefined;
  7663. return this._contextSelectElement[this._contextSelectElement.selectedIndex]._context;
  7664. },
  7665. _currentIsolatedContextId: function()
  7666. {
  7667. if (this._isolatedWorldSelectElement.hasStyleClass("hidden"))
  7668. return undefined;
  7669. if (this._isolatedWorldSelectElement.selectedIndex === -1)
  7670. return undefined;
  7671. return this._isolatedWorldSelectElement[this._isolatedWorldSelectElement.selectedIndex]._executionContextId;
  7672. },
  7673. _updateFilter: function(e)
  7674. {
  7675. var isMac = WebInspector.isMac();
  7676. var selectMultiple = false;
  7677. if (isMac && e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey)
  7678. selectMultiple = true;
  7679. if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey)
  7680. selectMultiple = true;
  7681. this.filter(e.target, selectMultiple);
  7682. },
  7683. filter: function(target, selectMultiple)
  7684. {
  7685. function unselectAll()
  7686. {
  7687. this.allElement.removeStyleClass("selected");
  7688. this.errorElement.removeStyleClass("selected");
  7689. this.warningElement.removeStyleClass("selected");
  7690. this.logElement.removeStyleClass("selected");
  7691. this.messagesElement.removeStyleClass("filter-all");
  7692. this.messagesElement.removeStyleClass("filter-errors");
  7693. this.messagesElement.removeStyleClass("filter-warnings");
  7694. this.messagesElement.removeStyleClass("filter-logs");
  7695. }
  7696. var targetFilterClass = "filter-" + target.category;
  7697. if (target.category === "all") {
  7698. if (target.hasStyleClass("selected")) {
  7699. return;
  7700. }
  7701. unselectAll.call(this);
  7702. } else {
  7703. if (this.allElement.hasStyleClass("selected")) {
  7704. this.allElement.removeStyleClass("selected");
  7705. this.messagesElement.removeStyleClass("filter-all");
  7706. }
  7707. }
  7708. if (!selectMultiple) {
  7709. unselectAll.call(this);
  7710. target.addStyleClass("selected");
  7711. this.messagesElement.addStyleClass(targetFilterClass);
  7712. return;
  7713. }
  7714. if (target.hasStyleClass("selected")) {
  7715. target.removeStyleClass("selected");
  7716. this.messagesElement.removeStyleClass(targetFilterClass);
  7717. } else {
  7718. target.addStyleClass("selected");
  7719. this.messagesElement.addStyleClass(targetFilterClass);
  7720. }
  7721. },
  7722. willHide: function()
  7723. {
  7724. this.prompt.hideSuggestBox();
  7725. this.prompt.clearAutoComplete(true);
  7726. },
  7727. wasShown: function()
  7728. {
  7729. if (!this.prompt.isCaretInsidePrompt())
  7730. this.prompt.moveCaretToEndOfPrompt();
  7731. },
  7732. afterShow: function()
  7733. {
  7734. WebInspector.setCurrentFocusElement(this.promptElement);
  7735. },
  7736. storeScrollPositions: function()
  7737. {
  7738. WebInspector.View.prototype.storeScrollPositions.call(this);
  7739. this._scrolledToBottom = this.messagesElement.isScrolledToBottom();
  7740. },
  7741. restoreScrollPositions: function()
  7742. {
  7743. if (this._scrolledToBottom)
  7744. this._immediatelyScrollIntoView();
  7745. else
  7746. WebInspector.View.prototype.restoreScrollPositions.call(this);
  7747. },
  7748. onResize: function()
  7749. {
  7750. this.restoreScrollPositions();
  7751. },
  7752. _isScrollIntoViewScheduled: function()
  7753. {
  7754. return !!this._scrollIntoViewTimer;
  7755. },
  7756. _scheduleScrollIntoView: function()
  7757. {
  7758. if (this._scrollIntoViewTimer)
  7759. return;
  7760. function scrollIntoView()
  7761. {
  7762. delete this._scrollIntoViewTimer;
  7763. this.promptElement.scrollIntoView(true);
  7764. }
  7765. this._scrollIntoViewTimer = setTimeout(scrollIntoView.bind(this), 20);
  7766. },
  7767. _immediatelyScrollIntoView: function()
  7768. {
  7769. this.promptElement.scrollIntoView(true);
  7770. this._cancelScheduledScrollIntoView();
  7771. },
  7772. _cancelScheduledScrollIntoView: function()
  7773. {
  7774. if (!this._isScrollIntoViewScheduled())
  7775. return;
  7776. clearTimeout(this._scrollIntoViewTimer);
  7777. delete this._scrollIntoViewTimer;
  7778. },
  7779. _consoleMessageAdded: function(event)
  7780. {
  7781. this._appendConsoleMessage(event.data);
  7782. },
  7783. _appendConsoleMessage: function(msg)
  7784. {
  7785. if (!this._isScrollIntoViewScheduled() && ((msg instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom()))
  7786. this._scheduleScrollIntoView();
  7787. this.messages.push(msg);
  7788. if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
  7789. var parentGroup = this.currentGroup.parentGroup
  7790. if (parentGroup)
  7791. this.currentGroup = parentGroup;
  7792. } else {
  7793. if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
  7794. var group = new WebInspector.ConsoleGroup(this.currentGroup);
  7795. this.currentGroup.messagesElement.appendChild(group.element);
  7796. this.currentGroup = group;
  7797. }
  7798. this.currentGroup.addMessage(msg);
  7799. }
  7800. this.dispatchEventToListeners(WebInspector.ConsoleView.Events.EntryAdded, msg);
  7801. },
  7802. _consoleCleared: function()
  7803. {
  7804. this._scrolledToBottom = true;
  7805. this.messages = [];
  7806. this.currentGroup = this.topGroup;
  7807. this.topGroup.messagesElement.removeChildren();
  7808. this.dispatchEventToListeners(WebInspector.ConsoleView.Events.ConsoleCleared);
  7809. this._linkifier.reset();
  7810. },
  7811. completionsForTextPrompt: function(textPrompt, wordRange, force, completionsReadyCallback)
  7812. {
  7813. var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, ExpressionStopCharacters, textPrompt.proxyElement, "backward");
  7814. var expressionString = expressionRange.toString();
  7815. var prefix = wordRange.toString();
  7816. this.completionsForExpression(expressionString, prefix, force, completionsReadyCallback);
  7817. },
  7818. completionsForExpression: function(expressionString, prefix, force, completionsReadyCallback)
  7819. {
  7820. var lastIndex = expressionString.length - 1;
  7821. var dotNotation = (expressionString[lastIndex] === ".");
  7822. var bracketNotation = (expressionString[lastIndex] === "[");
  7823. if (dotNotation || bracketNotation)
  7824. expressionString = expressionString.substr(0, lastIndex);
  7825. if (expressionString && parseInt(expressionString, 10) == expressionString) {
  7826. completionsReadyCallback([]);
  7827. return;
  7828. }
  7829. if (!prefix && !expressionString && !force) {
  7830. completionsReadyCallback([]);
  7831. return;
  7832. }
  7833. if (!expressionString && WebInspector.debuggerModel.selectedCallFrame())
  7834. WebInspector.debuggerModel.getSelectedCallFrameVariables(receivedPropertyNames.bind(this));
  7835. else
  7836. this.evalInInspectedWindow(expressionString, "completion", true, true, false, evaluated.bind(this));
  7837. function evaluated(result, wasThrown)
  7838. {
  7839. if (!result || wasThrown) {
  7840. completionsReadyCallback([]);
  7841. return;
  7842. }
  7843. function getCompletions(primitiveType)
  7844. {
  7845. var object;
  7846. if (primitiveType === "string")
  7847. object = new String("");
  7848. else if (primitiveType === "number")
  7849. object = new Number(0);
  7850. else if (primitiveType === "boolean")
  7851. object = new Boolean(false);
  7852. else
  7853. object = this;
  7854. var resultSet = {};
  7855. for (var o = object; o; o = o.__proto__) {
  7856. try {
  7857. var names = Object.getOwnPropertyNames(o);
  7858. for (var i = 0; i < names.length; ++i)
  7859. resultSet[names[i]] = true;
  7860. } catch (e) {
  7861. }
  7862. }
  7863. return resultSet;
  7864. }
  7865. if (result.type === "object" || result.type === "function")
  7866. result.callFunctionJSON(getCompletions, undefined, receivedPropertyNames.bind(this));
  7867. else if (result.type === "string" || result.type === "number" || result.type === "boolean")
  7868. this.evalInInspectedWindow("(" + getCompletions + ")(\"" + result.type + "\")", "completion", false, true, true, receivedPropertyNamesFromEval.bind(this));
  7869. }
  7870. function receivedPropertyNamesFromEval(notRelevant, wasThrown, result)
  7871. {
  7872. if (result && !wasThrown)
  7873. receivedPropertyNames.call(this, result.value);
  7874. else
  7875. completionsReadyCallback([]);
  7876. }
  7877. function receivedPropertyNames(propertyNames)
  7878. {
  7879. RuntimeAgent.releaseObjectGroup("completion");
  7880. if (!propertyNames) {
  7881. completionsReadyCallback([]);
  7882. return;
  7883. }
  7884. var includeCommandLineAPI = (!dotNotation && !bracketNotation);
  7885. if (includeCommandLineAPI) {
  7886. const commandLineAPI = ["dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear"];
  7887. for (var i = 0; i < commandLineAPI.length; ++i)
  7888. propertyNames[commandLineAPI[i]] = true;
  7889. }
  7890. this._reportCompletions(completionsReadyCallback, dotNotation, bracketNotation, expressionString, prefix, Object.keys(propertyNames));
  7891. }
  7892. },
  7893. _reportCompletions: function(completionsReadyCallback, dotNotation, bracketNotation, expressionString, prefix, properties) {
  7894. if (bracketNotation) {
  7895. if (prefix.length && prefix[0] === "'")
  7896. var quoteUsed = "'";
  7897. else
  7898. var quoteUsed = "\"";
  7899. }
  7900. var results = [];
  7901. if (!expressionString) {
  7902. const keywords = ["break", "case", "catch", "continue", "default", "delete", "do", "else", "finally", "for", "function", "if", "in",
  7903. "instanceof", "new", "return", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with"];
  7904. properties = properties.concat(keywords);
  7905. }
  7906. properties.sort();
  7907. for (var i = 0; i < properties.length; ++i) {
  7908. var property = properties[i];
  7909. if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property))
  7910. continue;
  7911. if (bracketNotation) {
  7912. if (!/^[0-9]+$/.test(property))
  7913. property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed;
  7914. property += "]";
  7915. }
  7916. if (property.length < prefix.length)
  7917. continue;
  7918. if (prefix.length && !property.startsWith(prefix))
  7919. continue;
  7920. results.push(property);
  7921. }
  7922. completionsReadyCallback(results);
  7923. },
  7924. _handleContextMenuEvent: function(event)
  7925. {
  7926. if (!window.getSelection().isCollapsed) {
  7927. return;
  7928. }
  7929. var contextMenu = new WebInspector.ContextMenu();
  7930. if (WebInspector.populateHrefContextMenu(contextMenu, null, event))
  7931. contextMenu.appendSeparator();
  7932. function monitoringXHRItemAction()
  7933. {
  7934. WebInspector.settings.monitoringXHREnabled.set(!WebInspector.settings.monitoringXHREnabled.get());
  7935. }
  7936. contextMenu.appendCheckboxItem(WebInspector.UIString("Log XMLHttpRequests"), monitoringXHRItemAction.bind(this), WebInspector.settings.monitoringXHREnabled.get());
  7937. function preserveLogItemAction()
  7938. {
  7939. WebInspector.settings.preserveConsoleLog.set(!WebInspector.settings.preserveConsoleLog.get());
  7940. }
  7941. contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Preserve log upon navigation" : "Preserve Log upon Navigation"), preserveLogItemAction.bind(this), WebInspector.settings.preserveConsoleLog.get());
  7942. contextMenu.appendSeparator();
  7943. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear console" : "Clear Console"), this._requestClearMessages.bind(this));
  7944. contextMenu.show(event);
  7945. },
  7946. _monitoringXHREnabledSettingChanged: function(event)
  7947. {
  7948. ConsoleAgent.setMonitoringXHREnabled(event.data);
  7949. },
  7950. _messagesClicked: function(event)
  7951. {
  7952. if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
  7953. this.prompt.moveCaretToEndOfPrompt();
  7954. },
  7955. _registerShortcuts: function()
  7956. {
  7957. this._shortcuts = {};
  7958. var shortcut = WebInspector.KeyboardShortcut;
  7959. if (WebInspector.isMac()) {
  7960. var shortcutK = shortcut.makeDescriptor("k", WebInspector.KeyboardShortcut.Modifiers.Meta);
  7961. this._shortcuts[shortcutK.key] = this._requestClearMessages.bind(this);
  7962. }
  7963. var shortcutL = shortcut.makeDescriptor("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
  7964. this._shortcuts[shortcutL.key] = this._requestClearMessages.bind(this);
  7965. var shortcutM = shortcut.makeDescriptor("m", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta | WebInspector.KeyboardShortcut.Modifiers.Shift);
  7966. this._shortcuts[shortcutM.key] = this._dumpMemory.bind(this);
  7967. var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
  7968. var keys = WebInspector.isMac() ? [ shortcutK.name, shortcutL.name ] : [ shortcutL.name ];
  7969. section.addAlternateKeys(keys, WebInspector.UIString("Clear console"));
  7970. keys = [
  7971. shortcut.shortcutToString(shortcut.Keys.Tab),
  7972. shortcut.shortcutToString(shortcut.Keys.Tab, shortcut.Modifiers.Shift)
  7973. ];
  7974. section.addRelatedKeys(keys, WebInspector.UIString("Next/previous suggestion"));
  7975. section.addKey(shortcut.shortcutToString(shortcut.Keys.Right), WebInspector.UIString("Accept suggestion"));
  7976. keys = [
  7977. shortcut.shortcutToString(shortcut.Keys.Down),
  7978. shortcut.shortcutToString(shortcut.Keys.Up)
  7979. ];
  7980. section.addRelatedKeys(keys, WebInspector.UIString("Next/previous line"));
  7981. keys = [
  7982. shortcut.shortcutToString("N", shortcut.Modifiers.Alt),
  7983. shortcut.shortcutToString("P", shortcut.Modifiers.Alt)
  7984. ];
  7985. if (WebInspector.isMac())
  7986. section.addRelatedKeys(keys, WebInspector.UIString("Next/previous command"));
  7987. section.addKey(shortcut.shortcutToString(shortcut.Keys.Enter), WebInspector.UIString("Execute command"));
  7988. },
  7989. _requestClearMessages: function()
  7990. {
  7991. WebInspector.console.requestClearMessages();
  7992. },
  7993. _promptKeyDown: function(event)
  7994. {
  7995. if (isEnterKey(event)) {
  7996. this._enterKeyPressed(event);
  7997. return;
  7998. }
  7999. var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
  8000. var handler = this._shortcuts[shortcut];
  8001. if (handler) {
  8002. handler();
  8003. event.preventDefault();
  8004. return;
  8005. }
  8006. },
  8007. evalInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback)
  8008. {
  8009. if (WebInspector.debuggerModel.selectedCallFrame()) {
  8010. WebInspector.debuggerModel.evaluateOnSelectedCallFrame(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback);
  8011. return;
  8012. }
  8013. if (!expression) {
  8014. expression = "this";
  8015. }
  8016. function evalCallback(error, result, wasThrown)
  8017. {
  8018. if (error) {
  8019. console.error(error);
  8020. callback(null, false);
  8021. return;
  8022. }
  8023. if (returnByValue)
  8024. callback(null, !!wasThrown, wasThrown ? null : result);
  8025. else
  8026. callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown);
  8027. }
  8028. var contextId = this._currentEvaluationContextId();
  8029. RuntimeAgent.evaluate(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, contextId, returnByValue, evalCallback);
  8030. },
  8031. evaluateUsingTextPrompt: function(expression, showResultOnly)
  8032. {
  8033. this._appendCommand(expression, this.prompt.text, false, showResultOnly);
  8034. },
  8035. _enterKeyPressed: function(event)
  8036. {
  8037. if (event.altKey || event.ctrlKey || event.shiftKey)
  8038. return;
  8039. event.consume(true);
  8040. this.prompt.clearAutoComplete(true);
  8041. var str = this.prompt.text;
  8042. if (!str.length)
  8043. return;
  8044. this._appendCommand(str, "", true, false);
  8045. },
  8046. _appendCommand: function(text, newPromptText, useCommandLineAPI, showResultOnly)
  8047. {
  8048. if (!showResultOnly) {
  8049. var commandMessage = new WebInspector.ConsoleCommand(text);
  8050. WebInspector.console.interruptRepeatCount();
  8051. this._appendConsoleMessage(commandMessage);
  8052. }
  8053. this.prompt.text = newPromptText;
  8054. function printResult(result, wasThrown)
  8055. {
  8056. if (!result)
  8057. return;
  8058. if (!showResultOnly) {
  8059. this.prompt.pushHistoryItem(text);
  8060. WebInspector.settings.consoleHistory.set(this.prompt.historyData.slice(-30));
  8061. }
  8062. this._appendConsoleMessage(new WebInspector.ConsoleCommandResult(result, wasThrown, commandMessage, this._linkifier));
  8063. }
  8064. this.evalInInspectedWindow(text, "console", true, false, false, printResult.bind(this));
  8065. WebInspector.userMetrics.ConsoleEvaluated.record();
  8066. },
  8067. elementsToRestoreScrollPositionsFor: function()
  8068. {
  8069. return [this.messagesElement];
  8070. },
  8071. _dumpMemory: function()
  8072. {
  8073. function comparator(a, b)
  8074. {
  8075. if (a.size < b.size)
  8076. return 1;
  8077. if (a.size > b.size)
  8078. return -1;
  8079. return a.title.localeCompare(b.title);
  8080. }
  8081. function callback(error, groups)
  8082. {
  8083. var titles = [];
  8084. groups.sort(comparator);
  8085. for (var i = 0; i < groups.length; ++i) {
  8086. var suffix = groups[i].size > 0 ? " [" + groups[i].size + "]" : "";
  8087. titles.push(groups[i].title + suffix + (groups[i].documentURI ? " (" + groups[i].documentURI + ")" : ""));
  8088. }
  8089. var counter = 1;
  8090. var previousTitle = null;
  8091. for (var i = 0; i < titles.length; ++i) {
  8092. var title = titles[i];
  8093. if (title === previousTitle) {
  8094. counter++;
  8095. continue;
  8096. }
  8097. if (previousTitle)
  8098. WebInspector.log(counter > 1 ? counter + " x " + previousTitle : previousTitle);
  8099. previousTitle = title;
  8100. counter = 1;
  8101. }
  8102. WebInspector.log(counter > 1 ? counter + " x " + previousTitle : previousTitle);
  8103. }
  8104. MemoryAgent.getDOMNodeCount(callback);
  8105. }
  8106. }
  8107. WebInspector.ConsoleView.prototype.__proto__ = WebInspector.View.prototype;
  8108. WebInspector.ConsoleCommand = function(command)
  8109. {
  8110. this.command = command;
  8111. }
  8112. WebInspector.ConsoleCommand.prototype = {
  8113. clearHighlight: function()
  8114. {
  8115. var highlightedMessage = this._formattedCommand;
  8116. delete this._formattedCommand;
  8117. this._formatCommand();
  8118. this._element.replaceChild(this._formattedCommand, highlightedMessage);
  8119. },
  8120. highlightSearchResults: function(regexObject)
  8121. {
  8122. regexObject.lastIndex = 0;
  8123. var text = this.command;
  8124. var match = regexObject.exec(text);
  8125. var offset = 0;
  8126. var matchRanges = [];
  8127. while (match) {
  8128. matchRanges.push({ offset: match.index, length: match[0].length });
  8129. match = regexObject.exec(text);
  8130. }
  8131. WebInspector.highlightSearchResults(this._formattedCommand, matchRanges);
  8132. this._element.scrollIntoViewIfNeeded();
  8133. },
  8134. matchesRegex: function(regexObject)
  8135. {
  8136. return regexObject.test(this.command);
  8137. },
  8138. toMessageElement: function()
  8139. {
  8140. if (!this._element) {
  8141. this._element = document.createElement("div");
  8142. this._element.command = this;
  8143. this._element.className = "console-user-command";
  8144. this._formatCommand();
  8145. this._element.appendChild(this._formattedCommand);
  8146. }
  8147. return this._element;
  8148. },
  8149. _formatCommand: function()
  8150. {
  8151. this._formattedCommand = document.createElement("span");
  8152. this._formattedCommand.className = "console-message-text source-code";
  8153. this._formattedCommand.textContent = this.command;
  8154. },
  8155. }
  8156. WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand, linkifier)
  8157. {
  8158. var level = (wasThrown ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
  8159. this.originatingCommand = originatingCommand;
  8160. WebInspector.ConsoleMessageImpl.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, "", linkifier, WebInspector.ConsoleMessage.MessageType.Result, undefined, undefined, undefined, [result]);
  8161. }
  8162. WebInspector.ConsoleCommandResult.prototype = {
  8163. toMessageElement: function()
  8164. {
  8165. var element = WebInspector.ConsoleMessageImpl.prototype.toMessageElement.call(this);
  8166. element.addStyleClass("console-user-command-result");
  8167. return element;
  8168. }
  8169. }
  8170. WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessageImpl.prototype;
  8171. WebInspector.ConsoleGroup = function(parentGroup)
  8172. {
  8173. this.parentGroup = parentGroup;
  8174. var element = document.createElement("div");
  8175. element.className = "console-group";
  8176. element.group = this;
  8177. this.element = element;
  8178. if (parentGroup) {
  8179. var bracketElement = document.createElement("div");
  8180. bracketElement.className = "console-group-bracket";
  8181. element.appendChild(bracketElement);
  8182. }
  8183. var messagesElement = document.createElement("div");
  8184. messagesElement.className = "console-group-messages";
  8185. element.appendChild(messagesElement);
  8186. this.messagesElement = messagesElement;
  8187. }
  8188. WebInspector.ConsoleGroup.prototype = {
  8189. addMessage: function(msg)
  8190. {
  8191. var element = msg.toMessageElement();
  8192. if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
  8193. this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
  8194. element.addEventListener("click", this._titleClicked.bind(this), false);
  8195. var groupElement = element.enclosingNodeOrSelfWithClass("console-group");
  8196. if (groupElement && msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
  8197. groupElement.addStyleClass("collapsed");
  8198. } else
  8199. this.messagesElement.appendChild(element);
  8200. if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand)
  8201. element.previousSibling.addStyleClass("console-adjacent-user-command-result");
  8202. },
  8203. _titleClicked: function(event)
  8204. {
  8205. var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title");
  8206. if (groupTitleElement) {
  8207. var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
  8208. if (groupElement)
  8209. if (groupElement.hasStyleClass("collapsed"))
  8210. groupElement.removeStyleClass("collapsed");
  8211. else
  8212. groupElement.addStyleClass("collapsed");
  8213. groupTitleElement.scrollIntoViewIfNeeded(true);
  8214. }
  8215. event.consume(true);
  8216. }
  8217. }
  8218. WebInspector.consoleView = null;
  8219. WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, repeatCount, parameters, stackTrace, request)
  8220. {
  8221. return new WebInspector.ConsoleMessageImpl(source, level, message, WebInspector.consoleView._linkifier, type, url, line, repeatCount, parameters, stackTrace, request);
  8222. }
  8223. WebInspector.Panel = function(name)
  8224. {
  8225. WebInspector.View.call(this);
  8226. this.element.addStyleClass("panel");
  8227. this.element.addStyleClass(name);
  8228. this._panelName = name;
  8229. this._shortcuts = {};
  8230. WebInspector.settings[this._sidebarWidthSettingName()] = WebInspector.settings.createSetting(this._sidebarWidthSettingName(), undefined);
  8231. }
  8232. WebInspector.Panel.counterRightMargin = 25;
  8233. WebInspector.Panel.prototype = {
  8234. get toolbarItem()
  8235. {
  8236. if (this._toolbarItem)
  8237. return this._toolbarItem;
  8238. this._toolbarItem = WebInspector.Toolbar.createPanelToolbarItem(this);
  8239. return this._toolbarItem;
  8240. },
  8241. get name()
  8242. {
  8243. return this._panelName;
  8244. },
  8245. show: function()
  8246. {
  8247. WebInspector.View.prototype.show.call(this, WebInspector.inspectorView.element);
  8248. },
  8249. wasShown: function()
  8250. {
  8251. var statusBarItems = this.statusBarItems;
  8252. if (statusBarItems) {
  8253. this._statusBarItemContainer = document.createElement("div");
  8254. for (var i = 0; i < statusBarItems.length; ++i)
  8255. this._statusBarItemContainer.appendChild(statusBarItems[i]);
  8256. document.getElementById("main-status-bar").appendChild(this._statusBarItemContainer);
  8257. }
  8258. if ("_toolbarItem" in this)
  8259. this._toolbarItem.addStyleClass("toggled-on");
  8260. this.focus();
  8261. },
  8262. willHide: function()
  8263. {
  8264. if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode)
  8265. this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer);
  8266. delete this._statusBarItemContainer;
  8267. if ("_toolbarItem" in this)
  8268. this._toolbarItem.removeStyleClass("toggled-on");
  8269. },
  8270. reset: function()
  8271. {
  8272. this.searchCanceled();
  8273. },
  8274. defaultFocusedElement: function()
  8275. {
  8276. return this.sidebarTreeElement || this.element;
  8277. },
  8278. searchCanceled: function()
  8279. {
  8280. WebInspector.searchController.updateSearchMatchesCount(0, this);
  8281. },
  8282. performSearch: function(query)
  8283. {
  8284. this.searchCanceled();
  8285. },
  8286. jumpToNextSearchResult: function()
  8287. {
  8288. },
  8289. jumpToPreviousSearchResult: function()
  8290. {
  8291. },
  8292. createSplitView: function(parentElement, position, defaultWidth)
  8293. {
  8294. if (this.splitView)
  8295. return;
  8296. if (!parentElement)
  8297. parentElement = this.element;
  8298. this.splitView = new WebInspector.SplitView(position || WebInspector.SplitView.SidebarPosition.Left, this._sidebarWidthSettingName(), defaultWidth);
  8299. this.splitView.show(parentElement);
  8300. this.splitView.addEventListener(WebInspector.SplitView.EventTypes.Resized, this.sidebarResized.bind(this));
  8301. this.sidebarElement = this.splitView.sidebarElement;
  8302. },
  8303. createSplitViewWithSidebarTree: function(parentElement, position, defaultWidth)
  8304. {
  8305. if (this.splitView)
  8306. return;
  8307. this.createSplitView(parentElement, position);
  8308. this.sidebarTreeElement = document.createElement("ol");
  8309. this.sidebarTreeElement.className = "sidebar-tree";
  8310. this.splitView.sidebarElement.appendChild(this.sidebarTreeElement);
  8311. this.splitView.sidebarElement.addStyleClass("sidebar");
  8312. this.sidebarTree = new TreeOutline(this.sidebarTreeElement);
  8313. this.sidebarTree.panel = this;
  8314. },
  8315. _sidebarWidthSettingName: function()
  8316. {
  8317. return this._panelName + "SidebarWidth";
  8318. },
  8319. get toolbarItemLabel()
  8320. {
  8321. },
  8322. get statusBarItems()
  8323. {
  8324. },
  8325. sidebarResized: function(width)
  8326. {
  8327. },
  8328. statusBarResized: function()
  8329. {
  8330. },
  8331. canShowAnchorLocation: function(anchor)
  8332. {
  8333. return false;
  8334. },
  8335. showAnchorLocation: function(anchor)
  8336. {
  8337. },
  8338. elementsToRestoreScrollPositionsFor: function()
  8339. {
  8340. return [];
  8341. },
  8342. handleShortcut: function(event)
  8343. {
  8344. var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
  8345. var handler = this._shortcuts[shortcutKey];
  8346. if (handler) {
  8347. handler(event);
  8348. event.handled = true;
  8349. }
  8350. },
  8351. registerShortcut: function(key, handler)
  8352. {
  8353. this._shortcuts[key] = handler;
  8354. },
  8355. unregisterShortcut: function(key)
  8356. {
  8357. delete this._shortcuts[key];
  8358. }
  8359. }
  8360. WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype;
  8361. WebInspector.InspectorView = function()
  8362. {
  8363. WebInspector.View.call(this);
  8364. this.markAsRoot();
  8365. this.element.id = "main-panels";
  8366. this.element.setAttribute("spellcheck", false);
  8367. this._history = [];
  8368. this._historyIterator = -1;
  8369. document.addEventListener("keydown", this._keyDown.bind(this), false);
  8370. this._panelOrder = [];
  8371. }
  8372. WebInspector.InspectorView.Events = {
  8373. PanelSelected: "panel-selected"
  8374. }
  8375. WebInspector.InspectorView.prototype = {
  8376. addPanel: function(panel)
  8377. {
  8378. this._panelOrder.push(panel);
  8379. WebInspector.toolbar.addPanel(panel);
  8380. },
  8381. currentPanel: function()
  8382. {
  8383. return this._currentPanel;
  8384. },
  8385. setCurrentPanel: function(x)
  8386. {
  8387. if (this._currentPanel === x)
  8388. return;
  8389. if (this._currentPanel)
  8390. this._currentPanel.detach();
  8391. this._currentPanel = x;
  8392. if (x) {
  8393. x.show();
  8394. this.dispatchEventToListeners(WebInspector.InspectorView.Events.PanelSelected);
  8395. WebInspector.searchController.activePanelChanged();
  8396. }
  8397. for (var panelName in WebInspector.panels) {
  8398. if (WebInspector.panels[panelName] === x) {
  8399. WebInspector.settings.lastActivePanel.set(panelName);
  8400. this._pushToHistory(panelName);
  8401. WebInspector.userMetrics.panelShown(panelName);
  8402. }
  8403. }
  8404. },
  8405. _keyDown: function(event)
  8406. {
  8407. switch (event.keyIdentifier) {
  8408. case "U+005B":
  8409. case "U+00DB":
  8410. var isRotateLeft = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && !event.altKey;
  8411. if (isRotateLeft) {
  8412. var index = this._panelOrder.indexOf(this.currentPanel());
  8413. index = (index === 0) ? this._panelOrder.length - 1 : index - 1;
  8414. this._panelOrder[index].toolbarItem.click();
  8415. event.consume();
  8416. return;
  8417. }
  8418. var isGoBack = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && event.altKey;
  8419. if (isGoBack && this._canGoBackInHistory()) {
  8420. this._goBackInHistory();
  8421. event.consume();
  8422. }
  8423. break;
  8424. case "U+005D":
  8425. case "U+00DD":
  8426. var isRotateRight = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && !event.altKey;
  8427. if (isRotateRight) {
  8428. var index = this._panelOrder.indexOf(this.currentPanel());
  8429. index = (index + 1) % this._panelOrder.length;
  8430. this._panelOrder[index].toolbarItem.click();
  8431. event.consume();
  8432. return;
  8433. }
  8434. var isGoForward = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && event.altKey;
  8435. if (isGoForward && this._canGoForwardInHistory()) {
  8436. this._goForwardInHistory();
  8437. event.consume();
  8438. }
  8439. break;
  8440. }
  8441. },
  8442. _canGoBackInHistory: function()
  8443. {
  8444. return this._historyIterator > 0;
  8445. },
  8446. _goBackInHistory: function()
  8447. {
  8448. this._inHistory = true;
  8449. this.setCurrentPanel(WebInspector.panels[this._history[--this._historyIterator]]);
  8450. delete this._inHistory;
  8451. },
  8452. _canGoForwardInHistory: function()
  8453. {
  8454. return this._historyIterator < this._history.length - 1;
  8455. },
  8456. _goForwardInHistory: function()
  8457. {
  8458. this._inHistory = true;
  8459. this.setCurrentPanel(WebInspector.panels[this._history[++this._historyIterator]]);
  8460. delete this._inHistory;
  8461. },
  8462. _pushToHistory: function(panelName)
  8463. {
  8464. if (this._inHistory)
  8465. return;
  8466. this._history.splice(this._historyIterator + 1, this._history.length - this._historyIterator - 1);
  8467. if (!this._history.length || this._history[this._history.length - 1] !== panelName)
  8468. this._history.push(panelName);
  8469. this._historyIterator = this._history.length - 1;
  8470. }
  8471. }
  8472. WebInspector.InspectorView.prototype.__proto__ = WebInspector.View.prototype;
  8473. WebInspector.inspectorView = null;
  8474. WebInspector.AdvancedSearchController = function()
  8475. {
  8476. this._shortcut = WebInspector.AdvancedSearchController.createShortcut();
  8477. this._searchId = 0;
  8478. WebInspector.settings.advancedSearchConfig = WebInspector.settings.createSetting("advancedSearchConfig", new WebInspector.SearchConfig("", true, false));
  8479. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
  8480. }
  8481. WebInspector.AdvancedSearchController.createShortcut = function()
  8482. {
  8483. if (WebInspector.isMac())
  8484. return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Alt);
  8485. else
  8486. return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Ctrl | WebInspector.KeyboardShortcut.Modifiers.Shift);
  8487. }
  8488. WebInspector.AdvancedSearchController.prototype = {
  8489. handleShortcut: function(event)
  8490. {
  8491. if (WebInspector.KeyboardShortcut.makeKeyFromEvent(event) === this._shortcut.key) {
  8492. this.show();
  8493. event.handled = true;
  8494. }
  8495. },
  8496. _frameNavigated: function()
  8497. {
  8498. this.resetSearch();
  8499. },
  8500. registerSearchScope: function(searchScope)
  8501. {
  8502. this._searchScope = searchScope;
  8503. },
  8504. show: function()
  8505. {
  8506. if (!this._searchView)
  8507. this._searchView = new WebInspector.SearchView(this);
  8508. if (this._searchView.isShowing())
  8509. this._searchView.focus();
  8510. else
  8511. WebInspector.showViewInDrawer(this._searchView);
  8512. },
  8513. close: function()
  8514. {
  8515. this.stopSearch();
  8516. WebInspector.closeDrawerView();
  8517. },
  8518. _onSearchResult: function(searchId, searchResult)
  8519. {
  8520. if (searchId !== this._searchId)
  8521. return;
  8522. this._searchView.addSearchResult(searchResult);
  8523. if (!searchResult.searchMatches.length)
  8524. return;
  8525. if (!this._searchResultsPane)
  8526. this._searchResultsPane = this._currentSearchScope.createSearchResultsPane(this._searchConfig);
  8527. this._searchView.resultsPane = this._searchResultsPane;
  8528. this._searchResultsPane.addSearchResult(searchResult);
  8529. },
  8530. _onSearchFinished: function(searchId, finished)
  8531. {
  8532. if (searchId !== this._searchId)
  8533. return;
  8534. if (!this._searchResultsPane)
  8535. this._searchView.nothingFound();
  8536. this._searchView.searchFinished(finished);
  8537. },
  8538. startSearch: function(searchConfig)
  8539. {
  8540. this.resetSearch();
  8541. ++this._searchId;
  8542. this._searchConfig = searchConfig;
  8543. this._currentSearchScope = this._searchScope;
  8544. var totalSearchResultsCount = this._currentSearchScope.performSearch(searchConfig, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId));
  8545. this._searchView.searchStarted(totalSearchResultsCount);
  8546. },
  8547. resetSearch: function()
  8548. {
  8549. this.stopSearch();
  8550. if (this._searchResultsPane) {
  8551. this._searchView.resetResults();
  8552. delete this._searchResultsPane;
  8553. }
  8554. },
  8555. stopSearch: function()
  8556. {
  8557. if (this._currentSearchScope)
  8558. this._currentSearchScope.stopSearch();
  8559. }
  8560. }
  8561. WebInspector.SearchView = function(controller)
  8562. {
  8563. WebInspector.View.call(this);
  8564. this.registerRequiredCSS("textViewer.css");
  8565. this._controller = controller;
  8566. this.element.className = "search-view";
  8567. this._searchPanelElement = this.element.createChild("div");
  8568. this._searchPanelElement.tabIndex = 0;
  8569. this._searchPanelElement.className = "search-panel";
  8570. this._searchPanelElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
  8571. this._searchResultsElement = this.element.createChild("div");
  8572. this._searchResultsElement.className = "search-results";
  8573. this._search = this._searchPanelElement.createChild("input");
  8574. this._search.setAttribute("type", "search");
  8575. this._search.addStyleClass("search-config-search");
  8576. this._search.setAttribute("results", "0");
  8577. this._search.setAttribute("size", 20);
  8578. this._ignoreCaseLabel = this._searchPanelElement.createChild("label");
  8579. this._ignoreCaseLabel.addStyleClass("search-config-label");
  8580. this._ignoreCaseCheckbox = this._ignoreCaseLabel.createChild("input");
  8581. this._ignoreCaseCheckbox.setAttribute("type", "checkbox");
  8582. this._ignoreCaseCheckbox.addStyleClass("search-config-checkbox");
  8583. this._ignoreCaseLabel.appendChild(document.createTextNode(WebInspector.UIString("Ignore case")));
  8584. this._regexLabel = this._searchPanelElement.createChild("label");
  8585. this._regexLabel.addStyleClass("search-config-label");
  8586. this._regexCheckbox = this._regexLabel.createChild("input");
  8587. this._regexCheckbox.setAttribute("type", "checkbox");
  8588. this._regexCheckbox.addStyleClass("search-config-checkbox");
  8589. this._regexLabel.appendChild(document.createTextNode(WebInspector.UIString("Regular expression")));
  8590. this._searchDoneButton = this._searchPanelElement.createChild("button");
  8591. this._searchDoneButton.textContent = WebInspector.UIString("Close");
  8592. this._searchDoneButton.addStyleClass("search-close-button");
  8593. this._searchDoneButton.addEventListener("click", this._closeButtonPressed.bind(this));
  8594. this._searchStatusBarElement = document.createElement("div");
  8595. this._searchStatusBarElement.className = "search-status-bar-item";
  8596. this._searchMessageElement = this._searchStatusBarElement.createChild("div");
  8597. this._searchMessageElement.className = "search-status-bar-message";
  8598. this._searchProgressElement = document.createElement("progress");
  8599. this._searchProgressElement.className = "search-status-bar-progress";
  8600. this._searchStopButtonItem = document.createElement("div");
  8601. this._searchStopButtonItem.className = "search-status-bar-stop-button-item";
  8602. this._searchStopStatusBarButton = new WebInspector.StatusBarButton(WebInspector.UIString("Stop search"), "search-status-bar-stop-button");
  8603. this._searchStopButtonItem.appendChild(this._searchStopStatusBarButton.element);
  8604. this._searchStopStatusBarButton.addEventListener("click", this._searchStopButtonPressed, this);
  8605. this._searchResultsMessageElement = document.createElement("span");
  8606. this._searchResultsMessageElement.className = "search-results-status-bar-message";
  8607. this._load();
  8608. }
  8609. WebInspector.SearchView.maxQueriesCount = 20;
  8610. WebInspector.SearchView.prototype = {
  8611. get statusBarItems()
  8612. {
  8613. return [this._searchStatusBarElement];
  8614. },
  8615. get counterElement()
  8616. {
  8617. return this._searchResultsMessageElement;
  8618. },
  8619. get searchConfig()
  8620. {
  8621. return new WebInspector.SearchConfig(this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
  8622. },
  8623. set resultsPane(resultsPane)
  8624. {
  8625. this.resetResults();
  8626. this._searchResultsElement.appendChild(resultsPane.element);
  8627. },
  8628. searchStarted: function(totalSearchResultsCount)
  8629. {
  8630. this.resetResults();
  8631. this._resetCounters();
  8632. this._totalSearchResultsCount = totalSearchResultsCount;
  8633. this._searchMessageElement.textContent = WebInspector.UIString("Searching...");
  8634. this._searchStatusBarElement.appendChild(this._searchProgressElement);
  8635. this._searchStatusBarElement.appendChild(this._searchStopButtonItem);
  8636. this._updateSearchProgress();
  8637. this._updateSearchResultsMessage();
  8638. if (!this._searchingView)
  8639. this._searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."));
  8640. this._searchingView.show(this._searchResultsElement);
  8641. },
  8642. _updateSearchResultsMessage: function()
  8643. {
  8644. if (this._searchMatchesCount && this._searchResultsCount)
  8645. this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount);
  8646. else
  8647. this._searchResultsMessageElement.textContent = "";
  8648. },
  8649. _updateSearchProgress: function()
  8650. {
  8651. this._searchProgressElement.setAttribute("max", this._totalSearchResultsCount);
  8652. this._searchProgressElement.setAttribute("value", this._searchResultsCount);
  8653. },
  8654. resetResults: function()
  8655. {
  8656. if (this._searchingView)
  8657. this._searchingView.detach();
  8658. if (this._notFoundView)
  8659. this._notFoundView.detach();
  8660. this._searchResultsElement.removeChildren();
  8661. },
  8662. _resetCounters: function()
  8663. {
  8664. this._searchMatchesCount = 0;
  8665. this._searchResultsCount = 0;
  8666. this._nonEmptySearchResultsCount = 0;
  8667. },
  8668. nothingFound: function()
  8669. {
  8670. this.resetResults();
  8671. if (!this._notFoundView)
  8672. this._notFoundView = new WebInspector.EmptyView(WebInspector.UIString("No matches found."));
  8673. this._notFoundView.show(this._searchResultsElement);
  8674. this._searchResultsMessageElement.textContent = WebInspector.UIString("No matches found.");
  8675. },
  8676. addSearchResult: function(searchResult)
  8677. {
  8678. this._searchMatchesCount += searchResult.searchMatches.length;
  8679. this._searchResultsCount++;
  8680. if (searchResult.searchMatches.length)
  8681. this._nonEmptySearchResultsCount++;
  8682. this._updateSearchResultsMessage();
  8683. this._updateSearchProgress();
  8684. },
  8685. searchFinished: function(finished)
  8686. {
  8687. this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted.");
  8688. this._searchStatusBarElement.removeChild(this._searchProgressElement);
  8689. this._searchStatusBarElement.removeChild(this._searchStopButtonItem);
  8690. },
  8691. focus: function()
  8692. {
  8693. WebInspector.setCurrentFocusElement(this._search);
  8694. this._search.select();
  8695. },
  8696. wasShown: function()
  8697. {
  8698. this.focus();
  8699. },
  8700. willHide: function()
  8701. {
  8702. this._controller.stopSearch();
  8703. },
  8704. _onKeyDown: function(event)
  8705. {
  8706. switch (event.keyCode) {
  8707. case WebInspector.KeyboardShortcut.Keys.Enter.code:
  8708. this._onAction();
  8709. break;
  8710. case WebInspector.KeyboardShortcut.Keys.Esc.code:
  8711. this._controller.close();
  8712. event.consume(true);
  8713. break;
  8714. }
  8715. },
  8716. _save: function()
  8717. {
  8718. var searchConfig = new WebInspector.SearchConfig(this.searchConfig.query, this.searchConfig.ignoreCase, this.searchConfig.isRegex);
  8719. WebInspector.settings.advancedSearchConfig.set(searchConfig);
  8720. },
  8721. _load: function()
  8722. {
  8723. var searchConfig = WebInspector.settings.advancedSearchConfig.get();
  8724. this._search.value = searchConfig.query;
  8725. this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase;
  8726. this._regexCheckbox.checked = searchConfig.isRegex;
  8727. },
  8728. _closeButtonPressed: function()
  8729. {
  8730. this._controller.close();
  8731. },
  8732. _searchStopButtonPressed: function()
  8733. {
  8734. this._controller.stopSearch();
  8735. this.focus();
  8736. },
  8737. _onAction: function()
  8738. {
  8739. if (!this.searchConfig.query || !this.searchConfig.query.length)
  8740. return;
  8741. this._save();
  8742. this._controller.startSearch(this.searchConfig);
  8743. }
  8744. }
  8745. WebInspector.SearchView.prototype.__proto__ = WebInspector.View.prototype;
  8746. WebInspector.SearchConfig = function(query, ignoreCase, isRegex)
  8747. {
  8748. this.query = query;
  8749. this.ignoreCase = ignoreCase;
  8750. this.isRegex = isRegex;
  8751. }
  8752. WebInspector.SearchScope = function()
  8753. {
  8754. }
  8755. WebInspector.SearchScope.prototype = {
  8756. performSearch: function(searchConfig, searchResultCallback, searchFinishedCallback) { },
  8757. stopSearch: function() { },
  8758. createSearchResultsPane: function(searchConfig) { }
  8759. }
  8760. WebInspector.SearchResult = function(offset, length)
  8761. {
  8762. this.offset = offset;
  8763. this.length = length;
  8764. }
  8765. WebInspector.SearchResultsPane = function(searchConfig)
  8766. {
  8767. this._searchConfig = searchConfig;
  8768. this.element = document.createElement("div");
  8769. }
  8770. WebInspector.SearchResultsPane.prototype = {
  8771. get searchConfig()
  8772. {
  8773. return this._searchConfig;
  8774. },
  8775. addSearchResult: function(searchResult) { }
  8776. }
  8777. WebInspector.FileBasedSearchResultsPane = function(searchConfig)
  8778. {
  8779. WebInspector.SearchResultsPane.call(this, searchConfig);
  8780. this._searchResults = [];
  8781. this.element.id ="search-results-pane-file-based";
  8782. this._treeOutlineElement = document.createElement("ol");
  8783. this._treeOutlineElement.className = "outline-disclosure";
  8784. this._treeOutlineElement.addStyleClass("search-results-outline-disclosure");
  8785. this.element.appendChild(this._treeOutlineElement);
  8786. this._treeOutline = new TreeOutline(this._treeOutlineElement);
  8787. this._matchesExpandedCount = 0;
  8788. }
  8789. WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20;
  8790. WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20;
  8791. WebInspector.FileBasedSearchResultsPane.prototype = {
  8792. _createAnchor: function(uiSourceCode, lineNumber, columnNumber)
  8793. {
  8794. var anchor = document.createElement("a");
  8795. anchor.preferredPanel = "scripts";
  8796. anchor.href = uiSourceCode.url;
  8797. anchor.uiSourceCode = uiSourceCode;
  8798. anchor.lineNumber = lineNumber;
  8799. return anchor;
  8800. },
  8801. addSearchResult: function(searchResult)
  8802. {
  8803. this._searchResults.push(searchResult);
  8804. var uiSourceCode = searchResult.uiSourceCode;
  8805. var searchMatches = searchResult.searchMatches;
  8806. var fileTreeElement = this._addFileTreeElement(uiSourceCode.url, searchMatches.length, this._searchResults.length - 1);
  8807. },
  8808. _fileTreeElementExpanded: function(searchResult, fileTreeElement)
  8809. {
  8810. if (fileTreeElement._initialized)
  8811. return;
  8812. var toIndex = Math.min(searchResult.searchMatches.length, WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce);
  8813. if (toIndex < searchResult.searchMatches.length) {
  8814. this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex - 1);
  8815. this._appendShowMoreMatchesElement(fileTreeElement, searchResult, toIndex - 1);
  8816. } else
  8817. this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex);
  8818. fileTreeElement._initialized = true;
  8819. },
  8820. _appendSearchMatches: function(fileTreeElement, searchResult, fromIndex, toIndex)
  8821. {
  8822. var uiSourceCode = searchResult.uiSourceCode;
  8823. var searchMatches = searchResult.searchMatches;
  8824. var regex = createSearchRegex(this._searchConfig.query, !this._searchConfig.ignoreCase, this._searchConfig.isRegex);
  8825. for (var i = fromIndex; i < toIndex; ++i) {
  8826. var lineNumber = searchMatches[i].lineNumber;
  8827. var lineContent = searchMatches[i].lineContent;
  8828. var matchRanges = this._regexMatchRanges(lineContent, regex);
  8829. var anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset);
  8830. var numberString = numberToStringWithSpacesPadding(lineNumber + 1, 4);
  8831. var lineNumberSpan = document.createElement("span");
  8832. lineNumberSpan.addStyleClass("webkit-line-number");
  8833. lineNumberSpan.addStyleClass("search-match-line-number");
  8834. lineNumberSpan.textContent = numberString;
  8835. anchor.appendChild(lineNumberSpan);
  8836. var contentSpan = this._createContentSpan(lineContent, matchRanges);
  8837. anchor.appendChild(contentSpan);
  8838. var searchMatchElement = new TreeElement("", null, false);
  8839. fileTreeElement.appendChild(searchMatchElement);
  8840. searchMatchElement.listItemElement.className = "search-match";
  8841. searchMatchElement.listItemElement.appendChild(anchor);
  8842. }
  8843. },
  8844. _appendShowMoreMatchesElement: function(fileTreeElement, searchResult, startMatchIndex)
  8845. {
  8846. var matchesLeftCount = searchResult.searchMatches.length - startMatchIndex;
  8847. var showMoreMatchesText = WebInspector.UIString("Show all matches (%d more).", matchesLeftCount);
  8848. var showMoreMatchesElement = new TreeElement(showMoreMatchesText, null, false);
  8849. fileTreeElement.appendChild(showMoreMatchesElement);
  8850. showMoreMatchesElement.listItemElement.addStyleClass("show-more-matches");
  8851. showMoreMatchesElement.onselect = this._showMoreMatchesElementSelected.bind(this, searchResult, startMatchIndex);
  8852. },
  8853. _showMoreMatchesElementSelected: function(searchResult, startMatchIndex, showMoreMatchesElement)
  8854. {
  8855. var fileTreeElement = showMoreMatchesElement.parent;
  8856. fileTreeElement.removeChild(showMoreMatchesElement);
  8857. this._appendSearchMatches(fileTreeElement, searchResult, startMatchIndex, searchResult.searchMatches.length);
  8858. },
  8859. _addFileTreeElement: function(fileName, searchMatchesCount, searchResultIndex)
  8860. {
  8861. var fileTreeElement = new TreeElement("", null, true);
  8862. fileTreeElement.toggleOnClick = true;
  8863. fileTreeElement.selectable = false;
  8864. this._treeOutline.appendChild(fileTreeElement);
  8865. fileTreeElement.listItemElement.addStyleClass("search-result");
  8866. var fileNameSpan = document.createElement("span");
  8867. fileNameSpan.className = "search-result-file-name";
  8868. fileNameSpan.textContent = fileName;
  8869. fileTreeElement.listItemElement.appendChild(fileNameSpan);
  8870. var matchesCountSpan = document.createElement("span");
  8871. matchesCountSpan.className = "search-result-matches-count";
  8872. if (searchMatchesCount === 1)
  8873. matchesCountSpan.textContent = WebInspector.UIString("(%d match)", searchMatchesCount);
  8874. else
  8875. matchesCountSpan.textContent = WebInspector.UIString("(%d matches)", searchMatchesCount);
  8876. fileTreeElement.listItemElement.appendChild(matchesCountSpan);
  8877. var searchResult = this._searchResults[searchResultIndex];
  8878. fileTreeElement.onexpand = this._fileTreeElementExpanded.bind(this, searchResult);
  8879. if (this._matchesExpandedCount < WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount)
  8880. fileTreeElement.expand();
  8881. this._matchesExpandedCount += searchResult.searchMatches.length;
  8882. return fileTreeElement;
  8883. },
  8884. _regexMatchRanges: function(lineContent, regex)
  8885. {
  8886. regex.lastIndex = 0;
  8887. var match;
  8888. var offset = 0;
  8889. var matchRanges = [];
  8890. while ((regex.lastIndex < lineContent.length) && (match = regex.exec(lineContent)))
  8891. matchRanges.push(new WebInspector.SearchResult(match.index, match[0].length));
  8892. return matchRanges;
  8893. },
  8894. _createContentSpan: function(lineContent, matchRanges)
  8895. {
  8896. var contentSpan = document.createElement("span");
  8897. contentSpan.className = "search-match-content";
  8898. contentSpan.textContent = lineContent;
  8899. WebInspector.highlightRangesWithStyleClass(contentSpan, matchRanges, "highlighted-match");
  8900. return contentSpan;
  8901. }
  8902. }
  8903. WebInspector.FileBasedSearchResultsPane.prototype.__proto__ = WebInspector.SearchResultsPane.prototype;
  8904. WebInspector.FileBasedSearchResultsPane.SearchResult = function(uiSourceCode, searchMatches) {
  8905. this.uiSourceCode = uiSourceCode;
  8906. this.searchMatches = searchMatches;
  8907. }
  8908. WebInspector.advancedSearchController = null;
  8909. WebInspector.TimelineGrid = function()
  8910. {
  8911. this.element = document.createElement("div");
  8912. this._itemsGraphsElement = document.createElement("div");
  8913. this._itemsGraphsElement.id = "resources-graphs";
  8914. this.element.appendChild(this._itemsGraphsElement);
  8915. this._dividersElement = document.createElement("div");
  8916. this._dividersElement.className = "resources-dividers";
  8917. this.element.appendChild(this._dividersElement);
  8918. this._eventDividersElement = document.createElement("div");
  8919. this._eventDividersElement.className = "resources-event-dividers";
  8920. this.element.appendChild(this._eventDividersElement);
  8921. this._dividersLabelBarElement = document.createElement("div");
  8922. this._dividersLabelBarElement.className = "resources-dividers-label-bar";
  8923. this.element.appendChild(this._dividersLabelBarElement);
  8924. }
  8925. WebInspector.TimelineGrid.prototype = {
  8926. get itemsGraphsElement()
  8927. {
  8928. return this._itemsGraphsElement;
  8929. },
  8930. get dividersElement()
  8931. {
  8932. return this._dividersElement;
  8933. },
  8934. removeDividers: function()
  8935. {
  8936. this._dividersElement.removeChildren();
  8937. this._dividersLabelBarElement.removeChildren();
  8938. },
  8939. updateDividers: function(calculator)
  8940. {
  8941. var dividersElementClientWidth = this._dividersElement.clientWidth;
  8942. var dividerCount = Math.round(dividersElementClientWidth / 64);
  8943. var slice = calculator.boundarySpan / dividerCount;
  8944. this._currentDividerSlice = slice;
  8945. var divider = this._dividersElement.firstChild;
  8946. var dividerLabelBar = this._dividersLabelBarElement.firstChild;
  8947. var paddingLeft = calculator.paddingLeft;
  8948. for (var i = paddingLeft ? 0 : 1; i <= dividerCount; ++i) {
  8949. if (!divider) {
  8950. divider = document.createElement("div");
  8951. divider.className = "resources-divider";
  8952. this._dividersElement.appendChild(divider);
  8953. dividerLabelBar = document.createElement("div");
  8954. dividerLabelBar.className = "resources-divider";
  8955. var label = document.createElement("div");
  8956. label.className = "resources-divider-label";
  8957. dividerLabelBar._labelElement = label;
  8958. dividerLabelBar.appendChild(label);
  8959. this._dividersLabelBarElement.appendChild(dividerLabelBar);
  8960. }
  8961. if (i === (paddingLeft ? 0 : 1)) {
  8962. divider.addStyleClass("first");
  8963. dividerLabelBar.addStyleClass("first");
  8964. } else {
  8965. divider.removeStyleClass("first");
  8966. dividerLabelBar.removeStyleClass("first");
  8967. }
  8968. if (i === dividerCount) {
  8969. divider.addStyleClass("last");
  8970. dividerLabelBar.addStyleClass("last");
  8971. } else {
  8972. divider.removeStyleClass("last");
  8973. dividerLabelBar.removeStyleClass("last");
  8974. }
  8975. var left;
  8976. if (!slice) {
  8977. left = dividersElementClientWidth / dividerCount * i + paddingLeft;
  8978. dividerLabelBar._labelElement.textContent = "";
  8979. } else {
  8980. left = calculator.computePosition(calculator.minimumBoundary + slice * i);
  8981. dividerLabelBar._labelElement.textContent = calculator.formatTime(slice * i);
  8982. }
  8983. var percentLeft = 100 * left / dividersElementClientWidth;
  8984. this._setDividerAndBarLeft(divider, dividerLabelBar, percentLeft);
  8985. divider = divider.nextSibling;
  8986. dividerLabelBar = dividerLabelBar.nextSibling;
  8987. }
  8988. while (divider) {
  8989. var nextDivider = divider.nextSibling;
  8990. this._dividersElement.removeChild(divider);
  8991. divider = nextDivider;
  8992. }
  8993. while (dividerLabelBar) {
  8994. var nextDivider = dividerLabelBar.nextSibling;
  8995. this._dividersLabelBarElement.removeChild(dividerLabelBar);
  8996. dividerLabelBar = nextDivider;
  8997. }
  8998. return true;
  8999. },
  9000. _setDividerAndBarLeft: function(divider, dividerLabelBar, percentLeft)
  9001. {
  9002. var percentStyleLeft = parseFloat(divider.style.left);
  9003. if (!isNaN(percentStyleLeft) && Math.abs(percentStyleLeft - percentLeft) < 0.1)
  9004. return;
  9005. divider.style.left = percentLeft + "%";
  9006. dividerLabelBar.style.left = percentLeft + "%";
  9007. },
  9008. addEventDivider: function(divider)
  9009. {
  9010. this._eventDividersElement.appendChild(divider);
  9011. },
  9012. addEventDividers: function(dividers)
  9013. {
  9014. this.element.removeChild(this._eventDividersElement);
  9015. for (var i = 0; i < dividers.length; ++i) {
  9016. if (dividers[i])
  9017. this._eventDividersElement.appendChild(dividers[i]);
  9018. }
  9019. this.element.appendChild(this._eventDividersElement);
  9020. },
  9021. removeEventDividers: function()
  9022. {
  9023. this._eventDividersElement.removeChildren();
  9024. },
  9025. hideEventDividers: function()
  9026. {
  9027. this._eventDividersElement.addStyleClass("hidden");
  9028. },
  9029. showEventDividers: function()
  9030. {
  9031. this._eventDividersElement.removeStyleClass("hidden");
  9032. },
  9033. setScrollAndDividerTop: function(scrollTop, dividersTop)
  9034. {
  9035. this._dividersElement.style.top = scrollTop + "px";
  9036. this._eventDividersElement.style.top = scrollTop + "px";
  9037. this._dividersLabelBarElement.style.top = dividersTop + "px";
  9038. }
  9039. }
  9040. WebInspector.ContentProvider = function() { }
  9041. WebInspector.ContentProvider.prototype = {
  9042. contentURL: function() { },
  9043. contentType: function() { },
  9044. requestContent: function(callback) { },
  9045. searchInContent: function(query, caseSensitive, isRegex, callback) { }
  9046. }
  9047. WebInspector.ContentProvider.SearchMatch = function(lineNumber, lineContent) {
  9048. this.lineNumber = lineNumber;
  9049. this.lineContent = lineContent;
  9050. }
  9051. WebInspector.Resource = function(request, url, documentURL, frameId, loaderId, type, mimeType)
  9052. {
  9053. this._request = request;
  9054. if (this._request)
  9055. this._request.setResource(this);
  9056. this.url = url;
  9057. this._documentURL = documentURL;
  9058. this._frameId = frameId;
  9059. this._loaderId = loaderId;
  9060. this._type = type || WebInspector.resourceTypes.Other;
  9061. this._mimeType = mimeType;
  9062. this.history = [];
  9063. this._content;
  9064. this._contentEncoded;
  9065. this._pendingContentCallbacks = [];
  9066. }
  9067. WebInspector.Resource._domainModelBindings = [];
  9068. WebInspector.Resource.registerDomainModelBinding = function(type, binding)
  9069. {
  9070. WebInspector.Resource._domainModelBindings[type.name()] = binding;
  9071. }
  9072. WebInspector.Resource._resourceRevisionRegistry = function()
  9073. {
  9074. if (!WebInspector.Resource._resourceRevisionRegistryObject) {
  9075. if (window.localStorage) {
  9076. var resourceHistory = window.localStorage["resource-history"];
  9077. try {
  9078. WebInspector.Resource._resourceRevisionRegistryObject = resourceHistory ? JSON.parse(resourceHistory) : {};
  9079. } catch (e) {
  9080. WebInspector.Resource._resourceRevisionRegistryObject = {};
  9081. }
  9082. } else
  9083. WebInspector.Resource._resourceRevisionRegistryObject = {};
  9084. }
  9085. return WebInspector.Resource._resourceRevisionRegistryObject;
  9086. }
  9087. WebInspector.Resource.restoreRevisions = function()
  9088. {
  9089. var registry = WebInspector.Resource._resourceRevisionRegistry();
  9090. var filteredRegistry = {};
  9091. for (var url in registry) {
  9092. var historyItems = registry[url];
  9093. var resource = WebInspector.resourceForURL(url);
  9094. var filteredHistoryItems = [];
  9095. for (var i = 0; historyItems && i < historyItems.length; ++i) {
  9096. var historyItem = historyItems[i];
  9097. if (resource && historyItem.loaderId === resource.loaderId) {
  9098. resource.addRevision(window.localStorage[historyItem.key], new Date(historyItem.timestamp), true);
  9099. filteredHistoryItems.push(historyItem);
  9100. filteredRegistry[url] = filteredHistoryItems;
  9101. } else
  9102. delete window.localStorage[historyItem.key];
  9103. }
  9104. }
  9105. WebInspector.Resource._resourceRevisionRegistryObject = filteredRegistry;
  9106. function persist()
  9107. {
  9108. window.localStorage["resource-history"] = JSON.stringify(filteredRegistry);
  9109. }
  9110. setTimeout(persist, 0);
  9111. }
  9112. WebInspector.Resource.persistRevision = function(resource)
  9113. {
  9114. if (!window.localStorage)
  9115. return;
  9116. var url = resource.url;
  9117. var loaderId = resource.loaderId;
  9118. var timestamp = resource._contentTimestamp.getTime();
  9119. var key = "resource-history|" + url + "|" + loaderId + "|" + timestamp;
  9120. var content = resource._content;
  9121. var registry = WebInspector.Resource._resourceRevisionRegistry();
  9122. var historyItems = registry[resource.url];
  9123. if (!historyItems) {
  9124. historyItems = [];
  9125. registry[resource.url] = historyItems;
  9126. }
  9127. historyItems.push({url: url, loaderId: loaderId, timestamp: timestamp, key: key});
  9128. function persist()
  9129. {
  9130. window.localStorage[key] = content;
  9131. window.localStorage["resource-history"] = JSON.stringify(registry);
  9132. }
  9133. setTimeout(persist, 0);
  9134. }
  9135. WebInspector.Resource.Events = {
  9136. RevisionAdded: "revision-added",
  9137. MessageAdded: "message-added",
  9138. MessagesCleared: "messages-cleared",
  9139. }
  9140. WebInspector.Resource.prototype = {
  9141. get request()
  9142. {
  9143. return this._request;
  9144. },
  9145. get url()
  9146. {
  9147. return this._url;
  9148. },
  9149. set url(x)
  9150. {
  9151. this._url = x;
  9152. this._parsedURL = new WebInspector.ParsedURL(x);
  9153. },
  9154. get parsedURL()
  9155. {
  9156. return this._parsedURL;
  9157. },
  9158. get documentURL()
  9159. {
  9160. return this._documentURL;
  9161. },
  9162. get frameId()
  9163. {
  9164. return this._frameId;
  9165. },
  9166. get loaderId()
  9167. {
  9168. return this._loaderId;
  9169. },
  9170. get displayName()
  9171. {
  9172. return this._parsedURL.displayName;
  9173. },
  9174. get type()
  9175. {
  9176. return this._request ? this._request.type : this._type;
  9177. },
  9178. get mimeType()
  9179. {
  9180. return this._request ? this._request.mimeType : this._mimeType;
  9181. },
  9182. get messages()
  9183. {
  9184. return this._messages || [];
  9185. },
  9186. addMessage: function(msg)
  9187. {
  9188. if (!msg.isErrorOrWarning() || !msg.message)
  9189. return;
  9190. if (!this._messages)
  9191. this._messages = [];
  9192. this._messages.push(msg);
  9193. this.dispatchEventToListeners(WebInspector.Resource.Events.MessageAdded, msg);
  9194. },
  9195. get errors()
  9196. {
  9197. return this._errors || 0;
  9198. },
  9199. set errors(x)
  9200. {
  9201. this._errors = x;
  9202. },
  9203. get warnings()
  9204. {
  9205. return this._warnings || 0;
  9206. },
  9207. set warnings(x)
  9208. {
  9209. this._warnings = x;
  9210. },
  9211. clearErrorsAndWarnings: function()
  9212. {
  9213. this._messages = [];
  9214. this._warnings = 0;
  9215. this._errors = 0;
  9216. this.dispatchEventToListeners(WebInspector.Resource.Events.MessagesCleared);
  9217. },
  9218. get content()
  9219. {
  9220. return this._content;
  9221. },
  9222. get contentEncoded()
  9223. {
  9224. return this._contentEncoded;
  9225. },
  9226. get contentTimestamp()
  9227. {
  9228. return this._contentTimestamp;
  9229. },
  9230. isEditable: function()
  9231. {
  9232. if (this._actualResource)
  9233. return false;
  9234. var binding = WebInspector.Resource._domainModelBindings[this.type.name()];
  9235. return binding && binding.canSetContent(this);
  9236. },
  9237. setContent: function(newContent, majorChange, callback)
  9238. {
  9239. if (!this.isEditable()) {
  9240. if (callback)
  9241. callback("Resource is not editable");
  9242. return;
  9243. }
  9244. var binding = WebInspector.Resource._domainModelBindings[this.type.name()];
  9245. binding.setContent(this, newContent, majorChange, callback);
  9246. },
  9247. addRevision: function(newContent, timestamp, restoringHistory)
  9248. {
  9249. var revision = new WebInspector.ResourceRevision(this, this._content, this._contentTimestamp);
  9250. this.history.push(revision);
  9251. this._content = newContent;
  9252. this._contentTimestamp = timestamp || new Date();
  9253. this.dispatchEventToListeners(WebInspector.Resource.Events.RevisionAdded, revision);
  9254. if (!restoringHistory)
  9255. this._persistRevision();
  9256. WebInspector.resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceContentCommitted, { resource: this, content: newContent });
  9257. },
  9258. _persistRevision: function()
  9259. {
  9260. WebInspector.Resource.persistRevision(this);
  9261. },
  9262. contentURL: function()
  9263. {
  9264. return this._url;
  9265. },
  9266. contentType: function()
  9267. {
  9268. return this.type;
  9269. },
  9270. requestContent: function(callback)
  9271. {
  9272. if (typeof this._content !== "undefined") {
  9273. callback(this._content, !!this._contentEncoded, this.canonicalMimeType());
  9274. return;
  9275. }
  9276. this._pendingContentCallbacks.push(callback);
  9277. this._innerRequestContent();
  9278. },
  9279. canonicalMimeType: function()
  9280. {
  9281. return this.type.canonicalMimeType() || this.mimeType;
  9282. },
  9283. searchInContent: function(query, caseSensitive, isRegex, callback)
  9284. {
  9285. function callbackWrapper(error, searchMatches)
  9286. {
  9287. callback(searchMatches || []);
  9288. }
  9289. if (this.frameId)
  9290. PageAgent.searchInResource(this.frameId, this.url, query, caseSensitive, isRegex, callbackWrapper);
  9291. else
  9292. callback([]);
  9293. },
  9294. populateImageSource: function(image)
  9295. {
  9296. function onResourceContent()
  9297. {
  9298. image.src = this._contentURL();
  9299. }
  9300. this.requestContent(onResourceContent.bind(this));
  9301. },
  9302. _contentURL: function()
  9303. {
  9304. const maxDataUrlSize = 1024 * 1024;
  9305. if (this._content == null || this._content.length > maxDataUrlSize)
  9306. return this.url;
  9307. return "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content;
  9308. },
  9309. _innerRequestContent: function()
  9310. {
  9311. if (this._contentRequested)
  9312. return;
  9313. this._contentRequested = true;
  9314. function callback(error, content, contentEncoded)
  9315. {
  9316. this._content = error ? null : content;
  9317. this._contentEncoded = contentEncoded;
  9318. this._originalContent = content;
  9319. var callbacks = this._pendingContentCallbacks.slice();
  9320. for (var i = 0; i < callbacks.length; ++i)
  9321. callbacks[i](this._content, this._contentEncoded, this.canonicalMimeType());
  9322. this._pendingContentCallbacks.length = 0;
  9323. delete this._contentRequested;
  9324. }
  9325. PageAgent.getResourceContent(this.frameId, this.url, callback.bind(this));
  9326. }
  9327. }
  9328. WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
  9329. WebInspector.ResourceRevision = function(resource, content, timestamp)
  9330. {
  9331. this._resource = resource;
  9332. this._content = content;
  9333. this._timestamp = timestamp;
  9334. }
  9335. WebInspector.ResourceRevision.prototype = {
  9336. get resource()
  9337. {
  9338. return this._resource;
  9339. },
  9340. get timestamp()
  9341. {
  9342. return this._timestamp;
  9343. },
  9344. get content()
  9345. {
  9346. return this._content || null;
  9347. },
  9348. revertToThis: function()
  9349. {
  9350. function revert(content)
  9351. {
  9352. this._resource.setContent(content, true);
  9353. }
  9354. this.requestContent(revert.bind(this));
  9355. },
  9356. contentURL: function()
  9357. {
  9358. return this._resource.url;
  9359. },
  9360. contentType: function()
  9361. {
  9362. return this._resource.contentType();
  9363. },
  9364. requestContent: function(callback)
  9365. {
  9366. if (typeof this._content === "string") {
  9367. callback(this._content, false, this.resource.mimeType);
  9368. return;
  9369. }
  9370. if (typeof this.resource._originalContent === "string") {
  9371. this._content = this._resource._originalContent;
  9372. callback(this._content, false, this.resource.mimeType);
  9373. return;
  9374. }
  9375. function callbackWrapper(error, content, contentEncoded)
  9376. {
  9377. callback(error ? null : content, contentEncoded, this.resource.mimeType);
  9378. }
  9379. PageAgent.getResourceContent(this._resource.frameId, this._resource.url, callbackWrapper.bind(this));
  9380. },
  9381. searchInContent: function(query, caseSensitive, isRegex, callback)
  9382. {
  9383. callback([]);
  9384. }
  9385. }
  9386. WebInspector.ResourceDomainModelBinding = function() { }
  9387. WebInspector.ResourceDomainModelBinding.prototype = {
  9388. canSetContent: function(resource) { return true; },
  9389. setContent: function(resource, content, majorChange, callback) { }
  9390. }
  9391. WebInspector.NetworkRequest = function(requestId, url, documentURL, frameId, loaderId)
  9392. {
  9393. this._requestId = requestId;
  9394. this.url = url;
  9395. this._documentURL = documentURL;
  9396. this._frameId = frameId;
  9397. this._loaderId = loaderId;
  9398. this._startTime = -1;
  9399. this._endTime = -1;
  9400. this.statusCode = 0;
  9401. this.statusText = "";
  9402. this.requestMethod = "";
  9403. this.requestTime = 0;
  9404. this.receiveHeadersEnd = 0;
  9405. this._type = WebInspector.resourceTypes.Other;
  9406. this._content = undefined;
  9407. this._contentEncoded = false;
  9408. this._pendingContentCallbacks = [];
  9409. this._frames = [];
  9410. }
  9411. WebInspector.NetworkRequest.Events = {
  9412. FinishedLoading: "FinishedLoading",
  9413. TimingChanged: "TimingChanged",
  9414. RequestHeadersChanged: "RequestHeadersChanged",
  9415. ResponseHeadersChanged: "ResponseHeadersChanged",
  9416. }
  9417. WebInspector.NetworkRequest.prototype = {
  9418. get requestId()
  9419. {
  9420. return this._requestId;
  9421. },
  9422. set requestId(requestId)
  9423. {
  9424. this._requestId = requestId;
  9425. },
  9426. get url()
  9427. {
  9428. return this._url;
  9429. },
  9430. set url(x)
  9431. {
  9432. if (this._url === x)
  9433. return;
  9434. this._url = x;
  9435. this._parsedURL = new WebInspector.ParsedURL(x);
  9436. delete this._parsedQueryParameters;
  9437. },
  9438. get documentURL()
  9439. {
  9440. return this._documentURL;
  9441. },
  9442. get parsedURL()
  9443. {
  9444. return this._parsedURL;
  9445. },
  9446. get frameId()
  9447. {
  9448. return this._frameId;
  9449. },
  9450. get loaderId()
  9451. {
  9452. return this._loaderId;
  9453. },
  9454. get startTime()
  9455. {
  9456. return this._startTime || -1;
  9457. },
  9458. set startTime(x)
  9459. {
  9460. this._startTime = x;
  9461. },
  9462. get responseReceivedTime()
  9463. {
  9464. return this._responseReceivedTime || -1;
  9465. },
  9466. set responseReceivedTime(x)
  9467. {
  9468. this._responseReceivedTime = x;
  9469. },
  9470. get endTime()
  9471. {
  9472. return this._endTime || -1;
  9473. },
  9474. set endTime(x)
  9475. {
  9476. if (this.timing && this.timing.requestTime) {
  9477. this._endTime = Math.max(x, this.responseReceivedTime);
  9478. } else {
  9479. this._endTime = x;
  9480. if (this._responseReceivedTime > x)
  9481. this._responseReceivedTime = x;
  9482. }
  9483. },
  9484. get duration()
  9485. {
  9486. if (this._endTime === -1 || this._startTime === -1)
  9487. return -1;
  9488. return this._endTime - this._startTime;
  9489. },
  9490. get latency()
  9491. {
  9492. if (this._responseReceivedTime === -1 || this._startTime === -1)
  9493. return -1;
  9494. return this._responseReceivedTime - this._startTime;
  9495. },
  9496. get receiveDuration()
  9497. {
  9498. if (this._endTime === -1 || this._responseReceivedTime === -1)
  9499. return -1;
  9500. return this._endTime - this._responseReceivedTime;
  9501. },
  9502. get resourceSize()
  9503. {
  9504. return this._resourceSize || 0;
  9505. },
  9506. set resourceSize(x)
  9507. {
  9508. this._resourceSize = x;
  9509. },
  9510. get transferSize()
  9511. {
  9512. if (this.cached)
  9513. return 0;
  9514. if (this.statusCode === 304)
  9515. return this.responseHeadersSize;
  9516. if (this._transferSize !== undefined)
  9517. return this._transferSize;
  9518. var bodySize = Number(this.responseHeaderValue("Content-Length") || this.resourceSize);
  9519. return this.responseHeadersSize + bodySize;
  9520. },
  9521. increaseTransferSize: function(x)
  9522. {
  9523. this._transferSize = (this._transferSize || 0) + x;
  9524. },
  9525. get finished()
  9526. {
  9527. return this._finished;
  9528. },
  9529. set finished(x)
  9530. {
  9531. if (this._finished === x)
  9532. return;
  9533. this._finished = x;
  9534. if (x) {
  9535. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading, this);
  9536. if (this._pendingContentCallbacks.length)
  9537. this._innerRequestContent();
  9538. }
  9539. },
  9540. get failed()
  9541. {
  9542. return this._failed;
  9543. },
  9544. set failed(x)
  9545. {
  9546. this._failed = x;
  9547. },
  9548. get canceled()
  9549. {
  9550. return this._canceled;
  9551. },
  9552. set canceled(x)
  9553. {
  9554. this._canceled = x;
  9555. },
  9556. get cached()
  9557. {
  9558. return this._cached;
  9559. },
  9560. set cached(x)
  9561. {
  9562. this._cached = x;
  9563. if (x)
  9564. delete this._timing;
  9565. },
  9566. get timing()
  9567. {
  9568. return this._timing;
  9569. },
  9570. set timing(x)
  9571. {
  9572. if (x && !this._cached) {
  9573. this._startTime = x.requestTime;
  9574. this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0;
  9575. this._timing = x;
  9576. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this);
  9577. }
  9578. },
  9579. get mimeType()
  9580. {
  9581. return this._mimeType;
  9582. },
  9583. set mimeType(x)
  9584. {
  9585. this._mimeType = x;
  9586. },
  9587. get displayName()
  9588. {
  9589. return this._parsedURL.displayName;
  9590. },
  9591. get folder()
  9592. {
  9593. var path = this._parsedURL.path;
  9594. var indexOfQuery = path.indexOf("?");
  9595. if (indexOfQuery !== -1)
  9596. path = path.substring(0, indexOfQuery);
  9597. var lastSlashIndex = path.lastIndexOf("/");
  9598. return lastSlashIndex !== -1 ? path.substring(0, lastSlashIndex) : "";
  9599. },
  9600. get type()
  9601. {
  9602. return this._type;
  9603. },
  9604. set type(x)
  9605. {
  9606. this._type = x;
  9607. },
  9608. get redirectSource()
  9609. {
  9610. if (this.redirects && this.redirects.length > 0)
  9611. return this.redirects[this.redirects.length - 1];
  9612. return this._redirectSource;
  9613. },
  9614. set redirectSource(x)
  9615. {
  9616. this._redirectSource = x;
  9617. },
  9618. get requestHeaders()
  9619. {
  9620. return this._requestHeaders || [];
  9621. },
  9622. set requestHeaders(x)
  9623. {
  9624. this._requestHeaders = x;
  9625. delete this._sortedRequestHeaders;
  9626. delete this._requestCookies;
  9627. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
  9628. },
  9629. get requestHeadersText()
  9630. {
  9631. if (this._requestHeadersText === undefined) {
  9632. this._requestHeadersText = this.requestMethod + " " + this.url + " HTTP/1.1\r\n";
  9633. for (var i = 0; i < this.requestHeaders; ++i)
  9634. this._requestHeadersText += this.requestHeaders[i].name + ": " + this.requestHeaders[i].value + "\r\n";
  9635. }
  9636. return this._requestHeadersText;
  9637. },
  9638. set requestHeadersText(x)
  9639. {
  9640. this._requestHeadersText = x;
  9641. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged);
  9642. },
  9643. get requestHeadersSize()
  9644. {
  9645. return this.requestHeadersText.length;
  9646. },
  9647. get sortedRequestHeaders()
  9648. {
  9649. if (this._sortedRequestHeaders !== undefined)
  9650. return this._sortedRequestHeaders;
  9651. this._sortedRequestHeaders = [];
  9652. this._sortedRequestHeaders = this.requestHeaders.slice();
  9653. this._sortedRequestHeaders.sort(function(a,b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) });
  9654. return this._sortedRequestHeaders;
  9655. },
  9656. requestHeaderValue: function(headerName)
  9657. {
  9658. return this._headerValue(this.requestHeaders, headerName);
  9659. },
  9660. get requestCookies()
  9661. {
  9662. if (!this._requestCookies)
  9663. this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie"));
  9664. return this._requestCookies;
  9665. },
  9666. get requestFormData()
  9667. {
  9668. return this._requestFormData;
  9669. },
  9670. set requestFormData(x)
  9671. {
  9672. this._requestFormData = x;
  9673. delete this._parsedFormParameters;
  9674. },
  9675. get requestHttpVersion()
  9676. {
  9677. var firstLine = this.requestHeadersText.split(/\r\n/)[0];
  9678. var match = firstLine.match(/(HTTP\/\d+\.\d+)$/);
  9679. return match ? match[1] : undefined;
  9680. },
  9681. get responseHeaders()
  9682. {
  9683. return this._responseHeaders || [];
  9684. },
  9685. set responseHeaders(x)
  9686. {
  9687. this._responseHeaders = x;
  9688. delete this._sortedResponseHeaders;
  9689. delete this._responseCookies;
  9690. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
  9691. },
  9692. get responseHeadersText()
  9693. {
  9694. if (this._responseHeadersText === undefined) {
  9695. this._responseHeadersText = "HTTP/1.1 " + this.statusCode + " " + this.statusText + "\r\n";
  9696. for (var i = 0; i < this.requestHeaders; ++i)
  9697. this._responseHeadersText += this.responseHeaders[i].name + ": " + this.responseHeaders[i].value + "\r\n";
  9698. }
  9699. return this._responseHeadersText;
  9700. },
  9701. set responseHeadersText(x)
  9702. {
  9703. this._responseHeadersText = x;
  9704. this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged);
  9705. },
  9706. get responseHeadersSize()
  9707. {
  9708. return this.responseHeadersText.length;
  9709. },
  9710. get sortedResponseHeaders()
  9711. {
  9712. if (this._sortedResponseHeaders !== undefined)
  9713. return this._sortedResponseHeaders;
  9714. this._sortedResponseHeaders = [];
  9715. this._sortedResponseHeaders = this.responseHeaders.slice();
  9716. this._sortedResponseHeaders.sort(function(a,b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) });
  9717. return this._sortedResponseHeaders;
  9718. },
  9719. responseHeaderValue: function(headerName)
  9720. {
  9721. return this._headerValue(this.responseHeaders, headerName);
  9722. },
  9723. get responseCookies()
  9724. {
  9725. if (!this._responseCookies)
  9726. this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie"));
  9727. return this._responseCookies;
  9728. },
  9729. get queryParameters()
  9730. {
  9731. if (this._parsedQueryParameters)
  9732. return this._parsedQueryParameters;
  9733. var queryString = this.url.split("?", 2)[1];
  9734. if (!queryString)
  9735. return null;
  9736. queryString = queryString.split("#", 2)[0];
  9737. this._parsedQueryParameters = this._parseParameters(queryString);
  9738. return this._parsedQueryParameters;
  9739. },
  9740. get formParameters()
  9741. {
  9742. if (this._parsedFormParameters)
  9743. return this._parsedFormParameters;
  9744. if (!this.requestFormData)
  9745. return null;
  9746. var requestContentType = this.requestContentType();
  9747. if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i))
  9748. return null;
  9749. this._parsedFormParameters = this._parseParameters(this.requestFormData);
  9750. return this._parsedFormParameters;
  9751. },
  9752. get responseHttpVersion()
  9753. {
  9754. var match = this.responseHeadersText.match(/^(HTTP\/\d+\.\d+)/);
  9755. return match ? match[1] : undefined;
  9756. },
  9757. _parseParameters: function(queryString)
  9758. {
  9759. function parseNameValue(pair)
  9760. {
  9761. var parameter = {};
  9762. var splitPair = pair.split("=", 2);
  9763. parameter.name = splitPair[0];
  9764. if (splitPair.length === 1)
  9765. parameter.value = "";
  9766. else
  9767. parameter.value = splitPair[1];
  9768. return parameter;
  9769. }
  9770. return queryString.split("&").map(parseNameValue);
  9771. },
  9772. _headerValue: function(headers, headerName)
  9773. {
  9774. headerName = headerName.toLowerCase();
  9775. var values = [];
  9776. for (var i = 0; i < headers.length; ++i) {
  9777. if (headers[i].name.toLowerCase() === headerName)
  9778. values.push(headers[i].value);
  9779. }
  9780. if (headerName === "set-cookie")
  9781. return values.join("\n");
  9782. return values.join(", ");
  9783. },
  9784. get content()
  9785. {
  9786. return this._content;
  9787. },
  9788. get contentEncoded()
  9789. {
  9790. return this._contentEncoded;
  9791. },
  9792. contentURL: function()
  9793. {
  9794. return this._url;
  9795. },
  9796. contentType: function()
  9797. {
  9798. return this._type;
  9799. },
  9800. requestContent: function(callback)
  9801. {
  9802. if (this.type === WebInspector.resourceTypes.WebSocket) {
  9803. callback(null, false, this._mimeType);
  9804. return;
  9805. }
  9806. if (typeof this._content !== "undefined") {
  9807. callback(this.content || null, this._contentEncoded, this._mimeType);
  9808. return;
  9809. }
  9810. this._pendingContentCallbacks.push(callback);
  9811. if (this.finished)
  9812. this._innerRequestContent();
  9813. },
  9814. searchInContent: function(query, caseSensitive, isRegex, callback)
  9815. {
  9816. callback([]);
  9817. },
  9818. isHttpFamily: function()
  9819. {
  9820. return !!this.url.match(/^https?:/i);
  9821. },
  9822. requestContentType: function()
  9823. {
  9824. return this.requestHeaderValue("Content-Type");
  9825. },
  9826. isPingRequest: function()
  9827. {
  9828. return "text/ping" === this.requestContentType();
  9829. },
  9830. hasErrorStatusCode: function()
  9831. {
  9832. return this.statusCode >= 400;
  9833. },
  9834. populateImageSource: function(image)
  9835. {
  9836. function onResourceContent(content, contentEncoded, mimeType)
  9837. {
  9838. const maxDataUrlSize = 1024 * 1024;
  9839. if (this._content == null || this._content.length > maxDataUrlSize)
  9840. return this.url;
  9841. image.src = "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content;
  9842. }
  9843. this.requestContent(onResourceContent.bind(this));
  9844. },
  9845. _innerRequestContent: function()
  9846. {
  9847. if (this._contentRequested)
  9848. return;
  9849. this._contentRequested = true;
  9850. function onResourceContent(error, content, contentEncoded)
  9851. {
  9852. this._content = error ? null : content;
  9853. this._contentEncoded = contentEncoded;
  9854. var callbacks = this._pendingContentCallbacks.slice();
  9855. for (var i = 0; i < callbacks.length; ++i)
  9856. callbacks[i](this._content, this._contentEncoded, this._mimeType);
  9857. this._pendingContentCallbacks.length = 0;
  9858. delete this._contentRequested;
  9859. }
  9860. NetworkAgent.getResponseBody(this._requestId, onResourceContent.bind(this));
  9861. },
  9862. setResource: function(resource)
  9863. {
  9864. this._resource = resource;
  9865. },
  9866. resource: function()
  9867. {
  9868. return this._resource;
  9869. },
  9870. frames: function()
  9871. {
  9872. return this._frames;
  9873. },
  9874. frame: function(position)
  9875. {
  9876. return this._frames[position];
  9877. },
  9878. addFrameError: function(errorMessage, time)
  9879. {
  9880. var errorObject = {};
  9881. errorObject.errorMessage = errorMessage;
  9882. errorObject.time = time;
  9883. this._pushFrame(errorObject);
  9884. },
  9885. addFrame: function(response, time, sent)
  9886. {
  9887. response.time = time;
  9888. if (sent)
  9889. response.sent = true;
  9890. this._pushFrame(response);
  9891. },
  9892. _pushFrame: function(object)
  9893. {
  9894. if (this._frames.length >= 100) {
  9895. this._frames.splice(0, 10);
  9896. }
  9897. this._frames.push(object);
  9898. }
  9899. }
  9900. WebInspector.NetworkRequest.prototype.__proto__ = WebInspector.Object.prototype;
  9901. WebInspector.CSSStyleModel = function()
  9902. {
  9903. this._pendingCommandsMajorState = [];
  9904. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoRequested, this._undoRedoRequested, this);
  9905. WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoCompleted, this._undoRedoCompleted, this);
  9906. new WebInspector.CSSStyleModelResourceBinding(this);
  9907. InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this));
  9908. CSSAgent.enable();
  9909. }
  9910. WebInspector.CSSStyleModel.parseRuleArrayPayload = function(ruleArray)
  9911. {
  9912. var result = [];
  9913. for (var i = 0; i < ruleArray.length; ++i)
  9914. result.push(WebInspector.CSSRule.parsePayload(ruleArray[i]));
  9915. return result;
  9916. }
  9917. WebInspector.CSSStyleModel.Events = {
  9918. StyleSheetChanged: "StyleSheetChanged",
  9919. MediaQueryResultChanged: "MediaQueryResultChanged"
  9920. }
  9921. WebInspector.CSSStyleModel.prototype = {
  9922. getMatchedStylesAsync: function(nodeId, forcedPseudoClasses, needPseudo, needInherited, userCallback)
  9923. {
  9924. function callback(userCallback, error, matchedPayload, pseudoPayload, inheritedPayload)
  9925. {
  9926. if (error) {
  9927. if (userCallback)
  9928. userCallback(null);
  9929. return;
  9930. }
  9931. var result = {};
  9932. if (matchedPayload)
  9933. result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(matchedPayload);
  9934. if (pseudoPayload) {
  9935. result.pseudoElements = [];
  9936. for (var i = 0; i < pseudoPayload.length; ++i) {
  9937. var entryPayload = pseudoPayload[i];
  9938. result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.rules) });
  9939. }
  9940. }
  9941. if (inheritedPayload) {
  9942. result.inherited = [];
  9943. for (var i = 0; i < inheritedPayload.length; ++i) {
  9944. var entryPayload = inheritedPayload[i];
  9945. var entry = {};
  9946. if (entryPayload.inlineStyle)
  9947. entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(entryPayload.inlineStyle);
  9948. if (entryPayload.matchedCSSRules)
  9949. entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.matchedCSSRules);
  9950. result.inherited.push(entry);
  9951. }
  9952. }
  9953. if (userCallback)
  9954. userCallback(result);
  9955. }
  9956. CSSAgent.getMatchedStylesForNode(nodeId, forcedPseudoClasses || [], needPseudo, needInherited, callback.bind(null, userCallback));
  9957. },
  9958. getComputedStyleAsync: function(nodeId, forcedPseudoClasses, userCallback)
  9959. {
  9960. function callback(userCallback, error, computedPayload)
  9961. {
  9962. if (error || !computedPayload)
  9963. userCallback(null);
  9964. else
  9965. userCallback(WebInspector.CSSStyleDeclaration.parseComputedStylePayload(computedPayload));
  9966. }
  9967. CSSAgent.getComputedStyleForNode(nodeId, forcedPseudoClasses || [], callback.bind(null, userCallback));
  9968. },
  9969. getInlineStylesAsync: function(nodeId, userCallback)
  9970. {
  9971. function callback(userCallback, error, inlinePayload, attributesStylePayload)
  9972. {
  9973. if (error || !inlinePayload)
  9974. userCallback(null, null);
  9975. else
  9976. userCallback(WebInspector.CSSStyleDeclaration.parsePayload(inlinePayload), attributesStylePayload ? WebInspector.CSSStyleDeclaration.parsePayload(attributesStylePayload) : null);
  9977. }
  9978. CSSAgent.getInlineStylesForNode(nodeId, callback.bind(null, userCallback));
  9979. },
  9980. setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback)
  9981. {
  9982. function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
  9983. {
  9984. if (!selectedNodeIds)
  9985. return;
  9986. var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
  9987. var rule = WebInspector.CSSRule.parsePayload(rulePayload);
  9988. successCallback(rule, doesAffectSelectedNode);
  9989. }
  9990. function callback(nodeId, successCallback, failureCallback, newSelector, error, rulePayload)
  9991. {
  9992. this._pendingCommandsMajorState.pop();
  9993. if (error)
  9994. failureCallback();
  9995. else {
  9996. WebInspector.domAgent.markUndoableState();
  9997. var ownerDocumentId = this._ownerDocumentId(nodeId);
  9998. if (ownerDocumentId)
  9999. WebInspector.domAgent.querySelectorAll(ownerDocumentId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
  10000. else
  10001. failureCallback();
  10002. }
  10003. }
  10004. this._pendingCommandsMajorState.push(true);
  10005. CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector));
  10006. },
  10007. addRule: function(nodeId, selector, successCallback, failureCallback)
  10008. {
  10009. function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
  10010. {
  10011. if (!selectedNodeIds)
  10012. return;
  10013. var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
  10014. var rule = WebInspector.CSSRule.parsePayload(rulePayload);
  10015. successCallback(rule, doesAffectSelectedNode);
  10016. }
  10017. function callback(successCallback, failureCallback, selector, error, rulePayload)
  10018. {
  10019. this._pendingCommandsMajorState.pop();
  10020. if (error) {
  10021. failureCallback();
  10022. } else {
  10023. WebInspector.domAgent.markUndoableState();
  10024. var ownerDocumentId = this._ownerDocumentId(nodeId);
  10025. if (ownerDocumentId)
  10026. WebInspector.domAgent.querySelectorAll(ownerDocumentId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
  10027. else
  10028. failureCallback();
  10029. }
  10030. }
  10031. this._pendingCommandsMajorState.push(true);
  10032. CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector));
  10033. },
  10034. mediaQueryResultChanged: function()
  10035. {
  10036. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged);
  10037. },
  10038. _ownerDocumentId: function(nodeId)
  10039. {
  10040. var node = WebInspector.domAgent.nodeForId(nodeId);
  10041. if (!node)
  10042. return null;
  10043. return node.ownerDocument ? node.ownerDocument.id : null;
  10044. },
  10045. _fireStyleSheetChanged: function(styleSheetId)
  10046. {
  10047. if (!this._pendingCommandsMajorState.length)
  10048. return;
  10049. var majorChange = this._pendingCommandsMajorState[this._pendingCommandsMajorState.length - 1];
  10050. if (!majorChange || !styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged))
  10051. return;
  10052. this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, majorChange: majorChange });
  10053. },
  10054. setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback)
  10055. {
  10056. function callback(error)
  10057. {
  10058. this._pendingCommandsMajorState.pop();
  10059. if (!error && majorChange)
  10060. WebInspector.domAgent.markUndoableState();
  10061. if (!error && userCallback)
  10062. userCallback(error);
  10063. }
  10064. this._pendingCommandsMajorState.push(majorChange);
  10065. CSSAgent.setStyleSheetText(styleSheetId, newText, callback.bind(this));
  10066. },
  10067. _undoRedoRequested: function()
  10068. {
  10069. this._pendingCommandsMajorState.push(true);
  10070. },
  10071. _undoRedoCompleted: function()
  10072. {
  10073. this._pendingCommandsMajorState.pop();
  10074. }
  10075. }
  10076. WebInspector.CSSStyleModel.prototype.__proto__ = WebInspector.Object.prototype;
  10077. WebInspector.CSSStyleDeclaration = function(payload)
  10078. {
  10079. this.id = payload.styleId;
  10080. this.width = payload.width;
  10081. this.height = payload.height;
  10082. this.range = payload.range;
  10083. this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries);
  10084. this._livePropertyMap = {};
  10085. this._allProperties = [];
  10086. this._longhandProperties = {};
  10087. this.__disabledProperties = {};
  10088. var payloadPropertyCount = payload.cssProperties.length;
  10089. var propertyIndex = 0;
  10090. for (var i = 0; i < payloadPropertyCount; ++i) {
  10091. var property = WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]);
  10092. this._allProperties.push(property);
  10093. if (property.disabled)
  10094. this.__disabledProperties[i] = property;
  10095. if (!property.active && !property.styleBased)
  10096. continue;
  10097. var name = property.name;
  10098. this[propertyIndex] = name;
  10099. this._livePropertyMap[name] = property;
  10100. if (property.shorthand) {
  10101. var longhands = this._longhandProperties[property.shorthand];
  10102. if (!longhands) {
  10103. longhands = [];
  10104. this._longhandProperties[property.shorthand] = longhands;
  10105. }
  10106. longhands.push(property);
  10107. }
  10108. ++propertyIndex;
  10109. }
  10110. this.length = propertyIndex;
  10111. if ("cssText" in payload)
  10112. this.cssText = payload.cssText;
  10113. }
  10114. WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries)
  10115. {
  10116. var result = {};
  10117. for (var i = 0; i < shorthandEntries.length; ++i)
  10118. result[shorthandEntries[i].name] = shorthandEntries[i].value;
  10119. return result;
  10120. }
  10121. WebInspector.CSSStyleDeclaration.parsePayload = function(payload)
  10122. {
  10123. return new WebInspector.CSSStyleDeclaration(payload);
  10124. }
  10125. WebInspector.CSSStyleDeclaration.parseComputedStylePayload = function(payload)
  10126. {
  10127. var newPayload = { cssProperties: [], shorthandEntries: [], width: "", height: "" };
  10128. if (payload)
  10129. newPayload.cssProperties = payload;
  10130. return new WebInspector.CSSStyleDeclaration(newPayload);
  10131. }
  10132. WebInspector.CSSStyleDeclaration.prototype = {
  10133. get allProperties()
  10134. {
  10135. return this._allProperties;
  10136. },
  10137. getLiveProperty: function(name)
  10138. {
  10139. return this._livePropertyMap[name];
  10140. },
  10141. getPropertyValue: function(name)
  10142. {
  10143. var property = this._livePropertyMap[name];
  10144. return property ? property.value : "";
  10145. },
  10146. getPropertyPriority: function(name)
  10147. {
  10148. var property = this._livePropertyMap[name];
  10149. return property ? property.priority : "";
  10150. },
  10151. getPropertyShorthand: function(name)
  10152. {
  10153. var property = this._livePropertyMap[name];
  10154. return property ? property.shorthand : "";
  10155. },
  10156. isPropertyImplicit: function(name)
  10157. {
  10158. var property = this._livePropertyMap[name];
  10159. return property ? property.implicit : "";
  10160. },
  10161. styleTextWithShorthands: function()
  10162. {
  10163. var cssText = "";
  10164. var foundProperties = {};
  10165. for (var i = 0; i < this.length; ++i) {
  10166. var individualProperty = this[i];
  10167. var shorthandProperty = this.getPropertyShorthand(individualProperty);
  10168. var propertyName = (shorthandProperty || individualProperty);
  10169. if (propertyName in foundProperties)
  10170. continue;
  10171. if (shorthandProperty) {
  10172. var value = this.getShorthandValue(shorthandProperty);
  10173. var priority = this.getShorthandPriority(shorthandProperty);
  10174. } else {
  10175. var value = this.getPropertyValue(individualProperty);
  10176. var priority = this.getPropertyPriority(individualProperty);
  10177. }
  10178. foundProperties[propertyName] = true;
  10179. cssText += propertyName + ": " + value;
  10180. if (priority)
  10181. cssText += " !" + priority;
  10182. cssText += "; ";
  10183. }
  10184. return cssText;
  10185. },
  10186. getLonghandProperties: function(name)
  10187. {
  10188. return this._longhandProperties[name] || [];
  10189. },
  10190. getShorthandValue: function(shorthandProperty)
  10191. {
  10192. var property = this.getLiveProperty(shorthandProperty);
  10193. return property ? property.value : this._shorthandValues[shorthandProperty];
  10194. },
  10195. getShorthandPriority: function(shorthandProperty)
  10196. {
  10197. var priority = this.getPropertyPriority(shorthandProperty);
  10198. if (priority)
  10199. return priority;
  10200. var longhands = this._longhandProperties[shorthandProperty];
  10201. return longhands ? this.getPropertyPriority(longhands[0]) : null;
  10202. },
  10203. propertyAt: function(index)
  10204. {
  10205. return (index < this.allProperties.length) ? this.allProperties[index] : null;
  10206. },
  10207. pastLastSourcePropertyIndex: function()
  10208. {
  10209. for (var i = this.allProperties.length - 1; i >= 0; --i) {
  10210. var property = this.allProperties[i];
  10211. if (property.active || property.disabled)
  10212. return i + 1;
  10213. }
  10214. return 0;
  10215. },
  10216. newBlankProperty: function(index)
  10217. {
  10218. index = (typeof index === "undefined") ? this.pastLastSourcePropertyIndex() : index;
  10219. return new WebInspector.CSSProperty(this, index, "", "", "", "active", true, false, false, "");
  10220. },
  10221. insertPropertyAt: function(index, name, value, userCallback)
  10222. {
  10223. function callback(userCallback, error, payload)
  10224. {
  10225. WebInspector.cssModel._pendingCommandsMajorState.pop();
  10226. if (!userCallback)
  10227. return;
  10228. if (error) {
  10229. console.error(error);
  10230. userCallback(null);
  10231. } else {
  10232. userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload));
  10233. }
  10234. }
  10235. WebInspector.cssModel._pendingCommandsMajorState.push(true);
  10236. CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(this, userCallback));
  10237. },
  10238. appendProperty: function(name, value, userCallback)
  10239. {
  10240. this.insertPropertyAt(this.allProperties.length, name, value, userCallback);
  10241. }
  10242. }
  10243. WebInspector.CSSRule = function(payload)
  10244. {
  10245. this.id = payload.ruleId;
  10246. this.selectorText = payload.selectorText;
  10247. this.sourceLine = payload.sourceLine;
  10248. this.sourceURL = payload.sourceURL;
  10249. this.origin = payload.origin;
  10250. this.style = WebInspector.CSSStyleDeclaration.parsePayload(payload.style);
  10251. this.style.parentRule = this;
  10252. this.selectorRange = payload.selectorRange;
  10253. if (payload.media)
  10254. this.media = WebInspector.CSSMedia.parseMediaArrayPayload(payload.media);
  10255. }
  10256. WebInspector.CSSRule.parsePayload = function(payload)
  10257. {
  10258. return new WebInspector.CSSRule(payload);
  10259. }
  10260. WebInspector.CSSRule.prototype = {
  10261. get isUserAgent()
  10262. {
  10263. return this.origin === "user-agent";
  10264. },
  10265. get isUser()
  10266. {
  10267. return this.origin === "user";
  10268. },
  10269. get isViaInspector()
  10270. {
  10271. return this.origin === "inspector";
  10272. },
  10273. get isRegular()
  10274. {
  10275. return this.origin === "regular";
  10276. }
  10277. }
  10278. WebInspector.CSSProperty = function(ownerStyle, index, name, value, priority, status, parsedOk, implicit, shorthand, text)
  10279. {
  10280. this.ownerStyle = ownerStyle;
  10281. this.index = index;
  10282. this.name = name;
  10283. this.value = value;
  10284. this.priority = priority;
  10285. this.status = status;
  10286. this.parsedOk = parsedOk;
  10287. this.implicit = implicit;
  10288. this.shorthand = shorthand;
  10289. this.text = text;
  10290. }
  10291. WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload)
  10292. {
  10293. var result = new WebInspector.CSSProperty(
  10294. ownerStyle, index, payload.name, payload.value, payload.priority || "", payload.status || "style", ("parsedOk" in payload) ? payload.parsedOk : true, !!payload.implicit, payload.shorthandName || "", payload.text);
  10295. return result;
  10296. }
  10297. WebInspector.CSSProperty.prototype = {
  10298. get propertyText()
  10299. {
  10300. if (this.text !== undefined)
  10301. return this.text;
  10302. if (this.name === "")
  10303. return "";
  10304. return this.name + ": " + this.value + (this.priority ? " !" + this.priority : "") + ";";
  10305. },
  10306. get isLive()
  10307. {
  10308. return this.active || this.styleBased;
  10309. },
  10310. get active()
  10311. {
  10312. return this.status === "active";
  10313. },
  10314. get styleBased()
  10315. {
  10316. return this.status === "style";
  10317. },
  10318. get inactive()
  10319. {
  10320. return this.status === "inactive";
  10321. },
  10322. get disabled()
  10323. {
  10324. return this.status === "disabled";
  10325. },
  10326. setText: function(propertyText, majorChange, overwrite, userCallback)
  10327. {
  10328. function enabledCallback(style)
  10329. {
  10330. if (userCallback)
  10331. userCallback(style);
  10332. }
  10333. function callback(error, stylePayload)
  10334. {
  10335. WebInspector.cssModel._pendingCommandsMajorState.pop();
  10336. if (!error) {
  10337. if (majorChange)
  10338. WebInspector.domAgent.markUndoableState();
  10339. this.text = propertyText;
  10340. var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
  10341. var newProperty = style.allProperties[this.index];
  10342. if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) {
  10343. newProperty.setDisabled(false, enabledCallback);
  10344. return;
  10345. }
  10346. if (userCallback)
  10347. userCallback(style);
  10348. } else {
  10349. if (userCallback)
  10350. userCallback(null);
  10351. }
  10352. }
  10353. if (!this.ownerStyle)
  10354. throw "No ownerStyle for property";
  10355. WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
  10356. CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, overwrite, callback.bind(this));
  10357. },
  10358. setValue: function(newValue, majorChange, overwrite, userCallback)
  10359. {
  10360. var text = this.name + ": " + newValue + (this.priority ? " !" + this.priority : "") + ";"
  10361. this.setText(text, majorChange, overwrite, userCallback);
  10362. },
  10363. setDisabled: function(disabled, userCallback)
  10364. {
  10365. if (!this.ownerStyle && userCallback)
  10366. userCallback(null);
  10367. if (disabled === this.disabled && userCallback)
  10368. userCallback(this.ownerStyle);
  10369. function callback(error, stylePayload)
  10370. {
  10371. WebInspector.cssModel._pendingCommandsMajorState.pop();
  10372. if (error) {
  10373. if (userCallback)
  10374. userCallback(null);
  10375. return;
  10376. }
  10377. WebInspector.domAgent.markUndoableState();
  10378. if (userCallback) {
  10379. var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
  10380. userCallback(style);
  10381. }
  10382. }
  10383. WebInspector.cssModel._pendingCommandsMajorState.push(false);
  10384. CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this));
  10385. }
  10386. }
  10387. WebInspector.CSSMedia = function(payload)
  10388. {
  10389. this.text = payload.text;
  10390. this.source = payload.source;
  10391. this.sourceURL = payload.sourceURL || "";
  10392. this.sourceLine = typeof payload.sourceLine === "undefined" || this.source === "linkedSheet" ? -1 : payload.sourceLine;
  10393. }
  10394. WebInspector.CSSMedia.Source = {
  10395. LINKED_SHEET: "linkedSheet",
  10396. INLINE_SHEET: "inlineSheet",
  10397. MEDIA_RULE: "mediaRule",
  10398. IMPORT_RULE: "importRule"
  10399. };
  10400. WebInspector.CSSMedia.parsePayload = function(payload)
  10401. {
  10402. return new WebInspector.CSSMedia(payload);
  10403. }
  10404. WebInspector.CSSMedia.parseMediaArrayPayload = function(payload)
  10405. {
  10406. var result = [];
  10407. for (var i = 0; i < payload.length; ++i)
  10408. result.push(WebInspector.CSSMedia.parsePayload(payload[i]));
  10409. return result;
  10410. }
  10411. WebInspector.CSSStyleSheet = function(payload)
  10412. {
  10413. this.id = payload.styleSheetId;
  10414. this.rules = [];
  10415. this.styles = {};
  10416. for (var i = 0; i < payload.rules.length; ++i) {
  10417. var rule = WebInspector.CSSRule.parsePayload(payload.rules[i]);
  10418. this.rules.push(rule);
  10419. if (rule.style)
  10420. this.styles[rule.style.id] = rule.style;
  10421. }
  10422. if ("text" in payload)
  10423. this._text = payload.text;
  10424. }
  10425. WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback)
  10426. {
  10427. function callback(error, styleSheetPayload)
  10428. {
  10429. if (error)
  10430. userCallback(null);
  10431. else
  10432. userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload));
  10433. }
  10434. CSSAgent.getStyleSheet(styleSheetId, callback.bind(this));
  10435. }
  10436. WebInspector.CSSStyleSheet.prototype = {
  10437. getText: function()
  10438. {
  10439. return this._text;
  10440. },
  10441. setText: function(newText, majorChange, userCallback)
  10442. {
  10443. function callback(error)
  10444. {
  10445. if (!error)
  10446. WebInspector.domAgent.markUndoableState();
  10447. WebInspector.cssModel._pendingCommandsMajorState.pop();
  10448. if (userCallback)
  10449. userCallback(error);
  10450. }
  10451. WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
  10452. CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this));
  10453. }
  10454. }
  10455. WebInspector.CSSStyleModelResourceBinding = function(cssModel)
  10456. {
  10457. this._cssModel = cssModel;
  10458. this._urlToStyleSheetId = {};
  10459. this._styleSheetIdToURL = {};
  10460. this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._styleSheetChanged, this);
  10461. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this);
  10462. WebInspector.Resource.registerDomainModelBinding(WebInspector.resourceTypes.Stylesheet, this);
  10463. }
  10464. WebInspector.CSSStyleModelResourceBinding.prototype = {
  10465. setContent: function(resource, content, majorChange, userCallback)
  10466. {
  10467. if (majorChange && resource.type === WebInspector.resourceTypes.Stylesheet)
  10468. resource.addRevision(content);
  10469. if (this._urlToStyleSheetId[resource.url]) {
  10470. this._innerSetContent(resource.url, content, majorChange, userCallback, null);
  10471. return;
  10472. }
  10473. this._loadStyleSheetHeaders(this._innerSetContent.bind(this, resource.url, content, majorChange, userCallback));
  10474. },
  10475. canSetContent: function()
  10476. {
  10477. return true;
  10478. },
  10479. _inspectedURLChanged: function(event)
  10480. {
  10481. this._urlToStyleSheetId = {};
  10482. this._styleSheetIdToURL = {};
  10483. },
  10484. _innerSetContent: function(url, content, majorChange, userCallback, error)
  10485. {
  10486. if (error) {
  10487. userCallback(error);
  10488. return;
  10489. }
  10490. var styleSheetId = this._urlToStyleSheetId[url];
  10491. if (!styleSheetId) {
  10492. if (userCallback)
  10493. userCallback("No stylesheet found: " + url);
  10494. return;
  10495. }
  10496. this._isSettingContent = true;
  10497. function callbackWrapper(error)
  10498. {
  10499. if (userCallback)
  10500. userCallback(error);
  10501. delete this._isSettingContent;
  10502. }
  10503. this._cssModel.setStyleSheetText(styleSheetId, content, majorChange, callbackWrapper.bind(this));
  10504. },
  10505. _loadStyleSheetHeaders: function(callback)
  10506. {
  10507. function didGetAllStyleSheets(error, infos)
  10508. {
  10509. if (error) {
  10510. callback(error);
  10511. return;
  10512. }
  10513. for (var i = 0; i < infos.length; ++i) {
  10514. var info = infos[i];
  10515. this._urlToStyleSheetId[info.sourceURL] = info.styleSheetId;
  10516. this._styleSheetIdToURL[info.styleSheetId] = info.sourceURL;
  10517. }
  10518. callback();
  10519. }
  10520. CSSAgent.getAllStyleSheets(didGetAllStyleSheets.bind(this));
  10521. },
  10522. _styleSheetChanged: function(event)
  10523. {
  10524. if (this._isSettingContent)
  10525. return;
  10526. if (!event.data.majorChange)
  10527. return;
  10528. function callback(error, content)
  10529. {
  10530. if (!error)
  10531. this._innerStyleSheetChanged(event.data.styleSheetId, content);
  10532. }
  10533. CSSAgent.getStyleSheetText(event.data.styleSheetId, callback.bind(this));
  10534. },
  10535. _innerStyleSheetChanged: function(styleSheetId, content)
  10536. {
  10537. function setContent()
  10538. {
  10539. var url = this._styleSheetIdToURL[styleSheetId];
  10540. if (!url)
  10541. return;
  10542. var resource = WebInspector.resourceForURL(url);
  10543. if (resource && resource.type === WebInspector.resourceTypes.Stylesheet)
  10544. resource.addRevision(content);
  10545. }
  10546. if (!this._styleSheetIdToURL[styleSheetId]) {
  10547. this._loadStyleSheetHeaders(setContent.bind(this));
  10548. return;
  10549. }
  10550. setContent.call(this);
  10551. }
  10552. }
  10553. WebInspector.CSSStyleModelResourceBinding.prototype.__proto__ = WebInspector.ResourceDomainModelBinding.prototype;
  10554. WebInspector.CSSDispatcher = function(cssModel)
  10555. {
  10556. this._cssModel = cssModel;
  10557. }
  10558. WebInspector.CSSDispatcher.prototype = {
  10559. mediaQueryResultChanged: function()
  10560. {
  10561. this._cssModel.mediaQueryResultChanged();
  10562. },
  10563. styleSheetChanged: function(styleSheetId)
  10564. {
  10565. this._cssModel._fireStyleSheetChanged(styleSheetId);
  10566. }
  10567. }
  10568. WebInspector.cssModel = null;
  10569. WebInspector.NetworkManager = function()
  10570. {
  10571. WebInspector.Object.call(this);
  10572. this._dispatcher = new WebInspector.NetworkDispatcher(this);
  10573. if (WebInspector.settings.cacheDisabled.get())
  10574. NetworkAgent.setCacheDisabled(true);
  10575. NetworkAgent.enable();
  10576. WebInspector.settings.cacheDisabled.addChangeListener(this._cacheDisabledSettingChanged, this);
  10577. if (WebInspector.settings.userAgent.get())
  10578. this._userAgentSettingChanged();
  10579. WebInspector.settings.userAgent.addChangeListener(this._userAgentSettingChanged, this);
  10580. }
  10581. WebInspector.NetworkManager.EventTypes = {
  10582. ResourceTrackingEnabled: "ResourceTrackingEnabled",
  10583. ResourceTrackingDisabled: "ResourceTrackingDisabled",
  10584. RequestStarted: "RequestStarted",
  10585. RequestUpdated: "RequestUpdated",
  10586. RequestFinished: "RequestFinished",
  10587. RequestUpdateDropped: "RequestUpdateDropped"
  10588. }
  10589. WebInspector.NetworkManager._MIMETypes = {
  10590. "text/html": {"document": true},
  10591. "text/xml": {"document": true},
  10592. "text/plain": {"document": true},
  10593. "application/xhtml+xml": {"document": true},
  10594. "text/css": {"stylesheet": true},
  10595. "text/xsl": {"stylesheet": true},
  10596. "image/jpeg": {"image": true},
  10597. "image/png": {"image": true},
  10598. "image/gif": {"image": true},
  10599. "image/bmp": {"image": true},
  10600. "image/svg+xml": {"image": true},
  10601. "image/vnd.microsoft.icon": {"image": true},
  10602. "image/webp": {"image": true},
  10603. "image/x-icon": {"image": true},
  10604. "image/x-xbitmap": {"image": true},
  10605. "font/ttf": {"font": true},
  10606. "font/opentype": {"font": true},
  10607. "font/woff": {"font": true},
  10608. "application/x-font-type1": {"font": true},
  10609. "application/x-font-ttf": {"font": true},
  10610. "application/x-font-woff": {"font": true},
  10611. "application/x-truetype-font": {"font": true},
  10612. "text/javascript": {"script": true},
  10613. "text/ecmascript": {"script": true},
  10614. "application/javascript": {"script": true},
  10615. "application/ecmascript": {"script": true},
  10616. "application/x-javascript": {"script": true},
  10617. "application/json": {"script": true},
  10618. "text/javascript1.1": {"script": true},
  10619. "text/javascript1.2": {"script": true},
  10620. "text/javascript1.3": {"script": true},
  10621. "text/jscript": {"script": true},
  10622. "text/livescript": {"script": true},
  10623. }
  10624. WebInspector.NetworkManager.prototype = {
  10625. enableResourceTracking: function()
  10626. {
  10627. function callback(error)
  10628. {
  10629. this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceTrackingEnabled);
  10630. }
  10631. NetworkAgent.enable(callback.bind(this));
  10632. },
  10633. disableResourceTracking: function()
  10634. {
  10635. function callback(error)
  10636. {
  10637. this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceTrackingDisabled);
  10638. }
  10639. NetworkAgent.disable(callback.bind(this));
  10640. },
  10641. inflightRequestForURL: function(url)
  10642. {
  10643. return this._dispatcher._inflightRequestsByURL[url];
  10644. },
  10645. _cacheDisabledSettingChanged: function(event)
  10646. {
  10647. var enabled = event.data;
  10648. NetworkAgent.setCacheDisabled(enabled);
  10649. },
  10650. _userAgentSettingChanged: function()
  10651. {
  10652. NetworkAgent.setUserAgentOverride(WebInspector.settings.userAgent.get());
  10653. }
  10654. }
  10655. WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype;
  10656. WebInspector.NetworkDispatcher = function(manager)
  10657. {
  10658. this._manager = manager;
  10659. this._inflightRequestsById = {};
  10660. this._inflightRequestsByURL = {};
  10661. InspectorBackend.registerNetworkDispatcher(this);
  10662. }
  10663. WebInspector.NetworkDispatcher.prototype = {
  10664. _headersMapToHeadersArray: function(headersMap)
  10665. {
  10666. var result = [];
  10667. for (var name in headersMap) {
  10668. var values = headersMap[name].split("\n");
  10669. for (var i = 0; i < values.length; ++i)
  10670. result.push({ name: name, value: values[i] });
  10671. }
  10672. return result;
  10673. },
  10674. _updateNetworkRequestWithRequest: function(networkRequest, request)
  10675. {
  10676. networkRequest.requestMethod = request.method;
  10677. networkRequest.requestHeaders = this._headersMapToHeadersArray(request.headers);
  10678. networkRequest.requestFormData = request.postData;
  10679. },
  10680. _updateNetworkRequestWithResponse: function(networkRequest, response)
  10681. {
  10682. if (!response)
  10683. return;
  10684. if (response.url && networkRequest.url !== response.url)
  10685. networkRequest.url = response.url;
  10686. networkRequest.mimeType = response.mimeType;
  10687. networkRequest.statusCode = response.status;
  10688. networkRequest.statusText = response.statusText;
  10689. networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers);
  10690. if (response.headersText)
  10691. networkRequest.responseHeadersText = response.headersText;
  10692. if (response.requestHeaders)
  10693. networkRequest.requestHeaders = this._headersMapToHeadersArray(response.requestHeaders);
  10694. if (response.requestHeadersText)
  10695. networkRequest.requestHeadersText = response.requestHeadersText;
  10696. networkRequest.connectionReused = response.connectionReused;
  10697. networkRequest.connectionId = response.connectionId;
  10698. if (response.fromDiskCache)
  10699. networkRequest.cached = true;
  10700. else
  10701. networkRequest.timing = response.timing;
  10702. if (!this._mimeTypeIsConsistentWithType(networkRequest)) {
  10703. WebInspector.console.addMessage(WebInspector.ConsoleMessage.create(WebInspector.ConsoleMessage.MessageSource.Network,
  10704. WebInspector.ConsoleMessage.MessageLevel.Warning,
  10705. WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s: \"%s\".", networkRequest.type.title(), networkRequest.mimeType, networkRequest.url),
  10706. WebInspector.ConsoleMessage.MessageType.Log,
  10707. "",
  10708. 0,
  10709. 1,
  10710. [],
  10711. null,
  10712. networkRequest));
  10713. }
  10714. },
  10715. _mimeTypeIsConsistentWithType: function(networkRequest)
  10716. {
  10717. if (networkRequest.hasErrorStatusCode() || networkRequest.statusCode === 304)
  10718. return true;
  10719. if (typeof networkRequest.type === "undefined"
  10720. || networkRequest.type === WebInspector.resourceTypes.Other
  10721. || networkRequest.type === WebInspector.resourceTypes.XHR
  10722. || networkRequest.type === WebInspector.resourceTypes.WebSocket)
  10723. return true;
  10724. if (!networkRequest.mimeType)
  10725. return true;
  10726. if (networkRequest.mimeType in WebInspector.NetworkManager._MIMETypes)
  10727. return networkRequest.type.name() in WebInspector.NetworkManager._MIMETypes[networkRequest.mimeType];
  10728. return false;
  10729. },
  10730. _updateNetworkRequestWithCachedResource: function(networkRequest, cachedResource)
  10731. {
  10732. networkRequest.type = WebInspector.resourceTypes[cachedResource.type];
  10733. networkRequest.resourceSize = cachedResource.bodySize;
  10734. this._updateNetworkRequestWithResponse(networkRequest, cachedResource.response);
  10735. },
  10736. _isNull: function(response)
  10737. {
  10738. if (!response)
  10739. return true;
  10740. return !response.status && !response.mimeType && (!response.headers || !Object.keys(response.headers).length);
  10741. },
  10742. requestWillBeSent: function(requestId, frameId, loaderId, documentURL, request, time, initiator, redirectResponse)
  10743. {
  10744. var networkRequest = this._inflightRequestsById[requestId];
  10745. if (networkRequest) {
  10746. if (!redirectResponse)
  10747. return;
  10748. this.responseReceived(requestId, frameId, loaderId, time, "Other", redirectResponse);
  10749. networkRequest = this._appendRedirect(requestId, time, request.url);
  10750. } else
  10751. networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, request.url, documentURL, initiator);
  10752. networkRequest.hasNetworkData = true;
  10753. this._updateNetworkRequestWithRequest(networkRequest, request);
  10754. networkRequest.startTime = time;
  10755. this._startNetworkRequest(networkRequest);
  10756. },
  10757. requestServedFromCache: function(requestId)
  10758. {
  10759. var networkRequest = this._inflightRequestsById[requestId];
  10760. if (!networkRequest)
  10761. return;
  10762. networkRequest.cached = true;
  10763. },
  10764. responseReceived: function(requestId, frameId, loaderId, time, resourceType, response)
  10765. {
  10766. if (this._isNull(response))
  10767. return;
  10768. var networkRequest = this._inflightRequestsById[requestId];
  10769. if (!networkRequest) {
  10770. var eventData = {};
  10771. eventData.url = response.url;
  10772. eventData.frameId = frameId;
  10773. eventData.loaderId = loaderId;
  10774. eventData.resourceType = resourceType;
  10775. eventData.mimeType = response.mimeType;
  10776. this._manager.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, eventData);
  10777. return;
  10778. }
  10779. networkRequest.responseReceivedTime = time;
  10780. networkRequest.type = WebInspector.resourceTypes[resourceType];
  10781. this._updateNetworkRequestWithResponse(networkRequest, response);
  10782. this._updateNetworkRequest(networkRequest);
  10783. },
  10784. dataReceived: function(requestId, time, dataLength, encodedDataLength)
  10785. {
  10786. var networkRequest = this._inflightRequestsById[requestId];
  10787. if (!networkRequest)
  10788. return;
  10789. networkRequest.resourceSize += dataLength;
  10790. if (encodedDataLength != -1)
  10791. networkRequest.increaseTransferSize(encodedDataLength);
  10792. networkRequest.endTime = time;
  10793. this._updateNetworkRequest(networkRequest);
  10794. },
  10795. loadingFinished: function(requestId, finishTime)
  10796. {
  10797. var networkRequest = this._inflightRequestsById[requestId];
  10798. if (!networkRequest)
  10799. return;
  10800. this._finishNetworkRequest(networkRequest, finishTime);
  10801. },
  10802. loadingFailed: function(requestId, time, localizedDescription, canceled)
  10803. {
  10804. var networkRequest = this._inflightRequestsById[requestId];
  10805. if (!networkRequest)
  10806. return;
  10807. networkRequest.failed = true;
  10808. networkRequest.canceled = canceled;
  10809. networkRequest.localizedFailDescription = localizedDescription;
  10810. this._finishNetworkRequest(networkRequest, time);
  10811. },
  10812. requestServedFromMemoryCache: function(requestId, frameId, loaderId, documentURL, time, initiator, cachedResource)
  10813. {
  10814. var networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, cachedResource.url, documentURL, initiator);
  10815. this._updateNetworkRequestWithCachedResource(networkRequest, cachedResource);
  10816. networkRequest.cached = true;
  10817. networkRequest.requestMethod = "GET";
  10818. this._startNetworkRequest(networkRequest);
  10819. networkRequest.startTime = networkRequest.responseReceivedTime = time;
  10820. this._finishNetworkRequest(networkRequest, time);
  10821. },
  10822. webSocketCreated: function(requestId, requestURL)
  10823. {
  10824. var networkRequest = new WebInspector.NetworkRequest(requestId, requestURL, "", "", "");
  10825. networkRequest.type = WebInspector.resourceTypes.WebSocket;
  10826. this._startNetworkRequest(networkRequest);
  10827. },
  10828. webSocketWillSendHandshakeRequest: function(requestId, time, request)
  10829. {
  10830. var networkRequest = this._inflightRequestsById[requestId];
  10831. if (!networkRequest)
  10832. return;
  10833. networkRequest.requestMethod = "GET";
  10834. networkRequest.requestHeaders = this._headersMapToHeadersArray(request.headers);
  10835. networkRequest.webSocketRequestKey3 = request.requestKey3;
  10836. networkRequest.startTime = time;
  10837. this._updateNetworkRequest(networkRequest);
  10838. },
  10839. webSocketHandshakeResponseReceived: function(requestId, time, response)
  10840. {
  10841. var networkRequest = this._inflightRequestsById[requestId];
  10842. if (!networkRequest)
  10843. return;
  10844. networkRequest.statusCode = response.status;
  10845. networkRequest.statusText = response.statusText;
  10846. networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers);
  10847. networkRequest.webSocketChallengeResponse = response.challengeResponse;
  10848. networkRequest.responseReceivedTime = time;
  10849. this._updateNetworkRequest(networkRequest);
  10850. },
  10851. webSocketFrameReceived: function(requestId, time, response)
  10852. {
  10853. var networkRequest = this._inflightRequestsById[requestId];
  10854. if (!networkRequest)
  10855. return;
  10856. networkRequest.addFrame(response, time);
  10857. networkRequest.responseReceivedTime = time;
  10858. this._updateNetworkRequest(networkRequest);
  10859. },
  10860. webSocketFrameSent: function(requestId, time, response)
  10861. {
  10862. var networkRequest = this._inflightRequestsById[requestId];
  10863. if (!networkRequest)
  10864. return;
  10865. networkRequest.addFrame(response, time, true);
  10866. networkRequest.responseReceivedTime = time;
  10867. this._updateNetworkRequest(networkRequest);
  10868. },
  10869. webSocketFrameError: function(requestId, time, errorMessage)
  10870. {
  10871. var networkRequest = this._inflightRequestsById[requestId];
  10872. if (!networkRequest)
  10873. return;
  10874. networkRequest.addFrameError(errorMessage, time);
  10875. networkRequest.responseReceivedTime = time;
  10876. this._updateNetworkRequest(networkRequest);
  10877. },
  10878. webSocketClosed: function(requestId, time)
  10879. {
  10880. var networkRequest = this._inflightRequestsById[requestId];
  10881. if (!networkRequest)
  10882. return;
  10883. this._finishNetworkRequest(networkRequest, time);
  10884. },
  10885. _appendRedirect: function(requestId, time, redirectURL)
  10886. {
  10887. var originalNetworkRequest = this._inflightRequestsById[requestId];
  10888. var previousRedirects = originalNetworkRequest.redirects || [];
  10889. originalNetworkRequest.requestId = "redirected:" + requestId + "." + previousRedirects.length;
  10890. delete originalNetworkRequest.redirects;
  10891. if (previousRedirects.length > 0)
  10892. originalNetworkRequest.redirectSource = previousRedirects[previousRedirects.length - 1];
  10893. this._finishNetworkRequest(originalNetworkRequest, time);
  10894. var newNetworkRequest = this._createNetworkRequest(requestId, originalNetworkRequest.frameId, originalNetworkRequest.loaderId,
  10895. redirectURL, originalNetworkRequest.documentURL, originalNetworkRequest.initiator);
  10896. newNetworkRequest.redirects = previousRedirects.concat(originalNetworkRequest);
  10897. return newNetworkRequest;
  10898. },
  10899. _startNetworkRequest: function(networkRequest)
  10900. {
  10901. this._inflightRequestsById[networkRequest.requestId] = networkRequest;
  10902. this._inflightRequestsByURL[networkRequest.url] = networkRequest;
  10903. this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestStarted, networkRequest);
  10904. },
  10905. _updateNetworkRequest: function(networkRequest)
  10906. {
  10907. this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdated, networkRequest);
  10908. },
  10909. _finishNetworkRequest: function(networkRequest, finishTime)
  10910. {
  10911. networkRequest.endTime = finishTime;
  10912. networkRequest.finished = true;
  10913. this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestFinished, networkRequest);
  10914. delete this._inflightRequestsById[networkRequest.requestId];
  10915. delete this._inflightRequestsByURL[networkRequest.url];
  10916. },
  10917. _dispatchEventToListeners: function(eventType, networkRequest)
  10918. {
  10919. this._manager.dispatchEventToListeners(eventType, networkRequest);
  10920. },
  10921. _createNetworkRequest: function(requestId, frameId, loaderId, url, documentURL, initiator)
  10922. {
  10923. var networkRequest = new WebInspector.NetworkRequest(requestId, url, documentURL, frameId, loaderId);
  10924. networkRequest.initiator = initiator;
  10925. return networkRequest;
  10926. }
  10927. }
  10928. WebInspector.networkManager = null;
  10929. WebInspector.NavigatorOverlayController = function(panel, parentSplitView, navigatorView, editorView)
  10930. {
  10931. this._panel = panel;
  10932. this._parentSplitView = parentSplitView;
  10933. this._navigatorView = navigatorView;
  10934. this._editorView = editorView;
  10935. this._navigatorSidebarResizeWidgetElement = document.createElement("div");
  10936. this._navigatorSidebarResizeWidgetElement.addStyleClass("scripts-navigator-resizer-widget");
  10937. this._parentSplitView.installResizer(this._navigatorSidebarResizeWidgetElement);
  10938. this._navigatorView.element.appendChild(this._navigatorSidebarResizeWidgetElement);
  10939. this._navigatorShowHideButton = new WebInspector.StatusBarButton(WebInspector.UIString("Hide navigator"), "scripts-navigator-show-hide-button", 3);
  10940. this._navigatorShowHideButton.state = "pinned";
  10941. this._navigatorShowHideButton.addEventListener("click", this._toggleNavigator, this);
  10942. this._editorView.element.appendChild(this._navigatorShowHideButton.element);
  10943. WebInspector.settings.navigatorHidden = WebInspector.settings.createSetting("navigatorHidden", true);
  10944. if (WebInspector.settings.navigatorHidden.get())
  10945. this._toggleNavigator();
  10946. }
  10947. WebInspector.NavigatorOverlayController.prototype = {
  10948. wasShown: function()
  10949. {
  10950. window.setTimeout(this._maybeShowNavigatorOverlay.bind(this), 0);
  10951. },
  10952. _escDownWhileNavigatorOverlayOpen: function(event)
  10953. {
  10954. this.hideNavigatorOverlay();
  10955. },
  10956. _maybeShowNavigatorOverlay: function()
  10957. {
  10958. if (WebInspector.settings.navigatorHidden.get() && !WebInspector.settings.navigatorWasOnceHidden.get())
  10959. this.showNavigatorOverlay();
  10960. },
  10961. _toggleNavigator: function()
  10962. {
  10963. if (this._navigatorShowHideButton.state === "overlay")
  10964. this._pinNavigator();
  10965. else if (this._navigatorShowHideButton.state === "hidden")
  10966. this.showNavigatorOverlay();
  10967. else
  10968. this._hidePinnedNavigator();
  10969. },
  10970. _hidePinnedNavigator: function()
  10971. {
  10972. this._navigatorShowHideButton.state = "hidden";
  10973. this._navigatorShowHideButton.title = WebInspector.UIString("Show navigator");
  10974. this._parentSplitView.element.appendChild(this._navigatorShowHideButton.element);
  10975. this._editorView.element.addStyleClass("navigator-hidden");
  10976. this._navigatorSidebarResizeWidgetElement.addStyleClass("hidden");
  10977. this._parentSplitView.hideSidebarElement();
  10978. this._navigatorView.detach();
  10979. this._editorView.focus();
  10980. WebInspector.settings.navigatorWasOnceHidden.set(true);
  10981. WebInspector.settings.navigatorHidden.set(true);
  10982. },
  10983. _pinNavigator: function()
  10984. {
  10985. this._navigatorShowHideButton.state = "pinned";
  10986. this._navigatorShowHideButton.title = WebInspector.UIString("Hide navigator");
  10987. this._editorView.element.removeStyleClass("navigator-hidden");
  10988. this._navigatorSidebarResizeWidgetElement.removeStyleClass("hidden");
  10989. this._editorView.element.appendChild(this._navigatorShowHideButton.element);
  10990. this._innerHideNavigatorOverlay();
  10991. this._parentSplitView.showSidebarElement();
  10992. this._navigatorView.show(this._parentSplitView.sidebarElement);
  10993. this._navigatorView.focus();
  10994. WebInspector.settings.navigatorHidden.set(false);
  10995. },
  10996. showNavigatorOverlay: function()
  10997. {
  10998. if (this._navigatorShowHideButton.state === "overlay")
  10999. return;
  11000. this._navigatorShowHideButton.state = "overlay";
  11001. this._navigatorShowHideButton.title = WebInspector.UIString("Pin navigator");
  11002. this._sidebarOverlay = new WebInspector.SidebarOverlay(this._navigatorView, "scriptsPanelNavigatorOverlayWidth", Preferences.minScriptsSidebarWidth);
  11003. var navigatorOverlayResizeWidgetElement = document.createElement("div");
  11004. navigatorOverlayResizeWidgetElement.addStyleClass("scripts-navigator-resizer-widget");
  11005. this._sidebarOverlay.resizerWidgetElement = navigatorOverlayResizeWidgetElement;
  11006. this._navigatorView.element.appendChild(this._navigatorShowHideButton.element);
  11007. this._boundContainingElementFocused = this._containingElementFocused.bind(this);
  11008. this._parentSplitView.element.addEventListener("mousedown", this._boundContainingElementFocused, false);
  11009. this._panel.registerShortcut(WebInspector.KeyboardShortcut.Keys.Esc.code, this._escDownWhileNavigatorOverlayOpen.bind(this));
  11010. this._sidebarOverlay.show(this._parentSplitView.element);
  11011. this._navigatorView.focus();
  11012. },
  11013. hideNavigatorOverlay: function()
  11014. {
  11015. if (this._navigatorShowHideButton.state !== "overlay")
  11016. return;
  11017. this._navigatorShowHideButton.state = "hidden";
  11018. this._navigatorShowHideButton.title = WebInspector.UIString("Show navigator");
  11019. this._parentSplitView.element.appendChild(this._navigatorShowHideButton.element);
  11020. this._innerHideNavigatorOverlay();
  11021. this._editorView.focus();
  11022. },
  11023. _innerHideNavigatorOverlay: function()
  11024. {
  11025. this._parentSplitView.element.removeEventListener("mousedown", this._boundContainingElementFocused, false);
  11026. this._panel.unregisterShortcut(WebInspector.KeyboardShortcut.Keys.Esc.code);
  11027. this._sidebarOverlay.hide();
  11028. },
  11029. _containingElementFocused: function(event)
  11030. {
  11031. if (!event.target.isSelfOrDescendant(this._sidebarOverlay.element))
  11032. this.hideNavigatorOverlay();
  11033. },
  11034. isNavigatorPinned: function()
  11035. {
  11036. return this._navigatorShowHideButton.state === "pinned";
  11037. },
  11038. isNavigatorHidden: function()
  11039. {
  11040. return this._navigatorShowHideButton.state === "hidden";
  11041. }
  11042. }
  11043. WebInspector.NavigatorView = function()
  11044. {
  11045. WebInspector.View.call(this);
  11046. this.registerRequiredCSS("navigatorView.css");
  11047. this._treeSearchBoxElement = document.createElement("div");
  11048. this._treeSearchBoxElement.className = "navigator-tree-search-box";
  11049. this.element.appendChild(this._treeSearchBoxElement);
  11050. var scriptsTreeElement = document.createElement("ol");
  11051. this._scriptsTree = new WebInspector.NavigatorTreeOutline(this._treeSearchBoxElement, scriptsTreeElement);
  11052. var scriptsOutlineElement = document.createElement("div");
  11053. scriptsOutlineElement.addStyleClass("outline-disclosure");
  11054. scriptsOutlineElement.addStyleClass("navigator");
  11055. scriptsOutlineElement.appendChild(scriptsTreeElement);
  11056. this.element.addStyleClass("fill");
  11057. this.element.addStyleClass("navigator-container");
  11058. this.element.appendChild(scriptsOutlineElement);
  11059. this.setDefaultFocusedElement(this._scriptsTree.element);
  11060. this._folderTreeElements = {};
  11061. this._scriptTreeElementsByUISourceCode = new Map();
  11062. WebInspector.settings.showScriptFolders.addChangeListener(this._showScriptFoldersSettingChanged.bind(this));
  11063. }
  11064. WebInspector.NavigatorView.Events = {
  11065. ItemSelected: "ItemSelected",
  11066. FileRenamed: "FileRenamed"
  11067. }
  11068. WebInspector.NavigatorView.prototype = {
  11069. addUISourceCode: function(uiSourceCode)
  11070. {
  11071. if (this._scriptTreeElementsByUISourceCode.get(uiSourceCode))
  11072. return;
  11073. var scriptTreeElement = new WebInspector.NavigatorSourceTreeElement(this, uiSourceCode, "");
  11074. this._scriptTreeElementsByUISourceCode.put(uiSourceCode, scriptTreeElement);
  11075. this._updateScriptTitle(uiSourceCode);
  11076. this._addUISourceCodeListeners(uiSourceCode);
  11077. var folderTreeElement = this.getOrCreateFolderTreeElement(uiSourceCode);
  11078. folderTreeElement.appendChild(scriptTreeElement);
  11079. },
  11080. _uiSourceCodeTitleChanged: function(event)
  11081. {
  11082. var uiSourceCode = event.target;
  11083. this._updateScriptTitle(uiSourceCode)
  11084. },
  11085. _uiSourceCodeWorkingCopyChanged: function(event)
  11086. {
  11087. var uiSourceCode = event.target;
  11088. this._updateScriptTitle(uiSourceCode)
  11089. },
  11090. _uiSourceCodeContentChanged: function(event)
  11091. {
  11092. var uiSourceCode = event.target;
  11093. this._updateScriptTitle(uiSourceCode);
  11094. },
  11095. _updateScriptTitle: function(uiSourceCode, ignoreIsDirty)
  11096. {
  11097. var scriptTreeElement = this._scriptTreeElementsByUISourceCode.get(uiSourceCode);
  11098. if (!scriptTreeElement)
  11099. return;
  11100. var titleText;
  11101. if (uiSourceCode.parsedURL.isValid) {
  11102. titleText = uiSourceCode.parsedURL.lastPathComponent;
  11103. if (uiSourceCode.parsedURL.queryParams)
  11104. titleText += "?" + uiSourceCode.parsedURL.queryParams;
  11105. } else if (uiSourceCode.parsedURL)
  11106. titleText = uiSourceCode.parsedURL.url;
  11107. if (!titleText)
  11108. titleText = WebInspector.UIString("(program)");
  11109. if (!ignoreIsDirty && uiSourceCode.isDirty())
  11110. titleText = "*" + titleText;
  11111. scriptTreeElement.titleText = titleText;
  11112. },
  11113. isScriptSourceAdded: function(uiSourceCode)
  11114. {
  11115. var scriptTreeElement = this._scriptTreeElementsByUISourceCode.get(uiSourceCode);
  11116. return !!scriptTreeElement;
  11117. },
  11118. revealUISourceCode: function(uiSourceCode)
  11119. {
  11120. if (this._scriptsTree.selectedTreeElement)
  11121. this._scriptsTree.selectedTreeElement.deselect();
  11122. this._lastSelectedUISourceCode = uiSourceCode;
  11123. var scriptTreeElement = this._scriptTreeElementsByUISourceCode.get(uiSourceCode);
  11124. scriptTreeElement.revealAndSelect(true);
  11125. },
  11126. replaceUISourceCode: function(oldUISourceCode, uiSourceCode)
  11127. {
  11128. var added = false;
  11129. var selected = false;
  11130. if (this._scriptTreeElementsByUISourceCode.get(oldUISourceCode)) {
  11131. added = true;
  11132. if (this._lastSelectedUISourceCode === oldUISourceCode)
  11133. selected = true;
  11134. this._removeUISourceCode(oldUISourceCode);
  11135. }
  11136. if (!added)
  11137. return;
  11138. this.addUISourceCode(uiSourceCode);
  11139. if (selected)
  11140. this.revealUISourceCode(uiSourceCode);
  11141. },
  11142. _scriptSelected: function(uiSourceCode, focusSource)
  11143. {
  11144. this._lastSelectedUISourceCode = uiSourceCode;
  11145. var data = { uiSourceCode: uiSourceCode, focusSource: focusSource};
  11146. this.dispatchEventToListeners(WebInspector.NavigatorView.Events.ItemSelected, data);
  11147. },
  11148. _removeUISourceCode: function(uiSourceCode)
  11149. {
  11150. var treeElement = this._scriptTreeElementsByUISourceCode.get(uiSourceCode);
  11151. while (treeElement) {
  11152. var parent = treeElement.parent;
  11153. if (parent) {
  11154. if (treeElement instanceof WebInspector.NavigatorFolderTreeElement)
  11155. delete this._folderTreeElements[treeElement.folderIdentifier];
  11156. parent.removeChild(treeElement);
  11157. if (parent.children.length)
  11158. break;
  11159. }
  11160. treeElement = parent;
  11161. }
  11162. this._scriptTreeElementsByUISourceCode.remove(uiSourceCode);
  11163. this._removeUISourceCodeListeners(uiSourceCode);
  11164. },
  11165. _addUISourceCodeListeners: function(uiSourceCode)
  11166. {
  11167. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
  11168. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
  11169. uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.ContentChanged, this._uiSourceCodeContentChanged, this);
  11170. },
  11171. _removeUISourceCodeListeners: function(uiSourceCode)
  11172. {
  11173. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.TitleChanged, this._uiSourceCodeTitleChanged, this);
  11174. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._uiSourceCodeWorkingCopyChanged, this);
  11175. uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.ContentChanged, this._uiSourceCodeContentChanged, this);
  11176. },
  11177. _showScriptFoldersSettingChanged: function()
  11178. {
  11179. var uiSourceCodes = this._scriptsTree.scriptTreeElements();
  11180. this.reset();
  11181. for (var i = 0; i < uiSourceCodes.length; ++i)
  11182. this.addUISourceCode(uiSourceCodes[i]);
  11183. if (this._lastSelectedUISourceCode)
  11184. this.revealUISourceCode(this._lastSelectedUISourceCode);
  11185. },
  11186. _fileRenamed: function(uiSourceCode, newTitle)
  11187. {
  11188. var data = { uiSourceCode: uiSourceCode, name: newTitle };
  11189. this.dispatchEventToListeners(WebInspector.NavigatorView.Events.FileRenamed, data);
  11190. },
  11191. rename: function(uiSourceCode, callback)
  11192. {
  11193. var scriptTreeElement = this._scriptTreeElementsByUISourceCode.get(uiSourceCode);
  11194. if (!scriptTreeElement)
  11195. return;
  11196. WebInspector.markBeingEdited(scriptTreeElement.treeOutline.element, true);
  11197. function commitHandler(element, newTitle, oldTitle)
  11198. {
  11199. if (newTitle && newTitle !== oldTitle)
  11200. this._fileRenamed(uiSourceCode, newTitle);
  11201. else
  11202. this._updateScriptTitle(uiSourceCode);
  11203. afterEditing(true);
  11204. }
  11205. function cancelHandler()
  11206. {
  11207. afterEditing(false);
  11208. }
  11209. function afterEditing(committed)
  11210. {
  11211. WebInspector.markBeingEdited(scriptTreeElement.treeOutline.element, false);
  11212. if (callback)
  11213. callback(committed);
  11214. }
  11215. var editingConfig = new WebInspector.EditingConfig(commitHandler.bind(this), cancelHandler.bind(this));
  11216. this._updateScriptTitle(uiSourceCode, true);
  11217. WebInspector.startEditing(scriptTreeElement.titleElement, editingConfig);
  11218. window.getSelection().setBaseAndExtent(scriptTreeElement.titleElement, 0, scriptTreeElement.titleElement, 1);
  11219. },
  11220. reset: function()
  11221. {
  11222. var uiSourceCodes = this._scriptsTree.scriptTreeElements;
  11223. for (var i = 0; i < uiSourceCodes.length; ++i)
  11224. this._removeUISourceCodeListeners(uiSourceCodes[i]);
  11225. this._scriptsTree.stopSearch();
  11226. this._scriptsTree.removeChildren();
  11227. this._folderTreeElements = {};
  11228. this._scriptTreeElementsByUISourceCode.clear();
  11229. },
  11230. createFolderTreeElement: function(parentFolderElement, folderIdentifier, domain, folderName)
  11231. {
  11232. var folderTreeElement = new WebInspector.NavigatorFolderTreeElement(folderIdentifier, domain, folderName);
  11233. parentFolderElement.appendChild(folderTreeElement);
  11234. this._folderTreeElements[folderIdentifier] = folderTreeElement;
  11235. return folderTreeElement;
  11236. },
  11237. getOrCreateFolderTreeElement: function(uiSourceCode)
  11238. {
  11239. return this._getOrCreateFolderTreeElement(uiSourceCode.parsedURL.host, uiSourceCode.parsedURL.folderPathComponents);
  11240. },
  11241. _getOrCreateFolderTreeElement: function(domain, folderName)
  11242. {
  11243. var folderIdentifier = domain + "/" + folderName;
  11244. if (this._folderTreeElements[folderIdentifier])
  11245. return this._folderTreeElements[folderIdentifier];
  11246. var showScriptFolders = WebInspector.settings.showScriptFolders.get();
  11247. if ((!domain && !folderName) || !showScriptFolders)
  11248. return this._scriptsTree;
  11249. var parentFolderElement;
  11250. if (!folderName)
  11251. parentFolderElement = this._scriptsTree;
  11252. else
  11253. parentFolderElement = this._getOrCreateFolderTreeElement(domain, "");
  11254. return this.createFolderTreeElement(parentFolderElement, folderIdentifier, domain, folderName);
  11255. },
  11256. handleContextMenu: function(event, uiSourceCode)
  11257. {
  11258. }
  11259. }
  11260. WebInspector.NavigatorView.prototype.__proto__ = WebInspector.View.prototype;
  11261. WebInspector.NavigatorTreeOutline = function(treeSearchBoxElement, element)
  11262. {
  11263. TreeOutline.call(this, element);
  11264. this.element = element;
  11265. this._treeSearchBoxElement = treeSearchBoxElement;
  11266. this.comparator = WebInspector.NavigatorTreeOutline._treeElementsCompare;
  11267. this.searchable = true;
  11268. this.searchInputElement = document.createElement("input");
  11269. }
  11270. WebInspector.NavigatorTreeOutline._treeElementsCompare = function compare(treeElement1, treeElement2)
  11271. {
  11272. function typeWeight(treeElement)
  11273. {
  11274. if (treeElement instanceof WebInspector.NavigatorFolderTreeElement) {
  11275. if (treeElement.isDomain)
  11276. return 1;
  11277. return 2;
  11278. }
  11279. return 3;
  11280. }
  11281. var typeWeight1 = typeWeight(treeElement1);
  11282. var typeWeight2 = typeWeight(treeElement2);
  11283. var result;
  11284. if (typeWeight1 > typeWeight2)
  11285. result = 1;
  11286. else if (typeWeight1 < typeWeight2)
  11287. result = -1;
  11288. else {
  11289. var title1 = treeElement1.titleText;
  11290. var title2 = treeElement2.titleText;
  11291. result = title1.localeCompare(title2);
  11292. }
  11293. return result;
  11294. }
  11295. WebInspector.NavigatorTreeOutline.prototype = {
  11296. scriptTreeElements: function()
  11297. {
  11298. var result = [];
  11299. if (this.children.length) {
  11300. for (var treeElement = this.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this, true)) {
  11301. if (treeElement instanceof WebInspector.NavigatorSourceTreeElement)
  11302. result.push(treeElement.uiSourceCode);
  11303. }
  11304. }
  11305. return result;
  11306. },
  11307. searchStarted: function()
  11308. {
  11309. this._treeSearchBoxElement.appendChild(this.searchInputElement);
  11310. this._treeSearchBoxElement.addStyleClass("visible");
  11311. },
  11312. searchFinished: function()
  11313. {
  11314. this._treeSearchBoxElement.removeChild(this.searchInputElement);
  11315. this._treeSearchBoxElement.removeStyleClass("visible");
  11316. }
  11317. }
  11318. WebInspector.NavigatorTreeOutline.prototype.__proto__ = TreeOutline.prototype;
  11319. WebInspector.BaseNavigatorTreeElement = function(title, iconClasses, hasChildren, noIcon)
  11320. {
  11321. TreeElement.call(this, "", null, hasChildren);
  11322. this._titleText = title;
  11323. this._iconClasses = iconClasses;
  11324. this._noIcon = noIcon;
  11325. }
  11326. WebInspector.BaseNavigatorTreeElement.prototype = {
  11327. onattach: function()
  11328. {
  11329. this.listItemElement.removeChildren();
  11330. if (this._iconClasses) {
  11331. for (var i = 0; i < this._iconClasses.length; ++i)
  11332. this.listItemElement.addStyleClass(this._iconClasses[i]);
  11333. }
  11334. var selectionElement = document.createElement("div");
  11335. selectionElement.className = "selection";
  11336. this.listItemElement.appendChild(selectionElement);
  11337. if (!this._noIcon) {
  11338. this.imageElement = document.createElement("img");
  11339. this.imageElement.className = "icon";
  11340. this.listItemElement.appendChild(this.imageElement);
  11341. }
  11342. this.titleElement = document.createElement("div");
  11343. this.titleElement.className = "base-navigator-tree-element-title";
  11344. this._titleTextNode = document.createTextNode("");
  11345. this._titleTextNode.textContent = this._titleText;
  11346. this.titleElement.appendChild(this._titleTextNode);
  11347. this.listItemElement.appendChild(this.titleElement);
  11348. this.expand();
  11349. },
  11350. onreveal: function()
  11351. {
  11352. if (this.listItemElement)
  11353. this.listItemElement.scrollIntoViewIfNeeded(true);
  11354. },
  11355. get titleText()
  11356. {
  11357. return this._titleText;
  11358. },
  11359. set titleText(titleText)
  11360. {
  11361. this._titleText = titleText || "";
  11362. if (this.titleElement)
  11363. this.titleElement.textContent = this._titleText;
  11364. },
  11365. matchesSearchText: function(searchText)
  11366. {
  11367. return this.titleText.match(new RegExp("^" + searchText.escapeForRegExp(), "i"));
  11368. }
  11369. }
  11370. WebInspector.BaseNavigatorTreeElement.prototype.__proto__ = TreeElement.prototype;
  11371. WebInspector.NavigatorFolderTreeElement = function(folderIdentifier, domain, folderName)
  11372. {
  11373. this._folderIdentifier = folderIdentifier;
  11374. this._folderName = folderName;
  11375. var iconClass = this.isDomain ? "navigator-domain-tree-item" : "navigator-folder-tree-item";
  11376. var title = this.isDomain ? domain : folderName.substring(1);
  11377. WebInspector.BaseNavigatorTreeElement.call(this, title, [iconClass], true);
  11378. this.tooltip = folderName;
  11379. }
  11380. WebInspector.NavigatorFolderTreeElement.prototype = {
  11381. get folderIdentifier()
  11382. {
  11383. return this._folderIdentifier;
  11384. },
  11385. get isDomain()
  11386. {
  11387. return this._folderName === "";
  11388. },
  11389. onattach: function()
  11390. {
  11391. WebInspector.BaseNavigatorTreeElement.prototype.onattach.call(this);
  11392. if (this._isDomain)
  11393. this.collapse();
  11394. else
  11395. this.expand();
  11396. }
  11397. }
  11398. WebInspector.NavigatorFolderTreeElement.prototype.__proto__ = WebInspector.BaseNavigatorTreeElement.prototype;
  11399. WebInspector.NavigatorSourceTreeElement = function(navigatorView, uiSourceCode, title)
  11400. {
  11401. WebInspector.BaseNavigatorTreeElement.call(this, title, ["navigator-" + uiSourceCode.contentType().name() + "-tree-item"], false);
  11402. this._navigatorView = navigatorView;
  11403. this._uiSourceCode = uiSourceCode;
  11404. this.tooltip = uiSourceCode.url;
  11405. }
  11406. WebInspector.NavigatorSourceTreeElement.prototype = {
  11407. get uiSourceCode()
  11408. {
  11409. return this._uiSourceCode;
  11410. },
  11411. onattach: function()
  11412. {
  11413. WebInspector.BaseNavigatorTreeElement.prototype.onattach.call(this);
  11414. this.listItemElement.addEventListener("click", this._onclick.bind(this), false);
  11415. this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
  11416. },
  11417. onspace: function()
  11418. {
  11419. this._navigatorView._scriptSelected(this.uiSourceCode, true);
  11420. return true;
  11421. },
  11422. _onclick: function(event)
  11423. {
  11424. this._navigatorView._scriptSelected(this.uiSourceCode, false);
  11425. },
  11426. ondblclick: function()
  11427. {
  11428. this._navigatorView._scriptSelected(this.uiSourceCode, true);
  11429. },
  11430. onenter: function()
  11431. {
  11432. this._navigatorView._scriptSelected(this.uiSourceCode, true);
  11433. return true;
  11434. },
  11435. _handleContextMenuEvent: function(event)
  11436. {
  11437. this._navigatorView.handleContextMenu(event, this._uiSourceCode);
  11438. }
  11439. }
  11440. WebInspector.NavigatorSourceTreeElement.prototype.__proto__ = WebInspector.BaseNavigatorTreeElement.prototype;
  11441. WebInspector.NetworkLog = function()
  11442. {
  11443. this._requests = [];
  11444. WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
  11445. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._onMainFrameNavigated, this);
  11446. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.OnLoad, this._onLoad, this);
  11447. WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._onDOMContentLoaded, this);
  11448. }
  11449. WebInspector.NetworkLog.prototype = {
  11450. get requests()
  11451. {
  11452. return this._requests;
  11453. },
  11454. pageLoadForRequest: function(request)
  11455. {
  11456. return request.__page;
  11457. },
  11458. _onMainFrameNavigated: function(event)
  11459. {
  11460. var mainFrame = event.data;
  11461. this._currentPageLoad = null;
  11462. var oldRequests = this._requests.splice(0, this._requests.length);
  11463. for (var i = 0; i < oldRequests.length; ++i) {
  11464. var request = oldRequests[i];
  11465. if (request.loaderId === mainFrame.loaderId) {
  11466. if (!this._currentPageLoad)
  11467. this._currentPageLoad = new WebInspector.PageLoad(request);
  11468. this._requests.push(request);
  11469. request.__page = this._currentPageLoad;
  11470. }
  11471. }
  11472. },
  11473. _onRequestStarted: function(event)
  11474. {
  11475. var request = event.data;
  11476. this._requests.push(request);
  11477. request.__page = this._currentPageLoad;
  11478. },
  11479. _onDOMContentLoaded: function(event)
  11480. {
  11481. if (this._currentPageLoad)
  11482. this._currentPageLoad.contentLoadTime = event.data;
  11483. },
  11484. _onLoad: function(event)
  11485. {
  11486. if (this._currentPageLoad)
  11487. this._currentPageLoad.loadTime = event.data;
  11488. }
  11489. }
  11490. WebInspector.networkLog = null;
  11491. WebInspector.PageLoad = function(mainRequest)
  11492. {
  11493. this.id = ++WebInspector.PageLoad._lastIdentifier;
  11494. this.url = mainRequest.url;
  11495. this.startTime = mainRequest.startTime;
  11496. }
  11497. WebInspector.PageLoad._lastIdentifier = 0;
  11498. WebInspector.ResourceTreeModel = function(networkManager)
  11499. {
  11500. networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceTrackingEnabled, this._onResourceTrackingEnabled, this);
  11501. networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdated, this._onRequestUpdated, this);
  11502. networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestUpdated, this);
  11503. networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, this._onRequestUpdateDropped, this);
  11504. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
  11505. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._consoleMessageAdded, this);
  11506. WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
  11507. PageAgent.enable();
  11508. NetworkAgent.enable();
  11509. this._fetchResourceTree();
  11510. InspectorBackend.registerPageDispatcher(new WebInspector.PageDispatcher(this));
  11511. this._pendingConsoleMessages = {};
  11512. }
  11513. WebInspector.ResourceTreeModel.EventTypes = {
  11514. FrameAdded: "FrameAdded",
  11515. FrameNavigated: "FrameNavigated",
  11516. FrameDetached: "FrameDetached",
  11517. MainFrameNavigated: "MainFrameNavigated",
  11518. ResourceAdded: "ResourceAdded",
  11519. ResourceContentCommitted: "resource-content-committed",
  11520. WillLoadCachedResources: "WillLoadCachedResources",
  11521. CachedResourcesLoaded: "CachedResourcesLoaded",
  11522. DOMContentLoaded: "DOMContentLoaded",
  11523. OnLoad: "OnLoad",
  11524. InspectedURLChanged: "InspectedURLChanged"
  11525. }
  11526. WebInspector.ResourceTreeModel.prototype = {
  11527. _onResourceTrackingEnabled: function()
  11528. {
  11529. this._fetchResourceTree();
  11530. },
  11531. _fetchResourceTree: function()
  11532. {
  11533. this._frames = {};
  11534. delete this._cachedResourcesProcessed;
  11535. PageAgent.getResourceTree(this._processCachedResources.bind(this));
  11536. },
  11537. _processCachedResources: function(error, mainFramePayload)
  11538. {
  11539. if (error) {
  11540. console.error(JSON.stringify(error));
  11541. return;
  11542. }
  11543. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources);
  11544. WebInspector.inspectedPageURL = mainFramePayload.frame.url;
  11545. this._addFramesRecursively(null, mainFramePayload);
  11546. this._dispatchInspectedURLChanged();
  11547. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded);
  11548. WebInspector.Resource.restoreRevisions();
  11549. this._cachedResourcesProcessed = true;
  11550. },
  11551. _dispatchInspectedURLChanged: function()
  11552. {
  11553. InspectorFrontendHost.inspectedURLChanged(WebInspector.inspectedPageURL);
  11554. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, WebInspector.inspectedPageURL);
  11555. },
  11556. _addFrame: function(frame)
  11557. {
  11558. this._frames[frame.id] = frame;
  11559. if (frame.isMainFrame())
  11560. this.mainFrame = frame;
  11561. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, frame);
  11562. },
  11563. _frameNavigated: function(framePayload)
  11564. {
  11565. if (this._frontendReused(framePayload))
  11566. return;
  11567. if (!this._cachedResourcesProcessed)
  11568. return;
  11569. var frame = this._frames[framePayload.id];
  11570. if (frame) {
  11571. frame._navigate(framePayload);
  11572. } else {
  11573. var parentFrame = this._frames[framePayload.parentId];
  11574. frame = new WebInspector.ResourceTreeFrame(this, parentFrame, framePayload);
  11575. if (frame.isMainFrame() && this.mainFrame) {
  11576. this._frameDetached(this.mainFrame.id);
  11577. }
  11578. this._addFrame(frame);
  11579. }
  11580. if (frame.isMainFrame())
  11581. WebInspector.inspectedPageURL = frame.url;
  11582. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, frame);
  11583. if (frame.isMainFrame())
  11584. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, frame);
  11585. var resources = frame.resources();
  11586. for (var i = 0; i < resources.length; ++i)
  11587. this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resources[i]);
  11588. if (frame.isMainFrame())
  11589. this._dispatchInspectedURLChanged();
  11590. },
  11591. _frontendReused: function(framePayload)
  11592. {
  11593. if (!framePayload.parentId && !WebInspector.networkLog.requests.length) {
  11594. this._fetchResourceTree();
  11595. return true;
  11596. }
  11597. return false;
  11598. },
  11599. _frameDetached: function(frameId)
  11600. {
  11601. if (!this._cachedResourcesProcessed)
  11602. return;
  11603. var frame = this._frames[frameId];
  11604. if (!frame)
  11605. return;
  11606. if (frame.parentFrame)
  11607. frame.parentFrame._removeChildFrame(frame);
  11608. else
  11609. frame._remove();
  11610. },
  11611. _onRequestUpdated: function(event)
  11612. {
  11613. if (!this._cachedResourcesProcessed)
  11614. return;
  11615. var request = event.data;
  11616. if (request.failed || request.type === WebInspector.resourceTypes.XHR)
  11617. return;
  11618. var frame = this._frames[request.frameId];
  11619. if (frame) {
  11620. var resource = frame._addRequest(request);
  11621. this._addPendingConsoleMessagesToResource(resource);
  11622. }
  11623. },
  11624. _onRequestUpdateDropped: function(event)
  11625. {
  11626. if (!this._cachedResourcesProcessed)
  11627. return;
  11628. var frameId = event.data.frameId;
  11629. var frame = this._frames[frameId];
  11630. if (!frame)
  11631. return;
  11632. var url = event.data.url;
  11633. if (frame._resourcesMap[url])
  11634. return;
  11635. var resource = new WebInspector.Resource(null, url, frame.url, frameId, event.data.loaderId, WebInspector.resourceTypes[event.data.resourceType], event.data.mimeType);
  11636. frame._addResource(resource);
  11637. },
  11638. frameForId: function(frameId)
  11639. {
  11640. return this._frames[frameId];
  11641. },
  11642. forAllResources: function(callback)
  11643. {
  11644. if (this.mainFrame)
  11645. return this.mainFrame._callForFrameResources(callback);
  11646. return false;
  11647. },
  11648. _consoleMessageAdded: function(event)
  11649. {
  11650. var msg = event.data;
  11651. var resource = msg.url ? this.resourceForURL(msg.url) : null;
  11652. if (resource)
  11653. this._addConsoleMessageToResource(msg, resource);
  11654. else
  11655. this._addPendingConsoleMessage(msg);
  11656. },
  11657. _addPendingConsoleMessage: function(msg)
  11658. {
  11659. if (!msg.url)
  11660. return;
  11661. if (!this._pendingConsoleMessages[msg.url])
  11662. this._pendingConsoleMessages[msg.url] = [];
  11663. this._pendingConsoleMessages[msg.url].push(msg);
  11664. },
  11665. _addPendingConsoleMessagesToResource: function(resource)
  11666. {
  11667. var messages = this._pendingConsoleMessages[resource.url];
  11668. if (messages) {
  11669. for (var i = 0; i < messages.length; i++)
  11670. this._addConsoleMessageToResource(messages[i], resource);
  11671. delete this._pendingConsoleMessages[resource.url];
  11672. }
  11673. },
  11674. _addConsoleMessageToResource: function(msg, resource)
  11675. {
  11676. switch (msg.level) {
  11677. case WebInspector.ConsoleMessage.MessageLevel.Warning:
  11678. resource.warnings += msg.repeatDelta;
  11679. break;
  11680. case WebInspector.ConsoleMessage.MessageLevel.Error:
  11681. resource.errors += msg.repeatDelta;
  11682. break;
  11683. }
  11684. resource.addMessage(msg);
  11685. },
  11686. _consoleCleared: function()
  11687. {
  11688. function callback(resource)
  11689. {
  11690. resource.clearErrorsAndWarnings();
  11691. }
  11692. this._pendingConsoleMessages = {};
  11693. this.forAllResources(callback);
  11694. },
  11695. resourceForURL: function(url)
  11696. {
  11697. return this.mainFrame ? this.mainFrame.resourceForURL(url) : null;
  11698. },
  11699. _addFramesRecursively: function(parentFrame, frameTreePayload)
  11700. {
  11701. var framePayload = frameTreePayload.frame;
  11702. var frame = new WebInspector.ResourceTreeFrame(this, parentFrame, framePayload);
  11703. var frameResource = this._createResourceFromFramePayload(framePayload, framePayload.url, WebInspector.resourceTypes.Document, framePayload.mimeType);
  11704. if (frame.isMainFrame())
  11705. WebInspector.inspectedPageURL = frameResource.url;
  11706. this._addFrame(frame);
  11707. frame._addResource(frameResource);
  11708. for (var i = 0; frameTreePayload.childFrames && i < frameTreePayload.childFrames.length; ++i)
  11709. this._addFramesRecursively(frame, frameTreePayload.childFrames[i]);
  11710. if (!frameTreePayload.resources)
  11711. return;
  11712. for (var i = 0; i < frameTreePayload.resources.length; ++i) {
  11713. var subresource = frameTreePayload.resources[i];
  11714. var resource = this._createResourceFromFramePayload(framePayload, subresource.url, WebInspector.resourceTypes[subresource.type], subresource.mimeType);
  11715. frame._addResource(resource);
  11716. }
  11717. },
  11718. _createResourceFromFramePayload: function(frame, url, type, mimeType)
  11719. {
  11720. return new WebInspector.Resource(null, url, frame.url, frame.id, frame.loaderId, type, mimeType);
  11721. }
  11722. }
  11723. WebInspector.ResourceTreeModel.prototype.__proto__ = WebInspector.Object.prototype;
  11724. WebInspector.ResourceTreeFrame = function(model, parentFrame, payload)
  11725. {
  11726. this._model = model;
  11727. this._parentFrame = parentFrame;
  11728. this._id = payload.id;
  11729. this._loaderId = payload.loaderId;
  11730. this._name = payload.name;
  11731. this._url = payload.url;
  11732. this._securityOrigin = payload.securityOrigin || "";
  11733. this._mimeType = payload.mimeType;
  11734. this._childFrames = [];
  11735. this._resourcesMap = {};
  11736. if (this._parentFrame)
  11737. this._parentFrame._childFrames.push(this);
  11738. }
  11739. WebInspector.ResourceTreeFrame.prototype = {
  11740. get id()
  11741. {
  11742. return this._id;
  11743. },
  11744. get name()
  11745. {
  11746. return this._name || "";
  11747. },
  11748. get url()
  11749. {
  11750. return this._url;
  11751. },
  11752. get securityOrigin()
  11753. {
  11754. return this._securityOrigin;
  11755. },
  11756. get loaderId()
  11757. {
  11758. return this._loaderId;
  11759. },
  11760. get parentFrame()
  11761. {
  11762. return this._parentFrame;
  11763. },
  11764. get childFrames()
  11765. {
  11766. return this._childFrames;
  11767. },
  11768. isMainFrame: function()
  11769. {
  11770. return !this._parentFrame;
  11771. },
  11772. _navigate: function(framePayload)
  11773. {
  11774. this._loaderId = framePayload.loaderId;
  11775. this._name = framePayload.name;
  11776. this._url = framePayload.url;
  11777. this._securityOrigin = framePayload.securityOrigin || "";
  11778. this._mimeType = framePayload.mimeType;
  11779. var mainResource = this._resourcesMap[this._url];
  11780. this._resourcesMap = {};
  11781. this._removeChildFrames();
  11782. if (mainResource && mainResource.loaderId === this._loaderId)
  11783. this._addResource(mainResource);
  11784. },
  11785. get mainResource()
  11786. {
  11787. return this._resourcesMap[this._url];
  11788. },
  11789. _removeChildFrame: function(frame)
  11790. {
  11791. this._childFrames.remove(frame);
  11792. frame._remove();
  11793. },
  11794. _removeChildFrames: function()
  11795. {
  11796. var copy = this._childFrames.slice();
  11797. for (var i = 0; i < copy.length; ++i)
  11798. this._removeChildFrame(copy[i]);
  11799. },
  11800. _remove: function()
  11801. {
  11802. this._removeChildFrames();
  11803. delete this._model._frames[this.id];
  11804. this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this);
  11805. },
  11806. _addResource: function(resource)
  11807. {
  11808. if (this._resourcesMap[resource.url] === resource) {
  11809. return;
  11810. }
  11811. this._resourcesMap[resource.url] = resource;
  11812. this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource);
  11813. },
  11814. _addRequest: function(request)
  11815. {
  11816. var resource = this._resourcesMap[request.url];
  11817. if (resource && resource.request === request) {
  11818. return resource;
  11819. }
  11820. resource = new WebInspector.Resource(request, request.url, request.documentURL, request.frameId, request.loaderId, request.type, request.mimeType);
  11821. this._resourcesMap[resource.url] = resource;
  11822. this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource);
  11823. return resource;
  11824. },
  11825. resources: function()
  11826. {
  11827. var result = [];
  11828. for (var url in this._resourcesMap)
  11829. result.push(this._resourcesMap[url]);
  11830. return result;
  11831. },
  11832. resourceForURL: function(url)
  11833. {
  11834. var result;
  11835. function filter(resource)
  11836. {
  11837. if (resource.url === url) {
  11838. result = resource;
  11839. return true;
  11840. }
  11841. }
  11842. this._callForFrameResources(filter);
  11843. return result;
  11844. },
  11845. _callForFrameResources: function(callback)
  11846. {
  11847. for (var url in this._resourcesMap) {
  11848. if (callback(this._resourcesMap[url]))
  11849. return true;
  11850. }
  11851. for (var i = 0; i < this._childFrames.length; ++i) {
  11852. if (this._childFrames[i]._callForFrameResources(callback))
  11853. return true;
  11854. }
  11855. return false;
  11856. }
  11857. }
  11858. WebInspector.PageDispatcher = function(resourceTreeModel)
  11859. {
  11860. this._resourceTreeModel = resourceTreeModel;
  11861. }
  11862. WebInspector.PageDispatcher.prototype = {
  11863. domContentEventFired: function(time)
  11864. {
  11865. this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, time);
  11866. },
  11867. loadEventFired: function(time)
  11868. {
  11869. this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.OnLoad, time);
  11870. },
  11871. frameNavigated: function(frame)
  11872. {
  11873. this._resourceTreeModel._frameNavigated(frame);
  11874. },
  11875. frameDetached: function(frameId)
  11876. {
  11877. this._resourceTreeModel._frameDetached(frameId);
  11878. }
  11879. }
  11880. WebInspector.resourceTreeModel = null;
  11881. WebInspector.ParsedURL = function(url)
  11882. {
  11883. this.isValid = false;
  11884. this.url = url;
  11885. this.scheme = "";
  11886. this.host = "";
  11887. this.port = "";
  11888. this.path = "";
  11889. this.queryParams = "";
  11890. this.fragment = "";
  11891. this.folderPathComponents = "";
  11892. this.lastPathComponent = "";
  11893. var match = url.match(/^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i);
  11894. if (match) {
  11895. this.isValid = true;
  11896. this.scheme = match[1].toLowerCase();
  11897. this.host = match[2];
  11898. this.port = match[3];
  11899. this.path = match[4] || "/";
  11900. this.fragment = match[5];
  11901. } else {
  11902. if (this.url.startsWith("data:")) {
  11903. this.scheme = "data";
  11904. return;
  11905. }
  11906. if (this.url === "about:blank") {
  11907. this.scheme = "about";
  11908. return;
  11909. }
  11910. this.path = this.url;
  11911. }
  11912. if (this.path) {
  11913. var path = this.path;
  11914. var indexOfQuery = path.indexOf("?");
  11915. if (indexOfQuery !== -1) {
  11916. this.queryParams = path.substring(indexOfQuery + 1)
  11917. path = path.substring(0, indexOfQuery);
  11918. }
  11919. var lastSlashIndex = path.lastIndexOf("/");
  11920. if (lastSlashIndex !== -1) {
  11921. this.folderPathComponents = path.substring(0, lastSlashIndex);
  11922. this.lastPathComponent = path.substring(lastSlashIndex + 1);
  11923. } else
  11924. this.lastPathComponent = path;
  11925. }
  11926. }
  11927. WebInspector.ParsedURL.prototype = {
  11928. get displayName()
  11929. {
  11930. if (this._displayName)
  11931. return this._displayName;
  11932. if (this.scheme === "data") {
  11933. this._displayName = this.url.trimEnd(20);
  11934. return this._displayName;
  11935. }
  11936. if (this.url === "about:blank")
  11937. return this.url;
  11938. this._displayName = this.lastPathComponent;
  11939. if (!this._displayName)
  11940. this._displayName = WebInspector.displayDomain(this.host);
  11941. if (!this._displayName && this.url)
  11942. this._displayName = this.url.trimURL(WebInspector.inspectedPageDomain ? WebInspector.inspectedPageDomain : "");
  11943. if (this._displayName === "/")
  11944. this._displayName = this.url;
  11945. return this._displayName;
  11946. }
  11947. }
  11948. String.prototype.asParsedURL = function()
  11949. {
  11950. var parsedURL = new WebInspector.ParsedURL(this.toString());
  11951. if (parsedURL.isValid)
  11952. return parsedURL;
  11953. return null;
  11954. }
  11955. WebInspector.resourceForURL = function(url)
  11956. {
  11957. return WebInspector.resourceTreeModel.resourceForURL(url);
  11958. }
  11959. WebInspector.forAllResources = function(callback)
  11960. {
  11961. WebInspector.resourceTreeModel.forAllResources(callback);
  11962. }
  11963. WebInspector.displayDomain = function(host)
  11964. {
  11965. if (host && (!WebInspector.inspectedPageDomain || (WebInspector.inspectedPageDomain && host !== WebInspector.inspectedPageDomain)))
  11966. return host;
  11967. return "";
  11968. }
  11969. WebInspector.displayNameForURL = function(url)
  11970. {
  11971. if (!url)
  11972. return "";
  11973. var resource = WebInspector.resourceForURL(url);
  11974. if (resource)
  11975. return resource.displayName;
  11976. if (!WebInspector.inspectedPageURL)
  11977. return url.trimURL("");
  11978. var parsedURL = WebInspector.inspectedPageURL.asParsedURL();
  11979. var lastPathComponent = parsedURL.lastPathComponent;
  11980. var index = WebInspector.inspectedPageURL.indexOf(lastPathComponent);
  11981. if (index !== -1 && index + lastPathComponent.length === WebInspector.inspectedPageURL.length) {
  11982. var baseURL = WebInspector.inspectedPageURL.substring(0, index);
  11983. if (url.startsWith(baseURL))
  11984. return url.substring(index);
  11985. }
  11986. return url.trimURL(parsedURL.host);
  11987. }
  11988. WebInspector.linkifyStringAsFragmentWithCustomLinkifier = function(string, linkifier)
  11989. {
  11990. var container = document.createDocumentFragment();
  11991. var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|www\.)[\w$\-_+*'=\|\/\\(){}[\]%@&#~,:;.!?]{2,}[\w$\-_+*=\|\/\\({%@&#~]/;
  11992. var lineColumnRegEx = /:(\d+)(:(\d+))?$/;
  11993. while (string) {
  11994. var linkString = linkStringRegEx.exec(string);
  11995. if (!linkString)
  11996. break;
  11997. linkString = linkString[0];
  11998. var linkIndex = string.indexOf(linkString);
  11999. var nonLink = string.substring(0, linkIndex);
  12000. container.appendChild(document.createTextNode(nonLink));
  12001. var title = linkString;
  12002. var realURL = (linkString.startsWith("www.") ? "http://" + linkString : linkString);
  12003. var lineColumnMatch = lineColumnRegEx.exec(realURL);
  12004. if (lineColumnMatch)
  12005. realURL = realURL.substring(0, realURL.length - lineColumnMatch[0].length);
  12006. var linkNode = linkifier(title, realURL, lineColumnMatch ? lineColumnMatch[1] : undefined);
  12007. container.appendChild(linkNode);
  12008. string = string.substring(linkIndex + linkString.length, string.length);
  12009. }
  12010. if (string)
  12011. container.appendChild(document.createTextNode(string));
  12012. return container;
  12013. }
  12014. WebInspector._linkifierPlugins = [];
  12015. /**
  12016. * @param {function(string):string} plugin
  12017. */
  12018. WebInspector.registerLinkifierPlugin = function(plugin)
  12019. {
  12020. WebInspector._linkifierPlugins.push(plugin);
  12021. }
  12022. /**
  12023. * @param {string} string
  12024. * @return {DocumentFragment}
  12025. */
  12026. WebInspector.linkifyStringAsFragment = function(string)
  12027. {
  12028. /**
  12029. * @param {string} title
  12030. * @param {string} url
  12031. * @param {string=} lineNumber
  12032. * @return {Node}
  12033. */
  12034. function linkifier(title, url, lineNumber)
  12035. {
  12036. for (var i = 0; i < WebInspector._linkifierPlugins.length; ++i)
  12037. title = WebInspector._linkifierPlugins[i](title);
  12038. var isExternal = !WebInspector.resourceForURL(url);
  12039. var urlNode = WebInspector.linkifyURLAsNode(url, title, undefined, isExternal);
  12040. if (typeof(lineNumber) !== "undefined") {
  12041. urlNode.lineNumber = lineNumber;
  12042. urlNode.preferredPanel = "scripts";
  12043. }
  12044. return urlNode;
  12045. }
  12046. return WebInspector.linkifyStringAsFragmentWithCustomLinkifier(string, linkifier);
  12047. }
  12048. /**
  12049. * @param {string} url
  12050. * @param {string=} linkText
  12051. * @param {string=} classes
  12052. * @param {boolean=} isExternal
  12053. * @param {string=} tooltipText
  12054. * @return {Element}
  12055. */
  12056. WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, tooltipText)
  12057. {
  12058. if (!linkText)
  12059. linkText = url;
  12060. classes = (classes ? classes + " " : "");
  12061. classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link";
  12062. var a = document.createElement("a");
  12063. a.href = url;
  12064. a.className = classes;
  12065. if (typeof tooltipText === "undefined")
  12066. a.title = url;
  12067. else if (typeof tooltipText !== "string" || tooltipText.length)
  12068. a.title = tooltipText;
  12069. a.textContent = linkText;
  12070. a.style.maxWidth = "100%";
  12071. if (isExternal)
  12072. a.setAttribute("target", "_blank");
  12073. return a;
  12074. }
  12075. /**
  12076. * @param {string} url
  12077. * @param {number=} lineNumber
  12078. * @return {string}
  12079. */
  12080. WebInspector.formatLinkText = function(url, lineNumber)
  12081. {
  12082. var text = WebInspector.displayNameForURL(url);
  12083. if (typeof lineNumber === "number")
  12084. text += ":" + (lineNumber + 1);
  12085. return text;
  12086. }
  12087. /**
  12088. * @param {string} url
  12089. * @param {number=} lineNumber
  12090. * @param {string=} classes
  12091. * @param {string=} tooltipText
  12092. * @return {Element}
  12093. */
  12094. WebInspector.linkifyResourceAsNode = function(url, lineNumber, classes, tooltipText)
  12095. {
  12096. var linkText = WebInspector.formatLinkText(url, lineNumber);
  12097. var anchor = WebInspector.linkifyURLAsNode(url, linkText, classes, false, tooltipText);
  12098. anchor.preferredPanel = "resources";
  12099. anchor.lineNumber = lineNumber;
  12100. return anchor;
  12101. }
  12102. /**
  12103. * @param {WebInspector.NetworkRequest} request
  12104. * @param {string=} classes
  12105. * @return {Element}
  12106. */
  12107. WebInspector.linkifyRequestAsNode = function(request, classes)
  12108. {
  12109. var anchor = WebInspector.linkifyURLAsNode(request.url);
  12110. anchor.preferredPanel = "network";
  12111. anchor.requestId = request.requestId;
  12112. return anchor;
  12113. }
  12114. /**
  12115. * @return {?string} null if the specified resource MUST NOT have a URL (e.g. "javascript:...")
  12116. */
  12117. WebInspector.resourceURLForRelatedNode = function(node, url)
  12118. {
  12119. if (!url || url.indexOf("://") > 0)
  12120. return url;
  12121. if (url.trim().startsWith("javascript:"))
  12122. return null; // Do not provide a resource URL for security.
  12123. for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
  12124. if (frameOwnerCandidate.documentURL) {
  12125. var result = WebInspector.completeURL(frameOwnerCandidate.documentURL, url);
  12126. if (result)
  12127. return result;
  12128. break;
  12129. }
  12130. }
  12131. // documentURL not found or has bad value
  12132. var resourceURL = url;
  12133. function callback(resource)
  12134. {
  12135. if (resource.parsedURL.path === url) {
  12136. resourceURL = resource.url;
  12137. return true;
  12138. }
  12139. }
  12140. WebInspector.forAllResources(callback);
  12141. return resourceURL;
  12142. }
  12143. /**
  12144. * @param {string} baseURL
  12145. * @param {string} href
  12146. * @return {?string}
  12147. */
  12148. WebInspector.completeURL = function(baseURL, href)
  12149. {
  12150. if (href) {
  12151. // Return absolute URLs as-is.
  12152. var parsedHref = href.asParsedURL();
  12153. if (parsedHref && parsedHref.scheme)
  12154. return href;
  12155. // Return special URLs as-is.
  12156. var trimmedHref = href.trim();
  12157. if (trimmedHref.startsWith("data:") || trimmedHref.startsWith("javascript:"))
  12158. return href;
  12159. }
  12160. var parsedURL = baseURL.asParsedURL();
  12161. if (parsedURL) {
  12162. var path = href;
  12163. if (path.charAt(0) !== "/") {
  12164. var basePath = parsedURL.path;
  12165. // Trim off the query part of the basePath.
  12166. var questionMarkIndex = basePath.indexOf("?");
  12167. if (questionMarkIndex > 0)
  12168. basePath = basePath.substring(0, questionMarkIndex);
  12169. // A href of "?foo=bar" implies "basePath?foo=bar".
  12170. // With "basePath?a=b" and "?foo=bar" we should get "basePath?foo=bar".
  12171. var prefix;
  12172. if (path.charAt(0) === "?") {
  12173. var basePathCutIndex = basePath.indexOf("?");
  12174. if (basePathCutIndex !== -1)
  12175. prefix = basePath.substring(0, basePathCutIndex);
  12176. else
  12177. prefix = basePath;
  12178. } else
  12179. prefix = basePath.substring(0, basePath.lastIndexOf("/")) + "/";
  12180. path = prefix + path;
  12181. } else if (path.length > 1 && path.charAt(1) === "/") {
  12182. // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol).
  12183. return parsedURL.scheme + ":" + path;
  12184. }
  12185. return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + path;
  12186. }
  12187. return null;
  12188. }
  12189. /* ResourceType.js */
  12190. /*
  12191. * Copyright (C) 2012 Google Inc. All rights reserved.
  12192. * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  12193. *
  12194. * Redistribution and use in source and binary forms, with or without
  12195. * modification, are permitted provided that the following conditions
  12196. * are met:
  12197. *
  12198. * 1. Redistributions of source code must retain the above copyright
  12199. * notice, this list of conditions and the following disclaimer.
  12200. * 2. Redistributions in binary form must reproduce the above copyright
  12201. * notice, this list of conditions and the following disclaimer in the
  12202. * documentation and/or other materials provided with the distribution.
  12203. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  12204. * its contributors may be used to endorse or promote products derived
  12205. * from this software without specific prior written permission.
  12206. *
  12207. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  12208. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  12209. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  12210. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  12211. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  12212. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  12213. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  12214. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12215. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  12216. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12217. */
  12218. /**
  12219. * @constructor
  12220. * @param {string} name
  12221. * @param {string} title
  12222. * @param {string} categoryTitle
  12223. * @param {string} color
  12224. * @param {boolean} isTextType
  12225. */
  12226. WebInspector.ResourceType = function(name, title, categoryTitle, color, isTextType)
  12227. {
  12228. this._name = name;
  12229. this._title = title;
  12230. this._categoryTitle = categoryTitle;
  12231. this._color = color;
  12232. this._isTextType = isTextType;
  12233. }
  12234. WebInspector.ResourceType.prototype = {
  12235. /**
  12236. * @return {string}
  12237. */
  12238. name: function()
  12239. {
  12240. return this._name;
  12241. },
  12242. /**
  12243. * @return {string}
  12244. */
  12245. title: function()
  12246. {
  12247. return this._title;
  12248. },
  12249. /**
  12250. * @return {string}
  12251. */
  12252. categoryTitle: function()
  12253. {
  12254. return this._categoryTitle;
  12255. },
  12256. /**
  12257. * @return {string}
  12258. */
  12259. color: function()
  12260. {
  12261. return this._color;
  12262. },
  12263. /**
  12264. * @return {boolean}
  12265. */
  12266. isTextType: function()
  12267. {
  12268. return this._isTextType;
  12269. },
  12270. /**
  12271. * @return {string}
  12272. */
  12273. toString: function()
  12274. {
  12275. return this._name;
  12276. },
  12277. /**
  12278. * @return {string}
  12279. */
  12280. canonicalMimeType: function()
  12281. {
  12282. if (this === WebInspector.resourceTypes.Document)
  12283. return "text/html";
  12284. if (this === WebInspector.resourceTypes.Script)
  12285. return "text/javascript";
  12286. if (this === WebInspector.resourceTypes.Stylesheet)
  12287. return "text/css";
  12288. return "";
  12289. }
  12290. }
  12291. //Keep these in sync with WebCore::InspectorPageAgent::resourceTypeJson
  12292. WebInspector.resourceTypes = {
  12293. Document: new WebInspector.ResourceType("document", "Document", "Documents", "rgb(47,102,236)", true),
  12294. Stylesheet: new WebInspector.ResourceType("stylesheet", "Stylesheet", "Stylesheets", "rgb(157,231,119)", true),
  12295. Image: new WebInspector.ResourceType("image", "Image", "Images", "rgb(164,60,255)", false),
  12296. Script: new WebInspector.ResourceType("script", "Script", "Scripts", "rgb(255,121,0)", true),
  12297. XHR: new WebInspector.ResourceType("xhr", "XHR", "XHR", "rgb(231,231,10)", true),
  12298. Font: new WebInspector.ResourceType("font", "Font", "Fonts", "rgb(255,82,62)", false),
  12299. WebSocket: new WebInspector.ResourceType("websocket", "WebSocket", "WebSockets", "rgb(186,186,186)", false), // FIXME: Decide the color.
  12300. Other: new WebInspector.ResourceType("other", "Other", "Other", "rgb(186,186,186)", false)
  12301. }
  12302. /* TimelineManager.js */
  12303. /*
  12304. * Copyright (C) 2011 Google Inc. All rights reserved.
  12305. *
  12306. * Redistribution and use in source and binary forms, with or without
  12307. * modification, are permitted provided that the following conditions are
  12308. * met:
  12309. *
  12310. * * Redistributions of source code must retain the above copyright
  12311. * notice, this list of conditions and the following disclaimer.
  12312. * * Redistributions in binary form must reproduce the above
  12313. * copyright notice, this list of conditions and the following disclaimer
  12314. * in the documentation and/or other materials provided with the
  12315. * distribution.
  12316. * * Neither the name of Google Inc. nor the names of its
  12317. * contributors may be used to endorse or promote products derived from
  12318. * this software without specific prior written permission.
  12319. *
  12320. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  12321. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  12322. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  12323. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  12324. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  12325. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  12326. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12327. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  12328. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12329. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  12330. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12331. */
  12332. /**
  12333. * @constructor
  12334. * @extends {WebInspector.Object}
  12335. */
  12336. WebInspector.TimelineManager = function()
  12337. {
  12338. WebInspector.Object.call(this);
  12339. this._dispatcher = new WebInspector.TimelineDispatcher(this);
  12340. this._enablementCount = 0;
  12341. }
  12342. WebInspector.TimelineManager.EventTypes = {
  12343. TimelineStarted: "TimelineStarted",
  12344. TimelineStopped: "TimelineStopped",
  12345. TimelineEventRecorded: "TimelineEventRecorded"
  12346. }
  12347. WebInspector.TimelineManager.prototype = {
  12348. /**
  12349. * @param {number=} maxCallStackDepth
  12350. */
  12351. start: function(maxCallStackDepth)
  12352. {
  12353. this._enablementCount++;
  12354. if (this._enablementCount === 1)
  12355. TimelineAgent.start(maxCallStackDepth, this._started.bind(this));
  12356. },
  12357. stop: function()
  12358. {
  12359. if (!this._enablementCount) {
  12360. console.error("WebInspector.TimelineManager start/stop calls are unbalanced");
  12361. return;
  12362. }
  12363. this._enablementCount--;
  12364. if (!this._enablementCount)
  12365. TimelineAgent.stop(this._stopped.bind(this));
  12366. },
  12367. _started: function()
  12368. {
  12369. this.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStarted);
  12370. },
  12371. _stopped: function()
  12372. {
  12373. this.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStopped);
  12374. }
  12375. }
  12376. WebInspector.TimelineManager.prototype.__proto__ = WebInspector.Object.prototype;
  12377. /**
  12378. * @constructor
  12379. * @implements {TimelineAgent.Dispatcher}
  12380. */
  12381. WebInspector.TimelineDispatcher = function(manager)
  12382. {
  12383. this._manager = manager;
  12384. InspectorBackend.registerTimelineDispatcher(this);
  12385. }
  12386. WebInspector.TimelineDispatcher.prototype = {
  12387. eventRecorded: function(record)
  12388. {
  12389. this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, record);
  12390. }
  12391. }
  12392. /**
  12393. * @type {WebInspector.TimelineManager}
  12394. */
  12395. WebInspector.timelineManager;
  12396. /* TimelineModel.js */
  12397. /*
  12398. * Copyright (C) 2012 Google Inc. All rights reserved.
  12399. *
  12400. * Redistribution and use in source and binary forms, with or without
  12401. * modification, are permitted provided that the following conditions are
  12402. * met:
  12403. *
  12404. * * Redistributions of source code must retain the above copyright
  12405. * notice, this list of conditions and the following disclaimer.
  12406. * * Redistributions in binary form must reproduce the above
  12407. * copyright notice, this list of conditions and the following disclaimer
  12408. * in the documentation and/or other materials provided with the
  12409. * distribution.
  12410. * * Neither the name of Google Inc. nor the names of its
  12411. * contributors may be used to endorse or promote products derived from
  12412. * this software without specific prior written permission.
  12413. *
  12414. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  12415. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  12416. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  12417. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  12418. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  12419. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  12420. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12421. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  12422. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12423. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  12424. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12425. */
  12426. /**
  12427. * @constructor
  12428. * @extends {WebInspector.Object}
  12429. */
  12430. WebInspector.TimelineModel = function()
  12431. {
  12432. this._records = [];
  12433. this._minimumRecordTime = -1;
  12434. this._maximumRecordTime = -1;
  12435. this._collectionEnabled = false;
  12436. WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, this._onRecordAdded, this);
  12437. }
  12438. WebInspector.TimelineModel.RecordType = {
  12439. Root: "Root",
  12440. EventDispatch: "EventDispatch",
  12441. BeginFrame: "BeginFrame",
  12442. Layout: "Layout",
  12443. RecalculateStyles: "RecalculateStyles",
  12444. Paint: "Paint",
  12445. ParseHTML: "ParseHTML",
  12446. TimerInstall: "TimerInstall",
  12447. TimerRemove: "TimerRemove",
  12448. TimerFire: "TimerFire",
  12449. XHRReadyStateChange: "XHRReadyStateChange",
  12450. XHRLoad: "XHRLoad",
  12451. EvaluateScript: "EvaluateScript",
  12452. TimeStamp: "TimeStamp",
  12453. MarkLoad: "MarkLoad",
  12454. MarkDOMContent: "MarkDOMContent",
  12455. ScheduleResourceRequest: "ScheduleResourceRequest",
  12456. ResourceSendRequest: "ResourceSendRequest",
  12457. ResourceReceiveResponse: "ResourceReceiveResponse",
  12458. ResourceReceivedData: "ResourceReceivedData",
  12459. ResourceFinish: "ResourceFinish",
  12460. FunctionCall: "FunctionCall",
  12461. GCEvent: "GCEvent",
  12462. RequestAnimationFrame: "RequestAnimationFrame",
  12463. CancelAnimationFrame: "CancelAnimationFrame",
  12464. FireAnimationFrame: "FireAnimationFrame"
  12465. }
  12466. WebInspector.TimelineModel.Events = {
  12467. RecordAdded: "RecordAdded",
  12468. RecordsCleared: "RecordsCleared"
  12469. }
  12470. WebInspector.TimelineModel.startTimeInSeconds = function(record)
  12471. {
  12472. return record.startTime / 1000;
  12473. }
  12474. WebInspector.TimelineModel.endTimeInSeconds = function(record)
  12475. {
  12476. return (typeof record.endTime === "undefined" ? record.startTime : record.endTime) / 1000;
  12477. }
  12478. WebInspector.TimelineModel.durationInSeconds = function(record)
  12479. {
  12480. return WebInspector.TimelineModel.endTimeInSeconds(record) - WebInspector.TimelineModel.startTimeInSeconds(record);
  12481. }
  12482. /**
  12483. * @param {Object} total
  12484. * @param {Object} rawRecord
  12485. */
  12486. WebInspector.TimelineModel.aggregateTimeForRecord = function(total, rawRecord)
  12487. {
  12488. var childrenTime = 0;
  12489. var children = rawRecord["children"] || [];
  12490. for (var i = 0; i < children.length; ++i) {
  12491. WebInspector.TimelineModel.aggregateTimeForRecord(total, children[i]);
  12492. childrenTime += WebInspector.TimelineModel.durationInSeconds(children[i]);
  12493. }
  12494. var categoryName = WebInspector.TimelinePresentationModel.recordStyle(rawRecord).category.name;
  12495. var ownTime = WebInspector.TimelineModel.durationInSeconds(rawRecord) - childrenTime;
  12496. total[categoryName] = (total[categoryName] || 0) + ownTime;
  12497. }
  12498. WebInspector.TimelineModel.prototype = {
  12499. startRecord: function()
  12500. {
  12501. if (this._collectionEnabled)
  12502. return;
  12503. this.reset();
  12504. WebInspector.timelineManager.start(30);
  12505. this._collectionEnabled = true;
  12506. },
  12507. stopRecord: function()
  12508. {
  12509. if (!this._collectionEnabled)
  12510. return;
  12511. WebInspector.timelineManager.stop();
  12512. this._collectionEnabled = false;
  12513. },
  12514. get records()
  12515. {
  12516. return this._records;
  12517. },
  12518. _onRecordAdded: function(event)
  12519. {
  12520. if (this._collectionEnabled)
  12521. this._addRecord(event.data);
  12522. },
  12523. _addRecord: function(record)
  12524. {
  12525. this._records.push(record);
  12526. this._updateBoundaries(record);
  12527. this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAdded, record);
  12528. },
  12529. _loadNextChunk: function(data, index)
  12530. {
  12531. for (var i = 0; i < 20 && index < data.length; ++i, ++index)
  12532. this._addRecord(data[index]);
  12533. if (index !== data.length)
  12534. setTimeout(this._loadNextChunk.bind(this, data, index), 0);
  12535. },
  12536. loadFromFile: function(file)
  12537. {
  12538. function onLoad(e)
  12539. {
  12540. var data = JSON.parse(e.target.result);
  12541. this.reset();
  12542. this._loadNextChunk(data, 1);
  12543. }
  12544. function onError(e)
  12545. {
  12546. switch(e.target.error.code) {
  12547. case e.target.error.NOT_FOUND_ERR:
  12548. WebInspector.log(WebInspector.UIString('Timeline.loadFromFile: File "%s" not found.', file.name));
  12549. break;
  12550. case e.target.error.NOT_READABLE_ERR:
  12551. WebInspector.log(WebInspector.UIString('Timeline.loadFromFile: File "%s" is not readable', file.name));
  12552. break;
  12553. case e.target.error.ABORT_ERR:
  12554. break;
  12555. default:
  12556. WebInspector.log(WebInspector.UIString('Timeline.loadFromFile: An error occurred while reading the file "%s"', file.name));
  12557. }
  12558. }
  12559. var reader = new FileReader();
  12560. reader.onload = onLoad.bind(this);
  12561. reader.onerror = onError;
  12562. reader.readAsText(file);
  12563. },
  12564. saveToFile: function()
  12565. {
  12566. var records = ['[' + JSON.stringify(new String(window.navigator.appVersion))];
  12567. for (var i = 0; i < this._records.length; ++i)
  12568. records.push(JSON.stringify(this._records[i]));
  12569. records[records.length - 1] = records[records.length - 1] + "]";
  12570. var now = new Date();
  12571. var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json";
  12572. WebInspector.fileManager.save(fileName, records.join(",\n"), true);
  12573. },
  12574. reset: function()
  12575. {
  12576. this._records = [];
  12577. this._minimumRecordTime = -1;
  12578. this._maximumRecordTime = -1;
  12579. this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsCleared);
  12580. },
  12581. minimumRecordTime: function()
  12582. {
  12583. return this._minimumRecordTime;
  12584. },
  12585. maximumRecordTime: function()
  12586. {
  12587. return this._maximumRecordTime;
  12588. },
  12589. _updateBoundaries: function(record)
  12590. {
  12591. var startTime = WebInspector.TimelineModel.startTimeInSeconds(record);
  12592. var endTime = WebInspector.TimelineModel.endTimeInSeconds(record);
  12593. if (this._minimumRecordTime === -1 || startTime < this._minimumRecordTime)
  12594. this._minimumRecordTime = startTime;
  12595. if (this._maximumRecordTime === -1 || endTime > this._maximumRecordTime)
  12596. this._maximumRecordTime = endTime;
  12597. },
  12598. /**
  12599. * @param {Object} rawRecord
  12600. */
  12601. recordOffsetInSeconds: function(rawRecord)
  12602. {
  12603. return WebInspector.TimelineModel.startTimeInSeconds(rawRecord) - this._minimumRecordTime;
  12604. }
  12605. }
  12606. WebInspector.TimelineModel.prototype.__proto__ = WebInspector.Object.prototype;
  12607. /* UserAgentSupport.js */
  12608. /*
  12609. * Copyright (C) 2012 Google Inc. All rights reserved.
  12610. *
  12611. * Redistribution and use in source and binary forms, with or without
  12612. * modification, are permitted provided that the following conditions are
  12613. * met:
  12614. *
  12615. * * Redistributions of source code must retain the above copyright
  12616. * notice, this list of conditions and the following disclaimer.
  12617. * * Redistributions in binary form must reproduce the above
  12618. * copyright notice, this list of conditions and the following disclaimer
  12619. * in the documentation and/or other materials provided with the
  12620. * distribution.
  12621. * * Neither the name of Google Inc. nor the names of its
  12622. * contributors may be used to endorse or promote products derived from
  12623. * this software without specific prior written permission.
  12624. *
  12625. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  12626. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  12627. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  12628. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  12629. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  12630. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  12631. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  12632. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  12633. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12634. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  12635. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12636. */
  12637. /**
  12638. * @constructor
  12639. */
  12640. WebInspector.UserAgentSupport = function()
  12641. {
  12642. if (WebInspector.settings.deviceMetrics.get())
  12643. this._deviceMetricsChanged();
  12644. WebInspector.settings.deviceMetrics.addChangeListener(this._deviceMetricsChanged, this);
  12645. WebInspector.settings.deviceFitWindow.addChangeListener(this._deviceMetricsChanged, this);
  12646. }
  12647. /**
  12648. * @constructor
  12649. * @param {number} width
  12650. * @param {number} height
  12651. * @param {number} fontScaleFactor
  12652. */
  12653. WebInspector.UserAgentSupport.DeviceMetrics = function(width, height, fontScaleFactor)
  12654. {
  12655. this.width = width;
  12656. this.height = height;
  12657. this.fontScaleFactor = fontScaleFactor;
  12658. }
  12659. /**
  12660. * @return {WebInspector.UserAgentSupport.DeviceMetrics}
  12661. */
  12662. WebInspector.UserAgentSupport.DeviceMetrics.parseSetting = function(value)
  12663. {
  12664. if (value) {
  12665. var splitMetrics = value.split("x");
  12666. if (splitMetrics.length === 3)
  12667. return new WebInspector.UserAgentSupport.DeviceMetrics(parseInt(splitMetrics[0], 10), parseInt(splitMetrics[1], 10), parseFloat(splitMetrics[2]));
  12668. }
  12669. return new WebInspector.UserAgentSupport.DeviceMetrics(0, 0, 1);
  12670. }
  12671. /**
  12672. * @return {?WebInspector.UserAgentSupport.DeviceMetrics}
  12673. */
  12674. WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput = function(widthString, heightString, fontScaleFactorString)
  12675. {
  12676. function isUserInputValid(value, isInteger)
  12677. {
  12678. if (!value)
  12679. return true;
  12680. return isInteger ? /^[0]*[1-9][\d]*$/.test(value) : /^[0]*([1-9][\d]*(\.\d+)?|\.\d+)$/.test(value);
  12681. }
  12682. if (!widthString ^ !heightString)
  12683. return null;
  12684. var isWidthValid = isUserInputValid(widthString, true);
  12685. var isHeightValid = isUserInputValid(heightString, true);
  12686. var isFontScaleFactorValid = isUserInputValid(fontScaleFactorString, false);
  12687. if (!isWidthValid && !isHeightValid && !isFontScaleFactorValid)
  12688. return null;
  12689. var width = isWidthValid ? parseInt(widthString || "0", 10) : -1;
  12690. var height = isHeightValid ? parseInt(heightString || "0", 10) : -1;
  12691. var fontScaleFactor = isFontScaleFactorValid ? parseFloat(fontScaleFactorString) : -1;
  12692. return new WebInspector.UserAgentSupport.DeviceMetrics(width, height, fontScaleFactor);
  12693. }
  12694. WebInspector.UserAgentSupport.DeviceMetrics.prototype = {
  12695. /**
  12696. * @return {boolean}
  12697. */
  12698. isValid: function()
  12699. {
  12700. return this.isWidthValid() && this.isHeightValid() && this.isFontScaleFactorValid();
  12701. },
  12702. /**
  12703. * @return {boolean}
  12704. */
  12705. isWidthValid: function()
  12706. {
  12707. return this.width >= 0;
  12708. },
  12709. /**
  12710. * @return {boolean}
  12711. */
  12712. isHeightValid: function()
  12713. {
  12714. return this.height >= 0;
  12715. },
  12716. /**
  12717. * @return {boolean}
  12718. */
  12719. isFontScaleFactorValid: function()
  12720. {
  12721. return this.fontScaleFactor > 0;
  12722. },
  12723. /**
  12724. * @return {string}
  12725. */
  12726. toSetting: function()
  12727. {
  12728. if (!this.isValid())
  12729. return "";
  12730. return this.width && this.height ? this.width + "x" + this.height + "x" + this.fontScaleFactor : "";
  12731. },
  12732. /**
  12733. * @return {string}
  12734. */
  12735. widthToInput: function()
  12736. {
  12737. return this.isWidthValid() && this.width ? String(this.width) : "";
  12738. },
  12739. /**
  12740. * @return {string}
  12741. */
  12742. heightToInput: function()
  12743. {
  12744. return this.isHeightValid() && this.height ? String(this.height) : "";
  12745. },
  12746. /**
  12747. * @return {string}
  12748. */
  12749. fontScaleFactorToInput: function()
  12750. {
  12751. return this.isFontScaleFactorValid() && this.fontScaleFactor ? String(this.fontScaleFactor) : "";
  12752. }
  12753. }
  12754. WebInspector.UserAgentSupport.prototype = {
  12755. _deviceMetricsChanged: function()
  12756. {
  12757. var metrics = WebInspector.UserAgentSupport.DeviceMetrics.parseSetting(WebInspector.settings.deviceMetrics.get());
  12758. if (metrics.isValid())
  12759. PageAgent.setDeviceMetricsOverride(metrics.width, metrics.height, metrics.fontScaleFactor, WebInspector.settings.deviceFitWindow.get());
  12760. }
  12761. }
  12762. /* Database.js */
  12763. /*
  12764. * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  12765. *
  12766. * Redistribution and use in source and binary forms, with or without
  12767. * modification, are permitted provided that the following conditions
  12768. * are met:
  12769. *
  12770. * 1. Redistributions of source code must retain the above copyright
  12771. * notice, this list of conditions and the following disclaimer.
  12772. * 2. Redistributions in binary form must reproduce the above copyright
  12773. * notice, this list of conditions and the following disclaimer in the
  12774. * documentation and/or other materials provided with the distribution.
  12775. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  12776. * its contributors may be used to endorse or promote products derived
  12777. * from this software without specific prior written permission.
  12778. *
  12779. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  12780. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  12781. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  12782. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  12783. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  12784. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  12785. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  12786. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12787. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  12788. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12789. */
  12790. /**
  12791. * @constructor
  12792. */
  12793. WebInspector.Database = function(id, domain, name, version)
  12794. {
  12795. this._id = id;
  12796. this._domain = domain;
  12797. this._name = name;
  12798. this._version = version;
  12799. }
  12800. WebInspector.Database.prototype = {
  12801. /** @return {string} */
  12802. get id()
  12803. {
  12804. return this._id;
  12805. },
  12806. /** @return {string} */
  12807. get name()
  12808. {
  12809. return this._name;
  12810. },
  12811. set name(x)
  12812. {
  12813. this._name = x;
  12814. },
  12815. /** @return {string} */
  12816. get version()
  12817. {
  12818. return this._version;
  12819. },
  12820. set version(x)
  12821. {
  12822. this._version = x;
  12823. },
  12824. /** @return {string} */
  12825. get domain()
  12826. {
  12827. return this._domain;
  12828. },
  12829. set domain(x)
  12830. {
  12831. this._domain = x;
  12832. },
  12833. /** @return {string} */
  12834. get displayDomain()
  12835. {
  12836. return WebInspector.displayDomain(this._domain);
  12837. },
  12838. /**
  12839. * @param {function(Array.<string>)} callback
  12840. */
  12841. getTableNames: function(callback)
  12842. {
  12843. function sortingCallback(error, names)
  12844. {
  12845. if (!error)
  12846. callback(names.sort());
  12847. }
  12848. DatabaseAgent.getDatabaseTableNames(this._id, sortingCallback);
  12849. },
  12850. /**
  12851. * @param {string} query
  12852. * @param {function(Array.<string>, Array.<*>)} onSuccess
  12853. * @param {function(DatabaseAgent.Error)} onError
  12854. */
  12855. executeSql: function(query, onSuccess, onError)
  12856. {
  12857. function callback(error, success, transactionId)
  12858. {
  12859. if (error) {
  12860. onError(error);
  12861. return;
  12862. }
  12863. if (!success) {
  12864. onError(WebInspector.UIString("Database not found."));
  12865. return;
  12866. }
  12867. WebInspector.DatabaseDispatcher._callbacks[transactionId] = {"onSuccess": onSuccess, "onError": onError};
  12868. }
  12869. DatabaseAgent.executeSQL(this._id, query, callback);
  12870. }
  12871. }
  12872. /**
  12873. * @constructor
  12874. * @implements {DatabaseAgent.Dispatcher}
  12875. */
  12876. WebInspector.DatabaseDispatcher = function()
  12877. {
  12878. }
  12879. WebInspector.DatabaseDispatcher._callbacks = {};
  12880. WebInspector.DatabaseDispatcher.prototype = {
  12881. /**
  12882. * @param {DatabaseAgent.Database} payload
  12883. */
  12884. addDatabase: function(payload)
  12885. {
  12886. var database = new WebInspector.Database(
  12887. payload.id,
  12888. payload.domain,
  12889. payload.name,
  12890. payload.version);
  12891. WebInspector.panels.resources.addDatabase(database);
  12892. },
  12893. /**
  12894. * @param {number} transactionId
  12895. * @param {Array.<string>} columnNames
  12896. * @param {Array.<*>} values
  12897. */
  12898. sqlTransactionSucceeded: function(transactionId, columnNames, values)
  12899. {
  12900. if (!WebInspector.DatabaseDispatcher._callbacks[transactionId])
  12901. return;
  12902. var callback = WebInspector.DatabaseDispatcher._callbacks[transactionId]["onSuccess"];
  12903. delete WebInspector.DatabaseDispatcher._callbacks[transactionId];
  12904. if (callback)
  12905. callback(columnNames, values);
  12906. },
  12907. /**
  12908. * @param {number} transactionId
  12909. * @param {?DatabaseAgent.Error} errorObj
  12910. */
  12911. sqlTransactionFailed: function(transactionId, errorObj)
  12912. {
  12913. if (!WebInspector.DatabaseDispatcher._callbacks[transactionId])
  12914. return;
  12915. var callback = WebInspector.DatabaseDispatcher._callbacks[transactionId]["onError"];
  12916. delete WebInspector.DatabaseDispatcher._callbacks[transactionId];
  12917. if (callback)
  12918. callback(errorObj);
  12919. }
  12920. }
  12921. /* DOMStorage.js */
  12922. /*
  12923. * Copyright (C) 2008 Nokia Inc. All rights reserved.
  12924. *
  12925. * Redistribution and use in source and binary forms, with or without
  12926. * modification, are permitted provided that the following conditions
  12927. * are met:
  12928. *
  12929. * 1. Redistributions of source code must retain the above copyright
  12930. * notice, this list of conditions and the following disclaimer.
  12931. * 2. Redistributions in binary form must reproduce the above copyright
  12932. * notice, this list of conditions and the following disclaimer in the
  12933. * documentation and/or other materials provided with the distribution.
  12934. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  12935. * its contributors may be used to endorse or promote products derived
  12936. * from this software without specific prior written permission.
  12937. *
  12938. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
  12939. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  12940. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  12941. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  12942. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  12943. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  12944. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  12945. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12946. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  12947. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  12948. */
  12949. /**
  12950. * @constructor
  12951. */
  12952. WebInspector.DOMStorage = function(id, domain, isLocalStorage)
  12953. {
  12954. this._id = id;
  12955. this._domain = domain;
  12956. this._isLocalStorage = isLocalStorage;
  12957. }
  12958. WebInspector.DOMStorage.prototype = {
  12959. /** @return {string} */
  12960. get id()
  12961. {
  12962. return this._id;
  12963. },
  12964. /** @return {string} */
  12965. get domain()
  12966. {
  12967. return this._domain;
  12968. },
  12969. /** @return {boolean} */
  12970. get isLocalStorage()
  12971. {
  12972. return this._isLocalStorage;
  12973. },
  12974. /**
  12975. * @param {function(?Protocol.Error, Array.<DOMStorageAgent.Entry>):void=} callback
  12976. */
  12977. getEntries: function(callback)
  12978. {
  12979. DOMStorageAgent.getDOMStorageEntries(this._id, callback);
  12980. },
  12981. /**
  12982. * @param {string} key
  12983. * @param {string} value
  12984. * @param {function(?Protocol.Error, boolean):void=} callback
  12985. */
  12986. setItem: function(key, value, callback)
  12987. {
  12988. DOMStorageAgent.setDOMStorageItem(this._id, key, value, callback);
  12989. },
  12990. /**
  12991. * @param {string} key
  12992. * @param {function(?Protocol.Error, boolean):void=} callback
  12993. */
  12994. removeItem: function(key, callback)
  12995. {
  12996. DOMStorageAgent.removeDOMStorageItem(this._id, key, callback);
  12997. }
  12998. }
  12999. /**
  13000. * @constructor
  13001. * @implements {DOMStorageAgent.Dispatcher}
  13002. */
  13003. WebInspector.DOMStorageDispatcher = function()
  13004. {
  13005. }
  13006. WebInspector.DOMStorageDispatcher.prototype = {
  13007. /**
  13008. * @param {DOMStorageAgent.Entry} payload
  13009. */
  13010. addDOMStorage: function(payload)
  13011. {
  13012. var domStorage = new WebInspector.DOMStorage(
  13013. payload.id,
  13014. payload.host,
  13015. payload.isLocalStorage);
  13016. WebInspector.panels.resources.addDOMStorage(domStorage);
  13017. },
  13018. /**
  13019. * @param {string} storageId
  13020. */
  13021. updateDOMStorage: function(storageId)
  13022. {
  13023. WebInspector.panels.resources.updateDOMStorage(storageId);
  13024. }
  13025. }
  13026. /* DOMStorageItemsView.js */
  13027. /*
  13028. * Copyright (C) 2008 Nokia Inc. All rights reserved.
  13029. *
  13030. * Redistribution and use in source and binary forms, with or without
  13031. * modification, are permitted provided that the following conditions
  13032. * are met:
  13033. * 1. Redistributions of source code must retain the above copyright
  13034. * notice, this list of conditions and the following disclaimer.
  13035. * 2. Redistributions in binary form must reproduce the above copyright
  13036. * notice, this list of conditions and the following disclaimer in the
  13037. * documentation and/or other materials provided with the distribution.
  13038. *
  13039. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
  13040. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13041. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  13042. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  13043. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  13044. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  13045. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  13046. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  13047. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  13048. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13049. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  13050. */
  13051. /**
  13052. * @constructor
  13053. * @extends {WebInspector.View}
  13054. */
  13055. WebInspector.DOMStorageItemsView = function(domStorage)
  13056. {
  13057. WebInspector.View.call(this);
  13058. this.domStorage = domStorage;
  13059. this.element.addStyleClass("storage-view");
  13060. this.element.addStyleClass("table");
  13061. this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
  13062. this.deleteButton.visible = false;
  13063. this.deleteButton.addEventListener("click", this._deleteButtonClicked, this);
  13064. this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
  13065. this.refreshButton.addEventListener("click", this._refreshButtonClicked, this);
  13066. }
  13067. WebInspector.DOMStorageItemsView.prototype = {
  13068. get statusBarItems()
  13069. {
  13070. return [this.refreshButton.element, this.deleteButton.element];
  13071. },
  13072. wasShown: function()
  13073. {
  13074. this.update();
  13075. },
  13076. willHide: function()
  13077. {
  13078. this.deleteButton.visible = false;
  13079. },
  13080. update: function()
  13081. {
  13082. this.detachChildViews();
  13083. this.domStorage.getEntries(this._showDOMStorageEntries.bind(this));
  13084. },
  13085. _showDOMStorageEntries: function(error, entries)
  13086. {
  13087. if (error)
  13088. return;
  13089. this._dataGrid = this._dataGridForDOMStorageEntries(entries);
  13090. this._dataGrid.show(this.element);
  13091. this._dataGrid.autoSizeColumns(10);
  13092. this.deleteButton.visible = true;
  13093. },
  13094. _dataGridForDOMStorageEntries: function(entries)
  13095. {
  13096. var columns = {};
  13097. columns[0] = {};
  13098. columns[1] = {};
  13099. columns[0].title = WebInspector.UIString("Key");
  13100. columns[1].title = WebInspector.UIString("Value");
  13101. var nodes = [];
  13102. var keys = [];
  13103. var length = entries.length;
  13104. for (var i = 0; i < entries.length; i++) {
  13105. var data = {};
  13106. var key = entries[i][0];
  13107. data[0] = key;
  13108. var value = entries[i][1];
  13109. data[1] = value;
  13110. var node = new WebInspector.DataGridNode(data, false);
  13111. node.selectable = true;
  13112. nodes.push(node);
  13113. keys.push(key);
  13114. }
  13115. var dataGrid = new WebInspector.DataGrid(columns, this._editingCallback.bind(this), this._deleteCallback.bind(this));
  13116. length = nodes.length;
  13117. for (var i = 0; i < length; ++i)
  13118. dataGrid.rootNode().appendChild(nodes[i]);
  13119. dataGrid.addCreationNode(false);
  13120. if (length > 0)
  13121. nodes[0].selected = true;
  13122. return dataGrid;
  13123. },
  13124. _deleteButtonClicked: function(event)
  13125. {
  13126. if (!this._dataGrid || !this._dataGrid.selectedNode)
  13127. return;
  13128. this._deleteCallback(this._dataGrid.selectedNode);
  13129. },
  13130. _refreshButtonClicked: function(event)
  13131. {
  13132. this.update();
  13133. },
  13134. _editingCallback: function(editingNode, columnIdentifier, oldText, newText)
  13135. {
  13136. var domStorage = this.domStorage;
  13137. if (columnIdentifier === 0) {
  13138. if (oldText)
  13139. domStorage.removeItem(oldText);
  13140. domStorage.setItem(newText, editingNode.data[1]);
  13141. } else {
  13142. domStorage.setItem(editingNode.data[0], newText);
  13143. }
  13144. this.update();
  13145. },
  13146. _deleteCallback: function(node)
  13147. {
  13148. if (!node || node.isCreationNode)
  13149. return;
  13150. if (this.domStorage)
  13151. this.domStorage.removeItem(node.data[0]);
  13152. this.update();
  13153. }
  13154. }
  13155. WebInspector.DOMStorageItemsView.prototype.__proto__ = WebInspector.View.prototype;
  13156. /* DataGrid.js */
  13157. /*
  13158. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  13159. *
  13160. * Redistribution and use in source and binary forms, with or without
  13161. * modification, are permitted provided that the following conditions
  13162. * are met:
  13163. * 1. Redistributions of source code must retain the above copyright
  13164. * notice, this list of conditions and the following disclaimer.
  13165. * 2. Redistributions in binary form must reproduce the above copyright
  13166. * notice, this list of conditions and the following disclaimer in the
  13167. * documentation and/or other materials provided with the distribution.
  13168. *
  13169. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  13170. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  13171. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  13172. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  13173. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  13174. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  13175. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  13176. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  13177. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  13178. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13179. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  13180. */
  13181. /**
  13182. * @constructor
  13183. * @extends {WebInspector.View}
  13184. * @param {function(WebInspector.DataGridNode, number, string, string)=} editCallback
  13185. * @param {function(WebInspector.DataGridNode)=} deleteCallback
  13186. */
  13187. WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
  13188. {
  13189. WebInspector.View.call(this);
  13190. this.registerRequiredCSS("dataGrid.css");
  13191. this.element.className = "data-grid";
  13192. this.element.tabIndex = 0;
  13193. this.element.addEventListener("keydown", this._keyDown.bind(this), false);
  13194. this._headerTable = document.createElement("table");
  13195. this._headerTable.className = "header";
  13196. this._headerTableHeaders = {};
  13197. this._dataTable = document.createElement("table");
  13198. this._dataTable.className = "data";
  13199. this._dataTable.addEventListener("mousedown", this._mouseDownInDataTable.bind(this), true);
  13200. this._dataTable.addEventListener("click", this._clickInDataTable.bind(this), true);
  13201. this._dataTable.addEventListener("contextmenu", this._contextMenuInDataTable.bind(this), true);
  13202. // FIXME: Add a createCallback which is different from editCallback and has different
  13203. // behavior when creating a new node.
  13204. if (editCallback) {
  13205. this._dataTable.addEventListener("dblclick", this._ondblclick.bind(this), false);
  13206. this._editCallback = editCallback;
  13207. }
  13208. if (deleteCallback)
  13209. this._deleteCallback = deleteCallback;
  13210. this.aligned = {};
  13211. this._scrollContainer = document.createElement("div");
  13212. this._scrollContainer.className = "data-container";
  13213. this._scrollContainer.appendChild(this._dataTable);
  13214. this.element.appendChild(this._headerTable);
  13215. this.element.appendChild(this._scrollContainer);
  13216. var headerRow = document.createElement("tr");
  13217. var columnGroup = document.createElement("colgroup");
  13218. this._columnCount = 0;
  13219. for (var columnIdentifier in columns) {
  13220. var column = columns[columnIdentifier];
  13221. if (column.disclosure)
  13222. this.disclosureColumnIdentifier = columnIdentifier;
  13223. var col = document.createElement("col");
  13224. if (column.width)
  13225. col.style.width = column.width;
  13226. column.element = col;
  13227. columnGroup.appendChild(col);
  13228. var cell = document.createElement("th");
  13229. cell.className = columnIdentifier + "-column";
  13230. cell.columnIdentifier = columnIdentifier;
  13231. this._headerTableHeaders[columnIdentifier] = cell;
  13232. var div = document.createElement("div");
  13233. if (column.titleDOMFragment)
  13234. div.appendChild(column.titleDOMFragment);
  13235. else
  13236. div.textContent = column.title;
  13237. cell.appendChild(div);
  13238. if (column.sort) {
  13239. cell.addStyleClass("sort-" + column.sort);
  13240. this._sortColumnCell = cell;
  13241. }
  13242. if (column.sortable) {
  13243. cell.addEventListener("click", this._clickInHeaderCell.bind(this), false);
  13244. cell.addStyleClass("sortable");
  13245. }
  13246. if (column.aligned)
  13247. this.aligned[columnIdentifier] = column.aligned;
  13248. headerRow.appendChild(cell);
  13249. ++this._columnCount;
  13250. }
  13251. columnGroup.span = this._columnCount;
  13252. var cell = document.createElement("th");
  13253. cell.className = "corner";
  13254. headerRow.appendChild(cell);
  13255. this._headerTableColumnGroup = columnGroup;
  13256. this._headerTable.appendChild(this._headerTableColumnGroup);
  13257. this.headerTableBody.appendChild(headerRow);
  13258. var fillerRow = document.createElement("tr");
  13259. fillerRow.className = "filler";
  13260. for (var columnIdentifier in columns) {
  13261. var column = columns[columnIdentifier];
  13262. var td = document.createElement("td");
  13263. td.className = columnIdentifier + "-column";
  13264. fillerRow.appendChild(td);
  13265. }
  13266. this._dataTableColumnGroup = columnGroup.cloneNode(true);
  13267. this._dataTable.appendChild(this._dataTableColumnGroup);
  13268. this.dataTableBody.appendChild(fillerRow);
  13269. this.columns = columns || {};
  13270. this._columnsArray = [];
  13271. for (var columnIdentifier in columns) {
  13272. columns[columnIdentifier].ordinal = this._columnsArray.length;
  13273. columns[columnIdentifier].identifier = columnIdentifier;
  13274. this._columnsArray.push(columns[columnIdentifier]);
  13275. }
  13276. for (var i = 0; i < this._columnsArray.length; ++i)
  13277. this._columnsArray[i].bodyElement = this._dataTableColumnGroup.children[i];
  13278. this.selectedNode = null;
  13279. this.expandNodesWhenArrowing = false;
  13280. this.setRootNode(new WebInspector.DataGridNode());
  13281. this.indentWidth = 15;
  13282. this.resizers = [];
  13283. this._columnWidthsInitialized = false;
  13284. }
  13285. WebInspector.DataGrid.Events = {
  13286. SelectedNode: "SelectedNode",
  13287. DeselectedNode: "DeselectedNode"
  13288. }
  13289. /**
  13290. * @param {Array.<string>} columnNames
  13291. * @param {Array.<string>} values
  13292. */
  13293. WebInspector.DataGrid.createSortableDataGrid = function(columnNames, values)
  13294. {
  13295. var numColumns = columnNames.length;
  13296. if (!numColumns)
  13297. return null;
  13298. var columns = {};
  13299. for (var i = 0; i < columnNames.length; ++i) {
  13300. var column = {};
  13301. column.width = columnNames[i].length;
  13302. column.title = columnNames[i];
  13303. column.sortable = true;
  13304. columns[columnNames[i]] = column;
  13305. }
  13306. var nodes = [];
  13307. for (var i = 0; i < values.length / numColumns; ++i) {
  13308. var data = {};
  13309. for (var j = 0; j < columnNames.length; ++j)
  13310. data[columnNames[j]] = values[numColumns * i + j];
  13311. var node = new WebInspector.DataGridNode(data, false);
  13312. node.selectable = false;
  13313. nodes.push(node);
  13314. }
  13315. var dataGrid = new WebInspector.DataGrid(columns);
  13316. var length = nodes.length;
  13317. for (var i = 0; i < length; ++i)
  13318. dataGrid.rootNode().appendChild(nodes[i]);
  13319. dataGrid.addEventListener("sorting changed", sortDataGrid, this);
  13320. function sortDataGrid()
  13321. {
  13322. var nodes = dataGrid._rootNode.children.slice();
  13323. var sortColumnIdentifier = dataGrid.sortColumnIdentifier;
  13324. var sortDirection = dataGrid.sortOrder === "ascending" ? 1 : -1;
  13325. var columnIsNumeric = true;
  13326. for (var i = 0; i < nodes.length; i++) {
  13327. if (isNaN(Number(nodes[i].data[sortColumnIdentifier])))
  13328. columnIsNumeric = false;
  13329. }
  13330. function comparator(dataGridNode1, dataGridNode2)
  13331. {
  13332. var item1 = dataGridNode1.data[sortColumnIdentifier];
  13333. var item2 = dataGridNode2.data[sortColumnIdentifier];
  13334. var comparison;
  13335. if (columnIsNumeric) {
  13336. // Sort numbers based on comparing their values rather than a lexicographical comparison.
  13337. var number1 = parseFloat(item1);
  13338. var number2 = parseFloat(item2);
  13339. comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0);
  13340. } else
  13341. comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0);
  13342. return sortDirection * comparison;
  13343. }
  13344. nodes.sort(comparator);
  13345. dataGrid.rootNode().removeChildren();
  13346. for (var i = 0; i < nodes.length; i++)
  13347. dataGrid._rootNode.appendChild(nodes[i]);
  13348. }
  13349. return dataGrid;
  13350. }
  13351. WebInspector.DataGrid.prototype = {
  13352. setRootNode: function(rootNode)
  13353. {
  13354. if (this._rootNode) {
  13355. this._rootNode.removeChildren();
  13356. this._rootNode.dataGrid = null;
  13357. this._rootNode._isRoot = false;
  13358. }
  13359. this._rootNode = rootNode;
  13360. rootNode._isRoot = true;
  13361. rootNode.hasChildren = false;
  13362. rootNode._expanded = true;
  13363. rootNode._revealed = true;
  13364. rootNode.dataGrid = this;
  13365. },
  13366. rootNode: function()
  13367. {
  13368. return this._rootNode;
  13369. },
  13370. get refreshCallback()
  13371. {
  13372. return this._refreshCallback;
  13373. },
  13374. set refreshCallback(refreshCallback)
  13375. {
  13376. this._refreshCallback = refreshCallback;
  13377. },
  13378. _ondblclick: function(event)
  13379. {
  13380. if (this._editing || this._editingNode)
  13381. return;
  13382. this._startEditing(event.target);
  13383. },
  13384. _startEditingColumnOfDataGridNode: function(node, column)
  13385. {
  13386. this._editing = true;
  13387. this._editingNode = node;
  13388. this._editingNode.select();
  13389. var element = this._editingNode._element.children[column];
  13390. WebInspector.startEditing(element, this._startEditingConfig(element));
  13391. window.getSelection().setBaseAndExtent(element, 0, element, 1);
  13392. },
  13393. _startEditing: function(target)
  13394. {
  13395. var element = target.enclosingNodeOrSelfWithNodeName("td");
  13396. if (!element)
  13397. return;
  13398. this._editingNode = this.dataGridNodeFromNode(target);
  13399. if (!this._editingNode) {
  13400. if (!this.creationNode)
  13401. return;
  13402. this._editingNode = this.creationNode;
  13403. }
  13404. // Force editing the 1st column when editing the creation node
  13405. if (this._editingNode.isCreationNode)
  13406. return this._startEditingColumnOfDataGridNode(this._editingNode, 0);
  13407. this._editing = true;
  13408. WebInspector.startEditing(element, this._startEditingConfig(element));
  13409. window.getSelection().setBaseAndExtent(element, 0, element, 1);
  13410. },
  13411. _startEditingConfig: function(element)
  13412. {
  13413. return new WebInspector.EditingConfig(this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent);
  13414. },
  13415. _editingCommitted: function(element, newText, oldText, context, moveDirection)
  13416. {
  13417. // FIXME: We need more column identifiers here throughout this function.
  13418. // Not needed yet since only editable DataGrid is DOM Storage, which is Key - Value.
  13419. // FIXME: Better way to do this than regular expressions?
  13420. var columnIdentifier = parseInt(element.className.match(/\b(\d+)-column\b/)[1], 10);
  13421. var textBeforeEditing = this._editingNode.data[columnIdentifier];
  13422. var currentEditingNode = this._editingNode;
  13423. function moveToNextIfNeeded(wasChange) {
  13424. if (!moveDirection)
  13425. return;
  13426. if (moveDirection === "forward") {
  13427. if (currentEditingNode.isCreationNode && columnIdentifier === 0 && !wasChange)
  13428. return;
  13429. if (columnIdentifier === 0)
  13430. return this._startEditingColumnOfDataGridNode(currentEditingNode, 1);
  13431. var nextDataGridNode = currentEditingNode.traverseNextNode(true, null, true);
  13432. if (nextDataGridNode)
  13433. return this._startEditingColumnOfDataGridNode(nextDataGridNode, 0);
  13434. if (currentEditingNode.isCreationNode && wasChange) {
  13435. this.addCreationNode(false);
  13436. return this._startEditingColumnOfDataGridNode(this.creationNode, 0);
  13437. }
  13438. return;
  13439. }
  13440. if (moveDirection === "backward") {
  13441. if (columnIdentifier === 1)
  13442. return this._startEditingColumnOfDataGridNode(currentEditingNode, 0);
  13443. var nextDataGridNode = currentEditingNode.traversePreviousNode(true, null, true);
  13444. if (nextDataGridNode)
  13445. return this._startEditingColumnOfDataGridNode(nextDataGridNode, 1);
  13446. return;
  13447. }
  13448. }
  13449. if (textBeforeEditing == newText) {
  13450. this._editingCancelled(element);
  13451. moveToNextIfNeeded.call(this, false);
  13452. return;
  13453. }
  13454. // Update the text in the datagrid that we typed
  13455. this._editingNode.data[columnIdentifier] = newText;
  13456. // Make the callback - expects an editing node (table row), the column number that is being edited,
  13457. // the text that used to be there, and the new text.
  13458. this._editCallback(this._editingNode, columnIdentifier, textBeforeEditing, newText);
  13459. if (this._editingNode.isCreationNode)
  13460. this.addCreationNode(false);
  13461. this._editingCancelled(element);
  13462. moveToNextIfNeeded.call(this, true);
  13463. },
  13464. _editingCancelled: function(element)
  13465. {
  13466. delete this._editing;
  13467. this._editingNode = null;
  13468. },
  13469. /**
  13470. * @return {?string}
  13471. */
  13472. get sortColumnIdentifier()
  13473. {
  13474. if (!this._sortColumnCell)
  13475. return null;
  13476. return this._sortColumnCell.columnIdentifier;
  13477. },
  13478. /**
  13479. * @return {?string}
  13480. */
  13481. get sortOrder()
  13482. {
  13483. if (!this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending"))
  13484. return "ascending";
  13485. if (this._sortColumnCell.hasStyleClass("sort-descending"))
  13486. return "descending";
  13487. return null;
  13488. },
  13489. get headerTableBody()
  13490. {
  13491. if ("_headerTableBody" in this)
  13492. return this._headerTableBody;
  13493. this._headerTableBody = this._headerTable.getElementsByTagName("tbody")[0];
  13494. if (!this._headerTableBody) {
  13495. this._headerTableBody = this.element.ownerDocument.createElement("tbody");
  13496. this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot);
  13497. }
  13498. return this._headerTableBody;
  13499. },
  13500. get dataTableBody()
  13501. {
  13502. if ("_dataTableBody" in this)
  13503. return this._dataTableBody;
  13504. this._dataTableBody = this._dataTable.getElementsByTagName("tbody")[0];
  13505. if (!this._dataTableBody) {
  13506. this._dataTableBody = this.element.ownerDocument.createElement("tbody");
  13507. this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot);
  13508. }
  13509. return this._dataTableBody;
  13510. },
  13511. /**
  13512. * @param {number=} maxDescentLevel
  13513. */
  13514. autoSizeColumns: function(minPercent, maxPercent, maxDescentLevel)
  13515. {
  13516. if (minPercent)
  13517. minPercent = Math.min(minPercent, Math.floor(100 / this._columnCount));
  13518. var widths = {};
  13519. var columns = this.columns;
  13520. for (var columnIdentifier in columns)
  13521. widths[columnIdentifier] = (columns[columnIdentifier].title || "").length;
  13522. maxDescentLevel = maxDescentLevel || 0;
  13523. var children = this._enumerateChildren(this._rootNode, [], maxDescentLevel + 1);
  13524. for (var i = 0; i < children.length; ++i) {
  13525. var node = children[i];
  13526. for (var columnIdentifier in columns) {
  13527. var text = node.data[columnIdentifier] || "";
  13528. if (text.length > widths[columnIdentifier])
  13529. widths[columnIdentifier] = text.length;
  13530. }
  13531. }
  13532. var totalColumnWidths = 0;
  13533. for (var columnIdentifier in columns)
  13534. totalColumnWidths += widths[columnIdentifier];
  13535. var recoupPercent = 0;
  13536. for (var columnIdentifier in columns) {
  13537. var width = Math.round(100 * widths[columnIdentifier] / totalColumnWidths);
  13538. if (minPercent && width < minPercent) {
  13539. recoupPercent += (minPercent - width);
  13540. width = minPercent;
  13541. } else if (maxPercent && width > maxPercent) {
  13542. recoupPercent -= (width - maxPercent);
  13543. width = maxPercent;
  13544. }
  13545. widths[columnIdentifier] = width;
  13546. }
  13547. while (minPercent && recoupPercent > 0) {
  13548. for (var columnIdentifier in columns) {
  13549. if (widths[columnIdentifier] > minPercent) {
  13550. --widths[columnIdentifier];
  13551. --recoupPercent;
  13552. if (!recoupPercent)
  13553. break;
  13554. }
  13555. }
  13556. }
  13557. while (maxPercent && recoupPercent < 0) {
  13558. for (var columnIdentifier in columns) {
  13559. if (widths[columnIdentifier] < maxPercent) {
  13560. ++widths[columnIdentifier];
  13561. ++recoupPercent;
  13562. if (!recoupPercent)
  13563. break;
  13564. }
  13565. }
  13566. }
  13567. for (var columnIdentifier in columns)
  13568. columns[columnIdentifier].element.style.width = widths[columnIdentifier] + "%";
  13569. this._columnWidthsInitialized = false;
  13570. this.updateWidths();
  13571. },
  13572. _enumerateChildren: function(rootNode, result, maxLevel)
  13573. {
  13574. if (!rootNode._isRoot)
  13575. result.push(rootNode);
  13576. if (!maxLevel)
  13577. return;
  13578. for (var i = 0; i < rootNode.children.length; ++i)
  13579. this._enumerateChildren(rootNode.children[i], result, maxLevel - 1);
  13580. return result;
  13581. },
  13582. onResize: function()
  13583. {
  13584. this.updateWidths();
  13585. },
  13586. // Updates the widths of the table, including the positions of the column
  13587. // resizers.
  13588. //
  13589. // IMPORTANT: This function MUST be called once after the element of the
  13590. // DataGrid is attached to its parent element and every subsequent time the
  13591. // width of the parent element is changed in order to make it possible to
  13592. // resize the columns.
  13593. //
  13594. // If this function is not called after the DataGrid is attached to its
  13595. // parent element, then the DataGrid's columns will not be resizable.
  13596. updateWidths: function()
  13597. {
  13598. var headerTableColumns = this._headerTableColumnGroup.children;
  13599. var tableWidth = this._dataTable.offsetWidth;
  13600. var numColumns = headerTableColumns.length;
  13601. if (!this._columnWidthsInitialized && this.element.offsetWidth) {
  13602. for (var i = 0; i < numColumns; i++) {
  13603. var columnWidth = this.headerTableBody.rows[0].cells[i].offsetWidth;
  13604. var percentWidth = ((columnWidth / tableWidth) * 100) + "%";
  13605. this._headerTableColumnGroup.children[i].style.width = percentWidth;
  13606. this._dataTableColumnGroup.children[i].style.width = percentWidth;
  13607. }
  13608. this._columnWidthsInitialized = true;
  13609. }
  13610. this._positionResizers();
  13611. this.dispatchEventToListeners("width changed");
  13612. },
  13613. columnWidthsMap: function()
  13614. {
  13615. var result = {};
  13616. for (var i = 0; i < this._columnsArray.length; ++i) {
  13617. var width = this._headerTableColumnGroup.children[i].style.width;
  13618. result[this._columnsArray[i].columnIdentifier] = parseFloat(width);
  13619. }
  13620. return result;
  13621. },
  13622. applyColumnWidthsMap: function(columnWidthsMap)
  13623. {
  13624. for (var columnIdentifier in this.columns) {
  13625. var column = this.columns[columnIdentifier];
  13626. var width = (columnWidthsMap[columnIdentifier] || 0) + "%";
  13627. this._headerTableColumnGroup.children[column.ordinal].style.width = width;
  13628. this._dataTableColumnGroup.children[column.ordinal].style.width = width;
  13629. }
  13630. delete this._columnWidthsInitialized;
  13631. this.updateWidths();
  13632. },
  13633. isColumnVisible: function(columnIdentifier)
  13634. {
  13635. var column = this.columns[columnIdentifier];
  13636. var columnElement = column.element;
  13637. return !columnElement.hidden;
  13638. },
  13639. showColumn: function(columnIdentifier)
  13640. {
  13641. var column = this.columns[columnIdentifier];
  13642. var columnElement = column.element;
  13643. if (!columnElement.hidden)
  13644. return;
  13645. columnElement.hidden = false;
  13646. columnElement.removeStyleClass("hidden");
  13647. var columnBodyElement = column.bodyElement;
  13648. columnBodyElement.hidden = false;
  13649. columnBodyElement.removeStyleClass("hidden");
  13650. },
  13651. hideColumn: function(columnIdentifier)
  13652. {
  13653. var column = this.columns[columnIdentifier];
  13654. var columnElement = column.element;
  13655. if (columnElement.hidden)
  13656. return;
  13657. var oldWidth = parseFloat(columnElement.style.width);
  13658. columnElement.hidden = true;
  13659. columnElement.addStyleClass("hidden");
  13660. columnElement.style.width = 0;
  13661. var columnBodyElement = column.bodyElement;
  13662. columnBodyElement.hidden = true;
  13663. columnBodyElement.addStyleClass("hidden");
  13664. columnBodyElement.style.width = 0;
  13665. this._columnWidthsInitialized = false;
  13666. },
  13667. get scrollContainer()
  13668. {
  13669. return this._scrollContainer;
  13670. },
  13671. isScrolledToLastRow: function()
  13672. {
  13673. return this._scrollContainer.isScrolledToBottom();
  13674. },
  13675. scrollToLastRow: function()
  13676. {
  13677. this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.offsetHeight;
  13678. },
  13679. _positionResizers: function()
  13680. {
  13681. var headerTableColumns = this._headerTableColumnGroup.children;
  13682. var numColumns = headerTableColumns.length;
  13683. var left = 0;
  13684. var previousResizer = null;
  13685. for (var i = 0; i < numColumns - 1; i++) {
  13686. var resizer = this.resizers[i];
  13687. if (!resizer) {
  13688. resizer = document.createElement("div");
  13689. resizer.addStyleClass("data-grid-resizer");
  13690. resizer.addEventListener("mousedown", this._startResizerDragging.bind(this), false);
  13691. this.element.appendChild(resizer);
  13692. this.resizers[i] = resizer;
  13693. }
  13694. left += this.headerTableBody.rows[0].cells[i].offsetWidth;
  13695. var columnIsVisible = !this._headerTableColumnGroup.children[i].hidden;
  13696. if (columnIsVisible) {
  13697. resizer.style.removeProperty("display");
  13698. resizer.style.left = left + "px";
  13699. resizer.leftNeighboringColumnID = i;
  13700. if (previousResizer)
  13701. previousResizer.rightNeighboringColumnID = i;
  13702. previousResizer = resizer;
  13703. } else {
  13704. resizer.style.setProperty("display", "none");
  13705. resizer.leftNeighboringColumnID = 0;
  13706. resizer.rightNeighboringColumnID = 0;
  13707. }
  13708. }
  13709. if (previousResizer)
  13710. previousResizer.rightNeighboringColumnID = numColumns - 1;
  13711. },
  13712. addCreationNode: function(hasChildren)
  13713. {
  13714. if (this.creationNode)
  13715. this.creationNode.makeNormal();
  13716. var emptyData = {};
  13717. for (var column in this.columns)
  13718. emptyData[column] = '';
  13719. this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren);
  13720. this.rootNode().appendChild(this.creationNode);
  13721. },
  13722. sortNodes: function(comparator, reverseMode)
  13723. {
  13724. function comparatorWrapper(a, b)
  13725. {
  13726. if (a._dataGridNode._data.summaryRow)
  13727. return 1;
  13728. if (b._dataGridNode._data.summaryRow)
  13729. return -1;
  13730. var aDataGirdNode = a._dataGridNode;
  13731. var bDataGirdNode = b._dataGridNode;
  13732. return reverseMode ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode);
  13733. }
  13734. var tbody = this.dataTableBody;
  13735. var tbodyParent = tbody.parentElement;
  13736. tbodyParent.removeChild(tbody);
  13737. var childNodes = tbody.childNodes;
  13738. var fillerRow = childNodes[childNodes.length - 1];
  13739. var sortedRows = Array.prototype.slice.call(childNodes, 0, childNodes.length - 1);
  13740. sortedRows.sort(comparatorWrapper);
  13741. var sortedRowsLength = sortedRows.length;
  13742. tbody.removeChildren();
  13743. var previousSiblingNode = null;
  13744. for (var i = 0; i < sortedRowsLength; ++i) {
  13745. var row = sortedRows[i];
  13746. var node = row._dataGridNode;
  13747. node.previousSibling = previousSiblingNode;
  13748. if (previousSiblingNode)
  13749. previousSiblingNode.nextSibling = node;
  13750. tbody.appendChild(row);
  13751. previousSiblingNode = node;
  13752. }
  13753. if (previousSiblingNode)
  13754. previousSiblingNode.nextSibling = null;
  13755. tbody.appendChild(fillerRow);
  13756. tbodyParent.appendChild(tbody);
  13757. },
  13758. _keyDown: function(event)
  13759. {
  13760. if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing)
  13761. return;
  13762. var handled = false;
  13763. var nextSelectedNode;
  13764. if (event.keyIdentifier === "Up" && !event.altKey) {
  13765. nextSelectedNode = this.selectedNode.traversePreviousNode(true);
  13766. while (nextSelectedNode && !nextSelectedNode.selectable)
  13767. nextSelectedNode = nextSelectedNode.traversePreviousNode(true);
  13768. handled = nextSelectedNode ? true : false;
  13769. } else if (event.keyIdentifier === "Down" && !event.altKey) {
  13770. nextSelectedNode = this.selectedNode.traverseNextNode(true);
  13771. while (nextSelectedNode && !nextSelectedNode.selectable)
  13772. nextSelectedNode = nextSelectedNode.traverseNextNode(true);
  13773. handled = nextSelectedNode ? true : false;
  13774. } else if (event.keyIdentifier === "Left") {
  13775. if (this.selectedNode.expanded) {
  13776. if (event.altKey)
  13777. this.selectedNode.collapseRecursively();
  13778. else
  13779. this.selectedNode.collapse();
  13780. handled = true;
  13781. } else if (this.selectedNode.parent && !this.selectedNode.parent._isRoot) {
  13782. handled = true;
  13783. if (this.selectedNode.parent.selectable) {
  13784. nextSelectedNode = this.selectedNode.parent;
  13785. handled = nextSelectedNode ? true : false;
  13786. } else if (this.selectedNode.parent)
  13787. this.selectedNode.parent.collapse();
  13788. }
  13789. } else if (event.keyIdentifier === "Right") {
  13790. if (!this.selectedNode.revealed) {
  13791. this.selectedNode.reveal();
  13792. handled = true;
  13793. } else if (this.selectedNode.hasChildren) {
  13794. handled = true;
  13795. if (this.selectedNode.expanded) {
  13796. nextSelectedNode = this.selectedNode.children[0];
  13797. handled = nextSelectedNode ? true : false;
  13798. } else {
  13799. if (event.altKey)
  13800. this.selectedNode.expandRecursively();
  13801. else
  13802. this.selectedNode.expand();
  13803. }
  13804. }
  13805. } else if (event.keyCode === 8 || event.keyCode === 46) {
  13806. if (this._deleteCallback) {
  13807. handled = true;
  13808. this._deleteCallback(this.selectedNode);
  13809. }
  13810. } else if (isEnterKey(event)) {
  13811. if (this._editCallback) {
  13812. handled = true;
  13813. this._startEditing(this.selectedNode._element.children[0]);
  13814. }
  13815. }
  13816. if (nextSelectedNode) {
  13817. nextSelectedNode.reveal();
  13818. nextSelectedNode.select();
  13819. }
  13820. if (handled)
  13821. event.consume(true);
  13822. },
  13823. dataGridNodeFromNode: function(target)
  13824. {
  13825. var rowElement = target.enclosingNodeOrSelfWithNodeName("tr");
  13826. return rowElement && rowElement._dataGridNode;
  13827. },
  13828. dataGridNodeFromPoint: function(x, y)
  13829. {
  13830. var node = this._dataTable.ownerDocument.elementFromPoint(x, y);
  13831. var rowElement = node.enclosingNodeOrSelfWithNodeName("tr");
  13832. return rowElement && rowElement._dataGridNode;
  13833. },
  13834. _clickInHeaderCell: function(event)
  13835. {
  13836. var cell = event.target.enclosingNodeOrSelfWithNodeName("th");
  13837. if (!cell || !cell.columnIdentifier || !cell.hasStyleClass("sortable"))
  13838. return;
  13839. var sortOrder = this.sortOrder;
  13840. if (this._sortColumnCell)
  13841. this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+");
  13842. if (cell == this._sortColumnCell) {
  13843. if (sortOrder === "ascending")
  13844. sortOrder = "descending";
  13845. else
  13846. sortOrder = "ascending";
  13847. }
  13848. this._sortColumnCell = cell;
  13849. cell.addStyleClass("sort-" + sortOrder);
  13850. this.dispatchEventToListeners("sorting changed");
  13851. },
  13852. markColumnAsSortedBy: function(columnIdentifier, sortOrder)
  13853. {
  13854. if (this._sortColumnCell)
  13855. this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+");
  13856. this._sortColumnCell = this._headerTableHeaders[columnIdentifier];
  13857. this._sortColumnCell.addStyleClass("sort-" + sortOrder);
  13858. },
  13859. headerTableHeader: function(columnIdentifier)
  13860. {
  13861. return this._headerTableHeaders[columnIdentifier];
  13862. },
  13863. _mouseDownInDataTable: function(event)
  13864. {
  13865. var gridNode = this.dataGridNodeFromNode(event.target);
  13866. if (!gridNode || !gridNode.selectable)
  13867. return;
  13868. if (gridNode.isEventWithinDisclosureTriangle(event))
  13869. return;
  13870. if (event.metaKey) {
  13871. if (gridNode.selected)
  13872. gridNode.deselect();
  13873. else
  13874. gridNode.select();
  13875. } else
  13876. gridNode.select();
  13877. },
  13878. _contextMenuInDataTable: function(event)
  13879. {
  13880. var contextMenu = new WebInspector.ContextMenu();
  13881. var gridNode = this.dataGridNodeFromNode(event.target);
  13882. if (this._refreshCallback && (!gridNode || gridNode !== this.creationNode))
  13883. contextMenu.appendItem(WebInspector.UIString("Refresh"), this._refreshCallback.bind(this));
  13884. if (gridNode && gridNode.selectable && !gridNode.isEventWithinDisclosureTriangle(event)) {
  13885. if (this._editCallback) {
  13886. if (gridNode === this.creationNode)
  13887. contextMenu.appendItem(WebInspector.UIString("Add New"), this._startEditing.bind(this, event.target));
  13888. else
  13889. contextMenu.appendItem(WebInspector.UIString("Edit"), this._startEditing.bind(this, event.target));
  13890. }
  13891. if (this._deleteCallback && gridNode !== this.creationNode)
  13892. contextMenu.appendItem(WebInspector.UIString("Delete"), this._deleteCallback.bind(this, gridNode));
  13893. }
  13894. contextMenu.show(event);
  13895. },
  13896. _clickInDataTable: function(event)
  13897. {
  13898. var gridNode = this.dataGridNodeFromNode(event.target);
  13899. if (!gridNode || !gridNode.hasChildren)
  13900. return;
  13901. if (!gridNode.isEventWithinDisclosureTriangle(event))
  13902. return;
  13903. if (gridNode.expanded) {
  13904. if (event.altKey)
  13905. gridNode.collapseRecursively();
  13906. else
  13907. gridNode.collapse();
  13908. } else {
  13909. if (event.altKey)
  13910. gridNode.expandRecursively();
  13911. else
  13912. gridNode.expand();
  13913. }
  13914. },
  13915. get resizeMethod()
  13916. {
  13917. if (typeof this._resizeMethod === "undefined")
  13918. return WebInspector.DataGrid.ResizeMethod.Nearest;
  13919. return this._resizeMethod;
  13920. },
  13921. set resizeMethod(method)
  13922. {
  13923. this._resizeMethod = method;
  13924. },
  13925. _startResizerDragging: function(event)
  13926. {
  13927. this._currentResizer = event.target;
  13928. if (!this._currentResizer.rightNeighboringColumnID)
  13929. return;
  13930. WebInspector.elementDragStart(this._currentResizer, this._resizerDragging.bind(this),
  13931. this._endResizerDragging.bind(this), event, "col-resize");
  13932. },
  13933. _resizerDragging: function(event)
  13934. {
  13935. var resizer = this._currentResizer;
  13936. if (!resizer)
  13937. return;
  13938. var dragPoint = event.clientX - this.element.totalOffsetLeft();
  13939. var leftCellIndex = resizer.leftNeighboringColumnID;
  13940. var rightCellIndex = resizer.rightNeighboringColumnID;
  13941. var firstRowCells = this.headerTableBody.rows[0].cells;
  13942. var leftEdgeOfPreviousColumn = 0;
  13943. for (var i = 0; i < leftCellIndex; i++)
  13944. leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth;
  13945. if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.Last) {
  13946. rightCellIndex = this.resizers.length;
  13947. } else if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.First) {
  13948. leftEdgeOfPreviousColumn += firstRowCells[leftCellIndex].offsetWidth - firstRowCells[0].offsetWidth;
  13949. leftCellIndex = 0;
  13950. }
  13951. var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[leftCellIndex].offsetWidth + firstRowCells[rightCellIndex].offsetWidth;
  13952. var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding;
  13953. var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding;
  13954. dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum);
  13955. resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px";
  13956. var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + "%";
  13957. this._headerTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
  13958. this._dataTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
  13959. var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + "%";
  13960. this._headerTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn;
  13961. this._dataTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn;
  13962. this._positionResizers();
  13963. event.preventDefault();
  13964. this.dispatchEventToListeners("width changed");
  13965. },
  13966. _endResizerDragging: function(event)
  13967. {
  13968. WebInspector.elementDragEnd(event);
  13969. this._currentResizer = null;
  13970. this.dispatchEventToListeners("width changed");
  13971. },
  13972. ColumnResizePadding: 10,
  13973. CenterResizerOverBorderAdjustment: 3,
  13974. }
  13975. WebInspector.DataGrid.ResizeMethod = {
  13976. Nearest: "nearest",
  13977. First: "first",
  13978. Last: "last"
  13979. }
  13980. WebInspector.DataGrid.prototype.__proto__ = WebInspector.View.prototype;
  13981. WebInspector.DataGridNode = function(data, hasChildren)
  13982. {
  13983. this._expanded = false;
  13984. this._selected = false;
  13985. this._shouldRefreshChildren = true;
  13986. this._data = data || {};
  13987. this.hasChildren = hasChildren || false;
  13988. this.children = [];
  13989. this.dataGrid = null;
  13990. this.parent = null;
  13991. this.previousSibling = null;
  13992. this.nextSibling = null;
  13993. this.disclosureToggleWidth = 10;
  13994. }
  13995. WebInspector.DataGridNode.prototype = {
  13996. selectable: true,
  13997. _isRoot: false,
  13998. get element()
  13999. {
  14000. if (this._element)
  14001. return this._element;
  14002. if (!this.dataGrid)
  14003. return null;
  14004. this._element = document.createElement("tr");
  14005. this._element._dataGridNode = this;
  14006. if (this.hasChildren)
  14007. this._element.addStyleClass("parent");
  14008. if (this.expanded)
  14009. this._element.addStyleClass("expanded");
  14010. if (this.selected)
  14011. this._element.addStyleClass("selected");
  14012. if (this.revealed)
  14013. this._element.addStyleClass("revealed");
  14014. this.createCells();
  14015. return this._element;
  14016. },
  14017. createCells: function()
  14018. {
  14019. for (var columnIdentifier in this.dataGrid.columns) {
  14020. var cell = this.createCell(columnIdentifier);
  14021. this._element.appendChild(cell);
  14022. }
  14023. },
  14024. get data()
  14025. {
  14026. return this._data;
  14027. },
  14028. set data(x)
  14029. {
  14030. this._data = x || {};
  14031. this.refresh();
  14032. },
  14033. get revealed()
  14034. {
  14035. if ("_revealed" in this)
  14036. return this._revealed;
  14037. var currentAncestor = this.parent;
  14038. while (currentAncestor && !currentAncestor._isRoot) {
  14039. if (!currentAncestor.expanded) {
  14040. this._revealed = false;
  14041. return false;
  14042. }
  14043. currentAncestor = currentAncestor.parent;
  14044. }
  14045. this._revealed = true;
  14046. return true;
  14047. },
  14048. set hasChildren(x)
  14049. {
  14050. if (this._hasChildren === x)
  14051. return;
  14052. this._hasChildren = x;
  14053. if (!this._element)
  14054. return;
  14055. if (this._hasChildren)
  14056. {
  14057. this._element.addStyleClass("parent");
  14058. if (this.expanded)
  14059. this._element.addStyleClass("expanded");
  14060. }
  14061. else
  14062. {
  14063. this._element.removeStyleClass("parent");
  14064. this._element.removeStyleClass("expanded");
  14065. }
  14066. },
  14067. get hasChildren()
  14068. {
  14069. return this._hasChildren;
  14070. },
  14071. set revealed(x)
  14072. {
  14073. if (this._revealed === x)
  14074. return;
  14075. this._revealed = x;
  14076. if (this._element) {
  14077. if (this._revealed)
  14078. this._element.addStyleClass("revealed");
  14079. else
  14080. this._element.removeStyleClass("revealed");
  14081. }
  14082. for (var i = 0; i < this.children.length; ++i)
  14083. this.children[i].revealed = x && this.expanded;
  14084. },
  14085. get depth()
  14086. {
  14087. if ("_depth" in this)
  14088. return this._depth;
  14089. if (this.parent && !this.parent._isRoot)
  14090. this._depth = this.parent.depth + 1;
  14091. else
  14092. this._depth = 0;
  14093. return this._depth;
  14094. },
  14095. get leftPadding()
  14096. {
  14097. if (typeof(this._leftPadding) === "number")
  14098. return this._leftPadding;
  14099. this._leftPadding = this.depth * this.dataGrid.indentWidth;
  14100. return this._leftPadding;
  14101. },
  14102. get shouldRefreshChildren()
  14103. {
  14104. return this._shouldRefreshChildren;
  14105. },
  14106. set shouldRefreshChildren(x)
  14107. {
  14108. this._shouldRefreshChildren = x;
  14109. if (x && this.expanded)
  14110. this.expand();
  14111. },
  14112. get selected()
  14113. {
  14114. return this._selected;
  14115. },
  14116. set selected(x)
  14117. {
  14118. if (x)
  14119. this.select();
  14120. else
  14121. this.deselect();
  14122. },
  14123. get expanded()
  14124. {
  14125. return this._expanded;
  14126. },
  14127. set expanded(x)
  14128. {
  14129. if (x)
  14130. this.expand();
  14131. else
  14132. this.collapse();
  14133. },
  14134. refresh: function()
  14135. {
  14136. if (!this._element || !this.dataGrid)
  14137. return;
  14138. this._element.removeChildren();
  14139. this.createCells();
  14140. },
  14141. createCell: function(columnIdentifier)
  14142. {
  14143. var cell = document.createElement("td");
  14144. cell.className = columnIdentifier + "-column";
  14145. var alignment = this.dataGrid.aligned[columnIdentifier];
  14146. if (alignment)
  14147. cell.addStyleClass(alignment);
  14148. var div = document.createElement("div");
  14149. div.textContent = this.data[columnIdentifier];
  14150. cell.appendChild(div);
  14151. if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) {
  14152. cell.addStyleClass("disclosure");
  14153. if (this.leftPadding)
  14154. cell.style.setProperty("padding-left", this.leftPadding + "px");
  14155. }
  14156. return cell;
  14157. },
  14158. nodeHeight: function()
  14159. {
  14160. var rowHeight = 16;
  14161. if (!this.revealed)
  14162. return 0;
  14163. if (!this.expanded)
  14164. return rowHeight;
  14165. var result = rowHeight;
  14166. for (var i = 0; i < this.children.length; i++)
  14167. result += this.children[i].nodeHeight();
  14168. return result;
  14169. },
  14170. appendChild: function(child)
  14171. {
  14172. this.insertChild(child, this.children.length);
  14173. },
  14174. insertChild: function(child, index)
  14175. {
  14176. if (!child)
  14177. throw("insertChild: Node can't be undefined or null.");
  14178. if (child.parent === this)
  14179. throw("insertChild: Node is already a child of this node.");
  14180. if (child.parent)
  14181. child.parent.removeChild(child);
  14182. this.children.splice(index, 0, child);
  14183. this.hasChildren = true;
  14184. child.parent = this;
  14185. child.dataGrid = this.dataGrid;
  14186. child._recalculateSiblings(index);
  14187. delete child._depth;
  14188. delete child._revealed;
  14189. delete child._attached;
  14190. child._shouldRefreshChildren = true;
  14191. var current = child.children[0];
  14192. while (current) {
  14193. current.dataGrid = this.dataGrid;
  14194. delete current._depth;
  14195. delete current._revealed;
  14196. delete current._attached;
  14197. current._shouldRefreshChildren = true;
  14198. current = current.traverseNextNode(false, child, true);
  14199. }
  14200. if (this.expanded)
  14201. child._attach();
  14202. if (!this.revealed)
  14203. child.revealed = false;
  14204. },
  14205. removeChild: function(child)
  14206. {
  14207. if (!child)
  14208. throw("removeChild: Node can't be undefined or null.");
  14209. if (child.parent !== this)
  14210. throw("removeChild: Node is not a child of this node.");
  14211. child.deselect();
  14212. child._detach();
  14213. this.children.remove(child, true);
  14214. if (child.previousSibling)
  14215. child.previousSibling.nextSibling = child.nextSibling;
  14216. if (child.nextSibling)
  14217. child.nextSibling.previousSibling = child.previousSibling;
  14218. child.dataGrid = null;
  14219. child.parent = null;
  14220. child.nextSibling = null;
  14221. child.previousSibling = null;
  14222. if (this.children.length <= 0)
  14223. this.hasChildren = false;
  14224. },
  14225. removeChildren: function()
  14226. {
  14227. for (var i = 0; i < this.children.length; ++i) {
  14228. var child = this.children[i];
  14229. child.deselect();
  14230. child._detach();
  14231. child.dataGrid = null;
  14232. child.parent = null;
  14233. child.nextSibling = null;
  14234. child.previousSibling = null;
  14235. }
  14236. this.children = [];
  14237. this.hasChildren = false;
  14238. },
  14239. _recalculateSiblings: function(myIndex)
  14240. {
  14241. if (!this.parent)
  14242. return;
  14243. var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null);
  14244. if (previousChild) {
  14245. previousChild.nextSibling = this;
  14246. this.previousSibling = previousChild;
  14247. } else
  14248. this.previousSibling = null;
  14249. var nextChild = this.parent.children[myIndex + 1];
  14250. if (nextChild) {
  14251. nextChild.previousSibling = this;
  14252. this.nextSibling = nextChild;
  14253. } else
  14254. this.nextSibling = null;
  14255. },
  14256. collapse: function()
  14257. {
  14258. if (this._isRoot)
  14259. return;
  14260. if (this._element)
  14261. this._element.removeStyleClass("expanded");
  14262. this._expanded = false;
  14263. for (var i = 0; i < this.children.length; ++i)
  14264. this.children[i].revealed = false;
  14265. this.dispatchEventToListeners("collapsed");
  14266. },
  14267. collapseRecursively: function()
  14268. {
  14269. var item = this;
  14270. while (item) {
  14271. if (item.expanded)
  14272. item.collapse();
  14273. item = item.traverseNextNode(false, this, true);
  14274. }
  14275. },
  14276. expand: function()
  14277. {
  14278. if (!this.hasChildren || this.expanded)
  14279. return;
  14280. if (this._isRoot)
  14281. return;
  14282. if (this.revealed && !this._shouldRefreshChildren)
  14283. for (var i = 0; i < this.children.length; ++i)
  14284. this.children[i].revealed = true;
  14285. if (this._shouldRefreshChildren) {
  14286. for (var i = 0; i < this.children.length; ++i)
  14287. this.children[i]._detach();
  14288. this.dispatchEventToListeners("populate");
  14289. if (this._attached) {
  14290. for (var i = 0; i < this.children.length; ++i) {
  14291. var child = this.children[i];
  14292. if (this.revealed)
  14293. child.revealed = true;
  14294. child._attach();
  14295. }
  14296. }
  14297. delete this._shouldRefreshChildren;
  14298. }
  14299. if (this._element)
  14300. this._element.addStyleClass("expanded");
  14301. this._expanded = true;
  14302. this.dispatchEventToListeners("expanded");
  14303. },
  14304. expandRecursively: function()
  14305. {
  14306. var item = this;
  14307. while (item) {
  14308. item.expand();
  14309. item = item.traverseNextNode(false, this);
  14310. }
  14311. },
  14312. reveal: function()
  14313. {
  14314. if (this._isRoot)
  14315. return;
  14316. var currentAncestor = this.parent;
  14317. while (currentAncestor && !currentAncestor._isRoot) {
  14318. if (!currentAncestor.expanded)
  14319. currentAncestor.expand();
  14320. currentAncestor = currentAncestor.parent;
  14321. }
  14322. this.element.scrollIntoViewIfNeeded(false);
  14323. this.dispatchEventToListeners("revealed");
  14324. },
  14325. select: function(supressSelectedEvent)
  14326. {
  14327. if (!this.dataGrid || !this.selectable || this.selected)
  14328. return;
  14329. if (this.dataGrid.selectedNode)
  14330. this.dataGrid.selectedNode.deselect();
  14331. this._selected = true;
  14332. this.dataGrid.selectedNode = this;
  14333. if (this._element)
  14334. this._element.addStyleClass("selected");
  14335. if (!supressSelectedEvent) {
  14336. this.dispatchEventToListeners("selected");
  14337. this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.SelectedNode);
  14338. }
  14339. },
  14340. revealAndSelect: function()
  14341. {
  14342. if (this._isRoot)
  14343. return;
  14344. this.reveal();
  14345. this.select();
  14346. },
  14347. deselect: function(supressDeselectedEvent)
  14348. {
  14349. if (!this.dataGrid || this.dataGrid.selectedNode !== this || !this.selected)
  14350. return;
  14351. this._selected = false;
  14352. this.dataGrid.selectedNode = null;
  14353. if (this._element)
  14354. this._element.removeStyleClass("selected");
  14355. if (!supressDeselectedEvent) {
  14356. this.dispatchEventToListeners("deselected");
  14357. this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.DeselectedNode);
  14358. }
  14359. },
  14360. traverseNextNode: function(skipHidden, stayWithin, dontPopulate, info)
  14361. {
  14362. if (!dontPopulate && this.hasChildren)
  14363. this.dispatchEventToListeners("populate");
  14364. if (info)
  14365. info.depthChange = 0;
  14366. var node = (!skipHidden || this.revealed) ? this.children[0] : null;
  14367. if (node && (!skipHidden || this.expanded)) {
  14368. if (info)
  14369. info.depthChange = 1;
  14370. return node;
  14371. }
  14372. if (this === stayWithin)
  14373. return null;
  14374. node = (!skipHidden || this.revealed) ? this.nextSibling : null;
  14375. if (node)
  14376. return node;
  14377. node = this;
  14378. while (node && !node._isRoot && !((!skipHidden || node.revealed) ? node.nextSibling : null) && node.parent !== stayWithin) {
  14379. if (info)
  14380. info.depthChange -= 1;
  14381. node = node.parent;
  14382. }
  14383. if (!node)
  14384. return null;
  14385. return (!skipHidden || node.revealed) ? node.nextSibling : null;
  14386. },
  14387. traversePreviousNode: function(skipHidden, dontPopulate)
  14388. {
  14389. var node = (!skipHidden || this.revealed) ? this.previousSibling : null;
  14390. if (!dontPopulate && node && node.hasChildren)
  14391. node.dispatchEventToListeners("populate");
  14392. while (node && ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null)) {
  14393. if (!dontPopulate && node.hasChildren)
  14394. node.dispatchEventToListeners("populate");
  14395. node = ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null);
  14396. }
  14397. if (node)
  14398. return node;
  14399. if (!this.parent || this.parent._isRoot)
  14400. return null;
  14401. return this.parent;
  14402. },
  14403. isEventWithinDisclosureTriangle: function(event)
  14404. {
  14405. if (!this.hasChildren)
  14406. return false;
  14407. var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
  14408. if (!cell.hasStyleClass("disclosure"))
  14409. return false;
  14410. var left = cell.totalOffsetLeft() + this.leftPadding;
  14411. return event.pageX >= left && event.pageX <= left + this.disclosureToggleWidth;
  14412. },
  14413. _attach: function()
  14414. {
  14415. if (!this.dataGrid || this._attached)
  14416. return;
  14417. this._attached = true;
  14418. var nextNode = null;
  14419. var previousNode = this.traversePreviousNode(true, true);
  14420. if (previousNode && previousNode.element.parentNode && previousNode.element.nextSibling)
  14421. nextNode = previousNode.element.nextSibling;
  14422. if (!nextNode)
  14423. nextNode = this.dataGrid.dataTableBody.firstChild;
  14424. this.dataGrid.dataTableBody.insertBefore(this.element, nextNode);
  14425. if (this.expanded)
  14426. for (var i = 0; i < this.children.length; ++i)
  14427. this.children[i]._attach();
  14428. },
  14429. _detach: function()
  14430. {
  14431. if (!this._attached)
  14432. return;
  14433. this._attached = false;
  14434. if (this._element && this._element.parentNode)
  14435. this._element.parentNode.removeChild(this._element);
  14436. for (var i = 0; i < this.children.length; ++i)
  14437. this.children[i]._detach();
  14438. this.wasDetached();
  14439. },
  14440. wasDetached: function()
  14441. {
  14442. },
  14443. savePosition: function()
  14444. {
  14445. if (this._savedPosition)
  14446. return;
  14447. if (!this.parent)
  14448. throw("savePosition: Node must have a parent.");
  14449. this._savedPosition = {
  14450. parent: this.parent,
  14451. index: this.parent.children.indexOf(this)
  14452. };
  14453. },
  14454. restorePosition: function()
  14455. {
  14456. if (!this._savedPosition)
  14457. return;
  14458. if (this.parent !== this._savedPosition.parent)
  14459. this._savedPosition.parent.insertChild(this, this._savedPosition.index);
  14460. delete this._savedPosition;
  14461. }
  14462. }
  14463. WebInspector.DataGridNode.prototype.__proto__ = WebInspector.Object.prototype;
  14464. WebInspector.CreationDataGridNode = function(data, hasChildren)
  14465. {
  14466. WebInspector.DataGridNode.call(this, data, hasChildren);
  14467. this.isCreationNode = true;
  14468. }
  14469. WebInspector.CreationDataGridNode.prototype = {
  14470. makeNormal: function()
  14471. {
  14472. delete this.isCreationNode;
  14473. delete this.makeNormal;
  14474. }
  14475. }
  14476. WebInspector.CreationDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
  14477. WebInspector.ShowMoreDataGridNode = function(callback, startPosition, endPosition, chunkSize)
  14478. {
  14479. WebInspector.DataGridNode.call(this, {summaryRow:true}, false);
  14480. this._callback = callback;
  14481. this._startPosition = startPosition;
  14482. this._endPosition = endPosition;
  14483. this._chunkSize = chunkSize;
  14484. this.showNext = document.createElement("button");
  14485. this.showNext.setAttribute("type", "button");
  14486. this.showNext.addEventListener("click", this._showNextChunk.bind(this), false);
  14487. this.showNext.textContent = WebInspector.UIString("Show %d before", this._chunkSize);
  14488. this.showAll = document.createElement("button");
  14489. this.showAll.setAttribute("type", "button");
  14490. this.showAll.addEventListener("click", this._showAll.bind(this), false);
  14491. this.showLast = document.createElement("button");
  14492. this.showLast.setAttribute("type", "button");
  14493. this.showLast.addEventListener("click", this._showLastChunk.bind(this), false);
  14494. this.showLast.textContent = WebInspector.UIString("Show %d after", this._chunkSize);
  14495. this._updateLabels();
  14496. this.selectable = false;
  14497. }
  14498. WebInspector.ShowMoreDataGridNode.prototype = {
  14499. _showNextChunk: function()
  14500. {
  14501. this._callback(this._startPosition, this._startPosition + this._chunkSize);
  14502. },
  14503. _showAll: function()
  14504. {
  14505. this._callback(this._startPosition, this._endPosition);
  14506. },
  14507. _showLastChunk: function()
  14508. {
  14509. this._callback(this._endPosition - this._chunkSize, this._endPosition);
  14510. },
  14511. _updateLabels: function()
  14512. {
  14513. var totalSize = this._endPosition - this._startPosition;
  14514. if (totalSize > this._chunkSize) {
  14515. this.showNext.removeStyleClass("hidden");
  14516. this.showLast.removeStyleClass("hidden");
  14517. } else {
  14518. this.showNext.addStyleClass("hidden");
  14519. this.showLast.addStyleClass("hidden");
  14520. }
  14521. this.showAll.textContent = WebInspector.UIString("Show all %d", totalSize);
  14522. },
  14523. createCells: function()
  14524. {
  14525. var cell = document.createElement("td");
  14526. if (this.depth)
  14527. cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px");
  14528. cell.appendChild(this.showNext);
  14529. cell.appendChild(this.showAll);
  14530. cell.appendChild(this.showLast);
  14531. this._element.appendChild(cell);
  14532. var columns = this.dataGrid.columns;
  14533. var count = 0;
  14534. for (var c in columns)
  14535. ++count;
  14536. while (--count > 0) {
  14537. cell = document.createElement("td");
  14538. this._element.appendChild(cell);
  14539. }
  14540. },
  14541. setStartPosition: function(from)
  14542. {
  14543. this._startPosition = from;
  14544. this._updateLabels();
  14545. },
  14546. setEndPosition: function(to)
  14547. {
  14548. this._endPosition = to;
  14549. this._updateLabels();
  14550. },
  14551. nodeHeight: function()
  14552. {
  14553. return 33;
  14554. }
  14555. };
  14556. WebInspector.ShowMoreDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype;
  14557. WebInspector.CookiesTable = function(cookieDomain, expandable, deleteCallback, refreshCallback)
  14558. {
  14559. WebInspector.View.call(this);
  14560. this.element.className = "fill";
  14561. this._cookieDomain = cookieDomain;
  14562. var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} };
  14563. columns[0].title = WebInspector.UIString("Name");
  14564. columns[0].sortable = true;
  14565. columns[0].disclosure = expandable;
  14566. columns[0].width = "24%";
  14567. columns[1].title = WebInspector.UIString("Value");
  14568. columns[1].sortable = true;
  14569. columns[1].width = "34%";
  14570. columns[2].title = WebInspector.UIString("Domain");
  14571. columns[2].sortable = true;
  14572. columns[2].width = "7%";
  14573. columns[3].title = WebInspector.UIString("Path");
  14574. columns[3].sortable = true;
  14575. columns[3].width = "7%";
  14576. columns[4].title = WebInspector.UIString("Expires");
  14577. columns[4].sortable = true;
  14578. columns[4].width = "7%";
  14579. columns[5].title = WebInspector.UIString("Size");
  14580. columns[5].aligned = "right";
  14581. columns[5].sortable = true;
  14582. columns[5].width = "7%";
  14583. columns[6].title = WebInspector.UIString("HTTP");
  14584. columns[6].aligned = "centered";
  14585. columns[6].sortable = true;
  14586. columns[6].width = "7%";
  14587. columns[7].title = WebInspector.UIString("Secure");
  14588. columns[7].aligned = "centered";
  14589. columns[7].sortable = true;
  14590. columns[7].width = "7%";
  14591. this._dataGrid = new WebInspector.DataGrid(columns, undefined, deleteCallback ? this._onDeleteFromGrid.bind(this, deleteCallback) : undefined);
  14592. this._dataGrid.addEventListener("sorting changed", this._rebuildTable, this);
  14593. this._dataGrid.refreshCallback = refreshCallback;
  14594. this._dataGrid.show(this.element);
  14595. this._data = [];
  14596. }
  14597. WebInspector.CookiesTable.prototype = {
  14598. updateWidths: function()
  14599. {
  14600. if (this._dataGrid)
  14601. this._dataGrid.updateWidths();
  14602. },
  14603. setCookies: function(cookies)
  14604. {
  14605. this._data = [{cookies: cookies}];
  14606. this._rebuildTable();
  14607. },
  14608. addCookiesFolder: function(folderName, cookies)
  14609. {
  14610. this._data.push({cookies: cookies, folderName: folderName});
  14611. this._rebuildTable();
  14612. },
  14613. get selectedCookie()
  14614. {
  14615. var node = this._dataGrid.selectedNode;
  14616. return node ? node.cookie : null;
  14617. },
  14618. _rebuildTable: function()
  14619. {
  14620. this._dataGrid.rootNode().removeChildren();
  14621. for (var i = 0; i < this._data.length; ++i) {
  14622. var item = this._data[i];
  14623. if (item.folderName) {
  14624. var groupData = [ item.folderName, "", "", "", "", this._totalSize(item.cookies), "", "" ];
  14625. var groupNode = new WebInspector.DataGridNode(groupData);
  14626. groupNode.selectable = true;
  14627. this._dataGrid.rootNode().appendChild(groupNode);
  14628. groupNode.element.addStyleClass("row-group");
  14629. this._populateNode(groupNode, item.cookies);
  14630. groupNode.expand();
  14631. } else
  14632. this._populateNode(this._dataGrid.rootNode(), item.cookies);
  14633. }
  14634. },
  14635. _populateNode: function(parentNode, cookies)
  14636. {
  14637. var selectedCookie = this.selectedCookie;
  14638. parentNode.removeChildren();
  14639. if (!cookies)
  14640. return;
  14641. this._sortCookies(cookies);
  14642. for (var i = 0; i < cookies.length; ++i) {
  14643. var cookieNode = this._createGridNode(cookies[i]);
  14644. parentNode.appendChild(cookieNode);
  14645. if (selectedCookie === cookies[i])
  14646. cookieNode.selected = true;
  14647. }
  14648. },
  14649. _totalSize: function(cookies)
  14650. {
  14651. var totalSize = 0;
  14652. for (var i = 0; cookies && i < cookies.length; ++i)
  14653. totalSize += cookies[i].size;
  14654. return totalSize;
  14655. },
  14656. _sortCookies: function(cookies)
  14657. {
  14658. var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1;
  14659. function localeCompare(field, cookie1, cookie2)
  14660. {
  14661. return sortDirection * (cookie1[field] + "").localeCompare(cookie2[field] + "")
  14662. }
  14663. function numberCompare(field, cookie1, cookie2)
  14664. {
  14665. return sortDirection * (cookie1[field] - cookie2[field]);
  14666. }
  14667. function expiresCompare(cookie1, cookie2)
  14668. {
  14669. if (cookie1.session !== cookie2.session)
  14670. return sortDirection * (cookie1.session ? 1 : -1);
  14671. if (cookie1.session)
  14672. return 0;
  14673. return sortDirection * (cookie1.expires - cookie2.expires);
  14674. }
  14675. var comparator;
  14676. switch (parseInt(this._dataGrid.sortColumnIdentifier, 10)) {
  14677. case 0: comparator = localeCompare.bind(this, "name"); break;
  14678. case 1: comparator = localeCompare.bind(this, "value"); break;
  14679. case 2: comparator = localeCompare.bind(this, "domain"); break;
  14680. case 3: comparator = localeCompare.bind(this, "path"); break;
  14681. case 4: comparator = expiresCompare; break;
  14682. case 5: comparator = numberCompare.bind(this, "size"); break;
  14683. case 6: comparator = localeCompare.bind(this, "httpOnly"); break;
  14684. case 7: comparator = localeCompare.bind(this, "secure"); break;
  14685. default: localeCompare.bind(this, "name");
  14686. }
  14687. cookies.sort(comparator);
  14688. },
  14689. _createGridNode: function(cookie)
  14690. {
  14691. var data = {};
  14692. data[0] = cookie.name;
  14693. data[1] = cookie.value;
  14694. data[2] = cookie.domain || "";
  14695. data[3] = cookie.path || "";
  14696. data[4] = cookie.type === WebInspector.Cookie.Type.Request ? "" :
  14697. (cookie.session ? WebInspector.UIString("Session") : new Date(cookie.expires).toGMTString());
  14698. data[5] = cookie.size;
  14699. const checkmark = "\u2713";
  14700. data[6] = (cookie.httpOnly ? checkmark : "");
  14701. data[7] = (cookie.secure ? checkmark : "");
  14702. var node = new WebInspector.DataGridNode(data);
  14703. node.cookie = cookie;
  14704. node.selectable = true;
  14705. return node;
  14706. },
  14707. _onDeleteFromGrid: function(deleteCallback, node)
  14708. {
  14709. deleteCallback(node.cookie);
  14710. }
  14711. }
  14712. WebInspector.CookiesTable.prototype.__proto__ = WebInspector.View.prototype;
  14713. WebInspector.CookieItemsView = function(treeElement, cookieDomain)
  14714. {
  14715. WebInspector.View.call(this);
  14716. this.element.addStyleClass("storage-view");
  14717. this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
  14718. this._deleteButton.visible = false;
  14719. this._deleteButton.addEventListener("click", this._deleteButtonClicked, this);
  14720. this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
  14721. this._refreshButton.addEventListener("click", this._refreshButtonClicked, this);
  14722. this._treeElement = treeElement;
  14723. this._cookieDomain = cookieDomain;
  14724. this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("This site has no cookies."));
  14725. this._emptyView.show(this.element);
  14726. this.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
  14727. }
  14728. WebInspector.CookieItemsView.prototype = {
  14729. get statusBarItems()
  14730. {
  14731. return [this._refreshButton.element, this._deleteButton.element];
  14732. },
  14733. wasShown: function()
  14734. {
  14735. this._update();
  14736. },
  14737. willHide: function()
  14738. {
  14739. this._deleteButton.visible = false;
  14740. },
  14741. _update: function()
  14742. {
  14743. WebInspector.Cookies.getCookiesAsync(this._updateWithCookies.bind(this));
  14744. },
  14745. _updateWithCookies: function(allCookies, isAdvanced)
  14746. {
  14747. this._cookies = isAdvanced ? this._filterCookiesForDomain(allCookies) : allCookies;
  14748. if (!this._cookies.length) {
  14749. this._emptyView.show(this.element);
  14750. this._deleteButton.visible = false;
  14751. if (this._cookiesTable)
  14752. this._cookiesTable.detach();
  14753. return;
  14754. }
  14755. if (!this._cookiesTable)
  14756. this._cookiesTable = isAdvanced ? new WebInspector.CookiesTable(this._cookieDomain, false, this._deleteCookie.bind(this), this._update.bind(this))