A Pen by Harris Novick on CodePen.
Created
October 3, 2013 16:46
-
-
Save Saminou24/6813009 to your computer and use it in GitHub Desktop.
A Pen by Harris Novick.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions | |
are met: | |
1. Redistributions of source code must retain the above copyright | |
notice, this list of conditions and the following disclaimer. | |
2. Redistributions in binary form must reproduce the above copyright | |
notice, this list of conditions and the following disclaimer in the | |
documentation and/or other materials provided with the distribution. | |
3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
its contributors may be used to endorse or promote products derived | |
from this software without specific prior written permission. | |
THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
--> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> | |
<link rel="stylesheet" type="text/css" href="devTools.css"> | |
<script type="text/javascript" src="DevTools.js"></script> | |
</head> | |
<body class="detached" id="webkit-web-inspector"> | |
<div class="outer"> | |
<div id="toolbar"> | |
<div class="toolbar-item close-left"><button id="close-button-left"></button></div> | |
<div id="toolbar-controls"> | |
<div class="toolbar-item"><button id="toolbar-dropdown-arrow" class="toolbar-label">»</button></div> | |
<div class="toolbar-item close-right"><button id="close-button-right"></button></div> | |
</div> | |
</div> | |
<div id="main"> | |
<div id="floating-status-bar-container" class="status-bar"><div id="floating-status-bar-resizer"></div></div> | |
</div> | |
<div id="drawer"></div> | |
<div id="main-status-bar" class="status-bar"> | |
<div id="bottom-status-bar-container"> | |
<div id="panel-status-bar"></div> | |
</div> | |
<div id="error-warning-count" class="hidden"></div> | |
</div> | |
</div> | |
</body> | |
</html> |
This file has been truncated, but you can view the full file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Object.isEmpty = function(obj) | |
{ | |
for (var i in obj) | |
return false; | |
return true; | |
} | |
Object.values = function(obj) | |
{ | |
var keys = Object.keys(obj); | |
var result = []; | |
for (var i = 0; i < keys.length; ++i) | |
result.push(obj[keys[i]]); | |
return result; | |
} | |
String.prototype.hasSubstring = function(string, caseInsensitive) | |
{ | |
if (!caseInsensitive) | |
return this.indexOf(string) !== -1; | |
return this.match(new RegExp(string.escapeForRegExp(), "i")); | |
} | |
String.prototype.findAll = function(string) | |
{ | |
var matches = []; | |
var i = this.indexOf(string); | |
while (i !== -1) { | |
matches.push(i); | |
i = this.indexOf(string, i + string.length); | |
} | |
return matches; | |
} | |
String.prototype.lineEndings = function() | |
{ | |
if (!this._lineEndings) { | |
this._lineEndings = this.findAll("\n"); | |
this._lineEndings.push(this.length); | |
} | |
return this._lineEndings; | |
} | |
String.prototype.escapeCharacters = function(chars) | |
{ | |
var foundChar = false; | |
for (var i = 0; i < chars.length; ++i) { | |
if (this.indexOf(chars.charAt(i)) !== -1) { | |
foundChar = true; | |
break; | |
} | |
} | |
if (!foundChar) | |
return this; | |
var result = ""; | |
for (var i = 0; i < this.length; ++i) { | |
if (chars.indexOf(this.charAt(i)) !== -1) | |
result += "\\"; | |
result += this.charAt(i); | |
} | |
return result; | |
} | |
String.prototype.escapeForRegExp = function() | |
{ | |
return this.escapeCharacters("^[]{}()\\.$*+?|"); | |
} | |
String.prototype.escapeHTML = function() | |
{ | |
return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """); | |
} | |
String.prototype.collapseWhitespace = function() | |
{ | |
return this.replace(/[\s\xA0]+/g, " "); | |
} | |
String.prototype.trimMiddle = function(maxLength) | |
{ | |
if (this.length <= maxLength) | |
return this; | |
var leftHalf = maxLength >> 1; | |
var rightHalf = maxLength - leftHalf - 1; | |
return this.substr(0, leftHalf) + "\u2026" + this.substr(this.length - rightHalf, rightHalf); | |
} | |
String.prototype.trimEnd = function(maxLength) | |
{ | |
if (this.length <= maxLength) | |
return this; | |
return this.substr(0, maxLength - 1) + "\u2026"; | |
} | |
String.prototype.trimURL = function(baseURLDomain) | |
{ | |
var result = this.replace(/^(https|http|file):\/\//i, ""); | |
if (baseURLDomain) | |
result = result.replace(new RegExp("^" + baseURLDomain.escapeForRegExp(), "i"), ""); | |
return result; | |
} | |
function sanitizeHref(href) | |
{ | |
return href && href.trim().toLowerCase().startsWith("javascript:") ? "" : href; | |
} | |
String.prototype.removeURLFragment = function() | |
{ | |
var fragmentIndex = this.indexOf("#"); | |
if (fragmentIndex == -1) | |
fragmentIndex = this.length; | |
return this.substring(0, fragmentIndex); | |
} | |
String.prototype.startsWith = function(substring) | |
{ | |
return !this.lastIndexOf(substring, 0); | |
} | |
String.prototype.endsWith = function(substring) | |
{ | |
return this.indexOf(substring, this.length - substring.length) !== -1; | |
} | |
Number.constrain = function(num, min, max) | |
{ | |
if (num < min) | |
num = min; | |
else if (num > max) | |
num = max; | |
return num; | |
} | |
Date.prototype.toISO8601Compact = function() | |
{ | |
function leadZero(x) | |
{ | |
return x > 9 ? '' + x : '0' + x | |
} | |
return this.getFullYear() + | |
leadZero(this.getMonth() + 1) + | |
leadZero(this.getDate()) + 'T' + | |
leadZero(this.getHours()) + | |
leadZero(this.getMinutes()) + | |
leadZero(this.getSeconds()); | |
} | |
Object.defineProperty(Array.prototype, "remove", | |
{ | |
value: function(value, onlyFirst) | |
{ | |
if (onlyFirst) { | |
var index = this.indexOf(value); | |
if (index !== -1) | |
this.splice(index, 1); | |
return; | |
} | |
var length = this.length; | |
for (var i = 0; i < length; ++i) { | |
if (this[i] === value) | |
this.splice(i, 1); | |
} | |
} | |
}); | |
Object.defineProperty(Array.prototype, "keySet", | |
{ | |
value: function() | |
{ | |
var keys = {}; | |
for (var i = 0; i < this.length; ++i) | |
keys[this[i]] = true; | |
return keys; | |
} | |
}); | |
Object.defineProperty(Array.prototype, "upperBound", | |
{ | |
value: function(value) | |
{ | |
var first = 0; | |
var count = this.length; | |
while (count > 0) { | |
var step = count >> 1; | |
var middle = first + step; | |
if (value >= this[middle]) { | |
first = middle + 1; | |
count -= step + 1; | |
} else | |
count = step; | |
} | |
return first; | |
} | |
}); | |
Object.defineProperty(Array.prototype, "rotate", | |
{ | |
value: function(index) | |
{ | |
var result = []; | |
for (var i = index; i < index + this.length; ++i) | |
result.push(this[i % this.length]); | |
return result; | |
} | |
}); | |
Object.defineProperty(Uint32Array.prototype, "sort", { | |
value: Array.prototype.sort | |
}); | |
(function() { | |
var partition = { | |
value: function(comparator, left, right, pivotIndex) | |
{ | |
function swap(array, i1, i2) | |
{ | |
var temp = array[i1]; | |
array[i1] = array[i2]; | |
array[i2] = temp; | |
} | |
var pivotValue = this[pivotIndex]; | |
swap(this, right, pivotIndex); | |
var storeIndex = left; | |
for (var i = left; i < right; ++i) { | |
if (comparator(this[i], pivotValue) < 0) { | |
swap(this, storeIndex, i); | |
++storeIndex; | |
} | |
} | |
swap(this, right, storeIndex); | |
return storeIndex; | |
} | |
}; | |
Object.defineProperty(Array.prototype, "partition", partition); | |
Object.defineProperty(Uint32Array.prototype, "partition", partition); | |
var sortRange = { | |
value: function(comparator, leftBound, rightBound, k) | |
{ | |
function quickSortFirstK(array, comparator, left, right, k) | |
{ | |
if (right <= left) | |
return; | |
var pivotIndex = Math.floor(Math.random() * (right - left)) + left; | |
var pivotNewIndex = array.partition(comparator, left, right, pivotIndex); | |
quickSortFirstK(array, comparator, left, pivotNewIndex - 1, k); | |
if (pivotNewIndex < left + k - 1) | |
quickSortFirstK(array, comparator, pivotNewIndex + 1, right, k); | |
} | |
if (leftBound === 0 && rightBound === (this.length - 1) && k === this.length) | |
this.sort(comparator); | |
else | |
quickSortFirstK(this, comparator, leftBound, rightBound, k); | |
return this; | |
} | |
} | |
Object.defineProperty(Array.prototype, "sortRange", sortRange); | |
Object.defineProperty(Uint32Array.prototype, "sortRange", sortRange); | |
})(); | |
Object.defineProperty(Array.prototype, "qselect", | |
{ | |
value: function(k, comparator) | |
{ | |
if (k < 0 || k >= this.length) | |
return; | |
if (!comparator) | |
comparator = function(a, b) { return a - b; } | |
var low = 0; | |
var high = this.length - 1; | |
for (;;) { | |
var pivotPosition = this.partition(comparator, low, high, Math.floor((high + low) / 2)); | |
if (pivotPosition === k) | |
return this[k]; | |
else if (pivotPosition > k) | |
high = pivotPosition - 1; | |
else | |
low = pivotPosition + 1; | |
} | |
} | |
}); | |
function binarySearch(object, array, comparator) | |
{ | |
var first = 0; | |
var last = array.length - 1; | |
while (first <= last) { | |
var mid = (first + last) >> 1; | |
var c = comparator(object, array[mid]); | |
if (c > 0) | |
first = mid + 1; | |
else if (c < 0) | |
last = mid - 1; | |
else | |
return mid; | |
} | |
return -(first + 1); | |
} | |
Object.defineProperty(Array.prototype, "binaryIndexOf", | |
{ | |
value: function(value, comparator) | |
{ | |
var result = binarySearch(value, this, comparator); | |
return result >= 0 ? result : -1; | |
} | |
}); | |
Object.defineProperty(Array.prototype, "select", | |
{ | |
value: function(field) | |
{ | |
var result = new Array(this.length); | |
for (var i = 0; i < this.length; ++i) | |
result[i] = this[i][field]; | |
return result; | |
} | |
}); | |
function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction) | |
{ | |
var index = binarySearch(anObject, aList, aFunction); | |
if (index < 0) | |
return -index - 1; | |
else { | |
while (index > 0 && aFunction(anObject, aList[index - 1]) === 0) | |
index--; | |
return index; | |
} | |
} | |
Array.convert = function(list) | |
{ | |
return Array.prototype.slice.call(list); | |
} | |
String.sprintf = function(format, var_arg) | |
{ | |
return String.vsprintf(format, Array.prototype.slice.call(arguments, 1)); | |
} | |
String.tokenizeFormatString = function(format, formatters) | |
{ | |
var tokens = []; | |
var substitutionIndex = 0; | |
function addStringToken(str) | |
{ | |
tokens.push({ type: "string", value: str }); | |
} | |
function addSpecifierToken(specifier, precision, substitutionIndex) | |
{ | |
tokens.push({ type: "specifier", specifier: specifier, precision: precision, substitutionIndex: substitutionIndex }); | |
} | |
function isDigit(c) | |
{ | |
return !!/[0-9]/.exec(c); | |
} | |
var index = 0; | |
for (var precentIndex = format.indexOf("%", index); precentIndex !== -1; precentIndex = format.indexOf("%", index)) { | |
addStringToken(format.substring(index, precentIndex)); | |
index = precentIndex + 1; | |
if (isDigit(format[index])) { | |
var number = parseInt(format.substring(index), 10); | |
while (isDigit(format[index])) | |
++index; | |
if (number > 0 && format[index] === "$") { | |
substitutionIndex = (number - 1); | |
++index; | |
} | |
} | |
var precision = -1; | |
if (format[index] === ".") { | |
++index; | |
precision = parseInt(format.substring(index), 10); | |
if (isNaN(precision)) | |
precision = 0; | |
while (isDigit(format[index])) | |
++index; | |
} | |
if (!(format[index] in formatters)) { | |
addStringToken(format.substring(precentIndex, index + 1)); | |
++index; | |
continue; | |
} | |
addSpecifierToken(format[index], precision, substitutionIndex); | |
++substitutionIndex; | |
++index; | |
} | |
addStringToken(format.substring(index)); | |
return tokens; | |
} | |
String.standardFormatters = { | |
d: function(substitution) | |
{ | |
return !isNaN(substitution) ? substitution : 0; | |
}, | |
f: function(substitution, token) | |
{ | |
if (substitution && token.precision > -1) | |
substitution = substitution.toFixed(token.precision); | |
return !isNaN(substitution) ? substitution : (token.precision > -1 ? Number(0).toFixed(token.precision) : 0); | |
}, | |
s: function(substitution) | |
{ | |
return substitution; | |
} | |
} | |
String.vsprintf = function(format, substitutions) | |
{ | |
return String.format(format, substitutions, String.standardFormatters, "", function(a, b) { return a + b; }).formattedResult; | |
} | |
String.format = function(format, substitutions, formatters, initialValue, append) | |
{ | |
if (!format || !substitutions || !substitutions.length) | |
return { formattedResult: append(initialValue, format), unusedSubstitutions: substitutions }; | |
function prettyFunctionName() | |
{ | |
return "String.format(\"" + format + "\", \"" + substitutions.join("\", \"") + "\")"; | |
} | |
function warn(msg) | |
{ | |
console.warn(prettyFunctionName() + ": " + msg); | |
} | |
function error(msg) | |
{ | |
console.error(prettyFunctionName() + ": " + msg); | |
} | |
var result = initialValue; | |
var tokens = String.tokenizeFormatString(format, formatters); | |
var usedSubstitutionIndexes = {}; | |
for (var i = 0; i < tokens.length; ++i) { | |
var token = tokens[i]; | |
if (token.type === "string") { | |
result = append(result, token.value); | |
continue; | |
} | |
if (token.type !== "specifier") { | |
error("Unknown token type \"" + token.type + "\" found."); | |
continue; | |
} | |
if (token.substitutionIndex >= substitutions.length) { | |
error("not enough substitution arguments. Had " + substitutions.length + " but needed " + (token.substitutionIndex + 1) + ", so substitution was skipped."); | |
result = append(result, "%" + (token.precision > -1 ? token.precision : "") + token.specifier); | |
continue; | |
} | |
usedSubstitutionIndexes[token.substitutionIndex] = true; | |
if (!(token.specifier in formatters)) { | |
warn("unsupported format character \u201C" + token.specifier + "\u201D. Treating as a string."); | |
result = append(result, substitutions[token.substitutionIndex]); | |
continue; | |
} | |
result = append(result, formatters[token.specifier](substitutions[token.substitutionIndex], token)); | |
} | |
var unusedSubstitutions = []; | |
for (var i = 0; i < substitutions.length; ++i) { | |
if (i in usedSubstitutionIndexes) | |
continue; | |
unusedSubstitutions.push(substitutions[i]); | |
} | |
return { formattedResult: result, unusedSubstitutions: unusedSubstitutions }; | |
} | |
function createSearchRegex(query, caseSensitive, isRegex) | |
{ | |
var regexFlags = caseSensitive ? "g" : "gi"; | |
var regexObject; | |
if (isRegex) { | |
try { | |
regexObject = new RegExp(query, regexFlags); | |
} catch (e) { | |
} | |
} | |
if (!regexObject) | |
regexObject = createPlainTextSearchRegex(query, regexFlags); | |
return regexObject; | |
} | |
function createPlainTextSearchRegex(query, flags) | |
{ | |
var regexSpecialCharacters = "[](){}+-*.,?\\^$|"; | |
var regex = ""; | |
for (var i = 0; i < query.length; ++i) { | |
var c = query.charAt(i); | |
if (regexSpecialCharacters.indexOf(c) != -1) | |
regex += "\\"; | |
regex += c; | |
} | |
return new RegExp(regex, flags || ""); | |
} | |
function countRegexMatches(regex, content) | |
{ | |
var text = content; | |
var result = 0; | |
var match; | |
while (text && (match = regex.exec(text))) { | |
if (match[0].length > 0) | |
++result; | |
text = text.substring(match.index + 1); | |
} | |
return result; | |
} | |
function numberToStringWithSpacesPadding(value, symbolsCount) | |
{ | |
var numberString = value.toString(); | |
var paddingLength = Math.max(0, symbolsCount - numberString.length); | |
var paddingString = Array(paddingLength + 1).join("\u00a0"); | |
return paddingString + numberString; | |
} | |
var Map = function() | |
{ | |
this._map = {}; | |
this._size = 0; | |
} | |
Map._lastObjectIdentifier = 0; | |
Map.prototype = { | |
put: function(key, value) | |
{ | |
var objectIdentifier = key.__identifier; | |
if (!objectIdentifier) { | |
objectIdentifier = ++Map._lastObjectIdentifier; | |
key.__identifier = objectIdentifier; | |
} | |
if (!this._map[objectIdentifier]) | |
++this._size; | |
this._map[objectIdentifier] = [key, value]; | |
}, | |
remove: function(key) | |
{ | |
var result = this._map[key.__identifier]; | |
delete this._map[key.__identifier]; | |
--this._size; | |
return result ? result[1] : undefined; | |
}, | |
keys: function() | |
{ | |
return this._list(0); | |
}, | |
values: function() | |
{ | |
return this._list(1); | |
}, | |
_list: function(index) | |
{ | |
var result = new Array(this._size); | |
var i = 0; | |
for (var objectIdentifier in this._map) | |
result[i++] = this._map[objectIdentifier][index]; | |
return result; | |
}, | |
get: function(key) | |
{ | |
var entry = this._map[key.__identifier]; | |
return entry ? entry[1] : undefined; | |
}, | |
size: function() | |
{ | |
return this._size; | |
}, | |
clear: function() | |
{ | |
this._map = {}; | |
this._size = 0; | |
} | |
} | |
function loadXHR(url, async, callback) | |
{ | |
function onReadyStateChanged() | |
{ | |
if (xhr.readyState !== XMLHttpRequest.DONE) | |
return; | |
if (xhr.status === 200) { | |
callback(xhr.responseText); | |
return; | |
} | |
callback(null); | |
} | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", url, async); | |
if (async) | |
xhr.onreadystatechange = onReadyStateChanged; | |
xhr.send(null); | |
if (!async) { | |
if (xhr.status === 200) | |
return xhr.responseText; | |
return null; | |
} | |
return null; | |
} | |
function StringPool() | |
{ | |
this.reset(); | |
} | |
StringPool.prototype = { | |
intern: function(string) | |
{ | |
if (string === "__proto__") | |
return "__proto__"; | |
var result = this._strings[string]; | |
if (result === undefined) { | |
this._strings[string] = string; | |
result = string; | |
} | |
return result; | |
}, | |
reset: function() | |
{ | |
this._strings = Object.create(null); | |
}, | |
internObjectStrings: function(obj, depthLimit) | |
{ | |
if (typeof depthLimit !== "number") | |
depthLimit = 100; | |
else if (--depthLimit < 0) | |
throw "recursion depth limit reached in StringPool.deepIntern(), perhaps attempting to traverse cyclical references?"; | |
for (var field in obj) { | |
switch (typeof obj[field]) { | |
case "string": | |
obj[field] = this.intern(obj[field]); | |
break; | |
case "object": | |
this.internObjectStrings(obj[field], depthLimit); | |
break; | |
} | |
} | |
} | |
} | |
var _importedScripts = {}; | |
function importScript(scriptName) | |
{ | |
if (_importedScripts[scriptName]) | |
return; | |
_importedScripts[scriptName] = true; | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", scriptName, false); | |
xhr.send(null); | |
window.eval(xhr.responseText + "\n//@ sourceURL=" + scriptName); | |
} | |
__whitespace = {" ":true, "\t":true, "\n":true, "\f":true, "\r":true}; | |
difflib = { | |
defaultJunkFunction: function (c) { | |
return __whitespace.hasOwnProperty(c); | |
}, | |
stripLinebreaks: function (str) { return str.replace(/^[\n\r]*|[\n\r]*$/g, ""); }, | |
stringAsLines: function (str) { | |
var lfpos = str.indexOf("\n"); | |
var crpos = str.indexOf("\r"); | |
var linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? "\n" : "\r"; | |
var lines = str.split(linebreak); | |
for (var i = 0; i < lines.length; i++) { | |
lines[i] = difflib.stripLinebreaks(lines[i]); | |
} | |
return lines; | |
}, | |
__reduce: function (func, list, initial) { | |
if (initial != null) { | |
var value = initial; | |
var idx = 0; | |
} else if (list) { | |
var value = list[0]; | |
var idx = 1; | |
} else { | |
return null; | |
} | |
for (; idx < list.length; idx++) { | |
value = func(value, list[idx]); | |
} | |
return value; | |
}, | |
__ntuplecomp: function (a, b) { | |
var mlen = Math.max(a.length, b.length); | |
for (var i = 0; i < mlen; i++) { | |
if (a[i] < b[i]) return -1; | |
if (a[i] > b[i]) return 1; | |
} | |
return a.length == b.length ? 0 : (a.length < b.length ? -1 : 1); | |
}, | |
__calculate_ratio: function (matches, length) { | |
return length ? 2.0 * matches / length : 1.0; | |
}, | |
__isindict: function (dict) { | |
return function (key) { return dict.hasOwnProperty(key); }; | |
}, | |
__dictget: function (dict, key, defaultValue) { | |
return dict.hasOwnProperty(key) ? dict[key] : defaultValue; | |
}, | |
SequenceMatcher: function (a, b, isjunk) { | |
this.set_seqs = function (a, b) { | |
this.set_seq1(a); | |
this.set_seq2(b); | |
} | |
this.set_seq1 = function (a) { | |
if (a == this.a) return; | |
this.a = a; | |
this.matching_blocks = this.opcodes = null; | |
} | |
this.set_seq2 = function (b) { | |
if (b == this.b) return; | |
this.b = b; | |
this.matching_blocks = this.opcodes = this.fullbcount = null; | |
this.__chain_b(); | |
} | |
this.__chain_b = function () { | |
var b = this.b; | |
var n = b.length; | |
var b2j = this.b2j = {}; | |
var populardict = {}; | |
for (var i = 0; i < b.length; i++) { | |
var elt = b[i]; | |
if (b2j.hasOwnProperty(elt)) { | |
var indices = b2j[elt]; | |
if (n >= 200 && indices.length * 100 > n) { | |
populardict[elt] = 1; | |
delete b2j[elt]; | |
} else { | |
indices.push(i); | |
} | |
} else { | |
b2j[elt] = [i]; | |
} | |
} | |
for (var elt in populardict) { | |
if (populardict.hasOwnProperty(elt)) { | |
delete b2j[elt]; | |
} | |
} | |
var isjunk = this.isjunk; | |
var junkdict = {}; | |
if (isjunk) { | |
for (var elt in populardict) { | |
if (populardict.hasOwnProperty(elt) && isjunk(elt)) { | |
junkdict[elt] = 1; | |
delete populardict[elt]; | |
} | |
} | |
for (var elt in b2j) { | |
if (b2j.hasOwnProperty(elt) && isjunk(elt)) { | |
junkdict[elt] = 1; | |
delete b2j[elt]; | |
} | |
} | |
} | |
this.isbjunk = difflib.__isindict(junkdict); | |
this.isbpopular = difflib.__isindict(populardict); | |
} | |
this.find_longest_match = function (alo, ahi, blo, bhi) { | |
var a = this.a; | |
var b = this.b; | |
var b2j = this.b2j; | |
var isbjunk = this.isbjunk; | |
var besti = alo; | |
var bestj = blo; | |
var bestsize = 0; | |
var j = null; | |
var j2len = {}; | |
var nothing = []; | |
for (var i = alo; i < ahi; i++) { | |
var newj2len = {}; | |
var jdict = difflib.__dictget(b2j, a[i], nothing); | |
for (var jkey in jdict) { | |
if (jdict.hasOwnProperty(jkey)) { | |
j = jdict[jkey]; | |
if (j < blo) continue; | |
if (j >= bhi) break; | |
newj2len[j] = k = difflib.__dictget(j2len, j - 1, 0) + 1; | |
if (k > bestsize) { | |
besti = i - k + 1; | |
bestj = j - k + 1; | |
bestsize = k; | |
} | |
} | |
} | |
j2len = newj2len; | |
} | |
while (besti > alo && bestj > blo && !isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) { | |
besti--; | |
bestj--; | |
bestsize++; | |
} | |
while (besti + bestsize < ahi && bestj + bestsize < bhi && | |
!isbjunk(b[bestj + bestsize]) && | |
a[besti + bestsize] == b[bestj + bestsize]) { | |
bestsize++; | |
} | |
while (besti > alo && bestj > blo && isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) { | |
besti--; | |
bestj--; | |
bestsize++; | |
} | |
while (besti + bestsize < ahi && bestj + bestsize < bhi && isbjunk(b[bestj + bestsize]) && | |
a[besti + bestsize] == b[bestj + bestsize]) { | |
bestsize++; | |
} | |
return [besti, bestj, bestsize]; | |
} | |
this.get_matching_blocks = function () { | |
if (this.matching_blocks != null) return this.matching_blocks; | |
var la = this.a.length; | |
var lb = this.b.length; | |
var queue = [[0, la, 0, lb]]; | |
var matching_blocks = []; | |
var alo, ahi, blo, bhi, qi, i, j, k, x; | |
while (queue.length) { | |
qi = queue.pop(); | |
alo = qi[0]; | |
ahi = qi[1]; | |
blo = qi[2]; | |
bhi = qi[3]; | |
x = this.find_longest_match(alo, ahi, blo, bhi); | |
i = x[0]; | |
j = x[1]; | |
k = x[2]; | |
if (k) { | |
matching_blocks.push(x); | |
if (alo < i && blo < j) | |
queue.push([alo, i, blo, j]); | |
if (i+k < ahi && j+k < bhi) | |
queue.push([i + k, ahi, j + k, bhi]); | |
} | |
} | |
matching_blocks.sort(difflib.__ntuplecomp); | |
var i1 = j1 = k1 = block = 0; | |
var non_adjacent = []; | |
for (var idx in matching_blocks) { | |
if (matching_blocks.hasOwnProperty(idx)) { | |
block = matching_blocks[idx]; | |
i2 = block[0]; | |
j2 = block[1]; | |
k2 = block[2]; | |
if (i1 + k1 == i2 && j1 + k1 == j2) { | |
k1 += k2; | |
} else { | |
if (k1) non_adjacent.push([i1, j1, k1]); | |
i1 = i2; | |
j1 = j2; | |
k1 = k2; | |
} | |
} | |
} | |
if (k1) non_adjacent.push([i1, j1, k1]); | |
non_adjacent.push([la, lb, 0]); | |
this.matching_blocks = non_adjacent; | |
return this.matching_blocks; | |
} | |
this.get_opcodes = function () { | |
if (this.opcodes != null) return this.opcodes; | |
var i = 0; | |
var j = 0; | |
var answer = []; | |
this.opcodes = answer; | |
var block, ai, bj, size, tag; | |
var blocks = this.get_matching_blocks(); | |
for (var idx in blocks) { | |
if (blocks.hasOwnProperty(idx)) { | |
block = blocks[idx]; | |
ai = block[0]; | |
bj = block[1]; | |
size = block[2]; | |
tag = ''; | |
if (i < ai && j < bj) { | |
tag = 'replace'; | |
} else if (i < ai) { | |
tag = 'delete'; | |
} else if (j < bj) { | |
tag = 'insert'; | |
} | |
if (tag) answer.push([tag, i, ai, j, bj]); | |
i = ai + size; | |
j = bj + size; | |
if (size) answer.push(['equal', ai, i, bj, j]); | |
} | |
} | |
return answer; | |
} | |
this.get_grouped_opcodes = function (n) { | |
if (!n) n = 3; | |
var codes = this.get_opcodes(); | |
if (!codes) codes = [["equal", 0, 1, 0, 1]]; | |
var code, tag, i1, i2, j1, j2; | |
if (codes[0][0] == 'equal') { | |
code = codes[0]; | |
tag = code[0]; | |
i1 = code[1]; | |
i2 = code[2]; | |
j1 = code[3]; | |
j2 = code[4]; | |
codes[0] = [tag, Math.max(i1, i2 - n), i2, Math.max(j1, j2 - n), j2]; | |
} | |
if (codes[codes.length - 1][0] == 'equal') { | |
code = codes[codes.length - 1]; | |
tag = code[0]; | |
i1 = code[1]; | |
i2 = code[2]; | |
j1 = code[3]; | |
j2 = code[4]; | |
codes[codes.length - 1] = [tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]; | |
} | |
var nn = n + n; | |
var groups = []; | |
for (var idx in codes) { | |
if (codes.hasOwnProperty(idx)) { | |
code = codes[idx]; | |
tag = code[0]; | |
i1 = code[1]; | |
i2 = code[2]; | |
j1 = code[3]; | |
j2 = code[4]; | |
if (tag == 'equal' && i2 - i1 > nn) { | |
groups.push([tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]); | |
i1 = Math.max(i1, i2-n); | |
j1 = Math.max(j1, j2-n); | |
} | |
groups.push([tag, i1, i2, j1, j2]); | |
} | |
} | |
if (groups && groups[groups.length - 1][0] == 'equal') groups.pop(); | |
return groups; | |
} | |
this.ratio = function () { | |
matches = difflib.__reduce( | |
function (sum, triple) { return sum + triple[triple.length - 1]; }, | |
this.get_matching_blocks(), 0); | |
return difflib.__calculate_ratio(matches, this.a.length + this.b.length); | |
} | |
this.quick_ratio = function () { | |
var fullbcount, elt; | |
if (this.fullbcount == null) { | |
this.fullbcount = fullbcount = {}; | |
for (var i = 0; i < this.b.length; i++) { | |
elt = this.b[i]; | |
fullbcount[elt] = difflib.__dictget(fullbcount, elt, 0) + 1; | |
} | |
} | |
fullbcount = this.fullbcount; | |
var avail = {}; | |
var availhas = difflib.__isindict(avail); | |
var matches = numb = 0; | |
for (var i = 0; i < this.a.length; i++) { | |
elt = this.a[i]; | |
if (availhas(elt)) { | |
numb = avail[elt]; | |
} else { | |
numb = difflib.__dictget(fullbcount, elt, 0); | |
} | |
avail[elt] = numb - 1; | |
if (numb > 0) matches++; | |
} | |
return difflib.__calculate_ratio(matches, this.a.length + this.b.length); | |
} | |
this.real_quick_ratio = function () { | |
var la = this.a.length; | |
var lb = this.b.length; | |
return _calculate_ratio(Math.min(la, lb), la + lb); | |
} | |
this.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction; | |
this.a = this.b = null; | |
this.set_seqs(a, b); | |
} | |
} | |
Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, direction) | |
{ | |
var startNode; | |
var startOffset = 0; | |
var endNode; | |
var endOffset = 0; | |
if (!stayWithinNode) | |
stayWithinNode = this; | |
if (!direction || direction === "backward" || direction === "both") { | |
var node = this; | |
while (node) { | |
if (node === stayWithinNode) { | |
if (!startNode) | |
startNode = stayWithinNode; | |
break; | |
} | |
if (node.nodeType === Node.TEXT_NODE) { | |
var start = (node === this ? (offset - 1) : (node.nodeValue.length - 1)); | |
for (var i = start; i >= 0; --i) { | |
if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) { | |
startNode = node; | |
startOffset = i + 1; | |
break; | |
} | |
} | |
} | |
if (startNode) | |
break; | |
node = node.traversePreviousNode(stayWithinNode); | |
} | |
if (!startNode) { | |
startNode = stayWithinNode; | |
startOffset = 0; | |
} | |
} else { | |
startNode = this; | |
startOffset = offset; | |
} | |
if (!direction || direction === "forward" || direction === "both") { | |
node = this; | |
while (node) { | |
if (node === stayWithinNode) { | |
if (!endNode) | |
endNode = stayWithinNode; | |
break; | |
} | |
if (node.nodeType === Node.TEXT_NODE) { | |
var start = (node === this ? offset : 0); | |
for (var i = start; i < node.nodeValue.length; ++i) { | |
if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) { | |
endNode = node; | |
endOffset = i; | |
break; | |
} | |
} | |
} | |
if (endNode) | |
break; | |
node = node.traverseNextNode(stayWithinNode); | |
} | |
if (!endNode) { | |
endNode = stayWithinNode; | |
endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinNode.nodeValue.length : stayWithinNode.childNodes.length; | |
} | |
} else { | |
endNode = this; | |
endOffset = offset; | |
} | |
var result = this.ownerDocument.createRange(); | |
result.setStart(startNode, startOffset); | |
result.setEnd(endNode, endOffset); | |
return result; | |
} | |
Node.prototype.traverseNextTextNode = function(stayWithin) | |
{ | |
var node = this.traverseNextNode(stayWithin); | |
if (!node) | |
return; | |
while (node && node.nodeType !== Node.TEXT_NODE) | |
node = node.traverseNextNode(stayWithin); | |
return node; | |
} | |
Node.prototype.rangeBoundaryForOffset = function(offset) | |
{ | |
var node = this.traverseNextTextNode(this); | |
while (node && offset > node.nodeValue.length) { | |
offset -= node.nodeValue.length; | |
node = node.traverseNextTextNode(this); | |
} | |
if (!node) | |
return { container: this, offset: 0 }; | |
return { container: node, offset: offset }; | |
} | |
Element.prototype.removeStyleClass = function(className) | |
{ | |
this.classList.remove(className); | |
} | |
Element.prototype.removeMatchingStyleClasses = function(classNameRegex) | |
{ | |
var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)"); | |
if (regex.test(this.className)) | |
this.className = this.className.replace(regex, " "); | |
} | |
Element.prototype.addStyleClass = function(className) | |
{ | |
this.classList.add(className); | |
} | |
Element.prototype.hasStyleClass = function(className) | |
{ | |
return this.classList.contains(className); | |
} | |
Element.prototype.positionAt = function(x, y) | |
{ | |
this.style.left = x + "px"; | |
this.style.top = y + "px"; | |
} | |
Element.prototype.pruneEmptyTextNodes = function() | |
{ | |
var sibling = this.firstChild; | |
while (sibling) { | |
var nextSibling = sibling.nextSibling; | |
if (sibling.nodeType === this.TEXT_NODE && sibling.nodeValue === "") | |
this.removeChild(sibling); | |
sibling = nextSibling; | |
} | |
} | |
Element.prototype.isScrolledToBottom = function() | |
{ | |
return this.scrollTop + this.clientHeight === this.scrollHeight; | |
} | |
Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray) | |
{ | |
for (var node = this; node && node !== this.ownerDocument; node = node.parentNode) | |
for (var i = 0; i < nameArray.length; ++i) | |
if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase()) | |
return node; | |
return null; | |
} | |
Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName) | |
{ | |
return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]); | |
} | |
Node.prototype.enclosingNodeOrSelfWithClass = function(className) | |
{ | |
for (var node = this; node && node !== this.ownerDocument; node = node.parentNode) | |
if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className)) | |
return node; | |
return null; | |
} | |
Node.prototype.enclosingNodeWithClass = function(className) | |
{ | |
if (!this.parentNode) | |
return null; | |
return this.parentNode.enclosingNodeOrSelfWithClass(className); | |
} | |
Element.prototype.query = function(query) | |
{ | |
return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; | |
} | |
Element.prototype.removeChildren = function() | |
{ | |
if (this.firstChild) | |
this.textContent = ""; | |
} | |
Element.prototype.isInsertionCaretInside = function() | |
{ | |
var selection = window.getSelection(); | |
if (!selection.rangeCount || !selection.isCollapsed) | |
return false; | |
var selectionRange = selection.getRangeAt(0); | |
return selectionRange.startContainer.isSelfOrDescendant(this); | |
} | |
Element.prototype.createChild = function(elementName, className) | |
{ | |
var element = this.ownerDocument.createElement(elementName); | |
if (className) | |
element.className = className; | |
this.appendChild(element); | |
return element; | |
} | |
DocumentFragment.prototype.createChild = Element.prototype.createChild; | |
Element.prototype.createTextChild = function(text) | |
{ | |
var element = this.ownerDocument.createTextNode(text); | |
this.appendChild(element); | |
return element; | |
} | |
DocumentFragment.prototype.createTextChild = Element.prototype.createTextChild; | |
Element.prototype.totalOffsetLeft = function() | |
{ | |
return this.totalOffset().left; | |
} | |
Element.prototype.totalOffsetTop = function() | |
{ | |
return this.totalOffset().top; | |
} | |
Element.prototype.totalOffset = function() | |
{ | |
var totalLeft = 0; | |
var totalTop = 0; | |
for (var element = this; element; element = element.offsetParent) { | |
totalLeft += element.offsetLeft; | |
totalTop += element.offsetTop; | |
if (this !== element) { | |
totalLeft += element.clientLeft - element.scrollLeft; | |
totalTop += element.clientTop - element.scrollTop; | |
} | |
} | |
return { left: totalLeft, top: totalTop }; | |
} | |
Element.prototype.scrollOffset = function() | |
{ | |
var curLeft = 0; | |
var curTop = 0; | |
for (var element = this; element; element = element.scrollParent) { | |
curLeft += element.scrollLeft; | |
curTop += element.scrollTop; | |
} | |
return { left: curLeft, top: curTop }; | |
} | |
function AnchorBox(x, y, width, height) | |
{ | |
this.x = x || 0; | |
this.y = y || 0; | |
this.width = width || 0; | |
this.height = height || 0; | |
} | |
Element.prototype.offsetRelativeToWindow = function(targetWindow) | |
{ | |
var elementOffset = new AnchorBox(); | |
var curElement = this; | |
var curWindow = this.ownerDocument.defaultView; | |
while (curWindow && curElement) { | |
elementOffset.x += curElement.totalOffsetLeft(); | |
elementOffset.y += curElement.totalOffsetTop(); | |
if (curWindow === targetWindow) | |
break; | |
curElement = curWindow.frameElement; | |
curWindow = curWindow.parent; | |
} | |
return elementOffset; | |
} | |
Element.prototype.boxInWindow = function(targetWindow) | |
{ | |
targetWindow = targetWindow || this.ownerDocument.defaultView; | |
var anchorBox = this.offsetRelativeToWindow(window); | |
anchorBox.width = Math.min(this.offsetWidth, window.innerWidth - anchorBox.x); | |
anchorBox.height = Math.min(this.offsetHeight, window.innerHeight - anchorBox.y); | |
return anchorBox; | |
} | |
Element.prototype.setTextAndTitle = function(text) | |
{ | |
this.textContent = text; | |
this.title = text; | |
} | |
KeyboardEvent.prototype.__defineGetter__("data", function() | |
{ | |
switch (this.type) { | |
case "keypress": | |
if (!this.ctrlKey && !this.metaKey) | |
return String.fromCharCode(this.charCode); | |
else | |
return ""; | |
case "keydown": | |
case "keyup": | |
if (!this.ctrlKey && !this.metaKey && !this.altKey) | |
return String.fromCharCode(this.which); | |
else | |
return ""; | |
} | |
}); | |
Event.prototype.consume = function(preventDefault) | |
{ | |
this.stopImmediatePropagation(); | |
if (preventDefault) | |
this.preventDefault(); | |
this.handled = true; | |
} | |
Text.prototype.select = function(start, end) | |
{ | |
start = start || 0; | |
end = end || this.textContent.length; | |
if (start < 0) | |
start = end + start; | |
var selection = this.ownerDocument.defaultView.getSelection(); | |
selection.removeAllRanges(); | |
var range = this.ownerDocument.createRange(); | |
range.setStart(this, start); | |
range.setEnd(this, end); | |
selection.addRange(range); | |
return this; | |
} | |
Element.prototype.selectionLeftOffset = function() | |
{ | |
var selection = window.getSelection(); | |
if (!selection.containsNode(this, true)) | |
return null; | |
var leftOffset = selection.anchorOffset; | |
var node = selection.anchorNode; | |
while (node !== this) { | |
while (node.previousSibling) { | |
node = node.previousSibling; | |
leftOffset += node.textContent.length; | |
} | |
node = node.parentNode; | |
} | |
return leftOffset; | |
} | |
Node.prototype.isAncestor = function(node) | |
{ | |
if (!node) | |
return false; | |
var currentNode = node.parentNode; | |
while (currentNode) { | |
if (this === currentNode) | |
return true; | |
currentNode = currentNode.parentNode; | |
} | |
return false; | |
} | |
Node.prototype.isDescendant = function(descendant) | |
{ | |
return !!descendant && descendant.isAncestor(this); | |
} | |
Node.prototype.isSelfOrAncestor = function(node) | |
{ | |
return !!node && (node === this || this.isAncestor(node)); | |
} | |
Node.prototype.isSelfOrDescendant = function(node) | |
{ | |
return !!node && (node === this || this.isDescendant(node)); | |
} | |
Node.prototype.traverseNextNode = function(stayWithin) | |
{ | |
var node = this.firstChild; | |
if (node) | |
return node; | |
if (stayWithin && this === stayWithin) | |
return null; | |
node = this.nextSibling; | |
if (node) | |
return node; | |
node = this; | |
while (node && !node.nextSibling && (!stayWithin || !node.parentNode || node.parentNode !== stayWithin)) | |
node = node.parentNode; | |
if (!node) | |
return null; | |
return node.nextSibling; | |
} | |
Node.prototype.traversePreviousNode = function(stayWithin) | |
{ | |
if (stayWithin && this === stayWithin) | |
return null; | |
var node = this.previousSibling; | |
while (node && node.lastChild) | |
node = node.lastChild; | |
if (node) | |
return node; | |
return this.parentNode; | |
} | |
HTMLTextAreaElement.prototype.moveCursorToEnd = function() | |
{ | |
var length = this.value.length; | |
this.setSelectionRange(length, length); | |
} | |
function isEnterKey(event) { | |
return event.keyCode !== 229 && event.keyIdentifier === "Enter"; | |
} | |
function consumeEvent(e) | |
{ | |
e.consume(); | |
} | |
function TreeOutline(listNode, nonFocusable) | |
{ | |
this.children = []; | |
this.selectedTreeElement = null; | |
this._childrenListNode = listNode; | |
this.childrenListElement = this._childrenListNode; | |
this._childrenListNode.removeChildren(); | |
this.expandTreeElementsWhenArrowing = false; | |
this.root = true; | |
this.hasChildren = false; | |
this.expanded = true; | |
this.selected = false; | |
this.treeOutline = this; | |
this.comparator = null; | |
this.searchable = false; | |
this.searchInputElement = null; | |
this.setFocusable(!nonFocusable); | |
this._childrenListNode.addEventListener("keydown", this._treeKeyDown.bind(this), true); | |
this._childrenListNode.addEventListener("keypress", this._treeKeyPress.bind(this), true); | |
this._treeElementsMap = new Map(); | |
this._expandedStateMap = new Map(); | |
} | |
TreeOutline.prototype.setFocusable = function(focusable) | |
{ | |
if (focusable) | |
this._childrenListNode.setAttribute("tabIndex", 0); | |
else | |
this._childrenListNode.removeAttribute("tabIndex"); | |
} | |
TreeOutline.prototype.appendChild = function(child) | |
{ | |
var insertionIndex; | |
if (this.treeOutline.comparator) | |
insertionIndex = insertionIndexForObjectInListSortedByFunction(child, this.children, this.treeOutline.comparator); | |
else | |
insertionIndex = this.children.length; | |
this.insertChild(child, insertionIndex); | |
} | |
TreeOutline.prototype.insertChild = function(child, index) | |
{ | |
if (!child) | |
throw("child can't be undefined or null"); | |
var previousChild = (index > 0 ? this.children[index - 1] : null); | |
if (previousChild) { | |
previousChild.nextSibling = child; | |
child.previousSibling = previousChild; | |
} else { | |
child.previousSibling = null; | |
} | |
var nextChild = this.children[index]; | |
if (nextChild) { | |
nextChild.previousSibling = child; | |
child.nextSibling = nextChild; | |
} else { | |
child.nextSibling = null; | |
} | |
this.children.splice(index, 0, child); | |
this.hasChildren = true; | |
child.parent = this; | |
child.treeOutline = this.treeOutline; | |
child.treeOutline._rememberTreeElement(child); | |
var current = child.children[0]; | |
while (current) { | |
current.treeOutline = this.treeOutline; | |
current.treeOutline._rememberTreeElement(current); | |
current = current.traverseNextTreeElement(false, child, true); | |
} | |
if (child.hasChildren && typeof(child.treeOutline._expandedStateMap.get(child.representedObject)) !== "undefined") | |
child.expanded = child.treeOutline._expandedStateMap.get(child.representedObject); | |
if (!this._childrenListNode) { | |
this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol"); | |
this._childrenListNode.parentTreeElement = this; | |
this._childrenListNode.classList.add("children"); | |
if (this.hidden) | |
this._childrenListNode.classList.add("hidden"); | |
} | |
child._attach(); | |
} | |
TreeOutline.prototype.removeChildAtIndex = function(childIndex) | |
{ | |
if (childIndex < 0 || childIndex >= this.children.length) | |
throw("childIndex out of range"); | |
var child = this.children[childIndex]; | |
this.children.splice(childIndex, 1); | |
var parent = child.parent; | |
if (child.deselect()) { | |
if (child.previousSibling) | |
child.previousSibling.select(); | |
else if (child.nextSibling) | |
child.nextSibling.select(); | |
else | |
parent.select(); | |
} | |
if (child.previousSibling) | |
child.previousSibling.nextSibling = child.nextSibling; | |
if (child.nextSibling) | |
child.nextSibling.previousSibling = child.previousSibling; | |
if (child.treeOutline) { | |
child.treeOutline._forgetTreeElement(child); | |
child.treeOutline._forgetChildrenRecursive(child); | |
} | |
child._detach(); | |
child.treeOutline = null; | |
child.parent = null; | |
child.nextSibling = null; | |
child.previousSibling = null; | |
} | |
TreeOutline.prototype.removeChild = function(child) | |
{ | |
if (!child) | |
throw("child can't be undefined or null"); | |
var childIndex = this.children.indexOf(child); | |
if (childIndex === -1) | |
throw("child not found in this node's children"); | |
this.removeChildAtIndex.call(this, childIndex); | |
} | |
TreeOutline.prototype.removeChildren = function() | |
{ | |
for (var i = 0; i < this.children.length; ++i) { | |
var child = this.children[i]; | |
child.deselect(); | |
if (child.treeOutline) { | |
child.treeOutline._forgetTreeElement(child); | |
child.treeOutline._forgetChildrenRecursive(child); | |
} | |
child._detach(); | |
child.treeOutline = null; | |
child.parent = null; | |
child.nextSibling = null; | |
child.previousSibling = null; | |
} | |
this.children = []; | |
} | |
TreeOutline.prototype._rememberTreeElement = function(element) | |
{ | |
if (!this._treeElementsMap.get(element.representedObject)) | |
this._treeElementsMap.put(element.representedObject, []); | |
var elements = this._treeElementsMap.get(element.representedObject); | |
if (elements.indexOf(element) !== -1) | |
return; | |
elements.push(element); | |
} | |
TreeOutline.prototype._forgetTreeElement = function(element) | |
{ | |
if (this._treeElementsMap.get(element.representedObject)) | |
this._treeElementsMap.get(element.representedObject).remove(element, true); | |
} | |
TreeOutline.prototype._forgetChildrenRecursive = function(parentElement) | |
{ | |
var child = parentElement.children[0]; | |
while (child) { | |
this._forgetTreeElement(child); | |
child = child.traverseNextTreeElement(false, parentElement, true); | |
} | |
} | |
TreeOutline.prototype.getCachedTreeElement = function(representedObject) | |
{ | |
if (!representedObject) | |
return null; | |
var elements = this._treeElementsMap.get(representedObject); | |
if (elements && elements.length) | |
return elements[0]; | |
return null; | |
} | |
TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor, getParent) | |
{ | |
if (!representedObject) | |
return null; | |
var cachedElement = this.getCachedTreeElement(representedObject); | |
if (cachedElement) | |
return cachedElement; | |
var item; | |
var found = false; | |
for (var i = 0; i < this.children.length; ++i) { | |
item = this.children[i]; | |
if (item.representedObject === representedObject || isAncestor(item.representedObject, representedObject)) { | |
found = true; | |
break; | |
} | |
} | |
if (!found) | |
return null; | |
var ancestors = []; | |
var currentObject = representedObject; | |
while (currentObject) { | |
ancestors.unshift(currentObject); | |
if (currentObject === item.representedObject) | |
break; | |
currentObject = getParent(currentObject); | |
} | |
for (var i = 0; i < ancestors.length; ++i) { | |
if (ancestors[i] === representedObject) | |
continue; | |
item = this.findTreeElement(ancestors[i], isAncestor, getParent); | |
if (item) | |
item.onpopulate(); | |
} | |
return this.getCachedTreeElement(representedObject); | |
} | |
TreeOutline.prototype.treeElementFromPoint = function(x, y) | |
{ | |
var node = this._childrenListNode.ownerDocument.elementFromPoint(x, y); | |
if (!node) | |
return null; | |
var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(["ol", "li"]); | |
if (listNode) | |
return listNode.parentTreeElement || listNode.treeElement; | |
return null; | |
} | |
TreeOutline.prototype._treeKeyPress = function(event) | |
{ | |
if (!this.searchable || WebInspector.isBeingEdited(this._childrenListNode)) | |
return; | |
var searchText = String.fromCharCode(event.charCode); | |
if (searchText.trim() !== searchText) | |
return; | |
this._startSearch(searchText); | |
event.consume(true); | |
} | |
TreeOutline.prototype._treeKeyDown = function(event) | |
{ | |
if (event.target !== this._childrenListNode) | |
return; | |
if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) | |
return; | |
var handled = false; | |
var nextSelectedElement; | |
if (event.keyIdentifier === "Up" && !event.altKey) { | |
nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true); | |
while (nextSelectedElement && !nextSelectedElement.selectable) | |
nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing); | |
handled = nextSelectedElement ? true : false; | |
} else if (event.keyIdentifier === "Down" && !event.altKey) { | |
nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true); | |
while (nextSelectedElement && !nextSelectedElement.selectable) | |
nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing); | |
handled = nextSelectedElement ? true : false; | |
} else if (event.keyIdentifier === "Left") { | |
if (this.selectedTreeElement.expanded) { | |
if (event.altKey) | |
this.selectedTreeElement.collapseRecursively(); | |
else | |
this.selectedTreeElement.collapse(); | |
handled = true; | |
} else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { | |
handled = true; | |
if (this.selectedTreeElement.parent.selectable) { | |
nextSelectedElement = this.selectedTreeElement.parent; | |
while (nextSelectedElement && !nextSelectedElement.selectable) | |
nextSelectedElement = nextSelectedElement.parent; | |
handled = nextSelectedElement ? true : false; | |
} else if (this.selectedTreeElement.parent) | |
this.selectedTreeElement.parent.collapse(); | |
} | |
} else if (event.keyIdentifier === "Right") { | |
if (!this.selectedTreeElement.revealed()) { | |
this.selectedTreeElement.reveal(); | |
handled = true; | |
} else if (this.selectedTreeElement.hasChildren) { | |
handled = true; | |
if (this.selectedTreeElement.expanded) { | |
nextSelectedElement = this.selectedTreeElement.children[0]; | |
while (nextSelectedElement && !nextSelectedElement.selectable) | |
nextSelectedElement = nextSelectedElement.nextSibling; | |
handled = nextSelectedElement ? true : false; | |
} else { | |
if (event.altKey) | |
this.selectedTreeElement.expandRecursively(); | |
else | |
this.selectedTreeElement.expand(); | |
} | |
} | |
} else if (event.keyCode === 8 || event.keyCode === 46 ) | |
handled = this.selectedTreeElement.ondelete(); | |
else if (isEnterKey(event)) | |
handled = this.selectedTreeElement.onenter(); | |
else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) | |
handled = this.selectedTreeElement.onspace(); | |
if (nextSelectedElement) { | |
nextSelectedElement.reveal(); | |
nextSelectedElement.select(false, true); | |
} | |
if (handled) | |
event.consume(true); | |
} | |
TreeOutline.prototype.expand = function() | |
{ | |
} | |
TreeOutline.prototype.collapse = function() | |
{ | |
} | |
TreeOutline.prototype.revealed = function() | |
{ | |
return true; | |
} | |
TreeOutline.prototype.reveal = function() | |
{ | |
} | |
TreeOutline.prototype.select = function() | |
{ | |
} | |
TreeOutline.prototype.revealAndSelect = function(omitFocus) | |
{ | |
} | |
TreeOutline.prototype._startSearch = function(searchText) | |
{ | |
if (!this.searchInputElement || !this.searchable) | |
return; | |
this._searching = true; | |
if (this.searchStarted) | |
this.searchStarted(); | |
this.searchInputElement.value = searchText; | |
function focusSearchInput() | |
{ | |
this.searchInputElement.focus(); | |
} | |
window.setTimeout(focusSearchInput.bind(this), 0); | |
this._searchTextChanged(); | |
this._boundSearchTextChanged = this._searchTextChanged.bind(this); | |
this.searchInputElement.addEventListener("paste", this._boundSearchTextChanged); | |
this.searchInputElement.addEventListener("cut", this._boundSearchTextChanged); | |
this.searchInputElement.addEventListener("keypress", this._boundSearchTextChanged); | |
this._boundSearchInputKeyDown = this._searchInputKeyDown.bind(this); | |
this.searchInputElement.addEventListener("keydown", this._boundSearchInputKeyDown); | |
this._boundSearchInputBlur = this._searchInputBlur.bind(this); | |
this.searchInputElement.addEventListener("blur", this._boundSearchInputBlur); | |
} | |
TreeOutline.prototype._searchTextChanged = function() | |
{ | |
function updateSearch() | |
{ | |
var nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.selectedTreeElement, false); | |
if (!nextSelectedElement) | |
nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.children[0], false); | |
this._showSearchMatchElement(nextSelectedElement); | |
} | |
window.setTimeout(updateSearch.bind(this), 0); | |
} | |
TreeOutline.prototype._showSearchMatchElement = function(treeElement) | |
{ | |
this._currentSearchMatchElement = treeElement; | |
if (treeElement) { | |
this._childrenListNode.classList.add("search-match-found"); | |
this._childrenListNode.classList.remove("search-match-not-found"); | |
treeElement.revealAndSelect(true); | |
} else { | |
this._childrenListNode.classList.remove("search-match-found"); | |
this._childrenListNode.classList.add("search-match-not-found"); | |
} | |
} | |
TreeOutline.prototype._searchInputKeyDown = function(event) | |
{ | |
if (event.shiftKey || event.metaKey || event.ctrlKey || event.altKey) | |
return; | |
var handled = false; | |
var nextSelectedElement; | |
if (event.keyIdentifier === "Down") { | |
nextSelectedElement = this._nextSearchMatch(this.searchInputElement.value, this.selectedTreeElement, true); | |
handled = true; | |
} else if (event.keyIdentifier === "Up") { | |
nextSelectedElement = this._previousSearchMatch(this.searchInputElement.value, this.selectedTreeElement); | |
handled = true; | |
} else if (event.keyCode === 27 ) { | |
this._searchFinished(); | |
handled = true; | |
} else if (isEnterKey(event)) { | |
var lastSearchMatchElement = this._currentSearchMatchElement; | |
this._searchFinished(); | |
lastSearchMatchElement.onenter(); | |
handled = true; | |
} | |
if (nextSelectedElement) | |
this._showSearchMatchElement(nextSelectedElement); | |
if (handled) | |
event.consume(true); | |
else | |
window.setTimeout(this._boundSearchTextChanged, 0); | |
} | |
TreeOutline.prototype._nextSearchMatch = function(searchText, startTreeElement, skipStartTreeElement) | |
{ | |
var currentTreeElement = startTreeElement; | |
var skipCurrentTreeElement = skipStartTreeElement; | |
while (currentTreeElement && (skipCurrentTreeElement || !currentTreeElement.matchesSearchText || !currentTreeElement.matchesSearchText(searchText))) { | |
currentTreeElement = currentTreeElement.traverseNextTreeElement(true, null, true); | |
skipCurrentTreeElement = false; | |
} | |
return currentTreeElement; | |
} | |
TreeOutline.prototype._previousSearchMatch = function(searchText, startTreeElement) | |
{ | |
var currentTreeElement = startTreeElement; | |
var skipCurrentTreeElement = true; | |
while (currentTreeElement && (skipCurrentTreeElement || !currentTreeElement.matchesSearchText || !currentTreeElement.matchesSearchText(searchText))) { | |
currentTreeElement = currentTreeElement.traversePreviousTreeElement(true, true); | |
skipCurrentTreeElement = false; | |
} | |
return currentTreeElement; | |
} | |
TreeOutline.prototype._searchInputBlur = function(event) | |
{ | |
this._searchFinished(); | |
} | |
TreeOutline.prototype._searchFinished = function() | |
{ | |
if (!this._searching) | |
return; | |
delete this._searching; | |
this._childrenListNode.classList.remove("search-match-found"); | |
this._childrenListNode.classList.remove("search-match-not-found"); | |
delete this._currentSearchMatchElement; | |
this.searchInputElement.value = ""; | |
this.searchInputElement.removeEventListener("paste", this._boundSearchTextChanged); | |
this.searchInputElement.removeEventListener("cut", this._boundSearchTextChanged); | |
delete this._boundSearchTextChanged; | |
this.searchInputElement.removeEventListener("keydown", this._boundSearchInputKeyDown); | |
delete this._boundSearchInputKeyDown; | |
this.searchInputElement.removeEventListener("blur", this._boundSearchInputBlur); | |
delete this._boundSearchInputBlur; | |
if (this.searchFinished) | |
this.searchFinished(); | |
this.treeOutline._childrenListNode.focus(); | |
} | |
TreeOutline.prototype.stopSearch = function() | |
{ | |
this._searchFinished(); | |
} | |
function TreeElement(title, representedObject, hasChildren) | |
{ | |
this._title = title; | |
this.representedObject = (representedObject || {}); | |
this._hidden = false; | |
this._selectable = true; | |
this.expanded = false; | |
this.selected = false; | |
this.hasChildren = hasChildren; | |
this.children = []; | |
this.treeOutline = null; | |
this.parent = null; | |
this.previousSibling = null; | |
this.nextSibling = null; | |
this._listItemNode = null; | |
} | |
TreeElement.prototype = { | |
arrowToggleWidth: 10, | |
get selectable() { | |
if (this._hidden) | |
return false; | |
return this._selectable; | |
}, | |
set selectable(x) { | |
this._selectable = x; | |
}, | |
get listItemElement() { | |
return this._listItemNode; | |
}, | |
get childrenListElement() { | |
return this._childrenListNode; | |
}, | |
get title() { | |
return this._title; | |
}, | |
set title(x) { | |
this._title = x; | |
this._setListItemNodeContent(); | |
}, | |
get tooltip() { | |
return this._tooltip; | |
}, | |
set tooltip(x) { | |
this._tooltip = x; | |
if (this._listItemNode) | |
this._listItemNode.title = x ? x : ""; | |
}, | |
get hasChildren() { | |
return this._hasChildren; | |
}, | |
set hasChildren(x) { | |
if (this._hasChildren === x) | |
return; | |
this._hasChildren = x; | |
if (!this._listItemNode) | |
return; | |
if (x) | |
this._listItemNode.classList.add("parent"); | |
else { | |
this._listItemNode.classList.remove("parent"); | |
this.collapse(); | |
} | |
}, | |
get hidden() { | |
return this._hidden; | |
}, | |
set hidden(x) { | |
if (this._hidden === x) | |
return; | |
this._hidden = x; | |
if (x) { | |
if (this._listItemNode) | |
this._listItemNode.classList.add("hidden"); | |
if (this._childrenListNode) | |
this._childrenListNode.classList.add("hidden"); | |
} else { | |
if (this._listItemNode) | |
this._listItemNode.classList.remove("hidden"); | |
if (this._childrenListNode) | |
this._childrenListNode.classList.remove("hidden"); | |
} | |
}, | |
get shouldRefreshChildren() { | |
return this._shouldRefreshChildren; | |
}, | |
set shouldRefreshChildren(x) { | |
this._shouldRefreshChildren = x; | |
if (x && this.expanded) | |
this.expand(); | |
}, | |
_setListItemNodeContent: function() | |
{ | |
if (!this._listItemNode) | |
return; | |
if (typeof this._title === "string") | |
this._listItemNode.textContent = this._title; | |
else { | |
this._listItemNode.removeChildren(); | |
if (this._title) | |
this._listItemNode.appendChild(this._title); | |
} | |
} | |
} | |
TreeElement.prototype.appendChild = TreeOutline.prototype.appendChild; | |
TreeElement.prototype.insertChild = TreeOutline.prototype.insertChild; | |
TreeElement.prototype.removeChild = TreeOutline.prototype.removeChild; | |
TreeElement.prototype.removeChildAtIndex = TreeOutline.prototype.removeChildAtIndex; | |
TreeElement.prototype.removeChildren = TreeOutline.prototype.removeChildren; | |
TreeElement.prototype._attach = function() | |
{ | |
if (!this._listItemNode || this.parent._shouldRefreshChildren) { | |
if (this._listItemNode && this._listItemNode.parentNode) | |
this._listItemNode.parentNode.removeChild(this._listItemNode); | |
this._listItemNode = this.treeOutline._childrenListNode.ownerDocument.createElement("li"); | |
this._listItemNode.treeElement = this; | |
this._setListItemNodeContent(); | |
this._listItemNode.title = this._tooltip ? this._tooltip : ""; | |
if (this.hidden) | |
this._listItemNode.classList.add("hidden"); | |
if (this.hasChildren) | |
this._listItemNode.classList.add("parent"); | |
if (this.expanded) | |
this._listItemNode.classList.add("expanded"); | |
if (this.selected) | |
this._listItemNode.classList.add("selected"); | |
this._listItemNode.addEventListener("mousedown", TreeElement.treeElementMouseDown, false); | |
this._listItemNode.addEventListener("click", TreeElement.treeElementToggled, false); | |
this._listItemNode.addEventListener("dblclick", TreeElement.treeElementDoubleClicked, false); | |
this.onattach(); | |
} | |
var nextSibling = null; | |
if (this.nextSibling && this.nextSibling._listItemNode && this.nextSibling._listItemNode.parentNode === this.parent._childrenListNode) | |
nextSibling = this.nextSibling._listItemNode; | |
this.parent._childrenListNode.insertBefore(this._listItemNode, nextSibling); | |
if (this._childrenListNode) | |
this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling); | |
if (this.selected) | |
this.select(); | |
if (this.expanded) | |
this.expand(); | |
} | |
TreeElement.prototype._detach = function() | |
{ | |
if (this._listItemNode && this._listItemNode.parentNode) | |
this._listItemNode.parentNode.removeChild(this._listItemNode); | |
if (this._childrenListNode && this._childrenListNode.parentNode) | |
this._childrenListNode.parentNode.removeChild(this._childrenListNode); | |
} | |
TreeElement.treeElementMouseDown = function(event) | |
{ | |
var element = event.currentTarget; | |
if (!element || !element.treeElement || !element.treeElement.selectable) | |
return; | |
if (element.treeElement.isEventWithinDisclosureTriangle(event)) | |
return; | |
element.treeElement.selectOnMouseDown(event); | |
} | |
TreeElement.treeElementToggled = function(event) | |
{ | |
var element = event.currentTarget; | |
if (!element || !element.treeElement) | |
return; | |
var toggleOnClick = element.treeElement.toggleOnClick && !element.treeElement.selectable; | |
var isInTriangle = element.treeElement.isEventWithinDisclosureTriangle(event); | |
if (!toggleOnClick && !isInTriangle) | |
return; | |
if (element.treeElement.expanded) { | |
if (event.altKey) | |
element.treeElement.collapseRecursively(); | |
else | |
element.treeElement.collapse(); | |
} else { | |
if (event.altKey) | |
element.treeElement.expandRecursively(); | |
else | |
element.treeElement.expand(); | |
} | |
event.consume(); | |
} | |
TreeElement.treeElementDoubleClicked = function(event) | |
{ | |
var element = event.currentTarget; | |
if (!element || !element.treeElement) | |
return; | |
var handled = element.treeElement.ondblclick.call(element.treeElement, event); | |
if (handled) | |
return; | |
if (element.treeElement.hasChildren && !element.treeElement.expanded) | |
element.treeElement.expand(); | |
} | |
TreeElement.prototype.collapse = function() | |
{ | |
if (this._listItemNode) | |
this._listItemNode.classList.remove("expanded"); | |
if (this._childrenListNode) | |
this._childrenListNode.classList.remove("expanded"); | |
this.expanded = false; | |
if (this.treeOutline) | |
this.treeOutline._expandedStateMap.put(this.representedObject, false); | |
this.oncollapse(); | |
} | |
TreeElement.prototype.collapseRecursively = function() | |
{ | |
var item = this; | |
while (item) { | |
if (item.expanded) | |
item.collapse(); | |
item = item.traverseNextTreeElement(false, this, true); | |
} | |
} | |
TreeElement.prototype.expand = function() | |
{ | |
if (!this.hasChildren || (this.expanded && !this._shouldRefreshChildren && this._childrenListNode)) | |
return; | |
this.expanded = true; | |
if (this.treeOutline) | |
this.treeOutline._expandedStateMap.put(this.representedObject, true); | |
if (this.treeOutline && (!this._childrenListNode || this._shouldRefreshChildren)) { | |
if (this._childrenListNode && this._childrenListNode.parentNode) | |
this._childrenListNode.parentNode.removeChild(this._childrenListNode); | |
this._childrenListNode = this.treeOutline._childrenListNode.ownerDocument.createElement("ol"); | |
this._childrenListNode.parentTreeElement = this; | |
this._childrenListNode.classList.add("children"); | |
if (this.hidden) | |
this._childrenListNode.classList.add("hidden"); | |
this.onpopulate(); | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i]._attach(); | |
delete this._shouldRefreshChildren; | |
} | |
if (this._listItemNode) { | |
this._listItemNode.classList.add("expanded"); | |
if (this._childrenListNode && this._childrenListNode.parentNode != this._listItemNode.parentNode) | |
this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling); | |
} | |
if (this._childrenListNode) | |
this._childrenListNode.classList.add("expanded"); | |
this.onexpand(); | |
} | |
TreeElement.prototype.expandRecursively = function(maxDepth) | |
{ | |
var item = this; | |
var info = {}; | |
var depth = 0; | |
if (typeof maxDepth === "undefined" || typeof maxDepth === "null") | |
maxDepth = 3; | |
while (item) { | |
if (depth < maxDepth) | |
item.expand(); | |
item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); | |
depth += info.depthChange; | |
} | |
} | |
TreeElement.prototype.hasAncestor = function(ancestor) { | |
if (!ancestor) | |
return false; | |
var currentNode = this.parent; | |
while (currentNode) { | |
if (ancestor === currentNode) | |
return true; | |
currentNode = currentNode.parent; | |
} | |
return false; | |
} | |
TreeElement.prototype.reveal = function() | |
{ | |
var currentAncestor = this.parent; | |
while (currentAncestor && !currentAncestor.root) { | |
if (!currentAncestor.expanded) | |
currentAncestor.expand(); | |
currentAncestor = currentAncestor.parent; | |
} | |
this.onreveal(this); | |
} | |
TreeElement.prototype.revealed = function() | |
{ | |
var currentAncestor = this.parent; | |
while (currentAncestor && !currentAncestor.root) { | |
if (!currentAncestor.expanded) | |
return false; | |
currentAncestor = currentAncestor.parent; | |
} | |
return true; | |
} | |
TreeElement.prototype.selectOnMouseDown = function(event) | |
{ | |
if (this.select(false, true)) | |
event.consume(true); | |
} | |
TreeElement.prototype.select = function(omitFocus, selectedByUser) | |
{ | |
if (!this.treeOutline || !this.selectable || this.selected) | |
return false; | |
if (this.treeOutline.selectedTreeElement) | |
this.treeOutline.selectedTreeElement.deselect(); | |
this.selected = true; | |
if(!omitFocus) | |
this.treeOutline._childrenListNode.focus(); | |
if (!this.treeOutline) | |
return false; | |
this.treeOutline.selectedTreeElement = this; | |
if (this._listItemNode) | |
this._listItemNode.classList.add("selected"); | |
return this.onselect(selectedByUser); | |
} | |
TreeElement.prototype.revealAndSelect = function(omitFocus) | |
{ | |
this.reveal(); | |
this.select(omitFocus); | |
} | |
TreeElement.prototype.deselect = function(supressOnDeselect) | |
{ | |
if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected) | |
return false; | |
this.selected = false; | |
this.treeOutline.selectedTreeElement = null; | |
if (this._listItemNode) | |
this._listItemNode.classList.remove("selected"); | |
return true; | |
} | |
TreeElement.prototype.onpopulate = function() { } | |
TreeElement.prototype.onenter = function() { } | |
TreeElement.prototype.ondelete = function() { } | |
TreeElement.prototype.onspace = function() { } | |
TreeElement.prototype.onattach = function() { } | |
TreeElement.prototype.onexpand = function() { } | |
TreeElement.prototype.oncollapse = function() { } | |
TreeElement.prototype.ondblclick = function() { } | |
TreeElement.prototype.onreveal = function() { } | |
TreeElement.prototype.onselect = function(selectedByUser) { } | |
TreeElement.prototype.traverseNextTreeElement = function(skipUnrevealed, stayWithin, dontPopulate, info) | |
{ | |
if (!dontPopulate && this.hasChildren) | |
this.onpopulate(); | |
if (info) | |
info.depthChange = 0; | |
var element = skipUnrevealed ? (this.revealed() ? this.children[0] : null) : this.children[0]; | |
if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { | |
if (info) | |
info.depthChange = 1; | |
return element; | |
} | |
if (this === stayWithin) | |
return null; | |
element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; | |
if (element) | |
return element; | |
element = this; | |
while (element && !element.root && !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) { | |
if (info) | |
info.depthChange -= 1; | |
element = element.parent; | |
} | |
if (!element) | |
return null; | |
return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); | |
} | |
TreeElement.prototype.traversePreviousTreeElement = function(skipUnrevealed, dontPopulate) | |
{ | |
var element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; | |
if (!dontPopulate && element && element.hasChildren) | |
element.onpopulate(); | |
while (element && (skipUnrevealed ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1])) { | |
if (!dontPopulate && element.hasChildren) | |
element.onpopulate(); | |
element = (skipUnrevealed ? (element.revealed() && element.expanded ? element.children[element.children.length - 1] : null) : element.children[element.children.length - 1]); | |
} | |
if (element) | |
return element; | |
if (!this.parent || this.parent.root) | |
return null; | |
return this.parent; | |
} | |
TreeElement.prototype.isEventWithinDisclosureTriangle = function(event) | |
{ | |
var paddingLeftValue = window.getComputedStyle(this._listItemNode).getPropertyCSSValue("padding-left"); | |
var computedLeftPadding = paddingLeftValue ? paddingLeftValue.getFloatValue(CSSPrimitiveValue.CSS_PX) : 0; | |
var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; | |
return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren; | |
} | |
var WebInspector = { | |
_panelDescriptors: function() | |
{ | |
this.panels = {}; | |
WebInspector.inspectorView = new WebInspector.InspectorView(); | |
var parentElement = document.getElementById("main"); | |
WebInspector.inspectorView.show(parentElement); | |
WebInspector.inspectorView.addEventListener(WebInspector.InspectorView.Events.PanelSelected, this._panelSelected, this); | |
var elements = new WebInspector.ElementsPanelDescriptor(); | |
var resources = new WebInspector.PanelDescriptor("resources", WebInspector.UIString("Resources"), "ResourcesPanel", "ResourcesPanel.js"); | |
var network = new WebInspector.NetworkPanelDescriptor(); | |
var scripts = new WebInspector.ScriptsPanelDescriptor(); | |
var timeline = new WebInspector.PanelDescriptor("timeline", WebInspector.UIString("Timeline"), "TimelinePanel", "TimelinePanel.js"); | |
var profiles = new WebInspector.PanelDescriptor("profiles", WebInspector.UIString("Profiles"), "ProfilesPanel", "ProfilesPanel.js"); | |
var audits = new WebInspector.PanelDescriptor("audits", WebInspector.UIString("Audits"), "AuditsPanel", "AuditsPanel.js"); | |
var console = new WebInspector.PanelDescriptor("console", WebInspector.UIString("Console"), "ConsolePanel"); | |
var allDescriptors = [elements, resources, network, scripts, timeline, profiles, audits, console]; | |
var panelDescriptors = []; | |
if (WebInspector.WorkerManager.isWorkerFrontend()) { | |
panelDescriptors.push(scripts); | |
panelDescriptors.push(timeline); | |
panelDescriptors.push(profiles); | |
panelDescriptors.push(console); | |
return panelDescriptors; | |
} | |
var allDescriptors = [elements, resources, network, scripts, timeline, profiles, audits, console]; | |
var hiddenPanels = InspectorFrontendHost.hiddenPanels(); | |
for (var i = 0; i < allDescriptors.length; ++i) { | |
if (hiddenPanels.indexOf(allDescriptors[i].name()) === -1) | |
panelDescriptors.push(allDescriptors[i]); | |
} | |
return panelDescriptors; | |
}, | |
_panelSelected: function() | |
{ | |
this._toggleConsoleButton.disabled = WebInspector.inspectorView.currentPanel().name === "console"; | |
}, | |
_createGlobalStatusBarItems: function() | |
{ | |
var bottomStatusBarContainer = document.getElementById("bottom-status-bar-container"); | |
this._dockToggleButton = new WebInspector.StatusBarButton("", "dock-status-bar-item", 3); | |
this._dockToggleButton.makeLongClickEnabled(this._createDockOptions.bind(this)); | |
this._dockToggleButton.addEventListener("click", this._toggleAttach.bind(this), false); | |
this._updateDockButtonState(); | |
var mainStatusBar = document.getElementById("main-status-bar"); | |
mainStatusBar.insertBefore(this._dockToggleButton.element, bottomStatusBarContainer); | |
this._toggleConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Show console."), "console-status-bar-item"); | |
this._toggleConsoleButton.addEventListener("click", this._toggleConsoleButtonClicked.bind(this), false); | |
mainStatusBar.insertBefore(this._toggleConsoleButton.element, bottomStatusBarContainer); | |
if (!WebInspector.WorkerManager.isWorkerFrontend()) { | |
this._nodeSearchButton = new WebInspector.StatusBarButton(WebInspector.UIString("Select an element in the page to inspect it."), "node-search-status-bar-item"); | |
this._nodeSearchButton.addEventListener("click", this.toggleSearchingForNode, this); | |
mainStatusBar.insertBefore(this._nodeSearchButton.element, bottomStatusBarContainer); | |
} | |
mainStatusBar.appendChild(this.settingsController.statusBarItem); | |
}, | |
_createDockOptions: function() | |
{ | |
var alternateDockToggleButton1 = new WebInspector.StatusBarButton("Dock to main window.", "dock-status-bar-item", 3); | |
var alternateDockToggleButton2 = new WebInspector.StatusBarButton("Undock into separate window.", "dock-status-bar-item", 3); | |
if (this.attached) { | |
alternateDockToggleButton1.state = WebInspector.settings.dockToRight.get() ? "bottom" : "right"; | |
alternateDockToggleButton2.state = "undock"; | |
} else { | |
alternateDockToggleButton1.state = WebInspector.settings.dockToRight.get() ? "bottom" : "right"; | |
alternateDockToggleButton2.state = WebInspector.settings.dockToRight.get() ? "right" : "bottom"; | |
} | |
alternateDockToggleButton1.addEventListener("click", onClick.bind(this), false); | |
alternateDockToggleButton2.addEventListener("click", onClick.bind(this), false); | |
function onClick(e) | |
{ | |
var state = e.target.state; | |
if (state === "undock") | |
this._toggleAttach(); | |
else if (state === "right") { | |
if (!this.attached) | |
this._toggleAttach(); | |
WebInspector.settings.dockToRight.set(true); | |
} else if (state === "bottom") { | |
if (!this.attached) | |
this._toggleAttach(); | |
WebInspector.settings.dockToRight.set(false); | |
} | |
} | |
return [alternateDockToggleButton1, alternateDockToggleButton2]; | |
}, | |
_updateDockButtonState: function() | |
{ | |
if (!this._dockToggleButton) | |
return; | |
if (this.attached) { | |
this._dockToggleButton.disabled = false; | |
this._dockToggleButton.state = "undock"; | |
this._dockToggleButton.title = WebInspector.UIString("Undock into separate window."); | |
} else { | |
this._dockToggleButton.disabled = this._isDockingUnavailable; | |
this._dockToggleButton.state = WebInspector.settings.dockToRight.get() ? "right" : "bottom"; | |
this._dockToggleButton.title = WebInspector.UIString("Dock to main window."); | |
} | |
}, | |
_toggleAttach: function() | |
{ | |
if (!this._attached) { | |
InspectorFrontendHost.requestAttachWindow(); | |
WebInspector.userMetrics.WindowDocked.record(); | |
} else { | |
InspectorFrontendHost.requestDetachWindow(); | |
WebInspector.userMetrics.WindowUndocked.record(); | |
} | |
}, | |
_toggleConsoleButtonClicked: function() | |
{ | |
if (this._toggleConsoleButton.disabled) | |
return; | |
this._toggleConsoleButton.toggled = !this._toggleConsoleButton.toggled; | |
var animationType = window.event && window.event.shiftKey ? WebInspector.Drawer.AnimationType.Slow : WebInspector.Drawer.AnimationType.Normal; | |
if (this._toggleConsoleButton.toggled) { | |
this._toggleConsoleButton.title = WebInspector.UIString("Hide console."); | |
this.drawer.show(this.consoleView, animationType); | |
this._consoleWasShown = true; | |
} else { | |
this._toggleConsoleButton.title = WebInspector.UIString("Show console."); | |
this.drawer.hide(animationType); | |
delete this._consoleWasShown; | |
} | |
}, | |
showViewInDrawer: function(statusBarElement, view, onclose) | |
{ | |
this._toggleConsoleButton.title = WebInspector.UIString("Hide console."); | |
this._toggleConsoleButton.toggled = false; | |
this._closePreviousDrawerView(); | |
var drawerStatusBarHeader = document.createElement("div"); | |
drawerStatusBarHeader.className = "drawer-header status-bar-item"; | |
drawerStatusBarHeader.appendChild(statusBarElement); | |
drawerStatusBarHeader.onclose = onclose; | |
var closeButton = drawerStatusBarHeader.createChild("span"); | |
closeButton.textContent = WebInspector.UIString("\u00D7"); | |
closeButton.addStyleClass("drawer-header-close-button"); | |
closeButton.addEventListener("click", this.closeViewInDrawer.bind(this), false); | |
document.getElementById("panel-status-bar").firstElementChild.appendChild(drawerStatusBarHeader); | |
this._drawerStatusBarHeader = drawerStatusBarHeader; | |
this.drawer.show(view, WebInspector.Drawer.AnimationType.Immediately); | |
}, | |
closeViewInDrawer: function() | |
{ | |
if (this._drawerStatusBarHeader) { | |
this._closePreviousDrawerView(); | |
if (!this._consoleWasShown) | |
this.drawer.hide(WebInspector.Drawer.AnimationType.Immediately); | |
else | |
this._toggleConsoleButtonClicked(); | |
} | |
}, | |
_closePreviousDrawerView: function() | |
{ | |
if (this._drawerStatusBarHeader) { | |
this._drawerStatusBarHeader.parentElement.removeChild(this._drawerStatusBarHeader); | |
if (this._drawerStatusBarHeader.onclose) | |
this._drawerStatusBarHeader.onclose(); | |
delete this._drawerStatusBarHeader; | |
} | |
}, | |
get attached() | |
{ | |
return this._attached; | |
}, | |
set attached(x) | |
{ | |
if (this._attached === x) | |
return; | |
this._attached = x; | |
if (x) | |
document.body.removeStyleClass("detached"); | |
else | |
document.body.addStyleClass("detached"); | |
this._setCompactMode(x && !WebInspector.settings.dockToRight.get()); | |
this._updateDockButtonState(); | |
}, | |
isCompactMode: function() | |
{ | |
return this.attached && !WebInspector.settings.dockToRight.get(); | |
}, | |
_setCompactMode: function(x) | |
{ | |
var body = document.body; | |
if (x) | |
body.addStyleClass("compact"); | |
else | |
body.removeStyleClass("compact"); | |
WebInspector.windowResize(); | |
}, | |
_updateErrorAndWarningCounts: function() | |
{ | |
var errorWarningElement = document.getElementById("error-warning-count"); | |
if (!errorWarningElement) | |
return; | |
var errors = WebInspector.console.errors; | |
var warnings = WebInspector.console.warnings; | |
if (!errors && !warnings) { | |
errorWarningElement.addStyleClass("hidden"); | |
return; | |
} | |
errorWarningElement.removeStyleClass("hidden"); | |
errorWarningElement.removeChildren(); | |
if (errors) { | |
var errorImageElement = document.createElement("img"); | |
errorImageElement.id = "error-count-img"; | |
errorWarningElement.appendChild(errorImageElement); | |
var errorElement = document.createElement("span"); | |
errorElement.id = "error-count"; | |
errorElement.textContent = errors; | |
errorWarningElement.appendChild(errorElement); | |
} | |
if (warnings) { | |
var warningsImageElement = document.createElement("img"); | |
warningsImageElement.id = "warning-count-img"; | |
errorWarningElement.appendChild(warningsImageElement); | |
var warningsElement = document.createElement("span"); | |
warningsElement.id = "warning-count"; | |
warningsElement.textContent = warnings; | |
errorWarningElement.appendChild(warningsElement); | |
} | |
if (errors) { | |
if (warnings) { | |
if (errors == 1) { | |
if (warnings == 1) | |
errorWarningElement.title = WebInspector.UIString("%d error, %d warning", errors, warnings); | |
else | |
errorWarningElement.title = WebInspector.UIString("%d error, %d warnings", errors, warnings); | |
} else if (warnings == 1) | |
errorWarningElement.title = WebInspector.UIString("%d errors, %d warning", errors, warnings); | |
else | |
errorWarningElement.title = WebInspector.UIString("%d errors, %d warnings", errors, warnings); | |
} else if (errors == 1) | |
errorWarningElement.title = WebInspector.UIString("%d error", errors); | |
else | |
errorWarningElement.title = WebInspector.UIString("%d errors", errors); | |
} else if (warnings == 1) | |
errorWarningElement.title = WebInspector.UIString("%d warning", warnings); | |
else if (warnings) | |
errorWarningElement.title = WebInspector.UIString("%d warnings", warnings); | |
else | |
errorWarningElement.title = null; | |
}, | |
get inspectedPageDomain() | |
{ | |
var parsedURL = WebInspector.inspectedPageURL && WebInspector.inspectedPageURL.asParsedURL(); | |
return parsedURL ? parsedURL.host : ""; | |
}, | |
_initializeCapability: function(name, callback, error, result) | |
{ | |
Capabilities[name] = result; | |
if (callback) | |
callback(); | |
}, | |
_zoomIn: function() | |
{ | |
++this._zoomLevel; | |
this._requestZoom(); | |
}, | |
_zoomOut: function() | |
{ | |
--this._zoomLevel; | |
this._requestZoom(); | |
}, | |
_resetZoom: function() | |
{ | |
this._zoomLevel = 0; | |
this._requestZoom(); | |
}, | |
_requestZoom: function() | |
{ | |
WebInspector.settings.zoomLevel.set(this._zoomLevel); | |
InspectorFrontendHost.setZoomFactor(Math.pow(1.2, this._zoomLevel)); | |
}, | |
toggleSearchingForNode: function() | |
{ | |
var enabled = !this._nodeSearchButton.toggled; | |
function callback(error) | |
{ | |
if (!error) | |
this._nodeSearchButton.toggled = enabled; | |
} | |
WebInspector.domAgent.setInspectModeEnabled(enabled, callback.bind(this)); | |
}, | |
_profilesLinkifier: function(title) | |
{ | |
var profileStringMatches = WebInspector.ProfileURLRegExp.exec(title); | |
if (profileStringMatches) { | |
var profilesPanel = WebInspector.panel("profiles"); | |
title = WebInspector.ProfilesPanel._instance.displayTitleForProfileLink(profileStringMatches[2], profileStringMatches[1]); | |
} | |
return title; | |
}, | |
_debuggerPaused: function() | |
{ | |
WebInspector.panel("scripts"); | |
} | |
} | |
WebInspector.Events = { | |
InspectorClosing: "InspectorClosing" | |
} | |
{(function parseQueryParameters() | |
{ | |
WebInspector.queryParamsObject = {}; | |
var queryParams = window.location.search; | |
if (!queryParams) | |
return; | |
var params = queryParams.substring(1).split("&"); | |
for (var i = 0; i < params.length; ++i) { | |
var pair = params[i].split("="); | |
WebInspector.queryParamsObject[pair[0]] = pair[1]; | |
} | |
})();} | |
WebInspector.loaded = function() | |
{ | |
InspectorBackend.loadFromJSONIfNeeded("../Inspector.json"); | |
if (WebInspector.WorkerManager.isDedicatedWorkerFrontend()) { | |
WebInspector.doLoadedDone(); | |
return; | |
} | |
var ws; | |
if ("ws" in WebInspector.queryParamsObject) | |
ws = "ws://" + WebInspector.queryParamsObject.ws; | |
else if ("page" in WebInspector.queryParamsObject) { | |
var page = WebInspector.queryParamsObject.page; | |
var host = "host" in WebInspector.queryParamsObject ? WebInspector.queryParamsObject.host : window.location.host; | |
ws = "ws://" + host + "/devtools/page/" + page; | |
} | |
if (ws) { | |
WebInspector.socket = new WebSocket(ws); | |
WebInspector.socket.onmessage = function(message) { InspectorBackend.dispatch(message.data); } | |
WebInspector.socket.onerror = function(error) { console.error(error); } | |
WebInspector.socket.onopen = function() { | |
InspectorFrontendHost.sendMessageToBackend = WebInspector.socket.send.bind(WebInspector.socket); | |
WebInspector.doLoadedDone(); | |
} | |
return; | |
} | |
WebInspector.doLoadedDone(); | |
if (InspectorFrontendHost.isStub) { | |
InspectorFrontendAPI.dispatchQueryParameters(); | |
WebInspector._doLoadedDoneWithCapabilities(); | |
} | |
} | |
WebInspector.doLoadedDone = function() | |
{ | |
WebInspector.installPortStyles(); | |
if (WebInspector.socket) | |
document.body.addStyleClass("remote"); | |
if (WebInspector.queryParamsObject.toolbarColor && WebInspector.queryParamsObject.textColor) | |
WebInspector.setToolbarColors(WebInspector.queryParamsObject.toolbarColor, WebInspector.queryParamsObject.textColor); | |
InspectorFrontendHost.loaded(); | |
WebInspector.WorkerManager.loaded(); | |
DebuggerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "debuggerCausesRecompilation", null)); | |
DebuggerAgent.supportsSeparateScriptCompilationAndExecution(WebInspector._initializeCapability.bind(WebInspector, "separateScriptCompilationAndExecutionEnabled", null)); | |
ProfilerAgent.causesRecompilation(WebInspector._initializeCapability.bind(WebInspector, "profilerCausesRecompilation", null)); | |
ProfilerAgent.isSampling(WebInspector._initializeCapability.bind(WebInspector, "samplingCPUProfiler", null)); | |
ProfilerAgent.hasHeapProfiler(WebInspector._initializeCapability.bind(WebInspector, "heapProfilerPresent", null)); | |
TimelineAgent.supportsFrameInstrumentation(WebInspector._initializeCapability.bind(WebInspector, "timelineSupportsFrameInstrumentation", null)); | |
PageAgent.canOverrideDeviceMetrics(WebInspector._initializeCapability.bind(WebInspector, "canOverrideDeviceMetrics", null)); | |
PageAgent.canOverrideGeolocation(WebInspector._initializeCapability.bind(WebInspector, "canOverrideGeolocation", null)); | |
PageAgent.canOverrideDeviceOrientation(WebInspector._initializeCapability.bind(WebInspector, "canOverrideDeviceOrientation", WebInspector._doLoadedDoneWithCapabilities.bind(WebInspector))); | |
} | |
WebInspector._doLoadedDoneWithCapabilities = function() | |
{ | |
WebInspector.shortcutsScreen = new WebInspector.ShortcutsScreen(); | |
this._registerShortcuts(); | |
WebInspector.shortcutsScreen.section(WebInspector.UIString("Console")); | |
WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel")); | |
this.console = new WebInspector.ConsoleModel(); | |
this.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._updateErrorAndWarningCounts, this); | |
this.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._updateErrorAndWarningCounts, this); | |
this.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._updateErrorAndWarningCounts, this); | |
WebInspector.CSSCompletions.requestCSSNameCompletions(); | |
this.drawer = new WebInspector.Drawer(); | |
this.networkManager = new WebInspector.NetworkManager(); | |
this.resourceTreeModel = new WebInspector.ResourceTreeModel(this.networkManager); | |
this.debuggerModel = new WebInspector.DebuggerModel(); | |
this.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); | |
this.networkLog = new WebInspector.NetworkLog(); | |
this.domAgent = new WebInspector.DOMAgent(); | |
this.runtimeModel = new WebInspector.RuntimeModel(this.resourceTreeModel); | |
this.consoleView = new WebInspector.ConsoleView(WebInspector.WorkerManager.isWorkerFrontend()); | |
InspectorBackend.registerInspectorDispatcher(this); | |
this.cssModel = new WebInspector.CSSStyleModel(); | |
this.timelineManager = new WebInspector.TimelineManager(); | |
this.userAgentSupport = new WebInspector.UserAgentSupport(); | |
this.searchController = new WebInspector.SearchController(); | |
this.advancedSearchController = new WebInspector.AdvancedSearchController(); | |
this.settingsController = new WebInspector.SettingsController(); | |
this.domBreakpointsSidebarPane = new WebInspector.DOMBreakpointsSidebarPane(); | |
this._zoomLevel = WebInspector.settings.zoomLevel.get(); | |
if (this._zoomLevel) | |
this._requestZoom(); | |
var autoselectPanel = WebInspector.UIString("a panel chosen automatically"); | |
var openAnchorLocationSetting = WebInspector.settings.createSetting("openLinkHandler", autoselectPanel); | |
this.openAnchorLocationRegistry = new WebInspector.HandlerRegistry(openAnchorLocationSetting); | |
this.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; }); | |
this.workspace = new WebInspector.Workspace(); | |
this.workspaceController = new WebInspector.WorkspaceController(this.workspace); | |
this.breakpointManager = new WebInspector.BreakpointManager(WebInspector.settings.breakpoints, this.debuggerModel, this.workspace); | |
this.scriptSnippetModel = new WebInspector.ScriptSnippetModel(this.workspace); | |
new WebInspector.DebuggerScriptMapping(this.workspace); | |
new WebInspector.NetworkUISourceCodeProvider(this.workspace); | |
new WebInspector.StylesSourceMapping(this.workspace); | |
if (WebInspector.experimentsSettings.sass.isEnabled()) | |
new WebInspector.SASSSourceMapping(this.workspace); | |
new WebInspector.PresentationConsoleMessageHelper(this.workspace); | |
this._createGlobalStatusBarItems(); | |
WebInspector._installDockToRight(); | |
this.toolbar = new WebInspector.Toolbar(); | |
WebInspector.startBatchUpdate(); | |
var panelDescriptors = this._panelDescriptors(); | |
for (var i = 0; i < panelDescriptors.length; ++i) | |
WebInspector.inspectorView.addPanel(panelDescriptors[i]); | |
WebInspector.endBatchUpdate(); | |
this.addMainEventListeners(document); | |
WebInspector.registerLinkifierPlugin(this._profilesLinkifier.bind(this)); | |
window.addEventListener("resize", this.windowResize.bind(this), true); | |
var errorWarningCount = document.getElementById("error-warning-count"); | |
errorWarningCount.addEventListener("click", this.showConsole.bind(this), false); | |
this._updateErrorAndWarningCounts(); | |
this.extensionServer.initExtensions(); | |
this.console.enableAgent(); | |
function showInitialPanel() | |
{ | |
if (!WebInspector.inspectorView.currentPanel()) | |
WebInspector.showPanel(WebInspector.settings.lastActivePanel.get()); | |
} | |
InspectorAgent.enable(showInitialPanel); | |
this.databaseModel = new WebInspector.DatabaseModel(); | |
this.domStorageModel = new WebInspector.DOMStorageModel(); | |
if (!Capabilities.profilerCausesRecompilation || WebInspector.settings.profilerEnabled.get()) | |
ProfilerAgent.enable(); | |
if (WebInspector.settings.showPaintRects.get()) | |
PageAgent.setShowPaintRects(true); | |
if (WebInspector.settings.javaScriptDisabled.get()) | |
PageAgent.setScriptExecutionDisabled(true); | |
this.domAgent._emulateTouchEventsChanged(); | |
WebInspector.WorkerManager.loadCompleted(); | |
InspectorFrontendAPI.loadCompleted(); | |
} | |
WebInspector._installDockToRight = function() | |
{ | |
WebInspector.settings.dockToRight.set(WebInspector.queryParamsObject.dockSide === "right"); | |
if (WebInspector.settings.dockToRight.get()) | |
document.body.addStyleClass("dock-to-right"); | |
if (WebInspector.attached) | |
WebInspector._setCompactMode(!WebInspector.settings.dockToRight.get()); | |
WebInspector.settings.dockToRight.addChangeListener(listener.bind(this)); | |
function listener(event) | |
{ | |
var value = WebInspector.settings.dockToRight.get(); | |
if (value) { | |
InspectorFrontendHost.requestSetDockSide("right"); | |
document.body.addStyleClass("dock-to-right"); | |
} else { | |
InspectorFrontendHost.requestSetDockSide("bottom"); | |
document.body.removeStyleClass("dock-to-right"); | |
} | |
if (WebInspector.attached) | |
WebInspector._setCompactMode(!value); | |
else | |
WebInspector._updateDockButtonState(); | |
} | |
} | |
var windowLoaded = function() | |
{ | |
var localizedStringsURL = InspectorFrontendHost.localizedStringsURL(); | |
if (localizedStringsURL) { | |
var localizedStringsScriptElement = document.createElement("script"); | |
localizedStringsScriptElement.addEventListener("load", WebInspector.loaded.bind(WebInspector), false); | |
localizedStringsScriptElement.type = "text/javascript"; | |
localizedStringsScriptElement.src = localizedStringsURL; | |
document.head.appendChild(localizedStringsScriptElement); | |
} else | |
WebInspector.loaded(); | |
WebInspector.attached = WebInspector.queryParamsObject.docked === "true"; | |
window.removeEventListener("DOMContentLoaded", windowLoaded, false); | |
delete windowLoaded; | |
}; | |
window.addEventListener("DOMContentLoaded", windowLoaded, false); | |
var messagesToDispatch = []; | |
WebInspector.dispatchQueueIsEmpty = function() { | |
return messagesToDispatch.length == 0; | |
} | |
WebInspector.dispatch = function(message) { | |
messagesToDispatch.push(message); | |
setTimeout(function() { | |
InspectorBackend.dispatch(messagesToDispatch.shift()); | |
}, 0); | |
} | |
WebInspector.dispatchMessageFromBackend = function(messageObject) | |
{ | |
WebInspector.dispatch(messageObject); | |
} | |
WebInspector.windowResize = function(event) | |
{ | |
if (WebInspector.inspectorView) | |
WebInspector.inspectorView.doResize(); | |
if (WebInspector.drawer) | |
WebInspector.drawer.resize(); | |
if (WebInspector.toolbar) | |
WebInspector.toolbar.resize(); | |
if (WebInspector.settingsController) | |
WebInspector.settingsController.resize(); | |
} | |
WebInspector.setDockingUnavailable = function(unavailable) | |
{ | |
this._isDockingUnavailable = unavailable; | |
this._updateDockButtonState(); | |
} | |
WebInspector.close = function(event) | |
{ | |
if (this._isClosing) | |
return; | |
this._isClosing = true; | |
this.notifications.dispatchEventToListeners(WebInspector.Events.InspectorClosing); | |
InspectorFrontendHost.closeWindow(); | |
} | |
WebInspector.documentClick = function(event) | |
{ | |
var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); | |
if (!anchor || anchor.target === "_blank") | |
return; | |
event.consume(true); | |
function followLink() | |
{ | |
if (WebInspector.isBeingEdited(event.target) || WebInspector._showAnchorLocation(anchor)) | |
return; | |
const profileMatch = WebInspector.ProfileURLRegExp.exec(anchor.href); | |
if (profileMatch) { | |
WebInspector.showProfileForURL(anchor.href); | |
return; | |
} | |
var parsedURL = anchor.href.asParsedURL(); | |
if (parsedURL && parsedURL.scheme === "webkit-link-action") { | |
if (parsedURL.host === "show-panel") { | |
var panel = parsedURL.path.substring(1); | |
if (WebInspector.panel(panel)) | |
WebInspector.showPanel(panel); | |
} | |
return; | |
} | |
InspectorFrontendHost.openInNewTab(anchor.href); | |
} | |
if (WebInspector.followLinkTimeout) | |
clearTimeout(WebInspector.followLinkTimeout); | |
if (anchor.preventFollowOnDoubleClick) { | |
if (event.detail === 1) | |
WebInspector.followLinkTimeout = setTimeout(followLink, 333); | |
return; | |
} | |
followLink(); | |
} | |
WebInspector.openResource = function(resourceURL, inResourcesPanel) | |
{ | |
var resource = WebInspector.resourceForURL(resourceURL); | |
if (inResourcesPanel && resource) | |
WebInspector.showPanel("resources").showResource(resource); | |
else | |
InspectorFrontendHost.openInNewTab(resourceURL); | |
} | |
WebInspector._registerShortcuts = function() | |
{ | |
var shortcut = WebInspector.KeyboardShortcut; | |
var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("All Panels")); | |
var keys = [ | |
shortcut.shortcutToString("]", shortcut.Modifiers.CtrlOrMeta), | |
shortcut.shortcutToString("[", shortcut.Modifiers.CtrlOrMeta) | |
]; | |
section.addRelatedKeys(keys, WebInspector.UIString("Go to the panel to the left/right")); | |
var keys = [ | |
shortcut.shortcutToString("[", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt), | |
shortcut.shortcutToString("]", shortcut.Modifiers.CtrlOrMeta | shortcut.Modifiers.Alt) | |
]; | |
section.addRelatedKeys(keys, WebInspector.UIString("Go back/forward in panel history")); | |
section.addKey(shortcut.shortcutToString(shortcut.Keys.Esc), WebInspector.UIString("Toggle console")); | |
section.addKey(shortcut.shortcutToString("f", shortcut.Modifiers.CtrlOrMeta), WebInspector.UIString("Search")); | |
var advancedSearchShortcut = WebInspector.AdvancedSearchController.createShortcut(); | |
section.addKey(advancedSearchShortcut.name, WebInspector.UIString("Search across all sources")); | |
var openResourceShortcut = WebInspector.KeyboardShortcut.makeDescriptor("o", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta); | |
section.addKey(openResourceShortcut.name, WebInspector.UIString("Go to source")); | |
if (WebInspector.isMac()) { | |
keys = [ | |
shortcut.shortcutToString("g", shortcut.Modifiers.Meta), | |
shortcut.shortcutToString("g", shortcut.Modifiers.Meta | shortcut.Modifiers.Shift) | |
]; | |
section.addRelatedKeys(keys, WebInspector.UIString("Find next/previous")); | |
} | |
var goToShortcut = WebInspector.GoToLineDialog.createShortcut(); | |
section.addKey(goToShortcut.name, WebInspector.UIString("Go to line")); | |
} | |
WebInspector.documentKeyDown = function(event) | |
{ | |
const helpKey = WebInspector.isMac() ? "U+003F" : "U+00BF"; | |
if (event.keyIdentifier === "F1" || | |
(event.keyIdentifier === helpKey && event.shiftKey && (!WebInspector.isBeingEdited(event.target) || event.metaKey))) { | |
this.settingsController.showSettingsScreen(WebInspector.SettingsScreen.Tabs.Shortcuts); | |
event.consume(true); | |
return; | |
} | |
if (WebInspector.currentFocusElement() && WebInspector.currentFocusElement().handleKeyEvent) { | |
WebInspector.currentFocusElement().handleKeyEvent(event); | |
if (event.handled) { | |
event.consume(true); | |
return; | |
} | |
} | |
if (WebInspector.inspectorView.currentPanel()) { | |
WebInspector.inspectorView.currentPanel().handleShortcut(event); | |
if (event.handled) { | |
event.consume(true); | |
return; | |
} | |
} | |
if (WebInspector.searchController.handleShortcut(event)) | |
return; | |
if (WebInspector.advancedSearchController.handleShortcut(event)) | |
return; | |
switch (event.keyIdentifier) { | |
case "U+004F": | |
if (!event.shiftKey && !event.altKey && WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) { | |
WebInspector.showPanel("scripts").showGoToSourceDialog(); | |
event.consume(true); | |
} | |
break; | |
case "U+0052": | |
if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event)) { | |
PageAgent.reload(event.shiftKey); | |
event.consume(true); | |
} | |
break; | |
case "F5": | |
if (!WebInspector.isMac()) { | |
PageAgent.reload(event.ctrlKey || event.shiftKey); | |
event.consume(true); | |
} | |
break; | |
} | |
var isValidZoomShortcut = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && | |
!event.altKey && | |
!InspectorFrontendHost.isStub; | |
switch (event.keyCode) { | |
case 107: | |
case 187: | |
if (isValidZoomShortcut) { | |
WebInspector._zoomIn(); | |
event.consume(true); | |
} | |
break; | |
case 109: | |
case 189: | |
if (isValidZoomShortcut) { | |
WebInspector._zoomOut(); | |
event.consume(true); | |
} | |
break; | |
case 48: | |
if (isValidZoomShortcut && !event.shiftKey) { | |
WebInspector._resetZoom(); | |
event.consume(true); | |
} | |
break; | |
} | |
if (event.keyIdentifier === "U+0043") { | |
if (WebInspector.isMac()) | |
var isNodeSearchKey = event.metaKey && !event.ctrlKey && !event.altKey && event.shiftKey; | |
else | |
var isNodeSearchKey = event.ctrlKey && !event.metaKey && !event.altKey && event.shiftKey; | |
if (isNodeSearchKey) { | |
this.toggleSearchingForNode(); | |
event.consume(true); | |
return; | |
} | |
return; | |
} | |
} | |
WebInspector.postDocumentKeyDown = function(event) | |
{ | |
if (event.handled) | |
return; | |
if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) { | |
if (!this._toggleConsoleButton.toggled && WebInspector.drawer.visible) | |
this.closeViewInDrawer(); | |
else | |
this._toggleConsoleButtonClicked(); | |
} | |
} | |
WebInspector.documentCanCopy = function(event) | |
{ | |
if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent) | |
event.preventDefault(); | |
} | |
WebInspector.documentCopy = function(event) | |
{ | |
if (WebInspector.inspectorView.currentPanel() && WebInspector.inspectorView.currentPanel().handleCopyEvent) | |
WebInspector.inspectorView.currentPanel().handleCopyEvent(event); | |
WebInspector.documentCopyEventFired(event); | |
} | |
WebInspector.documentCopyEventFired = function(event) | |
{ | |
} | |
WebInspector.contextMenuEventFired = function(event) | |
{ | |
if (event.handled || event.target.hasStyleClass("popup-glasspane")) | |
event.preventDefault(); | |
} | |
WebInspector.showConsole = function() | |
{ | |
if (WebInspector._toggleConsoleButton && !WebInspector._toggleConsoleButton.toggled) { | |
if (WebInspector.drawer.visible) | |
this._closePreviousDrawerView(); | |
WebInspector._toggleConsoleButtonClicked(); | |
} | |
} | |
WebInspector.showPanel = function(panel) | |
{ | |
return WebInspector.inspectorView.showPanel(panel); | |
} | |
WebInspector.panel = function(panel) | |
{ | |
return WebInspector.inspectorView.panel(panel); | |
} | |
WebInspector.bringToFront = function() | |
{ | |
InspectorFrontendHost.bringToFront(); | |
} | |
WebInspector.log = function(message, messageLevel, showConsole) | |
{ | |
var self = this; | |
function isLogAvailable() | |
{ | |
return WebInspector.ConsoleMessage && WebInspector.RemoteObject && self.console; | |
} | |
function flushQueue() | |
{ | |
var queued = WebInspector.log.queued; | |
if (!queued) | |
return; | |
for (var i = 0; i < queued.length; ++i) | |
logMessage(queued[i]); | |
delete WebInspector.log.queued; | |
} | |
function flushQueueIfAvailable() | |
{ | |
if (!isLogAvailable()) | |
return; | |
clearInterval(WebInspector.log.interval); | |
delete WebInspector.log.interval; | |
flushQueue(); | |
} | |
function logMessage(message) | |
{ | |
var msg = WebInspector.ConsoleMessage.create( | |
WebInspector.ConsoleMessage.MessageSource.Other, | |
messageLevel || WebInspector.ConsoleMessage.MessageLevel.Debug, | |
message); | |
self.console.addMessage(msg); | |
if (showConsole) | |
WebInspector.showConsole(); | |
} | |
if (!isLogAvailable()) { | |
if (!WebInspector.log.queued) | |
WebInspector.log.queued = []; | |
WebInspector.log.queued.push(message); | |
if (!WebInspector.log.interval) | |
WebInspector.log.interval = setInterval(flushQueueIfAvailable, 1000); | |
return; | |
} | |
flushQueue(); | |
logMessage(message); | |
} | |
WebInspector.showErrorMessage = function(error) | |
{ | |
WebInspector.log(error, WebInspector.ConsoleMessage.MessageLevel.Error, true); | |
} | |
WebInspector.inspect = function(payload, hints) | |
{ | |
var object = WebInspector.RemoteObject.fromPayload(payload); | |
if (object.subtype === "node") { | |
function callback(nodeId) | |
{ | |
WebInspector._updateFocusedNode(nodeId); | |
object.release(); | |
} | |
object.pushNodeToFrontend(callback); | |
return; | |
} | |
if (hints.databaseId) | |
WebInspector.showPanel("resources").selectDatabase(WebInspector.databaseModel.databaseForId(hints.databaseId)); | |
else if (hints.domStorageId) | |
WebInspector.showPanel("resources").selectDOMStorage(WebInspector.domStorageModel.storageForId(hints.domStorageId)); | |
object.release(); | |
} | |
WebInspector._updateFocusedNode = function(nodeId) | |
{ | |
if (WebInspector._nodeSearchButton.toggled) { | |
InspectorFrontendHost.bringToFront(); | |
WebInspector._nodeSearchButton.toggled = false; | |
} | |
WebInspector.showPanel("elements").revealAndSelectNode(nodeId); | |
} | |
WebInspector._showAnchorLocation = function(anchor) | |
{ | |
if (WebInspector.openAnchorLocationRegistry.dispatch({ url: anchor.href, lineNumber: anchor.lineNumber})) | |
return true; | |
var preferredPanel = this.panels[anchor.preferredPanel]; | |
if (preferredPanel && WebInspector._showAnchorLocationInPanel(anchor, preferredPanel)) | |
return true; | |
if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("scripts"))) | |
return true; | |
if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("resources"))) | |
return true; | |
if (WebInspector._showAnchorLocationInPanel(anchor, this.panel("network"))) | |
return true; | |
return false; | |
} | |
WebInspector._showAnchorLocationInPanel = function(anchor, panel) | |
{ | |
if (!panel || !panel.canShowAnchorLocation(anchor)) | |
return false; | |
if (anchor.hasStyleClass("webkit-html-external-link")) { | |
anchor.removeStyleClass("webkit-html-external-link"); | |
anchor.addStyleClass("webkit-html-resource-link"); | |
} | |
WebInspector.inspectorView.showPanelForAnchorNavigation(panel); | |
panel.showAnchorLocation(anchor); | |
return true; | |
} | |
WebInspector.showProfileForURL = function(url) | |
{ | |
WebInspector.showPanel("profiles").showProfileForURL(url); | |
} | |
WebInspector.evaluateInConsole = function(expression, showResultOnly) | |
{ | |
this.showConsole(); | |
this.consoleView.evaluateUsingTextPrompt(expression, showResultOnly); | |
} | |
WebInspector.addMainEventListeners = function(doc) | |
{ | |
doc.addEventListener("keydown", this.documentKeyDown.bind(this), true); | |
doc.addEventListener("keydown", this.postDocumentKeyDown.bind(this), false); | |
doc.addEventListener("beforecopy", this.documentCanCopy.bind(this), true); | |
doc.addEventListener("copy", this.documentCopy.bind(this), true); | |
doc.addEventListener("contextmenu", this.contextMenuEventFired.bind(this), true); | |
doc.addEventListener("click", this.documentClick.bind(this), true); | |
} | |
WebInspector.ProfileURLRegExp = /webkit-profile:\/\/(.+)\/(.+)#([0-9]+)/; | |
WebInspector.UIString = function(string, vararg) | |
{ | |
if (Preferences.localizeUI) { | |
if (window.localizedStrings && string in window.localizedStrings) | |
string = window.localizedStrings[string]; | |
else { | |
if (!(string in WebInspector._missingLocalizedStrings)) { | |
console.warn("Localized string \"" + string + "\" not found."); | |
WebInspector._missingLocalizedStrings[string] = true; | |
} | |
if (Preferences.showMissingLocalizedStrings) | |
string += " (not localized)"; | |
} | |
} | |
return String.vsprintf(string, Array.prototype.slice.call(arguments, 1)); | |
} | |
WebInspector._missingLocalizedStrings = {}; | |
WebInspector.installDragHandle = function(element, elementDragStart, elementDrag, elementDragEnd, cursor) | |
{ | |
element.addEventListener("mousedown", WebInspector._elementDragStart.bind(WebInspector, elementDragStart, elementDrag, elementDragEnd, cursor), false); | |
} | |
WebInspector._elementDragStart = function(elementDragStart, elementDrag, elementDragEnd, cursor, event) | |
{ | |
if (event.button || (WebInspector.isMac() && event.ctrlKey)) | |
return; | |
if (WebInspector._elementDraggingEventListener) | |
return; | |
if (elementDragStart && !elementDragStart(event)) | |
return; | |
if (WebInspector._elementDraggingGlassPane) { | |
WebInspector._elementDraggingGlassPane.dispose(); | |
delete WebInspector._elementDraggingGlassPane; | |
} | |
var targetDocument = event.target.ownerDocument; | |
WebInspector._elementDraggingEventListener = elementDrag; | |
WebInspector._elementEndDraggingEventListener = elementDragEnd; | |
WebInspector._mouseOutWhileDraggingTargetDocument = targetDocument; | |
targetDocument.addEventListener("mousemove", WebInspector._elementDraggingEventListener, true); | |
targetDocument.addEventListener("mouseup", WebInspector._elementDragEnd, true); | |
targetDocument.addEventListener("mouseout", WebInspector._mouseOutWhileDragging, true); | |
targetDocument.body.style.cursor = cursor; | |
event.preventDefault(); | |
} | |
WebInspector._mouseOutWhileDragging = function() | |
{ | |
WebInspector._unregisterMouseOutWhileDragging(); | |
WebInspector._elementDraggingGlassPane = new WebInspector.GlassPane(); | |
} | |
WebInspector._unregisterMouseOutWhileDragging = function() | |
{ | |
if (!WebInspector._mouseOutWhileDraggingTargetDocument) | |
return; | |
WebInspector._mouseOutWhileDraggingTargetDocument.removeEventListener("mouseout", WebInspector._mouseOutWhileDragging, true); | |
delete WebInspector._mouseOutWhileDraggingTargetDocument; | |
} | |
WebInspector._elementDragEnd = function(event) | |
{ | |
var targetDocument = event.target.ownerDocument; | |
targetDocument.removeEventListener("mousemove", WebInspector._elementDraggingEventListener, true); | |
targetDocument.removeEventListener("mouseup", WebInspector._elementDragEnd, true); | |
WebInspector._unregisterMouseOutWhileDragging(); | |
targetDocument.body.style.removeProperty("cursor"); | |
if (WebInspector._elementDraggingGlassPane) | |
WebInspector._elementDraggingGlassPane.dispose(); | |
var elementDragEnd = WebInspector._elementEndDraggingEventListener; | |
delete WebInspector._elementDraggingGlassPane; | |
delete WebInspector._elementDraggingEventListener; | |
delete WebInspector._elementEndDraggingEventListener; | |
event.preventDefault(); | |
if (elementDragEnd) | |
elementDragEnd(event); | |
} | |
WebInspector.GlassPane = function() | |
{ | |
this.element = document.createElement("div"); | |
this.element.style.cssText = "position:absolute;top:0;bottom:0;left:0;right:0;background-color:transparent;z-index:1000;"; | |
this.element.id = "glass-pane-for-drag"; | |
document.body.appendChild(this.element); | |
} | |
WebInspector.GlassPane.prototype = { | |
dispose: function() | |
{ | |
if (this.element.parentElement) | |
this.element.parentElement.removeChild(this.element); | |
} | |
} | |
WebInspector.animateStyle = function(animations, duration, callback) | |
{ | |
var interval; | |
var complete = 0; | |
var hasCompleted = false; | |
const intervalDuration = (1000 / 30); | |
const animationsLength = animations.length; | |
const propertyUnit = {opacity: ""}; | |
const defaultUnit = "px"; | |
function cubicInOut(t, b, c, d) | |
{ | |
if ((t/=d/2) < 1) return c/2*t*t*t + b; | |
return c/2*((t-=2)*t*t + 2) + b; | |
} | |
for (var i = 0; i < animationsLength; ++i) { | |
var animation = animations[i]; | |
var element = null, start = null, end = null, key = null; | |
for (key in animation) { | |
if (key === "element") | |
element = animation[key]; | |
else if (key === "start") | |
start = animation[key]; | |
else if (key === "end") | |
end = animation[key]; | |
} | |
if (!element || !end) | |
continue; | |
if (!start) { | |
var computedStyle = element.ownerDocument.defaultView.getComputedStyle(element); | |
start = {}; | |
for (key in end) | |
start[key] = parseInt(computedStyle.getPropertyValue(key), 10); | |
animation.start = start; | |
} else | |
for (key in start) | |
element.style.setProperty(key, start[key] + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); | |
} | |
function animateLoop() | |
{ | |
if (hasCompleted) | |
return; | |
complete += intervalDuration; | |
var next = complete + intervalDuration; | |
for (var i = 0; i < animationsLength; ++i) { | |
var animation = animations[i]; | |
var element = animation.element; | |
var start = animation.start; | |
var end = animation.end; | |
if (!element || !end) | |
continue; | |
var style = element.style; | |
for (key in end) { | |
var endValue = end[key]; | |
if (next < duration) { | |
var startValue = start[key]; | |
var newValue = cubicInOut(complete, startValue, endValue - startValue, duration); | |
style.setProperty(key, newValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); | |
} else | |
style.setProperty(key, endValue + (key in propertyUnit ? propertyUnit[key] : defaultUnit)); | |
} | |
} | |
if (complete >= duration) { | |
hasCompleted = true; | |
clearInterval(interval); | |
if (callback) | |
callback(); | |
} | |
} | |
function forceComplete() | |
{ | |
if (hasCompleted) | |
return; | |
complete = duration; | |
animateLoop(); | |
} | |
function cancel() | |
{ | |
hasCompleted = true; | |
clearInterval(interval); | |
} | |
interval = setInterval(animateLoop, intervalDuration); | |
return { | |
cancel: cancel, | |
forceComplete: forceComplete | |
}; | |
} | |
WebInspector.isBeingEdited = function(element) | |
{ | |
if (element.hasStyleClass("text-prompt") || element.nodeName === "INPUT") | |
return true; | |
if (!WebInspector.__editingCount) | |
return false; | |
while (element) { | |
if (element.__editing) | |
return true; | |
element = element.parentElement; | |
} | |
return false; | |
} | |
WebInspector.markBeingEdited = function(element, value) | |
{ | |
if (value) { | |
if (element.__editing) | |
return false; | |
element.__editing = true; | |
WebInspector.__editingCount = (WebInspector.__editingCount || 0) + 1; | |
} else { | |
if (!element.__editing) | |
return false; | |
delete element.__editing; | |
--WebInspector.__editingCount; | |
} | |
return true; | |
} | |
WebInspector.EditingConfig = function(commitHandler, cancelHandler, context) | |
{ | |
this.commitHandler = commitHandler; | |
this.cancelHandler = cancelHandler | |
this.context = context; | |
this.pasteHandler; | |
this.multiline; | |
this.customFinishHandler; | |
} | |
WebInspector.EditingConfig.prototype = { | |
setPasteHandler: function(pasteHandler) | |
{ | |
this.pasteHandler = pasteHandler; | |
}, | |
setMultiline: function(multiline) | |
{ | |
this.multiline = multiline; | |
}, | |
setCustomFinishHandler: function(customFinishHandler) | |
{ | |
this.customFinishHandler = customFinishHandler; | |
} | |
} | |
WebInspector.CSSNumberRegex = /^(-?(?:\d+(?:\.\d+)?|\.\d+))$/; | |
WebInspector.StyleValueDelimiters = " \xA0\t\n\"':;,/()"; | |
WebInspector._valueModificationDirection = function(event) | |
{ | |
var direction = null; | |
if (event.type === "mousewheel") { | |
if (event.wheelDeltaY > 0) | |
direction = "Up"; | |
else if (event.wheelDeltaY < 0) | |
direction = "Down"; | |
} else { | |
if (event.keyIdentifier === "Up" || event.keyIdentifier === "PageUp") | |
direction = "Up"; | |
else if (event.keyIdentifier === "Down" || event.keyIdentifier === "PageDown") | |
direction = "Down"; | |
} | |
return direction; | |
} | |
WebInspector._modifiedHexValue = function(hexString, event) | |
{ | |
var direction = WebInspector._valueModificationDirection(event); | |
if (!direction) | |
return hexString; | |
var number = parseInt(hexString, 16); | |
if (isNaN(number) || !isFinite(number)) | |
return hexString; | |
var maxValue = Math.pow(16, hexString.length) - 1; | |
var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel"); | |
var delta; | |
if (arrowKeyOrMouseWheelEvent) | |
delta = (direction === "Up") ? 1 : -1; | |
else | |
delta = (event.keyIdentifier === "PageUp") ? 16 : -16; | |
if (event.shiftKey) | |
delta *= 16; | |
var result = number + delta; | |
if (result < 0) | |
result = 0; | |
else if (result > maxValue) | |
return hexString; | |
var resultString = result.toString(16).toUpperCase(); | |
for (var i = 0, lengthDelta = hexString.length - resultString.length; i < lengthDelta; ++i) | |
resultString = "0" + resultString; | |
return resultString; | |
} | |
WebInspector._modifiedFloatNumber = function(number, event) | |
{ | |
var direction = WebInspector._valueModificationDirection(event); | |
if (!direction) | |
return number; | |
var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel"); | |
var changeAmount = 1; | |
if (event.shiftKey && !arrowKeyOrMouseWheelEvent) | |
changeAmount = 100; | |
else if (event.shiftKey || !arrowKeyOrMouseWheelEvent) | |
changeAmount = 10; | |
else if (event.altKey) | |
changeAmount = 0.1; | |
if (direction === "Down") | |
changeAmount *= -1; | |
var result = Number((number + changeAmount).toFixed(6)); | |
if (!String(result).match(WebInspector.CSSNumberRegex)) | |
return null; | |
return result; | |
} | |
WebInspector.handleElementValueModifications = function(event, element, finishHandler, suggestionHandler, customNumberHandler) | |
{ | |
var arrowKeyOrMouseWheelEvent = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down" || event.type === "mousewheel"); | |
var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown"); | |
if (!arrowKeyOrMouseWheelEvent && !pageKeyPressed) | |
return false; | |
var selection = window.getSelection(); | |
if (!selection.rangeCount) | |
return false; | |
var selectionRange = selection.getRangeAt(0); | |
if (!selectionRange.commonAncestorContainer.isSelfOrDescendant(element)) | |
return false; | |
var originalValue = element.textContent; | |
var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StyleValueDelimiters, element); | |
var wordString = wordRange.toString(); | |
if (suggestionHandler && suggestionHandler(wordString)) | |
return false; | |
var replacementString; | |
var prefix, suffix, number; | |
var matches; | |
matches = /(.*#)([\da-fA-F]+)(.*)/.exec(wordString); | |
if (matches && matches.length) { | |
prefix = matches[1]; | |
suffix = matches[3]; | |
number = WebInspector._modifiedHexValue(matches[2], event); | |
if (customNumberHandler) | |
number = customNumberHandler(number); | |
replacementString = prefix + number + suffix; | |
} else { | |
matches = /(.*?)(-?(?:\d+(?:\.\d+)?|\.\d+))(.*)/.exec(wordString); | |
if (matches && matches.length) { | |
prefix = matches[1]; | |
suffix = matches[3]; | |
number = WebInspector._modifiedFloatNumber(parseFloat(matches[2]), event); | |
if (number === null) | |
return false; | |
if (customNumberHandler) | |
number = customNumberHandler(number); | |
replacementString = prefix + number + suffix; | |
} | |
} | |
if (replacementString) { | |
var replacementTextNode = document.createTextNode(replacementString); | |
wordRange.deleteContents(); | |
wordRange.insertNode(replacementTextNode); | |
var finalSelectionRange = document.createRange(); | |
finalSelectionRange.setStart(replacementTextNode, 0); | |
finalSelectionRange.setEnd(replacementTextNode, replacementString.length); | |
selection.removeAllRanges(); | |
selection.addRange(finalSelectionRange); | |
event.handled = true; | |
event.preventDefault(); | |
if (finishHandler) | |
finishHandler(originalValue, replacementString); | |
return true; | |
} | |
return false; | |
} | |
WebInspector.startEditing = function(element, config) | |
{ | |
if (!WebInspector.markBeingEdited(element, true)) | |
return null; | |
config = config || new WebInspector.EditingConfig(function() {}, function() {}); | |
var committedCallback = config.commitHandler; | |
var cancelledCallback = config.cancelHandler; | |
var pasteCallback = config.pasteHandler; | |
var context = config.context; | |
var oldText = getContent(element); | |
var moveDirection = ""; | |
element.addStyleClass("editing"); | |
var oldTabIndex = element.getAttribute("tabIndex"); | |
if (typeof oldTabIndex !== "number" || oldTabIndex < 0) | |
element.tabIndex = 0; | |
function blurEventListener() { | |
editingCommitted.call(element); | |
} | |
function getContent(element) { | |
if (element.tagName === "INPUT" && element.type === "text") | |
return element.value; | |
else | |
return element.textContent; | |
} | |
function cleanUpAfterEditing() | |
{ | |
WebInspector.markBeingEdited(element, false); | |
this.removeStyleClass("editing"); | |
if (typeof oldTabIndex !== "number") | |
element.removeAttribute("tabIndex"); | |
else | |
this.tabIndex = oldTabIndex; | |
this.scrollTop = 0; | |
this.scrollLeft = 0; | |
element.removeEventListener("blur", blurEventListener, false); | |
element.removeEventListener("keydown", keyDownEventListener, true); | |
if (pasteCallback) | |
element.removeEventListener("paste", pasteEventListener, true); | |
WebInspector.restoreFocusFromElement(element); | |
} | |
function editingCancelled() | |
{ | |
if (this.tagName === "INPUT" && this.type === "text") | |
this.value = oldText; | |
else | |
this.textContent = oldText; | |
cleanUpAfterEditing.call(this); | |
cancelledCallback(this, context); | |
} | |
function editingCommitted() | |
{ | |
cleanUpAfterEditing.call(this); | |
committedCallback(this, getContent(this), oldText, context, moveDirection); | |
} | |
function defaultFinishHandler(event) | |
{ | |
var isMetaOrCtrl = WebInspector.isMac() ? | |
event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey : | |
event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; | |
if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl)) | |
return "commit"; | |
else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B") | |
return "cancel"; | |
else if (event.keyIdentifier === "U+0009") | |
return "move-" + (event.shiftKey ? "backward" : "forward"); | |
} | |
function handleEditingResult(result, event) | |
{ | |
if (result === "commit") { | |
editingCommitted.call(element); | |
event.consume(true); | |
} else if (result === "cancel") { | |
editingCancelled.call(element); | |
event.consume(true); | |
} else if (result && result.startsWith("move-")) { | |
moveDirection = result.substring(5); | |
if (event.keyIdentifier !== "U+0009") | |
blurEventListener(); | |
} | |
} | |
function pasteEventListener(event) | |
{ | |
var result = pasteCallback(event); | |
handleEditingResult(result, event); | |
} | |
function keyDownEventListener(event) | |
{ | |
var handler = config.customFinishHandler || defaultFinishHandler; | |
var result = handler(event); | |
handleEditingResult(result, event); | |
} | |
element.addEventListener("blur", blurEventListener, false); | |
element.addEventListener("keydown", keyDownEventListener, true); | |
if (pasteCallback) | |
element.addEventListener("paste", pasteEventListener, true); | |
WebInspector.setCurrentFocusElement(element); | |
return { | |
cancel: editingCancelled.bind(element), | |
commit: editingCommitted.bind(element) | |
}; | |
} | |
Number.secondsToString = function(seconds, higherResolution) | |
{ | |
if (seconds === 0) | |
return "0"; | |
var ms = seconds * 1000; | |
if (higherResolution && ms < 1000) | |
return WebInspector.UIString("%.3fms", ms); | |
else if (ms < 1000) | |
return WebInspector.UIString("%.0fms", ms); | |
if (seconds < 60) | |
return WebInspector.UIString("%.2fs", seconds); | |
var minutes = seconds / 60; | |
if (minutes < 60) | |
return WebInspector.UIString("%.1fmin", minutes); | |
var hours = minutes / 60; | |
if (hours < 24) | |
return WebInspector.UIString("%.1fhrs", hours); | |
var days = hours / 24; | |
return WebInspector.UIString("%.1f days", days); | |
} | |
Number.bytesToString = function(bytes, higherResolution) | |
{ | |
if (typeof higherResolution === "undefined") | |
higherResolution = true; | |
if (bytes < 1024) | |
return WebInspector.UIString("%.0fB", bytes); | |
var kilobytes = bytes / 1024; | |
if (higherResolution && kilobytes < 1024) | |
return WebInspector.UIString("%.2fKB", kilobytes); | |
else if (kilobytes < 1024) | |
return WebInspector.UIString("%.0fKB", kilobytes); | |
var megabytes = kilobytes / 1024; | |
if (higherResolution) | |
return WebInspector.UIString("%.2fMB", megabytes); | |
else | |
return WebInspector.UIString("%.0fMB", megabytes); | |
} | |
Number.withThousandsSeparator = function(num) | |
{ | |
var str = num + ""; | |
var re = /(\d+)(\d{3})/; | |
while (str.match(re)) | |
str = str.replace(re, "$1\u2009$2"); | |
return str; | |
} | |
WebInspector.useLowerCaseMenuTitles = function() | |
{ | |
return WebInspector.platform() === "windows" && Preferences.useLowerCaseMenuTitlesOnWindows; | |
} | |
WebInspector.formatLocalized = function(format, substitutions, formatters, initialValue, append) | |
{ | |
return String.format(WebInspector.UIString(format), substitutions, formatters, initialValue, append); | |
} | |
WebInspector.openLinkExternallyLabel = function() | |
{ | |
return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open link in new tab" : "Open Link in New Tab"); | |
} | |
WebInspector.copyLinkAddressLabel = function() | |
{ | |
return WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy link address" : "Copy Link Address"); | |
} | |
WebInspector.platform = function() | |
{ | |
if (!WebInspector._platform) | |
WebInspector._platform = InspectorFrontendHost.platform(); | |
return WebInspector._platform; | |
} | |
WebInspector.isMac = function() | |
{ | |
if (typeof WebInspector._isMac === "undefined") | |
WebInspector._isMac = WebInspector.platform() === "mac"; | |
return WebInspector._isMac; | |
} | |
WebInspector.isWin = function() | |
{ | |
if (typeof WebInspector._isWin === "undefined") | |
WebInspector._isWin = WebInspector.platform() === "windows"; | |
return WebInspector._isWin; | |
} | |
WebInspector.PlatformFlavor = { | |
WindowsVista: "windows-vista", | |
MacTiger: "mac-tiger", | |
MacLeopard: "mac-leopard", | |
MacSnowLeopard: "mac-snowleopard" | |
} | |
WebInspector.platformFlavor = function() | |
{ | |
function detectFlavor() | |
{ | |
const userAgent = navigator.userAgent; | |
if (WebInspector.platform() === "windows") { | |
var match = userAgent.match(/Windows NT (\d+)\.(?:\d+)/); | |
if (match && match[1] >= 6) | |
return WebInspector.PlatformFlavor.WindowsVista; | |
return null; | |
} else if (WebInspector.platform() === "mac") { | |
var match = userAgent.match(/Mac OS X\s*(?:(\d+)_(\d+))?/); | |
if (!match || match[1] != 10) | |
return WebInspector.PlatformFlavor.MacSnowLeopard; | |
switch (Number(match[2])) { | |
case 4: | |
return WebInspector.PlatformFlavor.MacTiger; | |
case 5: | |
return WebInspector.PlatformFlavor.MacLeopard; | |
case 6: | |
default: | |
return WebInspector.PlatformFlavor.MacSnowLeopard; | |
} | |
} | |
} | |
if (!WebInspector._platformFlavor) | |
WebInspector._platformFlavor = detectFlavor(); | |
return WebInspector._platformFlavor; | |
} | |
WebInspector.port = function() | |
{ | |
if (!WebInspector._port) | |
WebInspector._port = InspectorFrontendHost.port(); | |
return WebInspector._port; | |
} | |
WebInspector.installPortStyles = function() | |
{ | |
var platform = WebInspector.platform(); | |
document.body.addStyleClass("platform-" + platform); | |
var flavor = WebInspector.platformFlavor(); | |
if (flavor) | |
document.body.addStyleClass("platform-" + flavor); | |
var port = WebInspector.port(); | |
document.body.addStyleClass("port-" + port); | |
} | |
WebInspector._windowFocused = function(event) | |
{ | |
if (event.target.document.nodeType === Node.DOCUMENT_NODE) | |
document.body.removeStyleClass("inactive"); | |
} | |
WebInspector._windowBlurred = function(event) | |
{ | |
if (event.target.document.nodeType === Node.DOCUMENT_NODE) | |
document.body.addStyleClass("inactive"); | |
} | |
WebInspector.previousFocusElement = function() | |
{ | |
return WebInspector._previousFocusElement; | |
} | |
WebInspector.currentFocusElement = function() | |
{ | |
return WebInspector._currentFocusElement; | |
} | |
WebInspector._focusChanged = function(event) | |
{ | |
WebInspector.setCurrentFocusElement(event.target); | |
} | |
WebInspector._textInputTypes = ["text", "search", "tel", "url", "email", "password"].keySet(); | |
WebInspector._isTextEditingElement = function(element) | |
{ | |
if (element instanceof HTMLInputElement) | |
return element.type in WebInspector._textInputTypes; | |
if (element instanceof HTMLTextAreaElement) | |
return true; | |
return false; | |
} | |
WebInspector.setCurrentFocusElement = function(x) | |
{ | |
if (WebInspector._currentFocusElement !== x) | |
WebInspector._previousFocusElement = WebInspector._currentFocusElement; | |
WebInspector._currentFocusElement = x; | |
if (WebInspector._currentFocusElement) { | |
WebInspector._currentFocusElement.focus(); | |
var selection = window.getSelection(); | |
if (!WebInspector._isTextEditingElement(WebInspector._currentFocusElement) && selection.isCollapsed && !WebInspector._currentFocusElement.isInsertionCaretInside()) { | |
var selectionRange = WebInspector._currentFocusElement.ownerDocument.createRange(); | |
selectionRange.setStart(WebInspector._currentFocusElement, 0); | |
selectionRange.setEnd(WebInspector._currentFocusElement, 0); | |
selection.removeAllRanges(); | |
selection.addRange(selectionRange); | |
} | |
} else if (WebInspector._previousFocusElement) | |
WebInspector._previousFocusElement.blur(); | |
} | |
WebInspector.restoreFocusFromElement = function(element) | |
{ | |
if (element && element.isSelfOrAncestor(WebInspector.currentFocusElement())) | |
WebInspector.setCurrentFocusElement(WebInspector.previousFocusElement()); | |
} | |
WebInspector.setToolbarColors = function(backgroundColor, color) | |
{ | |
if (!WebInspector._themeStyleElement) { | |
WebInspector._themeStyleElement = document.createElement("style"); | |
document.head.appendChild(WebInspector._themeStyleElement); | |
} | |
WebInspector._themeStyleElement.textContent = | |
"#toolbar {\ | |
background-image: none !important;\ | |
background-color: " + backgroundColor + " !important;\ | |
}\ | |
\ | |
.toolbar-label {\ | |
color: " + color + " !important;\ | |
text-shadow: none;\ | |
}"; | |
} | |
WebInspector.resetToolbarColors = function() | |
{ | |
if (WebInspector._themeStyleElement) | |
WebInspector._themeStyleElement.textContent = ""; | |
} | |
WebInspector.highlightSearchResult = function(element, offset, length, domChanges) | |
{ | |
var result = WebInspector.highlightSearchResults(element, [{offset: offset, length: length }], domChanges); | |
return result.length ? result[0] : null; | |
} | |
WebInspector.highlightSearchResults = function(element, resultRanges, changes) | |
{ | |
return WebInspector.highlightRangesWithStyleClass(element, resultRanges, "webkit-search-result", changes); | |
} | |
WebInspector.highlightRangesWithStyleClass = function(element, resultRanges, styleClass, changes) | |
{ | |
changes = changes || []; | |
var highlightNodes = []; | |
var lineText = element.textContent; | |
var ownerDocument = element.ownerDocument; | |
var textNodeSnapshot = ownerDocument.evaluate(".//text()", element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); | |
var snapshotLength = textNodeSnapshot.snapshotLength; | |
if (snapshotLength === 0) | |
return highlightNodes; | |
var nodeRanges = []; | |
var rangeEndOffset = 0; | |
for (var i = 0; i < snapshotLength; ++i) { | |
var range = {}; | |
range.offset = rangeEndOffset; | |
range.length = textNodeSnapshot.snapshotItem(i).textContent.length; | |
rangeEndOffset = range.offset + range.length; | |
nodeRanges.push(range); | |
} | |
var startIndex = 0; | |
for (var i = 0; i < resultRanges.length; ++i) { | |
var startOffset = resultRanges[i].offset; | |
var endOffset = startOffset + resultRanges[i].length; | |
while (startIndex < snapshotLength && nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= startOffset) | |
startIndex++; | |
var endIndex = startIndex; | |
while (endIndex < snapshotLength && nodeRanges[endIndex].offset + nodeRanges[endIndex].length < endOffset) | |
endIndex++; | |
if (endIndex === snapshotLength) | |
break; | |
var highlightNode = ownerDocument.createElement("span"); | |
highlightNode.className = styleClass; | |
highlightNode.textContent = lineText.substring(startOffset, endOffset); | |
var lastTextNode = textNodeSnapshot.snapshotItem(endIndex); | |
var lastText = lastTextNode.textContent; | |
lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[endIndex].offset); | |
changes.push({ node: lastTextNode, type: "changed", oldText: lastText, newText: lastTextNode.textContent }); | |
if (startIndex === endIndex) { | |
lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode); | |
changes.push({ node: highlightNode, type: "added", nextSibling: lastTextNode, parent: lastTextNode.parentElement }); | |
highlightNodes.push(highlightNode); | |
var prefixNode = ownerDocument.createTextNode(lastText.substring(0, startOffset - nodeRanges[startIndex].offset)); | |
lastTextNode.parentElement.insertBefore(prefixNode, highlightNode); | |
changes.push({ node: prefixNode, type: "added", nextSibling: highlightNode, parent: lastTextNode.parentElement }); | |
} else { | |
var firstTextNode = textNodeSnapshot.snapshotItem(startIndex); | |
var firstText = firstTextNode.textContent; | |
var anchorElement = firstTextNode.nextSibling; | |
firstTextNode.parentElement.insertBefore(highlightNode, anchorElement); | |
changes.push({ node: highlightNode, type: "added", nextSibling: anchorElement, parent: firstTextNode.parentElement }); | |
highlightNodes.push(highlightNode); | |
firstTextNode.textContent = firstText.substring(0, startOffset - nodeRanges[startIndex].offset); | |
changes.push({ node: firstTextNode, type: "changed", oldText: firstText, newText: firstTextNode.textContent }); | |
for (var j = startIndex + 1; j < endIndex; j++) { | |
var textNode = textNodeSnapshot.snapshotItem(j); | |
var text = textNode.textContent; | |
textNode.textContent = ""; | |
changes.push({ node: textNode, type: "changed", oldText: text, newText: textNode.textContent }); | |
} | |
} | |
startIndex = endIndex; | |
nodeRanges[startIndex].offset = endOffset; | |
nodeRanges[startIndex].length = lastTextNode.textContent.length; | |
} | |
return highlightNodes; | |
} | |
WebInspector.applyDomChanges = function(domChanges) | |
{ | |
for (var i = 0, size = domChanges.length; i < size; ++i) { | |
var entry = domChanges[i]; | |
switch (entry.type) { | |
case "added": | |
entry.parent.insertBefore(entry.node, entry.nextSibling); | |
break; | |
case "changed": | |
entry.node.textContent = entry.newText; | |
break; | |
} | |
} | |
} | |
WebInspector.revertDomChanges = function(domChanges) | |
{ | |
for (var i = domChanges.length - 1; i >= 0; --i) { | |
var entry = domChanges[i]; | |
switch (entry.type) { | |
case "added": | |
if (entry.node.parentElement) | |
entry.node.parentElement.removeChild(entry.node); | |
break; | |
case "changed": | |
entry.node.textContent = entry.oldText; | |
break; | |
} | |
} | |
} | |
WebInspector._coalescingLevel = 0; | |
WebInspector.startBatchUpdate = function() | |
{ | |
if (!WebInspector._coalescingLevel) | |
WebInspector._postUpdateHandlers = new Map(); | |
WebInspector._coalescingLevel++; | |
} | |
WebInspector.endBatchUpdate = function() | |
{ | |
if (--WebInspector._coalescingLevel) | |
return; | |
var handlers = WebInspector._postUpdateHandlers; | |
delete WebInspector._postUpdateHandlers; | |
var keys = handlers.keys(); | |
for (var i = 0; i < keys.length; ++i) { | |
var object = keys[i]; | |
var methods = handlers.get(object).keys(); | |
for (var j = 0; j < methods.length; ++j) | |
methods[j].call(object); | |
} | |
} | |
WebInspector.invokeOnceAfterBatchUpdate = function(object, method) | |
{ | |
if (!WebInspector._coalescingLevel) { | |
method.call(object); | |
return; | |
} | |
var methods = WebInspector._postUpdateHandlers.get(object); | |
if (!methods) { | |
methods = new Map(); | |
WebInspector._postUpdateHandlers.put(object, methods); | |
} | |
methods.put(method); | |
} | |
;(function() { | |
function windowLoaded() | |
{ | |
window.addEventListener("focus", WebInspector._windowFocused, false); | |
window.addEventListener("blur", WebInspector._windowBlurred, false); | |
document.addEventListener("focus", WebInspector._focusChanged.bind(this), true); | |
window.removeEventListener("DOMContentLoaded", windowLoaded, false); | |
} | |
window.addEventListener("DOMContentLoaded", windowLoaded, false); | |
})(); | |
function InspectorBackendClass() | |
{ | |
this._lastCallbackId = 1; | |
this._pendingResponsesCount = 0; | |
this._callbacks = {}; | |
this._domainDispatchers = {}; | |
this._eventArgs = {}; | |
this._replyArgs = {}; | |
this.dumpInspectorTimeStats = false; | |
this.dumpInspectorProtocolMessages = false; | |
this._initialized = false; | |
} | |
InspectorBackendClass.prototype = { | |
_wrap: function(callback, method) | |
{ | |
var callbackId = this._lastCallbackId++; | |
if (!callback) | |
callback = function() {}; | |
this._callbacks[callbackId] = callback; | |
callback.methodName = method; | |
if (this.dumpInspectorTimeStats) | |
callback.sendRequestTime = Date.now(); | |
return callbackId; | |
}, | |
registerCommand: function(method, signature, replyArgs) | |
{ | |
var domainAndMethod = method.split("."); | |
var agentName = domainAndMethod[0] + "Agent"; | |
if (!window[agentName]) | |
window[agentName] = {}; | |
window[agentName][domainAndMethod[1]] = this._sendMessageToBackend.bind(this, method, signature); | |
window[agentName][domainAndMethod[1]]["invoke"] = this._invoke.bind(this, method, signature); | |
this._replyArgs[method] = replyArgs; | |
this._initialized = true; | |
}, | |
registerEvent: function(eventName, params) | |
{ | |
this._eventArgs[eventName] = params; | |
this._initialized = true; | |
}, | |
_invoke: function(method, signature, args, callback) | |
{ | |
this._wrapCallbackAndSendMessageObject(method, args, callback); | |
}, | |
_sendMessageToBackend: function(method, signature, vararg) | |
{ | |
var args = Array.prototype.slice.call(arguments, 2); | |
var callback = (args.length && typeof args[args.length - 1] === "function") ? args.pop() : null; | |
var params = {}; | |
var hasParams = false; | |
for (var i = 0; i < signature.length; ++i) { | |
var param = signature[i]; | |
var paramName = param["name"]; | |
var typeName = param["type"]; | |
var optionalFlag = param["optional"]; | |
if (!args.length && !optionalFlag) { | |
console.error("Protocol Error: Invalid number of arguments for method '" + method + "' call. It must have the following arguments '" + JSON.stringify(signature) + "'."); | |
return; | |
} | |
var value = args.shift(); | |
if (optionalFlag && typeof value === "undefined") { | |
continue; | |
} | |
if (typeof value !== typeName) { | |
console.error("Protocol Error: Invalid type of argument '" + paramName + "' for method '" + method + "' call. It must be '" + typeName + "' but it is '" + typeof value + "'."); | |
return; | |
} | |
params[paramName] = value; | |
hasParams = true; | |
} | |
if (args.length === 1 && !callback) { | |
if (typeof args[0] !== "undefined") { | |
console.error("Protocol Error: Optional callback argument for method '" + method + "' call must be a function but its type is '" + typeof args[0] + "'."); | |
return; | |
} | |
} | |
this._wrapCallbackAndSendMessageObject(method, hasParams ? params : null, callback); | |
}, | |
_wrapCallbackAndSendMessageObject: function(method, params, callback) | |
{ | |
var messageObject = {}; | |
messageObject.method = method; | |
if (params) | |
messageObject.params = params; | |
messageObject.id = this._wrap(callback, method); | |
if (this.dumpInspectorProtocolMessages) | |
console.log("frontend: " + JSON.stringify(messageObject)); | |
++this._pendingResponsesCount; | |
this.sendMessageObjectToBackend(messageObject); | |
}, | |
sendMessageObjectToBackend: function(messageObject) | |
{ | |
var message = JSON.stringify(messageObject); | |
InspectorFrontendHost.sendMessageToBackend(message); | |
}, | |
registerDomainDispatcher: function(domain, dispatcher) | |
{ | |
this._domainDispatchers[domain] = dispatcher; | |
}, | |
dispatch: function(message) | |
{ | |
if (this.dumpInspectorProtocolMessages) | |
console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message))); | |
var messageObject = (typeof message === "string") ? JSON.parse(message) : message; | |
if ("id" in messageObject) { | |
if (messageObject.error) { | |
if (messageObject.error.code !== -32000) | |
this.reportProtocolError(messageObject); | |
} | |
var callback = this._callbacks[messageObject.id]; | |
if (callback) { | |
var argumentsArray = []; | |
if (messageObject.result) { | |
var paramNames = this._replyArgs[callback.methodName]; | |
if (paramNames) { | |
for (var i = 0; i < paramNames.length; ++i) | |
argumentsArray.push(messageObject.result[paramNames[i]]); | |
} | |
} | |
var processingStartTime; | |
if (this.dumpInspectorTimeStats && callback.methodName) | |
processingStartTime = Date.now(); | |
argumentsArray.unshift(messageObject.error ? messageObject.error.message : null); | |
callback.apply(null, argumentsArray); | |
--this._pendingResponsesCount; | |
delete this._callbacks[messageObject.id]; | |
if (this.dumpInspectorTimeStats && callback.methodName) | |
console.log("time-stats: " + callback.methodName + " = " + (processingStartTime - callback.sendRequestTime) + " + " + (Date.now() - processingStartTime)); | |
} | |
if (this._scripts && !this._pendingResponsesCount) | |
this.runAfterPendingDispatches(); | |
return; | |
} else { | |
var method = messageObject.method.split("."); | |
var domainName = method[0]; | |
var functionName = method[1]; | |
if (!(domainName in this._domainDispatchers)) { | |
console.error("Protocol Error: the message is for non-existing domain '" + domainName + "'"); | |
return; | |
} | |
var dispatcher = this._domainDispatchers[domainName]; | |
if (!(functionName in dispatcher)) { | |
console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.method + "'"); | |
return; | |
} | |
if (!this._eventArgs[messageObject.method]) { | |
console.error("Protocol Error: Attempted to dispatch an unspecified method '" + messageObject.method + "'"); | |
return; | |
} | |
var params = []; | |
if (messageObject.params) { | |
var paramNames = this._eventArgs[messageObject.method]; | |
for (var i = 0; i < paramNames.length; ++i) | |
params.push(messageObject.params[paramNames[i]]); | |
} | |
var processingStartTime; | |
if (this.dumpInspectorTimeStats) | |
processingStartTime = Date.now(); | |
dispatcher[functionName].apply(dispatcher, params); | |
if (this.dumpInspectorTimeStats) | |
console.log("time-stats: " + messageObject.method + " = " + (Date.now() - processingStartTime)); | |
} | |
}, | |
reportProtocolError: function(messageObject) | |
{ | |
console.error("Request with id = " + messageObject.id + " failed. " + messageObject.error); | |
}, | |
runAfterPendingDispatches: function(script) | |
{ | |
if (!this._scripts) | |
this._scripts = []; | |
if (script) | |
this._scripts.push(script); | |
if (!this._pendingResponsesCount) { | |
var scripts = this._scripts; | |
this._scripts = [] | |
for (var id = 0; id < scripts.length; ++id) | |
scripts[id].call(this); | |
} | |
}, | |
loadFromJSONIfNeeded: function(jsonUrl) | |
{ | |
if (this._initialized) | |
return; | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", jsonUrl, false); | |
xhr.send(null); | |
var schema = JSON.parse(xhr.responseText); | |
var jsTypes = { integer: "number", array: "object" }; | |
var rawTypes = {}; | |
var domains = schema["domains"]; | |
for (var i = 0; i < domains.length; ++i) { | |
var domain = domains[i]; | |
for (var j = 0; domain.types && j < domain.types.length; ++j) { | |
var type = domain.types[j]; | |
rawTypes[domain.domain + "." + type.id] = jsTypes[type.type] || type.type; | |
} | |
} | |
var result = []; | |
for (var i = 0; i < domains.length; ++i) { | |
var domain = domains[i]; | |
var commands = domain["commands"] || []; | |
for (var j = 0; j < commands.length; ++j) { | |
var command = commands[j]; | |
var parameters = command["parameters"]; | |
var paramsText = []; | |
for (var k = 0; parameters && k < parameters.length; ++k) { | |
var parameter = parameters[k]; | |
var type; | |
if (parameter.type) | |
type = jsTypes[parameter.type] || parameter.type; | |
else { | |
var ref = parameter["$ref"]; | |
if (ref.indexOf(".") !== -1) | |
type = rawTypes[ref]; | |
else | |
type = rawTypes[domain.domain + "." + ref]; | |
} | |
var text = "{\"name\": \"" + parameter.name + "\", \"type\": \"" + type + "\", \"optional\": " + (parameter.optional ? "true" : "false") + "}"; | |
paramsText.push(text); | |
} | |
var returnsText = []; | |
var returns = command["returns"] || []; | |
for (var k = 0; k < returns.length; ++k) { | |
var parameter = returns[k]; | |
returnsText.push("\"" + parameter.name + "\""); | |
} | |
result.push("InspectorBackend.registerCommand(\"" + domain.domain + "." + command.name + "\", [" + paramsText.join(", ") + "], [" + returnsText.join(", ") + "]);"); | |
} | |
for (var j = 0; domain.events && j < domain.events.length; ++j) { | |
var event = domain.events[j]; | |
var paramsText = []; | |
for (var k = 0; event.parameters && k < event.parameters.length; ++k) { | |
var parameter = event.parameters[k]; | |
paramsText.push("\"" + parameter.name + "\""); | |
} | |
result.push("InspectorBackend.registerEvent(\"" + domain.domain + "." + event.name + "\", [" + paramsText.join(", ") + "]);"); | |
} | |
result.push("InspectorBackend.register" + domain.domain + "Dispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, \"" + domain.domain + "\");"); | |
} | |
eval(result.join("\n")); | |
} | |
} | |
InspectorBackend = new InspectorBackendClass(); | |
InspectorBackend.registerInspectorDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Inspector"); | |
InspectorBackend.registerEvent("Inspector.evaluateForTestInFrontend", ["testCallId", "script"]); | |
InspectorBackend.registerEvent("Inspector.inspect", ["object", "hints"]); | |
InspectorBackend.registerCommand("Inspector.enable", [], []); | |
InspectorBackend.registerCommand("Inspector.disable", [], []); | |
InspectorBackend.registerMemoryDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Memory"); | |
InspectorBackend.registerCommand("Memory.getDOMNodeCount", [], ["domGroups", "strings"]); | |
InspectorBackend.registerCommand("Memory.getProcessMemoryDistribution", [], ["distribution"]); | |
InspectorBackend.registerPageDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Page"); | |
InspectorBackend.registerEvent("Page.domContentEventFired", ["timestamp"]); | |
InspectorBackend.registerEvent("Page.loadEventFired", ["timestamp"]); | |
InspectorBackend.registerEvent("Page.frameNavigated", ["frame"]); | |
InspectorBackend.registerEvent("Page.frameDetached", ["frameId"]); | |
InspectorBackend.registerCommand("Page.enable", [], []); | |
InspectorBackend.registerCommand("Page.disable", [], []); | |
InspectorBackend.registerCommand("Page.addScriptToEvaluateOnLoad", [{"name": "scriptSource", "type": "string", "optional": false}], ["identifier"]); | |
InspectorBackend.registerCommand("Page.removeScriptToEvaluateOnLoad", [{"name": "identifier", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.reload", [{"name": "ignoreCache", "type": "boolean", "optional": true}, {"name": "scriptToEvaluateOnLoad", "type": "string", "optional": true}], []); | |
InspectorBackend.registerCommand("Page.navigate", [{"name": "url", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.getCookies", [], ["cookies", "cookiesString"]); | |
InspectorBackend.registerCommand("Page.deleteCookie", [{"name": "cookieName", "type": "string", "optional": false}, {"name": "domain", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.getResourceTree", [], ["frameTree"]); | |
InspectorBackend.registerCommand("Page.getResourceContent", [{"name": "frameId", "type": "string", "optional": false}, {"name": "url", "type": "string", "optional": false}], ["content", "base64Encoded"]); | |
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"]); | |
InspectorBackend.registerCommand("Page.searchInResources", [{"name": "text", "type": "string", "optional": false}, {"name": "caseSensitive", "type": "boolean", "optional": true}, {"name": "isRegex", "type": "boolean", "optional": true}], ["result"]); | |
InspectorBackend.registerCommand("Page.setDocumentContent", [{"name": "frameId", "type": "string", "optional": false}, {"name": "html", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.canOverrideDeviceMetrics", [], ["result"]); | |
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}], []); | |
InspectorBackend.registerCommand("Page.setShowPaintRects", [{"name": "result", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.getScriptExecutionStatus", [], ["result"]); | |
InspectorBackend.registerCommand("Page.setScriptExecutionDisabled", [{"name": "value", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.setGeolocationOverride", [{"name": "latitude", "type": "number", "optional": true}, {"name": "longitude", "type": "number", "optional": true}, {"name": "accuracy", "type": "number", "optional": true}], []); | |
InspectorBackend.registerCommand("Page.clearGeolocationOverride", [], []); | |
InspectorBackend.registerCommand("Page.canOverrideGeolocation", [], ["result"]); | |
InspectorBackend.registerCommand("Page.setDeviceOrientationOverride", [{"name": "alpha", "type": "number", "optional": false}, {"name": "beta", "type": "number", "optional": false}, {"name": "gamma", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("Page.clearDeviceOrientationOverride", [], []); | |
InspectorBackend.registerCommand("Page.canOverrideDeviceOrientation", [], ["result"]); | |
InspectorBackend.registerCommand("Page.setTouchEmulationEnabled", [{"name": "enabled", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerRuntimeDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Runtime"); | |
InspectorBackend.registerEvent("Runtime.executionContextCreated", ["context"]); | |
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"]); | |
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"]); | |
InspectorBackend.registerCommand("Runtime.getProperties", [{"name": "objectId", "type": "string", "optional": false}, {"name": "ownProperties", "type": "boolean", "optional": true}], ["result"]); | |
InspectorBackend.registerCommand("Runtime.releaseObject", [{"name": "objectId", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Runtime.releaseObjectGroup", [{"name": "objectGroup", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Runtime.run", [], []); | |
InspectorBackend.registerCommand("Runtime.setReportExecutionContextCreation", [{"name": "enabled", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerConsoleDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Console"); | |
InspectorBackend.registerEvent("Console.messageAdded", ["message"]); | |
InspectorBackend.registerEvent("Console.messageRepeatCountUpdated", ["count"]); | |
InspectorBackend.registerEvent("Console.messagesCleared", []); | |
InspectorBackend.registerCommand("Console.enable", [], []); | |
InspectorBackend.registerCommand("Console.disable", [], []); | |
InspectorBackend.registerCommand("Console.clearMessages", [], []); | |
InspectorBackend.registerCommand("Console.setMonitoringXHREnabled", [{"name": "enabled", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerCommand("Console.addInspectedNode", [{"name": "nodeId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("Console.addInspectedHeapObject", [{"name": "heapObjectId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerNetworkDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Network"); | |
InspectorBackend.registerEvent("Network.requestWillBeSent", ["requestId", "frameId", "loaderId", "documentURL", "request", "timestamp", "initiator", "redirectResponse"]); | |
InspectorBackend.registerEvent("Network.requestServedFromCache", ["requestId"]); | |
InspectorBackend.registerEvent("Network.responseReceived", ["requestId", "frameId", "loaderId", "timestamp", "type", "response"]); | |
InspectorBackend.registerEvent("Network.dataReceived", ["requestId", "timestamp", "dataLength", "encodedDataLength"]); | |
InspectorBackend.registerEvent("Network.loadingFinished", ["requestId", "timestamp"]); | |
InspectorBackend.registerEvent("Network.loadingFailed", ["requestId", "timestamp", "errorText", "canceled"]); | |
InspectorBackend.registerEvent("Network.requestServedFromMemoryCache", ["requestId", "frameId", "loaderId", "documentURL", "timestamp", "initiator", "resource"]); | |
InspectorBackend.registerEvent("Network.webSocketWillSendHandshakeRequest", ["requestId", "timestamp", "request"]); | |
InspectorBackend.registerEvent("Network.webSocketHandshakeResponseReceived", ["requestId", "timestamp", "response"]); | |
InspectorBackend.registerEvent("Network.webSocketCreated", ["requestId", "url"]); | |
InspectorBackend.registerEvent("Network.webSocketClosed", ["requestId", "timestamp"]); | |
InspectorBackend.registerEvent("Network.webSocketFrameReceived", ["requestId", "timestamp", "response"]); | |
InspectorBackend.registerEvent("Network.webSocketFrameError", ["requestId", "timestamp", "errorMessage"]); | |
InspectorBackend.registerEvent("Network.webSocketFrameSent", ["requestId", "timestamp", "response"]); | |
InspectorBackend.registerCommand("Network.enable", [], []); | |
InspectorBackend.registerCommand("Network.disable", [], []); | |
InspectorBackend.registerCommand("Network.setUserAgentOverride", [{"name": "userAgent", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Network.setExtraHTTPHeaders", [{"name": "headers", "type": "object", "optional": false}], []); | |
InspectorBackend.registerCommand("Network.getResponseBody", [{"name": "requestId", "type": "string", "optional": false}], ["body", "base64Encoded"]); | |
InspectorBackend.registerCommand("Network.replayXHR", [{"name": "requestId", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Network.canClearBrowserCache", [], ["result"]); | |
InspectorBackend.registerCommand("Network.clearBrowserCache", [], []); | |
InspectorBackend.registerCommand("Network.canClearBrowserCookies", [], ["result"]); | |
InspectorBackend.registerCommand("Network.clearBrowserCookies", [], []); | |
InspectorBackend.registerCommand("Network.setCacheDisabled", [{"name": "cacheDisabled", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerDatabaseDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Database"); | |
InspectorBackend.registerEvent("Database.addDatabase", ["database"]); | |
InspectorBackend.registerCommand("Database.enable", [], []); | |
InspectorBackend.registerCommand("Database.disable", [], []); | |
InspectorBackend.registerCommand("Database.getDatabaseTableNames", [{"name": "databaseId", "type": "string", "optional": false}], ["tableNames"]); | |
InspectorBackend.registerCommand("Database.executeSQL", [{"name": "databaseId", "type": "string", "optional": false}, {"name": "query", "type": "string", "optional": false}], ["columnNames", "values", "sqlError"]); | |
InspectorBackend.registerIndexedDBDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "IndexedDB"); | |
InspectorBackend.registerCommand("IndexedDB.enable", [], []); | |
InspectorBackend.registerCommand("IndexedDB.disable", [], []); | |
InspectorBackend.registerCommand("IndexedDB.requestDatabaseNamesForFrame", [{"name": "frameId", "type": "string", "optional": false}], ["securityOriginWithDatabaseNames"]); | |
InspectorBackend.registerCommand("IndexedDB.requestDatabase", [{"name": "frameId", "type": "string", "optional": false}, {"name": "databaseName", "type": "string", "optional": false}], ["databaseWithObjectStores"]); | |
InspectorBackend.registerCommand("IndexedDB.requestData", [{"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}], ["objectStoreDataEntries", "hasMore"]); | |
InspectorBackend.registerDOMStorageDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "DOMStorage"); | |
InspectorBackend.registerEvent("DOMStorage.addDOMStorage", ["storage"]); | |
InspectorBackend.registerEvent("DOMStorage.domStorageUpdated", ["storageId"]); | |
InspectorBackend.registerCommand("DOMStorage.enable", [], []); | |
InspectorBackend.registerCommand("DOMStorage.disable", [], []); | |
InspectorBackend.registerCommand("DOMStorage.getDOMStorageEntries", [{"name": "storageId", "type": "string", "optional": false}], ["entries"]); | |
InspectorBackend.registerCommand("DOMStorage.setDOMStorageItem", [{"name": "storageId", "type": "string", "optional": false}, {"name": "key", "type": "string", "optional": false}, {"name": "value", "type": "string", "optional": false}], ["success"]); | |
InspectorBackend.registerCommand("DOMStorage.removeDOMStorageItem", [{"name": "storageId", "type": "string", "optional": false}, {"name": "key", "type": "string", "optional": false}], ["success"]); | |
InspectorBackend.registerApplicationCacheDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "ApplicationCache"); | |
InspectorBackend.registerEvent("ApplicationCache.applicationCacheStatusUpdated", ["frameId", "manifestURL", "status"]); | |
InspectorBackend.registerEvent("ApplicationCache.networkStateUpdated", ["isNowOnline"]); | |
InspectorBackend.registerCommand("ApplicationCache.getFramesWithManifests", [], ["frameIds"]); | |
InspectorBackend.registerCommand("ApplicationCache.enable", [], []); | |
InspectorBackend.registerCommand("ApplicationCache.getManifestForFrame", [{"name": "frameId", "type": "string", "optional": false}], ["manifestURL"]); | |
InspectorBackend.registerCommand("ApplicationCache.getApplicationCacheForFrame", [{"name": "frameId", "type": "string", "optional": false}], ["applicationCache"]); | |
InspectorBackend.registerFileSystemDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "FileSystem"); | |
InspectorBackend.registerCommand("FileSystem.enable", [], []); | |
InspectorBackend.registerCommand("FileSystem.disable", [], []); | |
InspectorBackend.registerCommand("FileSystem.requestFileSystemRoot", [{"name": "origin", "type": "string", "optional": false}, {"name": "type", "type": "string", "optional": false}], ["errorCode", "root"]); | |
InspectorBackend.registerCommand("FileSystem.requestDirectoryContent", [{"name": "url", "type": "string", "optional": false}], ["errorCode", "entries"]); | |
InspectorBackend.registerCommand("FileSystem.requestMetadata", [{"name": "url", "type": "string", "optional": false}], ["errorCode", "metadata"]); | |
InspectorBackend.registerCommand("FileSystem.requestFileContent", [{"name": "url", "type": "string", "optional": false}, {"name": "readAsText", "type": "boolean", "optional": false}, {"name": "start", "type": "number", "optional": true}, {"name": "end", "type": "number", "optional": true}, {"name": "charset", "type": "string", "optional": true}], ["errorCode", "content", "charset"]); | |
InspectorBackend.registerCommand("FileSystem.deleteEntry", [{"name": "url", "type": "string", "optional": false}], ["errorCode"]); | |
InspectorBackend.registerDOMDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "DOM"); | |
InspectorBackend.registerEvent("DOM.documentUpdated", []); | |
InspectorBackend.registerEvent("DOM.setChildNodes", ["parentId", "nodes"]); | |
InspectorBackend.registerEvent("DOM.attributeModified", ["nodeId", "name", "value"]); | |
InspectorBackend.registerEvent("DOM.attributeRemoved", ["nodeId", "name"]); | |
InspectorBackend.registerEvent("DOM.inlineStyleInvalidated", ["nodeIds"]); | |
InspectorBackend.registerEvent("DOM.characterDataModified", ["nodeId", "characterData"]); | |
InspectorBackend.registerEvent("DOM.childNodeCountUpdated", ["nodeId", "childNodeCount"]); | |
InspectorBackend.registerEvent("DOM.childNodeInserted", ["parentNodeId", "previousNodeId", "node"]); | |
InspectorBackend.registerEvent("DOM.childNodeRemoved", ["parentNodeId", "nodeId"]); | |
InspectorBackend.registerEvent("DOM.shadowRootPushed", ["hostId", "root"]); | |
InspectorBackend.registerEvent("DOM.shadowRootPopped", ["hostId", "rootId"]); | |
InspectorBackend.registerCommand("DOM.getDocument", [], ["root"]); | |
InspectorBackend.registerCommand("DOM.requestChildNodes", [{"name": "nodeId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.querySelector", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["nodeId"]); | |
InspectorBackend.registerCommand("DOM.querySelectorAll", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["nodeIds"]); | |
InspectorBackend.registerCommand("DOM.setNodeName", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}], ["nodeId"]); | |
InspectorBackend.registerCommand("DOM.setNodeValue", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "value", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.removeNode", [{"name": "nodeId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.setAttributeValue", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}, {"name": "value", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.setAttributesAsText", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "text", "type": "string", "optional": false}, {"name": "name", "type": "string", "optional": true}], []); | |
InspectorBackend.registerCommand("DOM.removeAttribute", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "name", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.getEventListenersForNode", [{"name": "nodeId", "type": "number", "optional": false}], ["listeners"]); | |
InspectorBackend.registerCommand("DOM.getOuterHTML", [{"name": "nodeId", "type": "number", "optional": false}], ["outerHTML"]); | |
InspectorBackend.registerCommand("DOM.setOuterHTML", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "outerHTML", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.performSearch", [{"name": "query", "type": "string", "optional": false}], ["searchId", "resultCount"]); | |
InspectorBackend.registerCommand("DOM.getSearchResults", [{"name": "searchId", "type": "string", "optional": false}, {"name": "fromIndex", "type": "number", "optional": false}, {"name": "toIndex", "type": "number", "optional": false}], ["nodeIds"]); | |
InspectorBackend.registerCommand("DOM.discardSearchResults", [{"name": "searchId", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.requestNode", [{"name": "objectId", "type": "string", "optional": false}], ["nodeId"]); | |
InspectorBackend.registerCommand("DOM.setInspectModeEnabled", [{"name": "enabled", "type": "boolean", "optional": false}, {"name": "highlightConfig", "type": "object", "optional": true}], []); | |
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}], []); | |
InspectorBackend.registerCommand("DOM.highlightNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "highlightConfig", "type": "object", "optional": false}], []); | |
InspectorBackend.registerCommand("DOM.hideHighlight", [], []); | |
InspectorBackend.registerCommand("DOM.highlightFrame", [{"name": "frameId", "type": "string", "optional": false}, {"name": "contentColor", "type": "object", "optional": true}, {"name": "contentOutlineColor", "type": "object", "optional": true}], []); | |
InspectorBackend.registerCommand("DOM.pushNodeByPathToFrontend", [{"name": "path", "type": "string", "optional": false}], ["nodeId"]); | |
InspectorBackend.registerCommand("DOM.resolveNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}], ["object"]); | |
InspectorBackend.registerCommand("DOM.getAttributes", [{"name": "nodeId", "type": "number", "optional": false}], ["attributes"]); | |
InspectorBackend.registerCommand("DOM.moveTo", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "targetNodeId", "type": "number", "optional": false}, {"name": "insertBeforeNodeId", "type": "number", "optional": true}], ["nodeId"]); | |
InspectorBackend.registerCommand("DOM.undo", [], []); | |
InspectorBackend.registerCommand("DOM.redo", [], []); | |
InspectorBackend.registerCommand("DOM.markUndoableState", [], []); | |
InspectorBackend.registerCSSDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "CSS"); | |
InspectorBackend.registerEvent("CSS.mediaQueryResultChanged", []); | |
InspectorBackend.registerEvent("CSS.styleSheetChanged", ["styleSheetId"]); | |
InspectorBackend.registerEvent("CSS.namedFlowCreated", ["namedFlow"]); | |
InspectorBackend.registerEvent("CSS.namedFlowRemoved", ["documentNodeId", "flowName"]); | |
InspectorBackend.registerEvent("CSS.regionLayoutUpdated", ["namedFlow"]); | |
InspectorBackend.registerCommand("CSS.enable", [], []); | |
InspectorBackend.registerCommand("CSS.disable", [], []); | |
InspectorBackend.registerCommand("CSS.getMatchedStylesForNode", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "includePseudo", "type": "boolean", "optional": true}, {"name": "includeInherited", "type": "boolean", "optional": true}], ["matchedCSSRules", "pseudoElements", "inherited"]); | |
InspectorBackend.registerCommand("CSS.getInlineStylesForNode", [{"name": "nodeId", "type": "number", "optional": false}], ["inlineStyle", "attributesStyle"]); | |
InspectorBackend.registerCommand("CSS.getComputedStyleForNode", [{"name": "nodeId", "type": "number", "optional": false}], ["computedStyle"]); | |
InspectorBackend.registerCommand("CSS.getAllStyleSheets", [], ["headers"]); | |
InspectorBackend.registerCommand("CSS.getStyleSheet", [{"name": "styleSheetId", "type": "string", "optional": false}], ["styleSheet"]); | |
InspectorBackend.registerCommand("CSS.getStyleSheetText", [{"name": "styleSheetId", "type": "string", "optional": false}], ["text"]); | |
InspectorBackend.registerCommand("CSS.setStyleSheetText", [{"name": "styleSheetId", "type": "string", "optional": false}, {"name": "text", "type": "string", "optional": false}], []); | |
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"]); | |
InspectorBackend.registerCommand("CSS.toggleProperty", [{"name": "styleId", "type": "object", "optional": false}, {"name": "propertyIndex", "type": "number", "optional": false}, {"name": "disable", "type": "boolean", "optional": false}], ["style"]); | |
InspectorBackend.registerCommand("CSS.setRuleSelector", [{"name": "ruleId", "type": "object", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["rule"]); | |
InspectorBackend.registerCommand("CSS.addRule", [{"name": "contextNodeId", "type": "number", "optional": false}, {"name": "selector", "type": "string", "optional": false}], ["rule"]); | |
InspectorBackend.registerCommand("CSS.getSupportedCSSProperties", [], ["cssProperties"]); | |
InspectorBackend.registerCommand("CSS.forcePseudoState", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "forcedPseudoClasses", "type": "object", "optional": false}], []); | |
InspectorBackend.registerCommand("CSS.startSelectorProfiler", [], []); | |
InspectorBackend.registerCommand("CSS.stopSelectorProfiler", [], ["profile"]); | |
InspectorBackend.registerCommand("CSS.getNamedFlowCollection", [{"name": "documentNodeId", "type": "number", "optional": false}], ["namedFlows"]); | |
InspectorBackend.registerTimelineDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Timeline"); | |
InspectorBackend.registerEvent("Timeline.eventRecorded", ["record"]); | |
InspectorBackend.registerCommand("Timeline.start", [{"name": "maxCallStackDepth", "type": "number", "optional": true}], []); | |
InspectorBackend.registerCommand("Timeline.stop", [], []); | |
InspectorBackend.registerCommand("Timeline.setIncludeMemoryDetails", [{"name": "enabled", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerCommand("Timeline.supportsFrameInstrumentation", [], ["result"]); | |
InspectorBackend.registerDebuggerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Debugger"); | |
InspectorBackend.registerEvent("Debugger.globalObjectCleared", []); | |
InspectorBackend.registerEvent("Debugger.scriptParsed", ["scriptId", "url", "startLine", "startColumn", "endLine", "endColumn", "isContentScript", "sourceMapURL"]); | |
InspectorBackend.registerEvent("Debugger.scriptFailedToParse", ["url", "scriptSource", "startLine", "errorLine", "errorMessage"]); | |
InspectorBackend.registerEvent("Debugger.breakpointResolved", ["breakpointId", "location"]); | |
InspectorBackend.registerEvent("Debugger.paused", ["callFrames", "reason", "data"]); | |
InspectorBackend.registerEvent("Debugger.resumed", []); | |
InspectorBackend.registerCommand("Debugger.causesRecompilation", [], ["result"]); | |
InspectorBackend.registerCommand("Debugger.supportsSeparateScriptCompilationAndExecution", [], ["result"]); | |
InspectorBackend.registerCommand("Debugger.enable", [], []); | |
InspectorBackend.registerCommand("Debugger.disable", [], []); | |
InspectorBackend.registerCommand("Debugger.setBreakpointsActive", [{"name": "active", "type": "boolean", "optional": false}], []); | |
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"]); | |
InspectorBackend.registerCommand("Debugger.setBreakpoint", [{"name": "location", "type": "object", "optional": false}, {"name": "condition", "type": "string", "optional": true}], ["breakpointId", "actualLocation"]); | |
InspectorBackend.registerCommand("Debugger.removeBreakpoint", [{"name": "breakpointId", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("Debugger.continueToLocation", [{"name": "location", "type": "object", "optional": false}], []); | |
InspectorBackend.registerCommand("Debugger.stepOver", [], []); | |
InspectorBackend.registerCommand("Debugger.stepInto", [], []); | |
InspectorBackend.registerCommand("Debugger.stepOut", [], []); | |
InspectorBackend.registerCommand("Debugger.pause", [], []); | |
InspectorBackend.registerCommand("Debugger.resume", [], []); | |
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"]); | |
InspectorBackend.registerCommand("Debugger.canSetScriptSource", [], ["result"]); | |
InspectorBackend.registerCommand("Debugger.setScriptSource", [{"name": "scriptId", "type": "string", "optional": false}, {"name": "scriptSource", "type": "string", "optional": false}, {"name": "preview", "type": "boolean", "optional": true}], ["callFrames", "result"]); | |
InspectorBackend.registerCommand("Debugger.restartFrame", [{"name": "callFrameId", "type": "string", "optional": false}], ["callFrames", "result"]); | |
InspectorBackend.registerCommand("Debugger.getScriptSource", [{"name": "scriptId", "type": "string", "optional": false}], ["scriptSource"]); | |
InspectorBackend.registerCommand("Debugger.getFunctionDetails", [{"name": "functionId", "type": "string", "optional": false}], ["details"]); | |
InspectorBackend.registerCommand("Debugger.setPauseOnExceptions", [{"name": "state", "type": "string", "optional": false}], []); | |
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"]); | |
InspectorBackend.registerCommand("Debugger.compileScript", [{"name": "expression", "type": "string", "optional": false}, {"name": "sourceURL", "type": "string", "optional": false}], ["scriptId", "syntaxErrorMessage"]); | |
InspectorBackend.registerCommand("Debugger.runScript", [{"name": "scriptId", "type": "string", "optional": false}, {"name": "contextId", "type": "number", "optional": true}, {"name": "objectGroup", "type": "string", "optional": true}, {"name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true}], ["result", "wasThrown"]); | |
InspectorBackend.registerCommand("Debugger.setOverlayMessage", [{"name": "message", "type": "string", "optional": true}], []); | |
InspectorBackend.registerCommand("DOMDebugger.setDOMBreakpoint", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "type", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.removeDOMBreakpoint", [{"name": "nodeId", "type": "number", "optional": false}, {"name": "type", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.setEventListenerBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.removeEventListenerBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.setInstrumentationBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.removeInstrumentationBreakpoint", [{"name": "eventName", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.setXHRBreakpoint", [{"name": "url", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("DOMDebugger.removeXHRBreakpoint", [{"name": "url", "type": "string", "optional": false}], []); | |
InspectorBackend.registerProfilerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Profiler"); | |
InspectorBackend.registerEvent("Profiler.addProfileHeader", ["header"]); | |
InspectorBackend.registerEvent("Profiler.addHeapSnapshotChunk", ["uid", "chunk"]); | |
InspectorBackend.registerEvent("Profiler.finishHeapSnapshot", ["uid"]); | |
InspectorBackend.registerEvent("Profiler.setRecordingProfile", ["isProfiling"]); | |
InspectorBackend.registerEvent("Profiler.resetProfiles", []); | |
InspectorBackend.registerEvent("Profiler.reportHeapSnapshotProgress", ["done", "total"]); | |
InspectorBackend.registerCommand("Profiler.causesRecompilation", [], ["result"]); | |
InspectorBackend.registerCommand("Profiler.isSampling", [], ["result"]); | |
InspectorBackend.registerCommand("Profiler.hasHeapProfiler", [], ["result"]); | |
InspectorBackend.registerCommand("Profiler.enable", [], []); | |
InspectorBackend.registerCommand("Profiler.disable", [], []); | |
InspectorBackend.registerCommand("Profiler.start", [], []); | |
InspectorBackend.registerCommand("Profiler.stop", [], []); | |
InspectorBackend.registerCommand("Profiler.getProfileHeaders", [], ["headers"]); | |
InspectorBackend.registerCommand("Profiler.getProfile", [{"name": "type", "type": "string", "optional": false}, {"name": "uid", "type": "number", "optional": false}], ["profile"]); | |
InspectorBackend.registerCommand("Profiler.removeProfile", [{"name": "type", "type": "string", "optional": false}, {"name": "uid", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("Profiler.clearProfiles", [], []); | |
InspectorBackend.registerCommand("Profiler.takeHeapSnapshot", [], []); | |
InspectorBackend.registerCommand("Profiler.collectGarbage", [], []); | |
InspectorBackend.registerCommand("Profiler.getObjectByHeapObjectId", [{"name": "objectId", "type": "string", "optional": false}, {"name": "objectGroup", "type": "string", "optional": true}], ["result"]); | |
InspectorBackend.registerCommand("Profiler.getHeapObjectId", [{"name": "objectId", "type": "string", "optional": false}], ["heapSnapshotObjectId"]); | |
InspectorBackend.registerWorkerDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "Worker"); | |
InspectorBackend.registerEvent("Worker.workerCreated", ["workerId", "url", "inspectorConnected"]); | |
InspectorBackend.registerEvent("Worker.workerTerminated", ["workerId"]); | |
InspectorBackend.registerEvent("Worker.dispatchMessageFromWorker", ["workerId", "message"]); | |
InspectorBackend.registerEvent("Worker.disconnectedFromWorker", []); | |
InspectorBackend.registerCommand("Worker.enable", [], []); | |
InspectorBackend.registerCommand("Worker.disable", [], []); | |
InspectorBackend.registerCommand("Worker.sendMessageToWorker", [{"name": "workerId", "type": "number", "optional": false}, {"name": "message", "type": "object", "optional": false}], []); | |
InspectorBackend.registerCommand("Worker.connectToWorker", [{"name": "workerId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("Worker.disconnectFromWorker", [{"name": "workerId", "type": "number", "optional": false}], []); | |
InspectorBackend.registerCommand("Worker.setAutoconnectToWorkers", [{"name": "value", "type": "boolean", "optional": false}], []); | |
InspectorBackend.registerWebGLDispatcher = InspectorBackend.registerDomainDispatcher.bind(InspectorBackend, "WebGL"); | |
InspectorBackend.registerCommand("WebGL.enable", [], []); | |
InspectorBackend.registerCommand("WebGL.disable", [], []); | |
InspectorBackend.registerCommand("WebGL.dropTraceLog", [{"name": "traceLogId", "type": "string", "optional": false}], []); | |
InspectorBackend.registerCommand("WebGL.captureFrame", [], ["traceLogId"]); | |
InspectorBackend.registerCommand("WebGL.getTraceLog", [{"name": "traceLogId", "type": "string", "optional": false}], ["traceLog"]); | |
InspectorBackend.registerCommand("WebGL.replayTraceLog", [{"name": "traceLogId", "type": "string", "optional": false}, {"name": "stepNo", "type": "number", "optional": false}], ["screenshotDataUrl"]); | |
if (!window.InspectorExtensionRegistry) { | |
WebInspector.InspectorExtensionRegistryStub = function() | |
{ | |
} | |
WebInspector.InspectorExtensionRegistryStub.prototype = { | |
getExtensionsAsync: function() | |
{ | |
} | |
} | |
var InspectorExtensionRegistry = new WebInspector.InspectorExtensionRegistryStub(); | |
} | |
InspectorFrontendAPI = { | |
_pendingCommands: [], | |
isDebuggingEnabled: function() | |
{ | |
return WebInspector.debuggerModel.debuggerEnabled(); | |
}, | |
setDebuggingEnabled: function(enabled) | |
{ | |
if (enabled) { | |
WebInspector.debuggerModel.enableDebugger(); | |
WebInspector.showPanel("scripts"); | |
} else | |
WebInspector.debuggerModel.disableDebugger(); | |
}, | |
isTimelineProfilingEnabled: function() | |
{ | |
return WebInspector.panels.timeline && WebInspector.panels.timeline.timelineProfilingEnabled; | |
}, | |
setTimelineProfilingEnabled: function(enabled) | |
{ | |
WebInspector.showPanel("timeline").setTimelineProfilingEnabled(enabled); | |
}, | |
isProfilingJavaScript: function() | |
{ | |
return WebInspector.panels.profiles && WebInspector.CPUProfileType.instance && WebInspector.CPUProfileType.instance.isRecordingProfile(); | |
}, | |
startProfilingJavaScript: function() | |
{ | |
WebInspector.showPanel("profiles").enableProfiler(); | |
if (WebInspector.CPUProfileType.instance) | |
WebInspector.CPUProfileType.instance.startRecordingProfile(); | |
}, | |
stopProfilingJavaScript: function() | |
{ | |
WebInspector.showPanel("profiles"); | |
if (WebInspector.CPUProfileType.instance) | |
WebInspector.CPUProfileType.instance.stopRecordingProfile(); | |
}, | |
setAttachedWindow: function(attached) | |
{ | |
WebInspector.attached = attached; | |
}, | |
showConsole: function() | |
{ | |
WebInspector.showPanel("console"); | |
}, | |
showMainResourceForFrame: function(frameId) | |
{ | |
}, | |
showResources: function() | |
{ | |
WebInspector.showPanel("resources"); | |
}, | |
setDockingUnavailable: function(unavailable) | |
{ | |
WebInspector.setDockingUnavailable(unavailable); | |
}, | |
enterInspectElementMode: function() | |
{ | |
WebInspector.toggleSearchingForNode(); | |
}, | |
savedURL: function(url) | |
{ | |
WebInspector.fileManager.savedURL(url); | |
}, | |
appendedToURL: function(url) | |
{ | |
WebInspector.fileManager.appendedToURL(url); | |
}, | |
setToolbarColors: function(backgroundColor, color) | |
{ | |
WebInspector.setToolbarColors(backgroundColor, color); | |
}, | |
evaluateForTest: function(callId, script) | |
{ | |
WebInspector.evaluateForTestInFrontend(callId, script); | |
}, | |
dispatch: function(signature) | |
{ | |
if (InspectorFrontendAPI._isLoaded) { | |
var methodName = signature.shift(); | |
return InspectorFrontendAPI[methodName].apply(InspectorFrontendAPI, signature); | |
} | |
InspectorFrontendAPI._pendingCommands.push(signature); | |
}, | |
dispatchQueryParameters: function() | |
{ | |
if ("dispatch" in WebInspector.queryParamsObject) | |
InspectorFrontendAPI.dispatch(JSON.parse(window.decodeURI(WebInspector.queryParamsObject["dispatch"]))); | |
}, | |
loadTimelineFromURL: function(url) | |
{ | |
WebInspector.showPanel("timeline").loadFromURL(url); | |
}, | |
loadCompleted: function() | |
{ | |
InspectorFrontendAPI._isLoaded = true; | |
for (var i = 0; i < InspectorFrontendAPI._pendingCommands.length; ++i) | |
InspectorFrontendAPI.dispatch(InspectorFrontendAPI._pendingCommands[i]); | |
InspectorFrontendAPI._pendingCommands = []; | |
if (window.opener) | |
window.opener.postMessage(["loadCompleted"], "*"); | |
} | |
} | |
if (window.opener) { | |
function onMessageFromOpener(event) | |
{ | |
if (event.source === window.opener) | |
InspectorFrontendAPI.dispatch(event.data); | |
} | |
window.addEventListener("message", onMessageFromOpener, true); | |
} | |
WebInspector.Object = function() { | |
} | |
WebInspector.Object.prototype = { | |
addEventListener: function(eventType, listener, thisObject) | |
{ | |
console.assert(listener); | |
if (!this._listeners) | |
this._listeners = {}; | |
if (!this._listeners[eventType]) | |
this._listeners[eventType] = []; | |
this._listeners[eventType].push({ thisObject: thisObject, listener: listener }); | |
}, | |
removeEventListener: function(eventType, listener, thisObject) | |
{ | |
console.assert(listener); | |
if (!this._listeners || !this._listeners[eventType]) | |
return; | |
var listeners = this._listeners[eventType]; | |
for (var i = 0; i < listeners.length; ++i) { | |
if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject) | |
listeners.splice(i, 1); | |
else if (!listener && thisObject && listeners[i].thisObject === thisObject) | |
listeners.splice(i, 1); | |
} | |
if (!listeners.length) | |
delete this._listeners[eventType]; | |
}, | |
removeAllListeners: function() | |
{ | |
delete this._listeners; | |
}, | |
hasEventListeners: function(eventType) | |
{ | |
if (!this._listeners || !this._listeners[eventType]) | |
return false; | |
return true; | |
}, | |
dispatchEventToListeners: function(eventType, eventData) | |
{ | |
if (!this._listeners || !this._listeners[eventType]) | |
return false; | |
var event = new WebInspector.Event(this, eventType, eventData); | |
var listeners = this._listeners[eventType].slice(0); | |
for (var i = 0; i < listeners.length; ++i) { | |
listeners[i].listener.call(listeners[i].thisObject, event); | |
if (event._stoppedPropagation) | |
break; | |
} | |
return event.defaultPrevented; | |
} | |
} | |
WebInspector.Event = function(target, type, data) | |
{ | |
this.target = target; | |
this.type = type; | |
this.data = data; | |
this.defaultPrevented = false; | |
this._stoppedPropagation = false; | |
} | |
WebInspector.Event.prototype = { | |
stopPropagation: function() | |
{ | |
this._stoppedPropagation = true; | |
}, | |
preventDefault: function() | |
{ | |
this.defaultPrevented = true; | |
}, | |
consume: function(preventDefault) | |
{ | |
this.stopPropagation(); | |
if (preventDefault) | |
this.preventDefault(); | |
} | |
} | |
WebInspector.notifications = new WebInspector.Object(); | |
var Preferences = { | |
maxInlineTextChildLength: 80, | |
minConsoleHeight: 75, | |
minSidebarWidth: 100, | |
minElementsSidebarWidth: 200, | |
minScriptsSidebarWidth: 200, | |
styleRulesExpandedState: {}, | |
showMissingLocalizedStrings: false, | |
useLowerCaseMenuTitlesOnWindows: false, | |
sharedWorkersDebugNote: undefined, | |
localizeUI: true, | |
exposeDisableCache: false, | |
applicationTitle: "Web Inspector - %s", | |
showDockToRight: false, | |
exposeFileSystemInspection: false | |
} | |
var Capabilities = { | |
samplingCPUProfiler: false, | |
debuggerCausesRecompilation: true, | |
separateScriptCompilationAndExecutionEnabled: false, | |
profilerCausesRecompilation: true, | |
heapProfilerPresent: false, | |
canOverrideDeviceMetrics: false, | |
timelineSupportsFrameInstrumentation: false, | |
canOverrideGeolocation: false, | |
canOverrideDeviceOrientation: false, | |
} | |
WebInspector.Settings = function() | |
{ | |
this._eventSupport = new WebInspector.Object(); | |
this.colorFormat = this.createSetting("colorFormat", "hex"); | |
this.consoleHistory = this.createSetting("consoleHistory", []); | |
this.debuggerEnabled = this.createSetting("debuggerEnabled", false); | |
this.domWordWrap = this.createSetting("domWordWrap", true); | |
this.profilerEnabled = this.createSetting("profilerEnabled", false); | |
this.eventListenersFilter = this.createSetting("eventListenersFilter", "all"); | |
this.lastActivePanel = this.createSetting("lastActivePanel", "elements"); | |
this.lastViewedScriptFile = this.createSetting("lastViewedScriptFile", "application"); | |
this.monitoringXHREnabled = this.createSetting("monitoringXHREnabled", false); | |
this.preserveConsoleLog = this.createSetting("preserveConsoleLog", false); | |
this.resourcesLargeRows = this.createSetting("resourcesLargeRows", true); | |
this.resourcesSortOptions = this.createSetting("resourcesSortOptions", {timeOption: "responseTime", sizeOption: "transferSize"}); | |
this.resourceViewTab = this.createSetting("resourceViewTab", "preview"); | |
this.showInheritedComputedStyleProperties = this.createSetting("showInheritedComputedStyleProperties", false); | |
this.showUserAgentStyles = this.createSetting("showUserAgentStyles", true); | |
this.watchExpressions = this.createSetting("watchExpressions", []); | |
this.breakpoints = this.createSetting("breakpoints", []); | |
this.eventListenerBreakpoints = this.createSetting("eventListenerBreakpoints", []); | |
this.domBreakpoints = this.createSetting("domBreakpoints", []); | |
this.xhrBreakpoints = this.createSetting("xhrBreakpoints", []); | |
this.sourceMapsEnabled = this.createSetting("sourceMapsEnabled", false); | |
this.cacheDisabled = this.createSetting("cacheDisabled", false); | |
this.overrideUserAgent = this.createSetting("overrideUserAgent", ""); | |
this.userAgent = this.createSetting("userAgent", ""); | |
this.deviceMetrics = this.createSetting("deviceMetrics", ""); | |
this.deviceFitWindow = this.createSetting("deviceFitWindow", false); | |
this.showScriptFolders = this.createSetting("showScriptFolders", true); | |
this.dockToRight = this.createSetting("dockToRight", false); | |
this.emulateTouchEvents = this.createSetting("emulateTouchEvents", false); | |
this.showPaintRects = this.createSetting("showPaintRects", false); | |
this.zoomLevel = this.createSetting("zoomLevel", 0); | |
this.savedURLs = this.createSetting("savedURLs", {}); | |
this.javaScriptDisabled = this.createSetting("javaScriptDisabled", false); | |
this.geolocationOverride = this.createSetting("geolocationOverride", ""); | |
this.deviceOrientationOverride = this.createSetting("deviceOrientationOverride", ""); | |
this.showHeapSnapshotObjectsHiddenProperties = this.createSetting("showHeaSnapshotObjectsHiddenProperties", false); | |
this.searchInContentScripts = this.createSetting("searchInContentScripts", false); | |
this.textEditorIndent = this.createSetting("textEditorIndent", " "); | |
if (this.breakpoints.get().length > 500000) | |
this.breakpoints.set([]); | |
} | |
WebInspector.Settings.prototype = { | |
createSetting: function(key, defaultValue) | |
{ | |
return new WebInspector.Setting(key, defaultValue, this._eventSupport); | |
} | |
} | |
WebInspector.Setting = function(name, defaultValue, eventSupport) | |
{ | |
this._name = name; | |
this._defaultValue = defaultValue; | |
this._eventSupport = eventSupport; | |
} | |
WebInspector.Setting.prototype = { | |
addChangeListener: function(listener, thisObject) | |
{ | |
this._eventSupport.addEventListener(this._name, listener, thisObject); | |
}, | |
removeChangeListener: function(listener, thisObject) | |
{ | |
this._eventSupport.removeEventListener(this._name, listener, thisObject); | |
}, | |
get name() | |
{ | |
return this._name; | |
}, | |
get: function() | |
{ | |
if (typeof this._value !== "undefined") | |
return this._value; | |
this._value = this._defaultValue; | |
if (window.localStorage != null && this._name in window.localStorage) { | |
try { | |
this._value = JSON.parse(window.localStorage[this._name]); | |
} catch(e) { | |
window.localStorage.removeItem(this._name); | |
} | |
} | |
return this._value; | |
}, | |
set: function(value) | |
{ | |
this._value = value; | |
if (window.localStorage != null) { | |
try { | |
window.localStorage[this._name] = JSON.stringify(value); | |
} catch(e) { | |
console.error("Error saving setting with name:" + this._name); | |
} | |
} | |
this._eventSupport.dispatchEventToListeners(this._name, value); | |
} | |
} | |
WebInspector.ExperimentsSettings = function() | |
{ | |
this._setting = WebInspector.settings.createSetting("experiments", {}); | |
this._experiments = []; | |
this._enabledForTest = {}; | |
this.showShadowDOM = this._createExperiment("showShadowDOM", "Show shadow DOM"); | |
this.snippetsSupport = this._createExperiment("snippetsSupport", "Snippets support"); | |
this.nativeMemorySnapshots = this._createExperiment("nativeMemorySnapshots", "Native memory profiling"); | |
this.liveNativeMemoryChart = this._createExperiment("liveNativeMemoryChart", "Live native memory chart"); | |
this.fileSystemInspection = this._createExperiment("fileSystemInspection", "FileSystem inspection"); | |
this.webGLInspection = this._createExperiment("webGLInspection ", "WebGL inspection"); | |
this.mainThreadMonitoring = this._createExperiment("mainThreadMonitoring", "Show CPU activity in Timeline"); | |
this.geolocationOverride = this._createExperiment("geolocationOverride", "Override Device Geolocation"); | |
this.deviceOrientationOverride = this._createExperiment("deviceOrientationOverride", "Override Device Orientation"); | |
this.sass = this._createExperiment("sass", "Support for SASS"); | |
this.codemirror = this._createExperiment("codemirror", "Use CodeMirror editor"); | |
this.cssRegions = this._createExperiment("cssRegions", "CSS Regions Support"); | |
this._cleanUpSetting(); | |
} | |
WebInspector.ExperimentsSettings.prototype = { | |
get experiments() | |
{ | |
return this._experiments.slice(); | |
}, | |
get experimentsEnabled() | |
{ | |
return "experiments" in WebInspector.queryParamsObject; | |
}, | |
_createExperiment: function(experimentName, experimentTitle) | |
{ | |
var experiment = new WebInspector.Experiment(this, experimentName, experimentTitle); | |
this._experiments.push(experiment); | |
return experiment; | |
}, | |
isEnabled: function(experimentName) | |
{ | |
if (this._enabledForTest[experimentName]) | |
return true; | |
if (!this.experimentsEnabled) | |
return false; | |
var experimentsSetting = this._setting.get(); | |
return experimentsSetting[experimentName]; | |
}, | |
setEnabled: function(experimentName, enabled) | |
{ | |
var experimentsSetting = this._setting.get(); | |
experimentsSetting[experimentName] = enabled; | |
this._setting.set(experimentsSetting); | |
}, | |
_enableForTest: function(experimentName) | |
{ | |
this._enabledForTest[experimentName] = true; | |
}, | |
_cleanUpSetting: function() | |
{ | |
var experimentsSetting = this._setting.get(); | |
var cleanedUpExperimentSetting = {}; | |
for (var i = 0; i < this._experiments.length; ++i) { | |
var experimentName = this._experiments[i].name; | |
if (experimentsSetting[experimentName]) | |
cleanedUpExperimentSetting[experimentName] = true; | |
} | |
this._setting.set(cleanedUpExperimentSetting); | |
} | |
} | |
WebInspector.Experiment = function(experimentsSettings, name, title) | |
{ | |
this._name = name; | |
this._title = title; | |
this._experimentsSettings = experimentsSettings; | |
} | |
WebInspector.Experiment.prototype = { | |
get name() | |
{ | |
return this._name; | |
}, | |
get title() | |
{ | |
return this._title; | |
}, | |
isEnabled: function() | |
{ | |
return this._experimentsSettings.isEnabled(this._name); | |
}, | |
setEnabled: function(enabled) | |
{ | |
return this._experimentsSettings.setEnabled(this._name, enabled); | |
}, | |
enableForTest: function() | |
{ | |
this._experimentsSettings._enableForTest(this._name); | |
} | |
} | |
WebInspector.settings = new WebInspector.Settings(); | |
WebInspector.experimentsSettings = new WebInspector.ExperimentsSettings(); | |
WebInspector.View = function() | |
{ | |
this.element = document.createElement("div"); | |
this.element.__view = this; | |
this._visible = true; | |
this._isRoot = false; | |
this._isShowing = false; | |
this._children = []; | |
this._hideOnDetach = false; | |
this._cssFiles = []; | |
} | |
WebInspector.View._cssFileToVisibleViewCount = {}; | |
WebInspector.View._cssFileToStyleElement = {}; | |
WebInspector.View.prototype = { | |
markAsRoot: function() | |
{ | |
this._isRoot = true; | |
}, | |
isShowing: function() | |
{ | |
return this._isShowing; | |
}, | |
setHideOnDetach: function() | |
{ | |
this._hideOnDetach = true; | |
}, | |
_parentIsShowing: function() | |
{ | |
return this._isRoot || (this._parentView && this._parentView.isShowing()); | |
}, | |
_callOnVisibleChildren: function(method) | |
{ | |
for (var i = 0; i < this._children.length; ++i) | |
if (this._children[i]._visible) | |
method.call(this._children[i]); | |
}, | |
_processWillShow: function() | |
{ | |
this._loadCSSIfNeeded(); | |
this._callOnVisibleChildren(this._processWillShow); | |
}, | |
_processWasShown: function() | |
{ | |
this._isShowing = true; | |
this.restoreScrollPositions(); | |
this.wasShown(); | |
this.onResize(); | |
this._callOnVisibleChildren(this._processWasShown); | |
}, | |
_processWillHide: function() | |
{ | |
this.storeScrollPositions(); | |
this._callOnVisibleChildren(this._processWillHide); | |
this.willHide(); | |
this._isShowing = false; | |
}, | |
_processWasHidden: function() | |
{ | |
this._disableCSSIfNeeded(); | |
this._callOnVisibleChildren(this._processWasHidden); | |
}, | |
_processOnResize: function() | |
{ | |
if (!this.isShowing()) | |
return; | |
this.onResize(); | |
this._callOnVisibleChildren(this._processOnResize); | |
}, | |
wasShown: function() | |
{ | |
}, | |
willHide: function() | |
{ | |
}, | |
onResize: function() | |
{ | |
}, | |
show: function(parentElement, insertBefore) | |
{ | |
WebInspector.View._assert(parentElement, "Attempt to attach view with no parent element"); | |
if (this.element.parentElement !== parentElement) { | |
var currentParent = parentElement; | |
while (currentParent && !currentParent.__view) | |
currentParent = currentParent.parentElement; | |
if (currentParent) { | |
this._parentView = currentParent.__view; | |
this._parentView._children.push(this); | |
this._isRoot = false; | |
} else | |
WebInspector.View._assert(this._isRoot, "Attempt to attach view to orphan node"); | |
} else if (this._visible) | |
return; | |
this._visible = true; | |
if (this._parentIsShowing()) | |
this._processWillShow(); | |
this.element.addStyleClass("visible"); | |
if (this.element.parentElement !== parentElement) { | |
WebInspector.View._incrementViewCounter(parentElement, this.element); | |
if (insertBefore) | |
WebInspector.View._originalInsertBefore.call(parentElement, this.element, insertBefore); | |
else | |
WebInspector.View._originalAppendChild.call(parentElement, this.element); | |
} | |
if (this._parentIsShowing()) | |
this._processWasShown(); | |
}, | |
detach: function(overrideHideOnDetach) | |
{ | |
var parentElement = this.element.parentElement; | |
if (!parentElement) | |
return; | |
if (this._parentIsShowing()) | |
this._processWillHide(); | |
if (this._hideOnDetach && !overrideHideOnDetach) { | |
this.element.removeStyleClass("visible"); | |
this._visible = false; | |
if (this._parentIsShowing()) | |
this._processWasHidden(); | |
return; | |
} | |
WebInspector.View._decrementViewCounter(parentElement, this.element); | |
WebInspector.View._originalRemoveChild.call(parentElement, this.element); | |
this._visible = false; | |
if (this._parentIsShowing()) | |
this._processWasHidden(); | |
if (this._parentView) { | |
var childIndex = this._parentView._children.indexOf(this); | |
WebInspector.View._assert(childIndex >= 0, "Attempt to remove non-child view"); | |
this._parentView._children.splice(childIndex, 1); | |
this._parentView = null; | |
} else | |
WebInspector.View._assert(this._isRoot, "Removing non-root view from DOM"); | |
}, | |
detachChildViews: function() | |
{ | |
var children = this._children.slice(); | |
for (var i = 0; i < children.length; ++i) | |
children[i].detach(); | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return [this.element]; | |
}, | |
storeScrollPositions: function() | |
{ | |
var elements = this.elementsToRestoreScrollPositionsFor(); | |
for (var i = 0; i < elements.length; ++i) { | |
var container = elements[i]; | |
container._scrollTop = container.scrollTop; | |
container._scrollLeft = container.scrollLeft; | |
} | |
}, | |
restoreScrollPositions: function() | |
{ | |
var elements = this.elementsToRestoreScrollPositionsFor(); | |
for (var i = 0; i < elements.length; ++i) { | |
var container = elements[i]; | |
if (container._scrollTop) | |
container.scrollTop = container._scrollTop; | |
if (container._scrollLeft) | |
container.scrollLeft = container._scrollLeft; | |
} | |
}, | |
canHighlightLine: function() | |
{ | |
return false; | |
}, | |
highlightLine: function(line) | |
{ | |
}, | |
doResize: function() | |
{ | |
this._processOnResize(); | |
}, | |
registerRequiredCSS: function(cssFile) | |
{ | |
this._cssFiles.push(cssFile); | |
}, | |
_loadCSSIfNeeded: function() | |
{ | |
for (var i = 0; i < this._cssFiles.length; ++i) { | |
var cssFile = this._cssFiles[i]; | |
var viewsWithCSSFile = WebInspector.View._cssFileToVisibleViewCount[cssFile]; | |
WebInspector.View._cssFileToVisibleViewCount[cssFile] = (viewsWithCSSFile || 0) + 1; | |
if (!viewsWithCSSFile) | |
this._doLoadCSS(cssFile); | |
} | |
}, | |
_doLoadCSS: function(cssFile) | |
{ | |
var styleElement = WebInspector.View._cssFileToStyleElement[cssFile]; | |
if (styleElement) { | |
styleElement.disabled = false; | |
return; | |
} | |
if (window.debugCSS) { | |
styleElement = document.createElement("link"); | |
styleElement.rel = "stylesheet"; | |
styleElement.type = "text/css"; | |
styleElement.href = cssFile; | |
} else { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", cssFile, false); | |
xhr.send(null); | |
styleElement = document.createElement("style"); | |
styleElement.type = "text/css"; | |
styleElement.textContent = xhr.responseText; | |
} | |
document.head.insertBefore(styleElement, document.head.firstChild); | |
WebInspector.View._cssFileToStyleElement[cssFile] = styleElement; | |
}, | |
_disableCSSIfNeeded: function() | |
{ | |
for (var i = 0; i < this._cssFiles.length; ++i) { | |
var cssFile = this._cssFiles[i]; | |
var viewsWithCSSFile = WebInspector.View._cssFileToVisibleViewCount[cssFile]; | |
viewsWithCSSFile--; | |
WebInspector.View._cssFileToVisibleViewCount[cssFile] = viewsWithCSSFile; | |
if (!viewsWithCSSFile) | |
this._doUnloadCSS(cssFile); | |
} | |
}, | |
_doUnloadCSS: function(cssFile) | |
{ | |
var styleElement = WebInspector.View._cssFileToStyleElement[cssFile]; | |
styleElement.disabled = true; | |
}, | |
printViewHierarchy: function() | |
{ | |
var lines = []; | |
this._collectViewHierarchy("", lines); | |
console.log(lines.join("\n")); | |
}, | |
_collectViewHierarchy: function(prefix, lines) | |
{ | |
lines.push(prefix + "[" + this.element.className + "]" + (this._children.length ? " {" : "")); | |
for (var i = 0; i < this._children.length; ++i) | |
this._children[i]._collectViewHierarchy(prefix + " ", lines); | |
if (this._children.length) | |
lines.push(prefix + "}"); | |
}, | |
defaultFocusedElement: function() | |
{ | |
return this._defaultFocusedElement || this.element; | |
}, | |
setDefaultFocusedElement: function(element) | |
{ | |
this._defaultFocusedElement = element; | |
}, | |
focus: function() | |
{ | |
var element = this.defaultFocusedElement(); | |
if (!element || element.isAncestor(document.activeElement)) | |
return; | |
WebInspector.setCurrentFocusElement(element); | |
} | |
} | |
WebInspector.View.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.View._originalAppendChild = Element.prototype.appendChild; | |
WebInspector.View._originalInsertBefore = Element.prototype.insertBefore; | |
WebInspector.View._originalRemoveChild = Element.prototype.removeChild; | |
WebInspector.View._originalRemoveChildren = Element.prototype.removeChildren; | |
WebInspector.View._incrementViewCounter = function(parentElement, childElement) | |
{ | |
var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0); | |
if (!count) | |
return; | |
while (parentElement) { | |
parentElement.__viewCounter = (parentElement.__viewCounter || 0) + count; | |
parentElement = parentElement.parentElement; | |
} | |
} | |
WebInspector.View._decrementViewCounter = function(parentElement, childElement) | |
{ | |
var count = (childElement.__viewCounter || 0) + (childElement.__view ? 1 : 0); | |
if (!count) | |
return; | |
while (parentElement) { | |
parentElement.__viewCounter -= count; | |
parentElement = parentElement.parentElement; | |
} | |
} | |
WebInspector.View._assert = function(condition, message) | |
{ | |
if (!condition) { | |
console.trace(); | |
throw new Error(message); | |
} | |
} | |
Element.prototype.appendChild = function(child) | |
{ | |
WebInspector.View._assert(!child.__view, "Attempt to add view via regular DOM operation."); | |
return WebInspector.View._originalAppendChild.call(this, child); | |
} | |
Element.prototype.insertBefore = function(child, anchor) | |
{ | |
WebInspector.View._assert(!child.__view, "Attempt to add view via regular DOM operation."); | |
return WebInspector.View._originalInsertBefore.call(this, child, anchor); | |
} | |
Element.prototype.removeChild = function(child) | |
{ | |
WebInspector.View._assert(!child.__viewCounter && !child.__view, "Attempt to remove element containing view via regular DOM operation"); | |
return WebInspector.View._originalRemoveChild.call(this, child); | |
} | |
Element.prototype.removeChildren = function() | |
{ | |
WebInspector.View._assert(!this.__viewCounter, "Attempt to remove element containing view via regular DOM operation"); | |
WebInspector.View._originalRemoveChildren.call(this); | |
} | |
WebInspector.HelpScreen = function(title) | |
{ | |
WebInspector.View.call(this); | |
this.markAsRoot(); | |
this.registerRequiredCSS("helpScreen.css"); | |
this.element.className = "help-window-outer"; | |
this.element.addEventListener("keydown", this._onKeyDown.bind(this), false); | |
this.element.tabIndex = 0; | |
this.element.addEventListener("focus", this._onBlur.bind(this), false); | |
if (title) { | |
var mainWindow = this.element.createChild("div", "help-window-main"); | |
var captionWindow = mainWindow.createChild("div", "help-window-caption"); | |
captionWindow.appendChild(this._createCloseButton()); | |
this.contentElement = mainWindow.createChild("div", "help-content"); | |
captionWindow.createChild("h1", "help-window-title").textContent = title; | |
} | |
} | |
WebInspector.HelpScreen._visibleScreen = null; | |
WebInspector.HelpScreen.prototype = { | |
_createCloseButton: function() | |
{ | |
var closeButton = document.createElement("button"); | |
closeButton.className = "help-close-button"; | |
closeButton.textContent = "\u2716"; | |
closeButton.addEventListener("click", this.hide.bind(this), false); | |
return closeButton; | |
}, | |
showModal: function() | |
{ | |
var visibleHelpScreen = WebInspector.HelpScreen._visibleScreen; | |
if (visibleHelpScreen === this) | |
return; | |
if (visibleHelpScreen) | |
visibleHelpScreen.hide(); | |
WebInspector.HelpScreen._visibleScreen = this; | |
this.show(document.body); | |
this.focus(); | |
}, | |
hide: function() | |
{ | |
if (!this.isShowing()) | |
return; | |
WebInspector.HelpScreen._visibleScreen = null; | |
WebInspector.restoreFocusFromElement(this.element); | |
this.detach(); | |
}, | |
isClosingKey: function(keyCode) | |
{ | |
return [ | |
WebInspector.KeyboardShortcut.Keys.Enter.code, | |
WebInspector.KeyboardShortcut.Keys.Esc.code, | |
WebInspector.KeyboardShortcut.Keys.Space.code, | |
].indexOf(keyCode) >= 0; | |
}, | |
_onKeyDown: function(event) | |
{ | |
if (this.isShowing() && this.isClosingKey(event.keyCode)) { | |
this.hide(); | |
event.consume(); | |
} | |
}, | |
_onBlur: function(event) | |
{ | |
if (this.isShowing() && !this.element.isSelfOrAncestor(event.target)) | |
WebInspector.setCurrentFocusElement(this.element); | |
} | |
} | |
WebInspector.HelpScreen.prototype.__proto__ = WebInspector.View.prototype; | |
if (!window.InspectorFrontendHost) { | |
WebInspector.InspectorFrontendHostStub = function() | |
{ | |
this._attachedWindowHeight = 0; | |
this.isStub = true; | |
WebInspector.documentCopyEventFired = this.documentCopy.bind(this); | |
} | |
WebInspector.InspectorFrontendHostStub.prototype = { | |
platform: function() | |
{ | |
var match = navigator.userAgent.match(/Windows NT/); | |
if (match) | |
return "windows"; | |
match = navigator.userAgent.match(/Mac OS X/); | |
if (match) | |
return "mac"; | |
return "linux"; | |
}, | |
port: function() | |
{ | |
return "unknown"; | |
}, | |
bringToFront: function() | |
{ | |
this._windowVisible = true; | |
}, | |
closeWindow: function() | |
{ | |
this._windowVisible = false; | |
}, | |
requestAttachWindow: function() | |
{ | |
}, | |
requestDetachWindow: function() | |
{ | |
}, | |
requestSetDockSide: function() | |
{ | |
}, | |
setAttachedWindowHeight: function(height) | |
{ | |
}, | |
moveWindowBy: function(x, y) | |
{ | |
}, | |
setInjectedScriptForOrigin: function(origin, script) | |
{ | |
}, | |
loaded: function() | |
{ | |
}, | |
localizedStringsURL: function() | |
{ | |
return undefined; | |
}, | |
hiddenPanels: function() | |
{ | |
return WebInspector.queryParamsObject["hiddenPanels"] || ""; | |
}, | |
inspectedURLChanged: function(url) | |
{ | |
document.title = WebInspector.UIString(Preferences.applicationTitle, url); | |
}, | |
documentCopy: function(event) | |
{ | |
if (!this._textToCopy) | |
return; | |
event.clipboardData.setData("text", this._textToCopy); | |
event.preventDefault(); | |
delete this._textToCopy; | |
}, | |
copyText: function(text) | |
{ | |
this._textToCopy = text; | |
if (!document.execCommand("copy")) { | |
var screen = new WebInspector.ClipboardAccessDeniedScreen(); | |
screen.showModal(); | |
} | |
}, | |
openInNewTab: function(url) | |
{ | |
window.open(url, "_blank"); | |
}, | |
canSave: function() | |
{ | |
return true; | |
}, | |
save: function(url, content, forceSaveAs) | |
{ | |
var builder = new WebKitBlobBuilder(); | |
builder.append(content); | |
var blob = builder.getBlob("application/octet-stream"); | |
var fr = new FileReader(); | |
fr.onload = function(e) { | |
window.location = this.result; | |
} | |
fr.readAsDataURL(blob); | |
}, | |
canAppend: function() | |
{ | |
return false; | |
}, | |
append: function(url, content) | |
{ | |
}, | |
sendMessageToBackend: function(message) | |
{ | |
}, | |
recordActionTaken: function(actionCode) | |
{ | |
}, | |
recordPanelShown: function(panelCode) | |
{ | |
}, | |
recordSettingChanged: function(settingCode) | |
{ | |
}, | |
loadResourceSynchronously: function(url) | |
{ | |
return loadXHR(url); | |
}, | |
setZoomFactor: function(zoom) | |
{ | |
}, | |
canInspectWorkers: function() | |
{ | |
return true; | |
} | |
} | |
InspectorFrontendHost = new WebInspector.InspectorFrontendHostStub(); | |
Preferences.localizeUI = false; | |
WebInspector.clipboardAccessDeniedMessage = function() | |
{ | |
return ""; | |
} | |
WebInspector.ClipboardAccessDeniedScreen = function() | |
{ | |
WebInspector.HelpScreen.call(this, WebInspector.UIString("Clipboard access is denied")); | |
var platformMessage = WebInspector.clipboardAccessDeniedMessage(); | |
if (platformMessage) { | |
var p = this.contentElement.createChild("p"); | |
p.addStyleClass("help-section"); | |
p.textContent = platformMessage; | |
} | |
} | |
WebInspector.ClipboardAccessDeniedScreen.prototype.__proto__ = WebInspector.HelpScreen.prototype; | |
} | |
WebInspector.FileManager = function() | |
{ | |
} | |
WebInspector.FileManager.EventTypes = { | |
SavedURL: "SavedURL", | |
AppendedToURL: "AppendedToURL" | |
} | |
WebInspector.FileManager.prototype = { | |
canSave: function() | |
{ | |
return InspectorFrontendHost.canSave(); | |
}, | |
canAppend: function() | |
{ | |
return InspectorFrontendHost.canSave() && ("append" in InspectorFrontendHost); | |
}, | |
save: function(url, content, forceSaveAs) | |
{ | |
var savedURLs = WebInspector.settings.savedURLs.get(); | |
delete savedURLs[url]; | |
WebInspector.settings.savedURLs.set(savedURLs); | |
InspectorFrontendHost.save(url, content, forceSaveAs); | |
}, | |
savedURL: function(url) | |
{ | |
var savedURLs = WebInspector.settings.savedURLs.get(); | |
savedURLs[url] = true; | |
WebInspector.settings.savedURLs.set(savedURLs); | |
this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.SavedURL, url); | |
}, | |
isURLSaved: function(url) | |
{ | |
var savedURLs = WebInspector.settings.savedURLs.get(); | |
return savedURLs[url]; | |
}, | |
append: function(url, content) | |
{ | |
InspectorFrontendHost.append(url, content); | |
}, | |
appendedToURL: function(url) | |
{ | |
this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.AppendedToURL, url); | |
} | |
} | |
WebInspector.FileManager.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.fileManager = new WebInspector.FileManager(); | |
WebInspector.Checkbox = function(label, className, tooltip) | |
{ | |
this.element = document.createElement('label'); | |
this._inputElement = document.createElement('input'); | |
this._inputElement.type = "checkbox"; | |
this.element.className = className; | |
this.element.appendChild(this._inputElement); | |
this.element.appendChild(document.createTextNode(label)); | |
if (tooltip) | |
this.element.title = tooltip; | |
} | |
WebInspector.Checkbox.prototype = { | |
set checked(checked) | |
{ | |
this._inputElement.checked = checked; | |
}, | |
get checked() | |
{ | |
return this._inputElement.checked; | |
}, | |
addEventListener: function(listener) | |
{ | |
function listenerWrapper(event) | |
{ | |
if (listener) | |
listener(event); | |
event.consume(); | |
return true; | |
} | |
this._inputElement.addEventListener("click", listenerWrapper, false); | |
this.element.addEventListener("click", listenerWrapper, false); | |
} | |
} | |
WebInspector.ContextMenuItem = function(topLevelMenu, type, label, disabled, checked) | |
{ | |
this._type = type; | |
this._label = label; | |
this._disabled = disabled; | |
this._checked = checked; | |
this._contextMenu = topLevelMenu; | |
if (type === "item" || type === "checkbox") | |
this._id = topLevelMenu.nextId(); | |
} | |
WebInspector.ContextMenuItem.prototype = { | |
id: function() | |
{ | |
return this._id; | |
}, | |
type: function() | |
{ | |
return this._type; | |
}, | |
_buildDescriptor: function() | |
{ | |
switch (this._type) { | |
case "item": | |
return { type: "item", id: this._id, label: this._label, enabled: !this._disabled }; | |
case "separator": | |
return { type: "separator" }; | |
case "checkbox": | |
return { type: "checkbox", id: this._id, label: this._label, checked: !!this._checked, enabled: !this._disabled }; | |
} | |
} | |
} | |
WebInspector.ContextSubMenuItem = function(topLevelMenu, label, disabled) | |
{ | |
WebInspector.ContextMenuItem.call(this, topLevelMenu, "subMenu", label, disabled); | |
this._items = []; | |
} | |
WebInspector.ContextSubMenuItem.prototype = { | |
appendItem: function(label, handler, disabled) | |
{ | |
var item = new WebInspector.ContextMenuItem(this._contextMenu, "item", label, disabled); | |
this._pushItem(item); | |
this._contextMenu._setHandler(item.id(), handler); | |
return item; | |
}, | |
appendSubMenuItem: function(label, disabled) | |
{ | |
var item = new WebInspector.ContextSubMenuItem(this._contextMenu, label, disabled); | |
this._pushItem(item); | |
return item; | |
}, | |
appendCheckboxItem: function(label, handler, checked, disabled) | |
{ | |
var item = new WebInspector.ContextMenuItem(this._contextMenu, "checkbox", label, disabled, checked); | |
this._pushItem(item); | |
this._contextMenu._setHandler(item.id(), handler); | |
return item; | |
}, | |
appendSeparator: function() | |
{ | |
if (this._items.length) | |
this._pendingSeparator = true; | |
}, | |
_pushItem: function(item) | |
{ | |
if (this._pendingSeparator) { | |
this._items.push(new WebInspector.ContextMenuItem(this._contextMenu, "separator")); | |
delete this._pendingSeparator; | |
} | |
this._items.push(item); | |
}, | |
isEmpty: function() | |
{ | |
return !this._items.length; | |
}, | |
_buildDescriptor: function() | |
{ | |
var result = { type: "subMenu", label: this._label, enabled: !this._disabled, subItems: [] }; | |
for (var i = 0; i < this._items.length; ++i) | |
result.subItems.push(this._items[i]._buildDescriptor()); | |
return result; | |
} | |
} | |
WebInspector.ContextSubMenuItem.prototype.__proto__ = WebInspector.ContextMenuItem.prototype; | |
WebInspector.ContextMenu = function() { | |
WebInspector.ContextSubMenuItem.call(this, this, ""); | |
this._handlers = {}; | |
this._id = 0; | |
} | |
WebInspector.ContextMenu.prototype = { | |
nextId: function() | |
{ | |
return this._id++; | |
}, | |
show: function(event) | |
{ | |
var menuObject = this._buildDescriptor(); | |
if (menuObject.length) { | |
WebInspector._contextMenu = this; | |
InspectorFrontendHost.showContextMenu(event, menuObject); | |
} | |
event.consume(); | |
}, | |
_setHandler: function(id, handler) | |
{ | |
if (handler) | |
this._handlers[id] = handler; | |
}, | |
_buildDescriptor: function() | |
{ | |
var result = []; | |
for (var i = 0; i < this._items.length; ++i) | |
result.push(this._items[i]._buildDescriptor()); | |
return result; | |
}, | |
_itemSelected: function(id) | |
{ | |
if (this._handlers[id]) | |
this._handlers[id].call(this); | |
}, | |
appendApplicableItems: function(target) | |
{ | |
for (var i = 0; i < WebInspector.ContextMenu._providers.length; ++i) { | |
var provider = WebInspector.ContextMenu._providers[i]; | |
this.appendSeparator(); | |
provider.appendApplicableItems(this, target); | |
this.appendSeparator(); | |
} | |
} | |
} | |
WebInspector.ContextMenu.prototype.__proto__ = WebInspector.ContextSubMenuItem.prototype; | |
WebInspector.ContextMenu.Provider = function() { | |
} | |
WebInspector.ContextMenu.Provider.prototype = { | |
appendApplicableItems: function(contextMenu, target) { } | |
} | |
WebInspector.ContextMenu.registerProvider = function(provider) | |
{ | |
WebInspector.ContextMenu._providers.push(provider); | |
} | |
WebInspector.ContextMenu._providers = []; | |
WebInspector.contextMenuItemSelected = function(id) | |
{ | |
if (WebInspector._contextMenu) | |
WebInspector._contextMenu._itemSelected(id); | |
} | |
WebInspector.contextMenuCleared = function() | |
{ | |
} | |
if (!InspectorFrontendHost.showContextMenu) { | |
WebInspector.SoftContextMenu = function(items, parentMenu) | |
{ | |
this._items = items; | |
this._parentMenu = parentMenu; | |
} | |
WebInspector.SoftContextMenu.prototype = { | |
show: function(event) | |
{ | |
this._x = event.x; | |
this._y = event.y; | |
this._time = new Date().getTime(); | |
var absoluteX = event.pageX; | |
var absoluteY = event.pageY; | |
var targetElement = event.target; | |
while (targetElement && window !== targetElement.ownerDocument.defaultView) { | |
var frameElement = targetElement.ownerDocument.defaultView.frameElement; | |
absoluteY += frameElement.totalOffsetTop(); | |
absoluteX += frameElement.totalOffsetLeft(); | |
targetElement = frameElement; | |
} | |
this._contextMenuElement = document.createElement("div"); | |
this._contextMenuElement.className = "soft-context-menu"; | |
this._contextMenuElement.tabIndex = 0; | |
this._contextMenuElement.style.top = absoluteY + "px"; | |
this._contextMenuElement.style.left = absoluteX + "px"; | |
this._contextMenuElement.addEventListener("mouseup", consumeEvent, false); | |
this._contextMenuElement.addEventListener("keydown", this._menuKeyDown.bind(this), false); | |
for (var i = 0; i < this._items.length; ++i) | |
this._contextMenuElement.appendChild(this._createMenuItem(this._items[i])); | |
if (!this._parentMenu) { | |
this._glassPaneElement = document.createElement("div"); | |
this._glassPaneElement.className = "soft-context-menu-glass-pane"; | |
this._glassPaneElement.tabIndex = 0; | |
this._glassPaneElement.addEventListener("mouseup", this._glassPaneMouseUp.bind(this), false); | |
this._glassPaneElement.appendChild(this._contextMenuElement); | |
document.body.appendChild(this._glassPaneElement); | |
this._focus(); | |
} else | |
this._parentMenu._parentGlassPaneElement().appendChild(this._contextMenuElement); | |
if (document.body.offsetWidth < this._contextMenuElement.offsetLeft + this._contextMenuElement.offsetWidth) | |
this._contextMenuElement.style.left = (absoluteX - this._contextMenuElement.offsetWidth) + "px"; | |
if (document.body.offsetHeight < this._contextMenuElement.offsetTop + this._contextMenuElement.offsetHeight) | |
this._contextMenuElement.style.top = (document.body.offsetHeight - this._contextMenuElement.offsetHeight) + "px"; | |
event.consume(true); | |
}, | |
_parentGlassPaneElement: function() | |
{ | |
if (this._glassPaneElement) | |
return this._glassPaneElement; | |
if (this._parentMenu) | |
return this._parentMenu._parentGlassPaneElement(); | |
return null; | |
}, | |
_createMenuItem: function(item) | |
{ | |
if (item.type === "separator") | |
return this._createSeparator(); | |
if (item.type === "subMenu") | |
return this._createSubMenu(item); | |
var menuItemElement = document.createElement("div"); | |
menuItemElement.className = "soft-context-menu-item"; | |
var checkMarkElement = document.createElement("span"); | |
checkMarkElement.textContent = "\u2713 "; | |
checkMarkElement.className = "soft-context-menu-item-checkmark"; | |
if (!item.checked) | |
checkMarkElement.style.opacity = "0"; | |
menuItemElement.appendChild(checkMarkElement); | |
menuItemElement.appendChild(document.createTextNode(item.label)); | |
menuItemElement.addEventListener("mousedown", this._menuItemMouseDown.bind(this), false); | |
menuItemElement.addEventListener("mouseup", this._menuItemMouseUp.bind(this), false); | |
menuItemElement.addEventListener("mouseover", this._menuItemMouseOver.bind(this), false); | |
menuItemElement.addEventListener("mouseout", this._menuItemMouseOut.bind(this), false); | |
menuItemElement._actionId = item.id; | |
return menuItemElement; | |
}, | |
_createSubMenu: function(item) | |
{ | |
var menuItemElement = document.createElement("div"); | |
menuItemElement.className = "soft-context-menu-item"; | |
menuItemElement._subItems = item.subItems; | |
var checkMarkElement = document.createElement("span"); | |
checkMarkElement.textContent = "\u2713 "; | |
checkMarkElement.className = "soft-context-menu-item-checkmark"; | |
checkMarkElement.style.opacity = "0"; | |
menuItemElement.appendChild(checkMarkElement); | |
var subMenuArrowElement = document.createElement("span"); | |
subMenuArrowElement.textContent = "\u25B6"; | |
subMenuArrowElement.className = "soft-context-menu-item-submenu-arrow"; | |
menuItemElement.appendChild(document.createTextNode(item.label)); | |
menuItemElement.appendChild(subMenuArrowElement); | |
menuItemElement.addEventListener("mousedown", this._menuItemMouseDown.bind(this), false); | |
menuItemElement.addEventListener("mouseup", this._menuItemMouseUp.bind(this), false); | |
menuItemElement.addEventListener("mouseover", this._menuItemMouseOver.bind(this), false); | |
menuItemElement.addEventListener("mouseout", this._menuItemMouseOut.bind(this), false); | |
return menuItemElement; | |
}, | |
_createSeparator: function() | |
{ | |
var separatorElement = document.createElement("div"); | |
separatorElement.className = "soft-context-menu-separator"; | |
separatorElement._isSeparator = true; | |
separatorElement.addEventListener("mouseover", this._hideSubMenu.bind(this), false); | |
separatorElement.createChild("div", "separator-line"); | |
return separatorElement; | |
}, | |
_menuItemMouseDown: function(event) | |
{ | |
event.consume(true); | |
}, | |
_menuItemMouseUp: function(event) | |
{ | |
this._triggerAction(event.target, event); | |
event.consume(); | |
}, | |
_focus: function() | |
{ | |
this._contextMenuElement.focus(); | |
}, | |
_triggerAction: function(menuItemElement, event) | |
{ | |
if (!menuItemElement._subItems) { | |
this._discardMenu(true, event); | |
if (typeof menuItemElement._actionId !== "undefined") { | |
WebInspector.contextMenuItemSelected(menuItemElement._actionId); | |
delete menuItemElement._actionId; | |
} | |
return; | |
} | |
this._showSubMenu(menuItemElement, event); | |
event.consume(); | |
}, | |
_showSubMenu: function(menuItemElement, event) | |
{ | |
if (menuItemElement._subMenuTimer) { | |
clearTimeout(menuItemElement._subMenuTimer); | |
delete menuItemElement._subMenuTimer; | |
} | |
if (this._subMenu) | |
return; | |
this._subMenu = new WebInspector.SoftContextMenu(menuItemElement._subItems, this); | |
this._subMenu.show(this._buildMouseEventForSubMenu(menuItemElement)); | |
}, | |
_buildMouseEventForSubMenu: function(subMenuItemElement) | |
{ | |
var subMenuOffset = { x: subMenuItemElement.offsetWidth - 3, y: subMenuItemElement.offsetTop - 1 }; | |
var targetX = this._x + subMenuOffset.x; | |
var targetY = this._y + subMenuOffset.y; | |
var targetPageX = parseInt(this._contextMenuElement.style.left, 10) + subMenuOffset.x; | |
var targetPageY = parseInt(this._contextMenuElement.style.top, 10) + subMenuOffset.y; | |
return { x: targetX, y: targetY, pageX: targetPageX, pageY: targetPageY, consume: function() {} }; | |
}, | |
_hideSubMenu: function() | |
{ | |
if (!this._subMenu) | |
return; | |
this._subMenu._discardSubMenus(); | |
this._focus(); | |
}, | |
_menuItemMouseOver: function(event) | |
{ | |
this._highlightMenuItem(event.target); | |
}, | |
_menuItemMouseOut: function(event) | |
{ | |
if (!this._subMenu || !event.relatedTarget) { | |
this._highlightMenuItem(null); | |
return; | |
} | |
var relatedTarget = event.relatedTarget; | |
if (this._contextMenuElement.isSelfOrAncestor(relatedTarget) || relatedTarget.hasStyleClass("soft-context-menu-glass-pane")) | |
this._highlightMenuItem(null); | |
}, | |
_highlightMenuItem: function(menuItemElement) | |
{ | |
if (this._highlightedMenuItemElement === menuItemElement) | |
return; | |
this._hideSubMenu(); | |
if (this._highlightedMenuItemElement) { | |
this._highlightedMenuItemElement.removeStyleClass("soft-context-menu-item-mouse-over"); | |
if (this._highlightedMenuItemElement._subItems && this._highlightedMenuItemElement._subMenuTimer) { | |
clearTimeout(this._highlightedMenuItemElement._subMenuTimer); | |
delete this._highlightedMenuItemElement._subMenuTimer; | |
} | |
} | |
this._highlightedMenuItemElement = menuItemElement; | |
if (this._highlightedMenuItemElement) { | |
this._highlightedMenuItemElement.addStyleClass("soft-context-menu-item-mouse-over"); | |
this._contextMenuElement.focus(); | |
if (this._highlightedMenuItemElement._subItems && !this._highlightedMenuItemElement._subMenuTimer) | |
this._highlightedMenuItemElement._subMenuTimer = setTimeout(this._showSubMenu.bind(this, this._highlightedMenuItemElement, this._buildMouseEventForSubMenu(this._highlightedMenuItemElement)), 150); | |
} | |
}, | |
_highlightPrevious: function() | |
{ | |
var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.previousSibling : this._contextMenuElement.lastChild; | |
while (menuItemElement && menuItemElement._isSeparator) | |
menuItemElement = menuItemElement.previousSibling; | |
if (menuItemElement) | |
this._highlightMenuItem(menuItemElement); | |
}, | |
_highlightNext: function() | |
{ | |
var menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.nextSibling : this._contextMenuElement.firstChild; | |
while (menuItemElement && menuItemElement._isSeparator) | |
menuItemElement = menuItemElement.nextSibling; | |
if (menuItemElement) | |
this._highlightMenuItem(menuItemElement); | |
}, | |
_menuKeyDown: function(event) | |
{ | |
switch (event.keyIdentifier) { | |
case "Up": | |
this._highlightPrevious(); break; | |
case "Down": | |
this._highlightNext(); break; | |
case "Left": | |
if (this._parentMenu) { | |
this._highlightMenuItem(null); | |
this._parentMenu._focus(); | |
} | |
break; | |
case "Right": | |
if (!this._highlightedMenuItemElement) | |
break; | |
if (this._highlightedMenuItemElement._subItems) { | |
this._showSubMenu(this._highlightedMenuItemElement, this._buildMouseEventForSubMenu(this._highlightedMenuItemElement)); | |
this._subMenu._focus(); | |
this._subMenu._highlightNext(); | |
} | |
break; | |
case "U+001B": | |
this._discardMenu(true, event); break; | |
case "Enter": | |
if (!isEnterKey(event)) | |
break; | |
case "U+0020": | |
if (this._highlightedMenuItemElement) | |
this._triggerAction(this._highlightedMenuItemElement, event); | |
break; | |
} | |
event.consume(true); | |
}, | |
_glassPaneMouseUp: function(event) | |
{ | |
if (event.x === this._x && event.y === this._y && new Date().getTime() - this._time < 300) | |
return; | |
this._discardMenu(true, event); | |
event.consume(); | |
}, | |
_discardMenu: function(closeParentMenus, event) | |
{ | |
if (this._subMenu && !closeParentMenus) | |
return; | |
if (this._glassPaneElement) { | |
var glassPane = this._glassPaneElement; | |
delete this._glassPaneElement; | |
document.body.removeChild(glassPane); | |
if (this._parentMenu) { | |
delete this._parentMenu._subMenu; | |
if (closeParentMenus) | |
this._parentMenu._discardMenu(closeParentMenus, event); | |
} | |
if (event) | |
event.consume(true); | |
} else if (this._parentMenu && this._contextMenuElement.parentElement) { | |
this._discardSubMenus(); | |
if (closeParentMenus) | |
this._parentMenu._discardMenu(closeParentMenus, event); | |
if (event) | |
event.consume(true); | |
} | |
}, | |
_discardSubMenus: function() | |
{ | |
if (this._subMenu) | |
this._subMenu._discardSubMenus(); | |
if (this._contextMenuElement.parentElement) | |
this._contextMenuElement.parentElement.removeChild(this._contextMenuElement); | |
if (this._parentMenu) | |
delete this._parentMenu._subMenu; | |
} | |
} | |
InspectorFrontendHost.showContextMenu = function(event, items) | |
{ | |
new WebInspector.SoftContextMenu(items).show(event); | |
} | |
} | |
WebInspector.KeyboardShortcut = function() | |
{ | |
} | |
WebInspector.KeyboardShortcut.Modifiers = { | |
None: 0, | |
Shift: 1, | |
Ctrl: 2, | |
Alt: 4, | |
Meta: 8, | |
get CtrlOrMeta() | |
{ | |
return WebInspector.isMac() ? this.Meta : this.Ctrl; | |
} | |
}; | |
WebInspector.KeyboardShortcut.Keys = { | |
Backspace: { code: 8, name: "\u21a4" }, | |
Tab: { code: 9, name: { mac: "\u21e5", other: "<Tab>" } }, | |
Enter: { code: 13, name: { mac: "\u21a9", other: "<Enter>" } }, | |
Esc: { code: 27, name: { mac: "\u238b", other: "<Esc>" } }, | |
Space: { code: 32, name: "<Space>" }, | |
PageUp: { code: 33, name: { mac: "\u21de", other: "<PageUp>" } }, | |
PageDown: { code: 34, name: { mac: "\u21df", other: "<PageDown>" } }, | |
End: { code: 35, name: { mac: "\u2197", other: "<End>" } }, | |
Home: { code: 36, name: { mac: "\u2196", other: "<Home>" } }, | |
Left: { code: 37, name: "<Left>" }, | |
Up: { code: 38, name: "<Up>" }, | |
Right: { code: 39, name: "<Right>" }, | |
Down: { code: 40, name: "<Down>" }, | |
Delete: { code: 46, name: "<Del>" }, | |
Zero: { code: 48, name: "0" }, | |
F1: { code: 112, name: "F1" }, | |
F2: { code: 113, name: "F2" }, | |
F3: { code: 114, name: "F3" }, | |
F4: { code: 115, name: "F4" }, | |
F5: { code: 116, name: "F5" }, | |
F6: { code: 117, name: "F6" }, | |
F7: { code: 118, name: "F7" }, | |
F8: { code: 119, name: "F8" }, | |
F9: { code: 120, name: "F9" }, | |
F10: { code: 121, name: "F10" }, | |
F11: { code: 122, name: "F11" }, | |
F12: { code: 123, name: "F12" }, | |
Semicolon: { code: 186, name: ";" }, | |
Plus: { code: 187, name: "+" }, | |
Comma: { code: 188, name: "," }, | |
Minus: { code: 189, name: "-" }, | |
Period: { code: 190, name: "." }, | |
Slash: { code: 191, name: "/" }, | |
Apostrophe: { code: 192, name: "`" }, | |
SingleQuote: { code: 222, name: "\'" } | |
}; | |
WebInspector.KeyboardShortcut.makeKey = function(keyCode, modifiers) | |
{ | |
if (typeof keyCode === "string") | |
keyCode = keyCode.charCodeAt(0) - 32; | |
modifiers = modifiers || WebInspector.KeyboardShortcut.Modifiers.None; | |
return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, modifiers); | |
} | |
WebInspector.KeyboardShortcut.makeKeyFromEvent = function(keyboardEvent) | |
{ | |
var modifiers = WebInspector.KeyboardShortcut.Modifiers.None; | |
if (keyboardEvent.shiftKey) | |
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Shift; | |
if (keyboardEvent.ctrlKey) | |
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Ctrl; | |
if (keyboardEvent.altKey) | |
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Alt; | |
if (keyboardEvent.metaKey) | |
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Meta; | |
return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyboardEvent.keyCode, modifiers); | |
} | |
WebInspector.KeyboardShortcut.eventHasCtrlOrMeta = function(event) | |
{ | |
return WebInspector.isMac() ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey; | |
} | |
WebInspector.KeyboardShortcut.makeDescriptor = function(key, modifiers) | |
{ | |
return { | |
key: WebInspector.KeyboardShortcut.makeKey(typeof key === "string" ? key : key.code, modifiers), | |
name: WebInspector.KeyboardShortcut.shortcutToString(key, modifiers) | |
}; | |
} | |
WebInspector.KeyboardShortcut.shortcutToString = function(key, modifiers) | |
{ | |
return WebInspector.KeyboardShortcut._modifiersToString(modifiers) + WebInspector.KeyboardShortcut._keyName(key); | |
} | |
WebInspector.KeyboardShortcut._keyName = function(key) | |
{ | |
if (typeof key === "string") | |
return key.toUpperCase(); | |
if (typeof key.name === "string") | |
return key.name; | |
return key.name[WebInspector.platform()] || key.name.other; | |
} | |
WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers = function(keyCode, modifiers) | |
{ | |
return (keyCode & 255) | (modifiers << 8); | |
}; | |
WebInspector.KeyboardShortcut._modifiersToString = function(modifiers) | |
{ | |
const cmdKey = "\u2318"; | |
const optKey = "\u2325"; | |
const shiftKey = "\u21e7"; | |
const ctrlKey = "\u2303"; | |
var isMac = WebInspector.isMac(); | |
var res = ""; | |
if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Ctrl) | |
res += isMac ? ctrlKey : "<Ctrl> + "; | |
if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Alt) | |
res += isMac ? optKey : "<Alt> + "; | |
if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Shift) | |
res += isMac ? shiftKey : "<Shift> + "; | |
if (modifiers & WebInspector.KeyboardShortcut.Modifiers.Meta) | |
res += isMac ? cmdKey : "<Win> + "; | |
return res; | |
}; | |
WebInspector.TextPrompt = function(completions, stopCharacters) | |
{ | |
this._proxyElement; | |
this._proxyElementDisplay = "inline-block"; | |
this._loadCompletions = completions; | |
this._completionStopCharacters = stopCharacters; | |
this._suggestForceable = true; | |
} | |
WebInspector.TextPrompt.Events = { | |
ItemApplied: "text-prompt-item-applied", | |
ItemAccepted: "text-prompt-item-accepted" | |
}; | |
WebInspector.TextPrompt.prototype = { | |
get proxyElement() | |
{ | |
return this._proxyElement; | |
}, | |
setSuggestForceable: function(x) | |
{ | |
this._suggestForceable = x; | |
}, | |
setSuggestBoxEnabled: function(className) | |
{ | |
this._suggestBoxClassName = className; | |
}, | |
renderAsBlock: function() | |
{ | |
this._proxyElementDisplay = "block"; | |
}, | |
attach: function(element) | |
{ | |
return this._attachInternal(element); | |
}, | |
attachAndStartEditing: function(element, blurListener) | |
{ | |
this._attachInternal(element); | |
this._startEditing(blurListener); | |
return this.proxyElement; | |
}, | |
_attachInternal: function(element) | |
{ | |
if (this.proxyElement) | |
throw "Cannot attach an attached TextPrompt"; | |
this._element = element; | |
this._boundOnKeyDown = this.onKeyDown.bind(this); | |
this._boundOnMouseWheel = this.onMouseWheel.bind(this); | |
this._boundSelectStart = this._selectStart.bind(this); | |
this._proxyElement = element.ownerDocument.createElement("span"); | |
this._proxyElement.style.display = this._proxyElementDisplay; | |
element.parentElement.insertBefore(this.proxyElement, element); | |
this.proxyElement.appendChild(element); | |
this._element.addStyleClass("text-prompt"); | |
this._element.addEventListener("keydown", this._boundOnKeyDown, false); | |
this._element.addEventListener("mousewheel", this._boundOnMouseWheel, false); | |
this._element.addEventListener("selectstart", this._boundSelectStart, false); | |
if (typeof this._suggestBoxClassName === "string") | |
this._suggestBox = new WebInspector.TextPrompt.SuggestBox(this, this._element, this._suggestBoxClassName); | |
return this.proxyElement; | |
}, | |
detach: function() | |
{ | |
this._removeFromElement(); | |
this.proxyElement.parentElement.insertBefore(this._element, this.proxyElement); | |
this.proxyElement.parentElement.removeChild(this.proxyElement); | |
this._element.removeStyleClass("text-prompt"); | |
this._element.removeEventListener("keydown", this._boundOnKeyDown, false); | |
this._element.removeEventListener("mousewheel", this._boundOnMouseWheel, false); | |
this._element.removeEventListener("selectstart", this._boundSelectStart, false); | |
delete this._proxyElement; | |
WebInspector.restoreFocusFromElement(this._element); | |
}, | |
get text() | |
{ | |
return this._element.textContent; | |
}, | |
set text(x) | |
{ | |
this._removeSuggestionAids(); | |
if (!x) { | |
this._element.removeChildren(); | |
this._element.appendChild(document.createElement("br")); | |
} else | |
this._element.textContent = x; | |
this.moveCaretToEndOfPrompt(); | |
this._element.scrollIntoView(); | |
}, | |
_removeFromElement: function() | |
{ | |
this.clearAutoComplete(true); | |
this._element.removeEventListener("keydown", this._boundOnKeyDown, false); | |
this._element.removeEventListener("selectstart", this._boundSelectStart, false); | |
if (this._isEditing) | |
this._stopEditing(); | |
if (this._suggestBox) | |
this._suggestBox.removeFromElement(); | |
}, | |
_startEditing: function(blurListener) | |
{ | |
this._isEditing = true; | |
this._element.addStyleClass("editing"); | |
if (blurListener) { | |
this._blurListener = blurListener; | |
this._element.addEventListener("blur", this._blurListener, false); | |
} | |
this._oldTabIndex = this._element.tabIndex; | |
if (this._element.tabIndex < 0) | |
this._element.tabIndex = 0; | |
WebInspector.setCurrentFocusElement(this._element); | |
}, | |
_stopEditing: function() | |
{ | |
this._element.tabIndex = this._oldTabIndex; | |
if (this._blurListener) | |
this._element.removeEventListener("blur", this._blurListener, false); | |
this._element.removeStyleClass("editing"); | |
delete this._isEditing; | |
}, | |
_removeSuggestionAids: function() | |
{ | |
this.clearAutoComplete(); | |
this.hideSuggestBox(); | |
}, | |
_selectStart: function(event) | |
{ | |
if (this._selectionTimeout) | |
clearTimeout(this._selectionTimeout); | |
this._removeSuggestionAids(); | |
function moveBackIfOutside() | |
{ | |
delete this._selectionTimeout; | |
if (!this.isCaretInsidePrompt() && window.getSelection().isCollapsed) { | |
this.moveCaretToEndOfPrompt(); | |
this.autoCompleteSoon(); | |
} | |
} | |
this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100); | |
}, | |
defaultKeyHandler: function(event, force) | |
{ | |
this.clearAutoComplete(); | |
this.autoCompleteSoon(force); | |
return false; | |
}, | |
onMouseWheel: function(event) | |
{ | |
}, | |
onKeyDown: function(event) | |
{ | |
var handled = false; | |
var invokeDefault = true; | |
switch (event.keyIdentifier) { | |
case "Up": | |
handled = this.upKeyPressed(event); | |
break; | |
case "Down": | |
handled = this.downKeyPressed(event); | |
break; | |
case "PageUp": | |
handled = this.pageUpKeyPressed(event); | |
break; | |
case "PageDown": | |
handled = this.pageDownKeyPressed(event); | |
break; | |
case "U+0009": | |
handled = this.tabKeyPressed(event); | |
break; | |
case "Enter": | |
handled = this.enterKeyPressed(event); | |
break; | |
case "Left": | |
case "Home": | |
this._removeSuggestionAids(); | |
invokeDefault = false; | |
break; | |
case "Right": | |
case "End": | |
if (this.isCaretAtEndOfPrompt()) | |
handled = this.acceptAutoComplete(); | |
else | |
this._removeSuggestionAids(); | |
invokeDefault = false; | |
break; | |
case "U+001B": | |
if (this.isSuggestBoxVisible()) { | |
this._suggestBox.hide(); | |
handled = true; | |
} | |
break; | |
case "U+0020": | |
if (this._suggestForceable && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { | |
this.defaultKeyHandler(event, true); | |
handled = true; | |
} | |
break; | |
case "Alt": | |
case "Meta": | |
case "Shift": | |
case "Control": | |
invokeDefault = false; | |
break; | |
} | |
if (!handled && invokeDefault) | |
handled = this.defaultKeyHandler(event); | |
if (handled) | |
event.consume(true); | |
return handled; | |
}, | |
acceptAutoComplete: function() | |
{ | |
var result = false; | |
if (this.isSuggestBoxVisible()) | |
result = this._suggestBox.acceptSuggestion(); | |
if (!result) | |
result = this.acceptSuggestion(); | |
return result; | |
}, | |
clearAutoComplete: function(includeTimeout) | |
{ | |
if (includeTimeout && this._completeTimeout) { | |
clearTimeout(this._completeTimeout); | |
delete this._completeTimeout; | |
} | |
delete this._waitingForCompletions; | |
if (!this.autoCompleteElement) | |
return; | |
if (this.autoCompleteElement.parentNode) | |
this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement); | |
delete this.autoCompleteElement; | |
if (!this._userEnteredRange || !this._userEnteredText) | |
return; | |
this._userEnteredRange.deleteContents(); | |
this._element.pruneEmptyTextNodes(); | |
var userTextNode = document.createTextNode(this._userEnteredText); | |
this._userEnteredRange.insertNode(userTextNode); | |
var selectionRange = document.createRange(); | |
selectionRange.setStart(userTextNode, this._userEnteredText.length); | |
selectionRange.setEnd(userTextNode, this._userEnteredText.length); | |
var selection = window.getSelection(); | |
selection.removeAllRanges(); | |
selection.addRange(selectionRange); | |
delete this._userEnteredRange; | |
delete this._userEnteredText; | |
}, | |
autoCompleteSoon: function(force) | |
{ | |
var immediately = this.isSuggestBoxVisible() || force; | |
if (!this._completeTimeout) | |
this._completeTimeout = setTimeout(this.complete.bind(this, true, force), immediately ? 0 : 250); | |
}, | |
complete: function(auto, force, reverse) | |
{ | |
this.clearAutoComplete(true); | |
var selection = window.getSelection(); | |
if (!selection.rangeCount) | |
return; | |
var selectionRange = selection.getRangeAt(0); | |
var isEmptyInput = selectionRange.commonAncestorContainer === this._element; | |
var shouldExit; | |
if (auto && isEmptyInput && !force) | |
shouldExit = true; | |
else if (!auto && !isEmptyInput && !selectionRange.commonAncestorContainer.isDescendant(this._element)) | |
shouldExit = true; | |
else if (auto && !force && !this.isCaretAtEndOfPrompt() && !this.isSuggestBoxVisible()) | |
shouldExit = true; | |
else if (!selection.isCollapsed) | |
shouldExit = true; | |
else if (!force) { | |
var wordSuffixRange = selectionRange.startContainer.rangeOfWord(selectionRange.endOffset, this._completionStopCharacters, this._element, "forward"); | |
if (wordSuffixRange.toString().length) | |
shouldExit = true; | |
} | |
if (shouldExit) { | |
this.hideSuggestBox(); | |
return; | |
} | |
var wordPrefixRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, this._completionStopCharacters, this._element, "backward"); | |
this._waitingForCompletions = true; | |
this._loadCompletions(this, wordPrefixRange, force, this._completionsReady.bind(this, selection, auto, wordPrefixRange, !!reverse)); | |
}, | |
_boxForAnchorAtStart: function(selection, textRange) | |
{ | |
var rangeCopy = selection.getRangeAt(0).cloneRange(); | |
var anchorElement = document.createElement("span"); | |
anchorElement.textContent = "\u200B"; | |
textRange.insertNode(anchorElement); | |
var box = anchorElement.boxInWindow(window); | |
anchorElement.parentElement.removeChild(anchorElement); | |
selection.removeAllRanges(); | |
selection.addRange(rangeCopy); | |
return box; | |
}, | |
_buildCommonPrefix: function(completions, wordPrefixLength) | |
{ | |
var commonPrefix = completions[0]; | |
for (var i = 0; i < completions.length; ++i) { | |
var completion = completions[i]; | |
var lastIndex = Math.min(commonPrefix.length, completion.length); | |
for (var j = wordPrefixLength; j < lastIndex; ++j) { | |
if (commonPrefix[j] !== completion[j]) { | |
commonPrefix = commonPrefix.substr(0, j); | |
break; | |
} | |
} | |
} | |
return commonPrefix; | |
}, | |
_completionsReady: function(selection, auto, originalWordPrefixRange, reverse, completions) | |
{ | |
if (!this._waitingForCompletions || !completions || !completions.length) { | |
this.hideSuggestBox(); | |
return; | |
} | |
delete this._waitingForCompletions; | |
var selectionRange = selection.getRangeAt(0); | |
var fullWordRange = document.createRange(); | |
fullWordRange.setStart(originalWordPrefixRange.startContainer, originalWordPrefixRange.startOffset); | |
fullWordRange.setEnd(selectionRange.endContainer, selectionRange.endOffset); | |
if (originalWordPrefixRange.toString() + selectionRange.toString() != fullWordRange.toString()) | |
return; | |
this._userEnteredRange = fullWordRange; | |
this._userEnteredText = fullWordRange.toString(); | |
if (this._suggestBox) | |
this._suggestBox.updateSuggestions(this._boxForAnchorAtStart(selection, fullWordRange), completions, !this.isCaretAtEndOfPrompt()); | |
var wordPrefixLength = originalWordPrefixRange.toString().length; | |
if (auto) { | |
var completionText = completions[0]; | |
var commonPrefix = this._buildCommonPrefix(completions, wordPrefixLength); | |
this._commonPrefix = commonPrefix; | |
} else { | |
if (completions.length === 1) { | |
var completionText = completions[0]; | |
wordPrefixLength = completionText.length; | |
} else { | |
var commonPrefix = this._buildCommonPrefix(completions, wordPrefixLength); | |
wordPrefixLength = commonPrefix.length; | |
if (selection.isCollapsed) | |
var completionText = completions[0]; | |
else { | |
var currentText = fullWordRange.toString(); | |
var foundIndex = null; | |
for (var i = 0; i < completions.length; ++i) { | |
if (completions[i] === currentText) | |
foundIndex = i; | |
} | |
var nextIndex = foundIndex + (reverse ? -1 : 1); | |
if (foundIndex === null || nextIndex >= completions.length) | |
var completionText = completions[0]; | |
else if (nextIndex < 0) | |
var completionText = completions[completions.length - 1]; | |
else | |
var completionText = completions[nextIndex]; | |
} | |
} | |
} | |
if (auto) { | |
if (this.isCaretAtEndOfPrompt()) { | |
this._userEnteredRange.deleteContents(); | |
this._element.pruneEmptyTextNodes(); | |
var finalSelectionRange = document.createRange(); | |
var prefixText = completionText.substring(0, wordPrefixLength); | |
var suffixText = completionText.substring(wordPrefixLength); | |
var prefixTextNode = document.createTextNode(prefixText); | |
fullWordRange.insertNode(prefixTextNode); | |
this.autoCompleteElement = document.createElement("span"); | |
this.autoCompleteElement.className = "auto-complete-text"; | |
this.autoCompleteElement.textContent = suffixText; | |
prefixTextNode.parentNode.insertBefore(this.autoCompleteElement, prefixTextNode.nextSibling); | |
finalSelectionRange.setStart(prefixTextNode, wordPrefixLength); | |
finalSelectionRange.setEnd(prefixTextNode, wordPrefixLength); | |
selection.removeAllRanges(); | |
selection.addRange(finalSelectionRange); | |
} | |
} else | |
this.applySuggestion(completionText, completions.length > 1, originalWordPrefixRange); | |
}, | |
_completeCommonPrefix: function() | |
{ | |
if (!this.autoCompleteElement || !this._commonPrefix || !this._userEnteredText || !this._commonPrefix.startsWith(this._userEnteredText)) | |
return; | |
if (!this.isSuggestBoxVisible()) { | |
this.acceptAutoComplete(); | |
return; | |
} | |
this.autoCompleteElement.textContent = this._commonPrefix.substring(this._userEnteredText.length); | |
this.acceptSuggestion(true) | |
}, | |
applySuggestion: function(completionText, isIntermediateSuggestion, originalPrefixRange) | |
{ | |
var wordPrefixLength; | |
if (originalPrefixRange) | |
wordPrefixLength = originalPrefixRange.toString().length; | |
else | |
wordPrefixLength = this._userEnteredText ? this._userEnteredText.length : 0; | |
this._userEnteredRange.deleteContents(); | |
this._element.pruneEmptyTextNodes(); | |
var finalSelectionRange = document.createRange(); | |
var completionTextNode = document.createTextNode(completionText); | |
this._userEnteredRange.insertNode(completionTextNode); | |
if (this.autoCompleteElement && this.autoCompleteElement.parentNode) { | |
this.autoCompleteElement.parentNode.removeChild(this.autoCompleteElement); | |
delete this.autoCompleteElement; | |
} | |
if (isIntermediateSuggestion) | |
finalSelectionRange.setStart(completionTextNode, wordPrefixLength); | |
else | |
finalSelectionRange.setStart(completionTextNode, completionText.length); | |
finalSelectionRange.setEnd(completionTextNode, completionText.length); | |
var selection = window.getSelection(); | |
selection.removeAllRanges(); | |
selection.addRange(finalSelectionRange); | |
if (isIntermediateSuggestion) | |
this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemApplied, { itemText: completionText }); | |
}, | |
acceptSuggestion: function(prefixAccepted) | |
{ | |
if (this._isAcceptingSuggestion) | |
return false; | |
if (!this.autoCompleteElement || !this.autoCompleteElement.parentNode) | |
return false; | |
var text = this.autoCompleteElement.textContent; | |
var textNode = document.createTextNode(text); | |
this.autoCompleteElement.parentNode.replaceChild(textNode, this.autoCompleteElement); | |
delete this.autoCompleteElement; | |
var finalSelectionRange = document.createRange(); | |
finalSelectionRange.setStart(textNode, text.length); | |
finalSelectionRange.setEnd(textNode, text.length); | |
var selection = window.getSelection(); | |
selection.removeAllRanges(); | |
selection.addRange(finalSelectionRange); | |
if (!prefixAccepted) { | |
this.hideSuggestBox(); | |
this.dispatchEventToListeners(WebInspector.TextPrompt.Events.ItemAccepted); | |
} else | |
this.autoCompleteSoon(true); | |
return true; | |
}, | |
hideSuggestBox: function() | |
{ | |
if (this.isSuggestBoxVisible()) | |
this._suggestBox.hide(); | |
}, | |
isSuggestBoxVisible: function() | |
{ | |
return this._suggestBox && this._suggestBox.visible; | |
}, | |
isCaretInsidePrompt: function() | |
{ | |
return this._element.isInsertionCaretInside(); | |
}, | |
isCaretAtEndOfPrompt: function() | |
{ | |
var selection = window.getSelection(); | |
if (!selection.rangeCount || !selection.isCollapsed) | |
return false; | |
var selectionRange = selection.getRangeAt(0); | |
var node = selectionRange.startContainer; | |
if (!node.isSelfOrDescendant(this._element)) | |
return false; | |
if (node.nodeType === Node.TEXT_NODE && selectionRange.startOffset < node.nodeValue.length) | |
return false; | |
var foundNextText = false; | |
while (node) { | |
if (node.nodeType === Node.TEXT_NODE && node.nodeValue.length) { | |
if (foundNextText && (!this.autoCompleteElement || !this.autoCompleteElement.isAncestor(node))) | |
return false; | |
foundNextText = true; | |
} | |
node = node.traverseNextNode(this._element); | |
} | |
return true; | |
}, | |
isCaretOnFirstLine: function() | |
{ | |
var selection = window.getSelection(); | |
var focusNode = selection.focusNode; | |
if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element) | |
return true; | |
if (focusNode.textContent.substring(0, selection.focusOffset).indexOf("\n") !== -1) | |
return false; | |
focusNode = focusNode.previousSibling; | |
while (focusNode) { | |
if (focusNode.nodeType !== Node.TEXT_NODE) | |
return true; | |
if (focusNode.textContent.indexOf("\n") !== -1) | |
return false; | |
focusNode = focusNode.previousSibling; | |
} | |
return true; | |
}, | |
isCaretOnLastLine: function() | |
{ | |
var selection = window.getSelection(); | |
var focusNode = selection.focusNode; | |
if (!focusNode || focusNode.nodeType !== Node.TEXT_NODE || focusNode.parentNode !== this._element) | |
return true; | |
if (focusNode.textContent.substring(selection.focusOffset).indexOf("\n") !== -1) | |
return false; | |
focusNode = focusNode.nextSibling; | |
while (focusNode) { | |
if (focusNode.nodeType !== Node.TEXT_NODE) | |
return true; | |
if (focusNode.textContent.indexOf("\n") !== -1) | |
return false; | |
focusNode = focusNode.nextSibling; | |
} | |
return true; | |
}, | |
moveCaretToEndOfPrompt: function() | |
{ | |
var selection = window.getSelection(); | |
var selectionRange = document.createRange(); | |
var offset = this._element.childNodes.length; | |
selectionRange.setStart(this._element, offset); | |
selectionRange.setEnd(this._element, offset); | |
selection.removeAllRanges(); | |
selection.addRange(selectionRange); | |
}, | |
tabKeyPressed: function(event) | |
{ | |
this._completeCommonPrefix(); | |
return true; | |
}, | |
enterKeyPressed: function(event) | |
{ | |
if (this.isSuggestBoxVisible()) | |
return this._suggestBox.enterKeyPressed(event); | |
return false; | |
}, | |
upKeyPressed: function(event) | |
{ | |
if (this.isSuggestBoxVisible()) | |
return this._suggestBox.upKeyPressed(event); | |
return false; | |
}, | |
downKeyPressed: function(event) | |
{ | |
if (this.isSuggestBoxVisible()) | |
return this._suggestBox.downKeyPressed(event); | |
return false; | |
}, | |
pageUpKeyPressed: function(event) | |
{ | |
if (this.isSuggestBoxVisible()) | |
return this._suggestBox.pageUpKeyPressed(event); | |
return false; | |
}, | |
pageDownKeyPressed: function(event) | |
{ | |
if (this.isSuggestBoxVisible()) | |
return this._suggestBox.pageDownKeyPressed(event); | |
return false; | |
}, | |
} | |
WebInspector.TextPrompt.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.TextPromptWithHistory = function(completions, stopCharacters) | |
{ | |
WebInspector.TextPrompt.call(this, completions, stopCharacters); | |
this._data = []; | |
this._historyOffset = 1; | |
this._coalesceHistoryDupes = true; | |
} | |
WebInspector.TextPromptWithHistory.prototype = { | |
get historyData() | |
{ | |
return this._data; | |
}, | |
setCoalesceHistoryDupes: function(x) | |
{ | |
this._coalesceHistoryDupes = x; | |
}, | |
setHistoryData: function(data) | |
{ | |
this._data = [].concat(data); | |
this._historyOffset = 1; | |
}, | |
pushHistoryItem: function(text) | |
{ | |
if (this._uncommittedIsTop) { | |
this._data.pop(); | |
delete this._uncommittedIsTop; | |
} | |
this._historyOffset = 1; | |
if (this._coalesceHistoryDupes && text === this._currentHistoryItem()) | |
return; | |
this._data.push(text); | |
}, | |
_pushCurrentText: function() | |
{ | |
if (this._uncommittedIsTop) | |
this._data.pop(); | |
this._uncommittedIsTop = true; | |
this.clearAutoComplete(true); | |
this._data.push(this.text); | |
}, | |
_previous: function() | |
{ | |
if (this._historyOffset > this._data.length) | |
return undefined; | |
if (this._historyOffset === 1) | |
this._pushCurrentText(); | |
++this._historyOffset; | |
return this._currentHistoryItem(); | |
}, | |
_next: function() | |
{ | |
if (this._historyOffset === 1) | |
return undefined; | |
--this._historyOffset; | |
return this._currentHistoryItem(); | |
}, | |
_currentHistoryItem: function() | |
{ | |
return this._data[this._data.length - this._historyOffset]; | |
}, | |
defaultKeyHandler: function(event, force) | |
{ | |
var newText; | |
var isPrevious; | |
switch (event.keyIdentifier) { | |
case "Up": | |
if (!this.isCaretOnFirstLine()) | |
break; | |
newText = this._previous(); | |
isPrevious = true; | |
break; | |
case "Down": | |
if (!this.isCaretOnLastLine()) | |
break; | |
newText = this._next(); | |
break; | |
case "U+0050": | |
if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { | |
newText = this._previous(); | |
isPrevious = true; | |
} | |
break; | |
case "U+004E": | |
if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) | |
newText = this._next(); | |
break; | |
} | |
if (newText !== undefined) { | |
event.consume(true); | |
this.text = newText; | |
if (isPrevious) { | |
var firstNewlineIndex = this.text.indexOf("\n"); | |
if (firstNewlineIndex === -1) | |
this.moveCaretToEndOfPrompt(); | |
else { | |
var selection = window.getSelection(); | |
var selectionRange = document.createRange(); | |
selectionRange.setStart(this._element.firstChild, firstNewlineIndex); | |
selectionRange.setEnd(this._element.firstChild, firstNewlineIndex); | |
selection.removeAllRanges(); | |
selection.addRange(selectionRange); | |
} | |
} | |
return true; | |
} | |
return WebInspector.TextPrompt.prototype.defaultKeyHandler.apply(this, arguments); | |
} | |
} | |
WebInspector.TextPromptWithHistory.prototype.__proto__ = WebInspector.TextPrompt.prototype; | |
WebInspector.TextPrompt.SuggestBox = function(textPrompt, inputElement, className) | |
{ | |
this._textPrompt = textPrompt; | |
this._inputElement = inputElement; | |
this._selectedElement = null; | |
this._boundOnScroll = this._onscrollresize.bind(this, true); | |
this._boundOnResize = this._onscrollresize.bind(this, false); | |
window.addEventListener("scroll", this._boundOnScroll, true); | |
window.addEventListener("resize", this._boundOnResize, true); | |
this._bodyElement = inputElement.ownerDocument.body; | |
this._element = inputElement.ownerDocument.createElement("div"); | |
this._element.className = "suggest-box " + (className || ""); | |
this._element.addEventListener("mousedown", this._onboxmousedown.bind(this), true); | |
this.containerElement = this._element.createChild("div", "container"); | |
this.contentElement = this.containerElement.createChild("div", "content"); | |
} | |
WebInspector.TextPrompt.SuggestBox.prototype = { | |
get visible() | |
{ | |
return !!this._element.parentElement; | |
}, | |
get hasSelection() | |
{ | |
return !!this._selectedElement; | |
}, | |
_onscrollresize: function(isScroll, event) | |
{ | |
if (isScroll && this._element.isAncestor(event.target) || !this.visible) | |
return; | |
this._updateBoxPositionWithExistingAnchor(); | |
}, | |
_updateBoxPositionWithExistingAnchor: function() | |
{ | |
this._updateBoxPosition(this._anchorBox); | |
}, | |
_updateBoxPosition: function(anchorBox) | |
{ | |
this.contentElement.style.display = "inline-block"; | |
document.body.appendChild(this.contentElement); | |
this.contentElement.positionAt(0, 0); | |
var contentWidth = this.contentElement.offsetWidth; | |
var contentHeight = this.contentElement.offsetHeight; | |
this.contentElement.style.display = "block"; | |
this.containerElement.appendChild(this.contentElement); | |
this._anchorBox = anchorBox; | |
const spacer = 6; | |
const suggestBoxPaddingX = 21; | |
var maxWidth = document.body.offsetWidth - anchorBox.x - spacer; | |
var width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX; | |
var paddedWidth = contentWidth + suggestBoxPaddingX; | |
var boxX = anchorBox.x; | |
if (width < paddedWidth) { | |
maxWidth = document.body.offsetWidth - spacer; | |
width = Math.min(contentWidth, maxWidth - suggestBoxPaddingX) + suggestBoxPaddingX; | |
boxX = document.body.offsetWidth - width; | |
} | |
const suggestBoxPaddingY = 2; | |
var boxY; | |
var aboveHeight = anchorBox.y; | |
var underHeight = document.body.offsetHeight - anchorBox.y - anchorBox.height; | |
var maxHeight = Math.max(underHeight, aboveHeight) - spacer; | |
var height = Math.min(contentHeight, maxHeight - suggestBoxPaddingY) + suggestBoxPaddingY; | |
if (underHeight >= aboveHeight) { | |
boxY = anchorBox.y + anchorBox.height; | |
this._element.removeStyleClass("above-anchor"); | |
this._element.addStyleClass("under-anchor"); | |
} else { | |
boxY = anchorBox.y - height; | |
this._element.removeStyleClass("under-anchor"); | |
this._element.addStyleClass("above-anchor"); | |
} | |
this._element.positionAt(boxX, boxY); | |
this._element.style.width = width + "px"; | |
this._element.style.height = height + "px"; | |
}, | |
_onboxmousedown: function(event) | |
{ | |
event.preventDefault(); | |
}, | |
hide: function() | |
{ | |
if (!this.visible) | |
return; | |
this._element.parentElement.removeChild(this._element); | |
delete this._selectedElement; | |
}, | |
removeFromElement: function() | |
{ | |
window.removeEventListener("scroll", this._boundOnScroll, true); | |
window.removeEventListener("resize", this._boundOnResize, true); | |
this.hide(); | |
}, | |
_applySuggestion: function(text, isIntermediateSuggestion) | |
{ | |
if (!this.visible || !(text || this._selectedElement)) | |
return false; | |
var suggestion = text || this._selectedElement.textContent; | |
if (!suggestion) | |
return false; | |
this._textPrompt.applySuggestion(suggestion, isIntermediateSuggestion); | |
return true; | |
}, | |
acceptSuggestion: function(text) | |
{ | |
var result = this._applySuggestion(text, false); | |
this.hide(); | |
if (!result) | |
return false; | |
this._textPrompt.acceptSuggestion(); | |
return true; | |
}, | |
_onNextItem: function(event, isPageScroll) | |
{ | |
var children = this.contentElement.childNodes; | |
if (!children.length) | |
return false; | |
if (!this._selectedElement) | |
this._selectedElement = this.contentElement.firstChild; | |
else { | |
if (!isPageScroll) | |
this._selectedElement = this._selectedElement.nextSibling || this.contentElement.firstChild; | |
else { | |
var candidate = this._selectedElement; | |
for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) { | |
if (candidate.nextSibling) | |
candidate = candidate.nextSibling; | |
else | |
break; | |
} | |
this._selectedElement = candidate; | |
} | |
} | |
this._updateSelection(); | |
this._applySuggestion(undefined, true); | |
return true; | |
}, | |
_onPreviousItem: function(event, isPageScroll) | |
{ | |
var children = this.contentElement.childNodes; | |
if (!children.length) | |
return false; | |
if (!this._selectedElement) | |
this._selectedElement = this.contentElement.lastChild; | |
else { | |
if (!isPageScroll) | |
this._selectedElement = this._selectedElement.previousSibling || this.contentElement.lastChild; | |
else { | |
var candidate = this._selectedElement; | |
for (var itemsLeft = this._rowCountPerViewport; itemsLeft; --itemsLeft) { | |
if (candidate.previousSibling) | |
candidate = candidate.previousSibling; | |
else | |
break; | |
} | |
this._selectedElement = candidate; | |
} | |
} | |
this._updateSelection(); | |
this._applySuggestion(undefined, true); | |
return true; | |
}, | |
updateSuggestions: function(anchorBox, completions, canShowForSingleItem) | |
{ | |
if (this._suggestTimeout) { | |
clearTimeout(this._suggestTimeout); | |
delete this._suggestTimeout; | |
} | |
this._completionsReady(anchorBox, completions, canShowForSingleItem); | |
}, | |
_onItemMouseDown: function(text, event) | |
{ | |
this.acceptSuggestion(text); | |
event.consume(true); | |
}, | |
_createItemElement: function(prefix, text) | |
{ | |
var element = document.createElement("div"); | |
element.className = "suggest-box-content-item source-code"; | |
element.tabIndex = -1; | |
if (prefix && prefix.length && !text.indexOf(prefix)) { | |
var prefixElement = element.createChild("span", "prefix"); | |
prefixElement.textContent = prefix; | |
var suffixElement = element.createChild("span", "suffix"); | |
suffixElement.textContent = text.substring(prefix.length); | |
} else { | |
var suffixElement = element.createChild("span", "suffix"); | |
suffixElement.textContent = text; | |
} | |
element.addEventListener("mousedown", this._onItemMouseDown.bind(this, text), false); | |
return element; | |
}, | |
_updateItems: function(items, canShowForSingleItem) | |
{ | |
this.contentElement.removeChildren(); | |
var userEnteredText = this._textPrompt._userEnteredText; | |
for (var i = 0; i < items.length; ++i) { | |
var item = items[i]; | |
var currentItemElement = this._createItemElement(userEnteredText, item); | |
this.contentElement.appendChild(currentItemElement); | |
} | |
this._selectedElement = canShowForSingleItem ? this.contentElement.firstChild : null; | |
this._updateSelection(); | |
}, | |
_updateSelection: function() | |
{ | |
for (var child = this.contentElement.firstChild; child; child = child.nextSibling) { | |
if (child !== this._selectedElement) | |
child.removeStyleClass("selected"); | |
} | |
if (this._selectedElement) { | |
this._selectedElement.addStyleClass("selected"); | |
this._selectedElement.scrollIntoViewIfNeeded(false); | |
} | |
}, | |
_canShowBox: function(completions, canShowForSingleItem) | |
{ | |
if (!completions || !completions.length) | |
return false; | |
if (completions.length > 1) | |
return true; | |
return canShowForSingleItem && completions[0] !== this._textPrompt._userEnteredText; | |
}, | |
_rememberRowCountPerViewport: function() | |
{ | |
if (!this.contentElement.firstChild) | |
return; | |
this._rowCountPerViewport = Math.floor(this.containerElement.offsetHeight / this.contentElement.firstChild.offsetHeight); | |
}, | |
_completionsReady: function(anchorBox, completions, canShowForSingleItem) | |
{ | |
if (this._canShowBox(completions, canShowForSingleItem)) { | |
this._updateItems(completions, canShowForSingleItem); | |
this._updateBoxPosition(anchorBox); | |
if (!this.visible) | |
this._bodyElement.appendChild(this._element); | |
this._rememberRowCountPerViewport(); | |
} else | |
this.hide(); | |
}, | |
upKeyPressed: function(event) | |
{ | |
return this._onPreviousItem(event, false); | |
}, | |
downKeyPressed: function(event) | |
{ | |
return this._onNextItem(event, false); | |
}, | |
pageUpKeyPressed: function(event) | |
{ | |
return this._onPreviousItem(event, true); | |
}, | |
pageDownKeyPressed: function(event) | |
{ | |
return this._onNextItem(event, true); | |
}, | |
enterKeyPressed: function(event) | |
{ | |
var hasSelectedItem = !!this._selectedElement; | |
this.acceptSuggestion(); | |
return hasSelectedItem; | |
}, | |
tabKeyPressed: function(event) | |
{ | |
return this.enterKeyPressed(event); | |
} | |
} | |
WebInspector.Popover = function(popoverHelper) | |
{ | |
this.element = document.createElement("div"); | |
this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll"; | |
this._popupArrowElement = document.createElement("div"); | |
this._popupArrowElement.className = "arrow"; | |
this.element.appendChild(this._popupArrowElement); | |
this._contentDiv = document.createElement("div"); | |
this._contentDiv.className = "content"; | |
this._visible = false; | |
this._popoverHelper = popoverHelper; | |
} | |
WebInspector.Popover.prototype = { | |
show: function(contentElement, anchor, preferredWidth, preferredHeight) | |
{ | |
if (this._disposed) | |
return; | |
this.contentElement = contentElement; | |
if (WebInspector.Popover._popoverElement) | |
document.body.removeChild(WebInspector.Popover._popoverElement); | |
WebInspector.Popover._popoverElement = this.element; | |
this.contentElement.positionAt(0, 0); | |
document.body.appendChild(this.contentElement); | |
preferredWidth = preferredWidth || this.contentElement.offsetWidth; | |
preferredHeight = preferredHeight || this.contentElement.offsetHeight; | |
this._contentDiv.appendChild(this.contentElement); | |
this.element.appendChild(this._contentDiv); | |
document.body.appendChild(this.element); | |
this._positionElement(anchor, preferredWidth, preferredHeight); | |
this._visible = true; | |
if (this._popoverHelper) | |
contentElement.addEventListener("mousemove", this._popoverHelper._killHidePopoverTimer.bind(this._popoverHelper), true); | |
}, | |
hide: function() | |
{ | |
if (WebInspector.Popover._popoverElement) { | |
delete WebInspector.Popover._popoverElement; | |
document.body.removeChild(this.element); | |
} | |
this._visible = false; | |
}, | |
get visible() | |
{ | |
return this._visible; | |
}, | |
get disposed() | |
{ | |
return this._disposed; | |
}, | |
dispose: function() | |
{ | |
if (this.visible) | |
this.hide(); | |
this._disposed = true; | |
}, | |
setCanShrink: function(canShrink) | |
{ | |
this._hasFixedHeight = !canShrink; | |
this._contentDiv.addStyleClass("fixed-height"); | |
}, | |
_positionElement: function(anchorElement, preferredWidth, preferredHeight) | |
{ | |
const borderWidth = 25; | |
const scrollerWidth = this._hasFixedHeight ? 0 : 11; | |
const arrowHeight = 15; | |
const arrowOffset = 10; | |
const borderRadius = 10; | |
preferredWidth = Math.max(preferredWidth, 50); | |
const totalWidth = window.innerWidth; | |
const totalHeight = window.innerHeight; | |
var anchorBox = anchorElement.boxInWindow(window); | |
var newElementPosition = { x: 0, y: 0, width: preferredWidth + scrollerWidth, height: preferredHeight }; | |
var verticalAlignment; | |
var roomAbove = anchorBox.y; | |
var roomBelow = totalHeight - anchorBox.y - anchorBox.height; | |
if (roomAbove > roomBelow) { | |
if (anchorBox.y > newElementPosition.height + arrowHeight + borderRadius) | |
newElementPosition.y = anchorBox.y - newElementPosition.height - arrowHeight; | |
else { | |
newElementPosition.y = borderRadius; | |
newElementPosition.height = anchorBox.y - borderRadius * 2 - arrowHeight; | |
if (this._hasFixedHeight && newElementPosition.height < preferredHeight) { | |
newElementPosition.y = borderRadius; | |
newElementPosition.height = preferredHeight; | |
} | |
} | |
verticalAlignment = "bottom"; | |
} else { | |
newElementPosition.y = anchorBox.y + anchorBox.height + arrowHeight; | |
if (newElementPosition.y + newElementPosition.height + arrowHeight - borderWidth >= totalHeight) { | |
newElementPosition.height = totalHeight - anchorBox.y - anchorBox.height - borderRadius * 2 - arrowHeight; | |
if (this._hasFixedHeight && newElementPosition.height < preferredHeight) { | |
newElementPosition.y = totalHeight - preferredHeight - borderRadius; | |
newElementPosition.height = preferredHeight; | |
} | |
} | |
verticalAlignment = "top"; | |
} | |
var horizontalAlignment; | |
if (anchorBox.x + newElementPosition.width < totalWidth) { | |
newElementPosition.x = Math.max(borderRadius, anchorBox.x - borderRadius - arrowOffset); | |
horizontalAlignment = "left"; | |
} else if (newElementPosition.width + borderRadius * 2 < totalWidth) { | |
newElementPosition.x = totalWidth - newElementPosition.width - borderRadius; | |
horizontalAlignment = "right"; | |
var arrowRightPosition = Math.max(0, totalWidth - anchorBox.x - anchorBox.width - borderRadius - arrowOffset); | |
arrowRightPosition += anchorBox.width / 2; | |
arrowRightPosition = Math.min(arrowRightPosition, newElementPosition.width - borderRadius - arrowOffset); | |
this._popupArrowElement.style.right = arrowRightPosition + "px"; | |
} else { | |
newElementPosition.x = borderRadius; | |
newElementPosition.width = totalWidth - borderRadius * 2; | |
newElementPosition.height += scrollerWidth; | |
horizontalAlignment = "left"; | |
if (verticalAlignment === "bottom") | |
newElementPosition.y -= scrollerWidth; | |
this._popupArrowElement.style.left = Math.max(0, anchorBox.x - borderRadius * 2 - arrowOffset) + "px"; | |
this._popupArrowElement.style.left += anchorBox.width / 2; | |
} | |
this.element.className = "popover custom-popup-vertical-scroll custom-popup-horizontal-scroll " + verticalAlignment + "-" + horizontalAlignment + "-arrow"; | |
this.element.positionAt(newElementPosition.x - borderWidth, newElementPosition.y - borderWidth); | |
this.element.style.width = newElementPosition.width + borderWidth * 2 + "px"; | |
this.element.style.height = newElementPosition.height + borderWidth * 2 + "px"; | |
} | |
} | |
WebInspector.PopoverHelper = function(panelElement, getAnchor, showPopover, onHide, disableOnClick) | |
{ | |
this._panelElement = panelElement; | |
this._getAnchor = getAnchor; | |
this._showPopover = showPopover; | |
this._onHide = onHide; | |
this._disableOnClick = !!disableOnClick; | |
panelElement.addEventListener("mousedown", this._mouseDown.bind(this), false); | |
panelElement.addEventListener("mousemove", this._mouseMove.bind(this), false); | |
panelElement.addEventListener("mouseout", this._mouseOut.bind(this), false); | |
this.setTimeout(1000); | |
} | |
WebInspector.PopoverHelper.prototype = { | |
setTimeout: function(timeout) | |
{ | |
this._timeout = timeout; | |
}, | |
_mouseDown: function(event) | |
{ | |
if (this._disableOnClick || !event.target.isSelfOrDescendant(this._hoverElement)) | |
this.hidePopover(); | |
else { | |
this._killHidePopoverTimer(); | |
this._handleMouseAction(event, true); | |
} | |
}, | |
_mouseMove: function(event) | |
{ | |
if (event.target.isSelfOrDescendant(this._hoverElement)) | |
return; | |
this._startHidePopoverTimer(); | |
this._handleMouseAction(event, false); | |
}, | |
_mouseOut: function(event) | |
{ | |
if (event.target === this._hoverElement) | |
this._startHidePopoverTimer(); | |
}, | |
_startHidePopoverTimer: function() | |
{ | |
if (!this._popover || this._hidePopoverTimer) | |
return; | |
function doHide() | |
{ | |
this._hidePopover(); | |
delete this._hidePopoverTimer; | |
} | |
this._hidePopoverTimer = setTimeout(doHide.bind(this), this._timeout / 2); | |
}, | |
_handleMouseAction: function(event, isMouseDown) | |
{ | |
this._resetHoverTimer(); | |
if (event.which && this._disableOnClick) | |
return; | |
this._hoverElement = this._getAnchor(event.target, event); | |
if (!this._hoverElement) | |
return; | |
const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout); | |
this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay); | |
}, | |
_resetHoverTimer: function() | |
{ | |
if (this._hoverTimer) { | |
clearTimeout(this._hoverTimer); | |
delete this._hoverTimer; | |
} | |
}, | |
isPopoverVisible: function() | |
{ | |
return !!this._popover; | |
}, | |
hidePopover: function() | |
{ | |
this._resetHoverTimer(); | |
this._hidePopover(); | |
}, | |
_hidePopover: function() | |
{ | |
if (!this._popover) | |
return; | |
if (this._onHide) | |
this._onHide(); | |
this._popover.dispose(); | |
delete this._popover; | |
this._hoverElement = null; | |
}, | |
_mouseHover: function(element) | |
{ | |
delete this._hoverTimer; | |
this._hidePopover(); | |
this._popover = new WebInspector.Popover(this); | |
this._showPopover(element, this._popover); | |
}, | |
_killHidePopoverTimer: function() | |
{ | |
if (this._hidePopoverTimer) { | |
clearTimeout(this._hidePopoverTimer); | |
delete this._hidePopoverTimer; | |
this._resetHoverTimer(); | |
} | |
} | |
} | |
WebInspector.Placard = function(title, subtitle) | |
{ | |
this.element = document.createElement("div"); | |
this.element.className = "placard"; | |
this.element.placard = this; | |
this.titleElement = document.createElement("div"); | |
this.titleElement.className = "title"; | |
this.subtitleElement = document.createElement("div"); | |
this.subtitleElement.className = "subtitle"; | |
this.element.appendChild(this.subtitleElement); | |
this.element.appendChild(this.titleElement); | |
this.title = title; | |
this.subtitle = subtitle; | |
this.selected = false; | |
} | |
WebInspector.Placard.prototype = { | |
get title() | |
{ | |
return this._title; | |
}, | |
set title(x) | |
{ | |
if (this._title === x) | |
return; | |
this._title = x; | |
this.titleElement.textContent = x; | |
}, | |
get subtitle() | |
{ | |
return this._subtitle; | |
}, | |
set subtitle(x) | |
{ | |
if (this._subtitle === x) | |
return; | |
this._subtitle = x; | |
this.subtitleElement.textContent = x; | |
}, | |
get selected() | |
{ | |
return this._selected; | |
}, | |
set selected(x) | |
{ | |
if (x) | |
this.select(); | |
else | |
this.deselect(); | |
}, | |
select: function() | |
{ | |
if (this._selected) | |
return; | |
this._selected = true; | |
this.element.addStyleClass("selected"); | |
}, | |
deselect: function() | |
{ | |
if (!this._selected) | |
return; | |
this._selected = false; | |
this.element.removeStyleClass("selected"); | |
}, | |
toggleSelected: function() | |
{ | |
this.selected = !this.selected; | |
}, | |
discard: function() | |
{ | |
} | |
} | |
WebInspector.TabbedPane = function() | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("tabbedPane.css"); | |
this.element.addStyleClass("tabbed-pane"); | |
this._headerElement = this.element.createChild("div", "tabbed-pane-header"); | |
this._headerContentsElement = this._headerElement.createChild("div", "tabbed-pane-header-contents"); | |
this._tabsElement = this._headerContentsElement.createChild("div", "tabbed-pane-header-tabs"); | |
this._contentElement = this.element.createChild("div", "tabbed-pane-content"); | |
this._tabs = []; | |
this._tabsHistory = []; | |
this._tabsById = {}; | |
this.element.addEventListener("click", this.focus.bind(this), false); | |
this._dropDownButton = this._createDropDownButton(); | |
} | |
WebInspector.TabbedPane.EventTypes = { | |
TabSelected: "TabSelected", | |
TabClosed: "TabClosed" | |
} | |
WebInspector.TabbedPane.prototype = { | |
get visibleView() | |
{ | |
return this._currentTab ? this._currentTab.view : null; | |
}, | |
get selectedTabId() | |
{ | |
return this._currentTab ? this._currentTab.id : null; | |
}, | |
set shrinkableTabs(shrinkableTabs) | |
{ | |
this._shrinkableTabs = shrinkableTabs; | |
}, | |
set closeableTabs(closeableTabs) | |
{ | |
this._closeableTabs = closeableTabs; | |
}, | |
defaultFocusedElement: function() | |
{ | |
return this.visibleView ? this.visibleView.defaultFocusedElement() : null; | |
}, | |
appendTab: function(id, tabTitle, view, tabTooltip, userGesture) | |
{ | |
var tab = new WebInspector.TabbedPaneTab(this, id, tabTitle, this._closeableTabs, view, tabTooltip); | |
this._tabsById[id] = tab; | |
this._tabs.push(tab); | |
this._tabsHistory.push(tab); | |
if (this._tabsHistory[0] === tab) | |
this.selectTab(tab.id, userGesture); | |
this._updateTabElements(); | |
}, | |
closeTab: function(id, userGesture) | |
{ | |
this._innerCloseTab(id, userGesture); | |
this._updateTabElements(); | |
if (this._tabsHistory.length) | |
this.selectTab(this._tabsHistory[0].id, userGesture); | |
}, | |
_innerCloseTab: function(id, userGesture) | |
{ | |
if (this._currentTab && this._currentTab.id === id) | |
this._hideCurrentTab(); | |
var tab = this._tabsById[id]; | |
delete this._tabsById[id]; | |
this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1); | |
this._tabs.splice(this._tabs.indexOf(tab), 1); | |
if (tab._shown) | |
this._hideTabElement(tab); | |
var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture }; | |
this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabClosed, eventData); | |
return true; | |
}, | |
closeAllTabs: function(userGesture) | |
{ | |
var tabs = this._tabs.slice(); | |
for (var i = 0; i < tabs.length; ++i) | |
this._innerCloseTab(tabs[i].id, userGesture); | |
this._updateTabElements(); | |
}, | |
closeOtherTabs: function(id) | |
{ | |
var tabs = this._tabs.slice(); | |
for (var i = 0; i < tabs.length; ++i) { | |
if (tabs[i].id !== id) | |
this._innerCloseTab(tabs[i].id, true); | |
} | |
this._updateTabElements(); | |
this.selectTab(id, true); | |
}, | |
selectTab: function(id, userGesture) | |
{ | |
var tab = this._tabsById[id]; | |
if (!tab) | |
return; | |
if (this._currentTab && this._currentTab.id === id) | |
return; | |
this._hideCurrentTab(); | |
this._showTab(tab); | |
this._currentTab = tab; | |
this._tabsHistory.splice(this._tabsHistory.indexOf(tab), 1); | |
this._tabsHistory.splice(0, 0, tab); | |
this._updateTabElements(); | |
var eventData = { tabId: id, view: tab.view, isUserGesture: userGesture }; | |
this.dispatchEventToListeners(WebInspector.TabbedPane.EventTypes.TabSelected, eventData); | |
return true; | |
}, | |
lastOpenedTabIds: function(tabsCount) | |
{ | |
function tabToTabId(tab) { | |
return tab.id; | |
} | |
return this._tabsHistory.slice(0, tabsCount).map(tabToTabId); | |
}, | |
changeTabTitle: function(id, tabTitle) | |
{ | |
var tab = this._tabsById[id]; | |
tab.title = tabTitle; | |
this._updateTabElements(); | |
}, | |
changeTabView: function(id, view) | |
{ | |
var tab = this._tabsById[id]; | |
if (this._currentTab && this._currentTab.id === tab.id) { | |
this._hideTab(tab); | |
tab.view = view; | |
this._showTab(tab); | |
} else | |
tab.view = view; | |
}, | |
changeTabTooltip: function(id, tabTooltip) | |
{ | |
var tab = this._tabsById[id]; | |
tab.tooltip = tabTooltip; | |
}, | |
onResize: function() | |
{ | |
this._updateTabElements(); | |
}, | |
_updateTabElements: function() | |
{ | |
WebInspector.invokeOnceAfterBatchUpdate(this, this._innerUpdateTabElements); | |
}, | |
_innerUpdateTabElements: function() | |
{ | |
if (!this.isShowing()) | |
return; | |
if (!this._tabs.length) | |
this._contentElement.addStyleClass("has-no-tabs"); | |
else | |
this._contentElement.removeStyleClass("has-no-tabs"); | |
if (!this._measuredDropDownButtonWidth) | |
this._measureDropDownButton(); | |
this._updateWidths(); | |
this._updateTabsDropDown(); | |
}, | |
_showTabElement: function(index, tab) | |
{ | |
if (index >= this._tabsElement.children.length) | |
this._tabsElement.appendChild(tab.tabElement); | |
else | |
this._tabsElement.insertBefore(tab.tabElement, this._tabsElement.children[index]); | |
tab._shown = true; | |
}, | |
_hideTabElement: function(tab) | |
{ | |
this._tabsElement.removeChild(tab.tabElement); | |
tab._shown = false; | |
}, | |
_createDropDownButton: function() | |
{ | |
var dropDownContainer = document.createElement("div"); | |
dropDownContainer.addStyleClass("tabbed-pane-header-tabs-drop-down-container"); | |
var dropDownButton = dropDownContainer.createChild("div", "tabbed-pane-header-tabs-drop-down"); | |
dropDownButton.appendChild(document.createTextNode("\u00bb")); | |
this._tabsSelect = dropDownButton.createChild("select", "tabbed-pane-header-tabs-drop-down-select"); | |
this._tabsSelect.addEventListener("change", this._tabsSelectChanged.bind(this), false); | |
return dropDownContainer; | |
}, | |
_totalWidth: function() | |
{ | |
return this._headerContentsElement.getBoundingClientRect().width; | |
}, | |
_updateTabsDropDown: function() | |
{ | |
var tabsToShowIndexes = this._tabsToShowIndexes(this._tabs, this._tabsHistory, this._totalWidth(), this._measuredDropDownButtonWidth); | |
for (var i = 0; i < this._tabs.length; ++i) { | |
if (this._tabs[i]._shown && tabsToShowIndexes.indexOf(i) === -1) | |
this._hideTabElement(this._tabs[i]); | |
} | |
for (var i = 0; i < tabsToShowIndexes.length; ++i) { | |
var tab = this._tabs[tabsToShowIndexes[i]]; | |
if (!tab._shown) | |
this._showTabElement(i, tab); | |
} | |
this._populateDropDownFromIndex(); | |
}, | |
_populateDropDownFromIndex: function() | |
{ | |
if (this._dropDownButton.parentElement) | |
this._headerContentsElement.removeChild(this._dropDownButton); | |
this._tabsSelect.removeChildren(); | |
var tabsToShow = []; | |
for (var i = 0; i < this._tabs.length; ++i) { | |
if (!this._tabs[i]._shown) | |
tabsToShow.push(this._tabs[i]); | |
continue; | |
} | |
function compareFunction(tab1, tab2) | |
{ | |
return tab1.title.localeCompare(tab2.title); | |
} | |
tabsToShow.sort(compareFunction); | |
for (var i = 0; i < tabsToShow.length; ++i) { | |
var option = new Option(tabsToShow[i].title); | |
option.tab = tabsToShow[i]; | |
this._tabsSelect.appendChild(option); | |
} | |
if (this._tabsSelect.options.length) { | |
this._headerContentsElement.appendChild(this._dropDownButton); | |
this._tabsSelect.selectedIndex = -1; | |
} | |
}, | |
_tabsSelectChanged: function() | |
{ | |
var options = this._tabsSelect.options; | |
var selectedOption = options[this._tabsSelect.selectedIndex]; | |
this.selectTab(selectedOption.tab.id, true); | |
}, | |
_measureDropDownButton: function() | |
{ | |
this._dropDownButton.addStyleClass("measuring"); | |
this._headerContentsElement.appendChild(this._dropDownButton); | |
this._measuredDropDownButtonWidth = this._dropDownButton.getBoundingClientRect().width; | |
this._headerContentsElement.removeChild(this._dropDownButton); | |
this._dropDownButton.removeStyleClass("measuring"); | |
}, | |
_updateWidths: function() | |
{ | |
var measuredWidths = this._measureWidths(); | |
var maxWidth = this._shrinkableTabs ? this._calculateMaxWidth(measuredWidths.slice(), this._totalWidth()) : Number.MAX_VALUE; | |
var i = 0; | |
for (var tabId in this._tabs) { | |
var tab = this._tabs[tabId]; | |
tab.setWidth(Math.min(maxWidth, measuredWidths[i++])); | |
} | |
}, | |
_measureWidths: function() | |
{ | |
var measuringTabElements = []; | |
for (var tabId in this._tabs) { | |
var tab = this._tabs[tabId]; | |
if (typeof tab._measuredWidth === "number") | |
continue; | |
var measuringTabElement = tab._createTabElement(true); | |
measuringTabElement.__tab = tab; | |
measuringTabElements.push(measuringTabElement); | |
this._tabsElement.appendChild(measuringTabElement); | |
} | |
for (var i = 0; i < measuringTabElements.length; ++i) | |
measuringTabElements[i].__tab._measuredWidth = measuringTabElements[i].getBoundingClientRect().width; | |
for (var i = 0; i < measuringTabElements.length; ++i) | |
measuringTabElements[i].parentElement.removeChild(measuringTabElements[i]); | |
var measuredWidths = []; | |
for (var tabId in this._tabs) | |
measuredWidths.push(this._tabs[tabId]._measuredWidth); | |
return measuredWidths; | |
}, | |
_calculateMaxWidth: function(measuredWidths, totalWidth) | |
{ | |
if (!measuredWidths.length) | |
return 0; | |
measuredWidths.sort(function(x, y) { return x - y }); | |
var totalMeasuredWidth = 0; | |
for (var i = 0; i < measuredWidths.length; ++i) | |
totalMeasuredWidth += measuredWidths[i]; | |
if (totalWidth >= totalMeasuredWidth) | |
return measuredWidths[measuredWidths.length - 1]; | |
var totalExtraWidth = 0; | |
for (var i = measuredWidths.length - 1; i > 0; --i) { | |
var extraWidth = measuredWidths[i] - measuredWidths[i - 1]; | |
totalExtraWidth += (measuredWidths.length - i) * extraWidth; | |
if (totalWidth + totalExtraWidth >= totalMeasuredWidth) | |
return measuredWidths[i - 1] + (totalWidth + totalExtraWidth - totalMeasuredWidth) / (measuredWidths.length - i); | |
} | |
return totalWidth / measuredWidths.length; | |
}, | |
_tabsToShowIndexes: function(tabsOrdered, tabsHistory, totalWidth, measuredDropDownButtonWidth) | |
{ | |
var tabsToShowIndexes = []; | |
var totalTabsWidth = 0; | |
for (var i = 0; i < tabsHistory.length; ++i) { | |
totalTabsWidth += tabsHistory[i].width(); | |
var minimalRequiredWidth = totalTabsWidth; | |
if (i !== tabsHistory.length - 1) | |
minimalRequiredWidth += measuredDropDownButtonWidth; | |
if (minimalRequiredWidth > totalWidth) | |
break; | |
tabsToShowIndexes.push(tabsOrdered.indexOf(tabsHistory[i])); | |
} | |
tabsToShowIndexes.sort(function(x, y) { return x - y }); | |
return tabsToShowIndexes; | |
}, | |
_hideCurrentTab: function() | |
{ | |
if (!this._currentTab) | |
return; | |
this._hideTab(this._currentTab); | |
delete this._currentTab; | |
}, | |
_showTab: function(tab) | |
{ | |
tab.tabElement.addStyleClass("selected"); | |
tab.view.show(this._contentElement); | |
}, | |
_hideTab: function(tab) | |
{ | |
tab.tabElement.removeStyleClass("selected"); | |
tab.view.detach(); | |
}, | |
canHighlightLine: function() | |
{ | |
return this._currentTab && this._currentTab.view && this._currentTab.view.canHighlightLine(); | |
}, | |
highlightLine: function(line) | |
{ | |
if (this.canHighlightLine()) | |
this._currentTab.view.highlightLine(line); | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return [ this._contentElement ]; | |
}, | |
_insertBefore: function(tab, index) | |
{ | |
this._tabsElement.insertBefore(tab._tabElement, this._tabsElement.childNodes[index]); | |
var oldIndex = this._tabs.indexOf(tab); | |
this._tabs.splice(oldIndex, 1); | |
if (oldIndex < index) | |
--index; | |
this._tabs.splice(index, 0, tab); | |
} | |
} | |
WebInspector.TabbedPane.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.TabbedPaneTab = function(tabbedPane, id, title, closeable, view, tooltip) | |
{ | |
this._closeable = closeable; | |
this._tabbedPane = tabbedPane; | |
this._id = id; | |
this._title = title; | |
this._tooltip = tooltip; | |
this._view = view; | |
this._shown = false; | |
this._measuredWidth; | |
this._tabElement; | |
} | |
WebInspector.TabbedPaneTab.prototype = { | |
get id() | |
{ | |
return this._id; | |
}, | |
get title() | |
{ | |
return this._title; | |
}, | |
set title(title) | |
{ | |
this._title = title; | |
if (this._titleElement) | |
this._titleElement.textContent = title; | |
delete this._measuredWidth; | |
}, | |
get view() | |
{ | |
return this._view; | |
}, | |
set view(view) | |
{ | |
this._view = view; | |
}, | |
get tooltip() | |
{ | |
return this._tooltip; | |
}, | |
set tooltip(tooltip) | |
{ | |
this._tooltip = tooltip; | |
if (this._titleElement) | |
this._titleElement.title = tooltip || ""; | |
}, | |
get tabElement() | |
{ | |
if (typeof(this._tabElement) !== "undefined") | |
return this._tabElement; | |
this._createTabElement(false); | |
return this._tabElement; | |
}, | |
width: function() | |
{ | |
return this._width; | |
}, | |
setWidth: function(width) | |
{ | |
this.tabElement.style.width = width + "px"; | |
this._width = width; | |
}, | |
_createTabElement: function(measuring) | |
{ | |
var tabElement = document.createElement("div"); | |
tabElement.addStyleClass("tabbed-pane-header-tab"); | |
tabElement.tabIndex = -1; | |
var titleElement = tabElement.createChild("span", "tabbed-pane-header-tab-title"); | |
titleElement.textContent = this.title; | |
titleElement.title = this.tooltip || ""; | |
if (!measuring) | |
this._titleElement = titleElement; | |
if (this._closeable) { | |
var closeButtonSpan = tabElement.createChild("span", "tabbed-pane-header-tab-close-button"); | |
closeButtonSpan.textContent = "\u00D7"; | |
} | |
if (measuring) | |
tabElement.addStyleClass("measuring"); | |
else { | |
this._tabElement = tabElement; | |
tabElement.addEventListener("click", this._tabClicked.bind(this), false); | |
tabElement.addEventListener("mousedown", this._tabMouseDown.bind(this), false); | |
if (this._closeable) { | |
tabElement.addEventListener("contextmenu", this._tabContextMenu.bind(this), false); | |
WebInspector.installDragHandle(tabElement, this._startTabDragging.bind(this), this._tabDragging.bind(this), this._endTabDragging.bind(this), "pointer"); | |
} | |
} | |
return tabElement; | |
}, | |
_tabClicked: function(event) | |
{ | |
if (this._closeable && (event.button === 1 || event.target.hasStyleClass("tabbed-pane-header-tab-close-button"))) | |
this._tabbedPane.closeTab(this.id, true); | |
}, | |
_tabMouseDown: function(event) | |
{ | |
if (event.target.hasStyleClass("tabbed-pane-header-tab-close-button") || event.button === 1) | |
return; | |
this._tabbedPane.selectTab(this.id, true); | |
}, | |
_tabContextMenu: function(event) | |
{ | |
function close() | |
{ | |
this._tabbedPane.closeTab(this.id, true); | |
} | |
function closeOthers() | |
{ | |
this._tabbedPane.closeOtherTabs(this.id); | |
} | |
function closeAll() | |
{ | |
this._tabbedPane.closeAllTabs(true); | |
} | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendItem(WebInspector.UIString("Close"), close.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString("Close Others"), closeOthers.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString("Close All"), closeAll.bind(this)); | |
contextMenu.show(event); | |
}, | |
_startTabDragging: function(event) | |
{ | |
if (event.target.hasStyleClass("tabbed-pane-header-tab-close-button")) | |
return false; | |
this._dragStartX = event.pageX; | |
return true; | |
}, | |
_tabDragging: function(event) | |
{ | |
var tabElements = this._tabbedPane._tabsElement.childNodes; | |
for (var i = 0; i < tabElements.length; ++i) { | |
var tabElement = tabElements[i]; | |
if (tabElement === this._tabElement) | |
continue; | |
var intersects = tabElement.offsetLeft + tabElement.clientWidth > this._tabElement.offsetLeft && | |
this._tabElement.offsetLeft + this._tabElement.clientWidth > tabElement.offsetLeft; | |
if (!intersects) | |
continue; | |
if (Math.abs(event.pageX - this._dragStartX) < tabElement.clientWidth / 2 + 5) | |
break; | |
if (event.pageX - this._dragStartX > 0) { | |
tabElement = tabElement.nextSibling; | |
++i; | |
} | |
var oldOffsetLeft = this._tabElement.offsetLeft; | |
this._tabbedPane._insertBefore(this, i); | |
this._dragStartX += this._tabElement.offsetLeft - oldOffsetLeft; | |
break; | |
} | |
if (!this._tabElement.previousSibling && event.pageX - this._dragStartX < 0) { | |
this._tabElement.style.setProperty("left", "0px"); | |
return; | |
} | |
if (!this._tabElement.nextSibling && event.pageX - this._dragStartX > 0) { | |
this._tabElement.style.setProperty("left", "0px"); | |
return; | |
} | |
this._tabElement.style.setProperty("position", "relative"); | |
this._tabElement.style.setProperty("left", (event.pageX - this._dragStartX) + "px"); | |
}, | |
_endTabDragging: function(event) | |
{ | |
this._tabElement.style.removeProperty("position"); | |
this._tabElement.style.removeProperty("left"); | |
delete this._dragStartX; | |
} | |
} | |
WebInspector.Drawer = function() | |
{ | |
this.element = document.getElementById("drawer"); | |
this._savedHeight = 200; | |
this._mainElement = document.getElementById("main"); | |
this._toolbarElement = document.getElementById("toolbar"); | |
this._floatingStatusBarContainer = document.getElementById("floating-status-bar-container"); | |
WebInspector.installDragHandle(this._floatingStatusBarContainer, this._startStatusBarDragging.bind(this), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), "row-resize"); | |
this._drawerContentsElement = document.createElement("div"); | |
this._drawerContentsElement.id = "drawer-contents"; | |
this._drawerContentsElement.className = "drawer-contents"; | |
this.element.appendChild(this._drawerContentsElement); | |
this._viewStatusBar = document.createElement("div"); | |
this._bottomStatusBar = document.getElementById("bottom-status-bar-container"); | |
} | |
WebInspector.Drawer.AnimationType = { | |
Immediately: 0, | |
Normal: 1, | |
Slow: 2 | |
} | |
WebInspector.Drawer.prototype = { | |
get visible() | |
{ | |
return !!this._view; | |
}, | |
_constrainHeight: function(height) | |
{ | |
return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight); | |
}, | |
show: function(view, animationType) | |
{ | |
this.immediatelyFinishAnimation(); | |
var drawerWasVisible = this.visible; | |
if (this._view) { | |
this._view.detach(); | |
this._drawerContentsElement.removeChildren(); | |
} | |
this._view = view; | |
var statusBarItems = this._view.statusBarItems || []; | |
this._viewStatusBar.removeChildren(); | |
for (var i = 0; i < statusBarItems.length; ++i) | |
this._viewStatusBar.appendChild(statusBarItems[i]); | |
document.body.addStyleClass("drawer-visible"); | |
this._floatingStatusBarContainer.insertBefore(document.getElementById("panel-status-bar"), this._floatingStatusBarContainer.firstElementChild); | |
this._bottomStatusBar.appendChild(this._viewStatusBar); | |
this._view.markAsRoot(); | |
this._view.show(this._drawerContentsElement); | |
if (drawerWasVisible) | |
return; | |
var height = this._constrainHeight(this._savedHeight || this.element.offsetHeight); | |
var animations = [ | |
{element: this.element, end: {height: height}}, | |
{element: this._mainElement, end: {bottom: height}}, | |
{element: this._floatingStatusBarContainer, start: {"padding-left": this._bottomStatusBar.offsetLeft}, end: {"padding-left": 0}}, | |
{element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}} | |
]; | |
function animationFinished() | |
{ | |
WebInspector.inspectorView.currentPanel().doResize(); | |
if (this._view && this._view.afterShow) | |
this._view.afterShow(); | |
delete this._currentAnimation; | |
} | |
this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationFinished.bind(this)); | |
if (animationType === WebInspector.Drawer.AnimationType.Immediately) | |
this._currentAnimation.forceComplete(); | |
}, | |
hide: function(animationType) | |
{ | |
this.immediatelyFinishAnimation(); | |
if (!this.visible) | |
return; | |
this._savedHeight = this.element.offsetHeight; | |
WebInspector.restoreFocusFromElement(this.element); | |
document.body.removeStyleClass("drawer-visible"); | |
WebInspector.inspectorView.currentPanel().statusBarResized(); | |
document.body.addStyleClass("drawer-visible"); | |
var animations = [ | |
{element: this._mainElement, end: {bottom: 0}}, | |
{element: this.element, end: {height: 0}}, | |
{element: this._floatingStatusBarContainer, start: {"padding-left": 0}, end: {"padding-left": this._bottomStatusBar.offsetLeft} }, | |
{element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}} | |
]; | |
function animationFinished() | |
{ | |
WebInspector.inspectorView.currentPanel().doResize(); | |
this._view.detach(); | |
delete this._view; | |
this._bottomStatusBar.removeChildren(); | |
this._bottomStatusBar.appendChild(document.getElementById("panel-status-bar")); | |
this._drawerContentsElement.removeChildren(); | |
document.body.removeStyleClass("drawer-visible"); | |
delete this._currentAnimation; | |
} | |
this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationFinished.bind(this)); | |
if (animationType === WebInspector.Drawer.AnimationType.Immediately) | |
this._currentAnimation.forceComplete(); | |
}, | |
resize: function() | |
{ | |
if (!this.visible) | |
return; | |
this._view.storeScrollPositions(); | |
var height = this._constrainHeight(parseInt(this.element.style.height, 10)); | |
this._mainElement.style.bottom = height + "px"; | |
this.element.style.height = height + "px"; | |
this._view.doResize(); | |
}, | |
immediatelyFinishAnimation: function() | |
{ | |
if (this._currentAnimation) | |
this._currentAnimation.forceComplete(); | |
}, | |
_animationDuration: function(animationType) | |
{ | |
switch (animationType) { | |
case WebInspector.Drawer.AnimationType.Slow: | |
return 2000; | |
case WebInspector.Drawer.AnimationType.Normal: | |
return 250; | |
default: | |
return 0; | |
} | |
}, | |
_startStatusBarDragging: function(event) | |
{ | |
if (!this.visible || event.target !== this._floatingStatusBarContainer) | |
return false; | |
this._view.storeScrollPositions(); | |
this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop(); | |
return true; | |
}, | |
_statusBarDragging: function(event) | |
{ | |
var height = window.innerHeight - event.pageY + this._statusBarDragOffset; | |
height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight); | |
this._mainElement.style.bottom = height + "px"; | |
this.element.style.height = height + "px"; | |
if (WebInspector.inspectorView.currentPanel()) | |
WebInspector.inspectorView.currentPanel().doResize(); | |
this._view.doResize(); | |
event.consume(true); | |
}, | |
_endStatusBarDragging: function(event) | |
{ | |
this._savedHeight = this.element.offsetHeight; | |
delete this._statusBarDragOffset; | |
event.consume(); | |
} | |
} | |
WebInspector.drawer = null; | |
WebInspector.ConsoleModel = function() | |
{ | |
this.messages = []; | |
this.warnings = 0; | |
this.errors = 0; | |
this._interruptRepeatCount = false; | |
InspectorBackend.registerConsoleDispatcher(new WebInspector.ConsoleDispatcher(this)); | |
} | |
WebInspector.ConsoleModel.Events = { | |
ConsoleCleared: "console-cleared", | |
MessageAdded: "console-message-added", | |
RepeatCountUpdated: "repeat-count-updated" | |
} | |
WebInspector.ConsoleModel.prototype = { | |
enableAgent: function() | |
{ | |
if (WebInspector.settings.monitoringXHREnabled.get()) | |
ConsoleAgent.setMonitoringXHREnabled(true); | |
this._enablingConsole = true; | |
function callback() | |
{ | |
delete this._enablingConsole; | |
} | |
ConsoleAgent.enable(callback.bind(this)); | |
}, | |
enablingConsole: function() | |
{ | |
return !!this._enablingConsole; | |
}, | |
addMessage: function(msg) | |
{ | |
this.messages.push(msg); | |
this._previousMessage = msg; | |
this._incrementErrorWarningCount(msg); | |
this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.MessageAdded, msg); | |
this._interruptRepeatCount = false; | |
}, | |
_incrementErrorWarningCount: function(msg) | |
{ | |
switch (msg.level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
this.warnings += msg.repeatDelta; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
this.errors += msg.repeatDelta; | |
break; | |
} | |
}, | |
requestClearMessages: function() | |
{ | |
ConsoleAgent.clearMessages(); | |
this.clearMessages(); | |
}, | |
clearMessages: function() | |
{ | |
this.messages = []; | |
this.errors = 0; | |
this.warnings = 0; | |
this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.ConsoleCleared); | |
}, | |
interruptRepeatCount: function() | |
{ | |
this._interruptRepeatCount = true; | |
}, | |
_messageRepeatCountUpdated: function(count) | |
{ | |
var msg = this._previousMessage; | |
if (!msg) | |
return; | |
var prevRepeatCount = msg.totalRepeatCount; | |
if (!this._interruptRepeatCount) { | |
msg.repeatDelta = count - prevRepeatCount; | |
msg.repeatCount = msg.repeatCount + msg.repeatDelta; | |
msg.totalRepeatCount = count; | |
msg.updateRepeatCount(); | |
this._incrementErrorWarningCount(msg); | |
this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.RepeatCountUpdated, msg); | |
} else { | |
var msgCopy = msg.clone(); | |
msgCopy.totalRepeatCount = count; | |
msgCopy.repeatCount = (count - prevRepeatCount) || 1; | |
msgCopy.repeatDelta = msgCopy.repeatCount; | |
this.addMessage(msgCopy); | |
} | |
} | |
} | |
WebInspector.ConsoleModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.ConsoleMessage = function(source, level, url, line, repeatCount) | |
{ | |
this.source = source; | |
this.level = level; | |
this.url = url || null; | |
this.line = line || 0; | |
this.message = ""; | |
repeatCount = repeatCount || 1; | |
this.repeatCount = repeatCount; | |
this.repeatDelta = repeatCount; | |
this.totalRepeatCount = repeatCount; | |
} | |
WebInspector.ConsoleMessage.prototype = { | |
isErrorOrWarning: function() | |
{ | |
return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); | |
}, | |
updateRepeatCount: function() | |
{ | |
}, | |
clone: function() | |
{ | |
}, | |
location: function() | |
{ | |
} | |
} | |
WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, repeatCount, parameters, stackTrace, requestId, isOutdated) | |
{ | |
} | |
WebInspector.ConsoleMessage.MessageSource = { | |
HTML: "html", | |
XML: "xml", | |
JS: "javascript", | |
Network: "network", | |
ConsoleAPI: "console-api", | |
Other: "other" | |
} | |
WebInspector.ConsoleMessage.MessageType = { | |
Log: "log", | |
Dir: "dir", | |
DirXML: "dirxml", | |
Trace: "trace", | |
StartGroup: "startGroup", | |
StartGroupCollapsed: "startGroupCollapsed", | |
EndGroup: "endGroup", | |
Assert: "assert", | |
Result: "result" | |
} | |
WebInspector.ConsoleMessage.MessageLevel = { | |
Tip: "tip", | |
Log: "log", | |
Warning: "warning", | |
Error: "error", | |
Debug: "debug" | |
} | |
WebInspector.ConsoleDispatcher = function(console) | |
{ | |
this._console = console; | |
} | |
WebInspector.ConsoleDispatcher.prototype = { | |
messageAdded: function(payload) | |
{ | |
var consoleMessage = WebInspector.ConsoleMessage.create( | |
payload.source, | |
payload.level, | |
payload.text, | |
payload.type, | |
payload.url, | |
payload.line, | |
payload.repeatCount, | |
payload.parameters, | |
payload.stackTrace, | |
payload.networkRequestId, | |
this._console._enablingConsole); | |
this._console.addMessage(consoleMessage); | |
}, | |
messageRepeatCountUpdated: function(count) | |
{ | |
this._console._messageRepeatCountUpdated(count); | |
}, | |
messagesCleared: function() | |
{ | |
if (!WebInspector.settings.preserveConsoleLog.get()) | |
this._console.clearMessages(); | |
} | |
} | |
WebInspector.console = null; | |
WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, type, url, line, repeatCount, parameters, stackTrace, requestId, isOutdated) | |
{ | |
WebInspector.ConsoleMessage.call(this, source, level, url, line, repeatCount); | |
this._linkifier = linkifier; | |
this.type = type || WebInspector.ConsoleMessage.MessageType.Log; | |
this._messageText = message; | |
this._parameters = parameters; | |
this._stackTrace = stackTrace; | |
this._request = requestId ? WebInspector.networkLog.requestForId(requestId) : null; | |
this._isOutdated = isOutdated; | |
this._customFormatters = { | |
"object": this._formatParameterAsObject, | |
"array": this._formatParameterAsArray, | |
"node": this._formatParameterAsNode, | |
"string": this._formatParameterAsString | |
}; | |
} | |
WebInspector.ConsoleMessageImpl.prototype = { | |
_formatMessage: function() | |
{ | |
this._formattedMessage = document.createElement("span"); | |
this._formattedMessage.className = "console-message-text source-code"; | |
if (this.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) { | |
switch (this.type) { | |
case WebInspector.ConsoleMessage.MessageType.Trace: | |
this._messageElement = document.createTextNode("console.trace()"); | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Assert: | |
var args = [WebInspector.UIString("Assertion failed:")]; | |
if (this._parameters) | |
args = args.concat(this._parameters); | |
this._messageElement = this._format(args); | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Dir: | |
var obj = this._parameters ? this._parameters[0] : undefined; | |
var args = ["%O", obj]; | |
this._messageElement = this._format(args); | |
break; | |
default: | |
var args = this._parameters || [this._messageText]; | |
this._messageElement = this._format(args); | |
} | |
} else if (this.source === WebInspector.ConsoleMessage.MessageSource.Network) { | |
if (this._request) { | |
this._stackTrace = this._request.initiator.stackTrace; | |
if (this._request.initiator && this._request.initiator.url) { | |
this.url = this._request.initiator.url; | |
this.line = this._request.initiator.lineNumber; | |
} | |
this._messageElement = document.createElement("span"); | |
if (this.level === WebInspector.ConsoleMessage.MessageLevel.Error) { | |
this._messageElement.appendChild(document.createTextNode(this._request.requestMethod + " ")); | |
this._messageElement.appendChild(WebInspector.linkifyRequestAsNode(this._request)); | |
if (this._request.failed) | |
this._messageElement.appendChild(document.createTextNode(" " + this._request.localizedFailDescription)); | |
else | |
this._messageElement.appendChild(document.createTextNode(" " + this._request.statusCode + " (" + this._request.statusText + ")")); | |
} else { | |
var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(this._messageText, WebInspector.linkifyRequestAsNode.bind(null, this._request, "")); | |
this._messageElement.appendChild(fragment); | |
} | |
} else { | |
if (this.url) { | |
var isExternal = !WebInspector.resourceForURL(this.url); | |
this._anchorElement = WebInspector.linkifyURLAsNode(this.url, this.url, "console-message-url", isExternal); | |
} | |
this._messageElement = this._format([this._messageText]); | |
} | |
} else { | |
var args = this._parameters || [this._messageText]; | |
this._messageElement = this._format(args); | |
} | |
if (this.source !== WebInspector.ConsoleMessage.MessageSource.Network || this._request) { | |
if (this._stackTrace && this._stackTrace.length && this._stackTrace[0].url) { | |
this._anchorElement = this._linkifyCallFrame(this._stackTrace[0]); | |
} else if (this.url && this.url !== "undefined") { | |
this._anchorElement = this._linkifyLocation(this.url, this.line, 0); | |
} | |
} | |
this._formattedMessage.appendChild(this._messageElement); | |
if (this._anchorElement) { | |
this._formattedMessage.appendChild(document.createTextNode(" ")); | |
this._formattedMessage.appendChild(this._anchorElement); | |
} | |
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); | |
if (dumpStackTrace) { | |
var ol = document.createElement("ol"); | |
ol.className = "outline-disclosure"; | |
var treeOutline = new TreeOutline(ol); | |
var content = this._formattedMessage; | |
var root = new TreeElement(content, null, true); | |
content.treeElementForTest = root; | |
treeOutline.appendChild(root); | |
if (this.type === WebInspector.ConsoleMessage.MessageType.Trace) | |
root.expand(); | |
this._populateStackTraceTreeElement(root); | |
this._formattedMessage = ol; | |
} | |
this._message = this._messageElement.textContent; | |
}, | |
get message() | |
{ | |
var formattedMessage = this.formattedMessage; | |
return this._message; | |
}, | |
get formattedMessage() | |
{ | |
if (!this._formattedMessage) | |
this._formatMessage(); | |
return this._formattedMessage; | |
}, | |
_linkifyLocation: function(url, lineNumber, columnNumber) | |
{ | |
lineNumber = lineNumber ? lineNumber - 1 : 0; | |
columnNumber = columnNumber ? columnNumber - 1 : 0; | |
return this._linkifier.linkifyLocation(url, lineNumber, columnNumber, "console-message-url"); | |
}, | |
_linkifyCallFrame: function(callFrame) | |
{ | |
return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber); | |
}, | |
isErrorOrWarning: function() | |
{ | |
return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error); | |
}, | |
_format: function(parameters) | |
{ | |
var formattedResult = document.createElement("span"); | |
if (!parameters.length) | |
return formattedResult; | |
for (var i = 0; i < parameters.length; ++i) { | |
if (parameters[i] instanceof WebInspector.RemoteObject) | |
continue; | |
if (typeof parameters[i] === "object") | |
parameters[i] = WebInspector.RemoteObject.fromPayload(parameters[i]); | |
else | |
parameters[i] = WebInspector.RemoteObject.fromPrimitiveValue(parameters[i]); | |
} | |
var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this.type !== WebInspector.ConsoleMessage.MessageType.Result; | |
if (shouldFormatMessage) { | |
var result = this._formatWithSubstitutionString(parameters, formattedResult); | |
parameters = result.unusedSubstitutions; | |
if (parameters.length) | |
formattedResult.appendChild(document.createTextNode(" ")); | |
} | |
for (var i = 0; i < parameters.length; ++i) { | |
if (shouldFormatMessage && parameters[i].type === "string") | |
formattedResult.appendChild(document.createTextNode(parameters[i].description)); | |
else | |
formattedResult.appendChild(this._formatParameter(parameters[i], false, true)); | |
if (i < parameters.length - 1) | |
formattedResult.appendChild(document.createTextNode(" ")); | |
} | |
return formattedResult; | |
}, | |
_formatParameter: function(output, forceObjectFormat, includePreview) | |
{ | |
var type; | |
if (forceObjectFormat) | |
type = "object"; | |
else if (output instanceof WebInspector.RemoteObject) | |
type = output.subtype || output.type; | |
else | |
type = typeof output; | |
var formatter = this._customFormatters[type]; | |
if (!formatter) { | |
formatter = this._formatParameterAsValue; | |
output = output.description; | |
} | |
var span = document.createElement("span"); | |
span.className = "console-formatted-" + type + " source-code"; | |
formatter.call(this, output, span, includePreview); | |
return span; | |
}, | |
_formatParameterAsValue: function(val, elem) | |
{ | |
elem.appendChild(document.createTextNode(val)); | |
}, | |
_formatParameterAsObject: function(obj, elem, includePreview) | |
{ | |
this._formatParameterAsArrayOrObject(obj, obj.description, elem, includePreview); | |
}, | |
_formatParameterAsArrayOrObject: function(obj, description, elem, includePreview) | |
{ | |
var titleElement = document.createElement("span"); | |
if (description) | |
titleElement.createTextChild(description); | |
if (includePreview && obj.preview) { | |
titleElement.addStyleClass("console-object-preview"); | |
var lossless = this._appendObjectPreview(obj, description, titleElement); | |
if (lossless) { | |
elem.appendChild(titleElement); | |
return; | |
} | |
} | |
var section = new WebInspector.ObjectPropertiesSection(obj, titleElement); | |
section.enableContextMenu(); | |
elem.appendChild(section.element); | |
}, | |
_appendObjectPreview: function(obj, description, titleElement) | |
{ | |
var preview = obj.preview; | |
var isArray = obj.subtype === "array"; | |
if (description) | |
titleElement.createTextChild(" "); | |
titleElement.createTextChild(isArray ? "[" : "{"); | |
for (var i = 0; i < preview.properties.length; ++i) { | |
if (i > 0) | |
titleElement.createTextChild(", "); | |
var property = preview.properties[i]; | |
if (!isArray || property.name != i) { | |
titleElement.createChild("span", "name").textContent = property.name; | |
titleElement.createTextChild(": "); | |
} | |
var span = titleElement.createChild("span", "console-formatted-" + property.type); | |
if (property.type === "object") { | |
if (property.subtype === "node") | |
span.addStyleClass("console-formatted-preview-node"); | |
else if (property.subtype === "regexp") | |
span.addStyleClass("console-formatted-string"); | |
} | |
span.textContent = property.value; | |
} | |
if (preview.overflow) | |
titleElement.createChild("span").textContent = "\u2026"; | |
titleElement.createTextChild(isArray ? "]" : "}"); | |
return preview.lossless; | |
}, | |
_formatParameterAsNode: function(object, elem) | |
{ | |
function printNode(nodeId) | |
{ | |
if (!nodeId) { | |
this._formatParameterAsObject(object, elem, false); | |
return; | |
} | |
var treeOutline = new WebInspector.ElementsTreeOutline(false, false, true); | |
treeOutline.setVisible(true); | |
treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId); | |
treeOutline.element.addStyleClass("outline-disclosure"); | |
if (!treeOutline.children[0].hasChildren) | |
treeOutline.element.addStyleClass("single-node"); | |
elem.appendChild(treeOutline.element); | |
treeOutline.element.treeElementForTest = treeOutline.children[0]; | |
} | |
object.pushNodeToFrontend(printNode.bind(this)); | |
}, | |
_formatParameterAsArray: function(array, elem) | |
{ | |
if (array.preview) { | |
this._formatParameterAsArrayOrObject(array, "", elem, true); | |
return; | |
} | |
const maxFlatArrayLength = 100; | |
if (this._isOutdated || array.arrayLength() > maxFlatArrayLength) | |
this._formatParameterAsObject(array, elem, false); | |
else | |
array.getOwnProperties(this._printArray.bind(this, array, elem)); | |
}, | |
_formatParameterAsString: function(output, elem) | |
{ | |
var span = document.createElement("span"); | |
span.className = "console-formatted-string source-code"; | |
span.appendChild(WebInspector.linkifyStringAsFragment(output.description)); | |
elem.removeStyleClass("console-formatted-string"); | |
elem.appendChild(document.createTextNode("\"")); | |
elem.appendChild(span); | |
elem.appendChild(document.createTextNode("\"")); | |
}, | |
_printArray: function(array, elem, properties) | |
{ | |
if (!properties) | |
return; | |
var elements = []; | |
for (var i = 0; i < properties.length; ++i) { | |
var property = properties[i]; | |
var name = property.name; | |
if (!isNaN(name)) | |
elements[name] = this._formatAsArrayEntry(property.value); | |
} | |
elem.appendChild(document.createTextNode("[")); | |
var lastNonEmptyIndex = -1; | |
function appendUndefined(elem, index) | |
{ | |
if (index - lastNonEmptyIndex <= 1) | |
return; | |
var span = elem.createChild(span, "console-formatted-undefined"); | |
span.textContent = WebInspector.UIString("undefined × %d", index - lastNonEmptyIndex - 1); | |
} | |
var length = array.arrayLength(); | |
for (var i = 0; i < length; ++i) { | |
var element = elements[i]; | |
if (!element) | |
continue; | |
if (i - lastNonEmptyIndex > 1) { | |
appendUndefined(elem, i); | |
elem.appendChild(document.createTextNode(", ")); | |
} | |
elem.appendChild(element); | |
lastNonEmptyIndex = i; | |
if (i < length - 1) | |
elem.appendChild(document.createTextNode(", ")); | |
} | |
appendUndefined(elem, length); | |
elem.appendChild(document.createTextNode("]")); | |
}, | |
_formatAsArrayEntry: function(output) | |
{ | |
return this._formatParameter(output, output.subtype && output.subtype === "array", false); | |
}, | |
_formatWithSubstitutionString: function(parameters, formattedResult) | |
{ | |
var formatters = {} | |
function parameterFormatter(force, obj) | |
{ | |
return this._formatParameter(obj, force, false); | |
} | |
function valueFormatter(obj) | |
{ | |
return obj.description; | |
} | |
formatters.o = parameterFormatter.bind(this, false); | |
formatters.s = valueFormatter; | |
formatters.f = valueFormatter; | |
formatters.i = valueFormatter; | |
formatters.d = valueFormatter; | |
formatters.O = parameterFormatter.bind(this, true); | |
function append(a, b) | |
{ | |
if (!(b instanceof Node)) | |
a.appendChild(WebInspector.linkifyStringAsFragment(b.toString())); | |
else | |
a.appendChild(b); | |
return a; | |
} | |
return String.format(parameters[0].description, parameters.slice(1), formatters, formattedResult, append); | |
}, | |
clearHighlight: function() | |
{ | |
if (!this._formattedMessage) | |
return; | |
var highlightedMessage = this._formattedMessage; | |
delete this._formattedMessage; | |
delete this._anchorElement; | |
delete this._messageElement; | |
this._formatMessage(); | |
this._element.replaceChild(this._formattedMessage, highlightedMessage); | |
}, | |
highlightSearchResults: function(regexObject) | |
{ | |
if (!this._formattedMessage) | |
return; | |
this._highlightSearchResultsInElement(regexObject, this._messageElement); | |
if (this._anchorElement) | |
this._highlightSearchResultsInElement(regexObject, this._anchorElement); | |
this._element.scrollIntoViewIfNeeded(); | |
}, | |
_highlightSearchResultsInElement: function(regexObject, element) | |
{ | |
regexObject.lastIndex = 0; | |
var text = element.textContent; | |
var match = regexObject.exec(text); | |
var offset = 0; | |
var matchRanges = []; | |
while (match) { | |
matchRanges.push({ offset: match.index, length: match[0].length }); | |
match = regexObject.exec(text); | |
} | |
WebInspector.highlightSearchResults(element, matchRanges); | |
}, | |
matchesRegex: function(regexObject) | |
{ | |
return regexObject.test(this._message) || (this._anchorElement && regexObject.test(this._anchorElement.textContent)); | |
}, | |
toMessageElement: function() | |
{ | |
if (this._element) | |
return this._element; | |
var element = document.createElement("div"); | |
element.message = this; | |
element.className = "console-message"; | |
this._element = element; | |
switch (this.level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
element.addStyleClass("console-tip-level"); | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Log: | |
element.addStyleClass("console-log-level"); | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Debug: | |
element.addStyleClass("console-debug-level"); | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
element.addStyleClass("console-warning-level"); | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
element.addStyleClass("console-error-level"); | |
break; | |
} | |
if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) | |
element.addStyleClass("console-group-title"); | |
element.appendChild(this.formattedMessage); | |
if (this.repeatCount > 1) | |
this.updateRepeatCount(); | |
return element; | |
}, | |
_populateStackTraceTreeElement: function(parentTreeElement) | |
{ | |
for (var i = 0; i < this._stackTrace.length; i++) { | |
var frame = this._stackTrace[i]; | |
var content = document.createElement("div"); | |
var messageTextElement = document.createElement("span"); | |
messageTextElement.className = "console-message-text source-code"; | |
var functionName = frame.functionName || WebInspector.UIString("(anonymous function)"); | |
messageTextElement.appendChild(document.createTextNode(functionName)); | |
content.appendChild(messageTextElement); | |
if (frame.url) { | |
content.appendChild(document.createTextNode(" ")); | |
var urlElement = this._linkifyCallFrame(frame); | |
content.appendChild(urlElement); | |
} | |
var treeElement = new TreeElement(content); | |
parentTreeElement.appendChild(treeElement); | |
} | |
}, | |
updateRepeatCount: function() { | |
if (!this.repeatCountElement) { | |
this.repeatCountElement = document.createElement("span"); | |
this.repeatCountElement.className = "bubble"; | |
this._element.insertBefore(this.repeatCountElement, this._element.firstChild); | |
this._element.addStyleClass("repeated-message"); | |
} | |
this.repeatCountElement.textContent = this.repeatCount; | |
}, | |
toString: function() | |
{ | |
var sourceString; | |
switch (this.source) { | |
case WebInspector.ConsoleMessage.MessageSource.HTML: | |
sourceString = "HTML"; | |
break; | |
case WebInspector.ConsoleMessage.MessageSource.XML: | |
sourceString = "XML"; | |
break; | |
case WebInspector.ConsoleMessage.MessageSource.JS: | |
sourceString = "JS"; | |
break; | |
case WebInspector.ConsoleMessage.MessageSource.Network: | |
sourceString = "Network"; | |
break; | |
case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI: | |
sourceString = "ConsoleAPI"; | |
break; | |
case WebInspector.ConsoleMessage.MessageSource.Other: | |
sourceString = "Other"; | |
break; | |
} | |
var typeString; | |
switch (this.type) { | |
case WebInspector.ConsoleMessage.MessageType.Log: | |
typeString = "Log"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Dir: | |
typeString = "Dir"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.DirXML: | |
typeString = "Dir XML"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Trace: | |
typeString = "Trace"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed: | |
case WebInspector.ConsoleMessage.MessageType.StartGroup: | |
typeString = "Start Group"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.EndGroup: | |
typeString = "End Group"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Assert: | |
typeString = "Assert"; | |
break; | |
case WebInspector.ConsoleMessage.MessageType.Result: | |
typeString = "Result"; | |
break; | |
} | |
var levelString; | |
switch (this.level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
levelString = "Tip"; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Log: | |
levelString = "Log"; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
levelString = "Warning"; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Debug: | |
levelString = "Debug"; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
levelString = "Error"; | |
break; | |
} | |
return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; | |
}, | |
get text() | |
{ | |
return this._messageText; | |
}, | |
location: function() | |
{ | |
var lineNumber = this.stackTrace ? this.stackTrace[0].lineNumber - 1 : this.line - 1; | |
var columnNumber = this.stackTrace && this.stackTrace[0].columnNumber ? this.stackTrace[0].columnNumber - 1 : 0; | |
return WebInspector.debuggerModel.createRawLocationByURL(this.url, lineNumber, columnNumber); | |
}, | |
isEqual: function(msg) | |
{ | |
if (!msg) | |
return false; | |
if (this._stackTrace) { | |
if (!msg._stackTrace) | |
return false; | |
var l = this._stackTrace; | |
var r = msg._stackTrace; | |
for (var i = 0; i < l.length; i++) { | |
if (l[i].url !== r[i].url || | |
l[i].functionName !== r[i].functionName || | |
l[i].lineNumber !== r[i].lineNumber || | |
l[i].columnNumber !== r[i].columnNumber) | |
return false; | |
} | |
} | |
return (this.source === msg.source) | |
&& (this.type === msg.type) | |
&& (this.level === msg.level) | |
&& (this.line === msg.line) | |
&& (this.url === msg.url) | |
&& (this.message === msg.message) | |
&& (this._request === msg._request); | |
}, | |
get stackTrace() | |
{ | |
return this._stackTrace; | |
}, | |
clone: function() | |
{ | |
return WebInspector.ConsoleMessage.create(this.source, this.level, this._messageText, this.type, this.url, this.line, this.repeatCount, this._parameters, this._stackTrace, this._request ? this._request.requestId : undefined, this._isOutdated); | |
} | |
} | |
WebInspector.ConsoleMessageImpl.prototype.__proto__ = WebInspector.ConsoleMessage.prototype; | |
const ExpressionStopCharacters = " =:[({;,!+-*/&|^<>"; | |
WebInspector.ConsoleView = function(hideContextSelector) | |
{ | |
WebInspector.View.call(this); | |
this.element.id = "console-view"; | |
this.messages = []; | |
this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear console log."), "clear-status-bar-item"); | |
this._clearConsoleButton.addEventListener("click", this._requestClearMessages, this); | |
this._frameSelector = new WebInspector.StatusBarComboBox(this._frameChanged.bind(this), "console-context"); | |
this._contextSelector = new WebInspector.StatusBarComboBox(this._contextChanged.bind(this), "console-context"); | |
if (hideContextSelector) { | |
this._frameSelector.element.addStyleClass("hidden"); | |
this._contextSelector.element.addStyleClass("hidden"); | |
} | |
this.messagesElement = document.createElement("div"); | |
this.messagesElement.id = "console-messages"; | |
this.messagesElement.className = "monospace"; | |
this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true); | |
this.element.appendChild(this.messagesElement); | |
this._scrolledToBottom = true; | |
this.promptElement = document.createElement("div"); | |
this.promptElement.id = "console-prompt"; | |
this.promptElement.className = "source-code"; | |
this.promptElement.spellcheck = false; | |
this.messagesElement.appendChild(this.promptElement); | |
this.messagesElement.appendChild(document.createElement("br")); | |
this.topGroup = new WebInspector.ConsoleGroup(null); | |
this.messagesElement.insertBefore(this.topGroup.element, this.promptElement); | |
this.currentGroup = this.topGroup; | |
this._filterBarElement = document.createElement("div"); | |
this._filterBarElement.className = "scope-bar status-bar-item"; | |
function createDividerElement() | |
{ | |
var dividerElement = document.createElement("div"); | |
dividerElement.addStyleClass("scope-bar-divider"); | |
this._filterBarElement.appendChild(dividerElement); | |
} | |
var updateFilterHandler = this._updateFilter.bind(this); | |
function createFilterElement(category, label) | |
{ | |
var categoryElement = document.createElement("li"); | |
categoryElement.category = category; | |
categoryElement.className = category; | |
categoryElement.addEventListener("click", updateFilterHandler, false); | |
categoryElement.textContent = label; | |
this._filterBarElement.appendChild(categoryElement); | |
return categoryElement; | |
} | |
this.allElement = createFilterElement.call(this, "all", WebInspector.UIString("All")); | |
createDividerElement.call(this); | |
this.errorElement = createFilterElement.call(this, "errors", WebInspector.UIString("Errors")); | |
this.warningElement = createFilterElement.call(this, "warnings", WebInspector.UIString("Warnings")); | |
this.logElement = createFilterElement.call(this, "logs", WebInspector.UIString("Logs")); | |
this.filter(this.allElement, false); | |
this._registerShortcuts(); | |
this.registerRequiredCSS("textPrompt.css"); | |
this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false); | |
WebInspector.settings.monitoringXHREnabled.addChangeListener(this._monitoringXHREnabledSettingChanged.bind(this)); | |
WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this); | |
WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); | |
this._linkifier = new WebInspector.Linkifier(); | |
this.prompt = new WebInspector.TextPromptWithHistory(this.completionsForTextPrompt.bind(this), ExpressionStopCharacters + "."); | |
this.prompt.setSuggestBoxEnabled("generic-suggest"); | |
this.prompt.renderAsBlock(); | |
this.prompt.attach(this.promptElement); | |
this.prompt.proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), false); | |
this.prompt.setHistoryData(WebInspector.settings.consoleHistory.get()); | |
WebInspector.runtimeModel.contextLists().forEach(this._addFrame, this); | |
WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListAdded, this._frameAdded, this); | |
WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListRemoved, this._frameRemoved, this); | |
} | |
WebInspector.ConsoleView.Events = { | |
ConsoleCleared: "console-cleared", | |
EntryAdded: "console-entry-added", | |
} | |
WebInspector.ConsoleView.prototype = { | |
get statusBarItems() | |
{ | |
return [this._clearConsoleButton.element, this._frameSelector.element, this._contextSelector.element, this._filterBarElement]; | |
}, | |
_frameAdded: function(event) | |
{ | |
var contextList = event.data; | |
this._addFrame(contextList); | |
}, | |
_addFrame: function(contextList) | |
{ | |
var option = document.createElement("option"); | |
option.text = contextList.displayName; | |
option.title = contextList.url; | |
option._contextList = contextList; | |
contextList._consoleOption = option; | |
this._frameSelector.addOption(option); | |
contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextsUpdated, this._frameUpdated, this); | |
contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextAdded, this._contextAdded, this); | |
this._frameChanged(); | |
}, | |
_frameRemoved: function(event) | |
{ | |
var contextList = event.data; | |
this._frameSelector.removeOption(contextList._consoleOption); | |
this._frameChanged(); | |
}, | |
_frameChanged: function() | |
{ | |
var context = this._currentFrame(); | |
if (!context) { | |
delete this._currentExecutionContext; | |
this._contextSelector.element.addStyleClass("hidden"); | |
return; | |
} | |
var executionContexts = context.executionContexts(); | |
if (executionContexts.length) | |
this._currentExecutionContext = executionContexts[0]; | |
if (executionContexts.length === 1) { | |
this._contextSelector.element.addStyleClass("hidden"); | |
return; | |
} | |
this._contextSelector.element.removeStyleClass("hidden"); | |
this._contextSelector.removeOptions(); | |
for (var i = 0; i < executionContexts.length; i++) | |
this._appendContextOption(executionContexts[i]); | |
}, | |
_appendContextOption: function(executionContext) | |
{ | |
if (!this._currentExecutionContext) | |
this._currentExecutionContext = executionContext; | |
var option = document.createElement("option"); | |
option.text = executionContext.name; | |
option.title = executionContext.id; | |
option._executionContext = executionContext; | |
this._contextSelector.addOption(option); | |
}, | |
_contextChanged: function(event) | |
{ | |
var option = this._contextSelector.selectedOption(); | |
this._currentExecutionContext = option ? option._executionContext : undefined; | |
}, | |
_frameUpdated: function(event) | |
{ | |
var contextList = event.data; | |
var option = contextList._consoleOption; | |
option.text = contextList.displayName; | |
option.title = contextList.url; | |
}, | |
_contextAdded: function(event) | |
{ | |
var contextList = event.data; | |
if (contextList === this._currentFrame()) | |
this._frameChanged(); | |
}, | |
_currentFrame: function() | |
{ | |
var option = this._frameSelector.selectedOption(); | |
return option ? option._contextList : undefined; | |
}, | |
_updateFilter: function(e) | |
{ | |
var isMac = WebInspector.isMac(); | |
var selectMultiple = false; | |
if (isMac && e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) | |
selectMultiple = true; | |
if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey) | |
selectMultiple = true; | |
this.filter(e.target, selectMultiple); | |
}, | |
filter: function(target, selectMultiple) | |
{ | |
function unselectAll() | |
{ | |
this.allElement.removeStyleClass("selected"); | |
this.errorElement.removeStyleClass("selected"); | |
this.warningElement.removeStyleClass("selected"); | |
this.logElement.removeStyleClass("selected"); | |
this.messagesElement.removeStyleClass("filter-all"); | |
this.messagesElement.removeStyleClass("filter-errors"); | |
this.messagesElement.removeStyleClass("filter-warnings"); | |
this.messagesElement.removeStyleClass("filter-logs"); | |
} | |
var targetFilterClass = "filter-" + target.category; | |
if (target.category === "all") { | |
if (target.hasStyleClass("selected")) { | |
return; | |
} | |
unselectAll.call(this); | |
} else { | |
if (this.allElement.hasStyleClass("selected")) { | |
this.allElement.removeStyleClass("selected"); | |
this.messagesElement.removeStyleClass("filter-all"); | |
} | |
} | |
if (!selectMultiple) { | |
unselectAll.call(this); | |
target.addStyleClass("selected"); | |
this.messagesElement.addStyleClass(targetFilterClass); | |
return; | |
} | |
if (target.hasStyleClass("selected")) { | |
target.removeStyleClass("selected"); | |
this.messagesElement.removeStyleClass(targetFilterClass); | |
} else { | |
target.addStyleClass("selected"); | |
this.messagesElement.addStyleClass(targetFilterClass); | |
} | |
}, | |
willHide: function() | |
{ | |
this.prompt.hideSuggestBox(); | |
this.prompt.clearAutoComplete(true); | |
}, | |
wasShown: function() | |
{ | |
if (!this.prompt.isCaretInsidePrompt()) | |
this.prompt.moveCaretToEndOfPrompt(); | |
}, | |
afterShow: function() | |
{ | |
WebInspector.setCurrentFocusElement(this.promptElement); | |
}, | |
storeScrollPositions: function() | |
{ | |
WebInspector.View.prototype.storeScrollPositions.call(this); | |
this._scrolledToBottom = this.messagesElement.isScrolledToBottom(); | |
}, | |
restoreScrollPositions: function() | |
{ | |
if (this._scrolledToBottom) | |
this._immediatelyScrollIntoView(); | |
else | |
WebInspector.View.prototype.restoreScrollPositions.call(this); | |
}, | |
onResize: function() | |
{ | |
this.restoreScrollPositions(); | |
}, | |
_isScrollIntoViewScheduled: function() | |
{ | |
return !!this._scrollIntoViewTimer; | |
}, | |
_scheduleScrollIntoView: function() | |
{ | |
if (this._scrollIntoViewTimer) | |
return; | |
function scrollIntoView() | |
{ | |
delete this._scrollIntoViewTimer; | |
this.promptElement.scrollIntoView(true); | |
} | |
this._scrollIntoViewTimer = setTimeout(scrollIntoView.bind(this), 20); | |
}, | |
_immediatelyScrollIntoView: function() | |
{ | |
this.promptElement.scrollIntoView(true); | |
this._cancelScheduledScrollIntoView(); | |
}, | |
_cancelScheduledScrollIntoView: function() | |
{ | |
if (!this._isScrollIntoViewScheduled()) | |
return; | |
clearTimeout(this._scrollIntoViewTimer); | |
delete this._scrollIntoViewTimer; | |
}, | |
_consoleMessageAdded: function(event) | |
{ | |
this._appendConsoleMessage(event.data); | |
}, | |
_appendConsoleMessage: function(msg) | |
{ | |
if (!this._isScrollIntoViewScheduled() && ((msg instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom())) | |
this._scheduleScrollIntoView(); | |
this.messages.push(msg); | |
if (msg.type === WebInspector.ConsoleMessage.MessageType.EndGroup) { | |
var parentGroup = this.currentGroup.parentGroup | |
if (parentGroup) | |
this.currentGroup = parentGroup; | |
} else { | |
if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) { | |
var group = new WebInspector.ConsoleGroup(this.currentGroup); | |
this.currentGroup.messagesElement.appendChild(group.element); | |
this.currentGroup = group; | |
} | |
this.currentGroup.addMessage(msg); | |
} | |
this.dispatchEventToListeners(WebInspector.ConsoleView.Events.EntryAdded, msg); | |
}, | |
_consoleCleared: function() | |
{ | |
this._scrolledToBottom = true; | |
this.messages = []; | |
this.currentGroup = this.topGroup; | |
this.topGroup.messagesElement.removeChildren(); | |
this.dispatchEventToListeners(WebInspector.ConsoleView.Events.ConsoleCleared); | |
this._linkifier.reset(); | |
}, | |
completionsForTextPrompt: function(textPrompt, wordRange, force, completionsReadyCallback) | |
{ | |
var expressionRange = wordRange.startContainer.rangeOfWord(wordRange.startOffset, ExpressionStopCharacters, textPrompt.proxyElement, "backward"); | |
var expressionString = expressionRange.toString(); | |
var prefix = wordRange.toString(); | |
this.completionsForExpression(expressionString, prefix, force, completionsReadyCallback); | |
}, | |
completionsForExpression: function(expressionString, prefix, force, completionsReadyCallback) | |
{ | |
var lastIndex = expressionString.length - 1; | |
var dotNotation = (expressionString[lastIndex] === "."); | |
var bracketNotation = (expressionString[lastIndex] === "["); | |
if (dotNotation || bracketNotation) | |
expressionString = expressionString.substr(0, lastIndex); | |
if (expressionString && parseInt(expressionString, 10) == expressionString) { | |
completionsReadyCallback([]); | |
return; | |
} | |
if (!prefix && !expressionString && !force) { | |
completionsReadyCallback([]); | |
return; | |
} | |
if (!expressionString && WebInspector.debuggerModel.selectedCallFrame()) | |
WebInspector.debuggerModel.getSelectedCallFrameVariables(receivedPropertyNames.bind(this)); | |
else | |
this.evalInInspectedWindow(expressionString, "completion", true, true, false, evaluated.bind(this)); | |
function evaluated(result, wasThrown) | |
{ | |
if (!result || wasThrown) { | |
completionsReadyCallback([]); | |
return; | |
} | |
function getCompletions(primitiveType) | |
{ | |
var object; | |
if (primitiveType === "string") | |
object = new String(""); | |
else if (primitiveType === "number") | |
object = new Number(0); | |
else if (primitiveType === "boolean") | |
object = new Boolean(false); | |
else | |
object = this; | |
var resultSet = {}; | |
for (var o = object; o; o = o.__proto__) { | |
try { | |
var names = Object.getOwnPropertyNames(o); | |
for (var i = 0; i < names.length; ++i) | |
resultSet[names[i]] = true; | |
} catch (e) { | |
} | |
} | |
return resultSet; | |
} | |
if (result.type === "object" || result.type === "function") | |
result.callFunctionJSON(getCompletions, undefined, receivedPropertyNames.bind(this)); | |
else if (result.type === "string" || result.type === "number" || result.type === "boolean") | |
this.evalInInspectedWindow("(" + getCompletions + ")(\"" + result.type + "\")", "completion", false, true, true, receivedPropertyNamesFromEval.bind(this)); | |
} | |
function receivedPropertyNamesFromEval(notRelevant, wasThrown, result) | |
{ | |
if (result && !wasThrown) | |
receivedPropertyNames.call(this, result.value); | |
else | |
completionsReadyCallback([]); | |
} | |
function receivedPropertyNames(propertyNames) | |
{ | |
RuntimeAgent.releaseObjectGroup("completion"); | |
if (!propertyNames) { | |
completionsReadyCallback([]); | |
return; | |
} | |
var includeCommandLineAPI = (!dotNotation && !bracketNotation); | |
if (includeCommandLineAPI) { | |
const commandLineAPI = ["dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear"]; | |
for (var i = 0; i < commandLineAPI.length; ++i) | |
propertyNames[commandLineAPI[i]] = true; | |
} | |
this._reportCompletions(completionsReadyCallback, dotNotation, bracketNotation, expressionString, prefix, Object.keys(propertyNames)); | |
} | |
}, | |
_reportCompletions: function(completionsReadyCallback, dotNotation, bracketNotation, expressionString, prefix, properties) { | |
if (bracketNotation) { | |
if (prefix.length && prefix[0] === "'") | |
var quoteUsed = "'"; | |
else | |
var quoteUsed = "\""; | |
} | |
var results = []; | |
if (!expressionString) { | |
const keywords = ["break", "case", "catch", "continue", "default", "delete", "do", "else", "finally", "for", "function", "if", "in", | |
"instanceof", "new", "return", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with"]; | |
properties = properties.concat(keywords); | |
} | |
properties.sort(); | |
for (var i = 0; i < properties.length; ++i) { | |
var property = properties[i]; | |
if (dotNotation && !/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(property)) | |
continue; | |
if (bracketNotation) { | |
if (!/^[0-9]+$/.test(property)) | |
property = quoteUsed + property.escapeCharacters(quoteUsed + "\\") + quoteUsed; | |
property += "]"; | |
} | |
if (property.length < prefix.length) | |
continue; | |
if (prefix.length && !property.startsWith(prefix)) | |
continue; | |
results.push(property); | |
} | |
completionsReadyCallback(results); | |
}, | |
_handleContextMenuEvent: function(event) | |
{ | |
if (!window.getSelection().isCollapsed) { | |
return; | |
} | |
if (event.target.enclosingNodeOrSelfWithNodeName("a")) | |
return; | |
var contextMenu = new WebInspector.ContextMenu(); | |
function monitoringXHRItemAction() | |
{ | |
WebInspector.settings.monitoringXHREnabled.set(!WebInspector.settings.monitoringXHREnabled.get()); | |
} | |
contextMenu.appendCheckboxItem(WebInspector.UIString("Log XMLHttpRequests"), monitoringXHRItemAction.bind(this), WebInspector.settings.monitoringXHREnabled.get()); | |
function preserveLogItemAction() | |
{ | |
WebInspector.settings.preserveConsoleLog.set(!WebInspector.settings.preserveConsoleLog.get()); | |
} | |
contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Preserve log upon navigation" : "Preserve Log upon Navigation"), preserveLogItemAction.bind(this), WebInspector.settings.preserveConsoleLog.get()); | |
contextMenu.appendSeparator(); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear console" : "Clear Console"), this._requestClearMessages.bind(this)); | |
contextMenu.show(event); | |
}, | |
_monitoringXHREnabledSettingChanged: function(event) | |
{ | |
ConsoleAgent.setMonitoringXHREnabled(event.data); | |
}, | |
_messagesClicked: function(event) | |
{ | |
if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed) | |
this.prompt.moveCaretToEndOfPrompt(); | |
}, | |
_registerShortcuts: function() | |
{ | |
this._shortcuts = {}; | |
var shortcut = WebInspector.KeyboardShortcut; | |
if (WebInspector.isMac()) { | |
var shortcutK = shortcut.makeDescriptor("k", WebInspector.KeyboardShortcut.Modifiers.Meta); | |
this._shortcuts[shortcutK.key] = this._requestClearMessages.bind(this); | |
} | |
var shortcutL = shortcut.makeDescriptor("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl); | |
this._shortcuts[shortcutL.key] = this._requestClearMessages.bind(this); | |
var shortcutM = shortcut.makeDescriptor("m", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta | WebInspector.KeyboardShortcut.Modifiers.Shift); | |
this._shortcuts[shortcutM.key] = this._dumpMemory.bind(this); | |
var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Console")); | |
var keys = WebInspector.isMac() ? [ shortcutK.name, shortcutL.name ] : [ shortcutL.name ]; | |
section.addAlternateKeys(keys, WebInspector.UIString("Clear console")); | |
keys = [ | |
shortcut.shortcutToString(shortcut.Keys.Tab), | |
shortcut.shortcutToString(shortcut.Keys.Tab, shortcut.Modifiers.Shift) | |
]; | |
section.addRelatedKeys(keys, WebInspector.UIString("Next/previous suggestion")); | |
section.addKey(shortcut.shortcutToString(shortcut.Keys.Right), WebInspector.UIString("Accept suggestion")); | |
keys = [ | |
shortcut.shortcutToString(shortcut.Keys.Down), | |
shortcut.shortcutToString(shortcut.Keys.Up) | |
]; | |
section.addRelatedKeys(keys, WebInspector.UIString("Next/previous line")); | |
keys = [ | |
shortcut.shortcutToString("N", shortcut.Modifiers.Alt), | |
shortcut.shortcutToString("P", shortcut.Modifiers.Alt) | |
]; | |
if (WebInspector.isMac()) | |
section.addRelatedKeys(keys, WebInspector.UIString("Next/previous command")); | |
section.addKey(shortcut.shortcutToString(shortcut.Keys.Enter), WebInspector.UIString("Execute command")); | |
}, | |
_requestClearMessages: function() | |
{ | |
WebInspector.console.requestClearMessages(); | |
}, | |
_promptKeyDown: function(event) | |
{ | |
if (isEnterKey(event)) { | |
this._enterKeyPressed(event); | |
return; | |
} | |
var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); | |
var handler = this._shortcuts[shortcut]; | |
if (handler) { | |
handler(); | |
event.preventDefault(); | |
return; | |
} | |
}, | |
evalInInspectedWindow: function(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback) | |
{ | |
if (WebInspector.debuggerModel.selectedCallFrame()) { | |
WebInspector.debuggerModel.evaluateOnSelectedCallFrame(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, callback); | |
return; | |
} | |
if (!expression) { | |
expression = "this"; | |
} | |
function evalCallback(error, result, wasThrown) | |
{ | |
if (error) { | |
console.error(error); | |
callback(null, false); | |
return; | |
} | |
if (returnByValue) | |
callback(null, !!wasThrown, wasThrown ? null : result); | |
else | |
callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown); | |
} | |
RuntimeAgent.evaluate(expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, this._currentExecutionContext ? this._currentExecutionContext.id : undefined, returnByValue, evalCallback); | |
}, | |
evaluateUsingTextPrompt: function(expression, showResultOnly) | |
{ | |
this._appendCommand(expression, this.prompt.text, false, showResultOnly); | |
}, | |
_enterKeyPressed: function(event) | |
{ | |
if (event.altKey || event.ctrlKey || event.shiftKey) | |
return; | |
event.consume(true); | |
this.prompt.clearAutoComplete(true); | |
var str = this.prompt.text; | |
if (!str.length) | |
return; | |
this._appendCommand(str, "", true, false); | |
}, | |
runScript: function(scriptId) | |
{ | |
DebuggerAgent.runScript(scriptId, this._currentExecutionContext ? this._currentExecutionContext.id : undefined, "console", false, runCallback.bind(this)); | |
WebInspector.userMetrics.ConsoleEvaluated.record(); | |
function runCallback(error, result, wasThrown) | |
{ | |
if (error) { | |
console.error(error); | |
return; | |
} | |
this._printResult(result, wasThrown, null); | |
} | |
}, | |
_printResult: function(result, wasThrown, originatingCommand) | |
{ | |
if (!result) | |
return; | |
this._appendConsoleMessage(new WebInspector.ConsoleCommandResult(result, wasThrown, originatingCommand, this._linkifier)); | |
}, | |
_appendCommand: function(text, newPromptText, useCommandLineAPI, showResultOnly) | |
{ | |
if (!showResultOnly) { | |
var commandMessage = new WebInspector.ConsoleCommand(text); | |
WebInspector.console.interruptRepeatCount(); | |
this._appendConsoleMessage(commandMessage); | |
} | |
this.prompt.text = newPromptText; | |
function printResult(result, wasThrown) | |
{ | |
if (!result) | |
return; | |
if (!showResultOnly) { | |
this.prompt.pushHistoryItem(text); | |
WebInspector.settings.consoleHistory.set(this.prompt.historyData.slice(-30)); | |
} | |
this._printResult(result, wasThrown, commandMessage); | |
} | |
this.evalInInspectedWindow(text, "console", useCommandLineAPI, false, false, printResult.bind(this)); | |
WebInspector.userMetrics.ConsoleEvaluated.record(); | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return [this.messagesElement]; | |
}, | |
_dumpMemory: function() | |
{ | |
function comparator(a, b) | |
{ | |
if (a.size < b.size) | |
return 1; | |
if (a.size > b.size) | |
return -1; | |
return a.title.localeCompare(b.title); | |
} | |
function callback(error, groups) | |
{ | |
var titles = []; | |
groups.sort(comparator); | |
for (var i = 0; i < groups.length; ++i) { | |
var suffix = groups[i].size > 0 ? " [" + groups[i].size + "]" : ""; | |
titles.push(groups[i].title + suffix + (groups[i].documentURI ? " (" + groups[i].documentURI + ")" : "")); | |
} | |
var counter = 1; | |
var previousTitle = null; | |
for (var i = 0; i < titles.length; ++i) { | |
var title = titles[i]; | |
if (title === previousTitle) { | |
counter++; | |
continue; | |
} | |
if (previousTitle) | |
WebInspector.log(counter > 1 ? counter + " x " + previousTitle : previousTitle); | |
previousTitle = title; | |
counter = 1; | |
} | |
WebInspector.log(counter > 1 ? counter + " x " + previousTitle : previousTitle); | |
} | |
MemoryAgent.getDOMNodeCount(callback); | |
} | |
} | |
WebInspector.ConsoleView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.ConsoleCommand = function(command) | |
{ | |
this.command = command; | |
} | |
WebInspector.ConsoleCommand.prototype = { | |
clearHighlight: function() | |
{ | |
var highlightedMessage = this._formattedCommand; | |
delete this._formattedCommand; | |
this._formatCommand(); | |
this._element.replaceChild(this._formattedCommand, highlightedMessage); | |
}, | |
highlightSearchResults: function(regexObject) | |
{ | |
regexObject.lastIndex = 0; | |
var text = this.command; | |
var match = regexObject.exec(text); | |
var offset = 0; | |
var matchRanges = []; | |
while (match) { | |
matchRanges.push({ offset: match.index, length: match[0].length }); | |
match = regexObject.exec(text); | |
} | |
WebInspector.highlightSearchResults(this._formattedCommand, matchRanges); | |
this._element.scrollIntoViewIfNeeded(); | |
}, | |
matchesRegex: function(regexObject) | |
{ | |
return regexObject.test(this.command); | |
}, | |
toMessageElement: function() | |
{ | |
if (!this._element) { | |
this._element = document.createElement("div"); | |
this._element.command = this; | |
this._element.className = "console-user-command"; | |
this._formatCommand(); | |
this._element.appendChild(this._formattedCommand); | |
} | |
return this._element; | |
}, | |
_formatCommand: function() | |
{ | |
this._formattedCommand = document.createElement("span"); | |
this._formattedCommand.className = "console-message-text source-code"; | |
this._formattedCommand.textContent = this.command; | |
}, | |
} | |
WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand, linkifier) | |
{ | |
var level = (wasThrown ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log); | |
this.originatingCommand = originatingCommand; | |
WebInspector.ConsoleMessageImpl.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, "", linkifier, WebInspector.ConsoleMessage.MessageType.Result, undefined, undefined, undefined, [result]); | |
} | |
WebInspector.ConsoleCommandResult.prototype = { | |
toMessageElement: function() | |
{ | |
var element = WebInspector.ConsoleMessageImpl.prototype.toMessageElement.call(this); | |
element.addStyleClass("console-user-command-result"); | |
return element; | |
} | |
} | |
WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessageImpl.prototype; | |
WebInspector.ConsoleGroup = function(parentGroup) | |
{ | |
this.parentGroup = parentGroup; | |
var element = document.createElement("div"); | |
element.className = "console-group"; | |
element.group = this; | |
this.element = element; | |
if (parentGroup) { | |
var bracketElement = document.createElement("div"); | |
bracketElement.className = "console-group-bracket"; | |
element.appendChild(bracketElement); | |
} | |
var messagesElement = document.createElement("div"); | |
messagesElement.className = "console-group-messages"; | |
element.appendChild(messagesElement); | |
this.messagesElement = messagesElement; | |
} | |
WebInspector.ConsoleGroup.prototype = { | |
addMessage: function(msg) | |
{ | |
var element = msg.toMessageElement(); | |
if (msg.type === WebInspector.ConsoleMessage.MessageType.StartGroup || msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) { | |
this.messagesElement.parentNode.insertBefore(element, this.messagesElement); | |
element.addEventListener("click", this._titleClicked.bind(this), false); | |
var groupElement = element.enclosingNodeOrSelfWithClass("console-group"); | |
if (groupElement && msg.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) | |
groupElement.addStyleClass("collapsed"); | |
} else | |
this.messagesElement.appendChild(element); | |
if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand) | |
element.previousSibling.addStyleClass("console-adjacent-user-command-result"); | |
}, | |
_titleClicked: function(event) | |
{ | |
var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title"); | |
if (groupTitleElement) { | |
var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group"); | |
if (groupElement) | |
if (groupElement.hasStyleClass("collapsed")) | |
groupElement.removeStyleClass("collapsed"); | |
else | |
groupElement.addStyleClass("collapsed"); | |
groupTitleElement.scrollIntoViewIfNeeded(true); | |
} | |
event.consume(true); | |
} | |
} | |
WebInspector.consoleView = null; | |
WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, repeatCount, parameters, stackTrace, requestId, isOutdated) | |
{ | |
return new WebInspector.ConsoleMessageImpl(source, level, message, WebInspector.consoleView._linkifier, type, url, line, repeatCount, parameters, stackTrace, requestId, isOutdated); | |
} | |
WebInspector.Panel = function(name) | |
{ | |
WebInspector.View.call(this); | |
WebInspector.panels[name] = this; | |
this.element.addStyleClass("panel"); | |
this.element.addStyleClass(name); | |
this._panelName = name; | |
this._shortcuts = {}; | |
WebInspector.settings[this._sidebarWidthSettingName()] = WebInspector.settings.createSetting(this._sidebarWidthSettingName(), undefined); | |
} | |
WebInspector.Panel.counterRightMargin = 25; | |
WebInspector.Panel.prototype = { | |
get name() | |
{ | |
return this._panelName; | |
}, | |
show: function() | |
{ | |
WebInspector.View.prototype.show.call(this, WebInspector.inspectorView.panelsElement()); | |
}, | |
wasShown: function() | |
{ | |
var statusBarItems = this.statusBarItems; | |
if (statusBarItems) { | |
this._statusBarItemContainer = document.createElement("div"); | |
for (var i = 0; i < statusBarItems.length; ++i) | |
this._statusBarItemContainer.appendChild(statusBarItems[i]); | |
document.getElementById("panel-status-bar").appendChild(this._statusBarItemContainer); | |
} | |
this.focus(); | |
}, | |
willHide: function() | |
{ | |
if (this._statusBarItemContainer && this._statusBarItemContainer.parentNode) | |
this._statusBarItemContainer.parentNode.removeChild(this._statusBarItemContainer); | |
delete this._statusBarItemContainer; | |
}, | |
reset: function() | |
{ | |
this.searchCanceled(); | |
}, | |
defaultFocusedElement: function() | |
{ | |
return this.sidebarTreeElement || this.element; | |
}, | |
searchCanceled: function() | |
{ | |
WebInspector.searchController.updateSearchMatchesCount(0, this); | |
}, | |
performSearch: function(query) | |
{ | |
this.searchCanceled(); | |
}, | |
jumpToNextSearchResult: function() | |
{ | |
}, | |
jumpToPreviousSearchResult: function() | |
{ | |
}, | |
canSearchAndReplace: function() | |
{ | |
return false; | |
}, | |
replaceSelectionWith: function(text) | |
{ | |
}, | |
replaceAllWith: function(query, text) | |
{ | |
}, | |
canFilter: function() | |
{ | |
return false; | |
}, | |
performFilter: function(query) | |
{ | |
}, | |
createSplitView: function(parentElement, position, defaultWidth) | |
{ | |
if (this.splitView) | |
return; | |
if (!parentElement) | |
parentElement = this.element; | |
this.splitView = new WebInspector.SplitView(position || WebInspector.SplitView.SidebarPosition.Left, this._sidebarWidthSettingName(), defaultWidth); | |
this.splitView.show(parentElement); | |
this.splitView.addEventListener(WebInspector.SplitView.EventTypes.Resized, this.sidebarResized.bind(this)); | |
this.sidebarElement = this.splitView.sidebarElement; | |
}, | |
createSplitViewWithSidebarTree: function(parentElement, position, defaultWidth) | |
{ | |
if (this.splitView) | |
return; | |
this.createSplitView(parentElement, position); | |
this.sidebarTreeElement = document.createElement("ol"); | |
this.sidebarTreeElement.className = "sidebar-tree"; | |
this.splitView.sidebarElement.appendChild(this.sidebarTreeElement); | |
this.splitView.sidebarElement.addStyleClass("sidebar"); | |
this.sidebarTree = new TreeOutline(this.sidebarTreeElement); | |
this.sidebarTree.panel = this; | |
}, | |
_sidebarWidthSettingName: function() | |
{ | |
return this._panelName + "SidebarWidth"; | |
}, | |
get statusBarItems() | |
{ | |
}, | |
sidebarResized: function(width) | |
{ | |
}, | |
statusBarResized: function() | |
{ | |
}, | |
canShowAnchorLocation: function(anchor) | |
{ | |
return false; | |
}, | |
showAnchorLocation: function(anchor) | |
{ | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return []; | |
}, | |
handleShortcut: function(event) | |
{ | |
var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(event); | |
var handler = this._shortcuts[shortcutKey]; | |
if (handler) { | |
handler(event); | |
event.handled = true; | |
} | |
}, | |
registerShortcut: function(key, handler) | |
{ | |
this._shortcuts[key] = handler; | |
}, | |
unregisterShortcut: function(key) | |
{ | |
delete this._shortcuts[key]; | |
} | |
} | |
WebInspector.Panel.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.PanelDescriptor = function(name, title, className, scriptName, panel) | |
{ | |
this._name = name; | |
this._title = title; | |
this._className = className; | |
this._scriptName = scriptName; | |
this._panel = panel; | |
} | |
WebInspector.PanelDescriptor.prototype = { | |
name: function() | |
{ | |
return this._name; | |
}, | |
title: function() | |
{ | |
return this._title; | |
}, | |
iconURL: function() | |
{ | |
return this._iconURL; | |
}, | |
setIconURL: function(iconURL) | |
{ | |
this._iconURL = iconURL; | |
}, | |
panel: function() | |
{ | |
if (this._panel) | |
return this._panel; | |
if (this._scriptName) | |
importScript(this._scriptName); | |
this._panel = new WebInspector[this._className]; | |
return this._panel; | |
} | |
} | |
WebInspector.InspectorView = function() | |
{ | |
WebInspector.View.call(this); | |
this.markAsRoot(); | |
this.element.id = "main-panels"; | |
this.element.setAttribute("spellcheck", false); | |
this._history = []; | |
this._historyIterator = -1; | |
document.addEventListener("keydown", this._keyDown.bind(this), false); | |
document.addEventListener("keypress", this._keyPress.bind(this), false); | |
this._panelOrder = []; | |
this._panelDescriptors = {}; | |
this._openBracketIdentifiers = ["U+005B", "U+00DB"].keySet(); | |
this._closeBracketIdentifiers = ["U+005D", "U+00DD"].keySet(); | |
this._footerElementContainer = this.element.createChild("div", "inspector-footer status-bar hidden"); | |
this._panelsElement = this.element.createChild("div", "fill"); | |
} | |
WebInspector.InspectorView.Events = { | |
PanelSelected: "PanelSelected" | |
} | |
WebInspector.InspectorView.prototype = { | |
addPanel: function(panelDescriptor) | |
{ | |
this._panelOrder.push(panelDescriptor.name()); | |
this._panelDescriptors[panelDescriptor.name()] = panelDescriptor; | |
WebInspector.toolbar.addPanel(panelDescriptor); | |
}, | |
panel: function(panelName) | |
{ | |
var panelDescriptor = this._panelDescriptors[panelName]; | |
if (!panelDescriptor && this._panelOrder.length) | |
panelDescriptor = this._panelDescriptors[this._panelOrder[0]]; | |
return panelDescriptor ? panelDescriptor.panel() : null; | |
}, | |
showPanel: function(panelName) | |
{ | |
var panel = this.panel(panelName); | |
if (panel) | |
this.setCurrentPanel(panel); | |
return panel; | |
}, | |
currentPanel: function() | |
{ | |
return this._currentPanel; | |
}, | |
setCurrentPanel: function(x) | |
{ | |
if (this._currentPanel === x) | |
return; | |
if (this._currentPanel) | |
this._currentPanel.detach(); | |
this._currentPanel = x; | |
if (x) { | |
x.show(); | |
this.dispatchEventToListeners(WebInspector.InspectorView.Events.PanelSelected); | |
WebInspector.searchController.cancelSearch(); | |
} | |
for (var panelName in WebInspector.panels) { | |
if (WebInspector.panels[panelName] === x) { | |
WebInspector.settings.lastActivePanel.set(panelName); | |
this._pushToHistory(panelName); | |
WebInspector.userMetrics.panelShown(panelName); | |
} | |
} | |
}, | |
_keyPress: function(event) | |
{ | |
clearTimeout(this._keyDownTimer); | |
delete this._keyDownTimer; | |
}, | |
_keyDown: function(event) | |
{ | |
if (!WebInspector.isWin() || (!this._openBracketIdentifiers.hasOwnProperty(event.keyIdentifier) && !this._closeBracketIdentifiers.hasOwnProperty(event.keyIdentifier))) { | |
this._keyDownInternal(event); | |
return; | |
} | |
this._keyDownTimer = setTimeout(this._keyDownInternal.bind(this, event), 0); | |
}, | |
_keyDownInternal: function(event) | |
{ | |
if (this._openBracketIdentifiers.hasOwnProperty(event.keyIdentifier)) { | |
var isRotateLeft = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && !event.altKey; | |
if (isRotateLeft) { | |
var index = this._panelOrder.indexOf(this.currentPanel().name); | |
index = (index === 0) ? this._panelOrder.length - 1 : index - 1; | |
this.showPanel(this._panelOrder[index]); | |
event.consume(true); | |
return; | |
} | |
var isGoBack = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && event.altKey; | |
if (isGoBack && this._canGoBackInHistory()) { | |
this._goBackInHistory(); | |
event.consume(true); | |
} | |
return; | |
} | |
if (this._closeBracketIdentifiers.hasOwnProperty(event.keyIdentifier)) { | |
var isRotateRight = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && !event.altKey; | |
if (isRotateRight) { | |
var index = this._panelOrder.indexOf(this.currentPanel().name); | |
index = (index + 1) % this._panelOrder.length; | |
this.showPanel(this._panelOrder[index]); | |
event.consume(true); | |
return; | |
} | |
var isGoForward = WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && event.altKey; | |
if (isGoForward && this._canGoForwardInHistory()) { | |
this._goForwardInHistory(); | |
event.consume(true); | |
} | |
return; | |
} | |
}, | |
_canGoBackInHistory: function() | |
{ | |
return this._historyIterator > 0; | |
}, | |
_goBackInHistory: function() | |
{ | |
this._inHistory = true; | |
this.setCurrentPanel(WebInspector.panels[this._history[--this._historyIterator]]); | |
delete this._inHistory; | |
}, | |
_canGoForwardInHistory: function() | |
{ | |
return this._historyIterator < this._history.length - 1; | |
}, | |
_goForwardInHistory: function() | |
{ | |
this._inHistory = true; | |
this.setCurrentPanel(WebInspector.panels[this._history[++this._historyIterator]]); | |
delete this._inHistory; | |
}, | |
_pushToHistory: function(panelName) | |
{ | |
if (this._inHistory) | |
return; | |
this._history.splice(this._historyIterator + 1, this._history.length - this._historyIterator - 1); | |
if (!this._history.length || this._history[this._history.length - 1] !== panelName) | |
this._history.push(panelName); | |
this._historyIterator = this._history.length - 1; | |
}, | |
panelsElement: function() | |
{ | |
return this._panelsElement; | |
}, | |
setFooterElement: function(element) | |
{ | |
if (element) { | |
this._footerElementContainer.removeStyleClass("hidden"); | |
this._footerElementContainer.appendChild(element); | |
this._panelsElement.style.bottom = this._footerElementContainer.offsetHeight + "px"; | |
} else { | |
this._footerElementContainer.addStyleClass("hidden"); | |
this._footerElementContainer.removeChildren(); | |
this._panelsElement.style.bottom = 0; | |
} | |
this.doResize(); | |
}, | |
showPanelForAnchorNavigation: function(panel) | |
{ | |
WebInspector.searchController.disableSearchUntilExplicitAction(); | |
this.setCurrentPanel(panel); | |
} | |
} | |
WebInspector.InspectorView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.inspectorView = null; | |
WebInspector.AdvancedSearchController = function() | |
{ | |
this._shortcut = WebInspector.AdvancedSearchController.createShortcut(); | |
this._searchId = 0; | |
WebInspector.settings.advancedSearchConfig = WebInspector.settings.createSetting("advancedSearchConfig", new WebInspector.SearchConfig("", true, false)); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); | |
} | |
WebInspector.AdvancedSearchController.createShortcut = function() | |
{ | |
if (WebInspector.isMac()) | |
return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Alt); | |
else | |
return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Ctrl | WebInspector.KeyboardShortcut.Modifiers.Shift); | |
} | |
WebInspector.AdvancedSearchController.prototype = { | |
handleShortcut: function(event) | |
{ | |
if (WebInspector.KeyboardShortcut.makeKeyFromEvent(event) === this._shortcut.key) { | |
if (!this._searchView || !this._searchView.isShowing() || this._searchView._search !== document.activeElement) { | |
WebInspector.showPanel("scripts"); | |
this.show(); | |
} else | |
this.close(); | |
event.consume(true); | |
return true; | |
} | |
return false; | |
}, | |
_frameNavigated: function() | |
{ | |
this.resetSearch(); | |
}, | |
registerSearchScope: function(searchScope) | |
{ | |
this._searchScope = searchScope; | |
}, | |
show: function() | |
{ | |
if (!this._searchView) | |
this._searchView = new WebInspector.SearchView(this); | |
if (this._searchView.isShowing()) | |
this._searchView.focus(); | |
else | |
WebInspector.showViewInDrawer(this._searchView._searchPanelElement, this._searchView, this.stopSearch.bind(this)); | |
}, | |
close: function() | |
{ | |
this.stopSearch(); | |
WebInspector.closeViewInDrawer(); | |
}, | |
_onSearchResult: function(searchId, searchResult) | |
{ | |
if (searchId !== this._searchId) | |
return; | |
this._searchView.addSearchResult(searchResult); | |
if (!searchResult.searchMatches.length) | |
return; | |
if (!this._searchResultsPane) | |
this._searchResultsPane = this._currentSearchScope.createSearchResultsPane(this._searchConfig); | |
this._searchView.resultsPane = this._searchResultsPane; | |
this._searchResultsPane.addSearchResult(searchResult); | |
}, | |
_onSearchFinished: function(searchId, finished) | |
{ | |
if (searchId !== this._searchId) | |
return; | |
if (!this._searchResultsPane) | |
this._searchView.nothingFound(); | |
this._searchView.searchFinished(finished); | |
}, | |
startSearch: function(searchConfig) | |
{ | |
this.resetSearch(); | |
++this._searchId; | |
this._searchConfig = searchConfig; | |
this._currentSearchScope = this._searchScope; | |
var totalSearchResultsCount = this._currentSearchScope.performSearch(searchConfig, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId)); | |
this._searchView.searchStarted(totalSearchResultsCount); | |
}, | |
resetSearch: function() | |
{ | |
this.stopSearch(); | |
if (this._searchResultsPane) { | |
this._searchView.resetResults(); | |
delete this._searchResultsPane; | |
} | |
}, | |
stopSearch: function() | |
{ | |
if (this._currentSearchScope) | |
this._currentSearchScope.stopSearch(); | |
} | |
} | |
WebInspector.SearchView = function(controller) | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("textEditor.css"); | |
this._controller = controller; | |
this.element.className = "search-view"; | |
this._searchPanelElement = document.createElement("span"); | |
this._searchPanelElement.className = "search-drawer-header"; | |
this._searchPanelElement.addEventListener("keydown", this._onKeyDown.bind(this), false); | |
this._searchResultsElement = this.element.createChild("div"); | |
this._searchResultsElement.className = "search-results"; | |
this._searchLabel = this._searchPanelElement.createChild("span"); | |
this._searchLabel.textContent = WebInspector.UIString("Search sources"); | |
this._search = this._searchPanelElement.createChild("input"); | |
this._search.setAttribute("type", "search"); | |
this._search.addStyleClass("search-config-search"); | |
this._search.setAttribute("results", "0"); | |
this._search.setAttribute("size", 30); | |
this._ignoreCaseLabel = this._searchPanelElement.createChild("label"); | |
this._ignoreCaseLabel.addStyleClass("search-config-label"); | |
this._ignoreCaseCheckbox = this._ignoreCaseLabel.createChild("input"); | |
this._ignoreCaseCheckbox.setAttribute("type", "checkbox"); | |
this._ignoreCaseCheckbox.addStyleClass("search-config-checkbox"); | |
this._ignoreCaseLabel.appendChild(document.createTextNode(WebInspector.UIString("Ignore case"))); | |
this._regexLabel = this._searchPanelElement.createChild("label"); | |
this._regexLabel.addStyleClass("search-config-label"); | |
this._regexCheckbox = this._regexLabel.createChild("input"); | |
this._regexCheckbox.setAttribute("type", "checkbox"); | |
this._regexCheckbox.addStyleClass("search-config-checkbox"); | |
this._regexLabel.appendChild(document.createTextNode(WebInspector.UIString("Regular expression"))); | |
this._searchStatusBarElement = document.createElement("div"); | |
this._searchStatusBarElement.className = "search-status-bar-item"; | |
this._searchMessageElement = this._searchStatusBarElement.createChild("div"); | |
this._searchMessageElement.className = "search-status-bar-message"; | |
this._searchResultsMessageElement = document.createElement("span"); | |
this._searchResultsMessageElement.className = "search-results-status-bar-message"; | |
this._load(); | |
} | |
WebInspector.SearchView.maxQueriesCount = 20; | |
WebInspector.SearchView.prototype = { | |
__proto__: WebInspector.View.prototype, | |
get statusBarItems() | |
{ | |
return [this._searchStatusBarElement, this._searchResultsMessageElement]; | |
}, | |
get searchConfig() | |
{ | |
return new WebInspector.SearchConfig(this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked); | |
}, | |
set resultsPane(resultsPane) | |
{ | |
this.resetResults(); | |
this._searchResultsElement.appendChild(resultsPane.element); | |
}, | |
searchStarted: function(totalSearchResultsCount) | |
{ | |
this.resetResults(); | |
this._resetCounters(); | |
this._searchMessageElement.textContent = WebInspector.UIString("Searching..."); | |
this._progressIndicator = new WebInspector.ProgressIndicator(); | |
this._progressIndicator.setTotalWork(totalSearchResultsCount); | |
this._progressIndicator.show(this._searchStatusBarElement); | |
this._updateSearchResultsMessage(); | |
if (!this._searchingView) | |
this._searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching...")); | |
this._searchingView.show(this._searchResultsElement); | |
}, | |
_updateSearchResultsMessage: function() | |
{ | |
if (this._searchMatchesCount && this._searchResultsCount) | |
this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount); | |
else | |
this._searchResultsMessageElement.textContent = ""; | |
}, | |
resetResults: function() | |
{ | |
if (this._searchingView) | |
this._searchingView.detach(); | |
if (this._notFoundView) | |
this._notFoundView.detach(); | |
this._searchResultsElement.removeChildren(); | |
}, | |
_resetCounters: function() | |
{ | |
this._searchMatchesCount = 0; | |
this._searchResultsCount = 0; | |
this._nonEmptySearchResultsCount = 0; | |
}, | |
nothingFound: function() | |
{ | |
this.resetResults(); | |
if (!this._notFoundView) | |
this._notFoundView = new WebInspector.EmptyView(WebInspector.UIString("No matches found.")); | |
this._notFoundView.show(this._searchResultsElement); | |
this._searchResultsMessageElement.textContent = WebInspector.UIString("No matches found."); | |
}, | |
addSearchResult: function(searchResult) | |
{ | |
this._searchMatchesCount += searchResult.searchMatches.length; | |
this._searchResultsCount++; | |
if (searchResult.searchMatches.length) | |
this._nonEmptySearchResultsCount++; | |
this._updateSearchResultsMessage(); | |
if (this._progressIndicator.isCanceled()) | |
this._onCancel(); | |
else | |
this._progressIndicator.setWorked(this._searchResultsCount); | |
}, | |
searchFinished: function(finished) | |
{ | |
this._progressIndicator.done(); | |
this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted."); | |
}, | |
focus: function() | |
{ | |
WebInspector.setCurrentFocusElement(this._search); | |
this._search.select(); | |
}, | |
wasShown: function() | |
{ | |
this.focus(); | |
}, | |
willHide: function() | |
{ | |
this._controller.stopSearch(); | |
}, | |
_onKeyDown: function(event) | |
{ | |
switch (event.keyCode) { | |
case WebInspector.KeyboardShortcut.Keys.Enter.code: | |
this._onAction(); | |
break; | |
case WebInspector.KeyboardShortcut.Keys.Esc.code: | |
this._controller.close(); | |
event.consume(true); | |
break; | |
} | |
}, | |
_save: function() | |
{ | |
var searchConfig = new WebInspector.SearchConfig(this.searchConfig.query, this.searchConfig.ignoreCase, this.searchConfig.isRegex); | |
WebInspector.settings.advancedSearchConfig.set(searchConfig); | |
}, | |
_load: function() | |
{ | |
var searchConfig = WebInspector.settings.advancedSearchConfig.get(); | |
this._search.value = searchConfig.query; | |
this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase; | |
this._regexCheckbox.checked = searchConfig.isRegex; | |
}, | |
_onCancel: function() | |
{ | |
this._controller.stopSearch(); | |
this.focus(); | |
}, | |
_onAction: function() | |
{ | |
if (!this.searchConfig.query || !this.searchConfig.query.length) | |
return; | |
this._save(); | |
this._controller.startSearch(this.searchConfig); | |
} | |
} | |
WebInspector.SearchConfig = function(query, ignoreCase, isRegex) | |
{ | |
this.query = query; | |
this.ignoreCase = ignoreCase; | |
this.isRegex = isRegex; | |
} | |
WebInspector.SearchScope = function() | |
{ | |
} | |
WebInspector.SearchScope.prototype = { | |
performSearch: function(searchConfig, searchResultCallback, searchFinishedCallback) { }, | |
stopSearch: function() { }, | |
createSearchResultsPane: function(searchConfig) { } | |
} | |
WebInspector.SearchResult = function(offset, length) | |
{ | |
this.offset = offset; | |
this.length = length; | |
} | |
WebInspector.SearchResultsPane = function(searchConfig) | |
{ | |
this._searchConfig = searchConfig; | |
this.element = document.createElement("div"); | |
} | |
WebInspector.SearchResultsPane.prototype = { | |
get searchConfig() | |
{ | |
return this._searchConfig; | |
}, | |
addSearchResult: function(searchResult) { } | |
} | |
WebInspector.FileBasedSearchResultsPane = function(searchConfig) | |
{ | |
WebInspector.SearchResultsPane.call(this, searchConfig); | |
this._searchResults = []; | |
this.element.id ="search-results-pane-file-based"; | |
this._treeOutlineElement = document.createElement("ol"); | |
this._treeOutlineElement.className = "search-results-outline-disclosure"; | |
this.element.appendChild(this._treeOutlineElement); | |
this._treeOutline = new TreeOutline(this._treeOutlineElement); | |
this._matchesExpandedCount = 0; | |
} | |
WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20; | |
WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20; | |
WebInspector.FileBasedSearchResultsPane.prototype = { | |
_createAnchor: function(uiSourceCode, lineNumber, columnNumber) | |
{ | |
var anchor = document.createElement("a"); | |
anchor.preferredPanel = "scripts"; | |
anchor.href = sanitizeHref(uiSourceCode.url); | |
anchor.uiSourceCode = uiSourceCode; | |
anchor.lineNumber = lineNumber; | |
return anchor; | |
}, | |
addSearchResult: function(searchResult) | |
{ | |
this._searchResults.push(searchResult); | |
var uiSourceCode = searchResult.uiSourceCode; | |
var searchMatches = searchResult.searchMatches; | |
var fileTreeElement = this._addFileTreeElement(uiSourceCode.url, searchMatches.length, this._searchResults.length - 1); | |
}, | |
_fileTreeElementExpanded: function(searchResult, fileTreeElement) | |
{ | |
if (fileTreeElement._initialized) | |
return; | |
var toIndex = Math.min(searchResult.searchMatches.length, WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce); | |
if (toIndex < searchResult.searchMatches.length) { | |
this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex - 1); | |
this._appendShowMoreMatchesElement(fileTreeElement, searchResult, toIndex - 1); | |
} else | |
this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex); | |
fileTreeElement._initialized = true; | |
}, | |
_appendSearchMatches: function(fileTreeElement, searchResult, fromIndex, toIndex) | |
{ | |
var uiSourceCode = searchResult.uiSourceCode; | |
var searchMatches = searchResult.searchMatches; | |
var regex = createSearchRegex(this._searchConfig.query, !this._searchConfig.ignoreCase, this._searchConfig.isRegex); | |
for (var i = fromIndex; i < toIndex; ++i) { | |
var lineNumber = searchMatches[i].lineNumber; | |
var lineContent = searchMatches[i].lineContent; | |
var matchRanges = this._regexMatchRanges(lineContent, regex); | |
var anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset); | |
var numberString = numberToStringWithSpacesPadding(lineNumber + 1, 4); | |
var lineNumberSpan = document.createElement("span"); | |
lineNumberSpan.addStyleClass("webkit-line-number"); | |
lineNumberSpan.addStyleClass("search-match-line-number"); | |
lineNumberSpan.textContent = numberString; | |
anchor.appendChild(lineNumberSpan); | |
var contentSpan = this._createContentSpan(lineContent, matchRanges); | |
anchor.appendChild(contentSpan); | |
var searchMatchElement = new TreeElement("", null, false); | |
fileTreeElement.appendChild(searchMatchElement); | |
searchMatchElement.listItemElement.className = "search-match source-code"; | |
searchMatchElement.listItemElement.appendChild(anchor); | |
} | |
}, | |
_appendShowMoreMatchesElement: function(fileTreeElement, searchResult, startMatchIndex) | |
{ | |
var matchesLeftCount = searchResult.searchMatches.length - startMatchIndex; | |
var showMoreMatchesText = WebInspector.UIString("Show all matches (%d more).", matchesLeftCount); | |
var showMoreMatchesElement = new TreeElement(showMoreMatchesText, null, false); | |
fileTreeElement.appendChild(showMoreMatchesElement); | |
showMoreMatchesElement.listItemElement.addStyleClass("show-more-matches"); | |
showMoreMatchesElement.onselect = this._showMoreMatchesElementSelected.bind(this, searchResult, startMatchIndex, showMoreMatchesElement); | |
}, | |
_showMoreMatchesElementSelected: function(searchResult, startMatchIndex, showMoreMatchesElement) | |
{ | |
var fileTreeElement = showMoreMatchesElement.parent; | |
fileTreeElement.removeChild(showMoreMatchesElement); | |
this._appendSearchMatches(fileTreeElement, searchResult, startMatchIndex, searchResult.searchMatches.length); | |
}, | |
_addFileTreeElement: function(fileName, searchMatchesCount, searchResultIndex) | |
{ | |
var fileTreeElement = new TreeElement("", null, true); | |
fileTreeElement.toggleOnClick = true; | |
fileTreeElement.selectable = false; | |
this._treeOutline.appendChild(fileTreeElement); | |
fileTreeElement.listItemElement.addStyleClass("search-result"); | |
var fileNameSpan = document.createElement("span"); | |
fileNameSpan.className = "search-result-file-name"; | |
fileNameSpan.textContent = fileName; | |
fileTreeElement.listItemElement.appendChild(fileNameSpan); | |
var matchesCountSpan = document.createElement("span"); | |
matchesCountSpan.className = "search-result-matches-count"; | |
if (searchMatchesCount === 1) | |
matchesCountSpan.textContent = WebInspector.UIString("(%d match)", searchMatchesCount); | |
else | |
matchesCountSpan.textContent = WebInspector.UIString("(%d matches)", searchMatchesCount); | |
fileTreeElement.listItemElement.appendChild(matchesCountSpan); | |
var searchResult = this._searchResults[searchResultIndex]; | |
fileTreeElement.onexpand = this._fileTreeElementExpanded.bind(this, searchResult, fileTreeElement); | |
if (this._matchesExpandedCount < WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount) | |
fileTreeElement.expand(); | |
this._matchesExpandedCount += searchResult.searchMatches.length; | |
return fileTreeElement; | |
}, | |
_regexMatchRanges: function(lineContent, regex) | |
{ | |
regex.lastIndex = 0; | |
var match; | |
var offset = 0; | |
var matchRanges = []; | |
while ((regex.lastIndex < lineContent.length) && (match = regex.exec(lineContent))) | |
matchRanges.push(new WebInspector.SearchResult(match.index, match[0].length)); | |
return matchRanges; | |
}, | |
_createContentSpan: function(lineContent, matchRanges) | |
{ | |
var contentSpan = document.createElement("span"); | |
contentSpan.className = "search-match-content"; | |
contentSpan.textContent = lineContent; | |
WebInspector.highlightRangesWithStyleClass(contentSpan, matchRanges, "highlighted-match"); | |
return contentSpan; | |
} | |
} | |
WebInspector.FileBasedSearchResultsPane.prototype.__proto__ = WebInspector.SearchResultsPane.prototype; | |
WebInspector.FileBasedSearchResultsPane.SearchResult = function(uiSourceCode, searchMatches) { | |
this.uiSourceCode = uiSourceCode; | |
this.searchMatches = searchMatches; | |
} | |
WebInspector.advancedSearchController = null; | |
WebInspector.TimelineGrid = function() | |
{ | |
this.element = document.createElement("div"); | |
this._itemsGraphsElement = document.createElement("div"); | |
this._itemsGraphsElement.id = "resources-graphs"; | |
this.element.appendChild(this._itemsGraphsElement); | |
this._dividersElement = document.createElement("div"); | |
this._dividersElement.className = "resources-dividers"; | |
this.element.appendChild(this._dividersElement); | |
this._gridHeaderElement = document.createElement("div"); | |
this._eventDividersElement = document.createElement("div"); | |
this._eventDividersElement.className = "resources-event-dividers"; | |
this._gridHeaderElement.appendChild(this._eventDividersElement); | |
this._dividersLabelBarElement = document.createElement("div"); | |
this._dividersLabelBarElement.className = "resources-dividers-label-bar"; | |
this._gridHeaderElement.appendChild(this._dividersLabelBarElement); | |
this.element.appendChild(this._gridHeaderElement); | |
} | |
WebInspector.TimelineGrid.prototype = { | |
get itemsGraphsElement() | |
{ | |
return this._itemsGraphsElement; | |
}, | |
get dividersElement() | |
{ | |
return this._dividersElement; | |
}, | |
get dividersLabelBarElement() | |
{ | |
return this._dividersLabelBarElement; | |
}, | |
get gridHeaderElement() | |
{ | |
return this._gridHeaderElement; | |
}, | |
removeDividers: function() | |
{ | |
this._dividersElement.removeChildren(); | |
this._dividersLabelBarElement.removeChildren(); | |
}, | |
updateDividers: function(calculator) | |
{ | |
var dividersElementClientWidth = this._dividersElement.clientWidth; | |
var dividerCount = Math.round(dividersElementClientWidth / 64); | |
var slice = calculator.boundarySpan() / dividerCount; | |
this._currentDividerSlice = slice; | |
var divider = this._dividersElement.firstChild; | |
var dividerLabelBar = this._dividersLabelBarElement.firstChild; | |
var paddingLeft = calculator.paddingLeft; | |
for (var i = paddingLeft ? 0 : 1; i <= dividerCount; ++i) { | |
if (!divider) { | |
divider = document.createElement("div"); | |
divider.className = "resources-divider"; | |
this._dividersElement.appendChild(divider); | |
dividerLabelBar = document.createElement("div"); | |
dividerLabelBar.className = "resources-divider"; | |
var label = document.createElement("div"); | |
label.className = "resources-divider-label"; | |
dividerLabelBar._labelElement = label; | |
dividerLabelBar.appendChild(label); | |
this._dividersLabelBarElement.appendChild(dividerLabelBar); | |
} | |
if (i === (paddingLeft ? 0 : 1)) { | |
divider.addStyleClass("first"); | |
dividerLabelBar.addStyleClass("first"); | |
} else { | |
divider.removeStyleClass("first"); | |
dividerLabelBar.removeStyleClass("first"); | |
} | |
if (i === dividerCount) { | |
divider.addStyleClass("last"); | |
dividerLabelBar.addStyleClass("last"); | |
} else { | |
divider.removeStyleClass("last"); | |
dividerLabelBar.removeStyleClass("last"); | |
} | |
var left; | |
if (!slice) { | |
left = dividersElementClientWidth / dividerCount * i + paddingLeft; | |
dividerLabelBar._labelElement.textContent = ""; | |
} else { | |
left = calculator.computePosition(calculator.minimumBoundary() + slice * i); | |
dividerLabelBar._labelElement.textContent = calculator.formatTime(slice * i); | |
} | |
var percentLeft = 100 * left / dividersElementClientWidth; | |
this._setDividerAndBarLeft(divider, dividerLabelBar, percentLeft); | |
divider = divider.nextSibling; | |
dividerLabelBar = dividerLabelBar.nextSibling; | |
} | |
while (divider) { | |
var nextDivider = divider.nextSibling; | |
this._dividersElement.removeChild(divider); | |
divider = nextDivider; | |
} | |
while (dividerLabelBar) { | |
var nextDivider = dividerLabelBar.nextSibling; | |
this._dividersLabelBarElement.removeChild(dividerLabelBar); | |
dividerLabelBar = nextDivider; | |
} | |
return true; | |
}, | |
_setDividerAndBarLeft: function(divider, dividerLabelBar, percentLeft) | |
{ | |
var percentStyleLeft = parseFloat(divider.style.left); | |
if (!isNaN(percentStyleLeft) && Math.abs(percentStyleLeft - percentLeft) < 0.1) | |
return; | |
divider.style.left = percentLeft + "%"; | |
dividerLabelBar.style.left = percentLeft + "%"; | |
}, | |
addEventDivider: function(divider) | |
{ | |
this._eventDividersElement.appendChild(divider); | |
}, | |
addEventDividers: function(dividers) | |
{ | |
this._gridHeaderElement.removeChild(this._eventDividersElement); | |
for (var i = 0; i < dividers.length; ++i) { | |
if (dividers[i]) | |
this._eventDividersElement.appendChild(dividers[i]); | |
} | |
this._gridHeaderElement.appendChild(this._eventDividersElement); | |
}, | |
removeEventDividers: function() | |
{ | |
this._eventDividersElement.removeChildren(); | |
}, | |
hideEventDividers: function() | |
{ | |
this._eventDividersElement.addStyleClass("hidden"); | |
}, | |
showEventDividers: function() | |
{ | |
this._eventDividersElement.removeStyleClass("hidden"); | |
}, | |
setScrollAndDividerTop: function(scrollTop, dividersTop) | |
{ | |
this._dividersElement.style.top = scrollTop + "px"; | |
} | |
} | |
WebInspector.TimelineGrid.Calculator = function() { } | |
WebInspector.TimelineGrid.Calculator.prototype = { | |
computePosition: function(time) { }, | |
formatTime: function(time) { }, | |
minimumBoundary: function() { }, | |
maximumBoundary: function() { }, | |
boundarySpan: function() { } | |
} | |
WebInspector.ContentProvider = function() { } | |
WebInspector.ContentProvider.prototype = { | |
contentURL: function() { }, | |
contentType: function() { }, | |
requestContent: function(callback) { }, | |
searchInContent: function(query, caseSensitive, isRegex, callback) { } | |
} | |
WebInspector.ContentProvider.SearchMatch = function(lineNumber, lineContent) { | |
this.lineNumber = lineNumber; | |
this.lineContent = lineContent; | |
} | |
WebInspector.Resource = function(request, url, documentURL, frameId, loaderId, type, mimeType, isHidden) | |
{ | |
this._request = request; | |
this.url = url; | |
this._documentURL = documentURL; | |
this._frameId = frameId; | |
this._loaderId = loaderId; | |
this._type = type || WebInspector.resourceTypes.Other; | |
this._mimeType = mimeType; | |
this._isHidden = isHidden; | |
this._content; | |
this._contentEncoded; | |
this._pendingContentCallbacks = []; | |
if (this._request && !this._request.finished) | |
this._request.addEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); | |
} | |
WebInspector.Resource.Events = { | |
MessageAdded: "message-added", | |
MessagesCleared: "messages-cleared", | |
} | |
WebInspector.Resource.prototype = { | |
get request() | |
{ | |
return this._request; | |
}, | |
get url() | |
{ | |
return this._url; | |
}, | |
set url(x) | |
{ | |
this._url = x; | |
this._parsedURL = new WebInspector.ParsedURL(x); | |
}, | |
get parsedURL() | |
{ | |
return this._parsedURL; | |
}, | |
get documentURL() | |
{ | |
return this._documentURL; | |
}, | |
get frameId() | |
{ | |
return this._frameId; | |
}, | |
get loaderId() | |
{ | |
return this._loaderId; | |
}, | |
get displayName() | |
{ | |
return this._parsedURL.displayName; | |
}, | |
get type() | |
{ | |
return this._request ? this._request.type : this._type; | |
}, | |
get mimeType() | |
{ | |
return this._request ? this._request.mimeType : this._mimeType; | |
}, | |
get messages() | |
{ | |
return this._messages || []; | |
}, | |
addMessage: function(msg) | |
{ | |
if (!msg.isErrorOrWarning() || !msg.message) | |
return; | |
if (!this._messages) | |
this._messages = []; | |
this._messages.push(msg); | |
this.dispatchEventToListeners(WebInspector.Resource.Events.MessageAdded, msg); | |
}, | |
get errors() | |
{ | |
return this._errors || 0; | |
}, | |
set errors(x) | |
{ | |
this._errors = x; | |
}, | |
get warnings() | |
{ | |
return this._warnings || 0; | |
}, | |
set warnings(x) | |
{ | |
this._warnings = x; | |
}, | |
clearErrorsAndWarnings: function() | |
{ | |
this._messages = []; | |
this._warnings = 0; | |
this._errors = 0; | |
this.dispatchEventToListeners(WebInspector.Resource.Events.MessagesCleared); | |
}, | |
get content() | |
{ | |
return this._content; | |
}, | |
get contentEncoded() | |
{ | |
return this._contentEncoded; | |
}, | |
contentURL: function() | |
{ | |
return this._url; | |
}, | |
contentType: function() | |
{ | |
return this.type; | |
}, | |
requestContent: function(callback) | |
{ | |
if (typeof this._content !== "undefined") { | |
callback(this._content, !!this._contentEncoded, this.canonicalMimeType()); | |
return; | |
} | |
this._pendingContentCallbacks.push(callback); | |
if (!this._request || this._request.finished) | |
this._innerRequestContent(); | |
}, | |
canonicalMimeType: function() | |
{ | |
return this.type.canonicalMimeType() || this.mimeType; | |
}, | |
searchInContent: function(query, caseSensitive, isRegex, callback) | |
{ | |
function callbackWrapper(error, searchMatches) | |
{ | |
callback(searchMatches || []); | |
} | |
if (this.frameId) | |
PageAgent.searchInResource(this.frameId, this.url, query, caseSensitive, isRegex, callbackWrapper); | |
else | |
callback([]); | |
}, | |
populateImageSource: function(image) | |
{ | |
function onResourceContent() | |
{ | |
image.src = this._contentURL(); | |
} | |
this.requestContent(onResourceContent.bind(this)); | |
}, | |
_contentURL: function() | |
{ | |
const maxDataUrlSize = 1024 * 1024; | |
if (this._content == null || this._content.length > maxDataUrlSize) | |
return this.url; | |
return "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content; | |
}, | |
_requestFinished: function() | |
{ | |
this._request.removeEventListener(WebInspector.NetworkRequest.Events.FinishedLoading, this._requestFinished, this); | |
if (this._pendingContentCallbacks.length) | |
this._innerRequestContent(); | |
}, | |
_innerRequestContent: function() | |
{ | |
if (this._contentRequested) | |
return; | |
this._contentRequested = true; | |
function contentLoaded(content, contentEncoded) | |
{ | |
this._content = content; | |
this._contentEncoded = contentEncoded; | |
var callbacks = this._pendingContentCallbacks.slice(); | |
for (var i = 0; i < callbacks.length; ++i) | |
callbacks[i](this._content, this._contentEncoded, this.canonicalMimeType()); | |
this._pendingContentCallbacks.length = 0; | |
delete this._contentRequested; | |
} | |
function resourceContentLoaded(error, content, contentEncoded) | |
{ | |
if (error) | |
console.error("Resource content request failed: " + error); | |
contentLoaded.call(this, error ? null : content, contentEncoded); | |
} | |
if (this.request) { | |
function requestContentLoaded(content, contentEncoded, mimeType) | |
{ | |
contentLoaded.call(this, content, contentEncoded); | |
} | |
this.request.requestContent(requestContentLoaded.bind(this)); | |
return; | |
} | |
PageAgent.getResourceContent(this.frameId, this.url, resourceContentLoaded.bind(this)); | |
}, | |
isHidden: function() | |
{ | |
return !!this._isHidden; | |
} | |
} | |
WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.NetworkRequest = function(requestId, url, documentURL, frameId, loaderId) | |
{ | |
this._requestId = requestId; | |
this.url = url; | |
this._documentURL = documentURL; | |
this._frameId = frameId; | |
this._loaderId = loaderId; | |
this._startTime = -1; | |
this._endTime = -1; | |
this.statusCode = 0; | |
this.statusText = ""; | |
this.requestMethod = ""; | |
this.requestTime = 0; | |
this.receiveHeadersEnd = 0; | |
this._type = WebInspector.resourceTypes.Other; | |
this._content = undefined; | |
this._contentEncoded = false; | |
this._pendingContentCallbacks = []; | |
this._frames = []; | |
} | |
WebInspector.NetworkRequest.Events = { | |
FinishedLoading: "FinishedLoading", | |
TimingChanged: "TimingChanged", | |
RequestHeadersChanged: "RequestHeadersChanged", | |
ResponseHeadersChanged: "ResponseHeadersChanged", | |
} | |
WebInspector.NetworkRequest.prototype = { | |
get requestId() | |
{ | |
return this._requestId; | |
}, | |
set requestId(requestId) | |
{ | |
this._requestId = requestId; | |
}, | |
get url() | |
{ | |
return this._url; | |
}, | |
set url(x) | |
{ | |
if (this._url === x) | |
return; | |
this._url = x; | |
this._parsedURL = new WebInspector.ParsedURL(x); | |
delete this._parsedQueryParameters; | |
}, | |
get documentURL() | |
{ | |
return this._documentURL; | |
}, | |
get parsedURL() | |
{ | |
return this._parsedURL; | |
}, | |
get frameId() | |
{ | |
return this._frameId; | |
}, | |
get loaderId() | |
{ | |
return this._loaderId; | |
}, | |
get startTime() | |
{ | |
return this._startTime || -1; | |
}, | |
set startTime(x) | |
{ | |
this._startTime = x; | |
}, | |
get responseReceivedTime() | |
{ | |
return this._responseReceivedTime || -1; | |
}, | |
set responseReceivedTime(x) | |
{ | |
this._responseReceivedTime = x; | |
}, | |
get endTime() | |
{ | |
return this._endTime || -1; | |
}, | |
set endTime(x) | |
{ | |
if (this.timing && this.timing.requestTime) { | |
this._endTime = Math.max(x, this.responseReceivedTime); | |
} else { | |
this._endTime = x; | |
if (this._responseReceivedTime > x) | |
this._responseReceivedTime = x; | |
} | |
}, | |
get duration() | |
{ | |
if (this._endTime === -1 || this._startTime === -1) | |
return -1; | |
return this._endTime - this._startTime; | |
}, | |
get latency() | |
{ | |
if (this._responseReceivedTime === -1 || this._startTime === -1) | |
return -1; | |
return this._responseReceivedTime - this._startTime; | |
}, | |
get receiveDuration() | |
{ | |
if (this._endTime === -1 || this._responseReceivedTime === -1) | |
return -1; | |
return this._endTime - this._responseReceivedTime; | |
}, | |
get resourceSize() | |
{ | |
return this._resourceSize || 0; | |
}, | |
set resourceSize(x) | |
{ | |
this._resourceSize = x; | |
}, | |
get transferSize() | |
{ | |
if (this.cached) | |
return 0; | |
if (this.statusCode === 304) | |
return this.responseHeadersSize; | |
if (this._transferSize !== undefined) | |
return this._transferSize; | |
var bodySize = Number(this.responseHeaderValue("Content-Length") || this.resourceSize); | |
return this.responseHeadersSize + bodySize; | |
}, | |
increaseTransferSize: function(x) | |
{ | |
this._transferSize = (this._transferSize || 0) + x; | |
}, | |
get finished() | |
{ | |
return this._finished; | |
}, | |
set finished(x) | |
{ | |
if (this._finished === x) | |
return; | |
this._finished = x; | |
if (x) { | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.FinishedLoading, this); | |
if (this._pendingContentCallbacks.length) | |
this._innerRequestContent(); | |
} | |
}, | |
get failed() | |
{ | |
return this._failed; | |
}, | |
set failed(x) | |
{ | |
this._failed = x; | |
}, | |
get canceled() | |
{ | |
return this._canceled; | |
}, | |
set canceled(x) | |
{ | |
this._canceled = x; | |
}, | |
get cached() | |
{ | |
return this._cached; | |
}, | |
set cached(x) | |
{ | |
this._cached = x; | |
if (x) | |
delete this._timing; | |
}, | |
get timing() | |
{ | |
return this._timing; | |
}, | |
set timing(x) | |
{ | |
if (x && !this._cached) { | |
this._startTime = x.requestTime; | |
this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0; | |
this._timing = x; | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.TimingChanged, this); | |
} | |
}, | |
get mimeType() | |
{ | |
return this._mimeType; | |
}, | |
set mimeType(x) | |
{ | |
this._mimeType = x; | |
}, | |
get displayName() | |
{ | |
return this._parsedURL.displayName; | |
}, | |
get folder() | |
{ | |
var path = this._parsedURL.path; | |
var indexOfQuery = path.indexOf("?"); | |
if (indexOfQuery !== -1) | |
path = path.substring(0, indexOfQuery); | |
var lastSlashIndex = path.lastIndexOf("/"); | |
return lastSlashIndex !== -1 ? path.substring(0, lastSlashIndex) : ""; | |
}, | |
get type() | |
{ | |
return this._type; | |
}, | |
set type(x) | |
{ | |
this._type = x; | |
}, | |
get redirectSource() | |
{ | |
if (this.redirects && this.redirects.length > 0) | |
return this.redirects[this.redirects.length - 1]; | |
return this._redirectSource; | |
}, | |
set redirectSource(x) | |
{ | |
this._redirectSource = x; | |
}, | |
get requestHeaders() | |
{ | |
return this._requestHeaders || []; | |
}, | |
set requestHeaders(x) | |
{ | |
this._requestHeaders = x; | |
delete this._sortedRequestHeaders; | |
delete this._requestCookies; | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged); | |
}, | |
get requestHeadersText() | |
{ | |
if (this._requestHeadersText === undefined) { | |
this._requestHeadersText = this.requestMethod + " " + this.url + " HTTP/1.1\r\n"; | |
for (var i = 0; i < this.requestHeaders; ++i) | |
this._requestHeadersText += this.requestHeaders[i].name + ": " + this.requestHeaders[i].value + "\r\n"; | |
} | |
return this._requestHeadersText; | |
}, | |
set requestHeadersText(x) | |
{ | |
this._requestHeadersText = x; | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.RequestHeadersChanged); | |
}, | |
get requestHeadersSize() | |
{ | |
return this.requestHeadersText.length; | |
}, | |
get sortedRequestHeaders() | |
{ | |
if (this._sortedRequestHeaders !== undefined) | |
return this._sortedRequestHeaders; | |
this._sortedRequestHeaders = []; | |
this._sortedRequestHeaders = this.requestHeaders.slice(); | |
this._sortedRequestHeaders.sort(function(a,b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) }); | |
return this._sortedRequestHeaders; | |
}, | |
requestHeaderValue: function(headerName) | |
{ | |
return this._headerValue(this.requestHeaders, headerName); | |
}, | |
get requestCookies() | |
{ | |
if (!this._requestCookies) | |
this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie")); | |
return this._requestCookies; | |
}, | |
get requestFormData() | |
{ | |
return this._requestFormData; | |
}, | |
set requestFormData(x) | |
{ | |
this._requestFormData = x; | |
delete this._parsedFormParameters; | |
}, | |
get requestHttpVersion() | |
{ | |
var firstLine = this.requestHeadersText.split(/\r\n/)[0]; | |
var match = firstLine.match(/(HTTP\/\d+\.\d+)$/); | |
return match ? match[1] : undefined; | |
}, | |
get responseHeaders() | |
{ | |
return this._responseHeaders || []; | |
}, | |
set responseHeaders(x) | |
{ | |
this._responseHeaders = x; | |
delete this._sortedResponseHeaders; | |
delete this._responseCookies; | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged); | |
}, | |
get responseHeadersText() | |
{ | |
if (this._responseHeadersText === undefined) { | |
this._responseHeadersText = "HTTP/1.1 " + this.statusCode + " " + this.statusText + "\r\n"; | |
for (var i = 0; i < this.requestHeaders; ++i) | |
this._responseHeadersText += this.responseHeaders[i].name + ": " + this.responseHeaders[i].value + "\r\n"; | |
} | |
return this._responseHeadersText; | |
}, | |
set responseHeadersText(x) | |
{ | |
this._responseHeadersText = x; | |
this.dispatchEventToListeners(WebInspector.NetworkRequest.Events.ResponseHeadersChanged); | |
}, | |
get responseHeadersSize() | |
{ | |
return this.responseHeadersText.length; | |
}, | |
get sortedResponseHeaders() | |
{ | |
if (this._sortedResponseHeaders !== undefined) | |
return this._sortedResponseHeaders; | |
this._sortedResponseHeaders = []; | |
this._sortedResponseHeaders = this.responseHeaders.slice(); | |
this._sortedResponseHeaders.sort(function(a,b) { return a.name.toLowerCase().localeCompare(b.name.toLowerCase()) }); | |
return this._sortedResponseHeaders; | |
}, | |
responseHeaderValue: function(headerName) | |
{ | |
return this._headerValue(this.responseHeaders, headerName); | |
}, | |
get responseCookies() | |
{ | |
if (!this._responseCookies) | |
this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie")); | |
return this._responseCookies; | |
}, | |
get queryParameters() | |
{ | |
if (this._parsedQueryParameters) | |
return this._parsedQueryParameters; | |
var queryString = this.url.split("?", 2)[1]; | |
if (!queryString) | |
return null; | |
queryString = queryString.split("#", 2)[0]; | |
this._parsedQueryParameters = this._parseParameters(queryString); | |
return this._parsedQueryParameters; | |
}, | |
get formParameters() | |
{ | |
if (this._parsedFormParameters) | |
return this._parsedFormParameters; | |
if (!this.requestFormData) | |
return null; | |
var requestContentType = this.requestContentType(); | |
if (!requestContentType || !requestContentType.match(/^application\/x-www-form-urlencoded\s*(;.*)?$/i)) | |
return null; | |
this._parsedFormParameters = this._parseParameters(this.requestFormData); | |
return this._parsedFormParameters; | |
}, | |
get responseHttpVersion() | |
{ | |
var match = this.responseHeadersText.match(/^(HTTP\/\d+\.\d+)/); | |
return match ? match[1] : undefined; | |
}, | |
_parseParameters: function(queryString) | |
{ | |
function parseNameValue(pair) | |
{ | |
var parameter = {}; | |
var splitPair = pair.split("=", 2); | |
parameter.name = splitPair[0]; | |
if (splitPair.length === 1) | |
parameter.value = ""; | |
else | |
parameter.value = splitPair[1]; | |
return parameter; | |
} | |
return queryString.split("&").map(parseNameValue); | |
}, | |
_headerValue: function(headers, headerName) | |
{ | |
headerName = headerName.toLowerCase(); | |
var values = []; | |
for (var i = 0; i < headers.length; ++i) { | |
if (headers[i].name.toLowerCase() === headerName) | |
values.push(headers[i].value); | |
} | |
if (headerName === "set-cookie") | |
return values.join("\n"); | |
return values.join(", "); | |
}, | |
get content() | |
{ | |
return this._content; | |
}, | |
get contentEncoded() | |
{ | |
return this._contentEncoded; | |
}, | |
contentURL: function() | |
{ | |
return this._url; | |
}, | |
contentType: function() | |
{ | |
return this._type; | |
}, | |
requestContent: function(callback) | |
{ | |
if (this.type === WebInspector.resourceTypes.WebSocket) { | |
callback(null, false, this._mimeType); | |
return; | |
} | |
if (typeof this._content !== "undefined") { | |
callback(this.content || null, this._contentEncoded, this._mimeType); | |
return; | |
} | |
this._pendingContentCallbacks.push(callback); | |
if (this.finished) | |
this._innerRequestContent(); | |
}, | |
searchInContent: function(query, caseSensitive, isRegex, callback) | |
{ | |
callback([]); | |
}, | |
isHttpFamily: function() | |
{ | |
return !!this.url.match(/^https?:/i); | |
}, | |
requestContentType: function() | |
{ | |
return this.requestHeaderValue("Content-Type"); | |
}, | |
isPingRequest: function() | |
{ | |
return "text/ping" === this.requestContentType(); | |
}, | |
hasErrorStatusCode: function() | |
{ | |
return this.statusCode >= 400; | |
}, | |
populateImageSource: function(image) | |
{ | |
function onResourceContent(content, contentEncoded, mimeType) | |
{ | |
const maxDataUrlSize = 1024 * 1024; | |
if (this._content == null || this._content.length > maxDataUrlSize) | |
return this.url; | |
image.src = "data:" + this.mimeType + (this._contentEncoded ? ";base64," : ",") + this._content; | |
} | |
this.requestContent(onResourceContent.bind(this)); | |
}, | |
_innerRequestContent: function() | |
{ | |
if (this._contentRequested) | |
return; | |
this._contentRequested = true; | |
function onResourceContent(error, content, contentEncoded) | |
{ | |
this._content = error ? null : content; | |
this._contentEncoded = contentEncoded; | |
var callbacks = this._pendingContentCallbacks.slice(); | |
for (var i = 0; i < callbacks.length; ++i) | |
callbacks[i](this._content, this._contentEncoded, this._mimeType); | |
this._pendingContentCallbacks.length = 0; | |
delete this._contentRequested; | |
} | |
NetworkAgent.getResponseBody(this._requestId, onResourceContent.bind(this)); | |
}, | |
frames: function() | |
{ | |
return this._frames; | |
}, | |
frame: function(position) | |
{ | |
return this._frames[position]; | |
}, | |
addFrameError: function(errorMessage, time) | |
{ | |
var errorObject = {}; | |
errorObject.errorMessage = errorMessage; | |
errorObject.time = time; | |
this._pushFrame(errorObject); | |
}, | |
addFrame: function(response, time, sent) | |
{ | |
response.time = time; | |
if (sent) | |
response.sent = true; | |
this._pushFrame(response); | |
}, | |
_pushFrame: function(object) | |
{ | |
if (this._frames.length >= 100) { | |
this._frames.splice(0, 10); | |
} | |
this._frames.push(object); | |
} | |
} | |
WebInspector.NetworkRequest.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.CSSStyleModel = function() | |
{ | |
this._pendingCommandsMajorState = []; | |
this._sourceMappings = {}; | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoRequested, this._undoRedoRequested, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoCompleted, this._undoRedoCompleted, this); | |
this._resourceBinding = new WebInspector.CSSStyleModelResourceBinding(this); | |
this._namedFlowCollections = {}; | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._resetNamedFlowCollections, this); | |
InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this)); | |
CSSAgent.enable(); | |
} | |
WebInspector.CSSStyleModel.parseRuleArrayPayload = function(ruleArray) | |
{ | |
var result = []; | |
for (var i = 0; i < ruleArray.length; ++i) | |
result.push(WebInspector.CSSRule.parsePayload(ruleArray[i])); | |
return result; | |
} | |
WebInspector.CSSStyleModel.Events = { | |
StyleSheetChanged: "StyleSheetChanged", | |
MediaQueryResultChanged: "MediaQueryResultChanged", | |
NamedFlowCreated: "NamedFlowCreated", | |
NamedFlowRemoved: "NamedFlowRemoved", | |
RegionLayoutUpdated: "RegionLayoutUpdated" | |
} | |
WebInspector.CSSStyleModel.prototype = { | |
getMatchedStylesAsync: function(nodeId, needPseudo, needInherited, userCallback) | |
{ | |
function callback(userCallback, error, matchedPayload, pseudoPayload, inheritedPayload) | |
{ | |
if (error) { | |
if (userCallback) | |
userCallback(null); | |
return; | |
} | |
var result = {}; | |
if (matchedPayload) | |
result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(matchedPayload); | |
if (pseudoPayload) { | |
result.pseudoElements = []; | |
for (var i = 0; i < pseudoPayload.length; ++i) { | |
var entryPayload = pseudoPayload[i]; | |
result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.rules) }); | |
} | |
} | |
if (inheritedPayload) { | |
result.inherited = []; | |
for (var i = 0; i < inheritedPayload.length; ++i) { | |
var entryPayload = inheritedPayload[i]; | |
var entry = {}; | |
if (entryPayload.inlineStyle) | |
entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(entryPayload.inlineStyle); | |
if (entryPayload.matchedCSSRules) | |
entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleArrayPayload(entryPayload.matchedCSSRules); | |
result.inherited.push(entry); | |
} | |
} | |
if (userCallback) | |
userCallback(result); | |
} | |
CSSAgent.getMatchedStylesForNode(nodeId, needPseudo, needInherited, callback.bind(null, userCallback)); | |
}, | |
getComputedStyleAsync: function(nodeId, userCallback) | |
{ | |
function callback(userCallback, error, computedPayload) | |
{ | |
if (error || !computedPayload) | |
userCallback(null); | |
else | |
userCallback(WebInspector.CSSStyleDeclaration.parseComputedStylePayload(computedPayload)); | |
} | |
CSSAgent.getComputedStyleForNode(nodeId, callback.bind(null, userCallback)); | |
}, | |
getInlineStylesAsync: function(nodeId, userCallback) | |
{ | |
function callback(userCallback, error, inlinePayload, attributesStylePayload) | |
{ | |
if (error || !inlinePayload) | |
userCallback(null, null); | |
else | |
userCallback(WebInspector.CSSStyleDeclaration.parsePayload(inlinePayload), attributesStylePayload ? WebInspector.CSSStyleDeclaration.parsePayload(attributesStylePayload) : null); | |
} | |
CSSAgent.getInlineStylesForNode(nodeId, callback.bind(null, userCallback)); | |
}, | |
forcePseudoState: function(nodeId, forcedPseudoClasses, userCallback) | |
{ | |
CSSAgent.forcePseudoState(nodeId, forcedPseudoClasses || [], userCallback); | |
}, | |
getNamedFlowCollectionAsync: function(documentNodeId, userCallback) | |
{ | |
var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
if (namedFlowCollection) { | |
userCallback(namedFlowCollection); | |
return; | |
} | |
function callback(userCallback, error, namedFlowPayload) | |
{ | |
if (error || !namedFlowPayload) | |
userCallback(null); | |
else { | |
var namedFlowCollection = new WebInspector.NamedFlowCollection(namedFlowPayload); | |
this._namedFlowCollections[documentNodeId] = namedFlowCollection; | |
userCallback(namedFlowCollection); | |
} | |
} | |
CSSAgent.getNamedFlowCollection(documentNodeId, callback.bind(this, userCallback)); | |
}, | |
getFlowByNameAsync: function(documentNodeId, flowName, userCallback) | |
{ | |
var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
if (namedFlowCollection) { | |
userCallback(namedFlowCollection.flowByName(flowName)); | |
return; | |
} | |
function callback(userCallback, namedFlowCollection) | |
{ | |
if (!namedFlowCollection) | |
userCallback(null); | |
else | |
userCallback(namedFlowCollection.flowByName(flowName)); | |
} | |
this.getNamedFlowCollectionAsync(documentNodeId, callback.bind(this, userCallback)); | |
}, | |
setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback) | |
{ | |
function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds) | |
{ | |
if (!selectedNodeIds) | |
return; | |
var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0); | |
var rule = WebInspector.CSSRule.parsePayload(rulePayload); | |
successCallback(rule, doesAffectSelectedNode); | |
} | |
function callback(nodeId, successCallback, failureCallback, newSelector, error, rulePayload) | |
{ | |
this._pendingCommandsMajorState.pop(); | |
if (error) | |
failureCallback(); | |
else { | |
WebInspector.domAgent.markUndoableState(); | |
var ownerDocumentId = this._ownerDocumentId(nodeId); | |
if (ownerDocumentId) | |
WebInspector.domAgent.querySelectorAll(ownerDocumentId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); | |
else | |
failureCallback(); | |
} | |
} | |
this._pendingCommandsMajorState.push(true); | |
CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector)); | |
}, | |
addRule: function(nodeId, selector, successCallback, failureCallback) | |
{ | |
function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds) | |
{ | |
if (!selectedNodeIds) | |
return; | |
var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0); | |
var rule = WebInspector.CSSRule.parsePayload(rulePayload); | |
successCallback(rule, doesAffectSelectedNode); | |
} | |
function callback(successCallback, failureCallback, selector, error, rulePayload) | |
{ | |
this._pendingCommandsMajorState.pop(); | |
if (error) { | |
failureCallback(); | |
} else { | |
WebInspector.domAgent.markUndoableState(); | |
var ownerDocumentId = this._ownerDocumentId(nodeId); | |
if (ownerDocumentId) | |
WebInspector.domAgent.querySelectorAll(ownerDocumentId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); | |
else | |
failureCallback(); | |
} | |
} | |
this._pendingCommandsMajorState.push(true); | |
CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); | |
}, | |
mediaQueryResultChanged: function() | |
{ | |
this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged); | |
}, | |
_ownerDocumentId: function(nodeId) | |
{ | |
var node = WebInspector.domAgent.nodeForId(nodeId); | |
if (!node) | |
return null; | |
return node.ownerDocument ? node.ownerDocument.id : null; | |
}, | |
_fireStyleSheetChanged: function(styleSheetId) | |
{ | |
if (!this._pendingCommandsMajorState.length) | |
return; | |
var majorChange = this._pendingCommandsMajorState[this._pendingCommandsMajorState.length - 1]; | |
if (!majorChange || !styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged)) | |
return; | |
this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, majorChange: majorChange }); | |
}, | |
_namedFlowCreated: function(namedFlowPayload) | |
{ | |
var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload); | |
var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId]; | |
if (!namedFlowCollection) | |
return; | |
namedFlowCollection._appendNamedFlow(namedFlow); | |
this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowCreated, namedFlow); | |
}, | |
_namedFlowRemoved: function(documentNodeId, flowName) | |
{ | |
var namedFlowCollection = this._namedFlowCollections[documentNodeId]; | |
if (!namedFlowCollection) | |
return; | |
namedFlowCollection._removeNamedFlow(flowName); | |
this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, { documentNodeId: documentNodeId, flowName: flowName }); | |
}, | |
_regionLayoutUpdated: function(namedFlowPayload) | |
{ | |
var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload); | |
var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId]; | |
if (!namedFlowCollection) | |
return; | |
namedFlowCollection._appendNamedFlow(namedFlow); | |
this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, namedFlow); | |
}, | |
setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback) | |
{ | |
function callback(error) | |
{ | |
this._pendingCommandsMajorState.pop(); | |
if (!error && majorChange) | |
WebInspector.domAgent.markUndoableState(); | |
if (!error && userCallback) | |
userCallback(error); | |
} | |
this._pendingCommandsMajorState.push(majorChange); | |
CSSAgent.setStyleSheetText(styleSheetId, newText, callback.bind(this)); | |
}, | |
_undoRedoRequested: function() | |
{ | |
this._pendingCommandsMajorState.push(true); | |
}, | |
_undoRedoCompleted: function() | |
{ | |
this._pendingCommandsMajorState.pop(); | |
}, | |
getViaInspectorResourceForRule: function(rule, callback) | |
{ | |
if (!rule.id) { | |
callback(null); | |
return; | |
} | |
this._resourceBinding._requestViaInspectorResource(rule.id.styleSheetId, callback); | |
}, | |
resourceBinding: function() | |
{ | |
return this._resourceBinding; | |
}, | |
setSourceMapping: function(url, sourceMapping) | |
{ | |
this._sourceMappings[url] = sourceMapping; | |
}, | |
resetSourceMappings: function() | |
{ | |
this._sourceMappings = {}; | |
}, | |
_resetNamedFlowCollections: function() | |
{ | |
this._namedFlowCollections = {}; | |
}, | |
_rawLocationToUILocation: function(rawLocation) | |
{ | |
var sourceMapping = this._sourceMappings[rawLocation.url]; | |
return sourceMapping ? sourceMapping.rawLocationToUILocation(rawLocation) : null; | |
} | |
} | |
WebInspector.CSSStyleModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.CSSLocation = function(url, lineNumber) | |
{ | |
this.url = url; | |
this.lineNumber = lineNumber; | |
} | |
WebInspector.CSSStyleDeclaration = function(payload) | |
{ | |
this.id = payload.styleId; | |
this.width = payload.width; | |
this.height = payload.height; | |
this.range = payload.range; | |
this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries); | |
this._livePropertyMap = {}; | |
this._allProperties = []; | |
this.__disabledProperties = {}; | |
var payloadPropertyCount = payload.cssProperties.length; | |
var propertyIndex = 0; | |
for (var i = 0; i < payloadPropertyCount; ++i) { | |
var property = WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]); | |
this._allProperties.push(property); | |
if (property.disabled) | |
this.__disabledProperties[i] = property; | |
if (!property.active && !property.styleBased) | |
continue; | |
var name = property.name; | |
this[propertyIndex] = name; | |
this._livePropertyMap[name] = property; | |
++propertyIndex; | |
} | |
this.length = propertyIndex; | |
if ("cssText" in payload) | |
this.cssText = payload.cssText; | |
} | |
WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries) | |
{ | |
var result = {}; | |
for (var i = 0; i < shorthandEntries.length; ++i) | |
result[shorthandEntries[i].name] = shorthandEntries[i].value; | |
return result; | |
} | |
WebInspector.CSSStyleDeclaration.parsePayload = function(payload) | |
{ | |
return new WebInspector.CSSStyleDeclaration(payload); | |
} | |
WebInspector.CSSStyleDeclaration.parseComputedStylePayload = function(payload) | |
{ | |
var newPayload = { cssProperties: [], shorthandEntries: [], width: "", height: "" }; | |
if (payload) | |
newPayload.cssProperties = payload; | |
return new WebInspector.CSSStyleDeclaration(newPayload); | |
} | |
WebInspector.CSSStyleDeclaration.prototype = { | |
get allProperties() | |
{ | |
return this._allProperties; | |
}, | |
getLiveProperty: function(name) | |
{ | |
return this._livePropertyMap[name]; | |
}, | |
getPropertyValue: function(name) | |
{ | |
var property = this._livePropertyMap[name]; | |
return property ? property.value : ""; | |
}, | |
getPropertyPriority: function(name) | |
{ | |
var property = this._livePropertyMap[name]; | |
return property ? property.priority : ""; | |
}, | |
isPropertyImplicit: function(name) | |
{ | |
var property = this._livePropertyMap[name]; | |
return property ? property.implicit : ""; | |
}, | |
longhandProperties: function(name) | |
{ | |
var longhands = WebInspector.CSSCompletions.cssPropertiesMetainfo.longhands(name); | |
var result = []; | |
for (var i = 0; longhands && i < longhands.length; ++i) { | |
var property = this._livePropertyMap[longhands[i]]; | |
if (property) | |
result.push(property); | |
} | |
return result; | |
}, | |
shorthandValue: function(shorthandProperty) | |
{ | |
return this._shorthandValues[shorthandProperty]; | |
}, | |
propertyAt: function(index) | |
{ | |
return (index < this.allProperties.length) ? this.allProperties[index] : null; | |
}, | |
pastLastSourcePropertyIndex: function() | |
{ | |
for (var i = this.allProperties.length - 1; i >= 0; --i) { | |
var property = this.allProperties[i]; | |
if (property.active || property.disabled) | |
return i + 1; | |
} | |
return 0; | |
}, | |
newBlankProperty: function(index) | |
{ | |
index = (typeof index === "undefined") ? this.pastLastSourcePropertyIndex() : index; | |
return new WebInspector.CSSProperty(this, index, "", "", "", "active", true, false, ""); | |
}, | |
insertPropertyAt: function(index, name, value, userCallback) | |
{ | |
function callback(userCallback, error, payload) | |
{ | |
WebInspector.cssModel._pendingCommandsMajorState.pop(); | |
if (!userCallback) | |
return; | |
if (error) { | |
console.error(error); | |
userCallback(null); | |
} else { | |
userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload)); | |
} | |
} | |
if (!this.id) | |
throw "No style id"; | |
WebInspector.cssModel._pendingCommandsMajorState.push(true); | |
CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(this, userCallback)); | |
}, | |
appendProperty: function(name, value, userCallback) | |
{ | |
this.insertPropertyAt(this.allProperties.length, name, value, userCallback); | |
} | |
} | |
WebInspector.CSSRule = function(payload) | |
{ | |
this.id = payload.ruleId; | |
this.selectorText = payload.selectorText; | |
this.sourceLine = payload.sourceLine; | |
this.sourceURL = payload.sourceURL; | |
if (payload.sourceURL) | |
this._rawLocation = new WebInspector.CSSLocation(payload.sourceURL, payload.sourceLine); | |
this.origin = payload.origin; | |
this.style = WebInspector.CSSStyleDeclaration.parsePayload(payload.style); | |
this.style.parentRule = this; | |
this.selectorRange = payload.selectorRange; | |
if (payload.media) | |
this.media = WebInspector.CSSMedia.parseMediaArrayPayload(payload.media); | |
} | |
WebInspector.CSSRule.parsePayload = function(payload) | |
{ | |
return new WebInspector.CSSRule(payload); | |
} | |
WebInspector.CSSRule.prototype = { | |
get isUserAgent() | |
{ | |
return this.origin === "user-agent"; | |
}, | |
get isUser() | |
{ | |
return this.origin === "user"; | |
}, | |
get isViaInspector() | |
{ | |
return this.origin === "inspector"; | |
}, | |
get isRegular() | |
{ | |
return this.origin === "regular"; | |
}, | |
uiLocation: function() | |
{ | |
if (!this._rawLocation) | |
return null; | |
return WebInspector.cssModel._rawLocationToUILocation(this._rawLocation); | |
} | |
} | |
WebInspector.CSSProperty = function(ownerStyle, index, name, value, priority, status, parsedOk, implicit, text) | |
{ | |
this.ownerStyle = ownerStyle; | |
this.index = index; | |
this.name = name; | |
this.value = value; | |
this.priority = priority; | |
this.status = status; | |
this.parsedOk = parsedOk; | |
this.implicit = implicit; | |
this.text = text; | |
} | |
WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload) | |
{ | |
var result = new WebInspector.CSSProperty( | |
ownerStyle, index, payload.name, payload.value, payload.priority || "", payload.status || "style", ("parsedOk" in payload) ? !!payload.parsedOk : true, !!payload.implicit, payload.text); | |
return result; | |
} | |
WebInspector.CSSProperty.prototype = { | |
get propertyText() | |
{ | |
if (this.text !== undefined) | |
return this.text; | |
if (this.name === "") | |
return ""; | |
return this.name + ": " + this.value + (this.priority ? " !" + this.priority : "") + ";"; | |
}, | |
get isLive() | |
{ | |
return this.active || this.styleBased; | |
}, | |
get active() | |
{ | |
return this.status === "active"; | |
}, | |
get styleBased() | |
{ | |
return this.status === "style"; | |
}, | |
get inactive() | |
{ | |
return this.status === "inactive"; | |
}, | |
get disabled() | |
{ | |
return this.status === "disabled"; | |
}, | |
setText: function(propertyText, majorChange, overwrite, userCallback) | |
{ | |
function enabledCallback(style) | |
{ | |
if (userCallback) | |
userCallback(style); | |
} | |
function callback(error, stylePayload) | |
{ | |
WebInspector.cssModel._pendingCommandsMajorState.pop(); | |
if (!error) { | |
if (majorChange) | |
WebInspector.domAgent.markUndoableState(); | |
this.text = propertyText; | |
var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload); | |
var newProperty = style.allProperties[this.index]; | |
if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) { | |
newProperty.setDisabled(false, enabledCallback); | |
return; | |
} | |
if (userCallback) | |
userCallback(style); | |
} else { | |
if (userCallback) | |
userCallback(null); | |
} | |
} | |
if (!this.ownerStyle) | |
throw "No ownerStyle for property"; | |
if (!this.ownerStyle.id) | |
throw "No owner style id"; | |
WebInspector.cssModel._pendingCommandsMajorState.push(majorChange); | |
CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, overwrite, callback.bind(this)); | |
}, | |
setValue: function(newValue, majorChange, overwrite, userCallback) | |
{ | |
var text = this.name + ": " + newValue + (this.priority ? " !" + this.priority : "") + ";" | |
this.setText(text, majorChange, overwrite, userCallback); | |
}, | |
setDisabled: function(disabled, userCallback) | |
{ | |
if (!this.ownerStyle && userCallback) | |
userCallback(null); | |
if (disabled === this.disabled && userCallback) | |
userCallback(this.ownerStyle); | |
function callback(error, stylePayload) | |
{ | |
WebInspector.cssModel._pendingCommandsMajorState.pop(); | |
if (error) { | |
if (userCallback) | |
userCallback(null); | |
return; | |
} | |
WebInspector.domAgent.markUndoableState(); | |
if (userCallback) { | |
var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload); | |
userCallback(style); | |
} | |
} | |
if (!this.ownerStyle.id) | |
throw "No owner style id"; | |
WebInspector.cssModel._pendingCommandsMajorState.push(false); | |
CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this)); | |
} | |
} | |
WebInspector.CSSMedia = function(payload) | |
{ | |
this.text = payload.text; | |
this.source = payload.source; | |
this.sourceURL = payload.sourceURL || ""; | |
this.sourceLine = typeof payload.sourceLine === "undefined" || this.source === "linkedSheet" ? -1 : payload.sourceLine; | |
} | |
WebInspector.CSSMedia.Source = { | |
LINKED_SHEET: "linkedSheet", | |
INLINE_SHEET: "inlineSheet", | |
MEDIA_RULE: "mediaRule", | |
IMPORT_RULE: "importRule" | |
}; | |
WebInspector.CSSMedia.parsePayload = function(payload) | |
{ | |
return new WebInspector.CSSMedia(payload); | |
} | |
WebInspector.CSSMedia.parseMediaArrayPayload = function(payload) | |
{ | |
var result = []; | |
for (var i = 0; i < payload.length; ++i) | |
result.push(WebInspector.CSSMedia.parsePayload(payload[i])); | |
return result; | |
} | |
WebInspector.CSSStyleSheet = function(payload) | |
{ | |
this.id = payload.styleSheetId; | |
this.rules = []; | |
this.styles = {}; | |
for (var i = 0; i < payload.rules.length; ++i) { | |
var rule = WebInspector.CSSRule.parsePayload(payload.rules[i]); | |
this.rules.push(rule); | |
if (rule.style) | |
this.styles[rule.style.id] = rule.style; | |
} | |
if ("text" in payload) | |
this._text = payload.text; | |
} | |
WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback) | |
{ | |
function callback(error, styleSheetPayload) | |
{ | |
if (error) | |
userCallback(null); | |
else | |
userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload)); | |
} | |
CSSAgent.getStyleSheet(styleSheetId, callback.bind(this)); | |
} | |
WebInspector.CSSStyleSheet.prototype = { | |
getText: function() | |
{ | |
return this._text; | |
}, | |
setText: function(newText, majorChange, userCallback) | |
{ | |
function callback(error) | |
{ | |
if (!error) | |
WebInspector.domAgent.markUndoableState(); | |
WebInspector.cssModel._pendingCommandsMajorState.pop(); | |
if (userCallback) | |
userCallback(error); | |
} | |
WebInspector.cssModel._pendingCommandsMajorState.push(majorChange); | |
CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this)); | |
} | |
} | |
WebInspector.CSSStyleModelResourceBinding = function(cssModel) | |
{ | |
this._cssModel = cssModel; | |
this._frameAndURLToStyleSheetId = {}; | |
this._styleSheetIdToHeader = {}; | |
this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._styleSheetChanged, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this); | |
} | |
WebInspector.CSSStyleModelResourceBinding.prototype = { | |
setStyleContent: function(styleSource, content, majorChange, userCallback) | |
{ | |
var resource = styleSource.resource(); | |
if (this._styleSheetIdForResource(resource)) { | |
this._innerSetContent(resource, content, majorChange, userCallback, null); | |
return; | |
} | |
this._loadStyleSheetHeaders(this._innerSetContent.bind(this, resource, content, majorChange, userCallback)); | |
}, | |
_styleSheetIdForResource: function(resource) | |
{ | |
return this._frameAndURLToStyleSheetId[resource.frameId + ":" + resource.url]; | |
}, | |
_inspectedURLChanged: function(event) | |
{ | |
this._frameAndURLToStyleSheetId = {}; | |
this._styleSheetIdToHeader = {}; | |
}, | |
_innerSetContent: function(resource, content, majorChange, userCallback, error) | |
{ | |
if (error) { | |
userCallback(error); | |
return; | |
} | |
var styleSheetId = this._styleSheetIdForResource(resource); | |
if (!styleSheetId) { | |
userCallback("No stylesheet found: " + resource.frameId + ":" + resource.url); | |
return; | |
} | |
this._isSettingContent = true; | |
function callbackWrapper(error) | |
{ | |
userCallback(error); | |
delete this._isSettingContent; | |
} | |
this._cssModel.setStyleSheetText(styleSheetId, content, majorChange, callbackWrapper.bind(this)); | |
}, | |
_loadStyleSheetHeaders: function(callback) | |
{ | |
function didGetAllStyleSheets(error, infos) | |
{ | |
if (error) { | |
callback(error); | |
return; | |
} | |
for (var i = 0; i < infos.length; ++i) { | |
var info = infos[i]; | |
if (info.origin === "inspector") { | |
this._getOrCreateInspectorResource(info); | |
continue; | |
} | |
this._frameAndURLToStyleSheetId[info.frameId + ":" + info.sourceURL] = info.styleSheetId; | |
this._styleSheetIdToHeader[info.styleSheetId] = info; | |
} | |
callback(null); | |
} | |
CSSAgent.getAllStyleSheets(didGetAllStyleSheets.bind(this)); | |
}, | |
_styleSheetChanged: function(event) | |
{ | |
if (this._isSettingContent) | |
return; | |
if (!event.data.majorChange) | |
return; | |
function callback(error, content) | |
{ | |
if (!error) | |
this._innerStyleSheetChanged(event.data.styleSheetId, content); | |
} | |
CSSAgent.getStyleSheetText(event.data.styleSheetId, callback.bind(this)); | |
}, | |
_innerStyleSheetChanged: function(styleSheetId, content) | |
{ | |
function setContent() | |
{ | |
var header = this._styleSheetIdToHeader[styleSheetId]; | |
if (!header) | |
return; | |
var frame = WebInspector.resourceTreeModel.frameForId(header.frameId); | |
if (!frame) | |
return; | |
var styleSheetURL = header.origin === "inspector" ? this._viaInspectorResourceURL(header.sourceURL) : header.sourceURL; | |
var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(styleSheetURL); | |
if (!uiSourceCode) | |
return; | |
if (uiSourceCode.contentType() === WebInspector.resourceTypes.Stylesheet) | |
uiSourceCode.addRevision(content); | |
} | |
if (!this._styleSheetIdToHeader[styleSheetId]) { | |
this._loadStyleSheetHeaders(setContent.bind(this)); | |
return; | |
} | |
setContent.call(this); | |
}, | |
_requestViaInspectorResource: function(styleSheetId, callback) | |
{ | |
var header = this._styleSheetIdToHeader[styleSheetId]; | |
if (header) { | |
callback(this._getOrCreateInspectorResource(header)); | |
return; | |
} | |
function headersLoaded() | |
{ | |
var header = this._styleSheetIdToHeader[styleSheetId]; | |
if (header) | |
callback(this._getOrCreateInspectorResource(header)); | |
else | |
callback(null); | |
} | |
this._loadStyleSheetHeaders(headersLoaded.bind(this)); | |
}, | |
_getOrCreateInspectorResource: function(header) | |
{ | |
var frame = WebInspector.resourceTreeModel.frameForId(header.frameId); | |
if (!frame) | |
return null; | |
var viaInspectorURL = this._viaInspectorResourceURL(header.sourceURL); | |
var inspectorResource = frame.resourceForURL(viaInspectorURL); | |
if (inspectorResource) | |
return inspectorResource; | |
var resource = frame.resourceForURL(header.sourceURL); | |
if (!resource) | |
return null; | |
this._frameAndURLToStyleSheetId[header.frameId + ":" + viaInspectorURL] = header.styleSheetId; | |
this._styleSheetIdToHeader[header.styleSheetId] = header; | |
inspectorResource = new WebInspector.Resource(null, viaInspectorURL, resource.documentURL, resource.frameId, resource.loaderId, WebInspector.resourceTypes.Stylesheet, "text/css", true); | |
function overrideRequestContent(callback) | |
{ | |
function callbackWrapper(error, content) | |
{ | |
callback(error ? "" : content, false, "text/css"); | |
} | |
CSSAgent.getStyleSheetText(header.styleSheetId, callbackWrapper); | |
} | |
inspectorResource.requestContent = overrideRequestContent; | |
frame.addResource(inspectorResource); | |
return inspectorResource; | |
}, | |
_viaInspectorResourceURL: function(documentURL) | |
{ | |
var parsedURL = new WebInspector.ParsedURL(documentURL); | |
var fakeURL = "inspector://" + parsedURL.host + parsedURL.folderPathComponents; | |
if (!fakeURL.endsWith("/")) | |
fakeURL += "/"; | |
fakeURL += "inspector-stylesheet"; | |
return fakeURL; | |
} | |
} | |
WebInspector.CSSDispatcher = function(cssModel) | |
{ | |
this._cssModel = cssModel; | |
} | |
WebInspector.CSSDispatcher.prototype = { | |
mediaQueryResultChanged: function() | |
{ | |
this._cssModel.mediaQueryResultChanged(); | |
}, | |
styleSheetChanged: function(styleSheetId) | |
{ | |
this._cssModel._fireStyleSheetChanged(styleSheetId); | |
}, | |
namedFlowCreated: function(namedFlowPayload) | |
{ | |
this._cssModel._namedFlowCreated(namedFlowPayload); | |
}, | |
namedFlowRemoved: function(documentNodeId, flowName) | |
{ | |
this._cssModel._namedFlowRemoved(documentNodeId, flowName); | |
}, | |
regionLayoutUpdated: function(namedFlowPayload) | |
{ | |
this._cssModel._regionLayoutUpdated(namedFlowPayload); | |
} | |
} | |
WebInspector.NamedFlow = function(payload) | |
{ | |
this.documentNodeId = payload.documentNodeId; | |
this.name = payload.name; | |
this.overset = payload.overset; | |
this.content = payload.content; | |
this.regions = payload.regions; | |
} | |
WebInspector.NamedFlow.parsePayload = function(payload) | |
{ | |
return new WebInspector.NamedFlow(payload); | |
} | |
WebInspector.NamedFlowCollection = function(payload) | |
{ | |
this.namedFlowMap = {}; | |
for (var i = 0; i < payload.length; ++i) { | |
var namedFlow = WebInspector.NamedFlow.parsePayload(payload[i]); | |
this.namedFlowMap[namedFlow.name] = namedFlow; | |
} | |
} | |
WebInspector.NamedFlowCollection.prototype = { | |
_appendNamedFlow: function(namedFlow) | |
{ | |
this.namedFlowMap[namedFlow.name] = namedFlow; | |
}, | |
_removeNamedFlow: function(flowName) | |
{ | |
delete this.namedFlowMap[flowName]; | |
}, | |
flowByName: function(flowName) | |
{ | |
var namedFlow = this.namedFlowMap[flowName]; | |
if (!namedFlow) | |
return null; | |
return namedFlow; | |
} | |
} | |
WebInspector.cssModel = null; | |
WebInspector.NetworkManager = function() | |
{ | |
WebInspector.Object.call(this); | |
this._dispatcher = new WebInspector.NetworkDispatcher(this); | |
if (WebInspector.settings.cacheDisabled.get()) | |
NetworkAgent.setCacheDisabled(true); | |
NetworkAgent.enable(); | |
WebInspector.settings.cacheDisabled.addChangeListener(this._cacheDisabledSettingChanged, this); | |
if (WebInspector.settings.userAgent.get()) | |
this._userAgentSettingChanged(); | |
WebInspector.settings.userAgent.addChangeListener(this._userAgentSettingChanged, this); | |
} | |
WebInspector.NetworkManager.EventTypes = { | |
RequestStarted: "RequestStarted", | |
RequestUpdated: "RequestUpdated", | |
RequestFinished: "RequestFinished", | |
RequestUpdateDropped: "RequestUpdateDropped" | |
} | |
WebInspector.NetworkManager._MIMETypes = { | |
"text/html": {"document": true}, | |
"text/xml": {"document": true}, | |
"text/plain": {"document": true}, | |
"application/xhtml+xml": {"document": true}, | |
"text/css": {"stylesheet": true}, | |
"text/xsl": {"stylesheet": true}, | |
"image/jpeg": {"image": true}, | |
"image/png": {"image": true}, | |
"image/gif": {"image": true}, | |
"image/bmp": {"image": true}, | |
"image/svg+xml": {"image": true}, | |
"image/vnd.microsoft.icon": {"image": true}, | |
"image/webp": {"image": true}, | |
"image/x-icon": {"image": true}, | |
"image/x-xbitmap": {"image": true}, | |
"font/ttf": {"font": true}, | |
"font/opentype": {"font": true}, | |
"font/woff": {"font": true}, | |
"application/x-font-type1": {"font": true}, | |
"application/x-font-ttf": {"font": true}, | |
"application/x-font-woff": {"font": true}, | |
"application/x-truetype-font": {"font": true}, | |
"text/javascript": {"script": true}, | |
"text/ecmascript": {"script": true}, | |
"application/javascript": {"script": true}, | |
"application/ecmascript": {"script": true}, | |
"application/x-javascript": {"script": true}, | |
"application/json": {"script": true}, | |
"text/javascript1.1": {"script": true}, | |
"text/javascript1.2": {"script": true}, | |
"text/javascript1.3": {"script": true}, | |
"text/jscript": {"script": true}, | |
"text/livescript": {"script": true}, | |
} | |
WebInspector.NetworkManager.prototype = { | |
inflightRequestForURL: function(url) | |
{ | |
return this._dispatcher._inflightRequestsByURL[url]; | |
}, | |
_cacheDisabledSettingChanged: function(event) | |
{ | |
var enabled = event.data; | |
NetworkAgent.setCacheDisabled(enabled); | |
}, | |
_userAgentSettingChanged: function() | |
{ | |
NetworkAgent.setUserAgentOverride(WebInspector.settings.userAgent.get()); | |
} | |
} | |
WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.NetworkDispatcher = function(manager) | |
{ | |
this._manager = manager; | |
this._inflightRequestsById = {}; | |
this._inflightRequestsByURL = {}; | |
InspectorBackend.registerNetworkDispatcher(this); | |
} | |
WebInspector.NetworkDispatcher.prototype = { | |
_headersMapToHeadersArray: function(headersMap) | |
{ | |
var result = []; | |
for (var name in headersMap) { | |
var values = headersMap[name].split("\n"); | |
for (var i = 0; i < values.length; ++i) | |
result.push({ name: name, value: values[i] }); | |
} | |
return result; | |
}, | |
_updateNetworkRequestWithRequest: function(networkRequest, request) | |
{ | |
networkRequest.requestMethod = request.method; | |
networkRequest.requestHeaders = this._headersMapToHeadersArray(request.headers); | |
networkRequest.requestFormData = request.postData; | |
}, | |
_updateNetworkRequestWithResponse: function(networkRequest, response) | |
{ | |
if (!response) | |
return; | |
if (response.url && networkRequest.url !== response.url) | |
networkRequest.url = response.url; | |
networkRequest.mimeType = response.mimeType; | |
networkRequest.statusCode = response.status; | |
networkRequest.statusText = response.statusText; | |
networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers); | |
if (response.headersText) | |
networkRequest.responseHeadersText = response.headersText; | |
if (response.requestHeaders) | |
networkRequest.requestHeaders = this._headersMapToHeadersArray(response.requestHeaders); | |
if (response.requestHeadersText) | |
networkRequest.requestHeadersText = response.requestHeadersText; | |
networkRequest.connectionReused = response.connectionReused; | |
networkRequest.connectionId = response.connectionId; | |
if (response.fromDiskCache) | |
networkRequest.cached = true; | |
else | |
networkRequest.timing = response.timing; | |
if (!this._mimeTypeIsConsistentWithType(networkRequest)) { | |
WebInspector.console.addMessage(WebInspector.ConsoleMessage.create(WebInspector.ConsoleMessage.MessageSource.Network, | |
WebInspector.ConsoleMessage.MessageLevel.Warning, | |
WebInspector.UIString("Resource interpreted as %s but transferred with MIME type %s: \"%s\".", networkRequest.type.title(), networkRequest.mimeType, networkRequest.url), | |
WebInspector.ConsoleMessage.MessageType.Log, | |
"", | |
0, | |
1, | |
[], | |
null, | |
networkRequest.requestId)); | |
} | |
}, | |
_mimeTypeIsConsistentWithType: function(networkRequest) | |
{ | |
if (networkRequest.hasErrorStatusCode() || networkRequest.statusCode === 304 || networkRequest.statusCode === 204) | |
return true; | |
if (typeof networkRequest.type === "undefined" | |
|| networkRequest.type === WebInspector.resourceTypes.Other | |
|| networkRequest.type === WebInspector.resourceTypes.XHR | |
|| networkRequest.type === WebInspector.resourceTypes.WebSocket) | |
return true; | |
if (!networkRequest.mimeType) | |
return true; | |
if (networkRequest.mimeType in WebInspector.NetworkManager._MIMETypes) | |
return networkRequest.type.name() in WebInspector.NetworkManager._MIMETypes[networkRequest.mimeType]; | |
return false; | |
}, | |
_updateNetworkRequestWithCachedResource: function(networkRequest, cachedResource) | |
{ | |
networkRequest.type = WebInspector.resourceTypes[cachedResource.type]; | |
networkRequest.resourceSize = cachedResource.bodySize; | |
this._updateNetworkRequestWithResponse(networkRequest, cachedResource.response); | |
}, | |
_isNull: function(response) | |
{ | |
if (!response) | |
return true; | |
return !response.status && !response.mimeType && (!response.headers || !Object.keys(response.headers).length); | |
}, | |
requestWillBeSent: function(requestId, frameId, loaderId, documentURL, request, time, initiator, redirectResponse) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (networkRequest) { | |
if (!redirectResponse) | |
return; | |
this.responseReceived(requestId, frameId, loaderId, time, "Other", redirectResponse); | |
networkRequest = this._appendRedirect(requestId, time, request.url); | |
} else | |
networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, request.url, documentURL, initiator); | |
networkRequest.hasNetworkData = true; | |
this._updateNetworkRequestWithRequest(networkRequest, request); | |
networkRequest.startTime = time; | |
this._startNetworkRequest(networkRequest); | |
}, | |
requestServedFromCache: function(requestId) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.cached = true; | |
}, | |
responseReceived: function(requestId, frameId, loaderId, time, resourceType, response) | |
{ | |
if (this._isNull(response)) | |
return; | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) { | |
var eventData = {}; | |
eventData.url = response.url; | |
eventData.frameId = frameId; | |
eventData.loaderId = loaderId; | |
eventData.resourceType = resourceType; | |
eventData.mimeType = response.mimeType; | |
this._manager.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, eventData); | |
return; | |
} | |
networkRequest.responseReceivedTime = time; | |
networkRequest.type = WebInspector.resourceTypes[resourceType]; | |
this._updateNetworkRequestWithResponse(networkRequest, response); | |
this._updateNetworkRequest(networkRequest); | |
}, | |
dataReceived: function(requestId, time, dataLength, encodedDataLength) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.resourceSize += dataLength; | |
if (encodedDataLength != -1) | |
networkRequest.increaseTransferSize(encodedDataLength); | |
networkRequest.endTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
loadingFinished: function(requestId, finishTime) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
this._finishNetworkRequest(networkRequest, finishTime); | |
}, | |
loadingFailed: function(requestId, time, localizedDescription, canceled) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.failed = true; | |
networkRequest.canceled = canceled; | |
networkRequest.localizedFailDescription = localizedDescription; | |
this._finishNetworkRequest(networkRequest, time); | |
}, | |
requestServedFromMemoryCache: function(requestId, frameId, loaderId, documentURL, time, initiator, cachedResource) | |
{ | |
var networkRequest = this._createNetworkRequest(requestId, frameId, loaderId, cachedResource.url, documentURL, initiator); | |
this._updateNetworkRequestWithCachedResource(networkRequest, cachedResource); | |
networkRequest.cached = true; | |
networkRequest.requestMethod = "GET"; | |
this._startNetworkRequest(networkRequest); | |
networkRequest.startTime = networkRequest.responseReceivedTime = time; | |
this._finishNetworkRequest(networkRequest, time); | |
}, | |
webSocketCreated: function(requestId, requestURL) | |
{ | |
var networkRequest = new WebInspector.NetworkRequest(requestId, requestURL, "", "", ""); | |
networkRequest.type = WebInspector.resourceTypes.WebSocket; | |
this._startNetworkRequest(networkRequest); | |
}, | |
webSocketWillSendHandshakeRequest: function(requestId, time, request) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.requestMethod = "GET"; | |
networkRequest.requestHeaders = this._headersMapToHeadersArray(request.headers); | |
networkRequest.webSocketRequestKey3 = request.requestKey3; | |
networkRequest.startTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
webSocketHandshakeResponseReceived: function(requestId, time, response) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.statusCode = response.status; | |
networkRequest.statusText = response.statusText; | |
networkRequest.responseHeaders = this._headersMapToHeadersArray(response.headers); | |
networkRequest.webSocketChallengeResponse = response.challengeResponse; | |
networkRequest.responseReceivedTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
webSocketFrameReceived: function(requestId, time, response) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.addFrame(response, time); | |
networkRequest.responseReceivedTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
webSocketFrameSent: function(requestId, time, response) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.addFrame(response, time, true); | |
networkRequest.responseReceivedTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
webSocketFrameError: function(requestId, time, errorMessage) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
networkRequest.addFrameError(errorMessage, time); | |
networkRequest.responseReceivedTime = time; | |
this._updateNetworkRequest(networkRequest); | |
}, | |
webSocketClosed: function(requestId, time) | |
{ | |
var networkRequest = this._inflightRequestsById[requestId]; | |
if (!networkRequest) | |
return; | |
this._finishNetworkRequest(networkRequest, time); | |
}, | |
_appendRedirect: function(requestId, time, redirectURL) | |
{ | |
var originalNetworkRequest = this._inflightRequestsById[requestId]; | |
var previousRedirects = originalNetworkRequest.redirects || []; | |
originalNetworkRequest.requestId = "redirected:" + requestId + "." + previousRedirects.length; | |
delete originalNetworkRequest.redirects; | |
if (previousRedirects.length > 0) | |
originalNetworkRequest.redirectSource = previousRedirects[previousRedirects.length - 1]; | |
this._finishNetworkRequest(originalNetworkRequest, time); | |
var newNetworkRequest = this._createNetworkRequest(requestId, originalNetworkRequest.frameId, originalNetworkRequest.loaderId, | |
redirectURL, originalNetworkRequest.documentURL, originalNetworkRequest.initiator); | |
newNetworkRequest.redirects = previousRedirects.concat(originalNetworkRequest); | |
return newNetworkRequest; | |
}, | |
_startNetworkRequest: function(networkRequest) | |
{ | |
this._inflightRequestsById[networkRequest.requestId] = networkRequest; | |
this._inflightRequestsByURL[networkRequest.url] = networkRequest; | |
this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestStarted, networkRequest); | |
}, | |
_updateNetworkRequest: function(networkRequest) | |
{ | |
this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestUpdated, networkRequest); | |
}, | |
_finishNetworkRequest: function(networkRequest, finishTime) | |
{ | |
networkRequest.endTime = finishTime; | |
networkRequest.finished = true; | |
this._dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.RequestFinished, networkRequest); | |
delete this._inflightRequestsById[networkRequest.requestId]; | |
delete this._inflightRequestsByURL[networkRequest.url]; | |
}, | |
_dispatchEventToListeners: function(eventType, networkRequest) | |
{ | |
this._manager.dispatchEventToListeners(eventType, networkRequest); | |
}, | |
_createNetworkRequest: function(requestId, frameId, loaderId, url, documentURL, initiator) | |
{ | |
var networkRequest = new WebInspector.NetworkRequest(requestId, url, documentURL, frameId, loaderId); | |
networkRequest.initiator = initiator; | |
return networkRequest; | |
} | |
} | |
WebInspector.networkManager = null; | |
WebInspector.NetworkLog = function() | |
{ | |
this._requests = []; | |
this._requestForId = {}; | |
WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._onMainFrameNavigated, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.OnLoad, this._onLoad, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._onDOMContentLoaded, this); | |
} | |
WebInspector.NetworkLog.prototype = { | |
get requests() | |
{ | |
return this._requests; | |
}, | |
pageLoadForRequest: function(request) | |
{ | |
return request.__page; | |
}, | |
_onMainFrameNavigated: function(event) | |
{ | |
var mainFrame = event.data; | |
this._currentPageLoad = null; | |
var oldRequests = this._requests.splice(0, this._requests.length); | |
for (var i = 0; i < oldRequests.length; ++i) { | |
var request = oldRequests[i]; | |
if (request.loaderId === mainFrame.loaderId) { | |
if (!this._currentPageLoad) | |
this._currentPageLoad = new WebInspector.PageLoad(request); | |
this._requests.push(request); | |
request.__page = this._currentPageLoad; | |
} | |
} | |
}, | |
_onRequestStarted: function(event) | |
{ | |
var request = event.data; | |
this._requests.push(request); | |
this._requestForId[request.requestId] = request; | |
request.__page = this._currentPageLoad; | |
}, | |
_onDOMContentLoaded: function(event) | |
{ | |
if (this._currentPageLoad) | |
this._currentPageLoad.contentLoadTime = event.data; | |
}, | |
_onLoad: function(event) | |
{ | |
if (this._currentPageLoad) | |
this._currentPageLoad.loadTime = event.data; | |
}, | |
requestForId: function(requestId) | |
{ | |
return this._requestForId[requestId]; | |
} | |
} | |
WebInspector.networkLog = null; | |
WebInspector.PageLoad = function(mainRequest) | |
{ | |
this.id = ++WebInspector.PageLoad._lastIdentifier; | |
this.url = mainRequest.url; | |
this.startTime = mainRequest.startTime; | |
} | |
WebInspector.PageLoad._lastIdentifier = 0; | |
WebInspector.ResourceTreeModel = function(networkManager) | |
{ | |
networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this); | |
networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, this._onRequestUpdateDropped, this); | |
WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this); | |
WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.RepeatCountUpdated, this._consoleMessageAdded, this); | |
WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this); | |
PageAgent.enable(); | |
NetworkAgent.enable(); | |
this._fetchResourceTree(); | |
InspectorBackend.registerPageDispatcher(new WebInspector.PageDispatcher(this)); | |
this._pendingConsoleMessages = {}; | |
} | |
WebInspector.ResourceTreeModel.EventTypes = { | |
FrameAdded: "FrameAdded", | |
FrameNavigated: "FrameNavigated", | |
FrameDetached: "FrameDetached", | |
MainFrameNavigated: "MainFrameNavigated", | |
ResourceAdded: "ResourceAdded", | |
WillLoadCachedResources: "WillLoadCachedResources", | |
CachedResourcesLoaded: "CachedResourcesLoaded", | |
DOMContentLoaded: "DOMContentLoaded", | |
OnLoad: "OnLoad", | |
InspectedURLChanged: "InspectedURLChanged" | |
} | |
WebInspector.ResourceTreeModel.prototype = { | |
_fetchResourceTree: function() | |
{ | |
this._frames = {}; | |
delete this._cachedResourcesProcessed; | |
PageAgent.getResourceTree(this._processCachedResources.bind(this)); | |
}, | |
_processCachedResources: function(error, mainFramePayload) | |
{ | |
if (error) { | |
console.error(JSON.stringify(error)); | |
return; | |
} | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources); | |
WebInspector.inspectedPageURL = mainFramePayload.frame.url; | |
this._addFramesRecursively(null, mainFramePayload); | |
this._dispatchInspectedURLChanged(); | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded); | |
this._cachedResourcesProcessed = true; | |
}, | |
cachedResourcesLoaded: function() | |
{ | |
return this._cachedResourcesProcessed; | |
}, | |
_dispatchInspectedURLChanged: function() | |
{ | |
InspectorFrontendHost.inspectedURLChanged(WebInspector.inspectedPageURL); | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, WebInspector.inspectedPageURL); | |
}, | |
_addFrame: function(frame) | |
{ | |
this._frames[frame.id] = frame; | |
if (frame.isMainFrame()) | |
this.mainFrame = frame; | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, frame); | |
}, | |
_frameNavigated: function(framePayload) | |
{ | |
if (!this._cachedResourcesProcessed) | |
return; | |
var frame = this._frames[framePayload.id]; | |
if (frame) { | |
frame._navigate(framePayload); | |
} else { | |
var parentFrame = this._frames[framePayload.parentId]; | |
frame = new WebInspector.ResourceTreeFrame(this, parentFrame, framePayload); | |
if (frame.isMainFrame() && this.mainFrame) { | |
this._frameDetached(this.mainFrame.id); | |
} | |
this._addFrame(frame); | |
} | |
if (frame.isMainFrame()) | |
WebInspector.inspectedPageURL = frame.url; | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, frame); | |
if (frame.isMainFrame()) | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, frame); | |
var resources = frame.resources(); | |
for (var i = 0; i < resources.length; ++i) | |
this.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resources[i]); | |
if (frame.isMainFrame()) | |
this._dispatchInspectedURLChanged(); | |
}, | |
_frameDetached: function(frameId) | |
{ | |
if (!this._cachedResourcesProcessed) | |
return; | |
var frame = this._frames[frameId]; | |
if (!frame) | |
return; | |
if (frame.parentFrame) | |
frame.parentFrame._removeChildFrame(frame); | |
else | |
frame._remove(); | |
}, | |
_onRequestFinished: function(event) | |
{ | |
if (!this._cachedResourcesProcessed) | |
return; | |
var request = event.data; | |
if (request.failed || request.type === WebInspector.resourceTypes.XHR) | |
return; | |
var frame = this._frames[request.frameId]; | |
if (frame) { | |
var resource = frame._addRequest(request); | |
this._addPendingConsoleMessagesToResource(resource); | |
} | |
}, | |
_onRequestUpdateDropped: function(event) | |
{ | |
if (!this._cachedResourcesProcessed) | |
return; | |
var frameId = event.data.frameId; | |
var frame = this._frames[frameId]; | |
if (!frame) | |
return; | |
var url = event.data.url; | |
if (frame._resourcesMap[url]) | |
return; | |
var resource = new WebInspector.Resource(null, url, frame.url, frameId, event.data.loaderId, WebInspector.resourceTypes[event.data.resourceType], event.data.mimeType); | |
frame.addResource(resource); | |
}, | |
frameForId: function(frameId) | |
{ | |
return this._frames[frameId]; | |
}, | |
forAllResources: function(callback) | |
{ | |
if (this.mainFrame) | |
return this.mainFrame._callForFrameResources(callback); | |
return false; | |
}, | |
_consoleMessageAdded: function(event) | |
{ | |
var msg = event.data; | |
var resource = msg.url ? this.resourceForURL(msg.url) : null; | |
if (resource) | |
this._addConsoleMessageToResource(msg, resource); | |
else | |
this._addPendingConsoleMessage(msg); | |
}, | |
_addPendingConsoleMessage: function(msg) | |
{ | |
if (!msg.url) | |
return; | |
if (!this._pendingConsoleMessages[msg.url]) | |
this._pendingConsoleMessages[msg.url] = []; | |
this._pendingConsoleMessages[msg.url].push(msg); | |
}, | |
_addPendingConsoleMessagesToResource: function(resource) | |
{ | |
var messages = this._pendingConsoleMessages[resource.url]; | |
if (messages) { | |
for (var i = 0; i < messages.length; i++) | |
this._addConsoleMessageToResource(messages[i], resource); | |
delete this._pendingConsoleMessages[resource.url]; | |
} | |
}, | |
_addConsoleMessageToResource: function(msg, resource) | |
{ | |
switch (msg.level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
resource.warnings += msg.repeatDelta; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
resource.errors += msg.repeatDelta; | |
break; | |
} | |
resource.addMessage(msg); | |
}, | |
_consoleCleared: function() | |
{ | |
function callback(resource) | |
{ | |
resource.clearErrorsAndWarnings(); | |
} | |
this._pendingConsoleMessages = {}; | |
this.forAllResources(callback); | |
}, | |
resourceForURL: function(url) | |
{ | |
return this.mainFrame ? this.mainFrame.resourceForURL(url) : null; | |
}, | |
_addFramesRecursively: function(parentFrame, frameTreePayload) | |
{ | |
var framePayload = frameTreePayload.frame; | |
var frame = new WebInspector.ResourceTreeFrame(this, parentFrame, framePayload); | |
this._addFrame(frame); | |
var frameResource = this._createResourceFromFramePayload(framePayload, framePayload.url, WebInspector.resourceTypes.Document, framePayload.mimeType); | |
if (frame.isMainFrame()) | |
WebInspector.inspectedPageURL = frameResource.url; | |
frame.addResource(frameResource); | |
for (var i = 0; frameTreePayload.childFrames && i < frameTreePayload.childFrames.length; ++i) | |
this._addFramesRecursively(frame, frameTreePayload.childFrames[i]); | |
for (var i = 0; i < frameTreePayload.resources.length; ++i) { | |
var subresource = frameTreePayload.resources[i]; | |
var resource = this._createResourceFromFramePayload(framePayload, subresource.url, WebInspector.resourceTypes[subresource.type], subresource.mimeType); | |
frame.addResource(resource); | |
} | |
}, | |
_createResourceFromFramePayload: function(frame, url, type, mimeType) | |
{ | |
return new WebInspector.Resource(null, url, frame.url, frame.id, frame.loaderId, type, mimeType); | |
} | |
} | |
WebInspector.ResourceTreeModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.ResourceTreeFrame = function(model, parentFrame, payload) | |
{ | |
this._model = model; | |
this._parentFrame = parentFrame; | |
this._id = payload.id; | |
this._loaderId = payload.loaderId; | |
this._name = payload.name; | |
this._url = payload.url; | |
this._securityOrigin = payload.securityOrigin || ""; | |
this._mimeType = payload.mimeType; | |
this._childFrames = []; | |
this._resourcesMap = {}; | |
if (this._parentFrame) | |
this._parentFrame._childFrames.push(this); | |
} | |
WebInspector.ResourceTreeFrame.prototype = { | |
get id() | |
{ | |
return this._id; | |
}, | |
get name() | |
{ | |
return this._name || ""; | |
}, | |
get url() | |
{ | |
return this._url; | |
}, | |
get securityOrigin() | |
{ | |
return this._securityOrigin; | |
}, | |
get loaderId() | |
{ | |
return this._loaderId; | |
}, | |
get parentFrame() | |
{ | |
return this._parentFrame; | |
}, | |
get childFrames() | |
{ | |
return this._childFrames; | |
}, | |
isMainFrame: function() | |
{ | |
return !this._parentFrame; | |
}, | |
_navigate: function(framePayload) | |
{ | |
this._loaderId = framePayload.loaderId; | |
this._name = framePayload.name; | |
this._url = framePayload.url; | |
this._securityOrigin = framePayload.securityOrigin || ""; | |
this._mimeType = framePayload.mimeType; | |
var mainResource = this._resourcesMap[this._url]; | |
this._resourcesMap = {}; | |
this._removeChildFrames(); | |
if (mainResource && mainResource.loaderId === this._loaderId) | |
this.addResource(mainResource); | |
}, | |
get mainResource() | |
{ | |
return this._resourcesMap[this._url]; | |
}, | |
_removeChildFrame: function(frame) | |
{ | |
this._childFrames.remove(frame); | |
frame._remove(); | |
}, | |
_removeChildFrames: function() | |
{ | |
var copy = this._childFrames.slice(); | |
for (var i = 0; i < copy.length; ++i) | |
this._removeChildFrame(copy[i]); | |
}, | |
_remove: function() | |
{ | |
this._removeChildFrames(); | |
delete this._model._frames[this.id]; | |
this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this); | |
}, | |
addResource: function(resource) | |
{ | |
if (this._resourcesMap[resource.url] === resource) { | |
return; | |
} | |
this._resourcesMap[resource.url] = resource; | |
this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource); | |
}, | |
_addRequest: function(request) | |
{ | |
var resource = this._resourcesMap[request.url]; | |
if (resource && resource.request === request) { | |
return resource; | |
} | |
resource = new WebInspector.Resource(request, request.url, request.documentURL, request.frameId, request.loaderId, request.type, request.mimeType); | |
this._resourcesMap[resource.url] = resource; | |
this._model.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, resource); | |
return resource; | |
}, | |
resources: function() | |
{ | |
var result = []; | |
for (var url in this._resourcesMap) | |
result.push(this._resourcesMap[url]); | |
return result; | |
}, | |
resourceForURL: function(url) | |
{ | |
var result; | |
function filter(resource) | |
{ | |
if (resource.url === url) { | |
result = resource; | |
return true; | |
} | |
} | |
this._callForFrameResources(filter); | |
return result; | |
}, | |
_callForFrameResources: function(callback) | |
{ | |
for (var url in this._resourcesMap) { | |
if (callback(this._resourcesMap[url])) | |
return true; | |
} | |
for (var i = 0; i < this._childFrames.length; ++i) { | |
if (this._childFrames[i]._callForFrameResources(callback)) | |
return true; | |
} | |
return false; | |
} | |
} | |
WebInspector.PageDispatcher = function(resourceTreeModel) | |
{ | |
this._resourceTreeModel = resourceTreeModel; | |
} | |
WebInspector.PageDispatcher.prototype = { | |
domContentEventFired: function(time) | |
{ | |
this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, time); | |
}, | |
loadEventFired: function(time) | |
{ | |
this._resourceTreeModel.dispatchEventToListeners(WebInspector.ResourceTreeModel.EventTypes.OnLoad, time); | |
}, | |
frameNavigated: function(frame) | |
{ | |
this._resourceTreeModel._frameNavigated(frame); | |
}, | |
frameDetached: function(frameId) | |
{ | |
this._resourceTreeModel._frameDetached(frameId); | |
} | |
} | |
WebInspector.resourceTreeModel = null; | |
WebInspector.ParsedURL = function(url) | |
{ | |
this.isValid = false; | |
this.url = url; | |
this.scheme = ""; | |
this.host = ""; | |
this.port = ""; | |
this.path = ""; | |
this.queryParams = ""; | |
this.fragment = ""; | |
this.folderPathComponents = ""; | |
this.lastPathComponent = ""; | |
var match = url.match(/^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i); | |
if (match) { | |
this.isValid = true; | |
this.scheme = match[1].toLowerCase(); | |
this.host = match[2]; | |
this.port = match[3]; | |
this.path = match[4] || "/"; | |
this.fragment = match[5]; | |
} else { | |
if (this.url.startsWith("data:")) { | |
this.scheme = "data"; | |
return; | |
} | |
if (this.url === "about:blank") { | |
this.scheme = "about"; | |
return; | |
} | |
this.path = this.url; | |
} | |
if (this.path) { | |
var path = this.path; | |
var indexOfQuery = path.indexOf("?"); | |
if (indexOfQuery !== -1) { | |
this.queryParams = path.substring(indexOfQuery + 1) | |
path = path.substring(0, indexOfQuery); | |
} | |
var lastSlashIndex = path.lastIndexOf("/"); | |
if (lastSlashIndex !== -1) { | |
this.folderPathComponents = path.substring(0, lastSlashIndex); | |
this.lastPathComponent = path.substring(lastSlashIndex + 1); | |
} else | |
this.lastPathComponent = path; | |
} | |
} | |
WebInspector.ParsedURL.completeURL = function(baseURL, href) | |
{ | |
if (href) { | |
var trimmedHref = href.trim(); | |
if (trimmedHref.startsWith("data:") || trimmedHref.startsWith("blob:") || trimmedHref.startsWith("javascript:")) | |
return href; | |
var parsedHref = trimmedHref.asParsedURL(); | |
if (parsedHref && parsedHref.scheme) | |
return trimmedHref; | |
} else | |
return baseURL; | |
var parsedURL = baseURL.asParsedURL(); | |
if (parsedURL) { | |
var path = href; | |
if (path.charAt(0) !== "/") { | |
var basePath = parsedURL.path; | |
var questionMarkIndex = basePath.indexOf("?"); | |
if (questionMarkIndex > 0) | |
basePath = basePath.substring(0, questionMarkIndex); | |
var prefix; | |
if (path.charAt(0) === "?") { | |
var basePathCutIndex = basePath.indexOf("?"); | |
if (basePathCutIndex !== -1) | |
prefix = basePath.substring(0, basePathCutIndex); | |
else | |
prefix = basePath; | |
} else | |
prefix = basePath.substring(0, basePath.lastIndexOf("/")) + "/"; | |
path = prefix + path; | |
} else if (path.length > 1 && path.charAt(1) === "/") { | |
return parsedURL.scheme + ":" + path; | |
} | |
return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + path; | |
} | |
return null; | |
} | |
WebInspector.ParsedURL.prototype = { | |
get displayName() | |
{ | |
if (this._displayName) | |
return this._displayName; | |
if (this.scheme === "data") { | |
this._displayName = this.url.trimEnd(20); | |
return this._displayName; | |
} | |
if (this.url === "about:blank") | |
return this.url; | |
this._displayName = this.lastPathComponent; | |
if (!this._displayName) | |
this._displayName = this.host; | |
if (!this._displayName && this.url) | |
this._displayName = this.url.trimURL(WebInspector.inspectedPageDomain ? WebInspector.inspectedPageDomain : ""); | |
if (this._displayName === "/") | |
this._displayName = this.url; | |
return this._displayName; | |
} | |
} | |
String.prototype.asParsedURL = function() | |
{ | |
var parsedURL = new WebInspector.ParsedURL(this.toString()); | |
if (parsedURL.isValid) | |
return parsedURL; | |
return null; | |
} | |
WebInspector.resourceForURL = function(url) | |
{ | |
return WebInspector.resourceTreeModel.resourceForURL(url); | |
} | |
WebInspector.forAllResources = function(callback) | |
{ | |
WebInspector.resourceTreeModel.forAllResources(callback); | |
} | |
WebInspector.displayNameForURL = function(url) | |
{ | |
if (!url) | |
return ""; | |
var resource = WebInspector.resourceForURL(url); | |
if (resource) | |
return resource.displayName; | |
if (!WebInspector.inspectedPageURL) | |
return url.trimURL(""); | |
var parsedURL = WebInspector.inspectedPageURL.asParsedURL(); | |
var lastPathComponent = parsedURL ? parsedURL.lastPathComponent : parsedURL; | |
var index = WebInspector.inspectedPageURL.indexOf(lastPathComponent); | |
if (index !== -1 && index + lastPathComponent.length === WebInspector.inspectedPageURL.length) { | |
var baseURL = WebInspector.inspectedPageURL.substring(0, index); | |
if (url.startsWith(baseURL)) | |
return url.substring(index); | |
} | |
return parsedURL ? url.trimURL(parsedURL.host) : url; | |
} | |
WebInspector.linkifyStringAsFragmentWithCustomLinkifier = function(string, linkifier) | |
{ | |
var container = document.createDocumentFragment(); | |
var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|www\.)[\w$\-_+*'=\|\/\\(){}[\]%@&#~,:;.!?]{2,}[\w$\-_+*=\|\/\\({%@&#~]/; | |
var lineColumnRegEx = /:(\d+)(:(\d+))?$/; | |
while (string) { | |
var linkString = linkStringRegEx.exec(string); | |
if (!linkString) | |
break; | |
linkString = linkString[0]; | |
var linkIndex = string.indexOf(linkString); | |
var nonLink = string.substring(0, linkIndex); | |
container.appendChild(document.createTextNode(nonLink)); | |
var title = linkString; | |
var realURL = (linkString.startsWith("www.") ? "http://" + linkString : linkString); | |
var lineColumnMatch = lineColumnRegEx.exec(realURL); | |
var lineNumber; | |
if (lineColumnMatch) { | |
realURL = realURL.substring(0, realURL.length - lineColumnMatch[0].length); | |
lineNumber = parseInt(lineColumnMatch[1], 10); | |
lineNumber = isNaN(lineNumber) ? undefined : lineNumber; | |
} | |
var linkNode = linkifier(title, realURL, lineNumber); | |
container.appendChild(linkNode); | |
string = string.substring(linkIndex + linkString.length, string.length); | |
} | |
if (string) | |
container.appendChild(document.createTextNode(string)); | |
return container; | |
} | |
WebInspector._linkifierPlugins = []; | |
/** | |
* @param {function(string):string} plugin | |
*/ | |
WebInspector.registerLinkifierPlugin = function(plugin) | |
{ | |
WebInspector._linkifierPlugins.push(plugin); | |
} | |
/** | |
* @param {string} string | |
* @return {DocumentFragment} | |
*/ | |
WebInspector.linkifyStringAsFragment = function(string) | |
{ | |
/** | |
* @param {string} title | |
* @param {string} url | |
* @param {number=} lineNumber | |
* @return {Node} | |
*/ | |
function linkifier(title, url, lineNumber) | |
{ | |
for (var i = 0; i < WebInspector._linkifierPlugins.length; ++i) | |
title = WebInspector._linkifierPlugins[i](title); | |
var isExternal = !WebInspector.resourceForURL(url); | |
var urlNode = WebInspector.linkifyURLAsNode(url, title, undefined, isExternal); | |
if (typeof(lineNumber) !== "undefined") { | |
urlNode.lineNumber = lineNumber; | |
urlNode.preferredPanel = "scripts"; | |
} | |
return urlNode; | |
} | |
return WebInspector.linkifyStringAsFragmentWithCustomLinkifier(string, linkifier); | |
} | |
/** | |
* @param {string} url | |
* @param {string=} linkText | |
* @param {string=} classes | |
* @param {boolean=} isExternal | |
* @param {string=} tooltipText | |
* @return {Element} | |
*/ | |
WebInspector.linkifyURLAsNode = function(url, linkText, classes, isExternal, tooltipText) | |
{ | |
if (!linkText) | |
linkText = url; | |
classes = (classes ? classes + " " : ""); | |
classes += isExternal ? "webkit-html-external-link" : "webkit-html-resource-link"; | |
var a = document.createElement("a"); | |
a.href = sanitizeHref(url); | |
a.className = classes; | |
if (typeof tooltipText === "undefined") | |
a.title = url; | |
else if (typeof tooltipText !== "string" || tooltipText.length) | |
a.title = tooltipText; | |
a.textContent = linkText; | |
a.style.maxWidth = "100%"; | |
if (isExternal) | |
a.setAttribute("target", "_blank"); | |
return a; | |
} | |
/** | |
* @param {string} url | |
* @param {number=} lineNumber | |
* @return {string} | |
*/ | |
WebInspector.formatLinkText = function(url, lineNumber) | |
{ | |
var text = WebInspector.displayNameForURL(url); | |
if (typeof lineNumber === "number") | |
text += ":" + (lineNumber + 1); | |
return text; | |
} | |
/** | |
* @param {string} url | |
* @param {number=} lineNumber | |
* @param {string=} classes | |
* @param {string=} tooltipText | |
* @return {Element} | |
*/ | |
WebInspector.linkifyResourceAsNode = function(url, lineNumber, classes, tooltipText) | |
{ | |
var linkText = WebInspector.formatLinkText(url, lineNumber); | |
var anchor = WebInspector.linkifyURLAsNode(url, linkText, classes, false, tooltipText); | |
anchor.preferredPanel = "resources"; | |
anchor.lineNumber = lineNumber; | |
return anchor; | |
} | |
/** | |
* @param {WebInspector.NetworkRequest} request | |
* @param {string=} classes | |
* @return {Element} | |
*/ | |
WebInspector.linkifyRequestAsNode = function(request, classes) | |
{ | |
var anchor = WebInspector.linkifyURLAsNode(request.url); | |
anchor.preferredPanel = "network"; | |
anchor.requestId = request.requestId; | |
return anchor; | |
} | |
/* ResourceType.js */ | |
/* | |
* Copyright (C) 2012 Google Inc. All rights reserved. | |
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
* its contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
* @param {string} name | |
* @param {string} title | |
* @param {string} categoryTitle | |
* @param {string} color | |
* @param {boolean} isTextType | |
*/ | |
WebInspector.ResourceType = function(name, title, categoryTitle, color, isTextType) | |
{ | |
this._name = name; | |
this._title = title; | |
this._categoryTitle = categoryTitle; | |
this._color = color; | |
this._isTextType = isTextType; | |
} | |
WebInspector.ResourceType.prototype = { | |
/** | |
* @return {string} | |
*/ | |
name: function() | |
{ | |
return this._name; | |
}, | |
/** | |
* @return {string} | |
*/ | |
title: function() | |
{ | |
return this._title; | |
}, | |
/** | |
* @return {string} | |
*/ | |
categoryTitle: function() | |
{ | |
return this._categoryTitle; | |
}, | |
/** | |
* @return {string} | |
*/ | |
color: function() | |
{ | |
return this._color; | |
}, | |
/** | |
* @return {boolean} | |
*/ | |
isTextType: function() | |
{ | |
return this._isTextType; | |
}, | |
/** | |
* @return {string} | |
*/ | |
toString: function() | |
{ | |
return this._name; | |
}, | |
/** | |
* @return {string} | |
*/ | |
canonicalMimeType: function() | |
{ | |
if (this === WebInspector.resourceTypes.Document) | |
return "text/html"; | |
if (this === WebInspector.resourceTypes.Script) | |
return "text/javascript"; | |
if (this === WebInspector.resourceTypes.Stylesheet) | |
return "text/css"; | |
return ""; | |
} | |
} | |
//Keep these in sync with WebCore::InspectorPageAgent::resourceTypeJson | |
WebInspector.resourceTypes = { | |
Document: new WebInspector.ResourceType("document", "Document", "Documents", "rgb(47,102,236)", true), | |
Stylesheet: new WebInspector.ResourceType("stylesheet", "Stylesheet", "Stylesheets", "rgb(157,231,119)", true), | |
Image: new WebInspector.ResourceType("image", "Image", "Images", "rgb(164,60,255)", false), | |
Script: new WebInspector.ResourceType("script", "Script", "Scripts", "rgb(255,121,0)", true), | |
XHR: new WebInspector.ResourceType("xhr", "XHR", "XHR", "rgb(231,231,10)", true), | |
Font: new WebInspector.ResourceType("font", "Font", "Fonts", "rgb(255,82,62)", false), | |
WebSocket: new WebInspector.ResourceType("websocket", "WebSocket", "WebSockets", "rgb(186,186,186)", false), // FIXME: Decide the color. | |
Other: new WebInspector.ResourceType("other", "Other", "Other", "rgb(186,186,186)", false) | |
} | |
/* TimelineManager.js */ | |
/* | |
* Copyright (C) 2011 Google Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are | |
* met: | |
* | |
* * Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* * Redistributions in binary form must reproduce the above | |
* copyright notice, this list of conditions and the following disclaimer | |
* in the documentation and/or other materials provided with the | |
* distribution. | |
* * Neither the name of Google Inc. nor the names of its | |
* contributors may be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
* @extends {WebInspector.Object} | |
*/ | |
WebInspector.TimelineManager = function() | |
{ | |
WebInspector.Object.call(this); | |
this._dispatcher = new WebInspector.TimelineDispatcher(this); | |
this._enablementCount = 0; | |
} | |
WebInspector.TimelineManager.EventTypes = { | |
TimelineStarted: "TimelineStarted", | |
TimelineStopped: "TimelineStopped", | |
TimelineEventRecorded: "TimelineEventRecorded" | |
} | |
WebInspector.TimelineManager.prototype = { | |
/** | |
* @param {number=} maxCallStackDepth | |
*/ | |
start: function(maxCallStackDepth) | |
{ | |
this._enablementCount++; | |
if (this._enablementCount === 1) | |
TimelineAgent.start(maxCallStackDepth, this._started.bind(this)); | |
}, | |
stop: function() | |
{ | |
if (!this._enablementCount) { | |
console.error("WebInspector.TimelineManager start/stop calls are unbalanced"); | |
return; | |
} | |
this._enablementCount--; | |
if (!this._enablementCount) | |
TimelineAgent.stop(this._stopped.bind(this)); | |
}, | |
_started: function() | |
{ | |
this.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStarted); | |
}, | |
_stopped: function() | |
{ | |
this.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineStopped); | |
} | |
} | |
WebInspector.TimelineManager.prototype.__proto__ = WebInspector.Object.prototype; | |
/** | |
* @constructor | |
* @implements {TimelineAgent.Dispatcher} | |
*/ | |
WebInspector.TimelineDispatcher = function(manager) | |
{ | |
this._manager = manager; | |
InspectorBackend.registerTimelineDispatcher(this); | |
} | |
WebInspector.TimelineDispatcher.prototype = { | |
eventRecorded: function(record) | |
{ | |
this._manager.dispatchEventToListeners(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, record); | |
} | |
} | |
/** | |
* @type {WebInspector.TimelineManager} | |
*/ | |
WebInspector.timelineManager; | |
/* UserAgentSupport.js */ | |
/* | |
* Copyright (C) 2012 Google Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are | |
* met: | |
* | |
* * Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* * Redistributions in binary form must reproduce the above | |
* copyright notice, this list of conditions and the following disclaimer | |
* in the documentation and/or other materials provided with the | |
* distribution. | |
* * Neither the name of Google Inc. nor the names of its | |
* contributors may be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
*/ | |
WebInspector.UserAgentSupport = function() | |
{ | |
if (WebInspector.settings.deviceMetrics.get()) | |
this._deviceMetricsChanged(); | |
WebInspector.settings.deviceMetrics.addChangeListener(this._deviceMetricsChanged, this); | |
WebInspector.settings.deviceFitWindow.addChangeListener(this._deviceMetricsChanged, this); | |
WebInspector.settings.geolocationOverride.addChangeListener(this._geolocationPositionChanged, this); | |
WebInspector.settings.deviceOrientationOverride.addChangeListener(this._deviceOrientationChanged, this); | |
} | |
/** | |
* @constructor | |
* @param {number} width | |
* @param {number} height | |
* @param {number} fontScaleFactor | |
*/ | |
WebInspector.UserAgentSupport.DeviceMetrics = function(width, height, fontScaleFactor) | |
{ | |
this.width = width; | |
this.height = height; | |
this.fontScaleFactor = fontScaleFactor; | |
} | |
/** | |
* @return {WebInspector.UserAgentSupport.DeviceMetrics} | |
*/ | |
WebInspector.UserAgentSupport.DeviceMetrics.parseSetting = function(value) | |
{ | |
if (value) { | |
var splitMetrics = value.split("x"); | |
if (splitMetrics.length === 3) | |
return new WebInspector.UserAgentSupport.DeviceMetrics(parseInt(splitMetrics[0], 10), parseInt(splitMetrics[1], 10), parseFloat(splitMetrics[2])); | |
} | |
return new WebInspector.UserAgentSupport.DeviceMetrics(0, 0, 1); | |
} | |
/** | |
* @return {?WebInspector.UserAgentSupport.DeviceMetrics} | |
*/ | |
WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput = function(widthString, heightString, fontScaleFactorString) | |
{ | |
function isUserInputValid(value, isInteger) | |
{ | |
if (!value) | |
return true; | |
return isInteger ? /^[0]*[1-9][\d]*$/.test(value) : /^[0]*([1-9][\d]*(\.\d+)?|\.\d+)$/.test(value); | |
} | |
if (!widthString ^ !heightString) | |
return null; | |
var isWidthValid = isUserInputValid(widthString, true); | |
var isHeightValid = isUserInputValid(heightString, true); | |
var isFontScaleFactorValid = isUserInputValid(fontScaleFactorString, false); | |
if (!isWidthValid && !isHeightValid && !isFontScaleFactorValid) | |
return null; | |
var width = isWidthValid ? parseInt(widthString || "0", 10) : -1; | |
var height = isHeightValid ? parseInt(heightString || "0", 10) : -1; | |
var fontScaleFactor = isFontScaleFactorValid ? parseFloat(fontScaleFactorString) : -1; | |
return new WebInspector.UserAgentSupport.DeviceMetrics(width, height, fontScaleFactor); | |
} | |
WebInspector.UserAgentSupport.DeviceMetrics.prototype = { | |
/** | |
* @return {boolean} | |
*/ | |
isValid: function() | |
{ | |
return this.isWidthValid() && this.isHeightValid() && this.isFontScaleFactorValid(); | |
}, | |
/** | |
* @return {boolean} | |
*/ | |
isWidthValid: function() | |
{ | |
return this.width >= 0; | |
}, | |
/** | |
* @return {boolean} | |
*/ | |
isHeightValid: function() | |
{ | |
return this.height >= 0; | |
}, | |
/** | |
* @return {boolean} | |
*/ | |
isFontScaleFactorValid: function() | |
{ | |
return this.fontScaleFactor > 0; | |
}, | |
/** | |
* @return {string} | |
*/ | |
toSetting: function() | |
{ | |
if (!this.isValid()) | |
return ""; | |
return this.width && this.height ? this.width + "x" + this.height + "x" + this.fontScaleFactor : ""; | |
}, | |
/** | |
* @return {string} | |
*/ | |
widthToInput: function() | |
{ | |
return this.isWidthValid() && this.width ? String(this.width) : ""; | |
}, | |
/** | |
* @return {string} | |
*/ | |
heightToInput: function() | |
{ | |
return this.isHeightValid() && this.height ? String(this.height) : ""; | |
}, | |
/** | |
* @return {string} | |
*/ | |
fontScaleFactorToInput: function() | |
{ | |
return this.isFontScaleFactorValid() && this.fontScaleFactor ? String(this.fontScaleFactor) : ""; | |
} | |
} | |
/** | |
* @constructor | |
* @param {number} latitude | |
* @param {number} longitude | |
*/ | |
WebInspector.UserAgentSupport.GeolocationPosition = function(latitude, longitude, error) | |
{ | |
this.latitude = latitude; | |
this.longitude = longitude; | |
this.error = error; | |
} | |
WebInspector.UserAgentSupport.GeolocationPosition.prototype = { | |
/** | |
* @return {string} | |
*/ | |
toSetting: function() | |
{ | |
return (typeof this.latitude === "number" && typeof this.longitude === "number" && typeof this.error === "string") ? this.latitude + "@" + this.longitude + ":" + this.error : ""; | |
} | |
} | |
/** | |
* @return {WebInspector.UserAgentSupport.GeolocationPosition} | |
*/ | |
WebInspector.UserAgentSupport.GeolocationPosition.parseSetting = function(value) | |
{ | |
if (value) { | |
var splitError = value.split(":"); | |
if (splitError.length === 2) { | |
var splitPosition = splitError[0].split("@") | |
if (splitPosition.length === 2) | |
return new WebInspector.UserAgentSupport.GeolocationPosition(parseFloat(splitPosition[0]), parseFloat(splitPosition[1]), splitError[1]); | |
} | |
} | |
return new WebInspector.UserAgentSupport.GeolocationPosition(0, 0, ""); | |
} | |
/** | |
* @return {?WebInspector.UserAgentSupport.GeolocationPosition} | |
*/ | |
WebInspector.UserAgentSupport.GeolocationPosition.parseUserInput = function(latitudeString, longitudeString, errorStatus) | |
{ | |
function isUserInputValid(value) | |
{ | |
if (!value) | |
return true; | |
return /^[-]?[0-9]*[.]?[0-9]*$/.test(value); | |
} | |
if (!latitudeString ^ !latitudeString) | |
return null; | |
var isLatitudeValid = isUserInputValid(latitudeString); | |
var isLongitudeValid = isUserInputValid(longitudeString); | |
if (!isLatitudeValid && !isLongitudeValid) | |
return null; | |
var latitude = isLatitudeValid ? parseFloat(latitudeString) : -1; | |
var longitude = isLongitudeValid ? parseFloat(longitudeString) : -1; | |
return new WebInspector.UserAgentSupport.GeolocationPosition(latitude, longitude, errorStatus ? "PositionUnavailable" : ""); | |
} | |
WebInspector.UserAgentSupport.GeolocationPosition.clearGeolocationOverride = function() | |
{ | |
PageAgent.clearGeolocationOverride(); | |
} | |
/** | |
* @constructor | |
* @param {number} alpha | |
* @param {number} beta | |
* @param {number} gamma | |
*/ | |
WebInspector.UserAgentSupport.DeviceOrientation = function(alpha, beta, gamma) | |
{ | |
this.alpha = alpha; | |
this.beta = beta; | |
this.gamma = gamma; | |
} | |
WebInspector.UserAgentSupport.DeviceOrientation.prototype = { | |
/** | |
* @return {string} | |
*/ | |
toSetting: function() | |
{ | |
return JSON.stringify(this); | |
} | |
} | |
/** | |
* @return {WebInspector.UserAgentSupport.DeviceOrientation} | |
*/ | |
WebInspector.UserAgentSupport.DeviceOrientation.parseSetting = function(value) | |
{ | |
if (value) { | |
var jsonObject = JSON.parse(value); | |
return new WebInspector.UserAgentSupport.DeviceOrientation(jsonObject.alpha, jsonObject.beta, jsonObject.gamma); | |
} | |
return new WebInspector.UserAgentSupport.DeviceOrientation(0, 0, 0); | |
} | |
/** | |
* @return {?WebInspector.UserAgentSupport.DeviceOrientation} | |
*/ | |
WebInspector.UserAgentSupport.DeviceOrientation.parseUserInput = function(alphaString, betaString, gammaString) | |
{ | |
function isUserInputValid(value) | |
{ | |
if (!value) | |
return true; | |
return /^[-]?[0-9]*[.]?[0-9]*$/.test(value); | |
} | |
if (!alphaString ^ !betaString ^ !gammaString) | |
return null; | |
var isAlphaValid = isUserInputValid(alphaString); | |
var isBetaValid = isUserInputValid(betaString); | |
var isGammaValid = isUserInputValid(gammaString); | |
if (!isAlphaValid && !isBetaValid && !isGammaValid) | |
return null; | |
var alpha = isAlphaValid ? parseFloat(alphaString) : -1; | |
var beta = isBetaValid ? parseFloat(betaString) : -1; | |
var gamma = isGammaValid ? parseFloat(gammaString) : -1; | |
return new WebInspector.UserAgentSupport.DeviceOrientation(alpha, beta, gamma); | |
} | |
WebInspector.UserAgentSupport.DeviceOrientation.clearDeviceOrientationOverride = function() | |
{ | |
PageAgent.clearDeviceOrientationOverride(); | |
} | |
WebInspector.UserAgentSupport.prototype = { | |
_deviceMetricsChanged: function() | |
{ | |
var metrics = WebInspector.UserAgentSupport.DeviceMetrics.parseSetting(WebInspector.settings.deviceMetrics.get()); | |
if (metrics.isValid()) | |
PageAgent.setDeviceMetricsOverride(metrics.width, metrics.height, metrics.fontScaleFactor, WebInspector.settings.deviceFitWindow.get()); | |
}, | |
_geolocationPositionChanged: function() | |
{ | |
var geolocation = WebInspector.UserAgentSupport.GeolocationPosition.parseSetting(WebInspector.settings.geolocationOverride.get()); | |
if (geolocation.error) | |
PageAgent.setGeolocationOverride(); | |
else | |
PageAgent.setGeolocationOverride(geolocation.latitude, geolocation.longitude, 150); | |
}, | |
/** | |
* @param {WebInspector.Event} event | |
*/ | |
_deviceOrientationChanged: function(event) | |
{ | |
var deviceOrientation = WebInspector.UserAgentSupport.DeviceOrientation.parseSetting(WebInspector.settings.deviceOrientationOverride.get()); | |
PageAgent.setDeviceOrientationOverride(deviceOrientation.alpha, deviceOrientation.beta, deviceOrientation.gamma); | |
} | |
} | |
/* Database.js */ | |
/* | |
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
* its contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
* @param {WebInspector.DatabaseModel} model | |
*/ | |
WebInspector.Database = function(model, id, domain, name, version) | |
{ | |
this._model = model; | |
this._id = id; | |
this._domain = domain; | |
this._name = name; | |
this._version = version; | |
} | |
WebInspector.Database.prototype = { | |
/** @return {string} */ | |
get id() | |
{ | |
return this._id; | |
}, | |
/** @return {string} */ | |
get name() | |
{ | |
return this._name; | |
}, | |
set name(x) | |
{ | |
this._name = x; | |
}, | |
/** @return {string} */ | |
get version() | |
{ | |
return this._version; | |
}, | |
set version(x) | |
{ | |
this._version = x; | |
}, | |
/** @return {string} */ | |
get domain() | |
{ | |
return this._domain; | |
}, | |
set domain(x) | |
{ | |
this._domain = x; | |
}, | |
/** | |
* @param {function(Array.<string>)} callback | |
*/ | |
getTableNames: function(callback) | |
{ | |
function sortingCallback(error, names) | |
{ | |
if (!error) | |
callback(names.sort()); | |
} | |
DatabaseAgent.getDatabaseTableNames(this._id, sortingCallback); | |
}, | |
/** | |
* @param {string} query | |
* @param {function(Array.<string>=, Array.<*>=)} onSuccess | |
* @param {function(string)} onError | |
*/ | |
executeSql: function(query, onSuccess, onError) | |
{ | |
/** | |
* @param {?Protocol.Error} error | |
* @param {Array.<string>=} columnNames | |
* @param {Array.<*>=} values | |
* @param {DatabaseAgent.Error=} errorObj | |
*/ | |
function callback(error, columnNames, values, errorObj) | |
{ | |
if (error) { | |
onError(error); | |
return; | |
} | |
if (errorObj) { | |
var message; | |
if (errorObj.message) | |
message = errorObj.message; | |
else if (errorObj.code == 2) | |
message = WebInspector.UIString("Database no longer has expected version."); | |
else | |
message = WebInspector.UIString("An unexpected error %s occurred.", errorObj.code); | |
onError(message); | |
return; | |
} | |
onSuccess(columnNames, values); | |
} | |
DatabaseAgent.executeSQL(this._id, query, callback.bind(this)); | |
} | |
} | |
/** | |
* @constructor | |
* @extends {WebInspector.Object} | |
*/ | |
WebInspector.DatabaseModel = function() | |
{ | |
this._databases = []; | |
InspectorBackend.registerDatabaseDispatcher(new WebInspector.DatabaseDispatcher(this)); | |
DatabaseAgent.enable(); | |
} | |
WebInspector.DatabaseModel.Events = { | |
DatabaseAdded: "DatabaseAdded" | |
} | |
WebInspector.DatabaseModel.prototype = { | |
/** | |
* @return {Array.<WebInspector.Database>} | |
*/ | |
databases: function() | |
{ | |
var result = []; | |
for (var databaseId in this._databases) | |
result.push(this._databases[databaseId]); | |
return result; | |
}, | |
/** | |
* @param {DatabaseAgent.DatabaseId} databaseId | |
* @return {WebInspector.Database} | |
*/ | |
databaseForId: function(databaseId) | |
{ | |
return this._databases[databaseId]; | |
}, | |
/** | |
* @param {WebInspector.Database} database | |
*/ | |
_addDatabase: function(database) | |
{ | |
this._databases.push(database); | |
this.dispatchEventToListeners(WebInspector.DatabaseModel.Events.DatabaseAdded, database); | |
} | |
} | |
WebInspector.DatabaseModel.prototype.__proto__ = WebInspector.Object.prototype; | |
/** | |
* @constructor | |
* @implements {DatabaseAgent.Dispatcher} | |
* @param {WebInspector.DatabaseModel} model | |
*/ | |
WebInspector.DatabaseDispatcher = function(model) | |
{ | |
this._model = model; | |
} | |
WebInspector.DatabaseDispatcher.prototype = { | |
/** | |
* @param {DatabaseAgent.Database} payload | |
*/ | |
addDatabase: function(payload) | |
{ | |
this._model._addDatabase(new WebInspector.Database( | |
this._model, | |
payload.id, | |
payload.domain, | |
payload.name, | |
payload.version)); | |
} | |
} | |
/** | |
* @type {WebInspector.DatabaseModel} | |
*/ | |
WebInspector.databaseModel = null; | |
/* DOMStorage.js */ | |
/* | |
* Copyright (C) 2008 Nokia Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
* its contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
*/ | |
WebInspector.DOMStorage = function(id, domain, isLocalStorage) | |
{ | |
this._id = id; | |
this._domain = domain; | |
this._isLocalStorage = isLocalStorage; | |
} | |
WebInspector.DOMStorage.prototype = { | |
/** @return {string} */ | |
get id() | |
{ | |
return this._id; | |
}, | |
/** @return {string} */ | |
get domain() | |
{ | |
return this._domain; | |
}, | |
/** @return {boolean} */ | |
get isLocalStorage() | |
{ | |
return this._isLocalStorage; | |
}, | |
/** | |
* @param {function(?Protocol.Error, Array.<DOMStorageAgent.Entry>):void=} callback | |
*/ | |
getEntries: function(callback) | |
{ | |
DOMStorageAgent.getDOMStorageEntries(this._id, callback); | |
}, | |
/** | |
* @param {string} key | |
* @param {string} value | |
* @param {function(?Protocol.Error, boolean):void=} callback | |
*/ | |
setItem: function(key, value, callback) | |
{ | |
DOMStorageAgent.setDOMStorageItem(this._id, key, value, callback); | |
}, | |
/** | |
* @param {string} key | |
* @param {function(?Protocol.Error, boolean):void=} callback | |
*/ | |
removeItem: function(key, callback) | |
{ | |
DOMStorageAgent.removeDOMStorageItem(this._id, key, callback); | |
} | |
} | |
/** | |
* @constructor | |
* @extends {WebInspector.Object} | |
*/ | |
WebInspector.DOMStorageModel = function() | |
{ | |
this._storages = {}; | |
InspectorBackend.registerDOMStorageDispatcher(new WebInspector.DOMStorageDispatcher(this)); | |
DOMStorageAgent.enable(); | |
} | |
WebInspector.DOMStorageModel.Events = { | |
DOMStorageAdded: "DOMStorageAdded", | |
DOMStorageUpdated: "DOMStorageUpdated" | |
} | |
WebInspector.DOMStorageModel.prototype = { | |
/** | |
* @param {WebInspector.DOMStorage} domStorage | |
*/ | |
_addDOMStorage: function(domStorage) | |
{ | |
this._storages[domStorage.id] = domStorage; | |
this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageAdded, domStorage); | |
}, | |
/** | |
* @param {DOMStorageAgent.StorageId} storageId | |
*/ | |
_domStorageUpdated: function(storageId) | |
{ | |
this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageUpdated, this._storages[storageId]); | |
}, | |
/** | |
* @param {DOMStorageAgent.StorageId} storageId | |
* @return {WebInspector.DOMStorage} | |
*/ | |
storageForId: function(storageId) | |
{ | |
return this._storages[storageId]; | |
}, | |
/** | |
* @return {Array.<WebInspector.DOMStorage>} | |
*/ | |
storages: function() | |
{ | |
var result = []; | |
for (var storageId in this._storages) | |
result.push(this._storages[storageId]); | |
return result; | |
} | |
} | |
WebInspector.DOMStorageModel.prototype.__proto__ = WebInspector.Object.prototype; | |
/** | |
* @constructor | |
* @implements {DOMStorageAgent.Dispatcher} | |
* @param {WebInspector.DOMStorageModel} model | |
*/ | |
WebInspector.DOMStorageDispatcher = function(model) | |
{ | |
this._model = model; | |
} | |
WebInspector.DOMStorageDispatcher.prototype = { | |
/** | |
* @param {DOMStorageAgent.Entry} payload | |
*/ | |
addDOMStorage: function(payload) | |
{ | |
this._model._addDOMStorage(new WebInspector.DOMStorage( | |
payload.id, | |
payload.origin, | |
payload.isLocalStorage)); | |
}, | |
/** | |
* @param {string} storageId | |
*/ | |
domStorageUpdated: function(storageId) | |
{ | |
this._model._domStorageUpdated(storageId); | |
} | |
} | |
/** | |
* @type {WebInspector.DOMStorageModel} | |
*/ | |
WebInspector.domStorageModel = null; | |
/* DataGrid.js */ | |
/* | |
* Copyright (C) 2008 Apple Inc. All Rights Reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/** | |
* @constructor | |
* @extends {WebInspector.View} | |
* @param {function(WebInspector.DataGridNode, number, string, string)=} editCallback | |
* @param {function(WebInspector.DataGridNode)=} deleteCallback | |
*/ | |
WebInspector.DataGrid = function(columns, editCallback, deleteCallback) | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("dataGrid.css"); | |
this.element.className = "data-grid"; | |
this.element.tabIndex = 0; | |
this.element.addEventListener("keydown", this._keyDown.bind(this), false); | |
this._headerTable = document.createElement("table"); | |
this._headerTable.className = "header"; | |
this._headerTableHeaders = {}; | |
this._dataTable = document.createElement("table"); | |
this._dataTable.className = "data"; | |
this._dataTable.addEventListener("mousedown", this._mouseDownInDataTable.bind(this), true); | |
this._dataTable.addEventListener("click", this._clickInDataTable.bind(this), true); | |
this._dataTable.addEventListener("contextmenu", this._contextMenuInDataTable.bind(this), true); | |
// FIXME: Add a createCallback which is different from editCallback and has different | |
// behavior when creating a new node. | |
if (editCallback) { | |
this._dataTable.addEventListener("dblclick", this._ondblclick.bind(this), false); | |
this._editCallback = editCallback; | |
} | |
if (deleteCallback) | |
this._deleteCallback = deleteCallback; | |
this.aligned = {}; | |
this._scrollContainer = document.createElement("div"); | |
this._scrollContainer.className = "data-container"; | |
this._scrollContainer.appendChild(this._dataTable); | |
this.element.appendChild(this._headerTable); | |
this.element.appendChild(this._scrollContainer); | |
var headerRow = document.createElement("tr"); | |
var columnGroup = document.createElement("colgroup"); | |
this._columnCount = 0; | |
for (var columnIdentifier in columns) { | |
var column = columns[columnIdentifier]; | |
if (column.disclosure) | |
this.disclosureColumnIdentifier = columnIdentifier; | |
var col = document.createElement("col"); | |
if (column.width) | |
col.style.width = column.width; | |
column.element = col; | |
columnGroup.appendChild(col); | |
var cell = document.createElement("th"); | |
cell.className = columnIdentifier + "-column"; | |
cell.columnIdentifier = columnIdentifier; | |
this._headerTableHeaders[columnIdentifier] = cell; | |
var div = document.createElement("div"); | |
if (column.titleDOMFragment) | |
div.appendChild(column.titleDOMFragment); | |
else | |
div.textContent = column.title; | |
cell.appendChild(div); | |
if (column.sort) { | |
cell.addStyleClass("sort-" + column.sort); | |
this._sortColumnCell = cell; | |
} | |
if (column.sortable) { | |
cell.addEventListener("click", this._clickInHeaderCell.bind(this), false); | |
cell.addStyleClass("sortable"); | |
} | |
if (column.aligned) | |
this.aligned[columnIdentifier] = column.aligned; | |
headerRow.appendChild(cell); | |
++this._columnCount; | |
} | |
columnGroup.span = this._columnCount; | |
var cell = document.createElement("th"); | |
cell.className = "corner"; | |
headerRow.appendChild(cell); | |
this._headerTableColumnGroup = columnGroup; | |
this._headerTable.appendChild(this._headerTableColumnGroup); | |
this.headerTableBody.appendChild(headerRow); | |
var fillerRow = document.createElement("tr"); | |
fillerRow.className = "filler"; | |
for (var columnIdentifier in columns) { | |
var column = columns[columnIdentifier]; | |
var td = document.createElement("td"); | |
td.className = columnIdentifier + "-column"; | |
fillerRow.appendChild(td); | |
} | |
this._dataTableColumnGroup = columnGroup.cloneNode(true); | |
this._dataTable.appendChild(this._dataTableColumnGroup); | |
this.dataTableBody.appendChild(fillerRow); | |
this.columns = columns || {}; | |
this._columnsArray = []; | |
for (var columnIdentifier in columns) { | |
columns[columnIdentifier].ordinal = this._columnsArray.length; | |
columns[columnIdentifier].identifier = columnIdentifier; | |
this._columnsArray.push(columns[columnIdentifier]); | |
} | |
for (var i = 0; i < this._columnsArray.length; ++i) | |
this._columnsArray[i].bodyElement = this._dataTableColumnGroup.children[i]; | |
this.selectedNode = null; | |
this.expandNodesWhenArrowing = false; | |
this.setRootNode(new WebInspector.DataGridNode()); | |
this.indentWidth = 15; | |
this.resizers = []; | |
this._columnWidthsInitialized = false; | |
} | |
WebInspector.DataGrid.Events = { | |
SelectedNode: "SelectedNode", | |
DeselectedNode: "DeselectedNode" | |
} | |
/** | |
* @param {Array.<string>} columnNames | |
* @param {Array.<string>} values | |
*/ | |
WebInspector.DataGrid.createSortableDataGrid = function(columnNames, values) | |
{ | |
var numColumns = columnNames.length; | |
if (!numColumns) | |
return null; | |
var columns = {}; | |
for (var i = 0; i < columnNames.length; ++i) { | |
var column = {}; | |
column.width = columnNames[i].length; | |
column.title = columnNames[i]; | |
column.sortable = true; | |
columns[columnNames[i]] = column; | |
} | |
var nodes = []; | |
for (var i = 0; i < values.length / numColumns; ++i) { | |
var data = {}; | |
for (var j = 0; j < columnNames.length; ++j) | |
data[columnNames[j]] = values[numColumns * i + j]; | |
var node = new WebInspector.DataGridNode(data, false); | |
node.selectable = false; | |
nodes.push(node); | |
} | |
var dataGrid = new WebInspector.DataGrid(columns); | |
var length = nodes.length; | |
for (var i = 0; i < length; ++i) | |
dataGrid.rootNode().appendChild(nodes[i]); | |
dataGrid.addEventListener("sorting changed", sortDataGrid, this); | |
function sortDataGrid() | |
{ | |
var nodes = dataGrid._rootNode.children.slice(); | |
var sortColumnIdentifier = dataGrid.sortColumnIdentifier; | |
var sortDirection = dataGrid.sortOrder === "ascending" ? 1 : -1; | |
var columnIsNumeric = true; | |
for (var i = 0; i < nodes.length; i++) { | |
if (isNaN(Number(nodes[i].data[sortColumnIdentifier]))) | |
columnIsNumeric = false; | |
} | |
function comparator(dataGridNode1, dataGridNode2) | |
{ | |
var item1 = dataGridNode1.data[sortColumnIdentifier]; | |
var item2 = dataGridNode2.data[sortColumnIdentifier]; | |
var comparison; | |
if (columnIsNumeric) { | |
// Sort numbers based on comparing their values rather than a lexicographical comparison. | |
var number1 = parseFloat(item1); | |
var number2 = parseFloat(item2); | |
comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0); | |
} else | |
comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0); | |
return sortDirection * comparison; | |
} | |
nodes.sort(comparator); | |
dataGrid.rootNode().removeChildren(); | |
for (var i = 0; i < nodes.length; i++) | |
dataGrid._rootNode.appendChild(nodes[i]); | |
} | |
return dataGrid; | |
} | |
WebInspector.DataGrid.prototype = { | |
setRootNode: function(rootNode) | |
{ | |
if (this._rootNode) { | |
this._rootNode.removeChildren(); | |
this._rootNode.dataGrid = null; | |
this._rootNode._isRoot = false; | |
} | |
this._rootNode = rootNode; | |
rootNode._isRoot = true; | |
rootNode.hasChildren = false; | |
rootNode._expanded = true; | |
rootNode._revealed = true; | |
rootNode.dataGrid = this; | |
}, | |
rootNode: function() | |
{ | |
return this._rootNode; | |
}, | |
get refreshCallback() | |
{ | |
return this._refreshCallback; | |
}, | |
set refreshCallback(refreshCallback) | |
{ | |
this._refreshCallback = refreshCallback; | |
}, | |
_ondblclick: function(event) | |
{ | |
if (this._editing || this._editingNode) | |
return; | |
this._startEditing(event.target); | |
}, | |
_startEditingColumnOfDataGridNode: function(node, column) | |
{ | |
this._editing = true; | |
this._editingNode = node; | |
this._editingNode.select(); | |
var element = this._editingNode._element.children[column]; | |
WebInspector.startEditing(element, this._startEditingConfig(element)); | |
window.getSelection().setBaseAndExtent(element, 0, element, 1); | |
}, | |
_startEditing: function(target) | |
{ | |
var element = target.enclosingNodeOrSelfWithNodeName("td"); | |
if (!element) | |
return; | |
this._editingNode = this.dataGridNodeFromNode(target); | |
if (!this._editingNode) { | |
if (!this.creationNode) | |
return; | |
this._editingNode = this.creationNode; | |
} | |
// Force editing the 1st column when editing the creation node | |
if (this._editingNode.isCreationNode) | |
return this._startEditingColumnOfDataGridNode(this._editingNode, 0); | |
this._editing = true; | |
WebInspector.startEditing(element, this._startEditingConfig(element)); | |
window.getSelection().setBaseAndExtent(element, 0, element, 1); | |
}, | |
_startEditingConfig: function(element) | |
{ | |
return new WebInspector.EditingConfig(this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent); | |
}, | |
_editingCommitted: function(element, newText, oldText, context, moveDirection) | |
{ | |
// FIXME: We need more column identifiers here throughout this function. | |
// Not needed yet since only editable DataGrid is DOM Storage, which is Key - Value. | |
// FIXME: Better way to do this than regular expressions? | |
var columnIdentifier = parseInt(element.className.match(/\b(\d+)-column\b/)[1], 10); | |
var textBeforeEditing = this._editingNode.data[columnIdentifier]; | |
var currentEditingNode = this._editingNode; | |
function moveToNextIfNeeded(wasChange) { | |
if (!moveDirection) | |
return; | |
if (moveDirection === "forward") { | |
if (currentEditingNode.isCreationNode && columnIdentifier === 0 && !wasChange) | |
return; | |
if (columnIdentifier === 0) | |
return this._startEditingColumnOfDataGridNode(currentEditingNode, 1); | |
var nextDataGridNode = currentEditingNode.traverseNextNode(true, null, true); | |
if (nextDataGridNode) | |
return this._startEditingColumnOfDataGridNode(nextDataGridNode, 0); | |
if (currentEditingNode.isCreationNode && wasChange) { | |
this.addCreationNode(false); | |
return this._startEditingColumnOfDataGridNode(this.creationNode, 0); | |
} | |
return; | |
} | |
if (moveDirection === "backward") { | |
if (columnIdentifier === 1) | |
return this._startEditingColumnOfDataGridNode(currentEditingNode, 0); | |
var nextDataGridNode = currentEditingNode.traversePreviousNode(true, null, true); | |
if (nextDataGridNode) | |
return this._startEditingColumnOfDataGridNode(nextDataGridNode, 1); | |
return; | |
} | |
} | |
if (textBeforeEditing == newText) { | |
this._editingCancelled(element); | |
moveToNextIfNeeded.call(this, false); | |
return; | |
} | |
// Update the text in the datagrid that we typed | |
this._editingNode.data[columnIdentifier] = newText; | |
// Make the callback - expects an editing node (table row), the column number that is being edited, | |
// the text that used to be there, and the new text. | |
this._editCallback(this._editingNode, columnIdentifier, textBeforeEditing, newText); | |
if (this._editingNode.isCreationNode) | |
this.addCreationNode(false); | |
this._editingCancelled(element); | |
moveToNextIfNeeded.call(this, true); | |
}, | |
_editingCancelled: function(element) | |
{ | |
delete this._editing; | |
this._editingNode = null; | |
}, | |
/** | |
* @return {?string} | |
*/ | |
get sortColumnIdentifier() | |
{ | |
if (!this._sortColumnCell) | |
return null; | |
return this._sortColumnCell.columnIdentifier; | |
}, | |
/** | |
* @return {?string} | |
*/ | |
get sortOrder() | |
{ | |
if (!this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending")) | |
return "ascending"; | |
if (this._sortColumnCell.hasStyleClass("sort-descending")) | |
return "descending"; | |
return null; | |
}, | |
get headerTableBody() | |
{ | |
if ("_headerTableBody" in this) | |
return this._headerTableBody; | |
this._headerTableBody = this._headerTable.getElementsByTagName("tbody")[0]; | |
if (!this._headerTableBody) { | |
this._headerTableBody = this.element.ownerDocument.createElement("tbody"); | |
this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot); | |
} | |
return this._headerTableBody; | |
}, | |
get dataTableBody() | |
{ | |
if ("_dataTableBody" in this) | |
return this._dataTableBody; | |
this._dataTableBody = this._dataTable.getElementsByTagName("tbody")[0]; | |
if (!this._dataTableBody) { | |
this._dataTableBody = this.element.ownerDocument.createElement("tbody"); | |
this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot); | |
} | |
return this._dataTableBody; | |
}, | |
/** | |
* @param {number=} maxDescentLevel | |
*/ | |
autoSizeColumns: function(minPercent, maxPercent, maxDescentLevel) | |
{ | |
if (minPercent) | |
minPercent = Math.min(minPercent, Math.floor(100 / this._columnCount)); | |
var widths = {}; | |
var columns = this.columns; | |
for (var columnIdentifier in columns) | |
widths[columnIdentifier] = (columns[columnIdentifier].title || "").length; | |
maxDescentLevel = maxDescentLevel || 0; | |
var children = this._enumerateChildren(this._rootNode, [], maxDescentLevel + 1); | |
for (var i = 0; i < children.length; ++i) { | |
var node = children[i]; | |
for (var columnIdentifier in columns) { | |
var text = node.data[columnIdentifier] || ""; | |
if (text.length > widths[columnIdentifier]) | |
widths[columnIdentifier] = text.length; | |
} | |
} | |
var totalColumnWidths = 0; | |
for (var columnIdentifier in columns) | |
totalColumnWidths += widths[columnIdentifier]; | |
var recoupPercent = 0; | |
for (var columnIdentifier in columns) { | |
var width = Math.round(100 * widths[columnIdentifier] / totalColumnWidths); | |
if (minPercent && width < minPercent) { | |
recoupPercent += (minPercent - width); | |
width = minPercent; | |
} else if (maxPercent && width > maxPercent) { | |
recoupPercent -= (width - maxPercent); | |
width = maxPercent; | |
} | |
widths[columnIdentifier] = width; | |
} | |
while (minPercent && recoupPercent > 0) { | |
for (var columnIdentifier in columns) { | |
if (widths[columnIdentifier] > minPercent) { | |
--widths[columnIdentifier]; | |
--recoupPercent; | |
if (!recoupPercent) | |
break; | |
} | |
} | |
} | |
while (maxPercent && recoupPercent < 0) { | |
for (var columnIdentifier in columns) { | |
if (widths[columnIdentifier] < maxPercent) { | |
++widths[columnIdentifier]; | |
++recoupPercent; | |
if (!recoupPercent) | |
break; | |
} | |
} | |
} | |
for (var columnIdentifier in columns) | |
columns[columnIdentifier].element.style.width = widths[columnIdentifier] + "%"; | |
this._columnWidthsInitialized = false; | |
this.updateWidths(); | |
}, | |
_enumerateChildren: function(rootNode, result, maxLevel) | |
{ | |
if (!rootNode._isRoot) | |
result.push(rootNode); | |
if (!maxLevel) | |
return; | |
for (var i = 0; i < rootNode.children.length; ++i) | |
this._enumerateChildren(rootNode.children[i], result, maxLevel - 1); | |
return result; | |
}, | |
onResize: function() | |
{ | |
this.updateWidths(); | |
}, | |
// Updates the widths of the table, including the positions of the column | |
// resizers. | |
// | |
// IMPORTANT: This function MUST be called once after the element of the | |
// DataGrid is attached to its parent element and every subsequent time the | |
// width of the parent element is changed in order to make it possible to | |
// resize the columns. | |
// | |
// If this function is not called after the DataGrid is attached to its | |
// parent element, then the DataGrid's columns will not be resizable. | |
updateWidths: function() | |
{ | |
var headerTableColumns = this._headerTableColumnGroup.children; | |
var tableWidth = this._dataTable.offsetWidth; | |
var numColumns = headerTableColumns.length; | |
if (!this._columnWidthsInitialized && this.element.offsetWidth) { | |
for (var i = 0; i < numColumns; i++) { | |
var columnWidth = this.headerTableBody.rows[0].cells[i].offsetWidth; | |
var percentWidth = ((columnWidth / tableWidth) * 100) + "%"; | |
this._headerTableColumnGroup.children[i].style.width = percentWidth; | |
this._dataTableColumnGroup.children[i].style.width = percentWidth; | |
} | |
this._columnWidthsInitialized = true; | |
} | |
this._positionResizers(); | |
this.dispatchEventToListeners("width changed"); | |
}, | |
columnWidthsMap: function() | |
{ | |
var result = {}; | |
for (var i = 0; i < this._columnsArray.length; ++i) { | |
var width = this._headerTableColumnGroup.children[i].style.width; | |
result[this._columnsArray[i].columnIdentifier] = parseFloat(width); | |
} | |
return result; | |
}, | |
applyColumnWidthsMap: function(columnWidthsMap) | |
{ | |
for (var columnIdentifier in this.columns) { | |
var column = this.columns[columnIdentifier]; | |
var width = (columnWidthsMap[columnIdentifier] || 0) + "%"; | |
this._headerTableColumnGroup.children[column.ordinal].style.width = width; | |
this._dataTableColumnGroup.children[column.ordinal].style.width = width; | |
} | |
delete this._columnWidthsInitialized; | |
this.updateWidths(); | |
}, | |
isColumnVisible: function(columnIdentifier) | |
{ | |
var column = this.columns[columnIdentifier]; | |
var columnElement = column.element; | |
return !columnElement.hidden; | |
}, | |
showColumn: function(columnIdentifier) | |
{ | |
var column = this.columns[columnIdentifier]; | |
var columnElement = column.element; | |
if (!columnElement.hidden) | |
return; | |
columnElement.hidden = false; | |
columnElement.removeStyleClass("hidden"); | |
var columnBodyElement = column.bodyElement; | |
columnBodyElement.hidden = false; | |
columnBodyElement.removeStyleClass("hidden"); | |
}, | |
hideColumn: function(columnIdentifier) | |
{ | |
var column = this.columns[columnIdentifier]; | |
var columnElement = column.element; | |
if (columnElement.hidden) | |
return; | |
var oldWidth = parseFloat(columnElement.style.width); | |
columnElement.hidden = true; | |
columnElement.addStyleClass("hidden"); | |
columnElement.style.width = 0; | |
var columnBodyElement = column.bodyElement; | |
columnBodyElement.hidden = true; | |
columnBodyElement.addStyleClass("hidden"); | |
columnBodyElement.style.width = 0; | |
this._columnWidthsInitialized = false; | |
}, | |
get scrollContainer() | |
{ | |
return this._scrollContainer; | |
}, | |
isScrolledToLastRow: function() | |
{ | |
return this._scrollContainer.isScrolledToBottom(); | |
}, | |
scrollToLastRow: function() | |
{ | |
this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.offsetHeight; | |
}, | |
_positionResizers: function() | |
{ | |
var headerTableColumns = this._headerTableColumnGroup.children; | |
var numColumns = headerTableColumns.length; | |
var left = 0; | |
var previousResizer = null; | |
for (var i = 0; i < numColumns - 1; i++) { | |
var resizer = this.resizers[i]; | |
if (!resizer) { | |
resizer = document.createElement("div"); | |
resizer.addStyleClass("data-grid-resizer"); | |
WebInspector.installDragHandle(resizer, this._startResizerDragging.bind(this), this._resizerDragging.bind(this), this._endResizerDragging.bind(this), "col-resize"); | |
this.element.appendChild(resizer); | |
this.resizers[i] = resizer; | |
} | |
left += this.headerTableBody.rows[0].cells[i].offsetWidth; | |
var columnIsVisible = !this._headerTableColumnGroup.children[i].hidden; | |
if (columnIsVisible) { | |
resizer.style.removeProperty("display"); | |
resizer.style.left = left + "px"; | |
resizer.leftNeighboringColumnID = i; | |
if (previousResizer) | |
previousResizer.rightNeighboringColumnID = i; | |
previousResizer = resizer; | |
} else { | |
resizer.style.setProperty("display", "none"); | |
resizer.leftNeighboringColumnID = 0; | |
resizer.rightNeighboringColumnID = 0; | |
} | |
} | |
if (previousResizer) | |
previousResizer.rightNeighboringColumnID = numColumns - 1; | |
}, | |
addCreationNode: function(hasChildren) | |
{ | |
if (this.creationNode) | |
this.creationNode.makeNormal(); | |
var emptyData = {}; | |
for (var column in this.columns) | |
emptyData[column] = ''; | |
this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren); | |
this.rootNode().appendChild(this.creationNode); | |
}, | |
sortNodes: function(comparator, reverseMode) | |
{ | |
function comparatorWrapper(a, b) | |
{ | |
if (a._dataGridNode._data.summaryRow) | |
return 1; | |
if (b._dataGridNode._data.summaryRow) | |
return -1; | |
var aDataGirdNode = a._dataGridNode; | |
var bDataGirdNode = b._dataGridNode; | |
return reverseMode ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode); | |
} | |
var tbody = this.dataTableBody; | |
var tbodyParent = tbody.parentElement; | |
tbodyParent.removeChild(tbody); | |
var childNodes = tbody.childNodes; | |
var fillerRow = childNodes[childNodes.length - 1]; | |
var sortedRows = Array.prototype.slice.call(childNodes, 0, childNodes.length - 1); | |
sortedRows.sort(comparatorWrapper); | |
var sortedRowsLength = sortedRows.length; | |
tbody.removeChildren(); | |
var previousSiblingNode = null; | |
for (var i = 0; i < sortedRowsLength; ++i) { | |
var row = sortedRows[i]; | |
var node = row._dataGridNode; | |
node.previousSibling = previousSiblingNode; | |
if (previousSiblingNode) | |
previousSiblingNode.nextSibling = node; | |
tbody.appendChild(row); | |
previousSiblingNode = node; | |
} | |
if (previousSiblingNode) | |
previousSiblingNode.nextSibling = null; | |
tbody.appendChild(fillerRow); | |
tbodyParent.appendChild(tbody); | |
}, | |
_keyDown: function(event) | |
{ | |
if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing) | |
return; | |
var handled = false; | |
var nextSelectedNode; | |
if (event.keyIdentifier === "Up" && !event.altKey) { | |
nextSelectedNode = this.selectedNode.traversePreviousNode(true); | |
while (nextSelectedNode && !nextSelectedNode.selectable) | |
nextSelectedNode = nextSelectedNode.traversePreviousNode(true); | |
handled = nextSelectedNode ? true : false; | |
} else if (event.keyIdentifier === "Down" && !event.altKey) { | |
nextSelectedNode = this.selectedNode.traverseNextNode(true); | |
while (nextSelectedNode && !nextSelectedNode.selectable) | |
nextSelectedNode = nextSelectedNode.traverseNextNode(true); | |
handled = nextSelectedNode ? true : false; | |
} else if (event.keyIdentifier === "Left") { | |
if (this.selectedNode.expanded) { | |
if (event.altKey) | |
this.selectedNode.collapseRecursively(); | |
else | |
this.selectedNode.collapse(); | |
handled = true; | |
} else if (this.selectedNode.parent && !this.selectedNode.parent._isRoot) { | |
handled = true; | |
if (this.selectedNode.parent.selectable) { | |
nextSelectedNode = this.selectedNode.parent; | |
handled = nextSelectedNode ? true : false; | |
} else if (this.selectedNode.parent) | |
this.selectedNode.parent.collapse(); | |
} | |
} else if (event.keyIdentifier === "Right") { | |
if (!this.selectedNode.revealed) { | |
this.selectedNode.reveal(); | |
handled = true; | |
} else if (this.selectedNode.hasChildren) { | |
handled = true; | |
if (this.selectedNode.expanded) { | |
nextSelectedNode = this.selectedNode.children[0]; | |
handled = nextSelectedNode ? true : false; | |
} else { | |
if (event.altKey) | |
this.selectedNode.expandRecursively(); | |
else | |
this.selectedNode.expand(); | |
} | |
} | |
} else if (event.keyCode === 8 || event.keyCode === 46) { | |
if (this._deleteCallback) { | |
handled = true; | |
this._deleteCallback(this.selectedNode); | |
} | |
} else if (isEnterKey(event)) { | |
if (this._editCallback) { | |
handled = true; | |
this._startEditing(this.selectedNode._element.children[0]); | |
} | |
} | |
if (nextSelectedNode) { | |
nextSelectedNode.reveal(); | |
nextSelectedNode.select(); | |
} | |
if (handled) | |
event.consume(true); | |
}, | |
dataGridNodeFromNode: function(target) | |
{ | |
var rowElement = target.enclosingNodeOrSelfWithNodeName("tr"); | |
return rowElement && rowElement._dataGridNode; | |
}, | |
dataGridNodeFromPoint: function(x, y) | |
{ | |
var node = this._dataTable.ownerDocument.elementFromPoint(x, y); | |
var rowElement = node.enclosingNodeOrSelfWithNodeName("tr"); | |
return rowElement && rowElement._dataGridNode; | |
}, | |
_clickInHeaderCell: function(event) | |
{ | |
var cell = event.target.enclosingNodeOrSelfWithNodeName("th"); | |
if (!cell || !cell.columnIdentifier || !cell.hasStyleClass("sortable")) | |
return; | |
var sortOrder = this.sortOrder; | |
if (this._sortColumnCell) | |
this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+"); | |
if (cell == this._sortColumnCell) { | |
if (sortOrder === "ascending") | |
sortOrder = "descending"; | |
else | |
sortOrder = "ascending"; | |
} | |
this._sortColumnCell = cell; | |
cell.addStyleClass("sort-" + sortOrder); | |
this.dispatchEventToListeners("sorting changed"); | |
}, | |
markColumnAsSortedBy: function(columnIdentifier, sortOrder) | |
{ | |
if (this._sortColumnCell) | |
this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+"); | |
this._sortColumnCell = this._headerTableHeaders[columnIdentifier]; | |
this._sortColumnCell.addStyleClass("sort-" + sortOrder); | |
}, | |
headerTableHeader: function(columnIdentifier) | |
{ | |
return this._headerTableHeaders[columnIdentifier]; | |
}, | |
_mouseDownInDataTable: function(event) | |
{ | |
var gridNode = this.dataGridNodeFromNode(event.target); | |
if (!gridNode || !gridNode.selectable) | |
return; | |
if (gridNode.isEventWithinDisclosureTriangle(event)) | |
return; | |
if (event.metaKey) { | |
if (gridNode.selected) | |
gridNode.deselect(); | |
else | |
gridNode.select(); | |
} else | |
gridNode.select(); | |
}, | |
_contextMenuInDataTable: function(event) | |
{ | |
var contextMenu = new WebInspector.ContextMenu(); | |
var gridNode = this.dataGridNodeFromNode(event.target); | |
if (this._refreshCallback && (!gridNode || gridNode !== this.creationNode)) | |
contextMenu.appendItem(WebInspector.UIString("Refresh"), this._refreshCallback.bind(this)); | |
if (gridNode && gridNode.selectable && !gridNode.isEventWithinDisclosureTriangle(event)) { | |
if (this._editCallback) { | |
if (gridNode === this.creationNode) | |
contextMenu.appendItem(WebInspector.UIString("Add New"), this._startEditing.bind(this, event.target)); | |
else | |
contextMenu.appendItem(WebInspector.UIString("Edit"), this._startEditing.bind(this, event.target)); | |
} | |
if (this._deleteCallback && gridNode !== this.creationNode) | |
contextMenu.appendItem(WebInspector.UIString("Delete"), this._deleteCallback.bind(this, gridNode)); | |
} | |
contextMenu.show(event); | |
}, | |
_clickInDataTable: function(event) | |
{ | |
var gridNode = this.dataGridNodeFromNode(event.target); | |
if (!gridNode || !gridNode.hasChildren) | |
return; | |
if (!gridNode.isEventWithinDisclosureTriangle(event)) | |
return; | |
if (gridNode.expanded) { | |
if (event.altKey) | |
gridNode.collapseRecursively(); | |
else | |
gridNode.collapse(); | |
} else { | |
if (event.altKey) | |
gridNode.expandRecursively(); | |
else | |
gridNode.expand(); | |
} | |
}, | |
get resizeMethod() | |
{ | |
if (typeof this._resizeMethod === "undefined") | |
return WebInspector.DataGrid.ResizeMethod.Nearest; | |
return this._resizeMethod; | |
}, | |
set resizeMethod(method) | |
{ | |
this._resizeMethod = method; | |
}, | |
_startResizerDragging: function(event) | |
{ | |
this._currentResizer = event.target; | |
return !!this._currentResizer.rightNeighboringColumnID | |
}, | |
_resizerDragging: function(event) | |
{ | |
var resizer = this._currentResizer; | |
if (!resizer) | |
return; | |
var dragPoint = event.clientX - this.element.totalOffsetLeft(); | |
var leftCellIndex = resizer.leftNeighboringColumnID; | |
var rightCellIndex = resizer.rightNeighboringColumnID; | |
var firstRowCells = this.headerTableBody.rows[0].cells; | |
var leftEdgeOfPreviousColumn = 0; | |
for (var i = 0; i < leftCellIndex; i++) | |
leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth; | |
if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.Last) { | |
rightCellIndex = this.resizers.length; | |
} else if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.First) { | |
leftEdgeOfPreviousColumn += firstRowCells[leftCellIndex].offsetWidth - firstRowCells[0].offsetWidth; | |
leftCellIndex = 0; | |
} | |
var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[leftCellIndex].offsetWidth + firstRowCells[rightCellIndex].offsetWidth; | |
var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding; | |
var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding; | |
dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum); | |
resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px"; | |
var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + "%"; | |
this._headerTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn; | |
this._dataTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn; | |
var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + "%"; | |
this._headerTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn; | |
this._dataTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn; | |
this._positionResizers(); | |
event.preventDefault(); | |
this.dispatchEventToListeners("width changed"); | |
}, | |
_endResizerDragging: function(event) | |
{ | |
this._currentResizer = null; | |
this.dispatchEventToListeners("width changed"); | |
}, | |
ColumnResizePadding: 10, | |
CenterResizerOverBorderAdjustment: 3, | |
} | |
WebInspector.DataGrid.ResizeMethod = { | |
Nearest: "nearest", | |
First: "first", | |
Last: "last" | |
} | |
WebInspector.DataGrid.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.DataGridNode = function(data, hasChildren) | |
{ | |
this._expanded = false; | |
this._selected = false; | |
this._shouldRefreshChildren = true; | |
this._data = data || {}; | |
this.hasChildren = hasChildren || false; | |
this.children = []; | |
this.dataGrid = null; | |
this.parent = null; | |
this.previousSibling = null; | |
this.nextSibling = null; | |
this.disclosureToggleWidth = 10; | |
} | |
WebInspector.DataGridNode.prototype = { | |
selectable: true, | |
_isRoot: false, | |
get element() | |
{ | |
if (this._element) | |
return this._element; | |
if (!this.dataGrid) | |
return null; | |
this._element = document.createElement("tr"); | |
this._element._dataGridNode = this; | |
if (this.hasChildren) | |
this._element.addStyleClass("parent"); | |
if (this.expanded) | |
this._element.addStyleClass("expanded"); | |
if (this.selected) | |
this._element.addStyleClass("selected"); | |
if (this.revealed) | |
this._element.addStyleClass("revealed"); | |
this.createCells(); | |
return this._element; | |
}, | |
createCells: function() | |
{ | |
for (var columnIdentifier in this.dataGrid.columns) { | |
var cell = this.createCell(columnIdentifier); | |
this._element.appendChild(cell); | |
} | |
}, | |
get data() | |
{ | |
return this._data; | |
}, | |
set data(x) | |
{ | |
this._data = x || {}; | |
this.refresh(); | |
}, | |
get revealed() | |
{ | |
if ("_revealed" in this) | |
return this._revealed; | |
var currentAncestor = this.parent; | |
while (currentAncestor && !currentAncestor._isRoot) { | |
if (!currentAncestor.expanded) { | |
this._revealed = false; | |
return false; | |
} | |
currentAncestor = currentAncestor.parent; | |
} | |
this._revealed = true; | |
return true; | |
}, | |
set hasChildren(x) | |
{ | |
if (this._hasChildren === x) | |
return; | |
this._hasChildren = x; | |
if (!this._element) | |
return; | |
if (this._hasChildren) | |
{ | |
this._element.addStyleClass("parent"); | |
if (this.expanded) | |
this._element.addStyleClass("expanded"); | |
} | |
else | |
{ | |
this._element.removeStyleClass("parent"); | |
this._element.removeStyleClass("expanded"); | |
} | |
}, | |
get hasChildren() | |
{ | |
return this._hasChildren; | |
}, | |
set revealed(x) | |
{ | |
if (this._revealed === x) | |
return; | |
this._revealed = x; | |
if (this._element) { | |
if (this._revealed) | |
this._element.addStyleClass("revealed"); | |
else | |
this._element.removeStyleClass("revealed"); | |
} | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i].revealed = x && this.expanded; | |
}, | |
get depth() | |
{ | |
if ("_depth" in this) | |
return this._depth; | |
if (this.parent && !this.parent._isRoot) | |
this._depth = this.parent.depth + 1; | |
else | |
this._depth = 0; | |
return this._depth; | |
}, | |
get leftPadding() | |
{ | |
if (typeof(this._leftPadding) === "number") | |
return this._leftPadding; | |
this._leftPadding = this.depth * this.dataGrid.indentWidth; | |
return this._leftPadding; | |
}, | |
get shouldRefreshChildren() | |
{ | |
return this._shouldRefreshChildren; | |
}, | |
set shouldRefreshChildren(x) | |
{ | |
this._shouldRefreshChildren = x; | |
if (x && this.expanded) | |
this.expand(); | |
}, | |
get selected() | |
{ | |
return this._selected; | |
}, | |
set selected(x) | |
{ | |
if (x) | |
this.select(); | |
else | |
this.deselect(); | |
}, | |
get expanded() | |
{ | |
return this._expanded; | |
}, | |
set expanded(x) | |
{ | |
if (x) | |
this.expand(); | |
else | |
this.collapse(); | |
}, | |
refresh: function() | |
{ | |
if (!this._element || !this.dataGrid) | |
return; | |
this._element.removeChildren(); | |
this.createCells(); | |
}, | |
createCell: function(columnIdentifier) | |
{ | |
var cell = document.createElement("td"); | |
cell.className = columnIdentifier + "-column"; | |
var alignment = this.dataGrid.aligned[columnIdentifier]; | |
if (alignment) | |
cell.addStyleClass(alignment); | |
var div = document.createElement("div"); | |
div.textContent = this.data[columnIdentifier]; | |
cell.appendChild(div); | |
if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) { | |
cell.addStyleClass("disclosure"); | |
if (this.leftPadding) | |
cell.style.setProperty("padding-left", this.leftPadding + "px"); | |
} | |
return cell; | |
}, | |
nodeHeight: function() | |
{ | |
var rowHeight = 16; | |
if (!this.revealed) | |
return 0; | |
if (!this.expanded) | |
return rowHeight; | |
var result = rowHeight; | |
for (var i = 0; i < this.children.length; i++) | |
result += this.children[i].nodeHeight(); | |
return result; | |
}, | |
appendChild: function(child) | |
{ | |
this.insertChild(child, this.children.length); | |
}, | |
insertChild: function(child, index) | |
{ | |
if (!child) | |
throw("insertChild: Node can't be undefined or null."); | |
if (child.parent === this) | |
throw("insertChild: Node is already a child of this node."); | |
if (child.parent) | |
child.parent.removeChild(child); | |
this.children.splice(index, 0, child); | |
this.hasChildren = true; | |
child.parent = this; | |
child.dataGrid = this.dataGrid; | |
child._recalculateSiblings(index); | |
delete child._depth; | |
delete child._revealed; | |
delete child._attached; | |
child._shouldRefreshChildren = true; | |
var current = child.children[0]; | |
while (current) { | |
current.dataGrid = this.dataGrid; | |
delete current._depth; | |
delete current._revealed; | |
delete current._attached; | |
current._shouldRefreshChildren = true; | |
current = current.traverseNextNode(false, child, true); | |
} | |
if (this.expanded) | |
child._attach(); | |
if (!this.revealed) | |
child.revealed = false; | |
}, | |
removeChild: function(child) | |
{ | |
if (!child) | |
throw("removeChild: Node can't be undefined or null."); | |
if (child.parent !== this) | |
throw("removeChild: Node is not a child of this node."); | |
child.deselect(); | |
child._detach(); | |
this.children.remove(child, true); | |
if (child.previousSibling) | |
child.previousSibling.nextSibling = child.nextSibling; | |
if (child.nextSibling) | |
child.nextSibling.previousSibling = child.previousSibling; | |
child.dataGrid = null; | |
child.parent = null; | |
child.nextSibling = null; | |
child.previousSibling = null; | |
if (this.children.length <= 0) | |
this.hasChildren = false; | |
}, | |
removeChildren: function() | |
{ | |
for (var i = 0; i < this.children.length; ++i) { | |
var child = this.children[i]; | |
child.deselect(); | |
child._detach(); | |
child.dataGrid = null; | |
child.parent = null; | |
child.nextSibling = null; | |
child.previousSibling = null; | |
} | |
this.children = []; | |
this.hasChildren = false; | |
}, | |
_recalculateSiblings: function(myIndex) | |
{ | |
if (!this.parent) | |
return; | |
var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null); | |
if (previousChild) { | |
previousChild.nextSibling = this; | |
this.previousSibling = previousChild; | |
} else | |
this.previousSibling = null; | |
var nextChild = this.parent.children[myIndex + 1]; | |
if (nextChild) { | |
nextChild.previousSibling = this; | |
this.nextSibling = nextChild; | |
} else | |
this.nextSibling = null; | |
}, | |
collapse: function() | |
{ | |
if (this._isRoot) | |
return; | |
if (this._element) | |
this._element.removeStyleClass("expanded"); | |
this._expanded = false; | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i].revealed = false; | |
this.dispatchEventToListeners("collapsed"); | |
}, | |
collapseRecursively: function() | |
{ | |
var item = this; | |
while (item) { | |
if (item.expanded) | |
item.collapse(); | |
item = item.traverseNextNode(false, this, true); | |
} | |
}, | |
expand: function() | |
{ | |
if (!this.hasChildren || this.expanded) | |
return; | |
if (this._isRoot) | |
return; | |
if (this.revealed && !this._shouldRefreshChildren) | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i].revealed = true; | |
if (this._shouldRefreshChildren) { | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i]._detach(); | |
this.dispatchEventToListeners("populate"); | |
if (this._attached) { | |
for (var i = 0; i < this.children.length; ++i) { | |
var child = this.children[i]; | |
if (this.revealed) | |
child.revealed = true; | |
child._attach(); | |
} | |
} | |
delete this._shouldRefreshChildren; | |
} | |
if (this._element) | |
this._element.addStyleClass("expanded"); | |
this._expanded = true; | |
this.dispatchEventToListeners("expanded"); | |
}, | |
expandRecursively: function() | |
{ | |
var item = this; | |
while (item) { | |
item.expand(); | |
item = item.traverseNextNode(false, this); | |
} | |
}, | |
reveal: function() | |
{ | |
if (this._isRoot) | |
return; | |
var currentAncestor = this.parent; | |
while (currentAncestor && !currentAncestor._isRoot) { | |
if (!currentAncestor.expanded) | |
currentAncestor.expand(); | |
currentAncestor = currentAncestor.parent; | |
} | |
this.element.scrollIntoViewIfNeeded(false); | |
this.dispatchEventToListeners("revealed"); | |
}, | |
select: function(supressSelectedEvent) | |
{ | |
if (!this.dataGrid || !this.selectable || this.selected) | |
return; | |
if (this.dataGrid.selectedNode) | |
this.dataGrid.selectedNode.deselect(); | |
this._selected = true; | |
this.dataGrid.selectedNode = this; | |
if (this._element) | |
this._element.addStyleClass("selected"); | |
if (!supressSelectedEvent) { | |
this.dispatchEventToListeners("selected"); | |
this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.SelectedNode); | |
} | |
}, | |
revealAndSelect: function() | |
{ | |
if (this._isRoot) | |
return; | |
this.reveal(); | |
this.select(); | |
}, | |
deselect: function(supressDeselectedEvent) | |
{ | |
if (!this.dataGrid || this.dataGrid.selectedNode !== this || !this.selected) | |
return; | |
this._selected = false; | |
this.dataGrid.selectedNode = null; | |
if (this._element) | |
this._element.removeStyleClass("selected"); | |
if (!supressDeselectedEvent) { | |
this.dispatchEventToListeners("deselected"); | |
this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.DeselectedNode); | |
} | |
}, | |
traverseNextNode: function(skipHidden, stayWithin, dontPopulate, info) | |
{ | |
if (!dontPopulate && this.hasChildren) | |
this.dispatchEventToListeners("populate"); | |
if (info) | |
info.depthChange = 0; | |
var node = (!skipHidden || this.revealed) ? this.children[0] : null; | |
if (node && (!skipHidden || this.expanded)) { | |
if (info) | |
info.depthChange = 1; | |
return node; | |
} | |
if (this === stayWithin) | |
return null; | |
node = (!skipHidden || this.revealed) ? this.nextSibling : null; | |
if (node) | |
return node; | |
node = this; | |
while (node && !node._isRoot && !((!skipHidden || node.revealed) ? node.nextSibling : null) && node.parent !== stayWithin) { | |
if (info) | |
info.depthChange -= 1; | |
node = node.parent; | |
} | |
if (!node) | |
return null; | |
return (!skipHidden || node.revealed) ? node.nextSibling : null; | |
}, | |
traversePreviousNode: function(skipHidden, dontPopulate) | |
{ | |
var node = (!skipHidden || this.revealed) ? this.previousSibling : null; | |
if (!dontPopulate && node && node.hasChildren) | |
node.dispatchEventToListeners("populate"); | |
while (node && ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null)) { | |
if (!dontPopulate && node.hasChildren) | |
node.dispatchEventToListeners("populate"); | |
node = ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null); | |
} | |
if (node) | |
return node; | |
if (!this.parent || this.parent._isRoot) | |
return null; | |
return this.parent; | |
}, | |
isEventWithinDisclosureTriangle: function(event) | |
{ | |
if (!this.hasChildren) | |
return false; | |
var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); | |
if (!cell.hasStyleClass("disclosure")) | |
return false; | |
var left = cell.totalOffsetLeft() + this.leftPadding; | |
return event.pageX >= left && event.pageX <= left + this.disclosureToggleWidth; | |
}, | |
_attach: function() | |
{ | |
if (!this.dataGrid || this._attached) | |
return; | |
this._attached = true; | |
var nextNode = null; | |
var previousNode = this.traversePreviousNode(true, true); | |
if (previousNode && previousNode.element.parentNode && previousNode.element.nextSibling) | |
nextNode = previousNode.element.nextSibling; | |
if (!nextNode) | |
nextNode = this.dataGrid.dataTableBody.firstChild; | |
this.dataGrid.dataTableBody.insertBefore(this.element, nextNode); | |
if (this.expanded) | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i]._attach(); | |
}, | |
_detach: function() | |
{ | |
if (!this._attached) | |
return; | |
this._attached = false; | |
if (this._element && this._element.parentNode) | |
this._element.parentNode.removeChild(this._element); | |
for (var i = 0; i < this.children.length; ++i) | |
this.children[i]._detach(); | |
this.wasDetached(); | |
}, | |
wasDetached: function() | |
{ | |
}, | |
savePosition: function() | |
{ | |
if (this._savedPosition) | |
return; | |
if (!this.parent) | |
throw("savePosition: Node must have a parent."); | |
this._savedPosition = { | |
parent: this.parent, | |
index: this.parent.children.indexOf(this) | |
}; | |
}, | |
restorePosition: function() | |
{ | |
if (!this._savedPosition) | |
return; | |
if (this.parent !== this._savedPosition.parent) | |
this._savedPosition.parent.insertChild(this, this._savedPosition.index); | |
delete this._savedPosition; | |
} | |
} | |
WebInspector.DataGridNode.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.CreationDataGridNode = function(data, hasChildren) | |
{ | |
WebInspector.DataGridNode.call(this, data, hasChildren); | |
this.isCreationNode = true; | |
} | |
WebInspector.CreationDataGridNode.prototype = { | |
makeNormal: function() | |
{ | |
delete this.isCreationNode; | |
delete this.makeNormal; | |
} | |
} | |
WebInspector.CreationDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; | |
WebInspector.ShowMoreDataGridNode = function(callback, startPosition, endPosition, chunkSize) | |
{ | |
WebInspector.DataGridNode.call(this, {summaryRow:true}, false); | |
this._callback = callback; | |
this._startPosition = startPosition; | |
this._endPosition = endPosition; | |
this._chunkSize = chunkSize; | |
this.showNext = document.createElement("button"); | |
this.showNext.setAttribute("type", "button"); | |
this.showNext.addEventListener("click", this._showNextChunk.bind(this), false); | |
this.showNext.textContent = WebInspector.UIString("Show %d before", this._chunkSize); | |
this.showAll = document.createElement("button"); | |
this.showAll.setAttribute("type", "button"); | |
this.showAll.addEventListener("click", this._showAll.bind(this), false); | |
this.showLast = document.createElement("button"); | |
this.showLast.setAttribute("type", "button"); | |
this.showLast.addEventListener("click", this._showLastChunk.bind(this), false); | |
this.showLast.textContent = WebInspector.UIString("Show %d after", this._chunkSize); | |
this._updateLabels(); | |
this.selectable = false; | |
} | |
WebInspector.ShowMoreDataGridNode.prototype = { | |
_showNextChunk: function() | |
{ | |
this._callback(this._startPosition, this._startPosition + this._chunkSize); | |
}, | |
_showAll: function() | |
{ | |
this._callback(this._startPosition, this._endPosition); | |
}, | |
_showLastChunk: function() | |
{ | |
this._callback(this._endPosition - this._chunkSize, this._endPosition); | |
}, | |
_updateLabels: function() | |
{ | |
var totalSize = this._endPosition - this._startPosition; | |
if (totalSize > this._chunkSize) { | |
this.showNext.removeStyleClass("hidden"); | |
this.showLast.removeStyleClass("hidden"); | |
} else { | |
this.showNext.addStyleClass("hidden"); | |
this.showLast.addStyleClass("hidden"); | |
} | |
this.showAll.textContent = WebInspector.UIString("Show all %d", totalSize); | |
}, | |
createCells: function() | |
{ | |
var cell = document.createElement("td"); | |
if (this.depth) | |
cell.style.setProperty("padding-left", (this.depth * this.dataGrid.indentWidth) + "px"); | |
cell.appendChild(this.showNext); | |
cell.appendChild(this.showAll); | |
cell.appendChild(this.showLast); | |
this._element.appendChild(cell); | |
var columns = this.dataGrid.columns; | |
var count = 0; | |
for (var c in columns) | |
++count; | |
while (--count > 0) { | |
cell = document.createElement("td"); | |
this._element.appendChild(cell); | |
} | |
}, | |
setStartPosition: function(from) | |
{ | |
this._startPosition = from; | |
this._updateLabels(); | |
}, | |
setEndPosition: function(to) | |
{ | |
this._endPosition = to; | |
this._updateLabels(); | |
}, | |
nodeHeight: function() | |
{ | |
return 32; | |
}, | |
dispose: function() | |
{ | |
} | |
}; | |
WebInspector.ShowMoreDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; | |
WebInspector.CookiesTable = function(cookieDomain, expandable, deleteCallback, refreshCallback) | |
{ | |
WebInspector.View.call(this); | |
this.element.className = "fill"; | |
this._cookieDomain = cookieDomain; | |
var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} }; | |
columns[0].title = WebInspector.UIString("Name"); | |
columns[0].sortable = true; | |
columns[0].disclosure = expandable; | |
columns[0].width = "24%"; | |
columns[1].title = WebInspector.UIString("Value"); | |
columns[1].sortable = true; | |
columns[1].width = "34%"; | |
columns[2].title = WebInspector.UIString("Domain"); | |
columns[2].sortable = true; | |
columns[2].width = "7%"; | |
columns[3].title = WebInspector.UIString("Path"); | |
columns[3].sortable = true; | |
columns[3].width = "7%"; | |
columns[4].title = WebInspector.UIString("Expires"); | |
columns[4].sortable = true; | |
columns[4].width = "7%"; | |
columns[5].title = WebInspector.UIString("Size"); | |
columns[5].aligned = "right"; | |
columns[5].sortable = true; | |
columns[5].width = "7%"; | |
columns[6].title = WebInspector.UIString("HTTP"); | |
columns[6].aligned = "centered"; | |
columns[6].sortable = true; | |
columns[6].width = "7%"; | |
columns[7].title = WebInspector.UIString("Secure"); | |
columns[7].aligned = "centered"; | |
columns[7].sortable = true; | |
columns[7].width = "7%"; | |
this._dataGrid = new WebInspector.DataGrid(columns, undefined, deleteCallback ? this._onDeleteFromGrid.bind(this, deleteCallback) : undefined); | |
this._dataGrid.addEventListener("sorting changed", this._rebuildTable, this); | |
this._dataGrid.refreshCallback = refreshCallback; | |
this._dataGrid.show(this.element); | |
this._data = []; | |
} | |
WebInspector.CookiesTable.prototype = { | |
updateWidths: function() | |
{ | |
if (this._dataGrid) | |
this._dataGrid.updateWidths(); | |
}, | |
setCookies: function(cookies) | |
{ | |
this._data = [{cookies: cookies}]; | |
this._rebuildTable(); | |
}, | |
addCookiesFolder: function(folderName, cookies) | |
{ | |
this._data.push({cookies: cookies, folderName: folderName}); | |
this._rebuildTable(); | |
}, | |
get selectedCookie() | |
{ | |
var node = this._dataGrid.selectedNode; | |
return node ? node.cookie : null; | |
}, | |
_rebuildTable: function() | |
{ | |
this._dataGrid.rootNode().removeChildren(); | |
for (var i = 0; i < this._data.length; ++i) { | |
var item = this._data[i]; | |
if (item.folderName) { | |
var groupData = [ item.folderName, "", "", "", "", this._totalSize(item.cookies), "", "" ]; | |
var groupNode = new WebInspector.DataGridNode(groupData); | |
groupNode.selectable = true; | |
this._dataGrid.rootNode().appendChild(groupNode); | |
groupNode.element.addStyleClass("row-group"); | |
this._populateNode(groupNode, item.cookies); | |
groupNode.expand(); | |
} else | |
this._populateNode(this._dataGrid.rootNode(), item.cookies); | |
} | |
}, | |
_populateNode: function(parentNode, cookies) | |
{ | |
var selectedCookie = this.selectedCookie; | |
parentNode.removeChildren(); | |
if (!cookies) | |
return; | |
this._sortCookies(cookies); | |
for (var i = 0; i < cookies.length; ++i) { | |
var cookieNode = this._createGridNode(cookies[i]); | |
parentNode.appendChild(cookieNode); | |
if (selectedCookie === cookies[i]) | |
cookieNode.selected = true; | |
} | |
}, | |
_totalSize: function(cookies) | |
{ | |
var totalSize = 0; | |
for (var i = 0; cookies && i < cookies.length; ++i) | |
totalSize += cookies[i].size; | |
return totalSize; | |
}, | |
_sortCookies: function(cookies) | |
{ | |
var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1; | |
function localeCompare(field, cookie1, cookie2) | |
{ | |
return sortDirection * (cookie1[field] + "").localeCompare(cookie2[field] + "") | |
} | |
function numberCompare(field, cookie1, cookie2) | |
{ | |
return sortDirection * (cookie1[field] - cookie2[field]); | |
} | |
function expiresCompare(cookie1, cookie2) | |
{ | |
if (cookie1.session !== cookie2.session) | |
return sortDirection * (cookie1.session ? 1 : -1); | |
if (cookie1.session) | |
return 0; | |
return sortDirection * (cookie1.expires - cookie2.expires); | |
} | |
var comparator; | |
switch (parseInt(this._dataGrid.sortColumnIdentifier, 10)) { | |
case 0: comparator = localeCompare.bind(this, "name"); break; | |
case 1: comparator = localeCompare.bind(this, "value"); break; | |
case 2: comparator = localeCompare.bind(this, "domain"); break; | |
case 3: comparator = localeCompare.bind(this, "path"); break; | |
case 4: comparator = expiresCompare; break; | |
case 5: comparator = numberCompare.bind(this, "size"); break; | |
case 6: comparator = localeCompare.bind(this, "httpOnly"); break; | |
case 7: comparator = localeCompare.bind(this, "secure"); break; | |
default: localeCompare.bind(this, "name"); | |
} | |
cookies.sort(comparator); | |
}, | |
_createGridNode: function(cookie) | |
{ | |
var data = {}; | |
data[0] = cookie.name; | |
data[1] = cookie.value; | |
data[2] = cookie.domain || ""; | |
data[3] = cookie.path || ""; | |
data[4] = cookie.type === WebInspector.Cookie.Type.Request ? "" : | |
(cookie.session ? WebInspector.UIString("Session") : new Date(cookie.expires).toGMTString()); | |
data[5] = cookie.size; | |
const checkmark = "\u2713"; | |
data[6] = (cookie.httpOnly ? checkmark : ""); | |
data[7] = (cookie.secure ? checkmark : ""); | |
var node = new WebInspector.DataGridNode(data); | |
node.cookie = cookie; | |
node.selectable = true; | |
return node; | |
}, | |
_onDeleteFromGrid: function(deleteCallback, node) | |
{ | |
deleteCallback(node.cookie); | |
} | |
} | |
WebInspector.CookiesTable.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.CookieItemsView = function(treeElement, cookieDomain) | |
{ | |
WebInspector.View.call(this); | |
this.element.addStyleClass("storage-view"); | |
this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); | |
this._deleteButton.visible = false; | |
this._deleteButton.addEventListener("click", this._deleteButtonClicked, this); | |
this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); | |
this._refreshButton.addEventListener("click", this._refreshButtonClicked, this); | |
this._treeElement = treeElement; | |
this._cookieDomain = cookieDomain; | |
this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("This site has no cookies.")); | |
this._emptyView.show(this.element); | |
this.element.addEventListener("contextmenu", this._contextMenu.bind(this), true); | |
} | |
WebInspector.CookieItemsView.prototype = { | |
get statusBarItems() | |
{ | |
return [this._refreshButton.element, this._deleteButton.element]; | |
}, | |
wasShown: function() | |
{ | |
this._update(); | |
}, | |
willHide: function() | |
{ | |
this._deleteButton.visible = false; | |
}, | |
_update: function() | |
{ | |
WebInspector.Cookies.getCookiesAsync(this._updateWithCookies.bind(this)); | |
}, | |
_updateWithCookies: function(allCookies, isAdvanced) | |
{ | |
this._cookies = isAdvanced ? this._filterCookiesForDomain(allCookies) : allCookies; | |
if (!this._cookies.length) { | |
this._emptyView.show(this.element); | |
this._deleteButton.visible = false; | |
if (this._cookiesTable) | |
this._cookiesTable.detach(); | |
return; | |
} | |
if (!this._cookiesTable) | |
this._cookiesTable = isAdvanced ? new WebInspector.CookiesTable(this._cookieDomain, false, this._deleteCookie.bind(this), this._update.bind(this)) : new WebInspector.SimpleCookiesTable(); | |
this._cookiesTable.setCookies(this._cookies); | |
this._emptyView.detach(); | |
this._cookiesTable.show(this.element); | |
if (isAdvanced) { | |
this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length, | |
Number.bytesToString(this._totalSize)); | |
this._deleteButton.visible = true; | |
} | |
}, | |
_filterCookiesForDomain: function(allCookies) | |
{ | |
var cookies = []; | |
var resourceURLsForDocumentURL = []; | |
this._totalSize = 0; | |
function populateResourcesForDocuments(resource) | |
{ | |
var url = resource.documentURL.asParsedURL(); | |
if (url && url.host == this._cookieDomain) | |
resourceURLsForDocumentURL.push(resource.url); | |
} | |
WebInspector.forAllResources(populateResourcesForDocuments.bind(this)); | |
for (var i = 0; i < allCookies.length; ++i) { | |
var pushed = false; | |
var size = allCookies[i].size; | |
for (var j = 0; j < resourceURLsForDocumentURL.length; ++j) { | |
var resourceURL = resourceURLsForDocumentURL[j]; | |
if (WebInspector.Cookies.cookieMatchesResourceURL(allCookies[i], resourceURL)) { | |
this._totalSize += size; | |
if (!pushed) { | |
pushed = true; | |
cookies.push(allCookies[i]); | |
} | |
} | |
} | |
} | |
return cookies; | |
}, | |
_deleteCookie: function(cookie) | |
{ | |
PageAgent.deleteCookie(cookie.name, this._cookieDomain); | |
this._update(); | |
}, | |
_deleteButtonClicked: function() | |
{ | |
if (this._cookiesTable.selectedCookie) | |
this._deleteCookie(this._cookiesTable.selectedCookie); | |
}, | |
_refreshButtonClicked: function(event) | |
{ | |
this._update(); | |
}, | |
_contextMenu: function(event) | |
{ | |
if (!this._cookies.length) { | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendItem(WebInspector.UIString("Refresh"), this._update.bind(this)); | |
contextMenu.show(event); | |
} | |
} | |
} | |
WebInspector.CookieItemsView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.SimpleCookiesTable = function() | |
{ | |
WebInspector.View.call(this); | |
var columns = {}; | |
columns[0] = {}; | |
columns[1] = {}; | |
columns[0].title = WebInspector.UIString("Name"); | |
columns[1].title = WebInspector.UIString("Value"); | |
this._dataGrid = new WebInspector.DataGrid(columns); | |
this._dataGrid.autoSizeColumns(20, 80); | |
this._dataGrid.show(this.element); | |
} | |
WebInspector.SimpleCookiesTable.prototype = { | |
setCookies: function(cookies) | |
{ | |
this._dataGrid.rootNode().removeChildren(); | |
var addedCookies = {}; | |
for (var i = 0; i < cookies.length; ++i) { | |
if (addedCookies[cookies[i].name]) | |
continue; | |
addedCookies[cookies[i].name] = true; | |
var data = {}; | |
data[0] = cookies[i].name; | |
data[1] = cookies[i].value; | |
var node = new WebInspector.DataGridNode(data, false); | |
node.selectable = true; | |
this._dataGrid.rootNode().appendChild(node); | |
} | |
this._dataGrid.rootNode().children[0].selected = true; | |
} | |
} | |
WebInspector.SimpleCookiesTable.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.Cookies = {} | |
WebInspector.Cookies.getCookiesAsync = function(callback) | |
{ | |
function mycallback(error, cookies, cookiesString) | |
{ | |
if (error) | |
return; | |
if (cookiesString) | |
callback(WebInspector.Cookies.buildCookiesFromString(cookiesString), false); | |
else | |
callback(cookies, true); | |
} | |
PageAgent.getCookies(mycallback); | |
} | |
WebInspector.Cookies.buildCookiesFromString = function(rawCookieString) | |
{ | |
var rawCookies = rawCookieString.split(/;\s*/); | |
var cookies = []; | |
if (!(/^\s*$/.test(rawCookieString))) { | |
for (var i = 0; i < rawCookies.length; ++i) { | |
var cookie = rawCookies[i]; | |
var delimIndex = cookie.indexOf("="); | |
var name = cookie.substring(0, delimIndex); | |
var value = cookie.substring(delimIndex + 1); | |
var size = name.length + value.length; | |
cookies.push({ name: name, value: value, size: size }); | |
} | |
} | |
return cookies; | |
} | |
WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) | |
{ | |
var url = resourceURL.asParsedURL(); | |
if (!url || !WebInspector.Cookies.cookieDomainMatchesResourceDomain(cookie.domain, url.host)) | |
return false; | |
return (url.path.startsWith(cookie.path) | |
&& (!cookie.port || url.port == cookie.port) | |
&& (!cookie.secure || url.scheme === "https")); | |
} | |
WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain) | |
{ | |
if (cookieDomain.charAt(0) !== '.') | |
return resourceDomain === cookieDomain; | |
return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)?" + cookieDomain.substring(1).escapeForRegExp() + "$"), "i"); | |
} | |
WebInspector.ApplicationCacheModel = function() | |
{ | |
ApplicationCacheAgent.enable(); | |
InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher(this)); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); | |
this._statuses = {}; | |
this._manifestURLsByFrame = {}; | |
this._mainFrameNavigated(); | |
this._onLine = true; | |
} | |
WebInspector.ApplicationCacheModel.EventTypes = { | |
FrameManifestStatusUpdated: "FrameManifestStatusUpdated", | |
FrameManifestAdded: "FrameManifestAdded", | |
FrameManifestRemoved: "FrameManifestRemoved", | |
NetworkStateChanged: "NetworkStateChanged" | |
} | |
WebInspector.ApplicationCacheModel.prototype = { | |
_frameNavigated: function(event) | |
{ | |
var frame = event.data; | |
if (frame.isMainFrame()) { | |
this._mainFrameNavigated(); | |
return; | |
} | |
ApplicationCacheAgent.getManifestForFrame(frame.id, this._manifestForFrameLoaded.bind(this, frame.id)); | |
}, | |
_frameDetached: function(event) | |
{ | |
var frame = event.data; | |
this._frameManifestRemoved(frame.id); | |
}, | |
_mainFrameNavigated: function() | |
{ | |
ApplicationCacheAgent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this)); | |
}, | |
_manifestForFrameLoaded: function(frameId, error, manifestURL) | |
{ | |
if (error) { | |
console.error(error); | |
return; | |
} | |
if (!manifestURL) | |
this._frameManifestRemoved(frameId); | |
}, | |
_framesWithManifestsLoaded: function(error, framesWithManifests) | |
{ | |
if (error) { | |
console.error(error); | |
return; | |
} | |
for (var i = 0; i < framesWithManifests.length; ++i) | |
this._frameManifestUpdated(framesWithManifests[i].frameId, framesWithManifests[i].manifestURL, framesWithManifests[i].status); | |
}, | |
_frameManifestUpdated: function(frameId, manifestURL, status) | |
{ | |
if (status === applicationCache.UNCACHED) { | |
this._frameManifestRemoved(frameId); | |
return; | |
} | |
if (!manifestURL) | |
return; | |
if (this._manifestURLsByFrame[frameId] && manifestURL !== this._manifestURLsByFrame[frameId]) | |
this._frameManifestRemoved(frameId); | |
var statusChanged = this._statuses[frameId] !== status; | |
this._statuses[frameId] = status; | |
if (!this._manifestURLsByFrame[frameId]) { | |
this._manifestURLsByFrame[frameId] = manifestURL; | |
this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, frameId); | |
} | |
if (statusChanged) | |
this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, frameId); | |
}, | |
_frameManifestRemoved: function(frameId) | |
{ | |
if (!this._manifestURLsByFrame[frameId]) | |
return; | |
var manifestURL = this._manifestURLsByFrame[frameId]; | |
delete this._manifestURLsByFrame[frameId]; | |
delete this._statuses[frameId]; | |
this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, frameId); | |
}, | |
frameManifestURL: function(frameId) | |
{ | |
return this._manifestURLsByFrame[frameId] || ""; | |
}, | |
frameManifestStatus: function(frameId) | |
{ | |
return this._statuses[frameId] || applicationCache.UNCACHED; | |
}, | |
get onLine() | |
{ | |
return this._onLine; | |
}, | |
_statusUpdated: function(frameId, manifestURL, status) | |
{ | |
this._frameManifestUpdated(frameId, manifestURL, status); | |
}, | |
requestApplicationCache: function(frameId, callback) | |
{ | |
function callbackWrapper(error, applicationCache) | |
{ | |
if (error) { | |
console.error(error); | |
callback(null); | |
return; | |
} | |
callback(applicationCache); | |
} | |
ApplicationCacheAgent.getApplicationCacheForFrame(frameId, callbackWrapper.bind(this)); | |
}, | |
_networkStateUpdated: function(isNowOnline) | |
{ | |
this._onLine = isNowOnline; | |
this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, isNowOnline); | |
} | |
} | |
WebInspector.ApplicationCacheModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.ApplicationCacheDispatcher = function(applicationCacheModel) | |
{ | |
this._applicationCacheModel = applicationCacheModel; | |
} | |
WebInspector.ApplicationCacheDispatcher.prototype = { | |
applicationCacheStatusUpdated: function(frameId, manifestURL, status) | |
{ | |
this._applicationCacheModel._statusUpdated(frameId, manifestURL, status); | |
}, | |
networkStateUpdated: function(isNowOnline) | |
{ | |
this._applicationCacheModel._networkStateUpdated(isNowOnline); | |
} | |
} | |
WebInspector.IndexedDBModel = function() | |
{ | |
IndexedDBAgent.enable(); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameNavigated, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this); | |
this._frames = {}; | |
this._databases = new Map(); | |
this._frameIdsBySecurityOrigin = {}; | |
this._databaseNamesBySecurityOrigin = {}; | |
this.refreshDatabaseNames(); | |
} | |
WebInspector.IndexedDBModel.KeyTypes = { | |
NumberType: "number", | |
StringType: "string", | |
DateType: "date", | |
ArrayType: "array" | |
}; | |
WebInspector.IndexedDBModel.KeyPathTypes = { | |
NullType: "null", | |
StringType: "string", | |
ArrayType: "array" | |
}; | |
WebInspector.IndexedDBModel.idbKeyFromKey = function(key) | |
{ | |
var idbKey; | |
switch (key.type) { | |
case WebInspector.IndexedDBModel.KeyTypes.NumberType: | |
idbKey = key.number; | |
break; | |
case WebInspector.IndexedDBModel.KeyTypes.StringType: | |
idbKey = key.string; | |
break; | |
case WebInspector.IndexedDBModel.KeyTypes.DateType: | |
idbKey = new Date(key.date); | |
break; | |
case WebInspector.IndexedDBModel.KeyTypes.ArrayType: | |
idbKey = []; | |
for (var i = 0; i < key.array.length; ++i) | |
idbKey.push(WebInspector.IndexedDBModel.idbKeyFromKey(key.array[i])); | |
break; | |
} | |
return idbKey; | |
} | |
WebInspector.IndexedDBModel.keyFromIDBKey = function(idbKey) | |
{ | |
if (typeof(idbKey) === "undefined" || idbKey === null) | |
return null; | |
var key = {}; | |
switch (typeof(idbKey)) { | |
case "number": | |
key.number = idbKey; | |
key.type = WebInspector.IndexedDBModel.KeyTypes.NumberType; | |
break; | |
case "string": | |
key.string = idbKey; | |
key.type = WebInspector.IndexedDBModel.KeyTypes.StringType; | |
break; | |
case "object": | |
if (idbKey instanceof Date) { | |
key.date = idbKey.getTime(); | |
key.type = WebInspector.IndexedDBModel.KeyTypes.DateType; | |
} else if (idbKey instanceof Array) { | |
key.array = []; | |
for (var i = 0; i < idbKey.length; ++i) | |
key.array.push(WebInspector.IndexedDBModel.keyFromIDBKey(idbKey[i])); | |
key.type = WebInspector.IndexedDBModel.KeyTypes.ArrayType; | |
} | |
break; | |
default: | |
return null; | |
} | |
return key; | |
} | |
WebInspector.IndexedDBModel.keyRangeFromIDBKeyRange = function(idbKeyRange) | |
{ | |
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange; | |
if (typeof(idbKeyRange) === "undefined" || idbKeyRange === null) | |
return null; | |
var keyRange = {}; | |
keyRange.lower = WebInspector.IndexedDBModel.keyFromIDBKey(idbKeyRange.lower); | |
keyRange.upper = WebInspector.IndexedDBModel.keyFromIDBKey(idbKeyRange.upper); | |
keyRange.lowerOpen = idbKeyRange.lowerOpen; | |
keyRange.upperOpen = idbKeyRange.upperOpen; | |
return keyRange; | |
} | |
WebInspector.IndexedDBModel.idbKeyPathFromKeyPath = function(keyPath) | |
{ | |
var idbKeyPath; | |
switch (keyPath.type) { | |
case WebInspector.IndexedDBModel.KeyPathTypes.NullType: | |
idbKeyPath = null; | |
break; | |
case WebInspector.IndexedDBModel.KeyPathTypes.StringType: | |
idbKeyPath = keyPath.string; | |
break; | |
case WebInspector.IndexedDBModel.KeyPathTypes.ArrayType: | |
idbKeyPath = keyPath.array; | |
break; | |
} | |
return idbKeyPath; | |
} | |
WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath = function(idbKeyPath) | |
{ | |
if (typeof idbKeyPath === "string") | |
return "\"" + idbKeyPath + "\""; | |
if (idbKeyPath instanceof Array) | |
return "[\"" + idbKeyPath.join("\", \"") + "\"]"; | |
return null; | |
} | |
WebInspector.IndexedDBModel.EventTypes = { | |
DatabaseAdded: "DatabaseAdded", | |
DatabaseRemoved: "DatabaseRemoved", | |
DatabaseLoaded: "DatabaseLoaded" | |
} | |
WebInspector.IndexedDBModel.prototype = { | |
refreshDatabaseNames: function() | |
{ | |
this._reset(); | |
if (WebInspector.resourceTreeModel.mainFrame) | |
this._framesNavigatedRecursively(WebInspector.resourceTreeModel.mainFrame); | |
}, | |
refreshDatabase: function(databaseId) | |
{ | |
this._loadDatabase(databaseId); | |
}, | |
_framesNavigatedRecursively: function(resourceTreeFrame) | |
{ | |
this._processFrameNavigated(resourceTreeFrame); | |
for (var i = 0; i < resourceTreeFrame.childFrames.length; ++i) | |
this._framesNavigatedRecursively(resourceTreeFrame.childFrames[i]); | |
}, | |
_frameNavigated: function(event) | |
{ | |
var resourceTreeFrame = event.data; | |
this._processFrameNavigated(resourceTreeFrame); | |
}, | |
_frameDetached: function(event) | |
{ | |
var resourceTreeFrame = event.data; | |
this._originRemovedFromFrame(resourceTreeFrame.id); | |
}, | |
_reset: function() | |
{ | |
for (var frameId in this._frames) | |
this._originRemovedFromFrame(frameId); | |
}, | |
_processFrameNavigated: function(resourceTreeFrame) | |
{ | |
if (resourceTreeFrame.securityOrigin === "null") | |
return; | |
if (this._frameIdsBySecurityOrigin[resourceTreeFrame.securityOrigin]) | |
this._originAddedToFrame(resourceTreeFrame.id, resourceTreeFrame.securityOrigin); | |
else | |
this._loadDatabaseNamesForFrame(resourceTreeFrame.id); | |
}, | |
_originAddedToFrame: function(frameId, securityOrigin) | |
{ | |
if (!this._frameIdsBySecurityOrigin[securityOrigin]) { | |
this._frameIdsBySecurityOrigin[securityOrigin] = []; | |
this._frameIdsBySecurityOrigin[securityOrigin].push(frameId); | |
this._databaseNamesBySecurityOrigin[securityOrigin] = []; | |
} | |
this._frames[frameId] = new WebInspector.IndexedDBModel.Frame(frameId, securityOrigin); | |
}, | |
_originRemovedFromFrame: function(frameId) | |
{ | |
var currentSecurityOrigin = this._frames[frameId] ? this._frames[frameId].securityOrigin : null; | |
if (!currentSecurityOrigin) | |
return; | |
delete this._frames[frameId]; | |
var frameIdsForOrigin = this._frameIdsBySecurityOrigin[currentSecurityOrigin]; | |
for (var i = 0; i < frameIdsForOrigin; ++i) { | |
if (frameIdsForOrigin[i] === frameId) { | |
frameIdsForOrigin.splice(i, 1); | |
break; | |
} | |
} | |
if (!frameIdsForOrigin.length) | |
this._originRemoved(currentSecurityOrigin); | |
}, | |
_originRemoved: function(securityOrigin) | |
{ | |
var frameIdsForOrigin = this._frameIdsBySecurityOrigin[securityOrigin]; | |
for (var i = 0; i < frameIdsForOrigin; ++i) | |
delete this._frames[frameIdsForOrigin[i]]; | |
delete this._frameIdsBySecurityOrigin[securityOrigin]; | |
for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i) | |
this._databaseRemoved(securityOrigin, this._databaseNamesBySecurityOrigin[securityOrigin][i]); | |
delete this._databaseNamesBySecurityOrigin[securityOrigin]; | |
}, | |
_updateOriginDatabaseNames: function(securityOrigin, databaseNames) | |
{ | |
var newDatabaseNames = {}; | |
for (var i = 0; i < databaseNames.length; ++i) | |
newDatabaseNames[databaseNames[i]] = true; | |
var oldDatabaseNames = {}; | |
for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i) | |
oldDatabaseNames[databaseNames[i]] = true; | |
this._databaseNamesBySecurityOrigin[securityOrigin] = databaseNames; | |
for (var databaseName in oldDatabaseNames) { | |
if (!newDatabaseNames[databaseName]) | |
this._databaseRemoved(securityOrigin, databaseName); | |
} | |
for (var databaseName in newDatabaseNames) { | |
if (!oldDatabaseNames[databaseName]) | |
this._databaseAdded(securityOrigin, databaseName); | |
} | |
if (!this._databaseNamesBySecurityOrigin[securityOrigin].length) | |
this._originRemoved(securityOrigin); | |
}, | |
_databaseAdded: function(securityOrigin, databaseName) | |
{ | |
var databaseId = new WebInspector.IndexedDBModel.DatabaseId(securityOrigin, databaseName); | |
this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseAdded, databaseId); | |
}, | |
_databaseRemoved: function(securityOrigin, databaseName) | |
{ | |
var databaseId = new WebInspector.IndexedDBModel.DatabaseId(securityOrigin, databaseName); | |
this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseRemoved, databaseId); | |
}, | |
_loadDatabaseNamesForFrame: function(frameId) | |
{ | |
function callback(error, securityOriginWithDatabaseNames) | |
{ | |
if (error) { | |
console.error("IndexedDBAgent error: " + error); | |
return; | |
} | |
var databaseNames = securityOriginWithDatabaseNames.databaseNames; | |
var oldSecurityOrigin = this._frames[frameId] ? this._frames[frameId].securityOrigin : null; | |
if (!oldSecurityOrigin || oldSecurityOrigin !== securityOriginWithDatabaseNames.securityOrigin) { | |
this._originRemovedFromFrame(frameId); | |
this._originAddedToFrame(frameId, securityOriginWithDatabaseNames.securityOrigin); | |
} | |
this._updateOriginDatabaseNames(securityOriginWithDatabaseNames.securityOrigin, securityOriginWithDatabaseNames.databaseNames); | |
} | |
IndexedDBAgent.requestDatabaseNamesForFrame(frameId, callback.bind(this)); | |
}, | |
_assertFrameId: function(databaseId) | |
{ | |
var frameIds = this._frameIdsBySecurityOrigin[databaseId.securityOrigin]; | |
if (!frameIds || !frameIds.length) | |
return null; | |
return frameIds[0]; | |
}, | |
_loadDatabase: function(databaseId) | |
{ | |
var frameId = this._assertFrameId(databaseId); | |
if (!frameId) | |
return; | |
function callback(error, databaseWithObjectStores) | |
{ | |
if (error) { | |
console.error("IndexedDBAgent error: " + error); | |
return; | |
} | |
if (!this._frames[frameId]) | |
return; | |
var databaseModel = new WebInspector.IndexedDBModel.Database(databaseId, databaseWithObjectStores.version); | |
this._databases.put(databaseId, databaseModel); | |
for (var i = 0; i < databaseWithObjectStores.objectStores.length; ++i) { | |
var objectStore = databaseWithObjectStores.objectStores[i]; | |
var objectStoreIDBKeyPath = WebInspector.IndexedDBModel.idbKeyPathFromKeyPath(objectStore.keyPath); | |
var objectStoreModel = new WebInspector.IndexedDBModel.ObjectStore(objectStore.name, objectStoreIDBKeyPath, objectStore.autoIncrement); | |
for (var j = 0; j < objectStore.indexes.length; ++j) { | |
var index = objectStore.indexes[j]; | |
var indexIDBKeyPath = WebInspector.IndexedDBModel.idbKeyPathFromKeyPath(index.keyPath); | |
var indexModel = new WebInspector.IndexedDBModel.Index(index.name, indexIDBKeyPath, index.unique, index.multiEntry); | |
objectStoreModel.indexes[indexModel.name] = indexModel; | |
} | |
databaseModel.objectStores[objectStoreModel.name] = objectStoreModel; | |
} | |
this.dispatchEventToListeners(WebInspector.IndexedDBModel.EventTypes.DatabaseLoaded, databaseModel); | |
} | |
IndexedDBAgent.requestDatabase(frameId, databaseId.name, callback.bind(this)); | |
}, | |
loadObjectStoreData: function(databaseId, objectStoreName, idbKeyRange, skipCount, pageSize, callback) | |
{ | |
this._requestData(databaseId, databaseId.name, objectStoreName, "", idbKeyRange, skipCount, pageSize, callback); | |
}, | |
loadIndexData: function(databaseId, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) | |
{ | |
this._requestData(databaseId, databaseId.name, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback); | |
}, | |
_requestData: function(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) | |
{ | |
var frameId = this._assertFrameId(databaseId); | |
if (!frameId) | |
return; | |
function innerCallback(error, dataEntries, hasMore) | |
{ | |
if (error) { | |
console.error("IndexedDBAgent error: " + error); | |
return; | |
} | |
if (!this._frames[frameId]) | |
return; | |
var entries = []; | |
for (var i = 0; i < dataEntries.length; ++i) { | |
var key = WebInspector.IndexedDBModel.idbKeyFromKey(dataEntries[i].key); | |
var primaryKey = WebInspector.IndexedDBModel.idbKeyFromKey(dataEntries[i].primaryKey); | |
var value = WebInspector.RemoteObject.fromPayload(dataEntries[i].value); | |
entries.push(new WebInspector.IndexedDBModel.Entry(key, primaryKey, value)); | |
} | |
callback(entries, hasMore); | |
} | |
var keyRange = WebInspector.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange); | |
IndexedDBAgent.requestData(frameId, databaseName, objectStoreName, indexName, skipCount, pageSize, keyRange ? keyRange : undefined, innerCallback.bind(this)); | |
} | |
} | |
WebInspector.IndexedDBModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.IndexedDBModel.Entry = function(key, primaryKey, value) | |
{ | |
this.key = key; | |
this.primaryKey = primaryKey; | |
this.value = value; | |
} | |
WebInspector.IndexedDBModel.Frame = function(frameId, securityOrigin) | |
{ | |
this.frameId = frameId; | |
this.securityOrigin = securityOrigin; | |
this.databaseNames = {}; | |
} | |
WebInspector.IndexedDBModel.DatabaseId = function(securityOrigin, name) | |
{ | |
this.securityOrigin = securityOrigin; | |
this.name = name; | |
} | |
WebInspector.IndexedDBModel.DatabaseId.prototype = { | |
equals: function(databaseId) | |
{ | |
return this.name === databaseId.name && this.securityOrigin === databaseId.securityOrigin; | |
}, | |
} | |
WebInspector.IndexedDBModel.Database = function(databaseId, version) | |
{ | |
this.databaseId = databaseId; | |
this.version = version; | |
this.objectStores = {}; | |
} | |
WebInspector.IndexedDBModel.ObjectStore = function(name, keyPath, autoIncrement) | |
{ | |
this.name = name; | |
this.keyPath = keyPath; | |
this.autoIncrement = autoIncrement; | |
this.indexes = {}; | |
} | |
WebInspector.IndexedDBModel.ObjectStore.prototype = { | |
get keyPathString() | |
{ | |
return WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath(this.keyPath); | |
} | |
} | |
WebInspector.IndexedDBModel.Index = function(name, keyPath, unique, multiEntry) | |
{ | |
this.name = name; | |
this.keyPath = keyPath; | |
this.unique = unique; | |
this.multiEntry = multiEntry; | |
} | |
WebInspector.IndexedDBModel.Index.prototype = { | |
get keyPathString() | |
{ | |
return WebInspector.IndexedDBModel.keyPathStringFromIDBKeyPath(this.keyPath); | |
} | |
} | |
WebInspector.Spectrum = function() | |
{ | |
this._popover = new WebInspector.Popover(); | |
this._popover.setCanShrink(false); | |
this._popover.element.addEventListener("mousedown", consumeEvent, false); | |
this._containerElement = document.createElement('div'); | |
this._containerElement.className = "spectrum-container"; | |
this._containerElement.tabIndex = 0; | |
this._containerElement.addEventListener("keydown", this._onKeyDown.bind(this), false); | |
var topElement = this._containerElement.createChild("div", "spectrum-top"); | |
topElement.createChild("div", "spectrum-fill"); | |
var topInnerElement = topElement.createChild("div", "spectrum-top-inner fill"); | |
this._draggerElement = topInnerElement.createChild("div", "spectrum-color"); | |
this._dragHelperElement = this._draggerElement.createChild("div", "spectrum-sat fill").createChild("div", "spectrum-val fill").createChild("div", "spectrum-dragger"); | |
this._sliderElement = topInnerElement.createChild("div", "spectrum-hue"); | |
this.slideHelper = this._sliderElement.createChild("div", "spectrum-slider"); | |
var rangeContainer = this._containerElement.createChild("div", "spectrum-range-container"); | |
var alphaLabel = rangeContainer.createChild("label"); | |
alphaLabel.textContent = WebInspector.UIString("\u03B1:"); | |
this._alphaElement = rangeContainer.createChild("input", "spectrum-range"); | |
this._alphaElement.setAttribute("type", "range"); | |
this._alphaElement.setAttribute("min", "0"); | |
this._alphaElement.setAttribute("max", "100"); | |
this._alphaElement.addEventListener("change", alphaDrag.bind(this), false); | |
var swatchElement = document.createElement("span"); | |
swatchElement.className = "swatch"; | |
this._swatchInnerElement = swatchElement.createChild("span", "swatch-inner"); | |
var displayContainer = this._containerElement.createChild("div"); | |
displayContainer.appendChild(swatchElement); | |
this._displayElement = displayContainer.createChild("span", "source-code spectrum-display-value"); | |
WebInspector.Spectrum.draggable(this._sliderElement, hueDrag.bind(this)); | |
WebInspector.Spectrum.draggable(this._draggerElement, colorDrag.bind(this), colorDragStart.bind(this)); | |
function hueDrag(element, dragX, dragY) | |
{ | |
this.hsv[0] = (dragY / this.slideHeight); | |
this._onchange(); | |
} | |
var initialHelperOffset; | |
function colorDragStart(element, dragX, dragY) | |
{ | |
initialHelperOffset = { x: this._dragHelperElement.offsetLeft, y: this._dragHelperElement.offsetTop }; | |
} | |
function colorDrag(element, dragX, dragY, event) | |
{ | |
if (event.shiftKey) { | |
if (Math.abs(dragX - initialHelperOffset.x) >= Math.abs(dragY - initialHelperOffset.y)) | |
dragY = initialHelperOffset.y; | |
else | |
dragX = initialHelperOffset.x; | |
} | |
this.hsv[1] = dragX / this.dragWidth; | |
this.hsv[2] = (this.dragHeight - dragY) / this.dragHeight; | |
this._onchange(); | |
} | |
function alphaDrag() | |
{ | |
this.hsv[3] = this._alphaElement.value / 100; | |
this._onchange(); | |
} | |
this._hideProxy = this.hide.bind(this, true); | |
}; | |
WebInspector.Spectrum.Events = { | |
ColorChanged: "ColorChanged", | |
Hidden: "Hidden" | |
}; | |
WebInspector.Spectrum.hsvaToRGBA = function(h, s, v, a) | |
{ | |
var r, g, b; | |
var i = Math.floor(h * 6); | |
var f = h * 6 - i; | |
var p = v * (1 - s); | |
var q = v * (1 - f * s); | |
var t = v * (1 - (1 - f) * s); | |
switch(i % 6) { | |
case 0: | |
r = v, g = t, b = p; | |
break; | |
case 1: | |
r = q, g = v, b = p; | |
break; | |
case 2: | |
r = p, g = v, b = t; | |
break; | |
case 3: | |
r = p, g = q, b = v; | |
break; | |
case 4: | |
r = t, g = p, b = v; | |
break; | |
case 5: | |
r = v, g = p, b = q; | |
break; | |
} | |
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a]; | |
}; | |
WebInspector.Spectrum.rgbaToHSVA = function(r, g, b, a) | |
{ | |
r = r / 255; | |
g = g / 255; | |
b = b / 255; | |
var max = Math.max(r, g, b); | |
var min = Math.min(r, g, b); | |
var h; | |
var s; | |
var v = max; | |
var d = max - min; | |
s = max ? d / max : 0; | |
if(max === min) { | |
h = 0; | |
} else { | |
switch(max) { | |
case r: | |
h = (g - b) / d + (g < b ? 6 : 0); | |
break; | |
case g: | |
h = (b - r) / d + 2; | |
break; | |
case b: | |
h = (r - g) / d + 4; | |
break; | |
} | |
h /= 6; | |
} | |
return [h, s, v, a]; | |
}; | |
WebInspector.Spectrum.draggable = function(element, onmove, onstart, onstop) { | |
var doc = document; | |
var dragging; | |
var offset; | |
var scrollOffset; | |
var maxHeight; | |
var maxWidth; | |
function consume(e) | |
{ | |
e.consume(true); | |
} | |
function move(e) | |
{ | |
if (dragging) { | |
var dragX = Math.max(0, Math.min(e.pageX - offset.left + scrollOffset.left, maxWidth)); | |
var dragY = Math.max(0, Math.min(e.pageY - offset.top + scrollOffset.top, maxHeight)); | |
if (onmove) | |
onmove(element, dragX, dragY, e); | |
} | |
} | |
function start(e) | |
{ | |
var rightClick = e.which ? (e.which === 3) : (e.button === 2); | |
if (!rightClick && !dragging) { | |
if (onstart) | |
onstart(element, e) | |
dragging = true; | |
maxHeight = element.clientHeight; | |
maxWidth = element.clientWidth; | |
scrollOffset = element.scrollOffset(); | |
offset = element.totalOffset(); | |
doc.addEventListener("selectstart", consume, false); | |
doc.addEventListener("dragstart", consume, false); | |
doc.addEventListener("mousemove", move, false); | |
doc.addEventListener("mouseup", stop, false); | |
move(e); | |
consume(e); | |
} | |
} | |
function stop(e) | |
{ | |
if (dragging) { | |
doc.removeEventListener("selectstart", consume, false); | |
doc.removeEventListener("dragstart", consume, false); | |
doc.removeEventListener("mousemove", move, false); | |
doc.removeEventListener("mouseup", stop, false); | |
if (onstop) | |
onstop(element, e); | |
} | |
dragging = false; | |
} | |
element.addEventListener("mousedown", start, false); | |
}; | |
WebInspector.Spectrum.prototype = { | |
set color(color) | |
{ | |
var rgba = (color.rgba || color.rgb).slice(0); | |
if (rgba.length === 3) | |
rgba[3] = 1; | |
this.hsv = WebInspector.Spectrum.rgbaToHSVA(rgba[0], rgba[1], rgba[2], rgba[3]); | |
}, | |
get color() | |
{ | |
var rgba = WebInspector.Spectrum.hsvaToRGBA(this.hsv[0], this.hsv[1], this.hsv[2], this.hsv[3]); | |
var color; | |
if (rgba[3] === 1) | |
color = WebInspector.Color.fromRGB(rgba[0], rgba[1], rgba[2]); | |
else | |
color = WebInspector.Color.fromRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); | |
var colorValue = color.toString(this.outputColorFormat); | |
if (!colorValue) | |
colorValue = color.toString(); | |
return new WebInspector.Color(colorValue); | |
}, | |
get outputColorFormat() | |
{ | |
var cf = WebInspector.Color.Format; | |
var format = this._originalFormat; | |
if (this.hsv[3] === 1) { | |
if (format === cf.RGBA) | |
format = cf.RGB; | |
else if (format === cf.HSLA) | |
format = cf.HSL; | |
} else { | |
if (format === cf.HSL || format === cf.HSLA) | |
format = cf.HSLA; | |
else | |
format = cf.RGBA; | |
} | |
return format; | |
}, | |
get colorHueOnly() | |
{ | |
var rgba = WebInspector.Spectrum.hsvaToRGBA(this.hsv[0], 1, 1, 1); | |
return WebInspector.Color.fromRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); | |
}, | |
set displayText(text) | |
{ | |
this._displayElement.textContent = text; | |
}, | |
get visible() | |
{ | |
return this._popover.visible; | |
}, | |
_onchange: function() | |
{ | |
this._updateUI(); | |
this.dispatchEventToListeners(WebInspector.Spectrum.Events.ColorChanged, this.color); | |
}, | |
_updateHelperLocations: function() | |
{ | |
var h = this.hsv[0]; | |
var s = this.hsv[1]; | |
var v = this.hsv[2]; | |
var dragX = s * this.dragWidth; | |
var dragY = this.dragHeight - (v * this.dragHeight); | |
dragX = Math.max(-this._dragHelperElementHeight, | |
Math.min(this.dragWidth - this._dragHelperElementHeight, dragX - this._dragHelperElementHeight)); | |
dragY = Math.max(-this._dragHelperElementHeight, | |
Math.min(this.dragHeight - this._dragHelperElementHeight, dragY - this._dragHelperElementHeight)); | |
this._dragHelperElement.positionAt(dragX, dragY); | |
var slideY = (h * this.slideHeight) - this.slideHelperHeight; | |
this.slideHelper.style.top = slideY + "px"; | |
this._alphaElement.value = this.hsv[3] * 100; | |
}, | |
_updateUI: function() | |
{ | |
this._updateHelperLocations(); | |
var rgb = (this.color.rgba || this.color.rgb).slice(0); | |
if (rgb.length === 3) | |
rgb[3] = 1; | |
var rgbHueOnly = this.colorHueOnly.rgb; | |
var flatColor = "rgb(" + rgbHueOnly[0] + ", " + rgbHueOnly[1] + ", " + rgbHueOnly[2] + ")"; | |
var fullColor = "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")"; | |
this._draggerElement.style.backgroundColor = flatColor; | |
this._swatchInnerElement.style.backgroundColor = fullColor; | |
this._alphaElement.value = this.hsv[3] * 100; | |
}, | |
toggle: function(element, color, format) | |
{ | |
if (this.visible) | |
this.hide(true); | |
else | |
this.show(element, color, format); | |
return this.visible; | |
}, | |
show: function(element, color, format) | |
{ | |
if (this.visible) { | |
if (this.anchorElement === element) | |
return false; | |
this.hide(true); | |
} | |
this.reposition(element); | |
this.anchorElement = element; | |
document.addEventListener("mousedown", this._hideProxy, false); | |
window.addEventListener("blur", this._hideProxy, false); | |
this.slideHeight = this._sliderElement.offsetHeight; | |
this.dragWidth = this._draggerElement.offsetWidth; | |
this.dragHeight = this._draggerElement.offsetHeight; | |
this._dragHelperElementHeight = this._dragHelperElement.offsetHeight / 2; | |
this.slideHelperHeight = this.slideHelper.offsetHeight / 2; | |
this.color = color; | |
this._originalFormat = format || color.format; | |
this._updateUI(); | |
return true; | |
}, | |
reposition: function(element) | |
{ | |
if (!this._previousFocusElement) | |
this._previousFocusElement = WebInspector.currentFocusElement(); | |
this._popover.show(this._containerElement, element); | |
WebInspector.setCurrentFocusElement(this._containerElement); | |
}, | |
hide: function(commitEdit) | |
{ | |
this._popover.hide(); | |
document.removeEventListener("mousedown", this._hideProxy, false); | |
window.removeEventListener("blur", this._hideProxy, false); | |
this.dispatchEventToListeners(WebInspector.Spectrum.Events.Hidden, !!commitEdit); | |
WebInspector.setCurrentFocusElement(this._previousFocusElement); | |
delete this._previousFocusElement; | |
delete this.anchorElement; | |
}, | |
_onKeyDown: function(event) | |
{ | |
if (event.keyIdentifier === "Enter") { | |
this.hide(true); | |
event.consume(true); | |
return; | |
} | |
if (event.keyIdentifier === "U+001B") { | |
this.hide(false); | |
event.consume(true); | |
} | |
} | |
} | |
WebInspector.Spectrum.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.SidebarPane = function(title) | |
{ | |
this.element = document.createElement("div"); | |
this.element.className = "pane"; | |
this.titleElement = document.createElement("div"); | |
this.titleElement.className = "title"; | |
this.titleElement.tabIndex = 0; | |
this.titleElement.addEventListener("click", this.toggleExpanded.bind(this), false); | |
this.titleElement.addEventListener("keydown", this._onTitleKeyDown.bind(this), false); | |
this.bodyElement = document.createElement("div"); | |
this.bodyElement.className = "body"; | |
this.element.appendChild(this.titleElement); | |
this.element.appendChild(this.bodyElement); | |
this.title = title; | |
this.growbarVisible = false; | |
this.expanded = false; | |
} | |
WebInspector.SidebarPane.prototype = { | |
get title() | |
{ | |
return this._title; | |
}, | |
set title(x) | |
{ | |
if (this._title === x) | |
return; | |
this._title = x; | |
this.titleElement.textContent = x; | |
}, | |
get growbarVisible() | |
{ | |
return this._growbarVisible; | |
}, | |
set growbarVisible(x) | |
{ | |
if (this._growbarVisible === x) | |
return; | |
this._growbarVisible = x; | |
if (x && !this._growbarElement) { | |
this._growbarElement = document.createElement("div"); | |
this._growbarElement.className = "growbar"; | |
this.element.appendChild(this._growbarElement); | |
} else if (!x && this._growbarElement) { | |
if (this._growbarElement.parentNode) | |
this._growbarElement.parentNode(this._growbarElement); | |
delete this._growbarElement; | |
} | |
}, | |
get expanded() | |
{ | |
return this._expanded; | |
}, | |
set expanded(x) | |
{ | |
if (x) | |
this.expand(); | |
else | |
this.collapse(); | |
}, | |
expand: function() | |
{ | |
if (this._expanded) | |
return; | |
this._expanded = true; | |
this.element.addStyleClass("expanded"); | |
this.onexpand(); | |
}, | |
onexpand: function() | |
{ | |
}, | |
collapse: function() | |
{ | |
if (!this._expanded) | |
return; | |
this._expanded = false; | |
this.element.removeStyleClass("expanded"); | |
}, | |
toggleExpanded: function() | |
{ | |
this.expanded = !this.expanded; | |
}, | |
_onTitleKeyDown: function(event) | |
{ | |
if (isEnterKey(event) || event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) | |
this.toggleExpanded(); | |
} | |
} | |
WebInspector.SidebarPane.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.ElementsTreeOutline = function(omitRootDOMNode, selectEnabled, showInElementsPanelEnabled, contextMenuCallback, setPseudoClassCallback) | |
{ | |
this.element = document.createElement("ol"); | |
this.element.addEventListener("mousedown", this._onmousedown.bind(this), false); | |
this.element.addEventListener("mousemove", this._onmousemove.bind(this), false); | |
this.element.addEventListener("mouseout", this._onmouseout.bind(this), false); | |
this.element.addEventListener("dragstart", this._ondragstart.bind(this), false); | |
this.element.addEventListener("dragover", this._ondragover.bind(this), false); | |
this.element.addEventListener("dragleave", this._ondragleave.bind(this), false); | |
this.element.addEventListener("drop", this._ondrop.bind(this), false); | |
this.element.addEventListener("dragend", this._ondragend.bind(this), false); | |
TreeOutline.call(this, this.element); | |
this._includeRootDOMNode = !omitRootDOMNode; | |
this._selectEnabled = selectEnabled; | |
this._showInElementsPanelEnabled = showInElementsPanelEnabled; | |
this._rootDOMNode = null; | |
this._selectDOMNode = null; | |
this._eventSupport = new WebInspector.Object(); | |
this._editing = false; | |
this._visible = false; | |
this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true); | |
this._contextMenuCallback = contextMenuCallback; | |
this._setPseudoClassCallback = setPseudoClassCallback; | |
this._createNodeDecorators(); | |
} | |
WebInspector.ElementsTreeOutline.Events = { | |
SelectedNodeChanged: "SelectedNodeChanged" | |
} | |
WebInspector.ElementsTreeOutline.MappedCharToEntity = { | |
"\u00a0": "nbsp", | |
"\u2002": "ensp", | |
"\u2003": "emsp", | |
"\u2009": "thinsp", | |
"\u200b": "#8203", | |
"\u200c": "zwnj", | |
"\u200d": "zwj", | |
"\u200e": "lrm", | |
"\u200f": "rlm", | |
"\u202a": "#8234", | |
"\u202b": "#8235", | |
"\u202c": "#8236", | |
"\u202d": "#8237", | |
"\u202e": "#8238" | |
} | |
WebInspector.ElementsTreeOutline.prototype = { | |
_createNodeDecorators: function() | |
{ | |
this._nodeDecorators = []; | |
this._nodeDecorators.push(new WebInspector.ElementsTreeOutline.PseudoStateDecorator()); | |
}, | |
wireToDomAgent: function() | |
{ | |
this._elementsTreeUpdater = new WebInspector.ElementsTreeUpdater(this); | |
}, | |
setVisible: function(visible) | |
{ | |
this._visible = visible; | |
if (!this._visible) | |
return; | |
this._updateModifiedNodes(); | |
if (this._selectedDOMNode) | |
this._revealAndSelectNode(this._selectedDOMNode, false); | |
}, | |
addEventListener: function(eventType, listener, thisObject) | |
{ | |
this._eventSupport.addEventListener(eventType, listener, thisObject); | |
}, | |
removeEventListener: function(eventType, listener, thisObject) | |
{ | |
this._eventSupport.removeEventListener(eventType, listener, thisObject); | |
}, | |
get rootDOMNode() | |
{ | |
return this._rootDOMNode; | |
}, | |
set rootDOMNode(x) | |
{ | |
if (this._rootDOMNode === x) | |
return; | |
this._rootDOMNode = x; | |
this._isXMLMimeType = x && x.isXMLNode(); | |
this.update(); | |
}, | |
get isXMLMimeType() | |
{ | |
return this._isXMLMimeType; | |
}, | |
selectedDOMNode: function() | |
{ | |
return this._selectedDOMNode; | |
}, | |
selectDOMNode: function(node, focus) | |
{ | |
if (this._selectedDOMNode === node) { | |
this._revealAndSelectNode(node, !focus); | |
return; | |
} | |
this._selectedDOMNode = node; | |
this._revealAndSelectNode(node, !focus); | |
if (this._selectedDOMNode === node) | |
this._selectedNodeChanged(); | |
}, | |
get editing() | |
{ | |
return this._editing; | |
}, | |
update: function() | |
{ | |
var selectedNode = this.selectedTreeElement ? this.selectedTreeElement.representedObject : null; | |
this.removeChildren(); | |
if (!this.rootDOMNode) | |
return; | |
var treeElement; | |
if (this._includeRootDOMNode) { | |
treeElement = new WebInspector.ElementsTreeElement(this.rootDOMNode); | |
treeElement.selectable = this._selectEnabled; | |
this.appendChild(treeElement); | |
} else { | |
var node = this.rootDOMNode.firstChild; | |
while (node) { | |
treeElement = new WebInspector.ElementsTreeElement(node); | |
treeElement.selectable = this._selectEnabled; | |
this.appendChild(treeElement); | |
node = node.nextSibling; | |
} | |
} | |
if (selectedNode) | |
this._revealAndSelectNode(selectedNode, true); | |
}, | |
updateSelection: function() | |
{ | |
if (!this.selectedTreeElement) | |
return; | |
var element = this.treeOutline.selectedTreeElement; | |
element.updateSelection(); | |
}, | |
updateOpenCloseTags: function(node) | |
{ | |
var treeElement = this.findTreeElement(node); | |
if (treeElement) | |
treeElement.updateTitle(); | |
var children = treeElement.children; | |
var closingTagElement = children[children.length - 1]; | |
if (closingTagElement && closingTagElement._elementCloseTag) | |
closingTagElement.updateTitle(); | |
}, | |
_selectedNodeChanged: function() | |
{ | |
this._eventSupport.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedDOMNode); | |
}, | |
findTreeElement: function(node) | |
{ | |
function isAncestorNode(ancestor, node) | |
{ | |
return ancestor.isAncestor(node); | |
} | |
function parentNode(node) | |
{ | |
return node.parentNode; | |
} | |
var treeElement = TreeOutline.prototype.findTreeElement.call(this, node, isAncestorNode, parentNode); | |
if (!treeElement && node.nodeType() === Node.TEXT_NODE) { | |
treeElement = TreeOutline.prototype.findTreeElement.call(this, node.parentNode, isAncestorNode, parentNode); | |
} | |
return treeElement; | |
}, | |
createTreeElementFor: function(node) | |
{ | |
var treeElement = this.findTreeElement(node); | |
if (treeElement) | |
return treeElement; | |
if (!node.parentNode) | |
return null; | |
treeElement = this.createTreeElementFor(node.parentNode); | |
if (treeElement && treeElement.showChild(node.index)) | |
return treeElement.children[node.index]; | |
return null; | |
}, | |
set suppressRevealAndSelect(x) | |
{ | |
if (this._suppressRevealAndSelect === x) | |
return; | |
this._suppressRevealAndSelect = x; | |
}, | |
_revealAndSelectNode: function(node, omitFocus) | |
{ | |
if (!node || this._suppressRevealAndSelect) | |
return; | |
var treeElement = this.createTreeElementFor(node); | |
if (!treeElement) | |
return; | |
treeElement.revealAndSelect(omitFocus); | |
}, | |
_treeElementFromEvent: function(event) | |
{ | |
var scrollContainer = this.element.parentElement; | |
var x = scrollContainer.totalOffsetLeft() + scrollContainer.offsetWidth - 36; | |
var y = event.pageY; | |
var elementUnderMouse = this.treeElementFromPoint(x, y); | |
var elementAboveMouse = this.treeElementFromPoint(x, y - 2); | |
var element; | |
if (elementUnderMouse === elementAboveMouse) | |
element = elementUnderMouse; | |
else | |
element = this.treeElementFromPoint(x, y + 2); | |
return element; | |
}, | |
_onmousedown: function(event) | |
{ | |
var element = this._treeElementFromEvent(event); | |
if (!element || element.isEventWithinDisclosureTriangle(event)) | |
return; | |
element.select(); | |
}, | |
_onmousemove: function(event) | |
{ | |
var element = this._treeElementFromEvent(event); | |
if (element && this._previousHoveredElement === element) | |
return; | |
if (this._previousHoveredElement) { | |
this._previousHoveredElement.hovered = false; | |
delete this._previousHoveredElement; | |
} | |
if (element) { | |
element.hovered = true; | |
this._previousHoveredElement = element; | |
} | |
WebInspector.domAgent.highlightDOMNode(element ? element.representedObject.id : 0); | |
}, | |
_onmouseout: function(event) | |
{ | |
var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); | |
if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.element)) | |
return; | |
if (this._previousHoveredElement) { | |
this._previousHoveredElement.hovered = false; | |
delete this._previousHoveredElement; | |
} | |
WebInspector.domAgent.hideDOMNodeHighlight(); | |
}, | |
_ondragstart: function(event) | |
{ | |
var treeElement = this._treeElementFromEvent(event); | |
if (!treeElement) | |
return false; | |
if (!this._isValidDragSourceOrTarget(treeElement)) | |
return false; | |
if (treeElement.representedObject.nodeName() === "BODY" || treeElement.representedObject.nodeName() === "HEAD") | |
return false; | |
event.dataTransfer.setData("text/plain", treeElement.listItemElement.textContent); | |
event.dataTransfer.effectAllowed = "copyMove"; | |
this._treeElementBeingDragged = treeElement; | |
WebInspector.domAgent.hideDOMNodeHighlight(); | |
return true; | |
}, | |
_ondragover: function(event) | |
{ | |
if (!this._treeElementBeingDragged) | |
return false; | |
var treeElement = this._treeElementFromEvent(event); | |
if (!this._isValidDragSourceOrTarget(treeElement)) | |
return false; | |
var node = treeElement.representedObject; | |
while (node) { | |
if (node === this._treeElementBeingDragged.representedObject) | |
return false; | |
node = node.parentNode; | |
} | |
treeElement.updateSelection(); | |
treeElement.listItemElement.addStyleClass("elements-drag-over"); | |
this._dragOverTreeElement = treeElement; | |
event.preventDefault(); | |
event.dataTransfer.dropEffect = 'move'; | |
return false; | |
}, | |
_ondragleave: function(event) | |
{ | |
this._clearDragOverTreeElementMarker(); | |
event.preventDefault(); | |
return false; | |
}, | |
_isValidDragSourceOrTarget: function(treeElement) | |
{ | |
if (!treeElement) | |
return false; | |
var node = treeElement.representedObject; | |
if (!(node instanceof WebInspector.DOMNode)) | |
return false; | |
if (!node.parentNode || node.parentNode.nodeType() !== Node.ELEMENT_NODE) | |
return false; | |
return true; | |
}, | |
_ondrop: function(event) | |
{ | |
event.preventDefault(); | |
var treeElement = this._treeElementFromEvent(event); | |
if (treeElement) | |
this._doMove(treeElement); | |
}, | |
_doMove: function(treeElement) | |
{ | |
if (!this._treeElementBeingDragged) | |
return; | |
var parentNode; | |
var anchorNode; | |
if (treeElement._elementCloseTag) { | |
parentNode = treeElement.representedObject; | |
} else { | |
var dragTargetNode = treeElement.representedObject; | |
parentNode = dragTargetNode.parentNode; | |
anchorNode = dragTargetNode; | |
} | |
var wasExpanded = this._treeElementBeingDragged.expanded; | |
this._treeElementBeingDragged.representedObject.moveTo(parentNode, anchorNode, this._selectNodeAfterEdit.bind(this, null, wasExpanded)); | |
delete this._treeElementBeingDragged; | |
}, | |
_ondragend: function(event) | |
{ | |
event.preventDefault(); | |
this._clearDragOverTreeElementMarker(); | |
delete this._treeElementBeingDragged; | |
}, | |
_clearDragOverTreeElementMarker: function() | |
{ | |
if (this._dragOverTreeElement) { | |
this._dragOverTreeElement.updateSelection(); | |
this._dragOverTreeElement.listItemElement.removeStyleClass("elements-drag-over"); | |
delete this._dragOverTreeElement; | |
} | |
}, | |
_contextMenuEventFired: function(event) | |
{ | |
if (!this._showInElementsPanelEnabled) | |
return; | |
var treeElement = this._treeElementFromEvent(event); | |
if (!treeElement) | |
return; | |
function focusElement() | |
{ | |
WebInspector.domAgent.inspectElement(treeElement.representedObject.id); | |
} | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendItem(WebInspector.UIString("Reveal in Elements Panel"), focusElement.bind(this)); | |
contextMenu.show(event); | |
}, | |
populateContextMenu: function(contextMenu, event) | |
{ | |
var treeElement = this._treeElementFromEvent(event); | |
if (!treeElement) | |
return false; | |
var isTag = treeElement.representedObject.nodeType() === Node.ELEMENT_NODE; | |
var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node"); | |
if (textNode && textNode.hasStyleClass("bogus")) | |
textNode = null; | |
var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-comment"); | |
contextMenu.appendApplicableItems(event.target); | |
if (textNode) { | |
contextMenu.appendSeparator(); | |
treeElement._populateTextContextMenu(contextMenu, textNode); | |
} else if (isTag) { | |
contextMenu.appendSeparator(); | |
treeElement._populateTagContextMenu(contextMenu, event); | |
} else if (commentNode) { | |
contextMenu.appendSeparator(); | |
treeElement._populateNodeContextMenu(contextMenu, textNode); | |
} | |
}, | |
adjustCollapsedRange: function() | |
{ | |
}, | |
_updateModifiedNodes: function() | |
{ | |
if (this._elementsTreeUpdater) | |
this._elementsTreeUpdater._updateModifiedNodes(); | |
}, | |
_populateContextMenu: function(contextMenu, node) | |
{ | |
if (this._contextMenuCallback) | |
this._contextMenuCallback(contextMenu, node); | |
}, | |
handleShortcut: function(event) | |
{ | |
var node = this.selectedDOMNode(); | |
var treeElement = this.getCachedTreeElement(node); | |
if (!node || !treeElement) | |
return; | |
if (event.keyIdentifier === "F2") { | |
this._toggleEditAsHTML(node); | |
return; | |
} | |
if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && node.parentNode) { | |
if (event.keyIdentifier === "Up" && node.previousSibling) { | |
node.moveTo(node.parentNode, node.previousSibling, this._selectNodeAfterEdit.bind(this, null, treeElement.expanded)); | |
return; | |
} | |
if (event.keyIdentifier === "Down" && node.nextSibling) { | |
node.moveTo(node.parentNode, node.nextSibling.nextSibling, this._selectNodeAfterEdit.bind(this, null, treeElement.expanded)); | |
return; | |
} | |
} | |
}, | |
_toggleEditAsHTML: function(node) | |
{ | |
var treeElement = this.getCachedTreeElement(node); | |
if (!treeElement) | |
return; | |
if (treeElement._editing && treeElement._htmlEditElement && WebInspector.isBeingEdited(treeElement._htmlEditElement)) | |
treeElement._editing.commit(); | |
else | |
treeElement._editAsHTML(); | |
}, | |
_selectNodeAfterEdit: function(fallbackNode, wasExpanded, error, nodeId) | |
{ | |
if (error) | |
return; | |
this._updateModifiedNodes(); | |
var newNode = WebInspector.domAgent.nodeForId(nodeId) || fallbackNode; | |
if (!newNode) | |
return; | |
this.selectDOMNode(newNode, true); | |
var newTreeItem = this.findTreeElement(newNode); | |
if (wasExpanded) { | |
if (newTreeItem) | |
newTreeItem.expand(); | |
} | |
return newTreeItem; | |
} | |
} | |
WebInspector.ElementsTreeOutline.prototype.__proto__ = TreeOutline.prototype; | |
WebInspector.ElementsTreeOutline.ElementDecorator = function() | |
{ | |
} | |
WebInspector.ElementsTreeOutline.ElementDecorator.prototype = { | |
decorate: function(node) | |
{ | |
}, | |
decorateAncestor: function(node) | |
{ | |
} | |
} | |
WebInspector.ElementsTreeOutline.PseudoStateDecorator = function() | |
{ | |
WebInspector.ElementsTreeOutline.ElementDecorator.call(this); | |
} | |
WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName = "pseudoState"; | |
WebInspector.ElementsTreeOutline.PseudoStateDecorator.prototype = { | |
decorate: function(node) | |
{ | |
if (node.nodeType() !== Node.ELEMENT_NODE) | |
return null; | |
var propertyValue = node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName); | |
if (!propertyValue) | |
return null; | |
return WebInspector.UIString("Element state: %s", ":" + propertyValue.join(", :")); | |
}, | |
decorateAncestor: function(node) | |
{ | |
if (node.nodeType() !== Node.ELEMENT_NODE) | |
return null; | |
var descendantCount = node.descendantUserPropertyCount(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName); | |
if (!descendantCount) | |
return null; | |
if (descendantCount === 1) | |
return WebInspector.UIString("%d descendant with forced state", descendantCount); | |
return WebInspector.UIString("%d descendants with forced state", descendantCount); | |
} | |
} | |
WebInspector.ElementsTreeOutline.PseudoStateDecorator.prototype.__proto__ = WebInspector.ElementsTreeOutline.ElementDecorator.prototype; | |
WebInspector.ElementsTreeElement = function(node, elementCloseTag) | |
{ | |
this._elementCloseTag = elementCloseTag; | |
var hasChildrenOverride = !elementCloseTag && node.hasChildNodes() && !this._showInlineText(node); | |
TreeElement.call(this, "", node, hasChildrenOverride); | |
if (this.representedObject.nodeType() == Node.ELEMENT_NODE && !elementCloseTag) | |
this._canAddAttributes = true; | |
this._searchQuery = null; | |
this._expandedChildrenLimit = WebInspector.ElementsTreeElement.InitialChildrenLimit; | |
} | |
WebInspector.ElementsTreeElement.InitialChildrenLimit = 500; | |
WebInspector.ElementsTreeElement.ForbiddenClosingTagElements = [ | |
"area", "base", "basefont", "br", "canvas", "col", "command", "embed", "frame", | |
"hr", "img", "input", "isindex", "keygen", "link", "meta", "param", "source" | |
].keySet(); | |
WebInspector.ElementsTreeElement.EditTagBlacklist = [ | |
"html", "head", "body" | |
].keySet(); | |
WebInspector.ElementsTreeElement.prototype = { | |
highlightSearchResults: function(searchQuery) | |
{ | |
if (this._searchQuery !== searchQuery) { | |
this._updateSearchHighlight(false); | |
delete this._highlightResult; | |
} | |
this._searchQuery = searchQuery; | |
this._searchHighlightsVisible = true; | |
this.updateTitle(true); | |
}, | |
hideSearchHighlights: function() | |
{ | |
delete this._searchHighlightsVisible; | |
this._updateSearchHighlight(false); | |
}, | |
_updateSearchHighlight: function(show) | |
{ | |
if (!this._highlightResult) | |
return; | |
function updateEntryShow(entry) | |
{ | |
switch (entry.type) { | |
case "added": | |
entry.parent.insertBefore(entry.node, entry.nextSibling); | |
break; | |
case "changed": | |
entry.node.textContent = entry.newText; | |
break; | |
} | |
} | |
function updateEntryHide(entry) | |
{ | |
switch (entry.type) { | |
case "added": | |
if (entry.node.parentElement) | |
entry.node.parentElement.removeChild(entry.node); | |
break; | |
case "changed": | |
entry.node.textContent = entry.oldText; | |
break; | |
} | |
} | |
if (show) { | |
for (var i = 0, size = this._highlightResult.length; i < size; ++i) | |
updateEntryShow(this._highlightResult[i]); | |
} else { | |
for (var i = (this._highlightResult.length - 1); i >= 0; --i) | |
updateEntryHide(this._highlightResult[i]); | |
} | |
}, | |
get hovered() | |
{ | |
return this._hovered; | |
}, | |
set hovered(x) | |
{ | |
if (this._hovered === x) | |
return; | |
this._hovered = x; | |
if (this.listItemElement) { | |
if (x) { | |
this.updateSelection(); | |
this.listItemElement.addStyleClass("hovered"); | |
} else { | |
this.listItemElement.removeStyleClass("hovered"); | |
} | |
} | |
}, | |
get expandedChildrenLimit() | |
{ | |
return this._expandedChildrenLimit; | |
}, | |
set expandedChildrenLimit(x) | |
{ | |
if (this._expandedChildrenLimit === x) | |
return; | |
this._expandedChildrenLimit = x; | |
if (this.treeOutline && !this._updateChildrenInProgress) | |
this._updateChildren(true); | |
}, | |
get expandedChildCount() | |
{ | |
var count = this.children.length; | |
if (count && this.children[count - 1]._elementCloseTag) | |
count--; | |
if (count && this.children[count - 1].expandAllButton) | |
count--; | |
return count; | |
}, | |
showChild: function(index) | |
{ | |
if (this._elementCloseTag) | |
return; | |
if (index >= this.expandedChildrenLimit) { | |
this._expandedChildrenLimit = index + 1; | |
this._updateChildren(true); | |
} | |
return this.expandedChildCount > index; | |
}, | |
updateSelection: function() | |
{ | |
var listItemElement = this.listItemElement; | |
if (!listItemElement) | |
return; | |
if (!this._readyToUpdateSelection) { | |
if (document.body.offsetWidth > 0) | |
this._readyToUpdateSelection = true; | |
else { | |
return; | |
} | |
} | |
if (!this.selectionElement) { | |
this.selectionElement = document.createElement("div"); | |
this.selectionElement.className = "selection selected"; | |
listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild); | |
} | |
this.selectionElement.style.height = listItemElement.offsetHeight + "px"; | |
}, | |
onattach: function() | |
{ | |
if (this._hovered) { | |
this.updateSelection(); | |
this.listItemElement.addStyleClass("hovered"); | |
} | |
this.updateTitle(); | |
this._preventFollowingLinksOnDoubleClick(); | |
this.listItemElement.draggable = true; | |
}, | |
_preventFollowingLinksOnDoubleClick: function() | |
{ | |
var links = this.listItemElement.querySelectorAll("li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link"); | |
if (!links) | |
return; | |
for (var i = 0; i < links.length; ++i) | |
links[i].preventFollowOnDoubleClick = true; | |
}, | |
onpopulate: function() | |
{ | |
if (this.children.length || this._showInlineText(this.representedObject) || this._elementCloseTag) | |
return; | |
this.updateChildren(); | |
}, | |
updateChildren: function(fullRefresh) | |
{ | |
if (this._elementCloseTag) | |
return; | |
this.representedObject.getChildNodes(this._updateChildren.bind(this, fullRefresh)); | |
}, | |
insertChildElement: function(child, index, closingTag) | |
{ | |
var newElement = new WebInspector.ElementsTreeElement(child, closingTag); | |
newElement.selectable = this.treeOutline._selectEnabled; | |
this.insertChild(newElement, index); | |
return newElement; | |
}, | |
moveChild: function(child, targetIndex) | |
{ | |
var wasSelected = child.selected; | |
this.removeChild(child); | |
this.insertChild(child, targetIndex); | |
if (wasSelected) | |
child.select(); | |
}, | |
_updateChildren: function(fullRefresh) | |
{ | |
if (this._updateChildrenInProgress || !this.treeOutline._visible) | |
return; | |
this._updateChildrenInProgress = true; | |
var selectedNode = this.treeOutline.selectedDOMNode(); | |
var originalScrollTop = 0; | |
if (fullRefresh) { | |
var treeOutlineContainerElement = this.treeOutline.element.parentNode; | |
originalScrollTop = treeOutlineContainerElement.scrollTop; | |
var selectedTreeElement = this.treeOutline.selectedTreeElement; | |
if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) | |
this.select(); | |
this.removeChildren(); | |
} | |
var treeElement = this; | |
var treeChildIndex = 0; | |
var elementToSelect; | |
function updateChildrenOfNode(node) | |
{ | |
var treeOutline = treeElement.treeOutline; | |
var child = node.firstChild; | |
while (child) { | |
var currentTreeElement = treeElement.children[treeChildIndex]; | |
if (!currentTreeElement || currentTreeElement.representedObject !== child) { | |
var existingTreeElement = null; | |
for (var i = (treeChildIndex + 1), size = treeElement.expandedChildCount; i < size; ++i) { | |
if (treeElement.children[i].representedObject === child) { | |
existingTreeElement = treeElement.children[i]; | |
break; | |
} | |
} | |
if (existingTreeElement && existingTreeElement.parent === treeElement) { | |
treeElement.moveChild(existingTreeElement, treeChildIndex); | |
} else { | |
if (treeChildIndex < treeElement.expandedChildrenLimit) { | |
var newElement = treeElement.insertChildElement(child, treeChildIndex); | |
if (child === selectedNode) | |
elementToSelect = newElement; | |
if (treeElement.expandedChildCount > treeElement.expandedChildrenLimit) | |
treeElement.expandedChildrenLimit++; | |
} | |
} | |
} | |
child = child.nextSibling; | |
++treeChildIndex; | |
} | |
} | |
for (var i = (this.children.length - 1); i >= 0; --i) { | |
var currentChild = this.children[i]; | |
var currentNode = currentChild.representedObject; | |
var currentParentNode = currentNode.parentNode; | |
if (currentParentNode === this.representedObject) | |
continue; | |
var selectedTreeElement = this.treeOutline.selectedTreeElement; | |
if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) | |
this.select(); | |
this.removeChildAtIndex(i); | |
} | |
updateChildrenOfNode(this.representedObject); | |
this.adjustCollapsedRange(); | |
var lastChild = this.children[this.children.length - 1]; | |
if (this.representedObject.nodeType() == Node.ELEMENT_NODE && (!lastChild || !lastChild._elementCloseTag)) | |
this.insertChildElement(this.representedObject, this.children.length, true); | |
if (fullRefresh && elementToSelect) { | |
elementToSelect.select(); | |
if (treeOutlineContainerElement && originalScrollTop <= treeOutlineContainerElement.scrollHeight) | |
treeOutlineContainerElement.scrollTop = originalScrollTop; | |
} | |
delete this._updateChildrenInProgress; | |
}, | |
adjustCollapsedRange: function() | |
{ | |
if (this.expandAllButtonElement && this.expandAllButtonElement.__treeElement.parent) | |
this.removeChild(this.expandAllButtonElement.__treeElement); | |
const node = this.representedObject; | |
if (!node.children) | |
return; | |
const childNodeCount = node.children.length; | |
for (var i = this.expandedChildCount, limit = Math.min(this.expandedChildrenLimit, childNodeCount); i < limit; ++i) | |
this.insertChildElement(node.children[i], i); | |
const expandedChildCount = this.expandedChildCount; | |
if (childNodeCount > this.expandedChildCount) { | |
var targetButtonIndex = expandedChildCount; | |
if (!this.expandAllButtonElement) { | |
var button = document.createElement("button"); | |
button.className = "show-all-nodes"; | |
button.value = ""; | |
var item = new TreeElement(button, null, false); | |
item.selectable = false; | |
item.expandAllButton = true; | |
this.insertChild(item, targetButtonIndex); | |
this.expandAllButtonElement = item.listItemElement.firstChild; | |
this.expandAllButtonElement.__treeElement = item; | |
this.expandAllButtonElement.addEventListener("click", this.handleLoadAllChildren.bind(this), false); | |
} else if (!this.expandAllButtonElement.__treeElement.parent) | |
this.insertChild(this.expandAllButtonElement.__treeElement, targetButtonIndex); | |
this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)", childNodeCount - expandedChildCount); | |
} else if (this.expandAllButtonElement) | |
delete this.expandAllButtonElement; | |
}, | |
handleLoadAllChildren: function() | |
{ | |
this.expandedChildrenLimit = Math.max(this.representedObject._childNodeCount, this.expandedChildrenLimit + WebInspector.ElementsTreeElement.InitialChildrenLimit); | |
}, | |
onexpand: function() | |
{ | |
if (this._elementCloseTag) | |
return; | |
this.updateTitle(); | |
this.treeOutline.updateSelection(); | |
}, | |
oncollapse: function() | |
{ | |
if (this._elementCloseTag) | |
return; | |
this.updateTitle(); | |
this.treeOutline.updateSelection(); | |
}, | |
onreveal: function() | |
{ | |
if (this.listItemElement) { | |
var tagSpans = this.listItemElement.getElementsByClassName("webkit-html-tag-name"); | |
if (tagSpans.length) | |
tagSpans[0].scrollIntoViewIfNeeded(false); | |
else | |
this.listItemElement.scrollIntoViewIfNeeded(false); | |
} | |
}, | |
onselect: function(selectedByUser) | |
{ | |
this.treeOutline.suppressRevealAndSelect = true; | |
this.treeOutline.selectDOMNode(this.representedObject, selectedByUser); | |
if (selectedByUser) | |
WebInspector.domAgent.highlightDOMNode(this.representedObject.id); | |
this.updateSelection(); | |
this.treeOutline.suppressRevealAndSelect = false; | |
return true; | |
}, | |
ondelete: function() | |
{ | |
var startTagTreeElement = this.treeOutline.findTreeElement(this.representedObject); | |
startTagTreeElement ? startTagTreeElement.remove() : this.remove(); | |
return true; | |
}, | |
onenter: function() | |
{ | |
if (this.treeOutline.editing) | |
return false; | |
this._startEditing(); | |
return true; | |
}, | |
selectOnMouseDown: function(event) | |
{ | |
TreeElement.prototype.selectOnMouseDown.call(this, event); | |
if (this._editing) | |
return; | |
if (this.treeOutline._showInElementsPanelEnabled) { | |
WebInspector.showPanel("elements"); | |
this.treeOutline.selectDOMNode(this.representedObject, true); | |
} | |
if (event.detail >= 2) | |
event.preventDefault(); | |
}, | |
ondblclick: function(event) | |
{ | |
if (this._editing || this._elementCloseTag) | |
return; | |
if (this._startEditingTarget(event.target)) | |
return; | |
if (this.hasChildren && !this.expanded) | |
this.expand(); | |
}, | |
_insertInLastAttributePosition: function(tag, node) | |
{ | |
if (tag.getElementsByClassName("webkit-html-attribute").length > 0) | |
tag.insertBefore(node, tag.lastChild); | |
else { | |
var nodeName = tag.textContent.match(/^<(.*?)>$/)[1]; | |
tag.textContent = ''; | |
tag.appendChild(document.createTextNode('<'+nodeName)); | |
tag.appendChild(node); | |
tag.appendChild(document.createTextNode('>')); | |
} | |
this.updateSelection(); | |
}, | |
_startEditingTarget: function(eventTarget) | |
{ | |
if (this.treeOutline.selectedDOMNode() != this.representedObject) | |
return; | |
if (this.representedObject.nodeType() != Node.ELEMENT_NODE && this.representedObject.nodeType() != Node.TEXT_NODE) | |
return false; | |
var textNode = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-text-node"); | |
if (textNode) | |
return this._startEditingTextNode(textNode); | |
var attribute = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-attribute"); | |
if (attribute) | |
return this._startEditingAttribute(attribute, eventTarget); | |
var tagName = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-tag-name"); | |
if (tagName) | |
return this._startEditingTagName(tagName); | |
var newAttribute = eventTarget.enclosingNodeOrSelfWithClass("add-attribute"); | |
if (newAttribute) | |
return this._addNewAttribute(); | |
return false; | |
}, | |
_populateTagContextMenu: function(contextMenu, event) | |
{ | |
var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute"); | |
var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute"); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add attribute" : "Add Attribute"), this._addNewAttribute.bind(this)); | |
if (attribute && !newAttribute) | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit attribute" : "Edit Attribute"), this._startEditingAttribute.bind(this, attribute, event.target)); | |
contextMenu.appendSeparator(); | |
if (this.treeOutline._setPseudoClassCallback) { | |
var pseudoSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Force element state" : "Force Element State")); | |
this._populateForcedPseudoStateItems(pseudoSubMenu); | |
contextMenu.appendSeparator(); | |
} | |
this._populateNodeContextMenu(contextMenu); | |
this.treeOutline._populateContextMenu(contextMenu, this.representedObject); | |
contextMenu.appendSeparator(); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Scroll into view" : "Scroll Into View"), this._scrollIntoView.bind(this)); | |
}, | |
_populateForcedPseudoStateItems: function(subMenu) | |
{ | |
const pseudoClasses = ["active", "hover", "focus", "visited"]; | |
var node = this.representedObject; | |
var forcedPseudoState = (node ? node.getUserProperty("pseudoState") : null) || []; | |
for (var i = 0; i < pseudoClasses.length; ++i) { | |
var pseudoClassForced = forcedPseudoState.indexOf(pseudoClasses[i]) >= 0; | |
subMenu.appendCheckboxItem(":" + pseudoClasses[i], this.treeOutline._setPseudoClassCallback.bind(null, node.id, pseudoClasses[i], !pseudoClassForced), pseudoClassForced, false); | |
} | |
}, | |
_populateTextContextMenu: function(contextMenu, textNode) | |
{ | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit text" : "Edit Text"), this._startEditingTextNode.bind(this, textNode)); | |
this._populateNodeContextMenu(contextMenu); | |
}, | |
_populateNodeContextMenu: function(contextMenu) | |
{ | |
contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), this._editAsHTML.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._copyXPath.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); | |
}, | |
_startEditing: function() | |
{ | |
if (this.treeOutline.selectedDOMNode() !== this.representedObject) | |
return; | |
var listItem = this._listItemNode; | |
if (this._canAddAttributes) { | |
var attribute = listItem.getElementsByClassName("webkit-html-attribute")[0]; | |
if (attribute) | |
return this._startEditingAttribute(attribute, attribute.getElementsByClassName("webkit-html-attribute-value")[0]); | |
return this._addNewAttribute(); | |
} | |
if (this.representedObject.nodeType() === Node.TEXT_NODE) { | |
var textNode = listItem.getElementsByClassName("webkit-html-text-node")[0]; | |
if (textNode) | |
return this._startEditingTextNode(textNode); | |
return; | |
} | |
}, | |
_addNewAttribute: function() | |
{ | |
var container = document.createElement("span"); | |
this._buildAttributeDOM(container, " ", ""); | |
var attr = container.firstChild; | |
attr.style.marginLeft = "2px"; | |
attr.style.marginRight = "2px"; | |
var tag = this.listItemElement.getElementsByClassName("webkit-html-tag")[0]; | |
this._insertInLastAttributePosition(tag, attr); | |
return this._startEditingAttribute(attr, attr); | |
}, | |
_triggerEditAttribute: function(attributeName) | |
{ | |
var attributeElements = this.listItemElement.getElementsByClassName("webkit-html-attribute-name"); | |
for (var i = 0, len = attributeElements.length; i < len; ++i) { | |
if (attributeElements[i].textContent === attributeName) { | |
for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) { | |
if (elem.nodeType !== Node.ELEMENT_NODE) | |
continue; | |
if (elem.hasStyleClass("webkit-html-attribute-value")) | |
return this._startEditingAttribute(elem.parentNode, elem); | |
} | |
} | |
} | |
}, | |
_startEditingAttribute: function(attribute, elementForSelection) | |
{ | |
if (WebInspector.isBeingEdited(attribute)) | |
return true; | |
var attributeNameElement = attribute.getElementsByClassName("webkit-html-attribute-name")[0]; | |
if (!attributeNameElement) | |
return false; | |
var attributeName = attributeNameElement.textContent; | |
function removeZeroWidthSpaceRecursive(node) | |
{ | |
if (node.nodeType === Node.TEXT_NODE) { | |
node.nodeValue = node.nodeValue.replace(/\u200B/g, ""); | |
return; | |
} | |
if (node.nodeType !== Node.ELEMENT_NODE) | |
return; | |
for (var child = node.firstChild; child; child = child.nextSibling) | |
removeZeroWidthSpaceRecursive(child); | |
} | |
removeZeroWidthSpaceRecursive(attribute); | |
var config = new WebInspector.EditingConfig(this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName); | |
function handleKeyDownEvents(event) | |
{ | |
var isMetaOrCtrl = WebInspector.isMac() ? | |
event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey : | |
event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; | |
if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl)) | |
return "commit"; | |
else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B") | |
return "cancel"; | |
else if (event.keyIdentifier === "U+0009") | |
return "move-" + (event.shiftKey ? "backward" : "forward"); | |
else { | |
WebInspector.handleElementValueModifications(event, attribute); | |
return ""; | |
} | |
} | |
config.customFinishHandler = handleKeyDownEvents.bind(this); | |
this._editing = WebInspector.startEditing(attribute, config); | |
window.getSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1); | |
return true; | |
}, | |
_startEditingTextNode: function(textNode) | |
{ | |
if (WebInspector.isBeingEdited(textNode)) | |
return true; | |
var container = textNode.enclosingNodeOrSelfWithClass("webkit-html-text-node"); | |
if (container) | |
container.innerText = textNode._originalContent; | |
var config = new WebInspector.EditingConfig(this._textNodeEditingCommitted.bind(this), this._editingCancelled.bind(this)); | |
this._editing = WebInspector.startEditing(textNode, config); | |
window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); | |
return true; | |
}, | |
_startEditingTagName: function(tagNameElement) | |
{ | |
if (!tagNameElement) { | |
tagNameElement = this.listItemElement.getElementsByClassName("webkit-html-tag-name")[0]; | |
if (!tagNameElement) | |
return false; | |
} | |
var tagName = tagNameElement.textContent; | |
if (WebInspector.ElementsTreeElement.EditTagBlacklist[tagName.toLowerCase()]) | |
return false; | |
if (WebInspector.isBeingEdited(tagNameElement)) | |
return true; | |
var closingTagElement = this._distinctClosingTagElement(); | |
function keyupListener(event) | |
{ | |
if (closingTagElement) | |
closingTagElement.textContent = "</" + tagNameElement.textContent + ">"; | |
} | |
function editingComitted(element, newTagName) | |
{ | |
tagNameElement.removeEventListener('keyup', keyupListener, false); | |
this._tagNameEditingCommitted.apply(this, arguments); | |
} | |
function editingCancelled() | |
{ | |
tagNameElement.removeEventListener('keyup', keyupListener, false); | |
this._editingCancelled.apply(this, arguments); | |
} | |
tagNameElement.addEventListener('keyup', keyupListener, false); | |
var config = new WebInspector.EditingConfig(editingComitted.bind(this), editingCancelled.bind(this), tagName); | |
this._editing = WebInspector.startEditing(tagNameElement, config); | |
window.getSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1); | |
return true; | |
}, | |
_startEditingAsHTML: function(commitCallback, error, initialValue) | |
{ | |
if (error) | |
return; | |
if (this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement)) | |
return; | |
function consume(event) | |
{ | |
if (event.eventPhase === Event.AT_TARGET) | |
event.consume(true); | |
} | |
this._htmlEditElement = document.createElement("div"); | |
this._htmlEditElement.className = "source-code elements-tree-editor"; | |
this._htmlEditElement.textContent = initialValue; | |
var child = this.listItemElement.firstChild; | |
while (child) { | |
child.style.display = "none"; | |
child = child.nextSibling; | |
} | |
if (this._childrenListNode) | |
this._childrenListNode.style.display = "none"; | |
this.listItemElement.appendChild(this._htmlEditElement); | |
this.treeOutline.childrenListElement.parentElement.addEventListener("mousedown", consume, false); | |
this.updateSelection(); | |
function commit() | |
{ | |
commitCallback(initialValue, this._htmlEditElement.textContent); | |
dispose.call(this); | |
} | |
function dispose() | |
{ | |
this._editing = false; | |
this.listItemElement.removeChild(this._htmlEditElement); | |
delete this._htmlEditElement; | |
if (this._childrenListNode) | |
this._childrenListNode.style.removeProperty("display"); | |
var child = this.listItemElement.firstChild; | |
while (child) { | |
child.style.removeProperty("display"); | |
child = child.nextSibling; | |
} | |
this.treeOutline.childrenListElement.parentElement.removeEventListener("mousedown", consume, false); | |
this.updateSelection(); | |
} | |
var config = new WebInspector.EditingConfig(commit.bind(this), dispose.bind(this)); | |
config.setMultiline(true); | |
this._editing = WebInspector.startEditing(this._htmlEditElement, config); | |
}, | |
_attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection) | |
{ | |
this._editing = false; | |
var treeOutline = this.treeOutline; | |
function moveToNextAttributeIfNeeded(error) | |
{ | |
if (error) | |
this._editingCancelled(element, attributeName); | |
if (!moveDirection) | |
return; | |
treeOutline._updateModifiedNodes(); | |
var attributes = this.representedObject.attributes(); | |
for (var i = 0; i < attributes.length; ++i) { | |
if (attributes[i].name !== attributeName) | |
continue; | |
if (moveDirection === "backward") { | |
if (i === 0) | |
this._startEditingTagName(); | |
else | |
this._triggerEditAttribute(attributes[i - 1].name); | |
} else { | |
if (i === attributes.length - 1) | |
this._addNewAttribute(); | |
else | |
this._triggerEditAttribute(attributes[i + 1].name); | |
} | |
return; | |
} | |
if (moveDirection === "backward") { | |
if (newText === " ") { | |
if (attributes.length > 0) | |
this._triggerEditAttribute(attributes[attributes.length - 1].name); | |
} else { | |
if (attributes.length > 1) | |
this._triggerEditAttribute(attributes[attributes.length - 2].name); | |
} | |
} else if (moveDirection === "forward") { | |
if (!/^\s*$/.test(newText)) | |
this._addNewAttribute(); | |
else | |
this._startEditingTagName(); | |
} | |
} | |
if (oldText !== newText) | |
this.representedObject.setAttribute(attributeName, newText, moveToNextAttributeIfNeeded.bind(this)); | |
else | |
moveToNextAttributeIfNeeded.call(this); | |
}, | |
_tagNameEditingCommitted: function(element, newText, oldText, tagName, moveDirection) | |
{ | |
this._editing = false; | |
var self = this; | |
function cancel() | |
{ | |
var closingTagElement = self._distinctClosingTagElement(); | |
if (closingTagElement) | |
closingTagElement.textContent = "</" + tagName + ">"; | |
self._editingCancelled(element, tagName); | |
moveToNextAttributeIfNeeded.call(self); | |
} | |
function moveToNextAttributeIfNeeded() | |
{ | |
if (moveDirection !== "forward") { | |
this._addNewAttribute(); | |
return; | |
} | |
var attributes = this.representedObject.attributes(); | |
if (attributes.length > 0) | |
this._triggerEditAttribute(attributes[0].name); | |
else | |
this._addNewAttribute(); | |
} | |
newText = newText.trim(); | |
if (newText === oldText) { | |
cancel(); | |
return; | |
} | |
var treeOutline = this.treeOutline; | |
var wasExpanded = this.expanded; | |
function changeTagNameCallback(error, nodeId) | |
{ | |
if (error || !nodeId) { | |
cancel(); | |
return; | |
} | |
var newTreeItem = treeOutline._selectNodeAfterEdit(null, wasExpanded, error, nodeId); | |
moveToNextAttributeIfNeeded.call(newTreeItem); | |
} | |
this.representedObject.setNodeName(newText, changeTagNameCallback); | |
}, | |
_textNodeEditingCommitted: function(element, newText) | |
{ | |
this._editing = false; | |
var textNode; | |
if (this.representedObject.nodeType() === Node.ELEMENT_NODE) { | |
textNode = this.representedObject.firstChild; | |
} else if (this.representedObject.nodeType() == Node.TEXT_NODE) | |
textNode = this.representedObject; | |
textNode.setNodeValue(newText, this.updateTitle.bind(this)); | |
}, | |
_editingCancelled: function(element, context) | |
{ | |
this._editing = false; | |
this.updateTitle(); | |
}, | |
_distinctClosingTagElement: function() | |
{ | |
if (this.expanded) { | |
var closers = this._childrenListNode.querySelectorAll(".close"); | |
return closers[closers.length-1]; | |
} | |
var tags = this.listItemElement.getElementsByClassName("webkit-html-tag"); | |
return (tags.length === 1 ? null : tags[tags.length-1]); | |
}, | |
updateTitle: function(onlySearchQueryChanged) | |
{ | |
if (this._editing) | |
return; | |
if (onlySearchQueryChanged) { | |
if (this._highlightResult) | |
this._updateSearchHighlight(false); | |
} else { | |
var highlightElement = document.createElement("span"); | |
highlightElement.className = "highlight"; | |
highlightElement.appendChild(this._nodeTitleInfo(WebInspector.linkifyURLAsNode).titleDOM); | |
this.title = highlightElement; | |
this._updateDecorations(); | |
delete this._highlightResult; | |
} | |
delete this.selectionElement; | |
if (this.selected) | |
this.updateSelection(); | |
this._preventFollowingLinksOnDoubleClick(); | |
this._highlightSearchResults(); | |
}, | |
_createDecoratorElement: function() | |
{ | |
var node = this.representedObject; | |
var decoratorMessages = []; | |
var parentDecoratorMessages = []; | |
for (var i = 0; i < this.treeOutline._nodeDecorators.length; ++i) { | |
var decorator = this.treeOutline._nodeDecorators[i]; | |
var message = decorator.decorate(node); | |
if (message) { | |
decoratorMessages.push(message); | |
continue; | |
} | |
if (this.expanded || this._elementCloseTag) | |
continue; | |
message = decorator.decorateAncestor(node); | |
if (message) | |
parentDecoratorMessages.push(message) | |
} | |
if (!decoratorMessages.length && !parentDecoratorMessages.length) | |
return null; | |
var decoratorElement = document.createElement("div"); | |
decoratorElement.addStyleClass("elements-gutter-decoration"); | |
if (!decoratorMessages.length) | |
decoratorElement.addStyleClass("elements-has-decorated-children"); | |
decoratorElement.title = decoratorMessages.concat(parentDecoratorMessages).join("\n"); | |
return decoratorElement; | |
}, | |
_updateDecorations: function() | |
{ | |
if (this._decoratorElement && this._decoratorElement.parentElement) | |
this._decoratorElement.parentElement.removeChild(this._decoratorElement); | |
this._decoratorElement = this._createDecoratorElement(); | |
if (this._decoratorElement && this.listItemElement) | |
this.listItemElement.insertBefore(this._decoratorElement, this.listItemElement.firstChild); | |
}, | |
_buildAttributeDOM: function(parentElement, name, value, node, linkify) | |
{ | |
var hasText = (value.length > 0); | |
var attrSpanElement = parentElement.createChild("span", "webkit-html-attribute"); | |
var attrNameElement = attrSpanElement.createChild("span", "webkit-html-attribute-name"); | |
attrNameElement.textContent = name; | |
if (hasText) | |
attrSpanElement.appendChild(document.createTextNode("=\u200B\"")); | |
if (linkify && (name === "src" || name === "href")) { | |
var rewrittenHref = node.resolveURL(value); | |
value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B"); | |
if (rewrittenHref === null) { | |
var attrValueElement = attrSpanElement.createChild("span", "webkit-html-attribute-value"); | |
attrValueElement.textContent = value; | |
} else { | |
if (value.startsWith("data:")) | |
value = value.trimMiddle(60); | |
attrSpanElement.appendChild(linkify(rewrittenHref, value, "webkit-html-attribute-value", node.nodeName().toLowerCase() === "a")); | |
} | |
} else { | |
value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B"); | |
var attrValueElement = attrSpanElement.createChild("span", "webkit-html-attribute-value"); | |
attrValueElement.textContent = value; | |
} | |
if (hasText) | |
attrSpanElement.appendChild(document.createTextNode("\"")); | |
}, | |
_buildTagDOM: function(parentElement, tagName, isClosingTag, isDistinctTreeElement, linkify) | |
{ | |
var node = this.representedObject; | |
var classes = [ "webkit-html-tag" ]; | |
if (isClosingTag && isDistinctTreeElement) | |
classes.push("close"); | |
if (node.isInShadowTree()) | |
classes.push("shadow"); | |
var tagElement = parentElement.createChild("span", classes.join(" ")); | |
tagElement.appendChild(document.createTextNode("<")); | |
var tagNameElement = tagElement.createChild("span", isClosingTag ? "" : "webkit-html-tag-name"); | |
tagNameElement.textContent = (isClosingTag ? "/" : "") + tagName; | |
if (!isClosingTag && node.hasAttributes()) { | |
var attributes = node.attributes(); | |
for (var i = 0; i < attributes.length; ++i) { | |
var attr = attributes[i]; | |
tagElement.appendChild(document.createTextNode(" ")); | |
this._buildAttributeDOM(tagElement, attr.name, attr.value, node, linkify); | |
} | |
} | |
tagElement.appendChild(document.createTextNode(">")); | |
parentElement.appendChild(document.createTextNode("\u200B")); | |
}, | |
_convertWhitespaceToEntities: function(text) | |
{ | |
var result = ""; | |
var lastIndexAfterEntity = 0; | |
var charToEntity = WebInspector.ElementsTreeOutline.MappedCharToEntity; | |
for (var i = 0, size = text.length; i < size; ++i) { | |
var char = text.charAt(i); | |
if (charToEntity[char]) { | |
result += text.substring(lastIndexAfterEntity, i) + "&" + charToEntity[char] + ";"; | |
lastIndexAfterEntity = i + 1; | |
} | |
} | |
if (result) { | |
result += text.substring(lastIndexAfterEntity); | |
return result; | |
} | |
return text; | |
}, | |
_nodeTitleInfo: function(linkify) | |
{ | |
var node = this.representedObject; | |
var info = {titleDOM: document.createDocumentFragment(), hasChildren: this.hasChildren}; | |
switch (node.nodeType()) { | |
case Node.ATTRIBUTE_NODE: | |
var value = node.value || "\u200B"; | |
this._buildAttributeDOM(info.titleDOM, node.name, value); | |
break; | |
case Node.ELEMENT_NODE: | |
var tagName = node.nodeNameInCorrectCase(); | |
if (this._elementCloseTag) { | |
this._buildTagDOM(info.titleDOM, tagName, true, true); | |
info.hasChildren = false; | |
break; | |
} | |
this._buildTagDOM(info.titleDOM, tagName, false, false, linkify); | |
var textChild = this._singleTextChild(node); | |
var showInlineText = textChild && textChild.nodeValue().length < Preferences.maxInlineTextChildLength; | |
if (!this.expanded && (!showInlineText && (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements[tagName]))) { | |
if (this.hasChildren) { | |
var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node bogus"); | |
textNodeElement.textContent = "\u2026"; | |
info.titleDOM.appendChild(document.createTextNode("\u200B")); | |
} | |
this._buildTagDOM(info.titleDOM, tagName, true, false); | |
} | |
if (showInlineText) { | |
var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node"); | |
textNodeElement.textContent = this._convertWhitespaceToEntities(textChild.nodeValue()); | |
textNodeElement._originalContent = textChild.nodeValue(); | |
info.titleDOM.appendChild(document.createTextNode("\u200B")); | |
this._buildTagDOM(info.titleDOM, tagName, true, false); | |
info.hasChildren = false; | |
} | |
break; | |
case Node.TEXT_NODE: | |
if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "script") { | |
var newNode = info.titleDOM.createChild("span", "webkit-html-text-node webkit-html-js-node"); | |
newNode.textContent = node.nodeValue(); | |
var javascriptSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/javascript", true); | |
javascriptSyntaxHighlighter.syntaxHighlightNode(newNode); | |
} else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "style") { | |
var newNode = info.titleDOM.createChild("span", "webkit-html-text-node webkit-html-css-node"); | |
newNode.textContent = node.nodeValue(); | |
var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/css", true); | |
cssSyntaxHighlighter.syntaxHighlightNode(newNode); | |
} else { | |
info.titleDOM.appendChild(document.createTextNode("\"")); | |
var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node"); | |
textNodeElement.textContent = this._convertWhitespaceToEntities(node.nodeValue()); | |
textNodeElement._originalContent = node.nodeValue(); | |
info.titleDOM.appendChild(document.createTextNode("\"")); | |
} | |
break; | |
case Node.COMMENT_NODE: | |
var commentElement = info.titleDOM.createChild("span", "webkit-html-comment"); | |
commentElement.appendChild(document.createTextNode("<!--" + node.nodeValue() + "-->")); | |
break; | |
case Node.DOCUMENT_TYPE_NODE: | |
var docTypeElement = info.titleDOM.createChild("span", "webkit-html-doctype"); | |
docTypeElement.appendChild(document.createTextNode("<!DOCTYPE " + node.nodeName())); | |
if (node.publicId) { | |
docTypeElement.appendChild(document.createTextNode(" PUBLIC \"" + node.publicId + "\"")); | |
if (node.systemId) | |
docTypeElement.appendChild(document.createTextNode(" \"" + node.systemId + "\"")); | |
} else if (node.systemId) | |
docTypeElement.appendChild(document.createTextNode(" SYSTEM \"" + node.systemId + "\"")); | |
if (node.internalSubset) | |
docTypeElement.appendChild(document.createTextNode(" [" + node.internalSubset + "]")); | |
docTypeElement.appendChild(document.createTextNode(">")); | |
break; | |
case Node.CDATA_SECTION_NODE: | |
var cdataElement = info.titleDOM.createChild("span", "webkit-html-text-node"); | |
cdataElement.appendChild(document.createTextNode("<![CDATA[" + node.nodeValue() + "]]>")); | |
break; | |
case Node.DOCUMENT_FRAGMENT_NODE: | |
var fragmentElement = info.titleDOM.createChild("span", "webkit-html-fragment"); | |
fragmentElement.textContent = node.nodeNameInCorrectCase().collapseWhitespace(); | |
if (node.isInShadowTree()) | |
fragmentElement.addStyleClass("shadow"); | |
break; | |
default: | |
info.titleDOM.appendChild(document.createTextNode(node.nodeNameInCorrectCase().collapseWhitespace())); | |
} | |
return info; | |
}, | |
_singleTextChild: function(node) | |
{ | |
if (!node) | |
return null; | |
var firstChild = node.firstChild; | |
if (!firstChild || firstChild.nodeType() !== Node.TEXT_NODE) | |
return null; | |
var sibling = firstChild.nextSibling; | |
return sibling ? null : firstChild; | |
}, | |
_showInlineText: function(node) | |
{ | |
if (node.nodeType() === Node.ELEMENT_NODE) { | |
var textChild = this._singleTextChild(node); | |
if (textChild && textChild.nodeValue().length < Preferences.maxInlineTextChildLength) | |
return true; | |
} | |
return false; | |
}, | |
remove: function() | |
{ | |
var parentElement = this.parent; | |
if (!parentElement) | |
return; | |
var self = this; | |
function removeNodeCallback(error, removedNodeId) | |
{ | |
if (error) | |
return; | |
parentElement.removeChild(self); | |
parentElement.adjustCollapsedRange(); | |
} | |
if (!this.representedObject.parentNode || this.representedObject.parentNode.nodeType() === Node.DOCUMENT_NODE) | |
return; | |
this.representedObject.removeNode(removeNodeCallback); | |
}, | |
_editAsHTML: function() | |
{ | |
var treeOutline = this.treeOutline; | |
var node = this.representedObject; | |
var parentNode = node.parentNode; | |
var index = node.index; | |
var wasExpanded = this.expanded; | |
function selectNode(error, nodeId) | |
{ | |
if (error) | |
return; | |
treeOutline._updateModifiedNodes(); | |
var newNode = parentNode ? parentNode.children[index] || parentNode : null; | |
if (!newNode) | |
return; | |
treeOutline.selectDOMNode(newNode, true); | |
if (wasExpanded) { | |
var newTreeItem = treeOutline.findTreeElement(newNode); | |
if (newTreeItem) | |
newTreeItem.expand(); | |
} | |
} | |
function commitChange(initialValue, value) | |
{ | |
if (initialValue !== value) | |
node.setOuterHTML(value, selectNode); | |
else | |
return; | |
} | |
node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); | |
}, | |
_copyHTML: function() | |
{ | |
this.representedObject.copyNode(); | |
}, | |
_copyXPath: function() | |
{ | |
this.representedObject.copyXPath(true); | |
}, | |
_highlightSearchResults: function() | |
{ | |
if (!this._searchQuery || !this._searchHighlightsVisible) | |
return; | |
if (this._highlightResult) { | |
this._updateSearchHighlight(true); | |
return; | |
} | |
var text = this.listItemElement.textContent; | |
var regexObject = createPlainTextSearchRegex(this._searchQuery, "gi"); | |
var offset = 0; | |
var match = regexObject.exec(text); | |
var matchRanges = []; | |
while (match) { | |
matchRanges.push({ offset: match.index, length: match[0].length }); | |
match = regexObject.exec(text); | |
} | |
if (!matchRanges.length) | |
matchRanges.push({ offset: 0, length: text.length }); | |
this._highlightResult = []; | |
WebInspector.highlightSearchResults(this.listItemElement, matchRanges, this._highlightResult); | |
}, | |
_scrollIntoView: function() | |
{ | |
function scrollIntoViewCallback(object) | |
{ | |
function scrollIntoView() | |
{ | |
this.scrollIntoViewIfNeeded(true); | |
} | |
if (object) | |
object.callFunction(scrollIntoView); | |
} | |
var node = this.representedObject; | |
WebInspector.RemoteObject.resolveNode(node, "", scrollIntoViewCallback); | |
} | |
} | |
WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.ElementsTreeUpdater = function(treeOutline) | |
{ | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeInserted, this._nodeInserted, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeRemoved, this._nodeRemoved, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.AttrModified, this._attributesUpdated, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.AttrRemoved, this._attributesUpdated, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.CharacterDataModified, this._characterDataModified, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.ChildNodeCountUpdated, this._childNodeCountUpdated, this); | |
this._treeOutline = treeOutline; | |
this._recentlyModifiedNodes = new Map(); | |
} | |
WebInspector.ElementsTreeUpdater.prototype = { | |
_nodeModified: function(node, isUpdated, parentNode) | |
{ | |
if (this._treeOutline._visible) | |
this._updateModifiedNodesSoon(); | |
var entry = this._recentlyModifiedNodes.get(node); | |
if (!entry) { | |
entry = new WebInspector.ElementsTreeUpdater.UpdateEntry(isUpdated, parentNode); | |
this._recentlyModifiedNodes.put(node, entry); | |
return; | |
} | |
entry.isUpdated |= isUpdated; | |
if (parentNode) | |
entry.parent = parentNode; | |
}, | |
_documentUpdated: function(event) | |
{ | |
var inspectedRootDocument = event.data; | |
this._reset(); | |
if (!inspectedRootDocument) | |
return; | |
this._treeOutline.rootDOMNode = inspectedRootDocument; | |
}, | |
_attributesUpdated: function(event) | |
{ | |
this._nodeModified(event.data.node, true); | |
}, | |
_characterDataModified: function(event) | |
{ | |
this._nodeModified(event.data, true); | |
}, | |
_nodeInserted: function(event) | |
{ | |
this._nodeModified(event.data, false, event.data.parentNode); | |
}, | |
_nodeRemoved: function(event) | |
{ | |
this._nodeModified(event.data.node, false, event.data.parent); | |
}, | |
_childNodeCountUpdated: function(event) | |
{ | |
var treeElement = this._treeOutline.findTreeElement(event.data); | |
if (treeElement) | |
treeElement.hasChildren = event.data.hasChildNodes(); | |
}, | |
_updateModifiedNodesSoon: function() | |
{ | |
if (this._updateModifiedNodesTimeout) | |
return; | |
this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 50); | |
}, | |
_updateModifiedNodes: function() | |
{ | |
if (this._updateModifiedNodesTimeout) { | |
clearTimeout(this._updateModifiedNodesTimeout); | |
delete this._updateModifiedNodesTimeout; | |
} | |
var updatedParentTreeElements = []; | |
var hidePanelWhileUpdating = this._recentlyModifiedNodes.size() > 10; | |
if (hidePanelWhileUpdating) { | |
var treeOutlineContainerElement = this._treeOutline.element.parentNode; | |
this._treeOutline.element.addStyleClass("hidden"); | |
var originalScrollTop = treeOutlineContainerElement ? treeOutlineContainerElement.scrollTop : 0; | |
} | |
var keys = this._recentlyModifiedNodes.keys(); | |
for (var i = 0, size = keys.length; i < size; ++i) { | |
var node = keys[i]; | |
var entry = this._recentlyModifiedNodes.get(node); | |
var parent = entry.parent; | |
if (parent === this._treeOutline._rootDOMNode) { | |
this._treeOutline.update(); | |
this._treeOutline.element.removeStyleClass("hidden"); | |
return; | |
} | |
if (entry.isUpdated) { | |
var nodeItem = this._treeOutline.findTreeElement(node); | |
if (nodeItem) | |
nodeItem.updateTitle(); | |
} | |
if (!parent) | |
continue; | |
var parentNodeItem = this._treeOutline.findTreeElement(parent); | |
if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { | |
parentNodeItem.updateChildren(); | |
parentNodeItem.alreadyUpdatedChildren = true; | |
updatedParentTreeElements.push(parentNodeItem); | |
} | |
} | |
for (var i = 0; i < updatedParentTreeElements.length; ++i) | |
delete updatedParentTreeElements[i].alreadyUpdatedChildren; | |
if (hidePanelWhileUpdating) { | |
this._treeOutline.element.removeStyleClass("hidden"); | |
if (originalScrollTop) | |
treeOutlineContainerElement.scrollTop = originalScrollTop; | |
this._treeOutline.updateSelection(); | |
} | |
this._recentlyModifiedNodes.clear(); | |
}, | |
_reset: function() | |
{ | |
this._treeOutline.rootDOMNode = null; | |
this._treeOutline.selectDOMNode(null, false); | |
WebInspector.domAgent.hideDOMNodeHighlight(); | |
this._recentlyModifiedNodes.clear(); | |
} | |
} | |
WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent) | |
{ | |
this.isUpdated = isUpdated; | |
if (parent) | |
this.parent = parent; | |
} | |
WebInspector.DOMPresentationUtils = {} | |
WebInspector.DOMPresentationUtils.decorateNodeLabel = function(node, parentElement) | |
{ | |
var title = node.nodeNameInCorrectCase(); | |
var nameElement = document.createElement("span"); | |
nameElement.textContent = title; | |
parentElement.appendChild(nameElement); | |
var idAttribute = node.getAttribute("id"); | |
if (idAttribute) { | |
var idElement = document.createElement("span"); | |
parentElement.appendChild(idElement); | |
var part = "#" + idAttribute; | |
title += part; | |
idElement.appendChild(document.createTextNode(part)); | |
nameElement.className = "extra"; | |
} | |
var classAttribute = node.getAttribute("class"); | |
if (classAttribute) { | |
var classes = classAttribute.split(/\s+/); | |
var foundClasses = {}; | |
if (classes.length) { | |
var classesElement = document.createElement("span"); | |
classesElement.className = "extra"; | |
parentElement.appendChild(classesElement); | |
for (var i = 0; i < classes.length; ++i) { | |
var className = classes[i]; | |
if (className && !(className in foundClasses)) { | |
var part = "." + className; | |
title += part; | |
classesElement.appendChild(document.createTextNode(part)); | |
foundClasses[className] = true; | |
} | |
} | |
} | |
} | |
parentElement.title = title; | |
} | |
WebInspector.DOMPresentationUtils.linkifyNodeReference = function(node) | |
{ | |
var link = document.createElement("span"); | |
link.className = "node-link"; | |
WebInspector.DOMPresentationUtils.decorateNodeLabel(node, link); | |
link.addEventListener("click", WebInspector.domAgent.inspectElement.bind(WebInspector.domAgent, node.id), false); | |
link.addEventListener("mouseover", WebInspector.domAgent.highlightDOMNode.bind(WebInspector.domAgent, node.id, ""), false); | |
link.addEventListener("mouseout", WebInspector.domAgent.hideDOMNodeHighlight.bind(WebInspector.domAgent), false); | |
return link; | |
} | |
WebInspector.DOMPresentationUtils.linkifyNodeById = function(nodeId) | |
{ | |
var node = WebInspector.domAgent.nodeForId(nodeId); | |
if (!node) | |
return document.createTextNode(WebInspector.UIString("<node>")); | |
return WebInspector.DOMPresentationUtils.linkifyNodeReference(node); | |
} | |
WebInspector.DOMPresentationUtils.buildImagePreviewContents = function(imageURL, showDimensions, userCallback, precomputedDimensions) | |
{ | |
var resource = WebInspector.resourceTreeModel.resourceForURL(imageURL); | |
if (!resource) { | |
userCallback(); | |
return; | |
} | |
var imageElement = document.createElement("img"); | |
imageElement.addEventListener("load", buildContent, false); | |
imageElement.addEventListener("error", errorCallback, false); | |
resource.populateImageSource(imageElement); | |
function errorCallback() | |
{ | |
userCallback(); | |
} | |
function buildContent() | |
{ | |
var container = document.createElement("table"); | |
container.className = "image-preview-container"; | |
var naturalWidth = precomputedDimensions ? precomputedDimensions.naturalWidth : imageElement.naturalWidth; | |
var naturalHeight = precomputedDimensions ? precomputedDimensions.naturalHeight : imageElement.naturalHeight; | |
var offsetWidth = precomputedDimensions ? precomputedDimensions.offsetWidth : naturalWidth; | |
var offsetHeight = precomputedDimensions ? precomputedDimensions.offsetHeight : naturalHeight; | |
var description; | |
if (showDimensions) { | |
if (offsetHeight === naturalHeight && offsetWidth === naturalWidth) | |
description = WebInspector.UIString("%d \xd7 %d pixels", offsetWidth, offsetHeight); | |
else | |
description = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)", offsetWidth, offsetHeight, naturalWidth, naturalHeight); | |
} | |
container.createChild("tr").createChild("td", "image-container").appendChild(imageElement); | |
if (description) | |
container.createChild("tr").createChild("td").createChild("span", "description").textContent = description; | |
userCallback(container); | |
} | |
} | |
WebInspector.SidebarSectionTreeElement = function(title, representedObject, hasChildren) | |
{ | |
TreeElement.call(this, title.escapeHTML(), representedObject || {}, hasChildren); | |
this.expand(); | |
} | |
WebInspector.SidebarSectionTreeElement.prototype = { | |
selectable: false, | |
collapse: function() | |
{ | |
}, | |
get smallChildren() | |
{ | |
return this._smallChildren; | |
}, | |
set smallChildren(x) | |
{ | |
if (this._smallChildren === x) | |
return; | |
this._smallChildren = x; | |
if (this._smallChildren) | |
this._childrenListNode.addStyleClass("small"); | |
else | |
this._childrenListNode.removeStyleClass("small"); | |
}, | |
onattach: function() | |
{ | |
this._listItemNode.addStyleClass("sidebar-tree-section"); | |
}, | |
onreveal: function() | |
{ | |
if (this.listItemElement) | |
this.listItemElement.scrollIntoViewIfNeeded(false); | |
} | |
} | |
WebInspector.SidebarSectionTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.SidebarTreeElement = function(className, title, subtitle, representedObject, hasChildren) | |
{ | |
TreeElement.call(this, "", representedObject, hasChildren); | |
if (hasChildren) { | |
this.disclosureButton = document.createElement("button"); | |
this.disclosureButton.className = "disclosure-button"; | |
} | |
if (!this.iconElement) { | |
this.iconElement = document.createElement("img"); | |
this.iconElement.className = "icon"; | |
} | |
this.statusElement = document.createElement("div"); | |
this.statusElement.className = "status"; | |
this.titlesElement = document.createElement("div"); | |
this.titlesElement.className = "titles"; | |
this.titleElement = document.createElement("span"); | |
this.titleElement.className = "title"; | |
this.titlesElement.appendChild(this.titleElement); | |
this.subtitleElement = document.createElement("span"); | |
this.subtitleElement.className = "subtitle"; | |
this.titlesElement.appendChild(this.subtitleElement); | |
this.className = className; | |
this.mainTitle = title; | |
this.subtitle = subtitle; | |
} | |
WebInspector.SidebarTreeElement.prototype = { | |
get small() | |
{ | |
return this._small; | |
}, | |
set small(x) | |
{ | |
this._small = x; | |
if (this._listItemNode) { | |
if (this._small) | |
this._listItemNode.addStyleClass("small"); | |
else | |
this._listItemNode.removeStyleClass("small"); | |
} | |
}, | |
get mainTitle() | |
{ | |
return this._mainTitle; | |
}, | |
set mainTitle(x) | |
{ | |
this._mainTitle = x; | |
this.refreshTitles(); | |
}, | |
get subtitle() | |
{ | |
return this._subtitle; | |
}, | |
set subtitle(x) | |
{ | |
this._subtitle = x; | |
this.refreshTitles(); | |
}, | |
get bubbleText() | |
{ | |
return this._bubbleText; | |
}, | |
set bubbleText(x) | |
{ | |
if (!this.bubbleElement) { | |
this.bubbleElement = document.createElement("div"); | |
this.bubbleElement.className = "bubble"; | |
this.statusElement.appendChild(this.bubbleElement); | |
} | |
this._bubbleText = x; | |
this.bubbleElement.textContent = x; | |
}, | |
set wait(x) | |
{ | |
if (x) | |
this._listItemNode.addStyleClass("wait"); | |
else | |
this._listItemNode.removeStyleClass("wait"); | |
}, | |
refreshTitles: function() | |
{ | |
var mainTitle = this.mainTitle; | |
if (this.titleElement.textContent !== mainTitle) | |
this.titleElement.textContent = mainTitle; | |
var subtitle = this.subtitle; | |
if (subtitle) { | |
if (this.subtitleElement.textContent !== subtitle) | |
this.subtitleElement.textContent = subtitle; | |
this.titlesElement.removeStyleClass("no-subtitle"); | |
} else { | |
this.subtitleElement.textContent = ""; | |
this.titlesElement.addStyleClass("no-subtitle"); | |
} | |
}, | |
isEventWithinDisclosureTriangle: function(event) | |
{ | |
return event.target === this.disclosureButton; | |
}, | |
onattach: function() | |
{ | |
this._listItemNode.addStyleClass("sidebar-tree-item"); | |
if (this.className) | |
this._listItemNode.addStyleClass(this.className); | |
if (this.small) | |
this._listItemNode.addStyleClass("small"); | |
if (this.hasChildren && this.disclosureButton) | |
this._listItemNode.appendChild(this.disclosureButton); | |
this._listItemNode.appendChild(this.iconElement); | |
this._listItemNode.appendChild(this.statusElement); | |
this._listItemNode.appendChild(this.titlesElement); | |
}, | |
onreveal: function() | |
{ | |
if (this._listItemNode) | |
this._listItemNode.scrollIntoViewIfNeeded(false); | |
} | |
} | |
WebInspector.SidebarTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.Section = function(title, subtitle) | |
{ | |
this.element = document.createElement("div"); | |
this.element.className = "section"; | |
this.element._section = this; | |
this.headerElement = document.createElement("div"); | |
this.headerElement.className = "header"; | |
this.titleElement = document.createElement("div"); | |
this.titleElement.className = "title"; | |
this.subtitleElement = document.createElement("div"); | |
this.subtitleElement.className = "subtitle"; | |
this.headerElement.appendChild(this.subtitleElement); | |
this.headerElement.appendChild(this.titleElement); | |
this.headerElement.addEventListener("click", this.handleClick.bind(this), false); | |
this.element.appendChild(this.headerElement); | |
this.title = title; | |
this.subtitle = subtitle; | |
this._expanded = false; | |
} | |
WebInspector.Section.prototype = { | |
get title() | |
{ | |
return this._title; | |
}, | |
set title(x) | |
{ | |
if (this._title === x) | |
return; | |
this._title = x; | |
if (x instanceof Node) { | |
this.titleElement.removeChildren(); | |
this.titleElement.appendChild(x); | |
} else | |
this.titleElement.textContent = x; | |
}, | |
get subtitle() | |
{ | |
return this._subtitle; | |
}, | |
set subtitle(x) | |
{ | |
if (this._subtitle === x) | |
return; | |
this._subtitle = x; | |
this.subtitleElement.textContent = x; | |
}, | |
get subtitleAsTextForTest() | |
{ | |
var result = this.subtitleElement.textContent; | |
var child = this.subtitleElement.querySelector("[data-uncopyable]"); | |
if (child) { | |
var linkData = child.getAttribute("data-uncopyable"); | |
if (linkData) | |
result += linkData; | |
} | |
return result; | |
}, | |
get expanded() | |
{ | |
return this._expanded; | |
}, | |
set expanded(x) | |
{ | |
if (x) | |
this.expand(); | |
else | |
this.collapse(); | |
}, | |
get populated() | |
{ | |
return this._populated; | |
}, | |
set populated(x) | |
{ | |
this._populated = x; | |
if (!x && this._expanded) { | |
this.onpopulate(); | |
this._populated = true; | |
} | |
}, | |
onpopulate: function() | |
{ | |
}, | |
get firstSibling() | |
{ | |
var parent = this.element.parentElement; | |
if (!parent) | |
return null; | |
var childElement = parent.firstChild; | |
while (childElement) { | |
if (childElement._section) | |
return childElement._section; | |
childElement = childElement.nextSibling; | |
} | |
return null; | |
}, | |
get lastSibling() | |
{ | |
var parent = this.element.parentElement; | |
if (!parent) | |
return null; | |
var childElement = parent.lastChild; | |
while (childElement) { | |
if (childElement._section) | |
return childElement._section; | |
childElement = childElement.previousSibling; | |
} | |
return null; | |
}, | |
get nextSibling() | |
{ | |
var curElement = this.element; | |
do { | |
curElement = curElement.nextSibling; | |
} while (curElement && !curElement._section); | |
return curElement ? curElement._section : null; | |
}, | |
get previousSibling() | |
{ | |
var curElement = this.element; | |
do { | |
curElement = curElement.previousSibling; | |
} while (curElement && !curElement._section); | |
return curElement ? curElement._section : null; | |
}, | |
expand: function() | |
{ | |
if (this._expanded) | |
return; | |
this._expanded = true; | |
this.element.addStyleClass("expanded"); | |
if (!this._populated) { | |
this.onpopulate(); | |
this._populated = true; | |
} | |
}, | |
collapse: function() | |
{ | |
if (!this._expanded) | |
return; | |
this._expanded = false; | |
this.element.removeStyleClass("expanded"); | |
}, | |
toggleExpanded: function() | |
{ | |
this.expanded = !this.expanded; | |
}, | |
handleClick: function(event) | |
{ | |
this.toggleExpanded(); | |
event.consume(); | |
} | |
} | |
WebInspector.PropertiesSection = function(title, subtitle) | |
{ | |
WebInspector.Section.call(this, title, subtitle); | |
this.headerElement.addStyleClass("monospace"); | |
this.propertiesElement = document.createElement("ol"); | |
this.propertiesElement.className = "properties properties-tree monospace"; | |
this.propertiesTreeOutline = new TreeOutline(this.propertiesElement, true); | |
this.propertiesTreeOutline.setFocusable(false); | |
this.propertiesTreeOutline.section = this; | |
this.element.appendChild(this.propertiesElement); | |
} | |
WebInspector.PropertiesSection.prototype.__proto__ = WebInspector.Section.prototype; | |
WebInspector.RemoteObject = function(objectId, type, subtype, value, description, preview) | |
{ | |
this._type = type; | |
this._subtype = subtype; | |
if (objectId) { | |
this._objectId = objectId; | |
this._description = description; | |
this._hasChildren = true; | |
this._preview = preview; | |
} else { | |
console.assert(type !== "object" || value === null); | |
this._description = description || (value + ""); | |
this._hasChildren = false; | |
this.value = value; | |
} | |
} | |
WebInspector.RemoteObject.fromPrimitiveValue = function(value) | |
{ | |
return new WebInspector.RemoteObject(undefined, typeof value, undefined, value); | |
} | |
WebInspector.RemoteObject.fromLocalObject = function(value) | |
{ | |
return new WebInspector.LocalJSONObject(value); | |
} | |
WebInspector.RemoteObject.resolveNode = function(node, objectGroup, callback) | |
{ | |
function mycallback(error, object) | |
{ | |
if (!callback) | |
return; | |
if (error || !object) | |
callback(null); | |
else | |
callback(WebInspector.RemoteObject.fromPayload(object)); | |
} | |
DOMAgent.resolveNode(node.id, objectGroup, mycallback); | |
} | |
WebInspector.RemoteObject.fromPayload = function(payload) | |
{ | |
console.assert(typeof payload === "object", "Remote object payload should only be an object"); | |
return new WebInspector.RemoteObject(payload.objectId, payload.type, payload.subtype, payload.value, payload.description, payload.preview); | |
} | |
WebInspector.RemoteObject.type = function(remoteObject) | |
{ | |
if (remoteObject === null) | |
return "null"; | |
var type = typeof remoteObject; | |
if (type !== "object" && type !== "function") | |
return type; | |
return remoteObject.type; | |
} | |
WebInspector.RemoteObject.prototype = { | |
get objectId() | |
{ | |
return this._objectId; | |
}, | |
get type() | |
{ | |
return this._type; | |
}, | |
get subtype() | |
{ | |
return this._subtype; | |
}, | |
get description() | |
{ | |
return this._description; | |
}, | |
get hasChildren() | |
{ | |
return this._hasChildren; | |
}, | |
get preview() | |
{ | |
return this._preview; | |
}, | |
getOwnProperties: function(callback) | |
{ | |
this._getProperties(true, callback); | |
}, | |
getAllProperties: function(callback) | |
{ | |
this._getProperties(false, callback); | |
}, | |
_getProperties: function(ownProperties, callback) | |
{ | |
if (!this._objectId) { | |
callback([]); | |
return; | |
} | |
function remoteObjectBinder(error, properties) | |
{ | |
if (error) { | |
callback(null); | |
return; | |
} | |
var result = []; | |
for (var i = 0; properties && i < properties.length; ++i) { | |
var property = properties[i]; | |
if (property.get || property.set) { | |
if (property.get) | |
result.push(new WebInspector.RemoteObjectProperty("get " + property.name, WebInspector.RemoteObject.fromPayload(property.get), property)); | |
if (property.set) | |
result.push(new WebInspector.RemoteObjectProperty("set " + property.name, WebInspector.RemoteObject.fromPayload(property.set), property)); | |
} else | |
result.push(new WebInspector.RemoteObjectProperty(property.name, WebInspector.RemoteObject.fromPayload(property.value), property)); | |
} | |
callback(result); | |
} | |
RuntimeAgent.getProperties(this._objectId, ownProperties, remoteObjectBinder); | |
}, | |
setPropertyValue: function(name, value, callback) | |
{ | |
if (!this._objectId) { | |
callback("Can't set a property of non-object."); | |
return; | |
} | |
RuntimeAgent.evaluate.invoke({expression:value, doNotPauseOnExceptionsAndMuteConsole:true}, evaluatedCallback.bind(this)); | |
function evaluatedCallback(error, result, wasThrown) | |
{ | |
if (error || wasThrown) { | |
callback(error || result.description); | |
return; | |
} | |
function setPropertyValue(propertyName, propertyValue) | |
{ | |
this[propertyName] = propertyValue; | |
} | |
delete result.description; | |
RuntimeAgent.callFunctionOn(this._objectId, setPropertyValue.toString(), [{ value:name }, result], true, undefined, propertySetCallback.bind(this)); | |
if (result._objectId) | |
RuntimeAgent.releaseObject(result._objectId); | |
} | |
function propertySetCallback(error, result, wasThrown) | |
{ | |
if (error || wasThrown) { | |
callback(error || result.description); | |
return; | |
} | |
callback(); | |
} | |
}, | |
pushNodeToFrontend: function(callback) | |
{ | |
if (this._objectId) | |
WebInspector.domAgent.pushNodeToFrontend(this._objectId, callback); | |
else | |
callback(0); | |
}, | |
callFunction: function(functionDeclaration, args, callback) | |
{ | |
function mycallback(error, result, wasThrown) | |
{ | |
if (!callback) | |
return; | |
callback((error || wasThrown) ? null : WebInspector.RemoteObject.fromPayload(result)); | |
} | |
RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, undefined, mycallback); | |
}, | |
callFunctionJSON: function(functionDeclaration, args, callback) | |
{ | |
function mycallback(error, result, wasThrown) | |
{ | |
callback((error || wasThrown) ? null : result.value); | |
} | |
RuntimeAgent.callFunctionOn(this._objectId, functionDeclaration.toString(), args, true, true, mycallback); | |
}, | |
release: function() | |
{ | |
RuntimeAgent.releaseObject(this._objectId); | |
}, | |
arrayLength: function() | |
{ | |
if (this.subtype !== "array") | |
return 0; | |
var matches = this._description.match(/\[([0-9]+)\]/); | |
if (!matches) | |
return 0; | |
return parseInt(matches[1], 10); | |
} | |
} | |
WebInspector.RemoteObjectProperty = function(name, value, descriptor) | |
{ | |
this.name = name; | |
this.value = value; | |
this.enumerable = descriptor ? !!descriptor.enumerable : true; | |
this.writable = descriptor ? !!descriptor.writable : true; | |
if (descriptor && descriptor.wasThrown) | |
this.wasThrown = true; | |
} | |
WebInspector.RemoteObjectProperty.fromPrimitiveValue = function(name, value) | |
{ | |
return new WebInspector.RemoteObjectProperty(name, WebInspector.RemoteObject.fromPrimitiveValue(value)); | |
} | |
WebInspector.RemoteObjectProperty.fromScopeValue = function(name, value) | |
{ | |
var result = new WebInspector.RemoteObjectProperty(name, value); | |
result.writable = false; | |
return result; | |
} | |
WebInspector.LocalJSONObject = function(value) | |
{ | |
this._value = value; | |
} | |
WebInspector.LocalJSONObject.prototype = { | |
get description() | |
{ | |
if (this._cachedDescription) | |
return this._cachedDescription; | |
if (this.type === "object") { | |
switch (this.subtype) { | |
case "array": | |
function formatArrayItem(property) | |
{ | |
return property.value.description; | |
} | |
this._cachedDescription = this._concatenate("[", "]", formatArrayItem); | |
break; | |
case "date": | |
this._cachedDescription = "" + this._value; | |
break; | |
case "null": | |
this._cachedDescription = "null"; | |
break; | |
default: | |
function formatObjectItem(property) | |
{ | |
return property.name + ":" + property.value.description; | |
} | |
this._cachedDescription = this._concatenate("{", "}", formatObjectItem); | |
} | |
} else | |
this._cachedDescription = String(this._value); | |
return this._cachedDescription; | |
}, | |
_concatenate: function(prefix, suffix, formatProperty) | |
{ | |
const previewChars = 100; | |
var buffer = prefix; | |
var children = this._children(); | |
for (var i = 0; i < children.length; ++i) { | |
var itemDescription = formatProperty(children[i]); | |
if (buffer.length + itemDescription.length > previewChars) { | |
buffer += ",\u2026"; | |
break; | |
} | |
if (i) | |
buffer += ", "; | |
buffer += itemDescription; | |
} | |
buffer += suffix; | |
return buffer; | |
}, | |
get type() | |
{ | |
return typeof this._value; | |
}, | |
get subtype() | |
{ | |
if (this._value === null) | |
return "null"; | |
if (this._value instanceof Array) | |
return "array"; | |
if (this._value instanceof Date) | |
return "date"; | |
return undefined; | |
}, | |
get hasChildren() | |
{ | |
return typeof this._value === "object" && this._value !== null && !!Object.keys(this._value).length; | |
}, | |
getOwnProperties: function(callback) | |
{ | |
callback(this._children()); | |
}, | |
getAllProperties: function(callback) | |
{ | |
callback(this._children()); | |
}, | |
_children: function() | |
{ | |
if (!this.hasChildren) | |
return []; | |
function buildProperty(propName) | |
{ | |
return new WebInspector.RemoteObjectProperty(propName, new WebInspector.LocalJSONObject(this._value[propName])); | |
} | |
if (!this._cachedChildren) | |
this._cachedChildren = Object.keys(this._value || {}).map(buildProperty.bind(this)); | |
return this._cachedChildren; | |
}, | |
isError: function() | |
{ | |
return false; | |
}, | |
arrayLength: function() | |
{ | |
return this._value instanceof Array ? this._value.length : 0; | |
} | |
} | |
WebInspector.ObjectPropertiesSection = function(object, title, subtitle, emptyPlaceholder, ignoreHasOwnProperty, extraProperties, treeElementConstructor) | |
{ | |
this.emptyPlaceholder = (emptyPlaceholder || WebInspector.UIString("No Properties")); | |
this.object = object; | |
this.ignoreHasOwnProperty = ignoreHasOwnProperty; | |
this.extraProperties = extraProperties; | |
this.treeElementConstructor = treeElementConstructor || WebInspector.ObjectPropertyTreeElement; | |
this.editable = true; | |
this.skipProto = false; | |
WebInspector.PropertiesSection.call(this, title || "", subtitle); | |
} | |
WebInspector.ObjectPropertiesSection._arrayLoadThreshold = 100; | |
WebInspector.ObjectPropertiesSection.prototype = { | |
enableContextMenu: function() | |
{ | |
this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true); | |
}, | |
_contextMenuEventFired: function(event) | |
{ | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendApplicableItems(this.object); | |
contextMenu.show(event); | |
}, | |
onpopulate: function() | |
{ | |
this.update(); | |
}, | |
update: function() | |
{ | |
if (this.object.arrayLength() > WebInspector.ObjectPropertiesSection._arrayLoadThreshold) { | |
this.propertiesTreeOutline.removeChildren(); | |
WebInspector.ArrayGroupingTreeElement._populateArray(this.propertiesTreeOutline, this.object, 0, this.object.arrayLength() - 1); | |
return; | |
} | |
function callback(properties) | |
{ | |
if (!properties) | |
return; | |
this.updateProperties(properties); | |
} | |
if (this.ignoreHasOwnProperty) | |
this.object.getAllProperties(callback.bind(this)); | |
else | |
this.object.getOwnProperties(callback.bind(this)); | |
}, | |
updateProperties: function(properties, rootTreeElementConstructor, rootPropertyComparer) | |
{ | |
if (!rootTreeElementConstructor) | |
rootTreeElementConstructor = this.treeElementConstructor; | |
if (!rootPropertyComparer) | |
rootPropertyComparer = WebInspector.ObjectPropertiesSection.CompareProperties; | |
if (this.extraProperties) | |
for (var i = 0; i < this.extraProperties.length; ++i) | |
properties.push(this.extraProperties[i]); | |
properties.sort(rootPropertyComparer); | |
this.propertiesTreeOutline.removeChildren(); | |
for (var i = 0; i < properties.length; ++i) { | |
if (this.skipProto && properties[i].name === "__proto__") | |
continue; | |
properties[i].parentObject = this.object; | |
} | |
this.propertiesForTest = properties; | |
for (var i = 0; i < properties.length; ++i) | |
this.propertiesTreeOutline.appendChild(new rootTreeElementConstructor(properties[i])); | |
if (!this.propertiesTreeOutline.children.length) { | |
var title = document.createElement("div"); | |
title.className = "info"; | |
title.textContent = this.emptyPlaceholder; | |
var infoElement = new TreeElement(title, null, false); | |
this.propertiesTreeOutline.appendChild(infoElement); | |
} | |
} | |
} | |
WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype; | |
WebInspector.ObjectPropertiesSection.CompareProperties = function(propertyA, propertyB) | |
{ | |
var a = propertyA.name; | |
var b = propertyB.name; | |
if (a === "__proto__") | |
return 1; | |
if (b === "__proto__") | |
return -1; | |
var diff = 0; | |
var chunk = /^\d+|^\D+/; | |
var chunka, chunkb, anum, bnum; | |
while (diff === 0) { | |
if (!a && b) | |
return -1; | |
if (!b && a) | |
return 1; | |
chunka = a.match(chunk)[0]; | |
chunkb = b.match(chunk)[0]; | |
anum = !isNaN(chunka); | |
bnum = !isNaN(chunkb); | |
if (anum && !bnum) | |
return -1; | |
if (bnum && !anum) | |
return 1; | |
if (anum && bnum) { | |
diff = chunka - chunkb; | |
if (diff === 0 && chunka.length !== chunkb.length) { | |
if (!+chunka && !+chunkb) | |
return chunka.length - chunkb.length; | |
else | |
return chunkb.length - chunka.length; | |
} | |
} else if (chunka !== chunkb) | |
return (chunka < chunkb) ? -1 : 1; | |
a = a.substring(chunka.length); | |
b = b.substring(chunkb.length); | |
} | |
return diff; | |
} | |
WebInspector.ObjectPropertyTreeElement = function(property) | |
{ | |
this.property = property; | |
TreeElement.call(this, "", null, false); | |
this.toggleOnClick = true; | |
this.selectable = false; | |
} | |
WebInspector.ObjectPropertyTreeElement.prototype = { | |
onpopulate: function() | |
{ | |
return WebInspector.ObjectPropertyTreeElement.populate(this, this.property.value); | |
}, | |
ondblclick: function(event) | |
{ | |
if (this.property.writable) | |
this.startEditing(event); | |
}, | |
onattach: function() | |
{ | |
this.update(); | |
}, | |
update: function() | |
{ | |
this.nameElement = document.createElement("span"); | |
this.nameElement.className = "name"; | |
this.nameElement.textContent = this.property.name; | |
if (!this.property.enumerable) | |
this.nameElement.addStyleClass("dimmed"); | |
var separatorElement = document.createElement("span"); | |
separatorElement.className = "separator"; | |
separatorElement.textContent = ": "; | |
this.valueElement = document.createElement("span"); | |
this.valueElement.className = "value"; | |
var description = this.property.value.description; | |
if (this.property.wasThrown) | |
this.valueElement.textContent = "[Exception: " + description + "]"; | |
else if (this.property.value.type === "string" && typeof description === "string") { | |
this.valueElement.textContent = "\"" + description.replace(/\n/g, "\u21B5") + "\""; | |
this.valueElement._originalTextContent = "\"" + description + "\""; | |
} else if (this.property.value.type === "function" && typeof description === "string") { | |
this.valueElement.textContent = /.*/.exec(description)[0].replace(/ +$/g, ""); | |
this.valueElement._originalTextContent = description; | |
} else | |
this.valueElement.textContent = description; | |
if (this.property.wasThrown) | |
this.valueElement.addStyleClass("error"); | |
if (this.property.value.subtype) | |
this.valueElement.addStyleClass("console-formatted-" + this.property.value.subtype); | |
else if (this.property.value.type) | |
this.valueElement.addStyleClass("console-formatted-" + this.property.value.type); | |
this.valueElement.addEventListener("contextmenu", this._contextMenuFired.bind(this, this.property.value), false); | |
this.valueElement.title = description || ""; | |
this.listItemElement.removeChildren(); | |
this.listItemElement.appendChild(this.nameElement); | |
this.listItemElement.appendChild(separatorElement); | |
this.listItemElement.appendChild(this.valueElement); | |
this.hasChildren = this.property.value.hasChildren && !this.property.wasThrown; | |
}, | |
_contextMenuFired: function(value, event) | |
{ | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendApplicableItems(value); | |
contextMenu.show(event); | |
}, | |
updateSiblings: function() | |
{ | |
if (this.parent.root) | |
this.treeOutline.section.update(); | |
else | |
this.parent.shouldRefreshChildren = true; | |
}, | |
renderPromptAsBlock: function() | |
{ | |
return false; | |
}, | |
elementAndValueToEdit: function(event) | |
{ | |
return [this.valueElement, (typeof this.valueElement._originalTextContent === "string") ? this.valueElement._originalTextContent : undefined]; | |
}, | |
startEditing: function(event) | |
{ | |
var elementAndValueToEdit = this.elementAndValueToEdit(event); | |
var elementToEdit = elementAndValueToEdit[0]; | |
var valueToEdit = elementAndValueToEdit[1]; | |
if (WebInspector.isBeingEdited(elementToEdit) || !this.treeOutline.section.editable || this._readOnly) | |
return; | |
if (typeof valueToEdit !== "undefined") | |
elementToEdit.textContent = valueToEdit; | |
var context = { expanded: this.expanded, elementToEdit: elementToEdit, previousContent: elementToEdit.textContent }; | |
this.hasChildren = false; | |
this.listItemElement.addStyleClass("editing-sub-part"); | |
this._prompt = new WebInspector.ObjectPropertyPrompt(this.editingCommitted.bind(this, null, elementToEdit.textContent, context.previousContent, context), this.editingCancelled.bind(this, null, context), this.renderPromptAsBlock()); | |
function blurListener() | |
{ | |
this.editingCommitted(null, elementToEdit.textContent, context.previousContent, context); | |
} | |
var proxyElement = this._prompt.attachAndStartEditing(elementToEdit, blurListener.bind(this)); | |
window.getSelection().setBaseAndExtent(elementToEdit, 0, elementToEdit, 1); | |
proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this, context), false); | |
}, | |
editingEnded: function(context) | |
{ | |
this._prompt.detach(); | |
delete this._prompt; | |
this.listItemElement.scrollLeft = 0; | |
this.listItemElement.removeStyleClass("editing-sub-part"); | |
if (context.expanded) | |
this.expand(); | |
}, | |
editingCancelled: function(element, context) | |
{ | |
this.editingEnded(context); | |
this.update(); | |
}, | |
editingCommitted: function(element, userInput, previousContent, context) | |
{ | |
if (userInput === previousContent) | |
return this.editingCancelled(element, context); | |
this.editingEnded(context); | |
this.applyExpression(userInput, true); | |
}, | |
_promptKeyDown: function(context, event) | |
{ | |
if (isEnterKey(event)) { | |
event.consume(true); | |
return this.editingCommitted(null, context.elementToEdit.textContent, context.previousContent, context); | |
} | |
if (event.keyIdentifier === "U+001B") { | |
event.consume(); | |
return this.editingCancelled(null, context); | |
} | |
}, | |
applyExpression: function(expression, updateInterface) | |
{ | |
expression = expression.trim(); | |
var expressionLength = expression.length; | |
function callback(error) | |
{ | |
if (!updateInterface) | |
return; | |
if (error) | |
this.update(); | |
if (!expressionLength) { | |
this.parent.removeChild(this); | |
} else { | |
this.updateSiblings(); | |
} | |
}; | |
this.property.parentObject.setPropertyValue(this.property.name, expression.trim(), callback.bind(this)); | |
} | |
} | |
WebInspector.ObjectPropertyTreeElement.populate = function(treeElement, value) { | |
if (treeElement.children.length && !treeElement.shouldRefreshChildren) | |
return; | |
if (value.arrayLength() > WebInspector.ObjectPropertiesSection._arrayLoadThreshold) { | |
treeElement.removeChildren(); | |
WebInspector.ArrayGroupingTreeElement._populateArray(treeElement, value, 0, value.arrayLength() - 1); | |
return; | |
} | |
function callback(properties) | |
{ | |
treeElement.removeChildren(); | |
if (!properties) | |
return; | |
properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties); | |
for (var i = 0; i < properties.length; ++i) { | |
if (treeElement.treeOutline.section.skipProto && properties[i].name === "__proto__") | |
continue; | |
properties[i].parentObject = value; | |
treeElement.appendChild(new treeElement.treeOutline.section.treeElementConstructor(properties[i])); | |
} | |
if (value.type === "function") | |
treeElement.appendChild(new WebInspector.FunctionScopeMainTreeElement(value)); | |
} | |
value.getOwnProperties(callback); | |
} | |
WebInspector.ObjectPropertyTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.FunctionScopeMainTreeElement = function(remoteObject) | |
{ | |
TreeElement.call(this, "<function scope>", null, false); | |
this.toggleOnClick = true; | |
this.selectable = false; | |
this._remoteObject = remoteObject; | |
this.hasChildren = true; | |
} | |
WebInspector.FunctionScopeMainTreeElement.prototype = { | |
onpopulate: function() | |
{ | |
if (this.children.length && !this.shouldRefreshChildren) | |
return; | |
function didGetDetails(error, response) | |
{ | |
if (error) { | |
console.error(error); | |
return; | |
} | |
this.removeChildren(); | |
var scopeChain = response.scopeChain; | |
for (var i = 0; i < scopeChain.length; ++i) { | |
var scope = scopeChain[i]; | |
var title = null; | |
var isTrueObject; | |
switch (scope.type) { | |
case "local": | |
title = WebInspector.UIString("Local"); | |
isTrueObject = false; | |
break; | |
case "closure": | |
title = WebInspector.UIString("Closure"); | |
isTrueObject = false; | |
break; | |
case "catch": | |
title = WebInspector.UIString("Catch"); | |
isTrueObject = false; | |
break; | |
case "with": | |
title = WebInspector.UIString("With Block"); | |
isTrueObject = true; | |
break; | |
case "global": | |
title = WebInspector.UIString("Global"); | |
isTrueObject = true; | |
break; | |
} | |
var remoteObject = WebInspector.RemoteObject.fromPayload(scope.object); | |
if (isTrueObject) { | |
var property = WebInspector.RemoteObjectProperty.fromScopeValue(title, remoteObject); | |
property.parentObject = null; | |
this.appendChild(new this.treeOutline.section.treeElementConstructor(property)); | |
} else { | |
var scopeTreeElement = new WebInspector.ScopeTreeElement(title, null, remoteObject); | |
this.appendChild(scopeTreeElement); | |
} | |
} | |
} | |
DebuggerAgent.getFunctionDetails(this._remoteObject.objectId, didGetDetails.bind(this)); | |
} | |
}; | |
WebInspector.FunctionScopeMainTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.ScopeTreeElement = function(title, subtitle, remoteObject) | |
{ | |
TreeElement.call(this, title, null, false); | |
this.toggleOnClick = true; | |
this.selectable = false; | |
this._remoteObject = remoteObject; | |
this.hasChildren = true; | |
} | |
WebInspector.ScopeTreeElement.prototype = { | |
onpopulate: function() | |
{ | |
return WebInspector.ObjectPropertyTreeElement.populate(this, this._remoteObject); | |
} | |
}; | |
WebInspector.ScopeTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.ArrayGroupingTreeElement = function(object, fromIndex, toIndex, propertyCount) | |
{ | |
TreeElement.call(this, String.sprintf("[%d \u2026 %d]", fromIndex, toIndex), undefined, true); | |
this._fromIndex = fromIndex; | |
this._toIndex = toIndex; | |
this._object = object; | |
this._readOnly = true; | |
this._propertyCount = propertyCount; | |
this._populated = false; | |
} | |
WebInspector.ArrayGroupingTreeElement._bucketThreshold = 100; | |
WebInspector.ArrayGroupingTreeElement._populateArray = function(treeElement, object, fromIndex, toIndex) | |
{ | |
WebInspector.ArrayGroupingTreeElement._populateRanges(treeElement, object, fromIndex, toIndex, true); | |
} | |
WebInspector.ArrayGroupingTreeElement._populateRanges = function(treeElement, object, fromIndex, toIndex, topLevel) | |
{ | |
object.callFunctionJSON(packRanges, [{value: fromIndex}, {value: toIndex}, {value: WebInspector.ArrayGroupingTreeElement._bucketThreshold}], callback.bind(this)); | |
function packRanges(fromIndex, toIndex, bucketThreshold) | |
{ | |
var count = 0; | |
for (var i = fromIndex; i <= toIndex; ++i) { | |
var value = this[i]; | |
if (typeof value !== "undefined") | |
++count; | |
} | |
var bucketSize = count; | |
if (count <= bucketThreshold) | |
bucketSize = count; | |
else | |
bucketSize = Math.pow(bucketThreshold, Math.floor(Math.log(count) / Math.log(bucketThreshold))); | |
var ranges = []; | |
count = 0; | |
var groupStart = -1; | |
var groupEnd = 0; | |
for (var i = fromIndex; i <= toIndex; ++i) { | |
var value = this[i]; | |
if (typeof value === "undefined") | |
continue; | |
if (groupStart === -1) | |
groupStart = i; | |
groupEnd = i; | |
if (++count === bucketSize) { | |
ranges.push([groupStart, groupEnd, count]); | |
count = 0; | |
groupStart = -1; | |
} | |
} | |
if (count > 0) | |
ranges.push([groupStart, groupEnd, count]); | |
return ranges; | |
} | |
function callback(ranges) | |
{ | |
if (ranges.length == 1) | |
WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeElement, object, ranges[0][0], ranges[0][1]); | |
else { | |
for (var i = 0; i < ranges.length; ++i) { | |
var fromIndex = ranges[i][0]; | |
var toIndex = ranges[i][1]; | |
var count = ranges[i][2]; | |
if (fromIndex == toIndex) | |
WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeElement, object, fromIndex, toIndex); | |
else | |
treeElement.appendChild(new WebInspector.ArrayGroupingTreeElement(object, fromIndex, toIndex, count)); | |
} | |
} | |
if (topLevel) | |
WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties(treeElement, object); | |
} | |
} | |
WebInspector.ArrayGroupingTreeElement._populateAsFragment = function(treeElement, object, fromIndex, toIndex) | |
{ | |
object.callFunction(buildArrayFragment, [{value: fromIndex}, {value: toIndex}], processArrayFragment.bind(this)); | |
function buildArrayFragment(fromIndex, toIndex) | |
{ | |
var result = Object.create(null); | |
for (var i = fromIndex; i <= toIndex; ++i) { | |
var value = this[i]; | |
if (typeof value !== "undefined") | |
result[i] = value; | |
} | |
return result; | |
} | |
function processArrayFragment(arrayFragment) | |
{ | |
arrayFragment.getAllProperties(processProperties.bind(this)); | |
} | |
function processProperties(properties) | |
{ | |
if (!properties) | |
return; | |
properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties); | |
for (var i = 0; i < properties.length; ++i) { | |
properties[i].parentObject = this._object; | |
var childTreeElement = new treeElement.treeOutline.section.treeElementConstructor(properties[i]); | |
childTreeElement._readOnly = true; | |
treeElement.appendChild(childTreeElement); | |
} | |
} | |
} | |
WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties = function(treeElement, object) | |
{ | |
object.callFunction(buildObjectFragment, undefined, processObjectFragment.bind(this)); | |
function buildObjectFragment() | |
{ | |
var result = Object.create(this.__proto__); | |
var names = Object.getOwnPropertyNames(this); | |
for (var i = 0; i < names.length; ++i) { | |
var name = names[i]; | |
if (!isNaN(name)) | |
continue; | |
var descriptor = Object.getOwnPropertyDescriptor(this, name); | |
if (descriptor) | |
Object.defineProperty(result, name, descriptor); | |
} | |
return result; | |
} | |
function processObjectFragment(arrayFragment) | |
{ | |
arrayFragment.getOwnProperties(processProperties.bind(this)); | |
} | |
function processProperties(properties) | |
{ | |
if (!properties) | |
return; | |
properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties); | |
for (var i = 0; i < properties.length; ++i) { | |
properties[i].parentObject = this._object; | |
var childTreeElement = new treeElement.treeOutline.section.treeElementConstructor(properties[i]); | |
childTreeElement._readOnly = true; | |
treeElement.appendChild(childTreeElement); | |
} | |
} | |
} | |
WebInspector.ArrayGroupingTreeElement.prototype = { | |
onpopulate: function() | |
{ | |
if (this._populated) | |
return; | |
this._populated = true; | |
if (this._propertyCount >= WebInspector.ArrayGroupingTreeElement._bucketThreshold) { | |
WebInspector.ArrayGroupingTreeElement._populateRanges(this, this._object, this._fromIndex, this._toIndex, false); | |
return; | |
} | |
WebInspector.ArrayGroupingTreeElement._populateAsFragment(this, this._object, this._fromIndex, this._toIndex); | |
}, | |
onattach: function() | |
{ | |
this.listItemElement.addStyleClass("name"); | |
} | |
} | |
WebInspector.ArrayGroupingTreeElement.prototype.__proto__ = TreeElement.prototype; | |
WebInspector.ObjectPropertyPrompt = function(commitHandler, cancelHandler, renderAsBlock) | |
{ | |
const ExpressionStopCharacters = " =:[({;,!+-*/&|^<>."; | |
WebInspector.TextPrompt.call(this, WebInspector.consoleView.completionsForTextPrompt.bind(WebInspector.consoleView), ExpressionStopCharacters); | |
this.setSuggestBoxEnabled("generic-suggest"); | |
if (renderAsBlock) | |
this.renderAsBlock(); | |
} | |
WebInspector.ObjectPropertyPrompt.prototype.__proto__ = WebInspector.TextPrompt.prototype; | |
WebInspector.ObjectPopoverHelper = function(panelElement, getAnchor, queryObject, onHide, disableOnClick) | |
{ | |
WebInspector.PopoverHelper.call(this, panelElement, getAnchor, this._showObjectPopover.bind(this), this._onHideObjectPopover.bind(this), disableOnClick); | |
this._queryObject = queryObject; | |
this._onHideCallback = onHide; | |
this._popoverObjectGroup = "popover"; | |
panelElement.addEventListener("scroll", this.hidePopover.bind(this), true); | |
}; | |
WebInspector.ObjectPopoverHelper.prototype = { | |
_showObjectPopover: function(element, popover) | |
{ | |
function showObjectPopover(result, wasThrown, anchorOverride) | |
{ | |
if (popover.disposed) | |
return; | |
if (wasThrown) { | |
this.hidePopover(); | |
return; | |
} | |
var anchorElement = anchorOverride || element; | |
var popoverContentElement = null; | |
if (result.type !== "object") { | |
popoverContentElement = document.createElement("span"); | |
popoverContentElement.className = "monospace console-formatted-" + result.type; | |
popoverContentElement.style.whiteSpace = "pre"; | |
popoverContentElement.textContent = result.description; | |
if (result.type === "function") { | |
function didGetDetails(error, response) | |
{ | |
if (error) { | |
console.error(error); | |
return; | |
} | |
var container = document.createElement("div"); | |
container.style.display = "inline-block"; | |
var title = container.createChild("div", "function-popover-title source-code"); | |
var functionName = title.createChild("span", "function-name"); | |
functionName.textContent = response.name || response.inferredName || response.displayName || WebInspector.UIString("(anonymous function)"); | |
this._linkifier = new WebInspector.Linkifier(); | |
var rawLocation = response.location; | |
var link = this._linkifier.linkifyRawLocation(rawLocation, "function-location-link"); | |
if (link) | |
title.appendChild(link); | |
container.appendChild(popoverContentElement); | |
popover.show(container, anchorElement); | |
} | |
DebuggerAgent.getFunctionDetails(result.objectId, didGetDetails.bind(this)); | |
return; | |
} | |
if (result.type === "string") | |
popoverContentElement.textContent = "\"" + popoverContentElement.textContent + "\""; | |
popover.show(popoverContentElement, anchorElement); | |
} else { | |
popoverContentElement = document.createElement("div"); | |
this._titleElement = document.createElement("div"); | |
this._titleElement.className = "source-frame-popover-title monospace"; | |
this._titleElement.textContent = result.description; | |
popoverContentElement.appendChild(this._titleElement); | |
var section = new WebInspector.ObjectPropertiesSection(result); | |
if (result.description.substr(0, 4) === "HTML") { | |
this._sectionUpdateProperties = section.updateProperties.bind(section); | |
section.updateProperties = this._updateHTMLId.bind(this); | |
} | |
section.expanded = true; | |
section.element.addStyleClass("source-frame-popover-tree"); | |
section.headerElement.addStyleClass("hidden"); | |
popoverContentElement.appendChild(section.element); | |
const popoverWidth = 300; | |
const popoverHeight = 250; | |
popover.show(popoverContentElement, anchorElement, popoverWidth, popoverHeight); | |
} | |
} | |
this._queryObject(element, showObjectPopover.bind(this), this._popoverObjectGroup); | |
}, | |
_onHideObjectPopover: function() | |
{ | |
if (this._linkifier) { | |
this._linkifier.reset(); | |
delete this._linkifier; | |
} | |
if (this._onHideCallback) | |
this._onHideCallback(); | |
RuntimeAgent.releaseObjectGroup(this._popoverObjectGroup); | |
}, | |
_updateHTMLId: function(properties, rootTreeElementConstructor, rootPropertyComparer) | |
{ | |
for (var i = 0; i < properties.length; ++i) { | |
if (properties[i].name === "id") { | |
if (properties[i].value.description) | |
this._titleElement.textContent += "#" + properties[i].value.description; | |
break; | |
} | |
} | |
this._sectionUpdateProperties(properties, rootTreeElementConstructor, rootPropertyComparer); | |
} | |
} | |
WebInspector.ObjectPopoverHelper.prototype.__proto__ = WebInspector.PopoverHelper.prototype; | |
WebInspector.NativeBreakpointsSidebarPane = function(title) | |
{ | |
WebInspector.SidebarPane.call(this, title); | |
this.listElement = document.createElement("ol"); | |
this.listElement.className = "breakpoint-list"; | |
this.emptyElement = document.createElement("div"); | |
this.emptyElement.className = "info"; | |
this.emptyElement.textContent = WebInspector.UIString("No Breakpoints"); | |
this.bodyElement.appendChild(this.emptyElement); | |
} | |
WebInspector.NativeBreakpointsSidebarPane.prototype = { | |
_addListElement: function(element, beforeElement) | |
{ | |
if (beforeElement) | |
this.listElement.insertBefore(element, beforeElement); | |
else { | |
if (!this.listElement.firstChild) { | |
this.bodyElement.removeChild(this.emptyElement); | |
this.bodyElement.appendChild(this.listElement); | |
} | |
this.listElement.appendChild(element); | |
} | |
}, | |
_removeListElement: function(element) | |
{ | |
this.listElement.removeChild(element); | |
if (!this.listElement.firstChild) { | |
this.bodyElement.removeChild(this.listElement); | |
this.bodyElement.appendChild(this.emptyElement); | |
} | |
}, | |
_reset: function() | |
{ | |
this.listElement.removeChildren(); | |
if (this.listElement.parentElement) { | |
this.bodyElement.removeChild(this.listElement); | |
this.bodyElement.appendChild(this.emptyElement); | |
} | |
} | |
} | |
WebInspector.NativeBreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; | |
WebInspector.DOMBreakpointsSidebarPane = function() | |
{ | |
WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("DOM Breakpoints")); | |
this._breakpointElements = {}; | |
this._breakpointTypes = { | |
SubtreeModified: "subtree-modified", | |
AttributeModified: "attribute-modified", | |
NodeRemoved: "node-removed" | |
}; | |
this._breakpointTypeLabels = {}; | |
this._breakpointTypeLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString("Subtree Modified"); | |
this._breakpointTypeLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString("Attribute Modified"); | |
this._breakpointTypeLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString("Node Removed"); | |
this._contextMenuLabels = {}; | |
this._contextMenuLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Subtree modifications" : "Subtree Modifications"); | |
this._contextMenuLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Attributes modifications" : "Attributes Modifications"); | |
this._contextMenuLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Node removal" : "Node Removal"); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this); | |
WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeRemoved, this._nodeRemoved, this); | |
} | |
WebInspector.DOMBreakpointsSidebarPane.prototype = { | |
_inspectedURLChanged: function(event) | |
{ | |
this._breakpointElements = {}; | |
this._reset(); | |
var url = event.data; | |
this._inspectedURL = url.removeURLFragment(); | |
}, | |
populateNodeContextMenu: function(node, contextMenu) | |
{ | |
var nodeBreakpoints = {}; | |
for (var id in this._breakpointElements) { | |
var element = this._breakpointElements[id]; | |
if (element._node === node) | |
nodeBreakpoints[element._type] = true; | |
} | |
function toggleBreakpoint(type) | |
{ | |
if (!nodeBreakpoints[type]) | |
this._setBreakpoint(node, type, true); | |
else | |
this._removeBreakpoint(node, type); | |
this._saveBreakpoints(); | |
} | |
var breakPointSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Break on...")); | |
for (var key in this._breakpointTypes) { | |
var type = this._breakpointTypes[key]; | |
var label = this._contextMenuLabels[type]; | |
breakPointSubMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this, type), nodeBreakpoints[type]); | |
} | |
}, | |
createBreakpointHitStatusMessage: function(auxData, callback) | |
{ | |
if (auxData.type === this._breakpointTypes.SubtreeModified) { | |
var targetNodeObject = WebInspector.RemoteObject.fromPayload(auxData["targetNode"]); | |
function didPushNodeToFrontend(targetNodeId) | |
{ | |
if (targetNodeId) | |
targetNodeObject.release(); | |
this._doCreateBreakpointHitStatusMessage(auxData, targetNodeId, callback); | |
} | |
targetNodeObject.pushNodeToFrontend(didPushNodeToFrontend.bind(this)); | |
} else | |
this._doCreateBreakpointHitStatusMessage(auxData, null, callback); | |
}, | |
_doCreateBreakpointHitStatusMessage: function (auxData, targetNodeId, callback) | |
{ | |
var message; | |
var typeLabel = this._breakpointTypeLabels[auxData.type]; | |
var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeById(auxData.nodeId); | |
var substitutions = [typeLabel, linkifiedNode]; | |
var targetNode = ""; | |
if (targetNodeId) | |
targetNode = WebInspector.DOMPresentationUtils.linkifyNodeById(targetNodeId); | |
if (auxData.type === this._breakpointTypes.SubtreeModified) { | |
if (auxData.insertion) { | |
if (targetNodeId !== auxData.nodeId) { | |
message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s."; | |
substitutions.push(targetNode); | |
} else | |
message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node."; | |
} else { | |
message = "Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed."; | |
substitutions.push(targetNode); | |
} | |
} else | |
message = "Paused on a \"%s\" breakpoint set on %s."; | |
var element = document.createElement("span"); | |
var formatters = { | |
s: function(substitution) | |
{ | |
return substitution; | |
} | |
}; | |
function append(a, b) | |
{ | |
if (typeof b === "string") | |
b = document.createTextNode(b); | |
element.appendChild(b); | |
} | |
WebInspector.formatLocalized(message, substitutions, formatters, "", append); | |
callback(element); | |
}, | |
_nodeRemoved: function(event) | |
{ | |
var node = event.data.node; | |
this._removeBreakpointsForNode(event.data.node); | |
if (!node.children) | |
return; | |
for (var i = 0; i < node.children.length; ++i) | |
this._removeBreakpointsForNode(node.children[i]); | |
this._saveBreakpoints(); | |
}, | |
_removeBreakpointsForNode: function(node) | |
{ | |
for (var id in this._breakpointElements) { | |
var element = this._breakpointElements[id]; | |
if (element._node === node) | |
this._removeBreakpoint(element._node, element._type); | |
} | |
}, | |
_setBreakpoint: function(node, type, enabled) | |
{ | |
var breakpointId = this._createBreakpointId(node.id, type); | |
if (breakpointId in this._breakpointElements) | |
return; | |
var element = document.createElement("li"); | |
element._node = node; | |
element._type = type; | |
element.addEventListener("contextmenu", this._contextMenu.bind(this, node, type), true); | |
var checkboxElement = document.createElement("input"); | |
checkboxElement.className = "checkbox-elem"; | |
checkboxElement.type = "checkbox"; | |
checkboxElement.checked = enabled; | |
checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, node, type), false); | |
element._checkboxElement = checkboxElement; | |
element.appendChild(checkboxElement); | |
var labelElement = document.createElement("span"); | |
element.appendChild(labelElement); | |
var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeById(node.id); | |
linkifiedNode.addStyleClass("monospace"); | |
labelElement.appendChild(linkifiedNode); | |
var description = document.createElement("div"); | |
description.className = "source-text"; | |
description.textContent = this._breakpointTypeLabels[type]; | |
labelElement.appendChild(description); | |
var currentElement = this.listElement.firstChild; | |
while (currentElement) { | |
if (currentElement._type && currentElement._type < element._type) | |
break; | |
currentElement = currentElement.nextSibling; | |
} | |
this._addListElement(element, currentElement); | |
this._breakpointElements[breakpointId] = element; | |
if (enabled) | |
DOMDebuggerAgent.setDOMBreakpoint(node.id, type); | |
}, | |
_removeAllBreakpoints: function() | |
{ | |
for (var id in this._breakpointElements) { | |
var element = this._breakpointElements[id]; | |
this._removeBreakpoint(element._node, element._type); | |
} | |
this._saveBreakpoints(); | |
}, | |
_removeBreakpoint: function(node, type) | |
{ | |
var breakpointId = this._createBreakpointId(node.id, type); | |
var element = this._breakpointElements[breakpointId]; | |
if (!element) | |
return; | |
this._removeListElement(element); | |
delete this._breakpointElements[breakpointId]; | |
if (element._checkboxElement.checked) | |
DOMDebuggerAgent.removeDOMBreakpoint(node.id, type); | |
}, | |
_contextMenu: function(node, type, event) | |
{ | |
var contextMenu = new WebInspector.ContextMenu(); | |
function removeBreakpoint() | |
{ | |
this._removeBreakpoint(node, type); | |
this._saveBreakpoints(); | |
} | |
contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), removeBreakpoint.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all DOM breakpoints" : "Remove All DOM Breakpoints"), this._removeAllBreakpoints.bind(this)); | |
contextMenu.show(event); | |
}, | |
_checkboxClicked: function(node, type, event) | |
{ | |
if (event.target.checked) | |
DOMDebuggerAgent.setDOMBreakpoint(node.id, type); | |
else | |
DOMDebuggerAgent.removeDOMBreakpoint(node.id, type); | |
this._saveBreakpoints(); | |
}, | |
highlightBreakpoint: function(auxData) | |
{ | |
var breakpointId = this._createBreakpointId(auxData.nodeId, auxData.type); | |
var element = this._breakpointElements[breakpointId]; | |
if (!element) | |
return; | |
this.expanded = true; | |
element.addStyleClass("breakpoint-hit"); | |
this._highlightedElement = element; | |
}, | |
clearBreakpointHighlight: function() | |
{ | |
if (this._highlightedElement) { | |
this._highlightedElement.removeStyleClass("breakpoint-hit"); | |
delete this._highlightedElement; | |
} | |
}, | |
_createBreakpointId: function(nodeId, type) | |
{ | |
return nodeId + ":" + type; | |
}, | |
_saveBreakpoints: function() | |
{ | |
var breakpoints = []; | |
var storedBreakpoints = WebInspector.settings.domBreakpoints.get(); | |
for (var i = 0; i < storedBreakpoints.length; ++i) { | |
var breakpoint = storedBreakpoints[i]; | |
if (breakpoint.url !== this._inspectedURL) | |
breakpoints.push(breakpoint); | |
} | |
for (var id in this._breakpointElements) { | |
var element = this._breakpointElements[id]; | |
breakpoints.push({ url: this._inspectedURL, path: element._node.path(), type: element._type, enabled: element._checkboxElement.checked }); | |
} | |
WebInspector.settings.domBreakpoints.set(breakpoints); | |
}, | |
restoreBreakpoints: function() | |
{ | |
var pathToBreakpoints = {}; | |
function didPushNodeByPathToFrontend(path, nodeId) | |
{ | |
var node = WebInspector.domAgent.nodeForId(nodeId); | |
if (!node) | |
return; | |
var breakpoints = pathToBreakpoints[path]; | |
for (var i = 0; i < breakpoints.length; ++i) | |
this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].enabled); | |
} | |
var breakpoints = WebInspector.settings.domBreakpoints.get(); | |
for (var i = 0; i < breakpoints.length; ++i) { | |
var breakpoint = breakpoints[i]; | |
if (breakpoint.url !== this._inspectedURL) | |
continue; | |
var path = breakpoint.path; | |
if (!pathToBreakpoints[path]) { | |
pathToBreakpoints[path] = []; | |
WebInspector.domAgent.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path)); | |
} | |
pathToBreakpoints[path].push(breakpoint); | |
} | |
} | |
} | |
WebInspector.DOMBreakpointsSidebarPane.prototype.__proto__ = WebInspector.NativeBreakpointsSidebarPane.prototype; | |
WebInspector.Color = function(str) | |
{ | |
this.value = str; | |
this._parse(); | |
} | |
WebInspector.Color.fromRGBA = function(r, g, b, a) | |
{ | |
return new WebInspector.Color("rgba(" + r + "," + g + "," + b + "," + (typeof a === "undefined" ? 1 : a) + ")"); | |
} | |
WebInspector.Color.fromRGB = function(r, g, b) | |
{ | |
return new WebInspector.Color("rgb(" + r + "," + g + "," + b + ")"); | |
} | |
WebInspector.Color.prototype = { | |
get shorthex() | |
{ | |
if ("_short" in this) | |
return this._short; | |
if (!this.simple) | |
return ""; | |
var hex = this.hex; | |
if (hex.charAt(0) === hex.charAt(1) && hex.charAt(2) === hex.charAt(3) && hex.charAt(4) === hex.charAt(5)) | |
this._short = hex.charAt(0) + hex.charAt(2) + hex.charAt(4); | |
else | |
this._short = hex; | |
return this._short; | |
}, | |
get hex() | |
{ | |
if (!this.simple) | |
return ""; | |
return this._hex; | |
}, | |
set hex(x) | |
{ | |
this._hex = x; | |
}, | |
get rgb() | |
{ | |
if (this._rgb) | |
return this._rgb; | |
if (this.simple) | |
this._rgb = this._hexToRGB(this.hex); | |
else { | |
var rgba = this.rgba; | |
this._rgb = [rgba[0], rgba[1], rgba[2]]; | |
} | |
return this._rgb; | |
}, | |
set rgb(x) | |
{ | |
this._rgb = x; | |
}, | |
get hsl() | |
{ | |
if (this._hsl) | |
return this._hsl; | |
this._hsl = this._rgbToHSL(this.rgb); | |
return this._hsl; | |
}, | |
set hsl(x) | |
{ | |
this._hsl = x; | |
}, | |
get nickname() | |
{ | |
if (typeof this._nickname !== "undefined") | |
return this._nickname; | |
else | |
return ""; | |
}, | |
set nickname(x) | |
{ | |
this._nickname = x; | |
}, | |
get rgba() | |
{ | |
return this._rgba; | |
}, | |
set rgba(x) | |
{ | |
this._rgba = x; | |
}, | |
get hsla() | |
{ | |
return this._hsla; | |
}, | |
set hsla(x) | |
{ | |
this._hsla = x; | |
}, | |
hasShortHex: function() | |
{ | |
var shorthex = this.shorthex; | |
return (!!shorthex && shorthex.length === 3); | |
}, | |
toString: function(format) | |
{ | |
if (!format) | |
format = this.format; | |
switch (format) { | |
case "original": | |
return this.value; | |
case "rgb": | |
return "rgb(" + this.rgb.join(", ") + ")"; | |
case "rgba": | |
return "rgba(" + this.rgba.join(", ") + ")"; | |
case "hsl": | |
var hsl = this.hsl; | |
return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)"; | |
case "hsla": | |
var hsla = this.hsla; | |
return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " + hsla[3] + ")"; | |
case "hex": | |
return "#" + this.hex; | |
case "shorthex": | |
return "#" + this.shorthex; | |
case "nickname": | |
return this.nickname; | |
} | |
throw "invalid color format"; | |
}, | |
toProtocolRGBA: function() | |
{ | |
if (this._protocolRGBA) | |
return this._protocolRGBA; | |
var components = this.rgba; | |
if (components) | |
this._protocolRGBA = { r: Number(components[0]), g: Number(components[1]), b: Number(components[2]), a: Number(components[3]) }; | |
else { | |
components = this.rgb; | |
this._protocolRGBA = { r: Number(components[0]), g: Number(components[1]), b: Number(components[2]) }; | |
} | |
return this._protocolRGBA; | |
}, | |
_clamp: function(value, min, max) | |
{ | |
if (value < min) | |
return min; | |
if (value > max) | |
return max; | |
return value; | |
}, | |
_individualRGBValueToFloatValue: function(rgbValue) | |
{ | |
if (typeof rgbValue === "number") | |
return this._clamp(rgbValue, 0, 255); | |
if (rgbValue.indexOf("%") === -1) { | |
var intValue = parseInt(rgbValue, 10); | |
return this._clamp(intValue, 0, 255); | |
} | |
var percentValue = parseFloat(rgbValue); | |
return this._clamp(percentValue, 0, 100) * 2.55; | |
}, | |
_individualRGBValueToHexValue: function(rgbValue) | |
{ | |
var floatValue = this._individualRGBValueToFloatValue(rgbValue); | |
var hex = Math.round(floatValue).toString(16); | |
if (hex.length === 1) | |
hex = "0" + hex; | |
return hex; | |
}, | |
_rgbStringsToHex: function(rgb) | |
{ | |
var r = this._individualRGBValueToHexValue(rgb[0]); | |
var g = this._individualRGBValueToHexValue(rgb[1]); | |
var b = this._individualRGBValueToHexValue(rgb[2]); | |
return (r + g + b).toUpperCase(); | |
}, | |
_rgbToHex: function(rgb) | |
{ | |
var r = this._individualRGBValueToHexValue(rgb[0]); | |
var g = this._individualRGBValueToHexValue(rgb[1]); | |
var b = this._individualRGBValueToHexValue(rgb[2]); | |
return (r + g + b).toUpperCase(); | |
}, | |
_hexToRGB: function(hex) | |
{ | |
var r = parseInt(hex.substring(0,2), 16); | |
var g = parseInt(hex.substring(2,4), 16); | |
var b = parseInt(hex.substring(4,6), 16); | |
return [r, g, b]; | |
}, | |
_rgbToHSL: function(rgb) | |
{ | |
var r = this._individualRGBValueToFloatValue(rgb[0]) / 255; | |
var g = this._individualRGBValueToFloatValue(rgb[1]) / 255; | |
var b = this._individualRGBValueToFloatValue(rgb[2]) / 255; | |
var max = Math.max(r, g, b); | |
var min = Math.min(r, g, b); | |
var diff = max - min; | |
var add = max + min; | |
if (min === max) | |
var h = 0; | |
else if (r === max) | |
var h = ((60 * (g - b) / diff) + 360) % 360; | |
else if (g === max) | |
var h = (60 * (b - r) / diff) + 120; | |
else | |
var h = (60 * (r - g) / diff) + 240; | |
var l = 0.5 * add; | |
if (l === 0) | |
var s = 0; | |
else if (l === 1) | |
var s = 1; | |
else if (l <= 0.5) | |
var s = diff / add; | |
else | |
var s = diff / (2 - add); | |
h = Math.round(h); | |
s = Math.round(s*100); | |
l = Math.round(l*100); | |
return [h, s, l]; | |
}, | |
_hslToRGB: function(hsl) | |
{ | |
var h = parseFloat(hsl[0]) / 360; | |
var s = parseFloat(hsl[1]) / 100; | |
var l = parseFloat(hsl[2]) / 100; | |
if (s < 0) | |
s = 0; | |
if (l <= 0.5) | |
var q = l * (1 + s); | |
else | |
var q = l + s - (l * s); | |
var p = 2 * l - q; | |
var tr = h + (1 / 3); | |
var tg = h; | |
var tb = h - (1 / 3); | |
var r = Math.round(hueToRGB(p, q, tr) * 255); | |
var g = Math.round(hueToRGB(p, q, tg) * 255); | |
var b = Math.round(hueToRGB(p, q, tb) * 255); | |
return [r, g, b]; | |
function hueToRGB(p, q, h) { | |
if (h < 0) | |
h += 1; | |
else if (h > 1) | |
h -= 1; | |
if ((h * 6) < 1) | |
return p + (q - p) * h * 6; | |
else if ((h * 2) < 1) | |
return q; | |
else if ((h * 3) < 2) | |
return p + (q - p) * ((2 / 3) - h) * 6; | |
else | |
return p; | |
} | |
}, | |
_rgbaToHSLA: function(rgba, alpha) | |
{ | |
var hsl = this._rgbToHSL(rgba) | |
hsl.push(alpha); | |
return hsl; | |
}, | |
_hslaToRGBA: function(hsla, alpha) | |
{ | |
var rgb = this._hslToRGB(hsla); | |
rgb.push(alpha); | |
return rgb; | |
}, | |
_parse: function() | |
{ | |
var value = this.value.toLowerCase().replace(/%|\s+/g, ""); | |
if (value in WebInspector.Color.AdvancedNickNames) { | |
this.format = "nickname"; | |
var set = WebInspector.Color.AdvancedNickNames[value]; | |
this.simple = false; | |
this.rgba = set[0]; | |
this.hsla = set[1]; | |
this.nickname = set[2]; | |
this.alpha = set[0][3]; | |
return; | |
} | |
var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i; | |
var match = this.value.match(simple); | |
if (match) { | |
this.simple = true; | |
if (match[1]) { | |
var hex = match[1].toUpperCase(); | |
if (hex.length === 3) { | |
this.format = "shorthex"; | |
this.hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2); | |
} else { | |
this.format = "hex"; | |
this.hex = hex; | |
} | |
} else if (match[2]) { | |
this.format = "rgb"; | |
var rgb = match[2].split(/\s*,\s*/); | |
this.rgb = rgb; | |
this.hex = this._rgbStringsToHex(rgb); | |
} else if (match[3]) { | |
var nickname = match[3].toLowerCase(); | |
if (nickname in WebInspector.Color.Nicknames) { | |
this.format = "nickname"; | |
this.hex = WebInspector.Color.Nicknames[nickname]; | |
} else | |
throw "unknown color name"; | |
} else if (match[4]) { | |
this.format = "hsl"; | |
var hsl = match[4].replace(/%/g, "").split(/\s*,\s*/); | |
this.hsl = hsl; | |
this.rgb = this._hslToRGB(hsl); | |
this.hex = this._rgbToHex(this.rgb); | |
} | |
var hex = this.hex; | |
if (hex && hex in WebInspector.Color.HexTable) { | |
var set = WebInspector.Color.HexTable[hex]; | |
this.rgb = set[0]; | |
this.hsl = set[1]; | |
this.nickname = set[2]; | |
} | |
return; | |
} | |
var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/; | |
match = this.value.match(advanced); | |
if (match) { | |
this.simple = false; | |
if (match[1]) { | |
this.format = "rgba"; | |
this.rgba = match[1].split(/\s*,\s*/); | |
this.rgba[3] = this.alpha = this._clamp(this.rgba[3], 0, 1); | |
this.hsla = this._rgbaToHSLA(this.rgba, this.alpha); | |
} else if (match[2]) { | |
this.format = "hsla"; | |
this.hsla = match[2].replace(/%/g, "").split(/\s*,\s*/); | |
this.hsla[3] = this.alpha = this._clamp(this.hsla[3], 0, 1); | |
this.rgba = this._hslaToRGBA(this.hsla, this.alpha); | |
} | |
return; | |
} | |
throw "could not parse color"; | |
} | |
} | |
WebInspector.Color.HexTable = { | |
"000000": [[0, 0, 0], [0, 0, 0], "black"], | |
"000080": [[0, 0, 128], [240, 100, 25], "navy"], | |
"00008B": [[0, 0, 139], [240, 100, 27], "darkBlue"], | |
"0000CD": [[0, 0, 205], [240, 100, 40], "mediumBlue"], | |
"0000FF": [[0, 0, 255], [240, 100, 50], "blue"], | |
"006400": [[0, 100, 0], [120, 100, 20], "darkGreen"], | |
"008000": [[0, 128, 0], [120, 100, 25], "green"], | |
"008080": [[0, 128, 128], [180, 100, 25], "teal"], | |
"008B8B": [[0, 139, 139], [180, 100, 27], "darkCyan"], | |
"00BFFF": [[0, 191, 255], [195, 100, 50], "deepSkyBlue"], | |
"00CED1": [[0, 206, 209], [181, 100, 41], "darkTurquoise"], | |
"00FA9A": [[0, 250, 154], [157, 100, 49], "mediumSpringGreen"], | |
"00FF00": [[0, 255, 0], [120, 100, 50], "lime"], | |
"00FF7F": [[0, 255, 127], [150, 100, 50], "springGreen"], | |
"00FFFF": [[0, 255, 255], [180, 100, 50], "cyan"], | |
"191970": [[25, 25, 112], [240, 64, 27], "midnightBlue"], | |
"1E90FF": [[30, 144, 255], [210, 100, 56], "dodgerBlue"], | |
"20B2AA": [[32, 178, 170], [177, 70, 41], "lightSeaGreen"], | |
"228B22": [[34, 139, 34], [120, 61, 34], "forestGreen"], | |
"2E8B57": [[46, 139, 87], [146, 50, 36], "seaGreen"], | |
"2F4F4F": [[47, 79, 79], [180, 25, 25], "darkSlateGray"], | |
"32CD32": [[50, 205, 50], [120, 61, 50], "limeGreen"], | |
"3CB371": [[60, 179, 113], [147, 50, 47], "mediumSeaGreen"], | |
"40E0D0": [[64, 224, 208], [174, 72, 56], "turquoise"], | |
"4169E1": [[65, 105, 225], [225, 73, 57], "royalBlue"], | |
"4682B4": [[70, 130, 180], [207, 44, 49], "steelBlue"], | |
"483D8B": [[72, 61, 139], [248, 39, 39], "darkSlateBlue"], | |
"48D1CC": [[72, 209, 204], [178, 60, 55], "mediumTurquoise"], | |
"4B0082": [[75, 0, 130], [275, 100, 25], "indigo"], | |
"556B2F": [[85, 107, 47], [82, 39, 30], "darkOliveGreen"], | |
"5F9EA0": [[95, 158, 160], [182, 25, 50], "cadetBlue"], | |
"6495ED": [[100, 149, 237], [219, 79, 66], "cornflowerBlue"], | |
"66CDAA": [[102, 205, 170], [160, 51, 60], "mediumAquaMarine"], | |
"696969": [[105, 105, 105], [0, 0, 41], "dimGray"], | |
"6A5ACD": [[106, 90, 205], [248, 53, 58], "slateBlue"], | |
"6B8E23": [[107, 142, 35], [80, 60, 35], "oliveDrab"], | |
"708090": [[112, 128, 144], [210, 13, 50], "slateGray"], | |
"778899": [[119, 136, 153], [210, 14, 53], "lightSlateGray"], | |
"7B68EE": [[123, 104, 238], [249, 80, 67], "mediumSlateBlue"], | |
"7CFC00": [[124, 252, 0], [90, 100, 49], "lawnGreen"], | |
"7FFF00": [[127, 255, 0], [90, 100, 50], "chartreuse"], | |
"7FFFD4": [[127, 255, 212], [160, 100, 75], "aquamarine"], | |
"800000": [[128, 0, 0], [0, 100, 25], "maroon"], | |
"800080": [[128, 0, 128], [300, 100, 25], "purple"], | |
"808000": [[128, 128, 0], [60, 100, 25], "olive"], | |
"808080": [[128, 128, 128], [0, 0, 50], "gray"], | |
"87CEEB": [[135, 206, 235], [197, 71, 73], "skyBlue"], | |
"87CEFA": [[135, 206, 250], [203, 92, 75], "lightSkyBlue"], | |
"8A2BE2": [[138, 43, 226], [271, 76, 53], "blueViolet"], | |
"8B0000": [[139, 0, 0], [0, 100, 27], "darkRed"], | |
"8B008B": [[139, 0, 139], [300, 100, 27], "darkMagenta"], | |
"8B4513": [[139, 69, 19], [25, 76, 31], "saddleBrown"], | |
"8FBC8F": [[143, 188, 143], [120, 25, 65], "darkSeaGreen"], | |
"90EE90": [[144, 238, 144], [120, 73, 75], "lightGreen"], | |
"9370D8": [[147, 112, 219], [260, 60, 65], "mediumPurple"], | |
"9400D3": [[148, 0, 211], [282, 100, 41], "darkViolet"], | |
"98FB98": [[152, 251, 152], [120, 93, 79], "paleGreen"], | |
"9932CC": [[153, 50, 204], [280, 61, 50], "darkOrchid"], | |
"9ACD32": [[154, 205, 50], [80, 61, 50], "yellowGreen"], | |
"A0522D": [[160, 82, 45], [19, 56, 40], "sienna"], | |
"A52A2A": [[165, 42, 42], [0, 59, 41], "brown"], | |
"A9A9A9": [[169, 169, 169], [0, 0, 66], "darkGray"], | |
"ADD8E6": [[173, 216, 230], [195, 53, 79], "lightBlue"], | |
"ADFF2F": [[173, 255, 47], [84, 100, 59], "greenYellow"], | |
"AFEEEE": [[175, 238, 238], [180, 65, 81], "paleTurquoise"], | |
"B0C4DE": [[176, 196, 222], [214, 41, 78], "lightSteelBlue"], | |
"B0E0E6": [[176, 224, 230], [187, 52, 80], "powderBlue"], | |
"B22222": [[178, 34, 34], [0, 68, 42], "fireBrick"], | |
"B8860B": [[184, 134, 11], [43, 89, 38], "darkGoldenrod"], | |
"BA55D3": [[186, 85, 211], [288, 59, 58], "mediumOrchid"], | |
"BC8F8F": [[188, 143, 143], [0, 25, 65], "rosyBrown"], | |
"BDB76B": [[189, 183, 107], [56, 38, 58], "darkKhaki"], | |
"C0C0C0": [[192, 192, 192], [0, 0, 75], "silver"], | |
"C71585": [[199, 21, 133], [322, 81, 43], "mediumVioletRed"], | |
"CD5C5C": [[205, 92, 92], [0, 53, 58], "indianRed"], | |
"CD853F": [[205, 133, 63], [30, 59, 53], "peru"], | |
"D2691E": [[210, 105, 30], [25, 75, 47], "chocolate"], | |
"D2B48C": [[210, 180, 140], [34, 44, 69], "tan"], | |
"D3D3D3": [[211, 211, 211], [0, 0, 83], "lightGrey"], | |
"D87093": [[219, 112, 147], [340, 60, 65], "paleVioletRed"], | |
"D8BFD8": [[216, 191, 216], [300, 24, 80], "thistle"], | |
"DA70D6": [[218, 112, 214], [302, 59, 65], "orchid"], | |
"DAA520": [[218, 165, 32], [43, 74, 49], "goldenrod"], | |
"DC143C": [[237, 164, 61], [35, 83, 58], "crimson"], | |
"DCDCDC": [[220, 220, 220], [0, 0, 86], "gainsboro"], | |
"DDA0DD": [[221, 160, 221], [300, 47, 75], "plum"], | |
"DEB887": [[222, 184, 135], [34, 57, 70], "burlyWood"], | |
"E0FFFF": [[224, 255, 255], [180, 100, 94], "lightCyan"], | |
"E6E6FA": [[230, 230, 250], [240, 67, 94], "lavender"], | |
"E9967A": [[233, 150, 122], [15, 72, 70], "darkSalmon"], | |
"EE82EE": [[238, 130, 238], [300, 76, 72], "violet"], | |
"EEE8AA": [[238, 232, 170], [55, 67, 80], "paleGoldenrod"], | |
"F08080": [[240, 128, 128], [0, 79, 72], "lightCoral"], | |
"F0E68C": [[240, 230, 140], [54, 77, 75], "khaki"], | |
"F0F8FF": [[240, 248, 255], [208, 100, 97], "aliceBlue"], | |
"F0FFF0": [[240, 255, 240], [120, 100, 97], "honeyDew"], | |
"F0FFFF": [[240, 255, 255], [180, 100, 97], "azure"], | |
"F4A460": [[244, 164, 96], [28, 87, 67], "sandyBrown"], | |
"F5DEB3": [[245, 222, 179], [39, 77, 83], "wheat"], | |
"F5F5DC": [[245, 245, 220], [60, 56, 91], "beige"], | |
"F5F5F5": [[245, 245, 245], [0, 0, 96], "whiteSmoke"], | |
"F5FFFA": [[245, 255, 250], [150, 100, 98], "mintCream"], | |
"F8F8FF": [[248, 248, 255], [240, 100, 99], "ghostWhite"], | |
"FA8072": [[250, 128, 114], [6, 93, 71], "salmon"], | |
"FAEBD7": [[250, 235, 215], [34, 78, 91], "antiqueWhite"], | |
"FAF0E6": [[250, 240, 230], [30, 67, 94], "linen"], | |
"FAFAD2": [[250, 250, 210], [60, 80, 90], "lightGoldenrodYellow"], | |
"FDF5E6": [[253, 245, 230], [39, 85, 95], "oldLace"], | |
"FF0000": [[255, 0, 0], [0, 100, 50], "red"], | |
"FF00FF": [[255, 0, 255], [300, 100, 50], "magenta"], | |
"FF1493": [[255, 20, 147], [328, 100, 54], "deepPink"], | |
"FF4500": [[255, 69, 0], [16, 100, 50], "orangeRed"], | |
"FF6347": [[255, 99, 71], [9, 100, 64], "tomato"], | |
"FF69B4": [[255, 105, 180], [330, 100, 71], "hotPink"], | |
"FF7F50": [[255, 127, 80], [16, 100, 66], "coral"], | |
"FF8C00": [[255, 140, 0], [33, 100, 50], "darkOrange"], | |
"FFA07A": [[255, 160, 122], [17, 100, 74], "lightSalmon"], | |
"FFA500": [[255, 165, 0], [39, 100, 50], "orange"], | |
"FFB6C1": [[255, 182, 193], [351, 100, 86], "lightPink"], | |
"FFC0CB": [[255, 192, 203], [350, 100, 88], "pink"], | |
"FFD700": [[255, 215, 0], [51, 100, 50], "gold"], | |
"FFDAB9": [[255, 218, 185], [28, 100, 86], "peachPuff"], | |
"FFDEAD": [[255, 222, 173], [36, 100, 84], "navajoWhite"], | |
"FFE4B5": [[255, 228, 181], [38, 100, 85], "moccasin"], | |
"FFE4C4": [[255, 228, 196], [33, 100, 88], "bisque"], | |
"FFE4E1": [[255, 228, 225], [6, 100, 94], "mistyRose"], | |
"FFEBCD": [[255, 235, 205], [36, 100, 90], "blanchedAlmond"], | |
"FFEFD5": [[255, 239, 213], [37, 100, 92], "papayaWhip"], | |
"FFF0F5": [[255, 240, 245], [340, 100, 97], "lavenderBlush"], | |
"FFF5EE": [[255, 245, 238], [25, 100, 97], "seaShell"], | |
"FFF8DC": [[255, 248, 220], [48, 100, 93], "cornsilk"], | |
"FFFACD": [[255, 250, 205], [54, 100, 90], "lemonChiffon"], | |
"FFFAF0": [[255, 250, 240], [40, 100, 97], "floralWhite"], | |
"FFFAFA": [[255, 250, 250], [0, 100, 99], "snow"], | |
"FFFF00": [[255, 255, 0], [60, 100, 50], "yellow"], | |
"FFFFE0": [[255, 255, 224], [60, 100, 94], "lightYellow"], | |
"FFFFF0": [[255, 255, 240], [60, 100, 97], "ivory"], | |
"FFFFFF": [[255, 255, 255], [0, 100, 100], "white"] | |
}; | |
WebInspector.Color.Nicknames = { | |
"aliceblue": "F0F8FF", | |
"antiquewhite": "FAEBD7", | |
"aqua": "00FFFF", | |
"aquamarine": "7FFFD4", | |
"azure": "F0FFFF", | |
"beige": "F5F5DC", | |
"bisque": "FFE4C4", | |
"black": "000000", | |
"blanchedalmond": "FFEBCD", | |
"blue": "0000FF", | |
"blueviolet": "8A2BE2", | |
"brown": "A52A2A", | |
"burlywood": "DEB887", | |
"cadetblue": "5F9EA0", | |
"chartreuse": "7FFF00", | |
"chocolate": "D2691E", | |
"coral": "FF7F50", | |
"cornflowerblue": "6495ED", | |
"cornsilk": "FFF8DC", | |
"crimson": "DC143C", | |
"cyan": "00FFFF", | |
"darkblue": "00008B", | |
"darkcyan": "008B8B", | |
"darkgoldenrod": "B8860B", | |
"darkgray": "A9A9A9", | |
"darkgreen": "006400", | |
"darkkhaki": "BDB76B", | |
"darkmagenta": "8B008B", | |
"darkolivegreen": "556B2F", | |
"darkorange": "FF8C00", | |
"darkorchid": "9932CC", | |
"darkred": "8B0000", | |
"darksalmon": "E9967A", | |
"darkseagreen": "8FBC8F", | |
"darkslateblue": "483D8B", | |
"darkslategray": "2F4F4F", | |
"darkturquoise": "00CED1", | |
"darkviolet": "9400D3", | |
"deeppink": "FF1493", | |
"deepskyblue": "00BFFF", | |
"dimgray": "696969", | |
"dodgerblue": "1E90FF", | |
"firebrick": "B22222", | |
"floralwhite": "FFFAF0", | |
"forestgreen": "228B22", | |
"fuchsia": "FF00FF", | |
"gainsboro": "DCDCDC", | |
"ghostwhite": "F8F8FF", | |
"gold": "FFD700", | |
"goldenrod": "DAA520", | |
"gray": "808080", | |
"green": "008000", | |
"greenyellow": "ADFF2F", | |
"honeydew": "F0FFF0", | |
"hotpink": "FF69B4", | |
"indianred": "CD5C5C", | |
"indigo": "4B0082", | |
"ivory": "FFFFF0", | |
"khaki": "F0E68C", | |
"lavender": "E6E6FA", | |
"lavenderblush": "FFF0F5", | |
"lawngreen": "7CFC00", | |
"lemonchiffon": "FFFACD", | |
"lightblue": "ADD8E6", | |
"lightcoral": "F08080", | |
"lightcyan": "E0FFFF", | |
"lightgoldenrodyellow": "FAFAD2", | |
"lightgreen": "90EE90", | |
"lightgrey": "D3D3D3", | |
"lightpink": "FFB6C1", | |
"lightsalmon": "FFA07A", | |
"lightseagreen": "20B2AA", | |
"lightskyblue": "87CEFA", | |
"lightslategray": "778899", | |
"lightsteelblue": "B0C4DE", | |
"lightyellow": "FFFFE0", | |
"lime": "00FF00", | |
"limegreen": "32CD32", | |
"linen": "FAF0E6", | |
"magenta": "FF00FF", | |
"maroon": "800000", | |
"mediumaquamarine": "66CDAA", | |
"mediumblue": "0000CD", | |
"mediumorchid": "BA55D3", | |
"mediumpurple": "9370DB", | |
"mediumseagreen": "3CB371", | |
"mediumslateblue": "7B68EE", | |
"mediumspringgreen": "00FA9A", | |
"mediumturquoise": "48D1CC", | |
"mediumvioletred": "C71585", | |
"midnightblue": "191970", | |
"mintcream": "F5FFFA", | |
"mistyrose": "FFE4E1", | |
"moccasin": "FFE4B5", | |
"navajowhite": "FFDEAD", | |
"navy": "000080", | |
"oldlace": "FDF5E6", | |
"olive": "808000", | |
"olivedrab": "6B8E23", | |
"orange": "FFA500", | |
"orangered": "FF4500", | |
"orchid": "DA70D6", | |
"palegoldenrod": "EEE8AA", | |
"palegreen": "98FB98", | |
"paleturquoise": "AFEEEE", | |
"palevioletred": "DB7093", | |
"papayawhip": "FFEFD5", | |
"peachpuff": "FFDAB9", | |
"peru": "CD853F", | |
"pink": "FFC0CB", | |
"plum": "DDA0DD", | |
"powderblue": "B0E0E6", | |
"purple": "800080", | |
"red": "FF0000", | |
"rosybrown": "BC8F8F", | |
"royalblue": "4169E1", | |
"saddlebrown": "8B4513", | |
"salmon": "FA8072", | |
"sandybrown": "F4A460", | |
"seagreen": "2E8B57", | |
"seashell": "FFF5EE", | |
"sienna": "A0522D", | |
"silver": "C0C0C0", | |
"skyblue": "87CEEB", | |
"slateblue": "6A5ACD", | |
"slategray": "708090", | |
"snow": "FFFAFA", | |
"springgreen": "00FF7F", | |
"steelblue": "4682B4", | |
"tan": "D2B48C", | |
"teal": "008080", | |
"thistle": "D8BFD8", | |
"tomato": "FF6347", | |
"turquoise": "40E0D0", | |
"violet": "EE82EE", | |
"wheat": "F5DEB3", | |
"white": "FFFFFF", | |
"whitesmoke": "F5F5F5", | |
"yellow": "FFFF00", | |
"yellowgreen": "9ACD32" | |
}; | |
WebInspector.Color.AdvancedNickNames = { | |
"transparent": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], | |
"rgba(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], | |
"hsla(0,0,0,0)": [[0, 0, 0, 0], [0, 0, 0, 0], "transparent"], | |
}; | |
WebInspector.Color.PageHighlight = { | |
Content: WebInspector.Color.fromRGBA(111, 168, 220, .66), | |
ContentLight: WebInspector.Color.fromRGBA(111, 168, 220, .5), | |
ContentOutline: WebInspector.Color.fromRGBA(9, 83, 148), | |
Padding: WebInspector.Color.fromRGBA(147, 196, 125, .55), | |
PaddingLight: WebInspector.Color.fromRGBA(147, 196, 125, .4), | |
Border: WebInspector.Color.fromRGBA(255, 229, 153, .66), | |
BorderLight: WebInspector.Color.fromRGBA(255, 229, 153, .5), | |
Margin: WebInspector.Color.fromRGBA(246, 178, 107, .66), | |
MarginLight: WebInspector.Color.fromRGBA(246, 178, 107, .5) | |
} | |
WebInspector.Color.Format = { | |
Original: "original", | |
Nickname: "nickname", | |
HEX: "hex", | |
ShortHEX: "shorthex", | |
RGB: "rgb", | |
RGBA: "rgba", | |
HSL: "hsl", | |
HSLA: "hsla" | |
} | |
WebInspector.CSSCompletions = function(properties, acceptEmptyPrefix) | |
{ | |
this._values = []; | |
this._longhands = {}; | |
this._shorthands = {}; | |
for (var i = 0; i < properties.length; ++i) { | |
var property = properties[i]; | |
if (typeof property === "string") { | |
this._values.push(property); | |
continue; | |
} | |
var propertyName = property.name; | |
this._values.push(propertyName); | |
var longhands = properties[i].longhands; | |
if (longhands) { | |
this._longhands[propertyName] = longhands; | |
for (var j = 0; j < longhands.length; ++j) { | |
var longhandName = longhands[j]; | |
var shorthands = this._shorthands[longhandName]; | |
if (!shorthands) { | |
shorthands = []; | |
this._shorthands[longhandName] = shorthands; | |
} | |
shorthands.push(propertyName); | |
} | |
} | |
} | |
this._values.sort(); | |
this._acceptEmptyPrefix = acceptEmptyPrefix; | |
} | |
WebInspector.CSSCompletions.cssPropertiesMetainfo = null; | |
WebInspector.CSSCompletions.requestCSSNameCompletions = function() | |
{ | |
function propertyNamesCallback(error, properties) | |
{ | |
if (!error) | |
WebInspector.CSSCompletions.cssPropertiesMetainfo = new WebInspector.CSSCompletions(properties, false); | |
} | |
CSSAgent.getSupportedCSSProperties(propertyNamesCallback); | |
} | |
WebInspector.CSSCompletions.cssPropertiesMetainfoKeySet = function() | |
{ | |
if (!WebInspector.CSSCompletions._cssPropertiesMetainfoKeySet) | |
WebInspector.CSSCompletions._cssPropertiesMetainfoKeySet = WebInspector.CSSCompletions.cssPropertiesMetainfo.keySet(); | |
return WebInspector.CSSCompletions._cssPropertiesMetainfoKeySet; | |
} | |
WebInspector.CSSCompletions.prototype = { | |
startsWith: function(prefix) | |
{ | |
var firstIndex = this._firstIndexOfPrefix(prefix); | |
if (firstIndex === -1) | |
return []; | |
var results = []; | |
while (firstIndex < this._values.length && this._values[firstIndex].startsWith(prefix)) | |
results.push(this._values[firstIndex++]); | |
return results; | |
}, | |
firstStartsWith: function(prefix) | |
{ | |
var foundIndex = this._firstIndexOfPrefix(prefix); | |
return (foundIndex === -1 ? "" : this._values[foundIndex]); | |
}, | |
_firstIndexOfPrefix: function(prefix) | |
{ | |
if (!this._values.length) | |
return -1; | |
if (!prefix) | |
return this._acceptEmptyPrefix ? 0 : -1; | |
var maxIndex = this._values.length - 1; | |
var minIndex = 0; | |
var foundIndex; | |
do { | |
var middleIndex = (maxIndex + minIndex) >> 1; | |
if (this._values[middleIndex].startsWith(prefix)) { | |
foundIndex = middleIndex; | |
break; | |
} | |
if (this._values[middleIndex] < prefix) | |
minIndex = middleIndex + 1; | |
else | |
maxIndex = middleIndex - 1; | |
} while (minIndex <= maxIndex); | |
if (foundIndex === undefined) | |
return -1; | |
while (foundIndex && this._values[foundIndex - 1].startsWith(prefix)) | |
foundIndex--; | |
return foundIndex; | |
}, | |
keySet: function() | |
{ | |
if (!this._keySet) | |
this._keySet = this._values.keySet(); | |
return this._keySet; | |
}, | |
next: function(str, prefix) | |
{ | |
return this._closest(str, prefix, 1); | |
}, | |
previous: function(str, prefix) | |
{ | |
return this._closest(str, prefix, -1); | |
}, | |
_closest: function(str, prefix, shift) | |
{ | |
if (!str) | |
return ""; | |
var index = this._values.indexOf(str); | |
if (index === -1) | |
return ""; | |
if (!prefix) { | |
index = (index + this._values.length + shift) % this._values.length; | |
return this._values[index]; | |
} | |
var propertiesWithPrefix = this.startsWith(prefix); | |
var j = propertiesWithPrefix.indexOf(str); | |
j = (j + propertiesWithPrefix.length + shift) % propertiesWithPrefix.length; | |
return propertiesWithPrefix[j]; | |
}, | |
longhands: function(shorthand) | |
{ | |
return this._longhands[shorthand]; | |
}, | |
shorthands: function(longhand) | |
{ | |
return this._shorthands[longhand]; | |
} | |
} | |
WebInspector.CSSKeywordCompletions = {} | |
WebInspector.CSSKeywordCompletions.forProperty = function(propertyName) | |
{ | |
var acceptedKeywords = ["initial"]; | |
if (propertyName in WebInspector.CSSKeywordCompletions._propertyKeywordMap) | |
acceptedKeywords = acceptedKeywords.concat(WebInspector.CSSKeywordCompletions._propertyKeywordMap[propertyName]); | |
if (propertyName in WebInspector.CSSKeywordCompletions._colorAwareProperties) | |
acceptedKeywords = acceptedKeywords.concat(WebInspector.CSSKeywordCompletions._colors); | |
if (propertyName in WebInspector.CSSKeywordCompletions.InheritedProperties) | |
acceptedKeywords.push("inherit"); | |
return new WebInspector.CSSCompletions(acceptedKeywords, true); | |
} | |
WebInspector.CSSKeywordCompletions.isColorAwareProperty = function(propertyName) | |
{ | |
return WebInspector.CSSKeywordCompletions._colorAwareProperties[propertyName] === true; | |
} | |
WebInspector.CSSKeywordCompletions.colors = function() | |
{ | |
if (!WebInspector.CSSKeywordCompletions._colorsKeySet) | |
WebInspector.CSSKeywordCompletions._colorsKeySet = WebInspector.CSSKeywordCompletions._colors.keySet(); | |
return WebInspector.CSSKeywordCompletions._colorsKeySet; | |
} | |
WebInspector.CSSKeywordCompletions.InheritedProperties = [ | |
"azimuth", "border-collapse", "border-spacing", "caption-side", "color", "cursor", "direction", "elevation", | |
"empty-cells", "font-family", "font-size", "font-style", "font-variant", "font-weight", "font", "letter-spacing", | |
"line-height", "list-style-image", "list-style-position", "list-style-type", "list-style", "orphans", "pitch-range", | |
"pitch", "quotes", "richness", "speak-header", "speak-numeral", "speak-punctuation", "speak", "speech-rate", "stress", | |
"text-align", "text-indent", "text-transform", "text-shadow", "visibility", "voice-family", "volume", "white-space", "widows", "word-spacing" | |
].keySet(); | |
WebInspector.CSSKeywordCompletions._colors = [ | |
"aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "orange", "purple", "red", | |
"silver", "teal", "white", "yellow", "transparent", "currentcolor", "grey", "aliceblue", "antiquewhite", | |
"aquamarine", "azure", "beige", "bisque", "blanchedalmond", "blueviolet", "brown", "burlywood", "cadetblue", | |
"chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", | |
"darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", | |
"darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", | |
"darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", | |
"floralwhite", "forestgreen", "gainsboro", "ghostwhite", "gold", "goldenrod", "greenyellow", "honeydew", "hotpink", | |
"indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", | |
"lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", | |
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", | |
"limegreen", "linen", "magenta", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", | |
"mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", | |
"mistyrose", "moccasin", "navajowhite", "oldlace", "olivedrab", "orangered", "orchid", "palegoldenrod", "palegreen", | |
"paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "rosybrown", | |
"royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "skyblue", "slateblue", | |
"slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "thistle", "tomato", "turquoise", "violet", | |
"wheat", "whitesmoke", "yellowgreen" | |
]; | |
WebInspector.CSSKeywordCompletions._colorAwareProperties = [ | |
"background", "background-color", "background-image", "border", "border-color", "border-top", "border-right", "border-bottom", | |
"border-left", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", "box-shadow", "color", | |
"fill", "outline", "outline-color", "stroke", "text-line-through", "text-line-through-color", "text-overline", "text-overline-color", | |
"text-shadow", "text-underline", "text-underline-color", "-webkit-box-shadow", "-webkit-text-emphasis", "-webkit-text-emphasis-color" | |
].keySet(); | |
WebInspector.CSSKeywordCompletions._propertyKeywordMap = { | |
"table-layout": [ | |
"auto", "fixed" | |
], | |
"visibility": [ | |
"hidden", "visible", "collapse" | |
], | |
"background-repeat": [ | |
"repeat", "repeat-x", "repeat-y", "no-repeat", "space", "round" | |
], | |
"text-underline": [ | |
"none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" | |
], | |
"content": [ | |
"list-item", "close-quote", "no-close-quote", "no-open-quote", "open-quote" | |
], | |
"list-style-image": [ | |
"none" | |
], | |
"clear": [ | |
"none", "left", "right", "both" | |
], | |
"text-underline-mode": [ | |
"continuous", "skip-white-space" | |
], | |
"overflow-x": [ | |
"hidden", "auto", "visible", "overlay", "scroll" | |
], | |
"stroke-linejoin": [ | |
"round", "miter", "bevel" | |
], | |
"baseline-shift": [ | |
"baseline", "sub", "super" | |
], | |
"border-bottom-width": [ | |
"medium", "thick", "thin" | |
], | |
"marquee-speed": [ | |
"normal", "slow", "fast" | |
], | |
"margin-top-collapse": [ | |
"collapse", "separate", "discard" | |
], | |
"max-height": [ | |
"none" | |
], | |
"box-orient": [ | |
"horizontal", "vertical", "inline-axis", "block-axis" | |
], | |
"font-stretch": [ | |
"normal", "wider", "narrower", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", | |
"semi-expanded", "expanded", "extra-expanded", "ultra-expanded" | |
], | |
"-webkit-color-correction": [ | |
"default", "srgb" | |
], | |
"text-underline-style": [ | |
"none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" | |
], | |
"text-overline-mode": [ | |
"continuous", "skip-white-space" | |
], | |
"-webkit-background-composite": [ | |
"highlight", "clear", "copy", "source-over", "source-in", "source-out", "source-atop", "destination-over", | |
"destination-in", "destination-out", "destination-atop", "xor", "plus-darker", "plus-lighter" | |
], | |
"border-left-width": [ | |
"medium", "thick", "thin" | |
], | |
"-webkit-writing-mode": [ | |
"lr", "rl", "tb", "lr-tb", "rl-tb", "tb-rl", "horizontal-tb", "vertical-rl", "vertical-lr", "horizontal-bt" | |
], | |
"text-line-through-mode": [ | |
"continuous", "skip-white-space" | |
], | |
"border-collapse": [ | |
"collapse", "separate" | |
], | |
"page-break-inside": [ | |
"auto", "avoid" | |
], | |
"border-top-width": [ | |
"medium", "thick", "thin" | |
], | |
"outline-color": [ | |
"invert" | |
], | |
"text-line-through-style": [ | |
"none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" | |
], | |
"outline-style": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"cursor": [ | |
"none", "copy", "auto", "crosshair", "default", "pointer", "move", "vertical-text", "cell", "context-menu", | |
"alias", "progress", "no-drop", "not-allowed", "-webkit-zoom-in", "-webkit-zoom-out", "e-resize", "ne-resize", | |
"nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "ew-resize", "ns-resize", | |
"nesw-resize", "nwse-resize", "col-resize", "row-resize", "text", "wait", "help", "all-scroll", "-webkit-grab", | |
"-webkit-grabbing" | |
], | |
"border-width": [ | |
"medium", "thick", "thin" | |
], | |
"size": [ | |
"a3", "a4", "a5", "b4", "b5", "landscape", "ledger", "legal", "letter", "portrait" | |
], | |
"background-size": [ | |
"contain", "cover" | |
], | |
"direction": [ | |
"ltr", "rtl" | |
], | |
"marquee-direction": [ | |
"left", "right", "auto", "reverse", "forwards", "backwards", "ahead", "up", "down" | |
], | |
"enable-background": [ | |
"accumulate", "new" | |
], | |
"float": [ | |
"none", "left", "right" | |
], | |
"overflow-y": [ | |
"hidden", "auto", "visible", "overlay", "scroll" | |
], | |
"margin-bottom-collapse": [ | |
"collapse", "separate", "discard" | |
], | |
"box-reflect": [ | |
"left", "right", "above", "below" | |
], | |
"overflow": [ | |
"hidden", "auto", "visible", "overlay", "scroll" | |
], | |
"text-rendering": [ | |
"auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision" | |
], | |
"text-align": [ | |
"-webkit-auto", "left", "right", "center", "justify", "-webkit-left", "-webkit-right", "-webkit-center" | |
], | |
"list-style-position": [ | |
"outside", "inside" | |
], | |
"margin-bottom": [ | |
"auto" | |
], | |
"color-interpolation": [ | |
"linearrgb" | |
], | |
"background-origin": [ | |
"border-box", "content-box", "padding-box" | |
], | |
"word-wrap": [ | |
"normal", "break-word" | |
], | |
"font-weight": [ | |
"normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900" | |
], | |
"margin-before-collapse": [ | |
"collapse", "separate", "discard" | |
], | |
"text-overline-width": [ | |
"normal", "medium", "auto", "thick", "thin" | |
], | |
"text-transform": [ | |
"none", "capitalize", "uppercase", "lowercase" | |
], | |
"border-right-style": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"border-left-style": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"-webkit-text-emphasis": [ | |
"circle", "filled", "open", "dot", "double-circle", "triangle", "sesame" | |
], | |
"font-style": [ | |
"italic", "oblique", "normal" | |
], | |
"speak": [ | |
"none", "normal", "spell-out", "digits", "literal-punctuation", "no-punctuation" | |
], | |
"text-line-through": [ | |
"none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave", "continuous", | |
"skip-white-space" | |
], | |
"color-rendering": [ | |
"auto", "optimizeSpeed", "optimizeQuality" | |
], | |
"list-style-type": [ | |
"none", "disc", "circle", "square", "decimal", "decimal-leading-zero", "arabic-indic", "binary", "bengali", | |
"cambodian", "khmer", "devanagari", "gujarati", "gurmukhi", "kannada", "lower-hexadecimal", "lao", "malayalam", | |
"mongolian", "myanmar", "octal", "oriya", "persian", "urdu", "telugu", "tibetan", "thai", "upper-hexadecimal", | |
"lower-roman", "upper-roman", "lower-greek", "lower-alpha", "lower-latin", "upper-alpha", "upper-latin", "afar", | |
"ethiopic-halehame-aa-et", "ethiopic-halehame-aa-er", "amharic", "ethiopic-halehame-am-et", "amharic-abegede", | |
"ethiopic-abegede-am-et", "cjk-earthly-branch", "cjk-heavenly-stem", "ethiopic", "ethiopic-halehame-gez", | |
"ethiopic-abegede", "ethiopic-abegede-gez", "hangul-consonant", "hangul", "lower-norwegian", "oromo", | |
"ethiopic-halehame-om-et", "sidama", "ethiopic-halehame-sid-et", "somali", "ethiopic-halehame-so-et", "tigre", | |
"ethiopic-halehame-tig", "tigrinya-er", "ethiopic-halehame-ti-er", "tigrinya-er-abegede", | |
"ethiopic-abegede-ti-er", "tigrinya-et", "ethiopic-halehame-ti-et", "tigrinya-et-abegede", | |
"ethiopic-abegede-ti-et", "upper-greek", "upper-norwegian", "asterisks", "footnotes", "hebrew", "armenian", | |
"lower-armenian", "upper-armenian", "georgian", "cjk-ideographic", "hiragana", "katakana", "hiragana-iroha", | |
"katakana-iroha" | |
], | |
"-webkit-text-combine": [ | |
"none", "horizontal" | |
], | |
"outline": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"font": [ | |
"caption", "icon", "menu", "message-box", "small-caption", "-webkit-mini-control", "-webkit-small-control", | |
"-webkit-control", "status-bar", "italic", "oblique", "small-caps", "normal", "bold", "bolder", "lighter", | |
"100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium", | |
"large", "x-large", "xx-large", "-webkit-xxx-large", "smaller", "larger", "serif", "sans-serif", "cursive", | |
"fantasy", "monospace", "-webkit-body", "-webkit-pictograph" | |
], | |
"dominant-baseline": [ | |
"middle", "auto", "central", "text-before-edge", "text-after-edge", "ideographic", "alphabetic", "hanging", | |
"mathematical", "use-script", "no-change", "reset-size" | |
], | |
"display": [ | |
"none", "inline", "block", "list-item", "run-in", "compact", "inline-block", "table", "inline-table", | |
"table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", | |
"table-column", "table-cell", "table-caption", "-webkit-box", "-webkit-inline-box", "-wap-marquee" | |
], | |
"-webkit-text-emphasis-position": [ | |
"over", "under" | |
], | |
"image-rendering": [ | |
"auto", "optimizeSpeed", "optimizeQuality" | |
], | |
"alignment-baseline": [ | |
"baseline", "middle", "auto", "before-edge", "after-edge", "central", "text-before-edge", "text-after-edge", | |
"ideographic", "alphabetic", "hanging", "mathematical" | |
], | |
"outline-width": [ | |
"medium", "thick", "thin" | |
], | |
"text-line-through-width": [ | |
"normal", "medium", "auto", "thick", "thin" | |
], | |
"box-align": [ | |
"baseline", "center", "stretch", "start", "end" | |
], | |
"border-right-width": [ | |
"medium", "thick", "thin" | |
], | |
"border-top-style": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"line-height": [ | |
"normal" | |
], | |
"text-overflow": [ | |
"clip", "ellipsis" | |
], | |
"box-direction": [ | |
"normal", "reverse" | |
], | |
"margin-after-collapse": [ | |
"collapse", "separate", "discard" | |
], | |
"page-break-before": [ | |
"left", "right", "auto", "always", "avoid" | |
], | |
"-webkit-hyphens": [ | |
"none", "auto", "manual" | |
], | |
"border-image": [ | |
"repeat", "stretch" | |
], | |
"text-decoration": [ | |
"blink", "line-through", "overline", "underline" | |
], | |
"position": [ | |
"absolute", "fixed", "relative", "static" | |
], | |
"font-family": [ | |
"serif", "sans-serif", "cursive", "fantasy", "monospace", "-webkit-body", "-webkit-pictograph" | |
], | |
"text-overflow-mode": [ | |
"clip", "ellipsis" | |
], | |
"border-bottom-style": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"unicode-bidi": [ | |
"normal", "bidi-override", "embed" | |
], | |
"clip-rule": [ | |
"nonzero", "evenodd" | |
], | |
"margin-left": [ | |
"auto" | |
], | |
"margin-top": [ | |
"auto" | |
], | |
"zoom": [ | |
"document", "reset" | |
], | |
"text-overline-style": [ | |
"none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" | |
], | |
"max-width": [ | |
"none" | |
], | |
"empty-cells": [ | |
"hide", "show" | |
], | |
"pointer-events": [ | |
"none", "all", "auto", "visible", "visiblepainted", "visiblefill", "visiblestroke", "painted", "fill", "stroke" | |
], | |
"letter-spacing": [ | |
"normal" | |
], | |
"background-clip": [ | |
"border-box", "content-box", "padding-box" | |
], | |
"-webkit-font-smoothing": [ | |
"none", "auto", "antialiased", "subpixel-antialiased" | |
], | |
"border": [ | |
"none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" | |
], | |
"font-size": [ | |
"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "-webkit-xxx-large", "smaller", | |
"larger" | |
], | |
"font-variant": [ | |
"small-caps", "normal" | |
], | |
"vertical-align": [ | |
"baseline", "middle", "sub", "super", "text-top", "text-bottom", "top", "bottom", "-webkit-baseline-middle" | |
], | |
"marquee-style": [ | |
"none", "scroll", "slide", "alternate" | |
], | |
"white-space": [ | |
"normal", "nowrap", "pre", "pre-line", "pre-wrap" | |
], | |
"text-underline-width": [ | |
"normal", "medium", "auto", "thick", "thin" | |
], | |
"box-lines": [ | |
"single", "multiple" | |
], | |
"page-break-after": [ | |
"left", "right", "auto", "always", "avoid" | |
], | |
"clip-path": [ | |
"none" | |
], | |
"margin": [ | |
"auto" | |
], | |
"marquee-repetition": [ | |
"infinite" | |
], | |
"margin-right": [ | |
"auto" | |
], | |
"-webkit-text-emphasis-style": [ | |
"circle", "filled", "open", "dot", "double-circle", "triangle", "sesame" | |
], | |
"-webkit-transform": [ | |
"scale", "scaleX", "scaleY", "scale3d", "rotate", "rotateX", "rotateY", "rotateZ", "rotate3d", "skew", "skewX", "skewY", | |
"translate", "translateX", "translateY", "translateZ", "translate3d", "matrix", "matrix3d", "perspective" | |
] | |
} | |
WebInspector.PanelEnablerView = function(identifier, headingText, disclaimerText, buttonTitle) | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("panelEnablerView.css"); | |
this.element.addStyleClass("panel-enabler-view"); | |
this.element.addStyleClass(identifier); | |
this.contentElement = document.createElement("div"); | |
this.contentElement.className = "panel-enabler-view-content"; | |
this.element.appendChild(this.contentElement); | |
this.imageElement = document.createElement("img"); | |
this.contentElement.appendChild(this.imageElement); | |
this.choicesForm = document.createElement("form"); | |
this.contentElement.appendChild(this.choicesForm); | |
this.headerElement = document.createElement("h1"); | |
this.headerElement.textContent = headingText; | |
this.choicesForm.appendChild(this.headerElement); | |
var self = this; | |
function enableOption(text, checked) { | |
var label = document.createElement("label"); | |
var option = document.createElement("input"); | |
option.type = "radio"; | |
option.name = "enable-option"; | |
if (checked) | |
option.checked = true; | |
label.appendChild(option); | |
label.appendChild(document.createTextNode(text)); | |
self.choicesForm.appendChild(label); | |
return option; | |
}; | |
this.enabledForSession = enableOption(WebInspector.UIString("Only enable for this session"), true); | |
this.enabledAlways = enableOption(WebInspector.UIString("Always enable"), false); | |
this.disclaimerElement = document.createElement("div"); | |
this.disclaimerElement.className = "panel-enabler-disclaimer"; | |
this.disclaimerElement.textContent = disclaimerText; | |
this.choicesForm.appendChild(this.disclaimerElement); | |
this.enableButton = document.createElement("button"); | |
this.enableButton.setAttribute("type", "button"); | |
this.enableButton.textContent = buttonTitle; | |
this.enableButton.addEventListener("click", this._enableButtonCicked.bind(this), false); | |
this.choicesForm.appendChild(this.enableButton); | |
} | |
WebInspector.PanelEnablerView.prototype = { | |
_enableButtonCicked: function() | |
{ | |
this.dispatchEventToListeners("enable clicked"); | |
}, | |
onResize: function() | |
{ | |
this.imageElement.removeStyleClass("hidden"); | |
if (this.element.offsetWidth < (this.choicesForm.offsetWidth + this.imageElement.offsetWidth)) | |
this.imageElement.addStyleClass("hidden"); | |
}, | |
get alwaysEnabled() { | |
return this.enabledAlways.checked; | |
} | |
} | |
WebInspector.PanelEnablerView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.StatusBarButton = function(title, className, states) | |
{ | |
this.element = document.createElement("button"); | |
this.element.className = className + " status-bar-item"; | |
this.element.addEventListener("click", this._clicked.bind(this), false); | |
this.glyph = document.createElement("div"); | |
this.glyph.className = "glyph"; | |
this.element.appendChild(this.glyph); | |
this.glyphShadow = document.createElement("div"); | |
this.glyphShadow.className = "glyph shadow"; | |
this.element.appendChild(this.glyphShadow); | |
this.states = states; | |
if (!states) | |
this.states = 2; | |
if (states == 2) | |
this._state = false; | |
else | |
this._state = 0; | |
this.title = title; | |
this.disabled = false; | |
this._visible = true; | |
} | |
WebInspector.StatusBarButton.width = 31; | |
WebInspector.StatusBarButton.prototype = { | |
_clicked: function() | |
{ | |
this.dispatchEventToListeners("click"); | |
if (this._showOptionsTimer) | |
clearTimeout(this._showOptionsTimer); | |
}, | |
get disabled() | |
{ | |
return this._disabled; | |
}, | |
set disabled(x) | |
{ | |
if (this._disabled === x) | |
return; | |
this._disabled = x; | |
this.element.disabled = x; | |
}, | |
get title() | |
{ | |
return this._title; | |
}, | |
set title(x) | |
{ | |
if (this._title === x) | |
return; | |
this._title = x; | |
this.element.title = x; | |
}, | |
get state() | |
{ | |
return this._state; | |
}, | |
set state(x) | |
{ | |
if (this._state === x) | |
return; | |
if (this.states === 2) { | |
if (x) | |
this.element.addStyleClass("toggled-on"); | |
else | |
this.element.removeStyleClass("toggled-on"); | |
} else { | |
if (x !== 0) { | |
this.element.removeStyleClass("toggled-" + this._state); | |
this.element.addStyleClass("toggled-" + x); | |
} else | |
this.element.removeStyleClass("toggled-" + this._state); | |
} | |
this._state = x; | |
}, | |
get toggled() | |
{ | |
if (this.states !== 2) | |
throw("Only used toggled when there are 2 states, otherwise, use state"); | |
return this.state; | |
}, | |
set toggled(x) | |
{ | |
if (this.states !== 2) | |
throw("Only used toggled when there are 2 states, otherwise, use state"); | |
this.state = x; | |
}, | |
get visible() | |
{ | |
return this._visible; | |
}, | |
set visible(x) | |
{ | |
if (this._visible === x) | |
return; | |
if (x) | |
this.element.removeStyleClass("hidden"); | |
else | |
this.element.addStyleClass("hidden"); | |
this._visible = x; | |
}, | |
makeLongClickEnabled: function(buttonsProvider) | |
{ | |
this.longClickGlyph = document.createElement("div"); | |
this.longClickGlyph.className = "fill long-click-glyph"; | |
this.element.appendChild(this.longClickGlyph); | |
this.longClickGlyphShadow = document.createElement("div"); | |
this.longClickGlyphShadow.className = "fill long-click-glyph shadow"; | |
this.element.appendChild(this.longClickGlyphShadow); | |
this.element.addEventListener("mousedown", mouseDown.bind(this), false); | |
this.element.addEventListener("mouseout", mouseUp.bind(this), false); | |
this.element.addEventListener("mouseup", mouseUp.bind(this), false); | |
function mouseDown(e) | |
{ | |
if (e.which !== 1) | |
return; | |
this._showOptionsTimer = setTimeout(this._showOptions.bind(this, buttonsProvider), 200); | |
} | |
function mouseUp(e) | |
{ | |
if (e.which !== 1) | |
return; | |
if (this._showOptionsTimer) | |
clearTimeout(this._showOptionsTimer); | |
} | |
}, | |
_showOptions: function(buttonsProvider) | |
{ | |
var buttons = buttonsProvider(); | |
var mouseUpListener = mouseUp.bind(this); | |
document.documentElement.addEventListener("mouseup", mouseUpListener, false); | |
var optionsGlassPane = new WebInspector.GlassPane(); | |
var optionsBarElement = optionsGlassPane.element.createChild("div", "alternate-status-bar-buttons-bar"); | |
const buttonHeight = 24; | |
optionsBarElement.style.height = (buttonHeight * buttons.length) + "px"; | |
optionsBarElement.style.left = (this.element.offsetLeft + 1) + "px"; | |
var boundMouseOver = mouseOver.bind(this); | |
var boundMouseOut = mouseOut.bind(this); | |
for (var i = 0; i < buttons.length; ++i) { | |
buttons[i].element.addEventListener("mousemove", boundMouseOver.bind(this), false); | |
buttons[i].element.addEventListener("mouseout", boundMouseOut.bind(this), false); | |
optionsBarElement.appendChild(buttons[i].element); | |
} | |
buttons[buttons.length - 1].element.addStyleClass("emulate-active"); | |
function mouseOver(e) | |
{ | |
if (e.which !== 1) | |
return; | |
var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); | |
buttonElement.addStyleClass("emulate-active"); | |
} | |
function mouseOut(e) | |
{ | |
if (e.which !== 1) | |
return; | |
var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); | |
buttonElement.removeStyleClass("emulate-active"); | |
} | |
function mouseUp(e) | |
{ | |
if (e.which !== 1) | |
return; | |
optionsGlassPane.dispose(); | |
document.documentElement.removeEventListener("mouseup", mouseUpListener, false); | |
for (var i = 0; i < buttons.length; ++i) { | |
if (buttons[i].element.hasStyleClass("emulate-active")) | |
buttons[i]._clicked(); | |
} | |
} | |
} | |
} | |
WebInspector.StatusBarButton.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.StatusBarComboBox = function(changeHandler, className) | |
{ | |
this.element = document.createElement("span"); | |
this.element.className = "status-bar-select-container"; | |
this._selectElement = this.element.createChild("select", "status-bar-item"); | |
if (changeHandler) | |
this._selectElement.addEventListener("change", changeHandler, false); | |
if (className) | |
this._selectElement.addStyleClass(className); | |
} | |
WebInspector.StatusBarComboBox.prototype = { | |
addOption: function(option) | |
{ | |
this._selectElement.appendChild(option); | |
}, | |
removeOption: function(option) | |
{ | |
this._selectElement.removeChild(option); | |
}, | |
removeOptions: function() | |
{ | |
this._selectElement.removeChildren(); | |
}, | |
selectedOption: function() | |
{ | |
if (this._selectElement.selectedIndex >= 0) | |
return this._selectElement[this._selectElement.selectedIndex]; | |
return null; | |
}, | |
select: function(option) | |
{ | |
this._selectElement.selectedIndex = Array.prototype.indexOf.call(this._selectElement, option); | |
} | |
} | |
WebInspector.TextEditor = function() { }; | |
WebInspector.TextEditor.Events = { | |
GutterClick: "gutterClick" | |
}; | |
WebInspector.TextEditor.prototype = { | |
set mimeType(mimeType) { }, | |
setReadOnly: function(readOnly) { }, | |
readOnly: function() { }, | |
defaultFocusedElement: function() { }, | |
revealLine: function(lineNumber) { }, | |
addBreakpoint: function(lineNumber, disabled, conditional) { }, | |
removeBreakpoint: function(lineNumber) { }, | |
setExecutionLine: function(lineNumber) { }, | |
clearExecutionLine: function() { }, | |
addDecoration: function(lineNumber, element) { }, | |
removeDecoration: function(lineNumber, element) { }, | |
markAndRevealRange: function(range) { }, | |
highlightLine: function(lineNumber) { }, | |
clearLineHighlight: function() { }, | |
elementsToRestoreScrollPositionsFor: function() { }, | |
inheritScrollPositions: function(textEditor) { }, | |
beginUpdates: function() { }, | |
endUpdates: function() { }, | |
onResize: function() { }, | |
editRange: function(range, text) { }, | |
scrollToLine: function(lineNumber) { }, | |
selection: function(textRange) { }, | |
lastSelection: function() { }, | |
setSelection: function(textRange) { }, | |
setText: function(text) { }, | |
text: function() { }, | |
range: function() { }, | |
line: function(lineNumber) { }, | |
get linesCount() { }, | |
setAttribute: function(line, name, value) { }, | |
getAttribute: function(line, name) { }, | |
removeAttribute: function(line, name) { }, | |
wasShown: function() { }, | |
willHide: function() { } | |
} | |
WebInspector.TextEditorDelegate = function() | |
{ | |
} | |
WebInspector.TextEditorDelegate.prototype = { | |
onTextChanged: function(oldRange, newRange) { }, | |
selectionChanged: function(textRange) { }, | |
scrollChanged: function(lineNumber) { }, | |
populateLineGutterContextMenu: function(contextMenu, lineNumber) { }, | |
populateTextAreaContextMenu: function(contextMenu, lineNumber) { }, | |
createLink: function(hrefValue, isExternal) { } | |
} | |
WebInspector.DefaultTextEditor = function(url, delegate) | |
{ | |
WebInspector.View.call(this); | |
this._delegate = delegate; | |
this._url = url; | |
this.registerRequiredCSS("textEditor.css"); | |
this.element.className = "text-editor monospace"; | |
this._textModel = new WebInspector.TextEditorModel(); | |
this._textModel.addEventListener(WebInspector.TextEditorModel.Events.TextChanged, this._textChanged, this); | |
this._textModel.resetUndoStack(); | |
var enterTextChangeMode = this._enterInternalTextChangeMode.bind(this); | |
var exitTextChangeMode = this._exitInternalTextChangeMode.bind(this); | |
var syncScrollListener = this._syncScroll.bind(this); | |
var syncDecorationsForLineListener = this._syncDecorationsForLine.bind(this); | |
var syncLineHeightListener = this._syncLineHeight.bind(this); | |
this._mainPanel = new WebInspector.TextEditorMainPanel(this._delegate, this._textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode); | |
this._gutterPanel = new WebInspector.TextEditorGutterPanel(this._textModel, syncDecorationsForLineListener, syncLineHeightListener); | |
this._mainPanel.element.addEventListener("scroll", this._handleScrollChanged.bind(this), false); | |
this._mainPanel._container.addEventListener("focus", this._handleFocused.bind(this), false); | |
this._gutterPanel.element.addEventListener("mousedown", this._onMouseDown.bind(this), true); | |
this.element.appendChild(this._mainPanel.element); | |
this.element.appendChild(this._gutterPanel.element); | |
function forwardWheelEvent(event) | |
{ | |
var clone = document.createEvent("WheelEvent"); | |
clone.initWebKitWheelEvent(event.wheelDeltaX, event.wheelDeltaY, | |
event.view, | |
event.screenX, event.screenY, | |
event.clientX, event.clientY, | |
event.ctrlKey, event.altKey, event.shiftKey, event.metaKey); | |
this._mainPanel.element.dispatchEvent(clone); | |
} | |
this._gutterPanel.element.addEventListener("mousewheel", forwardWheelEvent.bind(this), false); | |
this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); | |
this.element.addEventListener("contextmenu", this._contextMenu.bind(this), true); | |
this._registerShortcuts(); | |
} | |
WebInspector.DefaultTextEditor.prototype = { | |
set mimeType(mimeType) | |
{ | |
this._mainPanel.mimeType = mimeType; | |
}, | |
setReadOnly: function(readOnly) | |
{ | |
if (this._mainPanel.readOnly() === readOnly) | |
return; | |
this._mainPanel.setReadOnly(readOnly, this.isShowing()); | |
WebInspector.markBeingEdited(this.element, !readOnly); | |
}, | |
readOnly: function() | |
{ | |
return this._mainPanel.readOnly(); | |
}, | |
get textModel() | |
{ | |
return this._textModel; | |
}, | |
defaultFocusedElement: function() | |
{ | |
return this._mainPanel.defaultFocusedElement(); | |
}, | |
revealLine: function(lineNumber) | |
{ | |
this._mainPanel.revealLine(lineNumber); | |
}, | |
_onMouseDown: function(event) | |
{ | |
var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); | |
if (!target) | |
return; | |
this.dispatchEventToListeners(WebInspector.TextEditor.Events.GutterClick, { lineNumber: target.lineNumber, event: event }); | |
}, | |
addBreakpoint: function(lineNumber, disabled, conditional) | |
{ | |
this.beginUpdates(); | |
this._gutterPanel.addDecoration(lineNumber, "webkit-breakpoint"); | |
if (disabled) | |
this._gutterPanel.addDecoration(lineNumber, "webkit-breakpoint-disabled"); | |
else | |
this._gutterPanel.removeDecoration(lineNumber, "webkit-breakpoint-disabled"); | |
if (conditional) | |
this._gutterPanel.addDecoration(lineNumber, "webkit-breakpoint-conditional"); | |
else | |
this._gutterPanel.removeDecoration(lineNumber, "webkit-breakpoint-conditional"); | |
this.endUpdates(); | |
}, | |
removeBreakpoint: function(lineNumber) | |
{ | |
this.beginUpdates(); | |
this._gutterPanel.removeDecoration(lineNumber, "webkit-breakpoint"); | |
this._gutterPanel.removeDecoration(lineNumber, "webkit-breakpoint-disabled"); | |
this._gutterPanel.removeDecoration(lineNumber, "webkit-breakpoint-conditional"); | |
this.endUpdates(); | |
}, | |
setExecutionLine: function(lineNumber) | |
{ | |
this._executionLineNumber = lineNumber; | |
this._mainPanel.addDecoration(lineNumber, "webkit-execution-line"); | |
this._gutterPanel.addDecoration(lineNumber, "webkit-execution-line"); | |
}, | |
clearExecutionLine: function() | |
{ | |
if (typeof this._executionLineNumber === "number") { | |
this._mainPanel.removeDecoration(this._executionLineNumber, "webkit-execution-line"); | |
this._gutterPanel.removeDecoration(this._executionLineNumber, "webkit-execution-line"); | |
} | |
delete this._executionLineNumber; | |
}, | |
addDecoration: function(lineNumber, element) | |
{ | |
this._mainPanel.addDecoration(lineNumber, element); | |
this._gutterPanel.addDecoration(lineNumber, element); | |
}, | |
removeDecoration: function(lineNumber, element) | |
{ | |
this._mainPanel.removeDecoration(lineNumber, element); | |
this._gutterPanel.removeDecoration(lineNumber, element); | |
}, | |
markAndRevealRange: function(range) | |
{ | |
if (range) | |
this.setSelection(range); | |
this._mainPanel.markAndRevealRange(range); | |
}, | |
highlightLine: function(lineNumber) | |
{ | |
if (typeof lineNumber !== "number" || lineNumber < 0) | |
return; | |
lineNumber = Math.min(lineNumber, this._textModel.linesCount - 1); | |
this._mainPanel.highlightLine(lineNumber); | |
}, | |
clearLineHighlight: function() | |
{ | |
this._mainPanel.clearLineHighlight(); | |
}, | |
_freeCachedElements: function() | |
{ | |
this._mainPanel._freeCachedElements(); | |
this._gutterPanel._freeCachedElements(); | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return [this._mainPanel.element]; | |
}, | |
inheritScrollPositions: function(textEditor) | |
{ | |
this._mainPanel.element._scrollTop = textEditor._mainPanel.element.scrollTop; | |
this._mainPanel.element._scrollLeft = textEditor._mainPanel.element.scrollLeft; | |
}, | |
beginUpdates: function() | |
{ | |
this._mainPanel.beginUpdates(); | |
this._gutterPanel.beginUpdates(); | |
}, | |
endUpdates: function() | |
{ | |
this._mainPanel.endUpdates(); | |
this._gutterPanel.endUpdates(); | |
this._updatePanelOffsets(); | |
}, | |
onResize: function() | |
{ | |
this._mainPanel.resize(); | |
this._gutterPanel.resize(); | |
this._updatePanelOffsets(); | |
}, | |
_textChanged: function(event) | |
{ | |
if (!this._internalTextChangeMode) | |
this._textModel.resetUndoStack(); | |
this._mainPanel.textChanged(event.data.oldRange, event.data.newRange); | |
this._gutterPanel.textChanged(event.data.oldRange, event.data.newRange); | |
this._updatePanelOffsets(); | |
}, | |
editRange: function(range, text) | |
{ | |
this._enterInternalTextChangeMode(); | |
this._textModel.markUndoableState(); | |
var newRange = this._textModel.editRange(range, text); | |
this._exitInternalTextChangeMode(range, newRange); | |
return newRange; | |
}, | |
_enterInternalTextChangeMode: function() | |
{ | |
this._internalTextChangeMode = true; | |
}, | |
_exitInternalTextChangeMode: function(oldRange, newRange) | |
{ | |
this._internalTextChangeMode = false; | |
this._delegate.onTextChanged(oldRange, newRange); | |
}, | |
_updatePanelOffsets: function() | |
{ | |
var lineNumbersWidth = this._gutterPanel.element.offsetWidth; | |
if (lineNumbersWidth) | |
this._mainPanel.element.style.setProperty("left", (lineNumbersWidth + 2) + "px"); | |
else | |
this._mainPanel.element.style.removeProperty("left"); | |
}, | |
_syncScroll: function() | |
{ | |
var mainElement = this._mainPanel.element; | |
var gutterElement = this._gutterPanel.element; | |
this._gutterPanel.syncClientHeight(mainElement.clientHeight); | |
gutterElement.scrollTop = mainElement.scrollTop; | |
}, | |
_syncDecorationsForLine: function(lineNumber) | |
{ | |
if (lineNumber >= this._textModel.linesCount) | |
return; | |
var mainChunk = this._mainPanel.chunkForLine(lineNumber); | |
if (mainChunk.linesCount === 1 && mainChunk.decorated) { | |
var gutterChunk = this._gutterPanel.makeLineAChunk(lineNumber); | |
var height = mainChunk.height; | |
if (height) | |
gutterChunk.element.style.setProperty("height", height + "px"); | |
else | |
gutterChunk.element.style.removeProperty("height"); | |
} else { | |
var gutterChunk = this._gutterPanel.chunkForLine(lineNumber); | |
if (gutterChunk.linesCount === 1) | |
gutterChunk.element.style.removeProperty("height"); | |
} | |
}, | |
_syncLineHeight: function(gutterRow) | |
{ | |
if (this._lineHeightSynced) | |
return; | |
if (gutterRow && gutterRow.offsetHeight) { | |
this.element.style.setProperty("line-height", gutterRow.offsetHeight + "px"); | |
this._lineHeightSynced = true; | |
} | |
}, | |
_registerShortcuts: function() | |
{ | |
var keys = WebInspector.KeyboardShortcut.Keys; | |
var modifiers = WebInspector.KeyboardShortcut.Modifiers; | |
this._shortcuts = {}; | |
var handleEnterKey = this._mainPanel.handleEnterKey.bind(this._mainPanel); | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Enter.code, WebInspector.KeyboardShortcut.Modifiers.None)] = handleEnterKey; | |
var handleUndo = this._mainPanel.handleUndoRedo.bind(this._mainPanel, false); | |
var handleRedo = this._mainPanel.handleUndoRedo.bind(this._mainPanel, true); | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", modifiers.CtrlOrMeta)] = handleUndo; | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", modifiers.Shift | modifiers.CtrlOrMeta)] = handleRedo; | |
var handleTabKey = this._mainPanel.handleTabKeyPress.bind(this._mainPanel, false); | |
var handleShiftTabKey = this._mainPanel.handleTabKeyPress.bind(this._mainPanel, true); | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Tab.code)] = handleTabKey; | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Tab.code, modifiers.Shift)] = handleShiftTabKey; | |
}, | |
_handleKeyDown: function(e) | |
{ | |
if (this.readOnly()) | |
return; | |
var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(e); | |
var handler = this._shortcuts[shortcutKey]; | |
if (handler && handler()) | |
e.consume(true); | |
}, | |
_contextMenu: function(event) | |
{ | |
var anchor = event.target.enclosingNodeOrSelfWithNodeName("a"); | |
if (anchor) | |
return; | |
var contextMenu = new WebInspector.ContextMenu(); | |
var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); | |
if (target) | |
this._delegate.populateLineGutterContextMenu(contextMenu, target.lineNumber); | |
else { | |
target = this._mainPanel._enclosingLineRowOrSelf(event.target); | |
this._delegate.populateTextAreaContextMenu(contextMenu, target && target.lineNumber); | |
} | |
contextMenu.show(event); | |
}, | |
_handleScrollChanged: function(event) | |
{ | |
var visibleFrom = this._mainPanel.element.scrollTop; | |
var firstVisibleLineNumber = this._mainPanel._findFirstVisibleLineNumber(visibleFrom); | |
this._delegate.scrollChanged(firstVisibleLineNumber); | |
}, | |
scrollToLine: function(lineNumber) | |
{ | |
this._mainPanel.scrollToLine(lineNumber); | |
}, | |
_handleSelectionChange: function(event) | |
{ | |
var textRange = this._mainPanel._getSelection(); | |
if (textRange) { | |
this._lastSelection = WebInspector.TextRange.createFromLocation(textRange.endLine, textRange.endColumn); | |
} | |
this._delegate.selectionChanged(textRange); | |
}, | |
selection: function(textRange) | |
{ | |
return this._mainPanel._getSelection(); | |
}, | |
lastSelection: function() | |
{ | |
return this._lastSelection; | |
}, | |
setSelection: function(textRange) | |
{ | |
this._lastSelection = textRange; | |
if (this.element.isAncestor(document.activeElement)) | |
this._mainPanel._restoreSelection(textRange); | |
}, | |
setText: function(text) | |
{ | |
this._textModel.setText(text); | |
}, | |
text: function() | |
{ | |
return this._textModel.text(); | |
}, | |
range: function() | |
{ | |
return this._textModel.range(); | |
}, | |
line: function(lineNumber) | |
{ | |
return this._textModel.line(lineNumber); | |
}, | |
get linesCount() | |
{ | |
return this._textModel.linesCount; | |
}, | |
setAttribute: function(line, name, value) | |
{ | |
this._textModel.setAttribute(line, name, value); | |
}, | |
getAttribute: function(line, name) | |
{ | |
return this._textModel.getAttribute(line, name); | |
}, | |
removeAttribute: function(line, name) | |
{ | |
this._textModel.removeAttribute(line, name); | |
}, | |
wasShown: function() | |
{ | |
if (!this.readOnly()) | |
WebInspector.markBeingEdited(this.element, true); | |
this._boundSelectionChangeListener = this._handleSelectionChange.bind(this); | |
document.addEventListener("selectionchange", this._boundSelectionChangeListener, false); | |
}, | |
_handleFocused: function() | |
{ | |
if (this._lastSelection) | |
this.setSelection(this._lastSelection); | |
}, | |
willHide: function() | |
{ | |
document.removeEventListener("selectionchange", this._boundSelectionChangeListener, false); | |
delete this._boundSelectionChangeListener; | |
if (!this.readOnly()) | |
WebInspector.markBeingEdited(this.element, false); | |
this._freeCachedElements(); | |
} | |
} | |
WebInspector.DefaultTextEditor.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.TextEditorChunkedPanel = function(textModel) | |
{ | |
this._textModel = textModel; | |
this._defaultChunkSize = 50; | |
this._paintCoalescingLevel = 0; | |
this._domUpdateCoalescingLevel = 0; | |
} | |
WebInspector.TextEditorChunkedPanel.prototype = { | |
get textModel() | |
{ | |
return this._textModel; | |
}, | |
scrollToLine: function(lineNumber) | |
{ | |
if (lineNumber >= this._textModel.linesCount) | |
return; | |
var chunk = this.makeLineAChunk(lineNumber); | |
this.element.scrollTop = chunk.offsetTop; | |
}, | |
revealLine: function(lineNumber) | |
{ | |
if (lineNumber >= this._textModel.linesCount) | |
return; | |
var chunk = this.makeLineAChunk(lineNumber); | |
chunk.element.scrollIntoViewIfNeeded(); | |
}, | |
addDecoration: function(lineNumber, decoration) | |
{ | |
if (lineNumber >= this._textModel.linesCount) | |
return; | |
var chunk = this.makeLineAChunk(lineNumber); | |
chunk.addDecoration(decoration); | |
}, | |
removeDecoration: function(lineNumber, decoration) | |
{ | |
if (lineNumber >= this._textModel.linesCount) | |
return; | |
var chunk = this.chunkForLine(lineNumber); | |
chunk.removeDecoration(decoration); | |
}, | |
_buildChunks: function() | |
{ | |
this.beginDomUpdates(); | |
this._container.removeChildren(); | |
this._textChunks = []; | |
for (var i = 0; i < this._textModel.linesCount; i += this._defaultChunkSize) { | |
var chunk = this._createNewChunk(i, i + this._defaultChunkSize); | |
this._textChunks.push(chunk); | |
this._container.appendChild(chunk.element); | |
} | |
this._repaintAll(); | |
this.endDomUpdates(); | |
}, | |
makeLineAChunk: function(lineNumber) | |
{ | |
var chunkNumber = this._chunkNumberForLine(lineNumber); | |
var oldChunk = this._textChunks[chunkNumber]; | |
if (!oldChunk) { | |
console.error("No chunk for line number: " + lineNumber); | |
return; | |
} | |
if (oldChunk.linesCount === 1) | |
return oldChunk; | |
return this._splitChunkOnALine(lineNumber, chunkNumber, true); | |
}, | |
_splitChunkOnALine: function(lineNumber, chunkNumber, createSuffixChunk) | |
{ | |
this.beginDomUpdates(); | |
var oldChunk = this._textChunks[chunkNumber]; | |
var wasExpanded = oldChunk.expanded; | |
oldChunk.expanded = false; | |
var insertIndex = chunkNumber + 1; | |
if (lineNumber > oldChunk.startLine) { | |
var prefixChunk = this._createNewChunk(oldChunk.startLine, lineNumber); | |
prefixChunk.readOnly = oldChunk.readOnly; | |
this._textChunks.splice(insertIndex++, 0, prefixChunk); | |
this._container.insertBefore(prefixChunk.element, oldChunk.element); | |
} | |
var endLine = createSuffixChunk ? lineNumber + 1 : oldChunk.startLine + oldChunk.linesCount; | |
var lineChunk = this._createNewChunk(lineNumber, endLine); | |
lineChunk.readOnly = oldChunk.readOnly; | |
this._textChunks.splice(insertIndex++, 0, lineChunk); | |
this._container.insertBefore(lineChunk.element, oldChunk.element); | |
if (oldChunk.startLine + oldChunk.linesCount > endLine) { | |
var suffixChunk = this._createNewChunk(endLine, oldChunk.startLine + oldChunk.linesCount); | |
suffixChunk.readOnly = oldChunk.readOnly; | |
this._textChunks.splice(insertIndex, 0, suffixChunk); | |
this._container.insertBefore(suffixChunk.element, oldChunk.element); | |
} | |
this._textChunks.splice(chunkNumber, 1); | |
this._container.removeChild(oldChunk.element); | |
if (wasExpanded) { | |
if (prefixChunk) | |
prefixChunk.expanded = true; | |
lineChunk.expanded = true; | |
if (suffixChunk) | |
suffixChunk.expanded = true; | |
} | |
this.endDomUpdates(); | |
return lineChunk; | |
}, | |
_scroll: function() | |
{ | |
this._scheduleRepaintAll(); | |
if (this._syncScrollListener) | |
this._syncScrollListener(); | |
}, | |
_scheduleRepaintAll: function() | |
{ | |
if (this._repaintAllTimer) | |
clearTimeout(this._repaintAllTimer); | |
this._repaintAllTimer = setTimeout(this._repaintAll.bind(this), 50); | |
}, | |
beginUpdates: function() | |
{ | |
this._paintCoalescingLevel++; | |
}, | |
endUpdates: function() | |
{ | |
this._paintCoalescingLevel--; | |
if (!this._paintCoalescingLevel) | |
this._repaintAll(); | |
}, | |
beginDomUpdates: function() | |
{ | |
this._domUpdateCoalescingLevel++; | |
}, | |
endDomUpdates: function() | |
{ | |
this._domUpdateCoalescingLevel--; | |
}, | |
_chunkNumberForLine: function(lineNumber) | |
{ | |
function compareLineNumbers(value, chunk) | |
{ | |
return value < chunk.startLine ? -1 : 1; | |
} | |
var insertBefore = insertionIndexForObjectInListSortedByFunction(lineNumber, this._textChunks, compareLineNumbers); | |
return insertBefore - 1; | |
}, | |
chunkForLine: function(lineNumber) | |
{ | |
return this._textChunks[this._chunkNumberForLine(lineNumber)]; | |
}, | |
_findFirstVisibleChunkNumber: function(visibleFrom) | |
{ | |
function compareOffsetTops(value, chunk) | |
{ | |
return value < chunk.offsetTop ? -1 : 1; | |
} | |
var insertBefore = insertionIndexForObjectInListSortedByFunction(visibleFrom, this._textChunks, compareOffsetTops); | |
return insertBefore - 1; | |
}, | |
_findVisibleChunks: function(visibleFrom, visibleTo) | |
{ | |
var from = this._findFirstVisibleChunkNumber(visibleFrom); | |
for (var to = from + 1; to < this._textChunks.length; ++to) { | |
if (this._textChunks[to].offsetTop >= visibleTo) | |
break; | |
} | |
return { start: from, end: to }; | |
}, | |
_findFirstVisibleLineNumber: function(visibleFrom) | |
{ | |
var chunk = this._textChunks[this._findFirstVisibleChunkNumber(visibleFrom)]; | |
if (!chunk.expanded) | |
return chunk.startLine; | |
var lineNumbers = []; | |
for (var i = 0; i < chunk.linesCount; ++i) { | |
lineNumbers.push(chunk.startLine + i); | |
} | |
function compareLineRowOffsetTops(value, lineNumber) | |
{ | |
var lineRow = chunk.getExpandedLineRow(lineNumber); | |
return value < lineRow.offsetTop ? -1 : 1; | |
} | |
var insertBefore = insertionIndexForObjectInListSortedByFunction(visibleFrom, lineNumbers, compareLineRowOffsetTops); | |
return lineNumbers[insertBefore - 1]; | |
}, | |
_repaintAll: function() | |
{ | |
delete this._repaintAllTimer; | |
if (this._paintCoalescingLevel || this._dirtyLines) | |
return; | |
var visibleFrom = this.element.scrollTop; | |
var visibleTo = this.element.scrollTop + this.element.clientHeight; | |
if (visibleTo) { | |
var result = this._findVisibleChunks(visibleFrom, visibleTo); | |
this._expandChunks(result.start, result.end); | |
} | |
}, | |
_expandChunks: function(fromIndex, toIndex) | |
{ | |
for (var i = 0; i < fromIndex; ++i) | |
this._textChunks[i].expanded = false; | |
for (var i = toIndex; i < this._textChunks.length; ++i) | |
this._textChunks[i].expanded = false; | |
for (var i = fromIndex; i < toIndex; ++i) | |
this._textChunks[i].expanded = true; | |
}, | |
_totalHeight: function(firstElement, lastElement) | |
{ | |
lastElement = (lastElement || firstElement).nextElementSibling; | |
if (lastElement) | |
return lastElement.offsetTop - firstElement.offsetTop; | |
var offsetParent = firstElement.offsetParent; | |
if (offsetParent && offsetParent.scrollHeight > offsetParent.clientHeight) | |
return offsetParent.scrollHeight - firstElement.offsetTop; | |
var total = 0; | |
while (firstElement && firstElement !== lastElement) { | |
total += firstElement.offsetHeight; | |
firstElement = firstElement.nextElementSibling; | |
} | |
return total; | |
}, | |
resize: function() | |
{ | |
this._repaintAll(); | |
} | |
} | |
WebInspector.TextEditorGutterPanel = function(textModel, syncDecorationsForLineListener, syncLineHeightListener) | |
{ | |
WebInspector.TextEditorChunkedPanel.call(this, textModel); | |
this._syncDecorationsForLineListener = syncDecorationsForLineListener; | |
this._syncLineHeightListener = syncLineHeightListener; | |
this.element = document.createElement("div"); | |
this.element.className = "text-editor-lines"; | |
this._container = document.createElement("div"); | |
this._container.className = "inner-container"; | |
this.element.appendChild(this._container); | |
this.element.addEventListener("scroll", this._scroll.bind(this), false); | |
this._freeCachedElements(); | |
this._buildChunks(); | |
this._decorations = {}; | |
} | |
WebInspector.TextEditorGutterPanel.prototype = { | |
_freeCachedElements: function() | |
{ | |
this._cachedRows = []; | |
}, | |
_createNewChunk: function(startLine, endLine) | |
{ | |
return new WebInspector.TextEditorGutterChunk(this, startLine, endLine); | |
}, | |
textChanged: function(oldRange, newRange) | |
{ | |
this.beginDomUpdates(); | |
var linesDiff = newRange.linesCount - oldRange.linesCount; | |
if (linesDiff) { | |
for (var chunkNumber = this._textChunks.length - 1; chunkNumber >= 0 ; --chunkNumber) { | |
var chunk = this._textChunks[chunkNumber]; | |
if (chunk.startLine + chunk.linesCount <= this._textModel.linesCount) | |
break; | |
chunk.expanded = false; | |
this._container.removeChild(chunk.element); | |
} | |
this._textChunks.length = chunkNumber + 1; | |
var totalLines = 0; | |
if (this._textChunks.length) { | |
var lastChunk = this._textChunks[this._textChunks.length - 1]; | |
totalLines = lastChunk.startLine + lastChunk.linesCount; | |
} | |
for (var i = totalLines; i < this._textModel.linesCount; i += this._defaultChunkSize) { | |
var chunk = this._createNewChunk(i, i + this._defaultChunkSize); | |
this._textChunks.push(chunk); | |
this._container.appendChild(chunk.element); | |
} | |
for (var lineNumber in this._decorations) { | |
lineNumber = parseInt(lineNumber, 10); | |
if (lineNumber < oldRange.startLine) | |
continue; | |
if (lineNumber === oldRange.startLine && oldRange.startColumn) | |
continue; | |
var lineDecorationsCopy = this._decorations[lineNumber].slice(); | |
for (var i = 0; i < lineDecorationsCopy.length; ++i) { | |
var decoration = lineDecorationsCopy[i]; | |
this.removeDecoration(lineNumber, decoration); | |
if (lineNumber < oldRange.endLine) | |
continue; | |
this.addDecoration(lineNumber + linesDiff, decoration); | |
} | |
} | |
this._repaintAll(); | |
} else { | |
var chunkNumber = this._chunkNumberForLine(newRange.startLine); | |
var chunk = this._textChunks[chunkNumber]; | |
while (chunk && chunk.startLine <= newRange.endLine) { | |
if (chunk.linesCount === 1) | |
this._syncDecorationsForLineListener(chunk.startLine); | |
chunk = this._textChunks[++chunkNumber]; | |
} | |
} | |
this.endDomUpdates(); | |
}, | |
syncClientHeight: function(clientHeight) | |
{ | |
if (this.element.offsetHeight > clientHeight) | |
this._container.style.setProperty("padding-bottom", (this.element.offsetHeight - clientHeight) + "px"); | |
else | |
this._container.style.removeProperty("padding-bottom"); | |
}, | |
addDecoration: function(lineNumber, decoration) | |
{ | |
WebInspector.TextEditorChunkedPanel.prototype.addDecoration.call(this, lineNumber, decoration); | |
var decorations = this._decorations[lineNumber]; | |
if (!decorations) { | |
decorations = []; | |
this._decorations[lineNumber] = decorations; | |
} | |
decorations.push(decoration); | |
}, | |
removeDecoration: function(lineNumber, decoration) | |
{ | |
WebInspector.TextEditorChunkedPanel.prototype.removeDecoration.call(this, lineNumber, decoration); | |
var decorations = this._decorations[lineNumber]; | |
if (decorations) { | |
decorations.remove(decoration); | |
if (!decorations.length) | |
delete this._decorations[lineNumber]; | |
} | |
} | |
} | |
WebInspector.TextEditorGutterPanel.prototype.__proto__ = WebInspector.TextEditorChunkedPanel.prototype; | |
WebInspector.TextEditorGutterChunk = function(textEditor, startLine, endLine) | |
{ | |
this._textEditor = textEditor; | |
this._textModel = textEditor._textModel; | |
this.startLine = startLine; | |
endLine = Math.min(this._textModel.linesCount, endLine); | |
this.linesCount = endLine - startLine; | |
this._expanded = false; | |
this.element = document.createElement("div"); | |
this.element.lineNumber = startLine; | |
this.element.className = "webkit-line-number"; | |
if (this.linesCount === 1) { | |
var innerSpan = document.createElement("span"); | |
innerSpan.className = "webkit-line-number-inner"; | |
innerSpan.textContent = startLine + 1; | |
var outerSpan = document.createElement("div"); | |
outerSpan.className = "webkit-line-number-outer"; | |
outerSpan.appendChild(innerSpan); | |
this.element.appendChild(outerSpan); | |
} else { | |
var lineNumbers = []; | |
for (var i = startLine; i < endLine; ++i) | |
lineNumbers.push(i + 1); | |
this.element.textContent = lineNumbers.join("\n"); | |
} | |
} | |
WebInspector.TextEditorGutterChunk.prototype = { | |
addDecoration: function(decoration) | |
{ | |
this._textEditor.beginDomUpdates(); | |
if (typeof decoration === "string") | |
this.element.addStyleClass(decoration); | |
this._textEditor.endDomUpdates(); | |
}, | |
removeDecoration: function(decoration) | |
{ | |
this._textEditor.beginDomUpdates(); | |
if (typeof decoration === "string") | |
this.element.removeStyleClass(decoration); | |
this._textEditor.endDomUpdates(); | |
}, | |
get expanded() | |
{ | |
return this._expanded; | |
}, | |
set expanded(expanded) | |
{ | |
if (this.linesCount === 1) | |
this._textEditor._syncDecorationsForLineListener(this.startLine); | |
if (this._expanded === expanded) | |
return; | |
this._expanded = expanded; | |
if (this.linesCount === 1) | |
return; | |
this._textEditor.beginDomUpdates(); | |
if (expanded) { | |
this._expandedLineRows = []; | |
var parentElement = this.element.parentElement; | |
for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { | |
var lineRow = this._createRow(i); | |
parentElement.insertBefore(lineRow, this.element); | |
this._expandedLineRows.push(lineRow); | |
} | |
parentElement.removeChild(this.element); | |
this._textEditor._syncLineHeightListener(this._expandedLineRows[0]); | |
} else { | |
var elementInserted = false; | |
for (var i = 0; i < this._expandedLineRows.length; ++i) { | |
var lineRow = this._expandedLineRows[i]; | |
var parentElement = lineRow.parentElement; | |
if (parentElement) { | |
if (!elementInserted) { | |
elementInserted = true; | |
parentElement.insertBefore(this.element, lineRow); | |
} | |
parentElement.removeChild(lineRow); | |
} | |
this._textEditor._cachedRows.push(lineRow); | |
} | |
delete this._expandedLineRows; | |
} | |
this._textEditor.endDomUpdates(); | |
}, | |
get height() | |
{ | |
if (!this._expandedLineRows) | |
return this._textEditor._totalHeight(this.element); | |
return this._textEditor._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); | |
}, | |
get offsetTop() | |
{ | |
return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop; | |
}, | |
_createRow: function(lineNumber) | |
{ | |
var lineRow = this._textEditor._cachedRows.pop() || document.createElement("div"); | |
lineRow.lineNumber = lineNumber; | |
lineRow.className = "webkit-line-number"; | |
lineRow.textContent = lineNumber + 1; | |
return lineRow; | |
} | |
} | |
WebInspector.TextEditorMainPanel = function(delegate, textModel, url, syncScrollListener, syncDecorationsForLineListener, enterTextChangeMode, exitTextChangeMode) | |
{ | |
WebInspector.TextEditorChunkedPanel.call(this, textModel); | |
this._delegate = delegate; | |
this._syncScrollListener = syncScrollListener; | |
this._syncDecorationsForLineListener = syncDecorationsForLineListener; | |
this._enterTextChangeMode = enterTextChangeMode; | |
this._exitTextChangeMode = exitTextChangeMode; | |
this._url = url; | |
this._highlighter = new WebInspector.TextEditorHighlighter(textModel, this._highlightDataReady.bind(this)); | |
this._readOnly = true; | |
this.element = document.createElement("div"); | |
this.element.className = "text-editor-contents"; | |
this.element.tabIndex = 0; | |
this._container = document.createElement("div"); | |
this._container.className = "inner-container"; | |
this._container.tabIndex = 0; | |
this.element.appendChild(this._container); | |
this.element.addEventListener("scroll", this._scroll.bind(this), false); | |
this.element.addEventListener("focus", this._handleElementFocus.bind(this), false); | |
this._handleDOMUpdatesCallback = this._handleDOMUpdates.bind(this); | |
this._container.addEventListener("DOMCharacterDataModified", this._handleDOMUpdatesCallback, false); | |
this._container.addEventListener("DOMNodeInserted", this._handleDOMUpdatesCallback, false); | |
this._container.addEventListener("DOMSubtreeModified", this._handleDOMUpdatesCallback, false); | |
this._freeCachedElements(); | |
this._buildChunks(); | |
} | |
WebInspector.TextEditorMainPanel.prototype = { | |
set mimeType(mimeType) | |
{ | |
this._highlighter.mimeType = mimeType; | |
}, | |
setReadOnly: function(readOnly, requestFocus) | |
{ | |
if (this._readOnly === readOnly) | |
return; | |
this.beginDomUpdates(); | |
this._readOnly = readOnly; | |
if (this._readOnly) | |
this._container.removeStyleClass("text-editor-editable"); | |
else { | |
this._container.addStyleClass("text-editor-editable"); | |
if (requestFocus) | |
this._updateSelectionOnStartEditing(); | |
} | |
this.endDomUpdates(); | |
}, | |
readOnly: function() | |
{ | |
return this._readOnly; | |
}, | |
_handleElementFocus: function() | |
{ | |
if (!this._readOnly) | |
this._container.focus(); | |
}, | |
defaultFocusedElement: function() | |
{ | |
if (this._readOnly) | |
return this.element; | |
return this._container; | |
}, | |
_updateSelectionOnStartEditing: function() | |
{ | |
this._container.focus(); | |
var selection = window.getSelection(); | |
if (selection.rangeCount) { | |
var commonAncestorContainer = selection.getRangeAt(0).commonAncestorContainer; | |
if (this._container.isSelfOrAncestor(commonAncestorContainer)) | |
return; | |
} | |
selection.removeAllRanges(); | |
var range = document.createRange(); | |
range.setStart(this._container, 0); | |
range.setEnd(this._container, 0); | |
selection.addRange(range); | |
}, | |
setEditableRange: function(startLine, endLine) | |
{ | |
this.beginDomUpdates(); | |
var firstChunkNumber = this._chunkNumberForLine(startLine); | |
var firstChunk = this._textChunks[firstChunkNumber]; | |
if (firstChunk.startLine !== startLine) { | |
this._splitChunkOnALine(startLine, firstChunkNumber); | |
firstChunkNumber += 1; | |
} | |
var lastChunkNumber = this._textChunks.length; | |
if (endLine !== this._textModel.linesCount) { | |
lastChunkNumber = this._chunkNumberForLine(endLine); | |
var lastChunk = this._textChunks[lastChunkNumber]; | |
if (lastChunk && lastChunk.startLine !== endLine) { | |
this._splitChunkOnALine(endLine, lastChunkNumber); | |
lastChunkNumber += 1; | |
} | |
} | |
for (var chunkNumber = 0; chunkNumber < firstChunkNumber; ++chunkNumber) | |
this._textChunks[chunkNumber].readOnly = true; | |
for (var chunkNumber = firstChunkNumber; chunkNumber < lastChunkNumber; ++chunkNumber) | |
this._textChunks[chunkNumber].readOnly = false; | |
for (var chunkNumber = lastChunkNumber; chunkNumber < this._textChunks.length; ++chunkNumber) | |
this._textChunks[chunkNumber].readOnly = true; | |
this.endDomUpdates(); | |
}, | |
clearEditableRange: function() | |
{ | |
for (var chunkNumber = 0; chunkNumber < this._textChunks.length; ++chunkNumber) | |
this._textChunks[chunkNumber].readOnly = false; | |
}, | |
markAndRevealRange: function(range) | |
{ | |
if (this._rangeToMark) { | |
var markedLine = this._rangeToMark.startLine; | |
delete this._rangeToMark; | |
if (!this._dirtyLines) { | |
this.beginDomUpdates(); | |
var chunk = this.chunkForLine(markedLine); | |
var wasExpanded = chunk.expanded; | |
chunk.expanded = false; | |
chunk.updateCollapsedLineRow(); | |
chunk.expanded = wasExpanded; | |
this.endDomUpdates(); | |
} else | |
this._paintLines(markedLine, markedLine + 1); | |
} | |
if (range) { | |
this._rangeToMark = range; | |
this.revealLine(range.startLine); | |
var chunk = this.makeLineAChunk(range.startLine); | |
this._paintLine(chunk.element); | |
if (this._markedRangeElement) | |
this._markedRangeElement.scrollIntoViewIfNeeded(); | |
} | |
delete this._markedRangeElement; | |
}, | |
highlightLine: function(lineNumber) | |
{ | |
this.clearLineHighlight(); | |
this._highlightedLine = lineNumber; | |
this.revealLine(lineNumber); | |
if (!this._readOnly) | |
this._restoreSelection(WebInspector.TextRange.createFromLocation(lineNumber, 0), false); | |
this.addDecoration(lineNumber, "webkit-highlighted-line"); | |
}, | |
clearLineHighlight: function() | |
{ | |
if (typeof this._highlightedLine === "number") { | |
this.removeDecoration(this._highlightedLine, "webkit-highlighted-line"); | |
delete this._highlightedLine; | |
} | |
}, | |
_freeCachedElements: function() | |
{ | |
this._cachedSpans = []; | |
this._cachedTextNodes = []; | |
this._cachedRows = []; | |
}, | |
handleUndoRedo: function(redo) | |
{ | |
if (this._dirtyLines) | |
return false; | |
this.beginUpdates(); | |
function before() | |
{ | |
this._enterTextChangeMode(); | |
} | |
function after(oldRange, newRange) | |
{ | |
this._exitTextChangeMode(oldRange, newRange); | |
} | |
var range = redo ? this._textModel.redo(before.bind(this), after.bind(this)) : this._textModel.undo(before.bind(this), after.bind(this)); | |
this.endUpdates(); | |
if (range) | |
this._restoreSelection(range, true); | |
return true; | |
}, | |
handleTabKeyPress: function(shiftKey) | |
{ | |
if (this._dirtyLines) | |
return false; | |
var selection = this._getSelection(); | |
if (!selection) | |
return false; | |
var range = selection.normalize(); | |
this.beginUpdates(); | |
this._enterTextChangeMode(); | |
var newRange; | |
var rangeWasEmpty = range.isEmpty(); | |
if (shiftKey) | |
newRange = this._unindentLines(range); | |
else { | |
if (rangeWasEmpty) | |
newRange = this._editRange(range, WebInspector.settings.textEditorIndent.get()); | |
else | |
newRange = this._indentLines(range); | |
} | |
this._exitTextChangeMode(range, newRange); | |
this.endUpdates(); | |
if (rangeWasEmpty) | |
newRange.startColumn = newRange.endColumn; | |
this._restoreSelection(newRange, true); | |
return true; | |
}, | |
_indentLines: function(range) | |
{ | |
var indent = WebInspector.settings.textEditorIndent.get(); | |
if (this._lastEditedRange) | |
this._textModel.markUndoableState(); | |
var newRange = range.clone(); | |
if (range.startColumn) | |
newRange.startColumn += indent.length; | |
var indentEndLine = range.endLine; | |
if (range.endColumn) | |
newRange.endColumn += indent.length; | |
else | |
indentEndLine--; | |
for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++) | |
this._textModel.editRange(WebInspector.TextRange.createFromLocation(lineNumber, 0), indent); | |
this._lastEditedRange = newRange; | |
return newRange; | |
}, | |
_unindentLines: function(range) | |
{ | |
if (this._lastEditedRange) | |
this._textModel.markUndoableState(); | |
var indent = WebInspector.settings.textEditorIndent.get(); | |
var indentLength = indent === WebInspector.TextEditorModel.Indent.TabCharacter ? 4 : indent.length; | |
var lineIndentRegex = new RegExp("^ {1," + indentLength + "}"); | |
var newRange = range.clone(); | |
var indentEndLine = range.endLine; | |
if (!range.endColumn) | |
indentEndLine--; | |
for (var lineNumber = range.startLine; lineNumber <= indentEndLine; lineNumber++) { | |
var line = this._textModel.line(lineNumber); | |
var firstCharacter = line.charAt(0); | |
var lineIndentLength; | |
if (firstCharacter === " ") | |
lineIndentLength = line.match(lineIndentRegex)[0].length; | |
else if (firstCharacter === "\t") | |
lineIndentLength = 1; | |
else | |
continue; | |
this._textModel.editRange(new WebInspector.TextRange(lineNumber, 0, lineNumber, lineIndentLength), ""); | |
if (lineNumber === range.startLine) | |
newRange.startColumn = Math.max(0, newRange.startColumn - lineIndentLength); | |
} | |
if (lineIndentLength) | |
newRange.endColumn = Math.max(0, newRange.endColumn - lineIndentLength); | |
this._lastEditedRange = newRange; | |
return newRange; | |
}, | |
handleEnterKey: function() | |
{ | |
if (this._dirtyLines) | |
return false; | |
var range = this._getSelection(); | |
if (!range) | |
return false; | |
range = range.normalize(); | |
if (range.endColumn === 0) | |
return false; | |
var line = this._textModel.line(range.startLine); | |
var linePrefix = line.substring(0, range.startColumn); | |
var indentMatch = linePrefix.match(/^\s+/); | |
var currentIndent = indentMatch ? indentMatch[0] : ""; | |
var textEditorIndent = WebInspector.settings.textEditorIndent.get(); | |
var indent = WebInspector.TextEditorModel.endsWithBracketRegex.test(linePrefix) ? currentIndent + textEditorIndent : currentIndent; | |
if (!indent) | |
return false; | |
this.beginUpdates(); | |
this._enterTextChangeMode(); | |
var lineBreak = this._textModel.lineBreak; | |
var newRange; | |
if (range.isEmpty() && line.substr(range.endColumn - 1, 2) === '{}') { | |
newRange = this._editRange(range, lineBreak + indent + lineBreak + currentIndent); | |
newRange.endLine--; | |
newRange.endColumn += textEditorIndent.length; | |
} else | |
newRange = this._editRange(range, lineBreak + indent); | |
this._exitTextChangeMode(range, newRange); | |
this.endUpdates(); | |
this._restoreSelection(newRange.collapseToEnd(), true); | |
return true; | |
}, | |
_splitChunkOnALine: function(lineNumber, chunkNumber, createSuffixChunk) | |
{ | |
var selection = this._getSelection(); | |
var chunk = WebInspector.TextEditorChunkedPanel.prototype._splitChunkOnALine.call(this, lineNumber, chunkNumber, createSuffixChunk); | |
this._restoreSelection(selection); | |
return chunk; | |
}, | |
beginDomUpdates: function() | |
{ | |
WebInspector.TextEditorChunkedPanel.prototype.beginDomUpdates.call(this); | |
if (this._domUpdateCoalescingLevel === 1) { | |
this._container.removeEventListener("DOMCharacterDataModified", this._handleDOMUpdatesCallback, false); | |
this._container.removeEventListener("DOMNodeInserted", this._handleDOMUpdatesCallback, false); | |
this._container.removeEventListener("DOMSubtreeModified", this._handleDOMUpdatesCallback, false); | |
} | |
}, | |
endDomUpdates: function() | |
{ | |
WebInspector.TextEditorChunkedPanel.prototype.endDomUpdates.call(this); | |
if (this._domUpdateCoalescingLevel === 0) { | |
this._container.addEventListener("DOMCharacterDataModified", this._handleDOMUpdatesCallback, false); | |
this._container.addEventListener("DOMNodeInserted", this._handleDOMUpdatesCallback, false); | |
this._container.addEventListener("DOMSubtreeModified", this._handleDOMUpdatesCallback, false); | |
} | |
}, | |
_buildChunks: function() | |
{ | |
for (var i = 0; i < this._textModel.linesCount; ++i) | |
this._textModel.removeAttribute(i, "highlight"); | |
WebInspector.TextEditorChunkedPanel.prototype._buildChunks.call(this); | |
}, | |
_createNewChunk: function(startLine, endLine) | |
{ | |
return new WebInspector.TextEditorMainChunk(this, startLine, endLine); | |
}, | |
_expandChunks: function(fromIndex, toIndex) | |
{ | |
var lastChunk = this._textChunks[toIndex - 1]; | |
var lastVisibleLine = lastChunk.startLine + lastChunk.linesCount; | |
var selection = this._getSelection(); | |
this._muteHighlightListener = true; | |
this._highlighter.highlight(lastVisibleLine); | |
delete this._muteHighlightListener; | |
this._restorePaintLinesOperationsCredit(); | |
WebInspector.TextEditorChunkedPanel.prototype._expandChunks.call(this, fromIndex, toIndex); | |
this._adjustPaintLinesOperationsRefreshValue(); | |
this._restoreSelection(selection); | |
}, | |
_highlightDataReady: function(fromLine, toLine) | |
{ | |
if (this._muteHighlightListener) | |
return; | |
this._restorePaintLinesOperationsCredit(); | |
this._paintLines(fromLine, toLine, true ); | |
}, | |
_schedulePaintLines: function(startLine, endLine) | |
{ | |
if (startLine >= endLine) | |
return; | |
if (!this._scheduledPaintLines) { | |
this._scheduledPaintLines = [ { startLine: startLine, endLine: endLine } ]; | |
this._paintScheduledLinesTimer = setTimeout(this._paintScheduledLines.bind(this), 0); | |
} else { | |
for (var i = 0; i < this._scheduledPaintLines.length; ++i) { | |
var chunk = this._scheduledPaintLines[i]; | |
if (chunk.startLine <= endLine && chunk.endLine >= startLine) { | |
chunk.startLine = Math.min(chunk.startLine, startLine); | |
chunk.endLine = Math.max(chunk.endLine, endLine); | |
return; | |
} | |
if (chunk.startLine > endLine) { | |
this._scheduledPaintLines.splice(i, 0, { startLine: startLine, endLine: endLine }); | |
return; | |
} | |
} | |
this._scheduledPaintLines.push({ startLine: startLine, endLine: endLine }); | |
} | |
}, | |
_paintScheduledLines: function(skipRestoreSelection) | |
{ | |
if (this._paintScheduledLinesTimer) | |
clearTimeout(this._paintScheduledLinesTimer); | |
delete this._paintScheduledLinesTimer; | |
if (!this._scheduledPaintLines) | |
return; | |
if (this._dirtyLines || this._repaintAllTimer) { | |
this._paintScheduledLinesTimer = setTimeout(this._paintScheduledLines.bind(this), 50); | |
return; | |
} | |
var scheduledPaintLines = this._scheduledPaintLines; | |
delete this._scheduledPaintLines; | |
this._restorePaintLinesOperationsCredit(); | |
this._paintLineChunks(scheduledPaintLines, !skipRestoreSelection); | |
this._adjustPaintLinesOperationsRefreshValue(); | |
}, | |
_restorePaintLinesOperationsCredit: function() | |
{ | |
if (!this._paintLinesOperationsRefreshValue) | |
this._paintLinesOperationsRefreshValue = 250; | |
this._paintLinesOperationsCredit = this._paintLinesOperationsRefreshValue; | |
this._paintLinesOperationsLastRefresh = Date.now(); | |
}, | |
_adjustPaintLinesOperationsRefreshValue: function() | |
{ | |
var operationsDone = this._paintLinesOperationsRefreshValue - this._paintLinesOperationsCredit; | |
if (operationsDone <= 0) | |
return; | |
var timePast = Date.now() - this._paintLinesOperationsLastRefresh; | |
if (timePast <= 0) | |
return; | |
var value = Math.floor(operationsDone / timePast * 50); | |
this._paintLinesOperationsRefreshValue = Number.constrain(value, 150, 1500); | |
}, | |
_paintLines: function(fromLine, toLine, restoreSelection) | |
{ | |
this._paintLineChunks([ { startLine: fromLine, endLine: toLine } ], restoreSelection); | |
}, | |
_paintLineChunks: function(lineChunks, restoreSelection) | |
{ | |
var visibleFrom = this.element.scrollTop; | |
var firstVisibleLineNumber = this._findFirstVisibleLineNumber(visibleFrom); | |
var chunk; | |
var selection; | |
var invisibleLineRows = []; | |
for (var i = 0; i < lineChunks.length; ++i) { | |
var lineChunk = lineChunks[i]; | |
if (this._dirtyLines || this._scheduledPaintLines) { | |
this._schedulePaintLines(lineChunk.startLine, lineChunk.endLine); | |
continue; | |
} | |
for (var lineNumber = lineChunk.startLine; lineNumber < lineChunk.endLine; ++lineNumber) { | |
if (!chunk || lineNumber < chunk.startLine || lineNumber >= chunk.startLine + chunk.linesCount) | |
chunk = this.chunkForLine(lineNumber); | |
var lineRow = chunk.getExpandedLineRow(lineNumber); | |
if (!lineRow) | |
continue; | |
if (lineNumber < firstVisibleLineNumber) { | |
invisibleLineRows.push(lineRow); | |
continue; | |
} | |
if (restoreSelection && !selection) | |
selection = this._getSelection(); | |
this._paintLine(lineRow); | |
if (this._paintLinesOperationsCredit < 0) { | |
this._schedulePaintLines(lineNumber + 1, lineChunk.endLine); | |
break; | |
} | |
} | |
} | |
for (var i = 0; i < invisibleLineRows.length; ++i) { | |
if (restoreSelection && !selection) | |
selection = this._getSelection(); | |
this._paintLine(invisibleLineRows[i]); | |
} | |
if (restoreSelection) | |
this._restoreSelection(selection); | |
}, | |
_paintLine: function(lineRow) | |
{ | |
var lineNumber = lineRow.lineNumber; | |
if (this._dirtyLines) { | |
this._schedulePaintLines(lineNumber, lineNumber + 1); | |
return; | |
} | |
this.beginDomUpdates(); | |
try { | |
if (this._scheduledPaintLines || this._paintLinesOperationsCredit < 0) { | |
this._schedulePaintLines(lineNumber, lineNumber + 1); | |
return; | |
} | |
var highlight = this._textModel.getAttribute(lineNumber, "highlight"); | |
if (!highlight) | |
return; | |
lineRow.removeChildren(); | |
var line = this._textModel.line(lineNumber); | |
if (!line) | |
lineRow.appendChild(document.createElement("br")); | |
var plainTextStart = -1; | |
for (var j = 0; j < line.length;) { | |
if (j > 1000) { | |
if (plainTextStart === -1) | |
plainTextStart = j; | |
break; | |
} | |
var attribute = highlight[j]; | |
if (!attribute || !attribute.tokenType) { | |
if (plainTextStart === -1) | |
plainTextStart = j; | |
j++; | |
} else { | |
if (plainTextStart !== -1) { | |
this._appendTextNode(lineRow, line.substring(plainTextStart, j)); | |
plainTextStart = -1; | |
--this._paintLinesOperationsCredit; | |
} | |
this._appendSpan(lineRow, line.substring(j, j + attribute.length), attribute.tokenType); | |
j += attribute.length; | |
--this._paintLinesOperationsCredit; | |
} | |
} | |
if (plainTextStart !== -1) { | |
this._appendTextNode(lineRow, line.substring(plainTextStart, line.length)); | |
--this._paintLinesOperationsCredit; | |
} | |
if (lineRow.decorationsElement) | |
lineRow.appendChild(lineRow.decorationsElement); | |
} finally { | |
if (this._rangeToMark && this._rangeToMark.startLine === lineNumber) | |
this._markedRangeElement = WebInspector.highlightSearchResult(lineRow, this._rangeToMark.startColumn, this._rangeToMark.endColumn - this._rangeToMark.startColumn); | |
this.endDomUpdates(); | |
} | |
}, | |
_releaseLinesHighlight: function(lineRow) | |
{ | |
if (!lineRow) | |
return; | |
if ("spans" in lineRow) { | |
var spans = lineRow.spans; | |
for (var j = 0; j < spans.length; ++j) | |
this._cachedSpans.push(spans[j]); | |
delete lineRow.spans; | |
} | |
if ("textNodes" in lineRow) { | |
var textNodes = lineRow.textNodes; | |
for (var j = 0; j < textNodes.length; ++j) | |
this._cachedTextNodes.push(textNodes[j]); | |
delete lineRow.textNodes; | |
} | |
this._cachedRows.push(lineRow); | |
}, | |
_getSelection: function() | |
{ | |
var selection = window.getSelection(); | |
if (!selection.rangeCount) | |
return null; | |
if (!this._container.isAncestor(selection.anchorNode) || !this._container.isAncestor(selection.focusNode)) | |
return null; | |
var start = this._selectionToPosition(selection.anchorNode, selection.anchorOffset); | |
var end = selection.isCollapsed ? start : this._selectionToPosition(selection.focusNode, selection.focusOffset); | |
return new WebInspector.TextRange(start.line, start.column, end.line, end.column); | |
}, | |
_restoreSelection: function(range, scrollIntoView) | |
{ | |
if (!range) | |
return; | |
var start = this._positionToSelection(range.startLine, range.startColumn); | |
var end = range.isEmpty() ? start : this._positionToSelection(range.endLine, range.endColumn); | |
window.getSelection().setBaseAndExtent(start.container, start.offset, end.container, end.offset); | |
if (scrollIntoView) { | |
for (var node = end.container; node; node = node.parentElement) { | |
if (node.scrollIntoViewIfNeeded) { | |
node.scrollIntoViewIfNeeded(); | |
break; | |
} | |
} | |
} | |
}, | |
_selectionToPosition: function(container, offset) | |
{ | |
if (container === this._container && offset === 0) | |
return { line: 0, column: 0 }; | |
if (container === this._container && offset === 1) | |
return { line: this._textModel.linesCount - 1, column: this._textModel.lineLength(this._textModel.linesCount - 1) }; | |
var lineRow = this._enclosingLineRowOrSelf(container); | |
var lineNumber = lineRow.lineNumber; | |
if (container === lineRow && offset === 0) | |
return { line: lineNumber, column: 0 }; | |
var column = 0; | |
var node = lineRow.nodeType === Node.TEXT_NODE ? lineRow : lineRow.traverseNextTextNode(lineRow); | |
while (node && node !== container) { | |
var text = node.textContent; | |
for (var i = 0; i < text.length; ++i) { | |
if (text.charAt(i) === "\n") { | |
lineNumber++; | |
column = 0; | |
} else | |
column++; | |
} | |
node = node.traverseNextTextNode(lineRow); | |
} | |
if (node === container && offset) { | |
var text = node.textContent; | |
for (var i = 0; i < offset; ++i) { | |
if (text.charAt(i) === "\n") { | |
lineNumber++; | |
column = 0; | |
} else | |
column++; | |
} | |
} | |
return { line: lineNumber, column: column }; | |
}, | |
_positionToSelection: function(line, column) | |
{ | |
var chunk = this.chunkForLine(line); | |
var lineRow = chunk.linesCount === 1 ? chunk.element : chunk.getExpandedLineRow(line); | |
if (lineRow) | |
var rangeBoundary = lineRow.rangeBoundaryForOffset(column); | |
else { | |
var offset = column; | |
for (var i = chunk.startLine; i < line; ++i) | |
offset += this._textModel.lineLength(i) + 1; | |
lineRow = chunk.element; | |
if (lineRow.firstChild) | |
var rangeBoundary = { container: lineRow.firstChild, offset: offset }; | |
else | |
var rangeBoundary = { container: lineRow, offset: 0 }; | |
} | |
return rangeBoundary; | |
}, | |
_enclosingLineRowOrSelf: function(element) | |
{ | |
var lineRow = element.enclosingNodeOrSelfWithClass("webkit-line-content"); | |
if (lineRow) | |
return lineRow; | |
for (lineRow = element; lineRow; lineRow = lineRow.parentElement) { | |
if (lineRow.parentElement === this._container) | |
return lineRow; | |
} | |
return null; | |
}, | |
_appendSpan: function(element, content, className) | |
{ | |
if (className === "html-resource-link" || className === "html-external-link") { | |
element.appendChild(this._createLink(content, className === "html-external-link")); | |
return; | |
} | |
var span = this._cachedSpans.pop() || document.createElement("span"); | |
span.className = "webkit-" + className; | |
span.textContent = content; | |
element.appendChild(span); | |
if (!("spans" in element)) | |
element.spans = []; | |
element.spans.push(span); | |
}, | |
_appendTextNode: function(element, text) | |
{ | |
var textNode = this._cachedTextNodes.pop(); | |
if (textNode) | |
textNode.nodeValue = text; | |
else | |
textNode = document.createTextNode(text); | |
element.appendChild(textNode); | |
if (!("textNodes" in element)) | |
element.textNodes = []; | |
element.textNodes.push(textNode); | |
}, | |
_createLink: function(content, isExternal) | |
{ | |
var quote = content.charAt(0); | |
if (content.length > 1 && (quote === "\"" || quote === "'")) | |
content = content.substring(1, content.length - 1); | |
else | |
quote = null; | |
var span = document.createElement("span"); | |
span.className = "webkit-html-attribute-value"; | |
if (quote) | |
span.appendChild(document.createTextNode(quote)); | |
span.appendChild(this._delegate.createLink(content, isExternal)); | |
if (quote) | |
span.appendChild(document.createTextNode(quote)); | |
return span; | |
}, | |
_handleDOMUpdates: function(e) | |
{ | |
if (this._domUpdateCoalescingLevel) | |
return; | |
var target = e.target; | |
if (target === this._container) | |
return; | |
var lineRow = this._enclosingLineRowOrSelf(target); | |
if (!lineRow) | |
return; | |
if (lineRow.decorationsElement && lineRow.decorationsElement.isSelfOrAncestor(target)) { | |
if (this._syncDecorationsForLineListener) | |
this._syncDecorationsForLineListener(lineRow.lineNumber); | |
return; | |
} | |
if (this._readOnly) | |
return; | |
if (target === lineRow && e.type === "DOMNodeInserted") { | |
delete lineRow.lineNumber; | |
} | |
var startLine = 0; | |
for (var row = lineRow; row; row = row.previousSibling) { | |
if (typeof row.lineNumber === "number") { | |
startLine = row.lineNumber; | |
break; | |
} | |
} | |
var endLine = startLine + 1; | |
for (var row = lineRow.nextSibling; row; row = row.nextSibling) { | |
if (typeof row.lineNumber === "number" && row.lineNumber > startLine) { | |
endLine = row.lineNumber; | |
break; | |
} | |
} | |
if (this._dirtyLines) { | |
this._dirtyLines.start = Math.min(this._dirtyLines.start, startLine); | |
this._dirtyLines.end = Math.max(this._dirtyLines.end, endLine); | |
} else { | |
this._dirtyLines = { start: startLine, end: endLine }; | |
setTimeout(this._applyDomUpdates.bind(this), 0); | |
this.markAndRevealRange(null); | |
} | |
}, | |
_applyDomUpdates: function() | |
{ | |
if (!this._dirtyLines) | |
return; | |
if (this._readOnly) { | |
delete this._dirtyLines; | |
return; | |
} | |
var dirtyLines = this._dirtyLines; | |
var firstChunkNumber = this._chunkNumberForLine(dirtyLines.start); | |
var startLine = this._textChunks[firstChunkNumber].startLine; | |
var endLine = this._textModel.linesCount; | |
var firstLineRow; | |
if (firstChunkNumber) { | |
var chunk = this._textChunks[firstChunkNumber - 1]; | |
firstLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine + chunk.linesCount - 1) : chunk.element; | |
firstLineRow = firstLineRow.nextSibling; | |
} else | |
firstLineRow = this._container.firstChild; | |
var lines = []; | |
for (var lineRow = firstLineRow; lineRow; lineRow = lineRow.nextSibling) { | |
if (typeof lineRow.lineNumber === "number" && lineRow.lineNumber >= dirtyLines.end) { | |
endLine = lineRow.lineNumber; | |
break; | |
} | |
lineRow.lineNumber = startLine + lines.length; | |
this._collectLinesFromDiv(lines, lineRow); | |
} | |
var startOffset = 0; | |
while (startLine < dirtyLines.start && startOffset < lines.length) { | |
if (this._textModel.line(startLine) !== lines[startOffset]) | |
break; | |
++startOffset; | |
++startLine; | |
} | |
var endOffset = lines.length; | |
while (endLine > dirtyLines.end && endOffset > startOffset) { | |
if (this._textModel.line(endLine - 1) !== lines[endOffset - 1]) | |
break; | |
--endOffset; | |
--endLine; | |
} | |
lines = lines.slice(startOffset, endOffset); | |
var startColumn = 0; | |
var endColumn = this._textModel.lineLength(endLine - 1); | |
if (lines.length > 0) { | |
var line1 = this._textModel.line(startLine); | |
var line2 = lines[0]; | |
while (line1[startColumn] && line1[startColumn] === line2[startColumn]) | |
++startColumn; | |
lines[0] = line2.substring(startColumn); | |
line1 = this._textModel.line(endLine - 1); | |
line2 = lines[lines.length - 1]; | |
for (var i = 0; i < endColumn && i < line2.length; ++i) { | |
if (startLine === endLine - 1 && endColumn - i <= startColumn) | |
break; | |
if (line1[endColumn - i - 1] !== line2[line2.length - i - 1]) | |
break; | |
} | |
if (i) { | |
endColumn -= i; | |
lines[lines.length - 1] = line2.substring(0, line2.length - i); | |
} | |
} | |
var selection = this._getSelection(); | |
if (lines.length === 0 && endLine < this._textModel.linesCount) | |
var oldRange = new WebInspector.TextRange(startLine, 0, endLine, 0); | |
else if (lines.length === 0 && startLine > 0) | |
var oldRange = new WebInspector.TextRange(startLine - 1, this._textModel.lineLength(startLine - 1), endLine - 1, this._textModel.lineLength(endLine - 1)); | |
else | |
var oldRange = new WebInspector.TextRange(startLine, startColumn, endLine - 1, endColumn); | |
var newContent = lines.join("\n"); | |
if (this._textModel.copyRange(oldRange) === newContent) { | |
delete this._dirtyLines; | |
return; | |
} | |
if (lines.length === 1 && lines[0] === "}" && oldRange.isEmpty() && selection.isEmpty() && !this._textModel.line(oldRange.endLine).trim()) | |
this._unindentAfterBlock(oldRange, selection); | |
this._enterTextChangeMode(); | |
delete this._dirtyLines; | |
var newRange = this._editRange(oldRange, newContent); | |
this._paintScheduledLines(true); | |
this._restoreSelection(selection); | |
this._exitTextChangeMode(oldRange, newRange); | |
}, | |
_unindentAfterBlock: function(oldRange, selection) | |
{ | |
var nestingLevel = 1; | |
for (var i = oldRange.endLine; i >= 0; --i) { | |
var attribute = this._textModel.getAttribute(i, "highlight"); | |
if (!attribute) | |
continue; | |
var columnNumbers = Object.keys(attribute).reverse(); | |
for (var j = 0; j < columnNumbers.length; ++j) { | |
var column = columnNumbers[j]; | |
if (attribute[column].tokenType === "block-start") { | |
if (!(--nestingLevel)) { | |
var lineContent = this._textModel.line(i); | |
var blockOffset = lineContent.length - lineContent.trimLeft().length; | |
if (blockOffset < oldRange.startColumn) { | |
oldRange.startColumn = blockOffset; | |
selection.startColumn = blockOffset + 1; | |
selection.endColumn = blockOffset + 1; | |
} | |
return; | |
} | |
} | |
if (attribute[column].tokenType === "block-end") | |
++nestingLevel; | |
} | |
} | |
}, | |
textChanged: function(oldRange, newRange) | |
{ | |
this.beginDomUpdates(); | |
this._removeDecorationsInRange(oldRange); | |
this._updateChunksForRanges(oldRange, newRange); | |
this._updateHighlightsForRange(newRange); | |
this.endDomUpdates(); | |
}, | |
_editRange: function(range, text) | |
{ | |
if (this._lastEditedRange && (!text || text.indexOf("\n") !== -1 || this._lastEditedRange.endLine !== range.startLine || this._lastEditedRange.endColumn !== range.startColumn)) | |
this._textModel.markUndoableState(); | |
var newRange = this._textModel.editRange(range, text); | |
this._lastEditedRange = newRange; | |
return newRange; | |
}, | |
_removeDecorationsInRange: function(range) | |
{ | |
for (var i = this._chunkNumberForLine(range.startLine); i < this._textChunks.length; ++i) { | |
var chunk = this._textChunks[i]; | |
if (chunk.startLine > range.endLine) | |
break; | |
chunk.removeAllDecorations(); | |
} | |
}, | |
_updateChunksForRanges: function(oldRange, newRange) | |
{ | |
var firstChunkNumber = this._chunkNumberForLine(oldRange.startLine); | |
var lastChunkNumber = firstChunkNumber; | |
while (lastChunkNumber + 1 < this._textChunks.length) { | |
if (this._textChunks[lastChunkNumber + 1].startLine > oldRange.endLine) | |
break; | |
++lastChunkNumber; | |
} | |
var startLine = this._textChunks[firstChunkNumber].startLine; | |
var linesCount = this._textChunks[lastChunkNumber].startLine + this._textChunks[lastChunkNumber].linesCount - startLine; | |
var linesDiff = newRange.linesCount - oldRange.linesCount; | |
linesCount += linesDiff; | |
if (linesDiff) { | |
for (var chunkNumber = lastChunkNumber + 1; chunkNumber < this._textChunks.length; ++chunkNumber) | |
this._textChunks[chunkNumber].startLine += linesDiff; | |
} | |
var firstLineRow; | |
if (firstChunkNumber) { | |
var chunk = this._textChunks[firstChunkNumber - 1]; | |
firstLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine + chunk.linesCount - 1) : chunk.element; | |
firstLineRow = firstLineRow.nextSibling; | |
} else | |
firstLineRow = this._container.firstChild; | |
for (var chunkNumber = firstChunkNumber; chunkNumber <= lastChunkNumber; ++chunkNumber) { | |
var chunk = this._textChunks[chunkNumber]; | |
if (chunk.startLine + chunk.linesCount > this._textModel.linesCount) | |
break; | |
var lineNumber = chunk.startLine; | |
for (var lineRow = firstLineRow; lineRow && lineNumber < chunk.startLine + chunk.linesCount; lineRow = lineRow.nextSibling) { | |
if (lineRow.lineNumber !== lineNumber || lineRow !== chunk.getExpandedLineRow(lineNumber) || lineRow.textContent !== this._textModel.line(lineNumber) || !lineRow.firstChild) | |
break; | |
++lineNumber; | |
} | |
if (lineNumber < chunk.startLine + chunk.linesCount) | |
break; | |
chunk.updateCollapsedLineRow(); | |
++firstChunkNumber; | |
firstLineRow = lineRow; | |
startLine += chunk.linesCount; | |
linesCount -= chunk.linesCount; | |
} | |
if (firstChunkNumber > lastChunkNumber && linesCount === 0) | |
return; | |
var chunk = this._textChunks[lastChunkNumber + 1]; | |
var linesInLastChunk = linesCount % this._defaultChunkSize; | |
if (chunk && !chunk.decorated && linesInLastChunk > 0 && linesInLastChunk + chunk.linesCount <= this._defaultChunkSize) { | |
++lastChunkNumber; | |
linesCount += chunk.linesCount; | |
} | |
var scrollTop = this.element.scrollTop; | |
var scrollLeft = this.element.scrollLeft; | |
var firstUnmodifiedLineRow = null; | |
chunk = this._textChunks[lastChunkNumber + 1]; | |
if (chunk) | |
firstUnmodifiedLineRow = chunk.expanded ? chunk.getExpandedLineRow(chunk.startLine) : chunk.element; | |
while (firstLineRow && firstLineRow !== firstUnmodifiedLineRow) { | |
var lineRow = firstLineRow; | |
firstLineRow = firstLineRow.nextSibling; | |
this._container.removeChild(lineRow); | |
} | |
for (var chunkNumber = firstChunkNumber; linesCount > 0; ++chunkNumber) { | |
var chunkLinesCount = Math.min(this._defaultChunkSize, linesCount); | |
var newChunk = this._createNewChunk(startLine, startLine + chunkLinesCount); | |
this._container.insertBefore(newChunk.element, firstUnmodifiedLineRow); | |
if (chunkNumber <= lastChunkNumber) | |
this._textChunks[chunkNumber] = newChunk; | |
else | |
this._textChunks.splice(chunkNumber, 0, newChunk); | |
startLine += chunkLinesCount; | |
linesCount -= chunkLinesCount; | |
} | |
if (chunkNumber <= lastChunkNumber) | |
this._textChunks.splice(chunkNumber, lastChunkNumber - chunkNumber + 1); | |
this.element.scrollTop = scrollTop; | |
this.element.scrollLeft = scrollLeft; | |
}, | |
_updateHighlightsForRange: function(range) | |
{ | |
var visibleFrom = this.element.scrollTop; | |
var visibleTo = this.element.scrollTop + this.element.clientHeight; | |
var result = this._findVisibleChunks(visibleFrom, visibleTo); | |
var chunk = this._textChunks[result.end - 1]; | |
var lastVisibleLine = chunk.startLine + chunk.linesCount; | |
lastVisibleLine = Math.max(lastVisibleLine, range.endLine + 1); | |
lastVisibleLine = Math.min(lastVisibleLine, this._textModel.linesCount); | |
var updated = this._highlighter.updateHighlight(range.startLine, lastVisibleLine); | |
if (!updated) { | |
for (var i = this._chunkNumberForLine(range.startLine); i < this._textChunks.length; ++i) | |
this._textChunks[i].expanded = false; | |
} | |
this._repaintAll(); | |
}, | |
_collectLinesFromDiv: function(lines, element) | |
{ | |
var textContents = []; | |
var node = element.nodeType === Node.TEXT_NODE ? element : element.traverseNextNode(element); | |
while (node) { | |
if (element.decorationsElement === node) { | |
node = node.nextSibling; | |
continue; | |
} | |
if (node.nodeName.toLowerCase() === "br") | |
textContents.push("\n"); | |
else if (node.nodeType === Node.TEXT_NODE) | |
textContents.push(node.textContent); | |
node = node.traverseNextNode(element); | |
} | |
var textContent = textContents.join(""); | |
textContent = textContent.replace(/\n$/, ""); | |
textContents = textContent.split("\n"); | |
for (var i = 0; i < textContents.length; ++i) | |
lines.push(textContents[i]); | |
} | |
} | |
WebInspector.TextEditorMainPanel.prototype.__proto__ = WebInspector.TextEditorChunkedPanel.prototype; | |
WebInspector.TextEditorMainChunk = function(chunkedPanel, startLine, endLine) | |
{ | |
this._chunkedPanel = chunkedPanel; | |
this._textModel = chunkedPanel._textModel; | |
this.element = document.createElement("div"); | |
this.element.lineNumber = startLine; | |
this.element.className = "webkit-line-content"; | |
this._startLine = startLine; | |
endLine = Math.min(this._textModel.linesCount, endLine); | |
this.linesCount = endLine - startLine; | |
this._expanded = false; | |
this._readOnly = false; | |
this.updateCollapsedLineRow(); | |
} | |
WebInspector.TextEditorMainChunk.prototype = { | |
addDecoration: function(decoration) | |
{ | |
this._chunkedPanel.beginDomUpdates(); | |
if (typeof decoration === "string") | |
this.element.addStyleClass(decoration); | |
else { | |
if (!this.element.decorationsElement) { | |
this.element.decorationsElement = document.createElement("div"); | |
this.element.decorationsElement.className = "webkit-line-decorations"; | |
this.element.appendChild(this.element.decorationsElement); | |
} | |
this.element.decorationsElement.appendChild(decoration); | |
} | |
this._chunkedPanel.endDomUpdates(); | |
}, | |
removeDecoration: function(decoration) | |
{ | |
this._chunkedPanel.beginDomUpdates(); | |
if (typeof decoration === "string") | |
this.element.removeStyleClass(decoration); | |
else if (this.element.decorationsElement) | |
this.element.decorationsElement.removeChild(decoration); | |
this._chunkedPanel.endDomUpdates(); | |
}, | |
removeAllDecorations: function() | |
{ | |
this._chunkedPanel.beginDomUpdates(); | |
this.element.className = "webkit-line-content"; | |
if (this.element.decorationsElement) { | |
this.element.removeChild(this.element.decorationsElement); | |
delete this.element.decorationsElement; | |
} | |
this._chunkedPanel.endDomUpdates(); | |
}, | |
get decorated() | |
{ | |
return this.element.className !== "webkit-line-content" || !!(this.element.decorationsElement && this.element.decorationsElement.firstChild); | |
}, | |
get startLine() | |
{ | |
return this._startLine; | |
}, | |
set startLine(startLine) | |
{ | |
this._startLine = startLine; | |
this.element.lineNumber = startLine; | |
if (this._expandedLineRows) { | |
for (var i = 0; i < this._expandedLineRows.length; ++i) | |
this._expandedLineRows[i].lineNumber = startLine + i; | |
} | |
}, | |
get expanded() | |
{ | |
return this._expanded; | |
}, | |
set expanded(expanded) | |
{ | |
if (this._expanded === expanded) | |
return; | |
this._expanded = expanded; | |
if (this.linesCount === 1) { | |
if (expanded) | |
this._chunkedPanel._paintLine(this.element); | |
return; | |
} | |
this._chunkedPanel.beginDomUpdates(); | |
if (expanded) { | |
this._expandedLineRows = []; | |
var parentElement = this.element.parentElement; | |
for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) { | |
var lineRow = this._createRow(i); | |
this._updateElementReadOnlyState(lineRow); | |
parentElement.insertBefore(lineRow, this.element); | |
this._expandedLineRows.push(lineRow); | |
} | |
parentElement.removeChild(this.element); | |
this._chunkedPanel._paintLines(this.startLine, this.startLine + this.linesCount); | |
} else { | |
var elementInserted = false; | |
for (var i = 0; i < this._expandedLineRows.length; ++i) { | |
var lineRow = this._expandedLineRows[i]; | |
var parentElement = lineRow.parentElement; | |
if (parentElement) { | |
if (!elementInserted) { | |
elementInserted = true; | |
parentElement.insertBefore(this.element, lineRow); | |
} | |
parentElement.removeChild(lineRow); | |
} | |
this._chunkedPanel._releaseLinesHighlight(lineRow); | |
} | |
delete this._expandedLineRows; | |
} | |
this._chunkedPanel.endDomUpdates(); | |
}, | |
set readOnly(readOnly) | |
{ | |
if (this._readOnly === readOnly) | |
return; | |
this._readOnly = readOnly; | |
this._updateElementReadOnlyState(this.element); | |
if (this._expandedLineRows) { | |
for (var i = 0; i < this._expandedLineRows.length; ++i) | |
this._updateElementReadOnlyState(this._expandedLineRows[i]); | |
} | |
}, | |
get readOnly() | |
{ | |
return this._readOnly; | |
}, | |
_updateElementReadOnlyState: function(element) | |
{ | |
if (this._readOnly) | |
element.addStyleClass("text-editor-read-only"); | |
else | |
element.removeStyleClass("text-editor-read-only"); | |
}, | |
get height() | |
{ | |
if (!this._expandedLineRows) | |
return this._chunkedPanel._totalHeight(this.element); | |
return this._chunkedPanel._totalHeight(this._expandedLineRows[0], this._expandedLineRows[this._expandedLineRows.length - 1]); | |
}, | |
get offsetTop() | |
{ | |
return (this._expandedLineRows && this._expandedLineRows.length) ? this._expandedLineRows[0].offsetTop : this.element.offsetTop; | |
}, | |
_createRow: function(lineNumber) | |
{ | |
var lineRow = this._chunkedPanel._cachedRows.pop() || document.createElement("div"); | |
lineRow.lineNumber = lineNumber; | |
lineRow.className = "webkit-line-content"; | |
lineRow.textContent = this._textModel.line(lineNumber); | |
if (!lineRow.textContent) | |
lineRow.appendChild(document.createElement("br")); | |
return lineRow; | |
}, | |
getExpandedLineRow: function(lineNumber) | |
{ | |
if (!this._expanded || lineNumber < this.startLine || lineNumber >= this.startLine + this.linesCount) | |
return null; | |
if (!this._expandedLineRows) | |
return this.element; | |
return this._expandedLineRows[lineNumber - this.startLine]; | |
}, | |
updateCollapsedLineRow: function() | |
{ | |
if (this.linesCount === 1 && this._expanded) | |
return; | |
var lines = []; | |
for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) | |
lines.push(this._textModel.line(i)); | |
this.element.removeChildren(); | |
this.element.textContent = lines.join("\n"); | |
if (!lines[lines.length - 1]) | |
this.element.appendChild(document.createElement("br")); | |
} | |
} | |
WebInspector.SourceFrame = function(contentProvider) | |
{ | |
WebInspector.View.call(this); | |
this.element.addStyleClass("script-view"); | |
this._url = contentProvider.contentURL(); | |
this._contentProvider = contentProvider; | |
var textEditorDelegate = new WebInspector.TextEditorDelegateForSourceFrame(this); | |
if (WebInspector.experimentsSettings.codemirror.isEnabled()) { | |
importScript("CodeMirrorTextEditor.js"); | |
this._textEditor = new WebInspector.CodeMirrorTextEditor(this._url, textEditorDelegate); | |
} else | |
this._textEditor = new WebInspector.DefaultTextEditor(this._url, textEditorDelegate); | |
this._currentSearchResultIndex = -1; | |
this._searchResults = []; | |
this._messages = []; | |
this._rowMessages = {}; | |
this._messageBubbles = {}; | |
this._textEditor.setReadOnly(!this.canEditSource()); | |
this._shortcuts = {}; | |
this._shortcuts[WebInspector.KeyboardShortcut.makeKey("s", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta)] = this._commitEditing.bind(this); | |
this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); | |
} | |
WebInspector.SourceFrame.createSearchRegex = function(query, modifiers) | |
{ | |
var regex; | |
modifiers = modifiers || ""; | |
try { | |
if (/^\/.*\/$/.test(query)) | |
regex = new RegExp(query.substring(1, query.length - 1), modifiers); | |
} catch (e) { | |
} | |
if (!regex) | |
regex = createPlainTextSearchRegex(query, "i" + modifiers); | |
return regex; | |
} | |
WebInspector.SourceFrame.Events = { | |
ScrollChanged: "ScrollChanged", | |
SelectionChanged: "SelectionChanged" | |
} | |
WebInspector.SourceFrame.prototype = { | |
wasShown: function() | |
{ | |
this._ensureContentLoaded(); | |
this._textEditor.show(this.element); | |
this._wasShownOrLoaded(); | |
}, | |
willHide: function() | |
{ | |
WebInspector.View.prototype.willHide.call(this); | |
this._clearLineHighlight(); | |
this._clearLineToReveal(); | |
}, | |
statusBarItems: function() | |
{ | |
return []; | |
}, | |
defaultFocusedElement: function() | |
{ | |
return this._textEditor.defaultFocusedElement(); | |
}, | |
get loaded() | |
{ | |
return this._loaded; | |
}, | |
hasContent: function() | |
{ | |
return true; | |
}, | |
get textEditor() | |
{ | |
return this._textEditor; | |
}, | |
_ensureContentLoaded: function() | |
{ | |
if (!this._contentRequested) { | |
this._contentRequested = true; | |
this._contentProvider.requestContent(this.setContent.bind(this)); | |
} | |
}, | |
addMessage: function(msg) | |
{ | |
this._messages.push(msg); | |
if (this.loaded) | |
this.addMessageToSource(msg.line - 1, msg); | |
}, | |
clearMessages: function() | |
{ | |
for (var line in this._messageBubbles) { | |
var bubble = this._messageBubbles[line]; | |
bubble.parentNode.removeChild(bubble); | |
} | |
this._messages = []; | |
this._rowMessages = {}; | |
this._messageBubbles = {}; | |
this._textEditor.doResize(); | |
}, | |
canHighlightLine: function(line) | |
{ | |
return true; | |
}, | |
highlightLine: function(line) | |
{ | |
this._clearLineToReveal(); | |
this._clearLineToScrollTo(); | |
this._lineToHighlight = line; | |
this._innerHighlightLineIfNeeded(); | |
this._textEditor.setSelection(WebInspector.TextRange.createFromLocation(line, 0)); | |
}, | |
_innerHighlightLineIfNeeded: function() | |
{ | |
if (typeof this._lineToHighlight === "number") { | |
if (this.loaded && this._textEditor.isShowing()) { | |
this._textEditor.highlightLine(this._lineToHighlight); | |
delete this._lineToHighlight | |
} | |
} | |
}, | |
_clearLineHighlight: function() | |
{ | |
this._textEditor.clearLineHighlight(); | |
delete this._lineToHighlight; | |
}, | |
revealLine: function(line) | |
{ | |
this._clearLineHighlight(); | |
this._clearLineToScrollTo(); | |
this._lineToReveal = line; | |
this._innerRevealLineIfNeeded(); | |
}, | |
_innerRevealLineIfNeeded: function() | |
{ | |
if (typeof this._lineToReveal === "number") { | |
if (this.loaded && this._textEditor.isShowing()) { | |
this._textEditor.revealLine(this._lineToReveal); | |
delete this._lineToReveal | |
} | |
} | |
}, | |
_clearLineToReveal: function() | |
{ | |
delete this._lineToReveal; | |
}, | |
scrollToLine: function(line) | |
{ | |
this._clearLineHighlight(); | |
this._clearLineToReveal(); | |
this._lineToScrollTo = line; | |
this._innerScrollToLineIfNeeded(); | |
}, | |
_innerScrollToLineIfNeeded: function() | |
{ | |
if (typeof this._lineToScrollTo === "number") { | |
if (this.loaded && this._textEditor.isShowing()) { | |
this._textEditor.scrollToLine(this._lineToScrollTo); | |
delete this._lineToScrollTo | |
} | |
} | |
}, | |
_clearLineToScrollTo: function() | |
{ | |
delete this._lineToScrollTo; | |
}, | |
setSelection: function(textRange) | |
{ | |
this._selectionToSet = textRange; | |
this._innerSetSelectionIfNeeded(); | |
}, | |
_innerSetSelectionIfNeeded: function() | |
{ | |
if (this._selectionToSet && this.loaded && this._textEditor.isShowing()) { | |
this._textEditor.setSelection(this._selectionToSet); | |
delete this._selectionToSet; | |
} | |
}, | |
_wasShownOrLoaded: function() | |
{ | |
this._innerHighlightLineIfNeeded(); | |
this._innerRevealLineIfNeeded(); | |
this._innerScrollToLineIfNeeded(); | |
this._innerSetSelectionIfNeeded(); | |
}, | |
onTextChanged: function(oldRange, newRange) | |
{ | |
if (!this._isReplacing) | |
WebInspector.searchController.cancelSearch(); | |
this.clearMessages(); | |
}, | |
setContent: function(content, contentEncoded, mimeType) | |
{ | |
this._textEditor.mimeType = mimeType; | |
this._loaded = true; | |
this._textEditor.setText(content || ""); | |
this._textEditor.beginUpdates(); | |
this._setTextEditorDecorations(); | |
this._wasShownOrLoaded(); | |
if (this._delayedFindSearchMatches) { | |
this._delayedFindSearchMatches(); | |
delete this._delayedFindSearchMatches; | |
} | |
this.onTextEditorContentLoaded(); | |
this._textEditor.endUpdates(); | |
}, | |
onTextEditorContentLoaded: function() {}, | |
_setTextEditorDecorations: function() | |
{ | |
this._rowMessages = {}; | |
this._messageBubbles = {}; | |
this._textEditor.beginUpdates(); | |
this._addExistingMessagesToSource(); | |
this._textEditor.doResize(); | |
this._textEditor.endUpdates(); | |
}, | |
performSearch: function(query, callback) | |
{ | |
this.searchCanceled(); | |
function doFindSearchMatches(query) | |
{ | |
this._currentSearchResultIndex = -1; | |
this._searchResults = []; | |
var regex = WebInspector.SourceFrame.createSearchRegex(query); | |
this._searchResults = this._collectRegexMatches(regex); | |
var shiftToIndex = 0; | |
var selection = this._textEditor.lastSelection(); | |
for (var i = 0; selection && i < this._searchResults.length; ++i) { | |
if (this._searchResults[i].compareTo(selection) >= 0) { | |
shiftToIndex = i; | |
break; | |
} | |
} | |
if (shiftToIndex) | |
this._searchResults = this._searchResults.rotate(shiftToIndex); | |
callback(this, this._searchResults.length); | |
} | |
if (this.loaded) | |
doFindSearchMatches.call(this, query); | |
else | |
this._delayedFindSearchMatches = doFindSearchMatches.bind(this, query); | |
this._ensureContentLoaded(); | |
}, | |
searchCanceled: function() | |
{ | |
delete this._delayedFindSearchMatches; | |
if (!this.loaded) | |
return; | |
this._currentSearchResultIndex = -1; | |
this._searchResults = []; | |
this._textEditor.markAndRevealRange(null); | |
}, | |
hasSearchResults: function() | |
{ | |
return this._searchResults.length > 0; | |
}, | |
jumpToFirstSearchResult: function() | |
{ | |
this.jumpToSearchResult(0); | |
}, | |
jumpToLastSearchResult: function() | |
{ | |
this.jumpToSearchResult(this._searchResults.length - 1); | |
}, | |
jumpToNextSearchResult: function() | |
{ | |
this.jumpToSearchResult(this._currentSearchResultIndex + 1); | |
}, | |
jumpToPreviousSearchResult: function() | |
{ | |
this.jumpToSearchResult(this._currentSearchResultIndex - 1); | |
}, | |
showingFirstSearchResult: function() | |
{ | |
return this._searchResults.length && this._currentSearchResultIndex === 0; | |
}, | |
showingLastSearchResult: function() | |
{ | |
return this._searchResults.length && this._currentSearchResultIndex === (this._searchResults.length - 1); | |
}, | |
get currentSearchResultIndex() | |
{ | |
return this._currentSearchResultIndex; | |
}, | |
jumpToSearchResult: function(index) | |
{ | |
if (!this.loaded || !this._searchResults.length) | |
return; | |
this._currentSearchResultIndex = (index + this._searchResults.length) % this._searchResults.length; | |
this._textEditor.markAndRevealRange(this._searchResults[this._currentSearchResultIndex]); | |
}, | |
replaceSearchMatchWith: function(text) | |
{ | |
var range = this._searchResults[this._currentSearchResultIndex]; | |
if (!range) | |
return; | |
this._textEditor.markAndRevealRange(null); | |
this._isReplacing = true; | |
var newRange = this._textEditor.editRange(range, text); | |
delete this._isReplacing; | |
this._textEditor.setSelection(newRange.collapseToEnd()); | |
}, | |
replaceAllWith: function(query, replacement) | |
{ | |
this._textEditor.markAndRevealRange(null); | |
var text = this._textEditor.text(); | |
var range = this._textEditor.range(); | |
text = text.replace(WebInspector.SourceFrame.createSearchRegex(query, "g"), replacement); | |
this._isReplacing = true; | |
this._textEditor.editRange(range, text); | |
delete this._isReplacing; | |
}, | |
_collectRegexMatches: function(regexObject) | |
{ | |
var ranges = []; | |
for (var i = 0; i < this._textEditor.linesCount; ++i) { | |
var line = this._textEditor.line(i); | |
var offset = 0; | |
do { | |
var match = regexObject.exec(line); | |
if (match) { | |
if (match[0].length) | |
ranges.push(new WebInspector.TextRange(i, offset + match.index, i, offset + match.index + match[0].length)); | |
offset += match.index + 1; | |
line = line.substring(match.index + 1); | |
} | |
} while (match && line); | |
} | |
return ranges; | |
}, | |
_addExistingMessagesToSource: function() | |
{ | |
var length = this._messages.length; | |
for (var i = 0; i < length; ++i) | |
this.addMessageToSource(this._messages[i].line - 1, this._messages[i]); | |
}, | |
addMessageToSource: function(lineNumber, msg) | |
{ | |
if (lineNumber >= this._textEditor.linesCount) | |
lineNumber = this._textEditor.linesCount - 1; | |
if (lineNumber < 0) | |
lineNumber = 0; | |
var messageBubbleElement = this._messageBubbles[lineNumber]; | |
if (!messageBubbleElement || messageBubbleElement.nodeType !== Node.ELEMENT_NODE || !messageBubbleElement.hasStyleClass("webkit-html-message-bubble")) { | |
messageBubbleElement = document.createElement("div"); | |
messageBubbleElement.className = "webkit-html-message-bubble"; | |
this._messageBubbles[lineNumber] = messageBubbleElement; | |
this._textEditor.addDecoration(lineNumber, messageBubbleElement); | |
} | |
var rowMessages = this._rowMessages[lineNumber]; | |
if (!rowMessages) { | |
rowMessages = []; | |
this._rowMessages[lineNumber] = rowMessages; | |
} | |
for (var i = 0; i < rowMessages.length; ++i) { | |
if (rowMessages[i].consoleMessage.isEqual(msg)) { | |
rowMessages[i].repeatCount = msg.totalRepeatCount; | |
this._updateMessageRepeatCount(rowMessages[i]); | |
return; | |
} | |
} | |
var rowMessage = { consoleMessage: msg }; | |
rowMessages.push(rowMessage); | |
var imageURL; | |
switch (msg.level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
messageBubbleElement.addStyleClass("webkit-html-error-message"); | |
imageURL = "Images/errorIcon.png"; | |
break; | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
messageBubbleElement.addStyleClass("webkit-html-warning-message"); | |
imageURL = "Images/warningIcon.png"; | |
break; | |
} | |
var messageLineElement = document.createElement("div"); | |
messageLineElement.className = "webkit-html-message-line"; | |
messageBubbleElement.appendChild(messageLineElement); | |
var image = document.createElement("img"); | |
image.src = imageURL; | |
image.className = "webkit-html-message-icon"; | |
messageLineElement.appendChild(image); | |
messageLineElement.appendChild(document.createTextNode(msg.message)); | |
rowMessage.element = messageLineElement; | |
rowMessage.repeatCount = msg.totalRepeatCount; | |
this._updateMessageRepeatCount(rowMessage); | |
}, | |
_updateMessageRepeatCount: function(rowMessage) | |
{ | |
if (rowMessage.repeatCount < 2) | |
return; | |
if (!rowMessage.repeatCountElement) { | |
var repeatCountElement = document.createElement("span"); | |
rowMessage.element.appendChild(repeatCountElement); | |
rowMessage.repeatCountElement = repeatCountElement; | |
} | |
rowMessage.repeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", rowMessage.repeatCount); | |
}, | |
removeMessageFromSource: function(lineNumber, msg) | |
{ | |
if (lineNumber >= this._textEditor.linesCount) | |
lineNumber = this._textEditor.linesCount - 1; | |
if (lineNumber < 0) | |
lineNumber = 0; | |
var rowMessages = this._rowMessages[lineNumber]; | |
for (var i = 0; rowMessages && i < rowMessages.length; ++i) { | |
var rowMessage = rowMessages[i]; | |
if (rowMessage.consoleMessage !== msg) | |
continue; | |
var messageLineElement = rowMessage.element; | |
var messageBubbleElement = messageLineElement.parentElement; | |
messageBubbleElement.removeChild(messageLineElement); | |
rowMessages.remove(rowMessage); | |
if (!rowMessages.length) | |
delete this._rowMessages[lineNumber]; | |
if (!messageBubbleElement.childElementCount) { | |
this._textEditor.removeDecoration(lineNumber, messageBubbleElement); | |
delete this._messageBubbles[lineNumber]; | |
} | |
break; | |
} | |
}, | |
populateLineGutterContextMenu: function(contextMenu, lineNumber) | |
{ | |
}, | |
populateTextAreaContextMenu: function(contextMenu, lineNumber) | |
{ | |
}, | |
inheritScrollPositions: function(sourceFrame) | |
{ | |
this._textEditor.inheritScrollPositions(sourceFrame._textEditor); | |
}, | |
canEditSource: function() | |
{ | |
return false; | |
}, | |
commitEditing: function(text) | |
{ | |
}, | |
selectionChanged: function(textRange) | |
{ | |
this.dispatchEventToListeners(WebInspector.SourceFrame.Events.SelectionChanged, textRange); | |
}, | |
scrollChanged: function(lineNumber) | |
{ | |
this.dispatchEventToListeners(WebInspector.SourceFrame.Events.ScrollChanged, lineNumber); | |
}, | |
_handleKeyDown: function(e) | |
{ | |
var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(e); | |
var handler = this._shortcuts[shortcutKey]; | |
if (handler && handler()) | |
e.consume(true); | |
}, | |
_commitEditing: function() | |
{ | |
if (this._textEditor.readOnly()) | |
return false; | |
var content = this._textEditor.text(); | |
this.commitEditing(content); | |
if (this._url && WebInspector.fileManager.isURLSaved(this._url)) | |
WebInspector.fileManager.save(this._url, content, false); | |
return true; | |
} | |
} | |
WebInspector.SourceFrame.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.TextEditorDelegateForSourceFrame = function(sourceFrame) | |
{ | |
this._sourceFrame = sourceFrame; | |
} | |
WebInspector.TextEditorDelegateForSourceFrame.prototype = { | |
onTextChanged: function(oldRange, newRange) | |
{ | |
this._sourceFrame.onTextChanged(oldRange, newRange); | |
}, | |
selectionChanged: function(textRange) | |
{ | |
this._sourceFrame.selectionChanged(textRange); | |
}, | |
scrollChanged: function(lineNumber) | |
{ | |
this._sourceFrame.scrollChanged(lineNumber); | |
}, | |
populateLineGutterContextMenu: function(contextMenu, lineNumber) | |
{ | |
this._sourceFrame.populateLineGutterContextMenu(contextMenu, lineNumber); | |
}, | |
populateTextAreaContextMenu: function(contextMenu, lineNumber) | |
{ | |
this._sourceFrame.populateTextAreaContextMenu(contextMenu, lineNumber); | |
}, | |
createLink: function(hrefValue, isExternal) | |
{ | |
var targetLocation = WebInspector.ParsedURL.completeURL(this._sourceFrame._url, hrefValue); | |
return WebInspector.linkifyURLAsNode(targetLocation || hrefValue, hrefValue, undefined, isExternal); | |
} | |
} | |
WebInspector.TextEditorDelegateForSourceFrame.prototype.__proto__ = WebInspector.TextEditorDelegate.prototype; | |
WebInspector.ResourceView = function(resource) | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("resourceView.css"); | |
this.element.addStyleClass("resource-view"); | |
this.resource = resource; | |
} | |
WebInspector.ResourceView.prototype = { | |
hasContent: function() | |
{ | |
return false; | |
} | |
} | |
WebInspector.ResourceView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.ResourceView.hasTextContent = function(resource) | |
{ | |
if (resource.type.isTextType()) | |
return true; | |
if (resource.type === WebInspector.resourceTypes.Other) | |
return resource.content && !resource.contentEncoded; | |
return false; | |
} | |
WebInspector.ResourceView.nonSourceViewForResource = function(resource) | |
{ | |
switch (resource.type) { | |
case WebInspector.resourceTypes.Image: | |
return new WebInspector.ImageView(resource); | |
case WebInspector.resourceTypes.Font: | |
return new WebInspector.FontView(resource); | |
default: | |
return new WebInspector.ResourceView(resource); | |
} | |
} | |
WebInspector.ResourceSourceFrame = function(resource) | |
{ | |
this._resource = resource; | |
WebInspector.SourceFrame.call(this, resource); | |
} | |
WebInspector.ResourceSourceFrame.prototype = { | |
get resource() | |
{ | |
return this._resource; | |
}, | |
populateTextAreaContextMenu: function(contextMenu, lineNumber) | |
{ | |
contextMenu.appendApplicableItems(this._resource); | |
if (this._resource.request) | |
contextMenu.appendApplicableItems(this._resource.request); | |
} | |
} | |
WebInspector.ResourceSourceFrame.prototype.__proto__ = WebInspector.SourceFrame.prototype; | |
WebInspector.FontView = function(resource) | |
{ | |
WebInspector.ResourceView.call(this, resource); | |
this.element.addStyleClass("font"); | |
} | |
WebInspector.FontView._fontPreviewLines = [ "ABCDEFGHIJKLM", "NOPQRSTUVWXYZ", "abcdefghijklm", "nopqrstuvwxyz", "1234567890" ]; | |
WebInspector.FontView._fontId = 0; | |
WebInspector.FontView._measureFontSize = 50; | |
WebInspector.FontView.prototype = { | |
hasContent: function() | |
{ | |
return true; | |
}, | |
_createContentIfNeeded: function() | |
{ | |
if (this.fontPreviewElement) | |
return; | |
var uniqueFontName = "WebInspectorFontPreview" + (++WebInspector.FontView._fontId); | |
this.fontStyleElement = document.createElement("style"); | |
this.fontStyleElement.textContent = "@font-face { font-family: \"" + uniqueFontName + "\"; src: url(" + this.resource.url + "); }"; | |
document.head.appendChild(this.fontStyleElement); | |
var fontPreview = document.createElement("div"); | |
for (var i = 0; i < WebInspector.FontView._fontPreviewLines.length; ++i) { | |
if (i > 0) | |
fontPreview.appendChild(document.createElement("br")); | |
fontPreview.appendChild(document.createTextNode(WebInspector.FontView._fontPreviewLines[i])); | |
} | |
this.fontPreviewElement = fontPreview.cloneNode(true); | |
this.fontPreviewElement.style.setProperty("font-family", uniqueFontName); | |
this.fontPreviewElement.style.setProperty("visibility", "hidden"); | |
this._dummyElement = fontPreview; | |
this._dummyElement.style.visibility = "hidden"; | |
this._dummyElement.style.zIndex = "-1"; | |
this._dummyElement.style.display = "inline"; | |
this._dummyElement.style.position = "absolute"; | |
this._dummyElement.style.setProperty("font-family", uniqueFontName); | |
this._dummyElement.style.setProperty("font-size", WebInspector.FontView._measureFontSize + "px"); | |
this.element.appendChild(this.fontPreviewElement); | |
}, | |
wasShown: function() | |
{ | |
this._createContentIfNeeded(); | |
this.updateFontPreviewSize(); | |
}, | |
onResize: function() | |
{ | |
if (this._inResize) | |
return; | |
this._inResize = true; | |
try { | |
this.updateFontPreviewSize(); | |
} finally { | |
delete this._inResize; | |
} | |
}, | |
_measureElement: function() | |
{ | |
this.element.appendChild(this._dummyElement); | |
var result = { width: this._dummyElement.offsetWidth, height: this._dummyElement.offsetHeight }; | |
this.element.removeChild(this._dummyElement); | |
return result; | |
}, | |
updateFontPreviewSize: function() | |
{ | |
if (!this.fontPreviewElement || !this.isShowing()) | |
return; | |
this.fontPreviewElement.style.removeProperty("visibility"); | |
var dimension = this._measureElement(); | |
const height = dimension.height; | |
const width = dimension.width; | |
const containerWidth = this.element.offsetWidth - 50; | |
const containerHeight = this.element.offsetHeight - 30; | |
if (!height || !width || !containerWidth || !containerHeight) { | |
this.fontPreviewElement.style.removeProperty("font-size"); | |
return; | |
} | |
var widthRatio = containerWidth / width; | |
var heightRatio = containerHeight / height; | |
var finalFontSize = Math.floor(WebInspector.FontView._measureFontSize * Math.min(widthRatio, heightRatio)) - 2; | |
this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null); | |
} | |
} | |
WebInspector.FontView.prototype.__proto__ = WebInspector.ResourceView.prototype; | |
WebInspector.ImageView = function(resource) | |
{ | |
WebInspector.ResourceView.call(this, resource); | |
this.element.addStyleClass("image"); | |
} | |
WebInspector.ImageView.prototype = { | |
hasContent: function() | |
{ | |
return true; | |
}, | |
wasShown: function() | |
{ | |
this._createContentIfNeeded(); | |
}, | |
_createContentIfNeeded: function() | |
{ | |
if (this._container) | |
return; | |
var imageContainer = document.createElement("div"); | |
imageContainer.className = "image"; | |
this.element.appendChild(imageContainer); | |
var imagePreviewElement = document.createElement("img"); | |
imagePreviewElement.addStyleClass("resource-image-view"); | |
imageContainer.appendChild(imagePreviewElement); | |
imagePreviewElement.addEventListener("contextmenu", this._contextMenu.bind(this), true); | |
this._container = document.createElement("div"); | |
this._container.className = "info"; | |
this.element.appendChild(this._container); | |
var imageNameElement = document.createElement("h1"); | |
imageNameElement.className = "title"; | |
imageNameElement.textContent = this.resource.displayName; | |
this._container.appendChild(imageNameElement); | |
var infoListElement = document.createElement("dl"); | |
infoListElement.className = "infoList"; | |
this.resource.populateImageSource(imagePreviewElement); | |
function onImageLoad() | |
{ | |
var content = this.resource.content; | |
if (content) | |
var resourceSize = this._base64ToSize(content); | |
else | |
var resourceSize = this.resource.resourceSize; | |
var imageProperties = [ | |
{ name: WebInspector.UIString("Dimensions"), value: WebInspector.UIString("%d × %d", imagePreviewElement.naturalWidth, imagePreviewElement.naturalHeight) }, | |
{ name: WebInspector.UIString("File size"), value: Number.bytesToString(resourceSize) }, | |
{ name: WebInspector.UIString("MIME type"), value: this.resource.mimeType } | |
]; | |
infoListElement.removeChildren(); | |
for (var i = 0; i < imageProperties.length; ++i) { | |
var dt = document.createElement("dt"); | |
dt.textContent = imageProperties[i].name; | |
infoListElement.appendChild(dt); | |
var dd = document.createElement("dd"); | |
dd.textContent = imageProperties[i].value; | |
infoListElement.appendChild(dd); | |
} | |
var dt = document.createElement("dt"); | |
dt.textContent = WebInspector.UIString("URL"); | |
infoListElement.appendChild(dt); | |
var dd = document.createElement("dd"); | |
var externalResource = true; | |
dd.appendChild(WebInspector.linkifyURLAsNode(this.resource.url, undefined, undefined, externalResource)); | |
infoListElement.appendChild(dd); | |
this._container.appendChild(infoListElement); | |
} | |
imagePreviewElement.addEventListener("load", onImageLoad.bind(this), false); | |
}, | |
_base64ToSize: function(content) | |
{ | |
if (!content.length) | |
return 0; | |
var size = (content.length || 0) * 3 / 4; | |
if (content.length > 0 && content[content.length - 1] === "=") | |
size--; | |
if (content.length > 1 && content[content.length - 2] === "=") | |
size--; | |
return size; | |
}, | |
_contextMenu: function(event) | |
{ | |
var contextMenu = new WebInspector.ContextMenu(); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy image URL" : "Copy Image URL"), this._copyImageURL.bind(this)); | |
contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open image in new tab" : "Open Image in New Tab"), this._openInNewTab.bind(this)); | |
contextMenu.show(event); | |
}, | |
_copyImageURL: function(event) | |
{ | |
InspectorFrontendHost.copyText(this.resource.url); | |
}, | |
_openInNewTab: function(event) | |
{ | |
InspectorFrontendHost.openInNewTab(this.resource.url); | |
} | |
} | |
WebInspector.ImageView.prototype.__proto__ = WebInspector.ResourceView.prototype; | |
WebInspector.SplitView = function(sidebarPosition, sidebarWidthSettingName, defaultSidebarWidth) | |
{ | |
WebInspector.View.call(this); | |
this.registerRequiredCSS("splitView.css"); | |
this.element.className = "split-view"; | |
this._leftElement = document.createElement("div"); | |
this._leftElement.className = "split-view-contents"; | |
this.element.appendChild(this._leftElement); | |
this._rightElement = document.createElement("div"); | |
this._rightElement.className = "split-view-contents"; | |
this.element.appendChild(this._rightElement); | |
this.sidebarResizerElement = document.createElement("div"); | |
this.sidebarResizerElement.className = "split-view-resizer"; | |
this.installResizer(this.sidebarResizerElement); | |
this._resizable = true; | |
this.element.appendChild(this.sidebarResizerElement); | |
defaultSidebarWidth = defaultSidebarWidth || 200; | |
this._savedSidebarWidth = defaultSidebarWidth; | |
this._sidebarWidthSettingName = sidebarWidthSettingName; | |
if (this._sidebarWidthSettingName) | |
WebInspector.settings[this._sidebarWidthSettingName] = WebInspector.settings.createSetting(this._sidebarWidthSettingName, undefined); | |
this._minimalSidebarWidth = Preferences.minSidebarWidth; | |
this._minimalMainWidth = 0; | |
this._minimalSidebarWidthPercent = 0; | |
this._minimalMainWidthPercent = 50; | |
this._mainElementHidden = false; | |
this._sidebarElementHidden = false; | |
this._innerSetSidebarPosition(sidebarPosition || WebInspector.SplitView.SidebarPosition.Left); | |
} | |
WebInspector.SplitView.EventTypes = { | |
Resized: "Resized" | |
} | |
WebInspector.SplitView.SidebarPosition = { | |
Left: "Left", | |
Right: "Right" | |
} | |
WebInspector.SplitView.prototype = { | |
get hasLeftSidebar() | |
{ | |
return this._sidebarPosition === WebInspector.SplitView.SidebarPosition.Left; | |
}, | |
get mainElement() | |
{ | |
return this.hasLeftSidebar ? this._rightElement : this._leftElement; | |
}, | |
get sidebarElement() | |
{ | |
return this.hasLeftSidebar ? this._leftElement : this._rightElement; | |
}, | |
get resizable() | |
{ | |
return this._resizable && !this._mainElementHidden && !this._sidebarElementHidden; | |
}, | |
set resizable(resizable) | |
{ | |
if (this._resizable === resizable) | |
return; | |
this._resizable = resizable; | |
this._updateResizer(resizable); | |
}, | |
_updateResizer: function() | |
{ | |
if (this.resizable) | |
this.sidebarResizerElement.removeStyleClass("hidden"); | |
else | |
this.sidebarResizerElement.addStyleClass("hidden"); | |
}, | |
set sidebarPosition(sidebarPosition) | |
{ | |
if (this._sidebarPosition === sidebarPosition) | |
return; | |
this._innerSetSidebarPosition(sidebarPosition); | |
this._restoreSidebarWidth(); | |
}, | |
_innerSetSidebarPosition: function(sidebarPosition) | |
{ | |
this._sidebarPosition = sidebarPosition; | |
this._leftElement.style.left = 0; | |
this._rightElement.style.right = 0; | |
if (this.hasLeftSidebar) { | |
this._leftElement.addStyleClass("split-view-sidebar-left"); | |
this._rightElement.removeStyleClass("split-view-sidebar-right"); | |
this._leftElement.style.removeProperty("right"); | |
this._rightElement.style.removeProperty("width"); | |
this.sidebarResizerElement.style.removeProperty("right"); | |
} else { | |
this._rightElement.addStyleClass("split-view-sidebar-right"); | |
this._leftElement.removeStyleClass("split-view-sidebar-left"); | |
this._leftElement.style.removeProperty("width"); | |
this._rightElement.style.removeProperty("left"); | |
this.sidebarResizerElement.style.removeProperty("left"); | |
} | |
}, | |
set minimalSidebarWidth(width) | |
{ | |
this._minimalSidebarWidth = width; | |
}, | |
set minimalMainWidth(width) | |
{ | |
this._minimalMainWidth = width; | |
}, | |
set minimalSidebarWidthPercent(widthPercent) | |
{ | |
this._minimalSidebarWidthPercent = widthPercent; | |
}, | |
set minimalMainWidthPercent(widthPercent) | |
{ | |
this._minimalMainWidthPercent = widthPercent; | |
}, | |
setMainWidth: function(width) | |
{ | |
this.setSidebarWidth(this._totalWidth - width); | |
}, | |
setSidebarWidth: function(width) | |
{ | |
if (this._sidebarWidth === width) | |
return; | |
this._innerSetSidebarWidth(width); | |
this.saveSidebarWidth(); | |
}, | |
sidebarWidth: function() | |
{ | |
return this._sidebarWidth; | |
}, | |
_innerSetSidebarWidth: function(width) | |
{ | |
if (this.hasLeftSidebar) | |
this._innerSetLeftSidebarWidth(width); | |
else | |
this._innerSetRightSidebarWidth(width); | |
this._sidebarWidth = width; | |
this.doResize(); | |
this.dispatchEventToListeners(WebInspector.SplitView.EventTypes.Resized, this._sidebarWidth); | |
}, | |
_innerSetLeftSidebarWidth: function(width) | |
{ | |
this._leftElement.style.width = width + "px"; | |
this._rightElement.style.left = width + "px"; | |
this.sidebarResizerElement.style.left = (width - 3) + "px"; | |
}, | |
_innerSetRightSidebarWidth: function(width) | |
{ | |
this._rightElement.style.width = width + "px"; | |
this._leftElement.style.right = width + "px"; | |
this.sidebarResizerElement.style.right = (width - 3) + "px"; | |
}, | |
_setSidebarWidthEnsuringConstraints: function(width) | |
{ | |
var minWidth = Math.max(this._minimalSidebarWidth, this._totalWidth * this._minimalSidebarWidthPercent); | |
var maxWidth = Math.min(this._totalWidth - this._minimalMainWidth, this._totalWidth * (100 - this._minimalMainWidthPercent) / 100 ); | |
width = Number.constrain(width, minWidth, maxWidth); | |
this.setSidebarWidth(width); | |
}, | |
hideMainElement: function() | |
{ | |
if (this._mainElementHidden) | |
return; | |
if (this._sidebarElementHidden) | |
this.showSidebarElement(); | |
this.mainElement.addStyleClass("hidden"); | |
this.sidebarElement.addStyleClass("maximized"); | |
if (this.hasLeftSidebar) | |
this.sidebarElement.style.right = "0px"; | |
else | |
this.sidebarElement.style.left = "0px"; | |
this._mainElementHidden = true; | |
this._updateResizer(); | |
this._restoreSidebarWidth(); | |
this.doResize(); | |
}, | |
showMainElement: function() | |
{ | |
if (!this._mainElementHidden) | |
return; | |
this.mainElement.removeStyleClass("hidden"); | |
this.sidebarElement.removeStyleClass("maximized"); | |
if (this.hasLeftSidebar) | |
this.sidebarElement.style.right = ""; | |
else | |
this.sidebarElement.style.left = ""; | |
this._mainElementHidden = false; | |
this._updateResizer(); | |
this._restoreSidebarWidth(); | |
this.doResize(); | |
}, | |
hideSidebarElement: function() | |
{ | |
if (this._sidebarElementHidden) | |
return; | |
if (this._mainElementHidden) | |
this.showMainElement(); | |
this.sidebarElement.addStyleClass("hidden"); | |
this._sidebarElementHidden = true; | |
this._updateResizer(); | |
this._restoreSidebarWidth(); | |
this.doResize(); | |
}, | |
showSidebarElement: function() | |
{ | |
if (!this._sidebarElementHidden) | |
return; | |
this.sidebarElement.removeStyleClass("hidden"); | |
this._sidebarElementHidden = false; | |
this._updateResizer(); | |
this._restoreSidebarWidth(); | |
this.doResize(); | |
}, | |
wasShown: function() | |
{ | |
this._totalWidth = this.element.offsetWidth; | |
this._restoreSidebarWidth(); | |
}, | |
onResize: function() | |
{ | |
this._totalWidth = this.element.offsetWidth; | |
if (this._mainElementHidden) | |
this._sidebarWidth = this._totalWidth; | |
}, | |
_startResizerDragging: function(event) | |
{ | |
if (!this._resizable) | |
return false; | |
var leftWidth = this.hasLeftSidebar ? this._sidebarWidth : this._totalWidth - this._sidebarWidth; | |
this._dragOffset = leftWidth - event.pageX; | |
return true; | |
}, | |
_resizerDragging: function(event) | |
{ | |
var leftWidth = event.pageX + this._dragOffset; | |
var rightWidth = this._totalWidth - leftWidth; | |
var sidebarWidth = this.hasLeftSidebar ? leftWidth : rightWidth; | |
this._setSidebarWidthEnsuringConstraints(sidebarWidth); | |
event.preventDefault(); | |
}, | |
_endResizerDragging: function(event) | |
{ | |
delete this._dragOffset; | |
}, | |
installResizer: function(resizerElement) | |
{ | |
WebInspector.installDragHandle(resizerElement, this._startResizerDragging.bind(this), this._resizerDragging.bind(this), this._endResizerDragging.bind(this), "ew-resize"); | |
}, | |
preferredSidebarWidth: function() | |
{ | |
if (!this._sidebarWidthSettingName) | |
return this._savedSidebarWidth; | |
return WebInspector.settings[this._sidebarWidthSettingName].get() || this._savedSidebarWidth; | |
}, | |
_restoreSidebarWidth: function() | |
{ | |
if (this._mainElementHidden) { | |
this.sidebarElement.style.width = ""; | |
this._sidebarWidth = this._totalWidth; | |
return; | |
} | |
if (this._sidebarElementHidden) { | |
this._innerSetSidebarWidth(0); | |
return; | |
} | |
this._setSidebarWidthEnsuringConstraints(this.preferredSidebarWidth()); | |
}, | |
saveSidebarWidth: function() | |
{ | |
this._savedSidebarWidth = this._sidebarWidth; | |
if (!this._sidebarWidthSettingName) | |
return; | |
WebInspector.settings[this._sidebarWidthSettingName].set(this._sidebarWidth); | |
}, | |
elementsToRestoreScrollPositionsFor: function() | |
{ | |
return [ this.mainElement, this.sidebarElement ]; | |
} | |
} | |
WebInspector.SplitView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.ConsolePanel = function() | |
{ | |
WebInspector.Panel.call(this, "console"); | |
WebInspector.consoleView.addEventListener(WebInspector.ConsoleView.Events.EntryAdded, this._consoleMessageAdded, this); | |
WebInspector.consoleView.addEventListener(WebInspector.ConsoleView.Events.ConsoleCleared, this._consoleCleared, this); | |
this._view = WebInspector.consoleView; | |
} | |
WebInspector.ConsolePanel.prototype = { | |
get statusBarItems() | |
{ | |
return this._view.statusBarItems; | |
}, | |
wasShown: function() | |
{ | |
WebInspector.Panel.prototype.wasShown.call(this); | |
if (WebInspector.drawer.visible) { | |
WebInspector.drawer.hide(WebInspector.Drawer.AnimationType.Immediately); | |
this._drawerWasVisible = true; | |
} | |
this._view.show(this.element); | |
}, | |
willHide: function() | |
{ | |
if (this._drawerWasVisible) { | |
WebInspector.drawer.show(this._view, WebInspector.Drawer.AnimationType.Immediately); | |
delete this._drawerWasVisible; | |
} | |
WebInspector.Panel.prototype.willHide.call(this); | |
}, | |
searchCanceled: function() | |
{ | |
this._clearCurrentSearchResultHighlight(); | |
delete this._searchResults; | |
delete this._searchRegex; | |
}, | |
performSearch: function(query) | |
{ | |
WebInspector.searchController.updateSearchMatchesCount(0, this); | |
this.searchCanceled(); | |
this._searchRegex = createPlainTextSearchRegex(query, "gi"); | |
this._searchResults = []; | |
var messages = WebInspector.consoleView.messages; | |
for (var i = 0; i < messages.length; i++) { | |
if (messages[i].matchesRegex(this._searchRegex)) { | |
this._searchResults.push(messages[i]); | |
this._searchRegex.lastIndex = 0; | |
} | |
} | |
WebInspector.searchController.updateSearchMatchesCount(this._searchResults.length, this); | |
this._currentSearchResultIndex = -1; | |
if (this._searchResults.length) | |
this._jumpToSearchResult(0); | |
}, | |
jumpToNextSearchResult: function() | |
{ | |
if (!this._searchResults || !this._searchResults.length) | |
return; | |
this._jumpToSearchResult((this._currentSearchResultIndex + 1) % this._searchResults.length); | |
}, | |
jumpToPreviousSearchResult: function() | |
{ | |
if (!this._searchResults || !this._searchResults.length) | |
return; | |
var index = this._currentSearchResultIndex - 1; | |
if (index === -1) | |
index = this._searchResults.length - 1; | |
this._jumpToSearchResult(index); | |
return true; | |
}, | |
_clearCurrentSearchResultHighlight: function() | |
{ | |
if (!this._searchResults) | |
return; | |
var highlightedMessage = this._searchResults[this._currentSearchResultIndex]; | |
if (highlightedMessage) | |
highlightedMessage.clearHighlight(); | |
this._currentSearchResultIndex = -1; | |
}, | |
_jumpToSearchResult: function(index) | |
{ | |
this._clearCurrentSearchResultHighlight(); | |
this._currentSearchResultIndex = index; | |
WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this); | |
this._searchResults[index].highlightSearchResults(this._searchRegex); | |
}, | |
_consoleMessageAdded: function(event) | |
{ | |
if (!this._searchRegex || !this.isShowing()) | |
return; | |
var message = event.data; | |
this._searchRegex.lastIndex = 0; | |
if (message.matchesRegex(this._searchRegex)) { | |
this._searchResults.push(message); | |
WebInspector.searchController.updateSearchMatchesCount(this._searchResults.length, this); | |
} | |
}, | |
_consoleCleared: function() | |
{ | |
if (!this._searchResults) | |
return; | |
this._clearCurrentSearchResultHighlight(); | |
this._searchResults.length = 0; | |
if (this.isShowing()) | |
WebInspector.searchController.updateSearchMatchesCount(0, this); | |
} | |
} | |
WebInspector.ConsolePanel.prototype.__proto__ = WebInspector.Panel.prototype; | |
function defineCommonExtensionSymbols(apiPrivate) | |
{ | |
if (!apiPrivate.audits) | |
apiPrivate.audits = {}; | |
apiPrivate.audits.Severity = { | |
Info: "info", | |
Warning: "warning", | |
Severe: "severe" | |
}; | |
if (!apiPrivate.console) | |
apiPrivate.console = {}; | |
apiPrivate.console.Severity = { | |
Tip: "tip", | |
Debug: "debug", | |
Log: "log", | |
Warning: "warning", | |
Error: "error" | |
}; | |
if (!apiPrivate.panels) | |
apiPrivate.panels = {}; | |
apiPrivate.panels.SearchAction = { | |
CancelSearch: "cancelSearch", | |
PerformSearch: "performSearch", | |
NextSearchResult: "nextSearchResult", | |
PreviousSearchResult: "previousSearchResult" | |
}; | |
apiPrivate.Events = { | |
AuditStarted: "audit-started-", | |
ButtonClicked: "button-clicked-", | |
ConsoleMessageAdded: "console-message-added", | |
ElementsPanelObjectSelected: "panel-objectSelected-elements", | |
NetworkRequestFinished: "network-request-finished", | |
Reset: "reset", | |
OpenResource: "open-resource", | |
PanelSearch: "panel-search-", | |
Reload: "Reload", | |
ResourceAdded: "resource-added", | |
ResourceContentCommitted: "resource-content-committed", | |
TimelineEventRecorded: "timeline-event-recorded", | |
ViewShown: "view-shown-", | |
ViewHidden: "view-hidden-" | |
}; | |
apiPrivate.Commands = { | |
AddAuditCategory: "addAuditCategory", | |
AddAuditResult: "addAuditResult", | |
AddConsoleMessage: "addConsoleMessage", | |
AddRequestHeaders: "addRequestHeaders", | |
CreatePanel: "createPanel", | |
CreateSidebarPane: "createSidebarPane", | |
CreateStatusBarButton: "createStatusBarButton", | |
EvaluateOnInspectedPage: "evaluateOnInspectedPage", | |
GetConsoleMessages: "getConsoleMessages", | |
GetHAR: "getHAR", | |
GetPageResources: "getPageResources", | |
GetRequestContent: "getRequestContent", | |
GetResourceContent: "getResourceContent", | |
Subscribe: "subscribe", | |
SetOpenResourceHandler: "setOpenResourceHandler", | |
SetResourceContent: "setResourceContent", | |
SetSidebarContent: "setSidebarContent", | |
SetSidebarHeight: "setSidebarHeight", | |
SetSidebarPage: "setSidebarPage", | |
ShowPanel: "showPanel", | |
StopAuditCategoryRun: "stopAuditCategoryRun", | |
Unsubscribe: "unsubscribe", | |
UpdateAuditProgress: "updateAuditProgress", | |
UpdateButton: "updateButton", | |
InspectedURLChanged: "inspectedURLChanged" | |
}; | |
} | |
function injectedExtensionAPI(injectedScriptId) | |
{ | |
var apiPrivate = {}; | |
defineCommonExtensionSymbols(apiPrivate); | |
var commands = apiPrivate.Commands; | |
var events = apiPrivate.Events; | |
var userAction = false; | |
function EventSinkImpl(type, customDispatch) | |
{ | |
this._type = type; | |
this._listeners = []; | |
this._customDispatch = customDispatch; | |
} | |
EventSinkImpl.prototype = { | |
addListener: function(callback) | |
{ | |
if (typeof callback !== "function") | |
throw "addListener: callback is not a function"; | |
if (this._listeners.length === 0) | |
extensionServer.sendRequest({ command: commands.Subscribe, type: this._type }); | |
this._listeners.push(callback); | |
extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this)); | |
}, | |
removeListener: function(callback) | |
{ | |
var listeners = this._listeners; | |
for (var i = 0; i < listeners.length; ++i) { | |
if (listeners[i] === callback) { | |
listeners.splice(i, 1); | |
break; | |
} | |
} | |
if (this._listeners.length === 0) | |
extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type }); | |
}, | |
_fire: function() | |
{ | |
var listeners = this._listeners.slice(); | |
for (var i = 0; i < listeners.length; ++i) | |
listeners[i].apply(null, arguments); | |
}, | |
_dispatch: function(request) | |
{ | |
if (this._customDispatch) | |
this._customDispatch.call(this, request); | |
else | |
this._fire.apply(this, request.arguments); | |
} | |
} | |
function InspectorExtensionAPI() | |
{ | |
this.audits = new Audits(); | |
this.inspectedWindow = new InspectedWindow(); | |
this.panels = new Panels(); | |
this.network = new Network(); | |
defineDeprecatedProperty(this, "webInspector", "resources", "network"); | |
this.timeline = new Timeline(); | |
this.console = new ConsoleAPI(); | |
this.onReset = new EventSink(events.Reset); | |
} | |
InspectorExtensionAPI.prototype = { | |
log: function(message) | |
{ | |
extensionServer.sendRequest({ command: commands.Log, message: message }); | |
} | |
} | |
function ConsoleAPI() | |
{ | |
this.onMessageAdded = new EventSink(events.ConsoleMessageAdded); | |
} | |
ConsoleAPI.prototype = { | |
getMessages: function(callback) | |
{ | |
extensionServer.sendRequest({ command: commands.GetConsoleMessages }, callback); | |
}, | |
addMessage: function(severity, text, url, line) | |
{ | |
extensionServer.sendRequest({ command: commands.AddConsoleMessage, severity: severity, text: text, url: url, line: line }); | |
}, | |
get Severity() | |
{ | |
return apiPrivate.console.Severity; | |
} | |
} | |
function Network() | |
{ | |
function dispatchRequestEvent(message) | |
{ | |
var request = message.arguments[1]; | |
request.__proto__ = new Request(message.arguments[0]); | |
this._fire(request); | |
} | |
this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent); | |
defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished"); | |
this.onNavigated = new EventSink(events.InspectedURLChanged); | |
} | |
Network.prototype = { | |
getHAR: function(callback) | |
{ | |
function callbackWrapper(result) | |
{ | |
var entries = (result && result.entries) || []; | |
for (var i = 0; i < entries.length; ++i) { | |
entries[i].__proto__ = new Request(entries[i]._requestId); | |
delete entries[i]._requestId; | |
} | |
callback(result); | |
} | |
return extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper); | |
}, | |
addRequestHeaders: function(headers) | |
{ | |
return extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname }); | |
} | |
} | |
function RequestImpl(id) | |
{ | |
this._id = id; | |
} | |
RequestImpl.prototype = { | |
getContent: function(callback) | |
{ | |
function callbackWrapper(response) | |
{ | |
callback(response.content, response.encoding); | |
} | |
extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper); | |
} | |
} | |
function Panels() | |
{ | |
var panels = { | |
elements: new ElementsPanel() | |
}; | |
function panelGetter(name) | |
{ | |
return panels[name]; | |
} | |
for (var panel in panels) | |
this.__defineGetter__(panel, panelGetter.bind(null, panel)); | |
} | |
Panels.prototype = { | |
create: function(title, icon, page, callback) | |
{ | |
var id = "extension-panel-" + extensionServer.nextObjectId(); | |
var request = { | |
command: commands.CreatePanel, | |
id: id, | |
title: title, | |
icon: icon, | |
page: page | |
}; | |
extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id))); | |
}, | |
setOpenResourceHandler: function(callback) | |
{ | |
var hadHandler = extensionServer.hasHandler(events.OpenResource); | |
if (!callback) | |
extensionServer.unregisterHandler(events.OpenResource); | |
else { | |
function callbackWrapper(message) | |
{ | |
userAction = true; | |
try { | |
callback.call(null, new Resource(message.resource), message.lineNumber); | |
} finally { | |
userAction = false; | |
} | |
} | |
extensionServer.registerHandler(events.OpenResource, callbackWrapper); | |
} | |
if (hadHandler === !callback) | |
extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback }); | |
}, | |
get SearchAction() | |
{ | |
return apiPrivate.panels.SearchAction; | |
} | |
} | |
function ExtensionViewImpl(id) | |
{ | |
this._id = id; | |
function dispatchShowEvent(message) | |
{ | |
var frameIndex = message.arguments[0]; | |
this._fire(window.parent.frames[frameIndex]); | |
} | |
this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent); | |
this.onHidden = new EventSink(events.ViewHidden + id); | |
} | |
function PanelWithSidebarImpl(id) | |
{ | |
this._id = id; | |
} | |
PanelWithSidebarImpl.prototype = { | |
createSidebarPane: function(title, callback) | |
{ | |
var id = "extension-sidebar-" + extensionServer.nextObjectId(); | |
var request = { | |
command: commands.CreateSidebarPane, | |
panel: this._id, | |
id: id, | |
title: title | |
}; | |
function callbackWrapper() | |
{ | |
callback(new ExtensionSidebarPane(id)); | |
} | |
extensionServer.sendRequest(request, callback && callbackWrapper); | |
} | |
} | |
PanelWithSidebarImpl.prototype.__proto__ = ExtensionViewImpl.prototype; | |
function ElementsPanel() | |
{ | |
var id = "elements"; | |
PanelWithSidebar.call(this, id); | |
this.onSelectionChanged = new EventSink(events.ElementsPanelObjectSelected); | |
} | |
function ExtensionPanelImpl(id) | |
{ | |
ExtensionViewImpl.call(this, id); | |
this.onSearch = new EventSink(events.PanelSearch + id); | |
} | |
ExtensionPanelImpl.prototype = { | |
createStatusBarButton: function(iconPath, tooltipText, disabled) | |
{ | |
var id = "button-" + extensionServer.nextObjectId(); | |
var request = { | |
command: commands.CreateStatusBarButton, | |
panel: this._id, | |
id: id, | |
icon: iconPath, | |
tooltip: tooltipText, | |
disabled: !!disabled | |
}; | |
extensionServer.sendRequest(request); | |
return new Button(id); | |
}, | |
show: function() | |
{ | |
if (!userAction) | |
return; | |
var request = { | |
command: commands.ShowPanel, | |
id: this._id | |
}; | |
extensionServer.sendRequest(request); | |
} | |
}; | |
ExtensionPanelImpl.prototype.__proto__ = ExtensionViewImpl.prototype; | |
function ExtensionSidebarPaneImpl(id) | |
{ | |
ExtensionViewImpl.call(this, id); | |
} | |
ExtensionSidebarPaneImpl.prototype = { | |
setHeight: function(height) | |
{ | |
extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height }); | |
}, | |
setExpression: function(expression, rootTitle, evaluateOptions) | |
{ | |
var callback = extractCallbackArgument(arguments); | |
var request = { | |
command: commands.SetSidebarContent, | |
id: this._id, | |
expression: expression, | |
rootTitle: rootTitle, | |
evaluateOnPage: true, | |
}; | |
if (typeof evaluateOptions === "object") | |
request.evaluateOptions = evaluateOptions; | |
extensionServer.sendRequest(request, callback); | |
}, | |
setObject: function(jsonObject, rootTitle, callback) | |
{ | |
extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback); | |
}, | |
setPage: function(page) | |
{ | |
extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page }); | |
} | |
} | |
function ButtonImpl(id) | |
{ | |
this._id = id; | |
this.onClicked = new EventSink(events.ButtonClicked + id); | |
} | |
ButtonImpl.prototype = { | |
update: function(iconPath, tooltipText, disabled) | |
{ | |
var request = { | |
command: commands.UpdateButton, | |
id: this._id, | |
icon: iconPath, | |
tooltip: tooltipText, | |
disabled: !!disabled | |
}; | |
extensionServer.sendRequest(request); | |
} | |
}; | |
function Audits() | |
{ | |
} | |
Audits.prototype = { | |
addCategory: function(displayName, resultCount) | |
{ | |
var id = "extension-audit-category-" + extensionServer.nextObjectId(); | |
if (typeof resultCount !== "undefined") | |
console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead."); | |
extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount }); | |
return new AuditCategory(id); | |
} | |
} | |
function AuditCategoryImpl(id) | |
{ | |
function dispatchAuditEvent(request) | |
{ | |
var auditResult = new AuditResult(request.arguments[0]); | |
try { | |
this._fire(auditResult); | |
} catch (e) { | |
console.error("Uncaught exception in extension audit event handler: " + e); | |
auditResult.done(); | |
} | |
} | |
this._id = id; | |
this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent); | |
} | |
function AuditResultImpl(id) | |
{ | |
this._id = id; | |
this.createURL = this._nodeFactory.bind(null, "url"); | |
this.createSnippet = this._nodeFactory.bind(null, "snippet"); | |
this.createText = this._nodeFactory.bind(null, "text"); | |
this.createObject = this._nodeFactory.bind(null, "object"); | |
this.createNode = this._nodeFactory.bind(null, "node"); | |
} | |
AuditResultImpl.prototype = { | |
addResult: function(displayName, description, severity, details) | |
{ | |
if (details && !(details instanceof AuditResultNode)) | |
details = new AuditResultNode(details instanceof Array ? details : [details]); | |
var request = { | |
command: commands.AddAuditResult, | |
resultId: this._id, | |
displayName: displayName, | |
description: description, | |
severity: severity, | |
details: details | |
}; | |
extensionServer.sendRequest(request); | |
}, | |
createResult: function() | |
{ | |
return new AuditResultNode(Array.prototype.slice.call(arguments)); | |
}, | |
updateProgress: function(worked, totalWork) | |
{ | |
extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork }); | |
}, | |
done: function() | |
{ | |
extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id }); | |
}, | |
get Severity() | |
{ | |
return apiPrivate.audits.Severity; | |
}, | |
createResourceLink: function(url, lineNumber) | |
{ | |
return { | |
type: "resourceLink", | |
arguments: [url, lineNumber && lineNumber - 1] | |
}; | |
}, | |
_nodeFactory: function(type) | |
{ | |
return { | |
type: type, | |
arguments: Array.prototype.slice.call(arguments, 1) | |
}; | |
} | |
} | |
function AuditResultNode(contents) | |
{ | |
this.contents = contents; | |
this.children = []; | |
this.expanded = false; | |
} | |
AuditResultNode.prototype = { | |
addChild: function() | |
{ | |
var node = new AuditResultNode(Array.prototype.slice.call(arguments)); | |
this.children.push(node); | |
return node; | |
} | |
}; | |
function InspectedWindow() | |
{ | |
function dispatchResourceEvent(message) | |
{ | |
this._fire(new Resource(message.arguments[0])); | |
} | |
function dispatchResourceContentEvent(message) | |
{ | |
this._fire(new Resource(message.arguments[0]), message.arguments[1]); | |
} | |
this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent); | |
this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent); | |
} | |
InspectedWindow.prototype = { | |
reload: function(optionsOrUserAgent) | |
{ | |
var options = null; | |
if (typeof optionsOrUserAgent === "object") | |
options = optionsOrUserAgent; | |
else if (typeof optionsOrUserAgent === "string") { | |
options = { userAgent: optionsOrUserAgent }; | |
console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " + | |
"Use inspectedWindow.reload({ userAgent: value}) instead."); | |
} | |
return extensionServer.sendRequest({ command: commands.Reload, options: options }); | |
}, | |
eval: function(expression, evaluateOptions) | |
{ | |
var callback = extractCallbackArgument(arguments); | |
function callbackWrapper(result) | |
{ | |
callback(result.value, result.isException); | |
} | |
var request = { | |
command: commands.EvaluateOnInspectedPage, | |
expression: expression | |
}; | |
if (typeof evaluateOptions === "object") | |
request.evaluateOptions = evaluateOptions; | |
return extensionServer.sendRequest(request, callback && callbackWrapper); | |
}, | |
getResources: function(callback) | |
{ | |
function wrapResource(resourceData) | |
{ | |
return new Resource(resourceData); | |
} | |
function callbackWrapper(resources) | |
{ | |
callback(resources.map(wrapResource)); | |
} | |
return extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper); | |
} | |
} | |
function ResourceImpl(resourceData) | |
{ | |
this._url = resourceData.url | |
this._type = resourceData.type; | |
} | |
ResourceImpl.prototype = { | |
get url() | |
{ | |
return this._url; | |
}, | |
get type() | |
{ | |
return this._type; | |
}, | |
getContent: function(callback) | |
{ | |
function callbackWrapper(response) | |
{ | |
callback(response.content, response.encoding); | |
} | |
return extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper); | |
}, | |
setContent: function(content, commit, callback) | |
{ | |
return extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback); | |
} | |
} | |
function TimelineImpl() | |
{ | |
this.onEventRecorded = new EventSink(events.TimelineEventRecorded); | |
} | |
function ExtensionServerClient() | |
{ | |
this._callbacks = {}; | |
this._handlers = {}; | |
this._lastRequestId = 0; | |
this._lastObjectId = 0; | |
this.registerHandler("callback", this._onCallback.bind(this)); | |
var channel = new MessageChannel(); | |
this._port = channel.port1; | |
this._port.addEventListener("message", this._onMessage.bind(this), false); | |
this._port.start(); | |
window.parent.postMessage("registerExtension", [ channel.port2 ], "*"); | |
} | |
ExtensionServerClient.prototype = { | |
sendRequest: function(message, callback) | |
{ | |
if (typeof callback === "function") | |
message.requestId = this._registerCallback(callback); | |
return this._port.postMessage(message); | |
}, | |
hasHandler: function(command) | |
{ | |
return !!this._handlers[command]; | |
}, | |
registerHandler: function(command, handler) | |
{ | |
this._handlers[command] = handler; | |
}, | |
unregisterHandler: function(command) | |
{ | |
delete this._handlers[command]; | |
}, | |
nextObjectId: function() | |
{ | |
return injectedScriptId + "_" + ++this._lastObjectId; | |
}, | |
_registerCallback: function(callback) | |
{ | |
var id = ++this._lastRequestId; | |
this._callbacks[id] = callback; | |
return id; | |
}, | |
_onCallback: function(request) | |
{ | |
if (request.requestId in this._callbacks) { | |
var callback = this._callbacks[request.requestId]; | |
delete this._callbacks[request.requestId]; | |
callback(request.result); | |
} | |
}, | |
_onMessage: function(event) | |
{ | |
var request = event.data; | |
var handler = this._handlers[request.command]; | |
if (handler) | |
handler.call(this, request); | |
} | |
} | |
function populateInterfaceClass(interface, implementation) | |
{ | |
for (var member in implementation) { | |
if (member.charAt(0) === "_") | |
continue; | |
var descriptor = null; | |
for (var owner = implementation; owner && !descriptor; owner = owner.__proto__) | |
descriptor = Object.getOwnPropertyDescriptor(owner, member); | |
if (!descriptor) | |
continue; | |
if (typeof descriptor.value === "function") | |
interface[member] = descriptor.value.bind(implementation); | |
else if (typeof descriptor.get === "function") | |
interface.__defineGetter__(member, descriptor.get.bind(implementation)); | |
else | |
Object.defineProperty(interface, member, descriptor); | |
} | |
} | |
function declareInterfaceClass(implConstructor) | |
{ | |
return function() | |
{ | |
var impl = { __proto__: implConstructor.prototype }; | |
implConstructor.apply(impl, arguments); | |
populateInterfaceClass(this, impl); | |
} | |
} | |
function defineDeprecatedProperty(object, className, oldName, newName) | |
{ | |
var warningGiven = false; | |
function getter() | |
{ | |
if (!warningGiven) { | |
console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead"); | |
warningGiven = true; | |
} | |
return object[newName]; | |
} | |
object.__defineGetter__(oldName, getter); | |
} | |
function extractCallbackArgument(args) | |
{ | |
var lastArgument = args[args.length - 1]; | |
return typeof lastArgument === "function" ? lastArgument : undefined; | |
} | |
var AuditCategory = declareInterfaceClass(AuditCategoryImpl); | |
var AuditResult = declareInterfaceClass(AuditResultImpl); | |
var Button = declareInterfaceClass(ButtonImpl); | |
var EventSink = declareInterfaceClass(EventSinkImpl); | |
var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl); | |
var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl); | |
var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl); | |
var Request = declareInterfaceClass(RequestImpl); | |
var Resource = declareInterfaceClass(ResourceImpl); | |
var Timeline = declareInterfaceClass(TimelineImpl); | |
var extensionServer = new ExtensionServerClient(); | |
return new InspectorExtensionAPI(); | |
} | |
function buildPlatformExtensionAPI(extensionInfo) | |
{ | |
function platformExtensionAPI(coreAPI) | |
{ | |
window.webInspector = coreAPI; | |
} | |
return platformExtensionAPI.toString(); | |
} | |
function buildExtensionAPIInjectedScript(extensionInfo) | |
{ | |
return "(function(injectedScriptHost, inspectedWindow, injectedScriptId){ " + | |
defineCommonExtensionSymbols.toString() + ";" + | |
injectedExtensionAPI.toString() + ";" + | |
buildPlatformExtensionAPI(extensionInfo) + ";" + | |
"platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" + | |
"return {};" + | |
"})"; | |
} | |
WebInspector.ExtensionAuditCategory = function(extensionOrigin, id, displayName, ruleCount) | |
{ | |
this._extensionOrigin = extensionOrigin; | |
this._id = id; | |
this._displayName = displayName; | |
this._ruleCount = ruleCount; | |
} | |
WebInspector.ExtensionAuditCategory.prototype = { | |
get id() | |
{ | |
return this._id; | |
}, | |
get displayName() | |
{ | |
return this._displayName; | |
}, | |
run: function(requests, ruleResultCallback, categoryDoneCallback, progress) | |
{ | |
var results = new WebInspector.ExtensionAuditCategoryResults(this, ruleResultCallback, categoryDoneCallback, progress); | |
WebInspector.extensionServer.startAuditRun(this, results); | |
} | |
} | |
WebInspector.ExtensionAuditCategoryResults = function(category, ruleResultCallback, categoryDoneCallback, progress) | |
{ | |
this._category = category; | |
this._ruleResultCallback = ruleResultCallback; | |
this._categoryDoneCallback = categoryDoneCallback; | |
this._progress = progress; | |
this._progress.setTotalWork(1); | |
this._expectedResults = category._ruleCount; | |
this._actualResults = 0; | |
this.id = category.id + "-" + ++WebInspector.ExtensionAuditCategoryResults._lastId; | |
} | |
WebInspector.ExtensionAuditCategoryResults.prototype = { | |
done: function() | |
{ | |
WebInspector.extensionServer.stopAuditRun(this); | |
this._progress.done(); | |
this._categoryDoneCallback(); | |
}, | |
addResult: function(displayName, description, severity, details) | |
{ | |
var result = new WebInspector.AuditRuleResult(displayName); | |
result.addChild(description); | |
result.severity = severity; | |
if (details) | |
this._addNode(result, details); | |
this._addResult(result); | |
}, | |
_addNode: function(parent, node) | |
{ | |
var contents = WebInspector.auditFormatters.partiallyApply(WebInspector.ExtensionAuditFormatters, this, node.contents); | |
var addedNode = parent.addChild(contents, node.expanded); | |
if (node.children) { | |
for (var i = 0; i < node.children.length; ++i) | |
this._addNode(addedNode, node.children[i]); | |
} | |
}, | |
_addResult: function(result) | |
{ | |
this._ruleResultCallback(result); | |
++this._actualResults; | |
if (typeof this._expectedResults === "number") { | |
this._progress.setWorked(this._actualResults / this._expectedResults); | |
if (this._actualResults === this._expectedResults) | |
this.done(); | |
} | |
}, | |
updateProgress: function(progress) | |
{ | |
this._progress.setWorked(progress); | |
}, | |
evaluate: function(expression, evaluateOptions, callback) | |
{ | |
function onEvaluate(error, result, wasThrown) | |
{ | |
if (wasThrown) | |
return; | |
var object = WebInspector.RemoteObject.fromPayload(result); | |
callback(object); | |
} | |
WebInspector.extensionServer.evaluate(expression, false, false, evaluateOptions, this._category._extensionOrigin, onEvaluate); | |
} | |
} | |
WebInspector.ExtensionAuditFormatters = { | |
object: function(expression, title, evaluateOptions) | |
{ | |
var parentElement = document.createElement("div"); | |
function onEvaluate(remoteObject) | |
{ | |
var section = new WebInspector.ObjectPropertiesSection(remoteObject, title); | |
section.expanded = true; | |
section.editable = false; | |
parentElement.appendChild(section.element); | |
} | |
this.evaluate(expression, evaluateOptions, onEvaluate); | |
return parentElement; | |
}, | |
node: function(expression, evaluateOptions) | |
{ | |
var parentElement = document.createElement("div"); | |
function onNodeAvailable(nodeId) | |
{ | |
if (!nodeId) | |
return; | |
var treeOutline = new WebInspector.ElementsTreeOutline(false, false, true); | |
treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId); | |
treeOutline.element.addStyleClass("outline-disclosure"); | |
treeOutline.setVisible(true); | |
parentElement.appendChild(treeOutline.element); | |
} | |
function onEvaluate(remoteObject) | |
{ | |
remoteObject.pushNodeToFrontend(onNodeAvailable); | |
} | |
this.evaluate(expression, evaluateOptions, onEvaluate); | |
return parentElement; | |
} | |
} | |
WebInspector.ExtensionAuditCategoryResults._lastId = 0; | |
WebInspector.ExtensionServer = function() | |
{ | |
this._clientObjects = {}; | |
this._handlers = {}; | |
this._subscribers = {}; | |
this._subscriptionStartHandlers = {}; | |
this._subscriptionStopHandlers = {}; | |
this._extraHeaders = {}; | |
this._requests = {}; | |
this._lastRequestId = 0; | |
this._registeredExtensions = {}; | |
this._status = new WebInspector.ExtensionStatus(); | |
var commands = WebInspector.extensionAPI.Commands; | |
this._registerHandler(commands.AddAuditCategory, this._onAddAuditCategory.bind(this)); | |
this._registerHandler(commands.AddAuditResult, this._onAddAuditResult.bind(this)); | |
this._registerHandler(commands.AddConsoleMessage, this._onAddConsoleMessage.bind(this)); | |
this._registerHandler(commands.AddRequestHeaders, this._onAddRequestHeaders.bind(this)); | |
this._registerHandler(commands.CreatePanel, this._onCreatePanel.bind(this)); | |
this._registerHandler(commands.CreateSidebarPane, this._onCreateSidebarPane.bind(this)); | |
this._registerHandler(commands.CreateStatusBarButton, this._onCreateStatusBarButton.bind(this)); | |
this._registerHandler(commands.EvaluateOnInspectedPage, this._onEvaluateOnInspectedPage.bind(this)); | |
this._registerHandler(commands.GetHAR, this._onGetHAR.bind(this)); | |
this._registerHandler(commands.GetConsoleMessages, this._onGetConsoleMessages.bind(this)); | |
this._registerHandler(commands.GetPageResources, this._onGetPageResources.bind(this)); | |
this._registerHandler(commands.GetRequestContent, this._onGetRequestContent.bind(this)); | |
this._registerHandler(commands.GetResourceContent, this._onGetResourceContent.bind(this)); | |
this._registerHandler(commands.Log, this._onLog.bind(this)); | |
this._registerHandler(commands.Reload, this._onReload.bind(this)); | |
this._registerHandler(commands.SetOpenResourceHandler, this._onSetOpenResourceHandler.bind(this)); | |
this._registerHandler(commands.SetResourceContent, this._onSetResourceContent.bind(this)); | |
this._registerHandler(commands.SetSidebarHeight, this._onSetSidebarHeight.bind(this)); | |
this._registerHandler(commands.SetSidebarContent, this._onSetSidebarContent.bind(this)); | |
this._registerHandler(commands.SetSidebarPage, this._onSetSidebarPage.bind(this)); | |
this._registerHandler(commands.ShowPanel, this._onShowPanel.bind(this)); | |
this._registerHandler(commands.StopAuditCategoryRun, this._onStopAuditCategoryRun.bind(this)); | |
this._registerHandler(commands.Subscribe, this._onSubscribe.bind(this)); | |
this._registerHandler(commands.Unsubscribe, this._onUnsubscribe.bind(this)); | |
this._registerHandler(commands.UpdateButton, this._onUpdateButton.bind(this)); | |
this._registerHandler(commands.UpdateAuditProgress, this._onUpdateAuditProgress.bind(this)); | |
window.addEventListener("message", this._onWindowMessage.bind(this), false); | |
} | |
WebInspector.ExtensionServer.prototype = { | |
hasExtensions: function() | |
{ | |
return !!Object.keys(this._registeredExtensions).length; | |
}, | |
notifySearchAction: function(panelId, action, searchString) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.PanelSearch + panelId, action, searchString); | |
}, | |
notifyViewShown: function(identifier, frameIndex) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.ViewShown + identifier, frameIndex); | |
}, | |
notifyViewHidden: function(identifier) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.ViewHidden + identifier); | |
}, | |
notifyButtonClicked: function(identifier) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.ButtonClicked + identifier); | |
}, | |
_inspectedURLChanged: function(event) | |
{ | |
this._requests = {}; | |
var url = event.data; | |
this._postNotification(WebInspector.extensionAPI.Events.InspectedURLChanged, url); | |
}, | |
_mainFrameNavigated: function(event) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.Reset); | |
}, | |
startAuditRun: function(category, auditRun) | |
{ | |
this._clientObjects[auditRun.id] = auditRun; | |
this._postNotification("audit-started-" + category.id, auditRun.id); | |
}, | |
stopAuditRun: function(auditRun) | |
{ | |
delete this._clientObjects[auditRun.id]; | |
}, | |
_postNotification: function(type, vararg) | |
{ | |
var subscribers = this._subscribers[type]; | |
if (!subscribers) | |
return; | |
var message = { | |
command: "notify-" + type, | |
arguments: Array.prototype.slice.call(arguments, 1) | |
}; | |
for (var i = 0; i < subscribers.length; ++i) | |
subscribers[i].postMessage(message); | |
}, | |
_onSubscribe: function(message, port) | |
{ | |
var subscribers = this._subscribers[message.type]; | |
if (subscribers) | |
subscribers.push(port); | |
else { | |
this._subscribers[message.type] = [ port ]; | |
if (this._subscriptionStartHandlers[message.type]) | |
this._subscriptionStartHandlers[message.type](); | |
} | |
}, | |
_onUnsubscribe: function(message, port) | |
{ | |
var subscribers = this._subscribers[message.type]; | |
if (!subscribers) | |
return; | |
subscribers.remove(port); | |
if (!subscribers.length) { | |
delete this._subscribers[message.type]; | |
if (this._subscriptionStopHandlers[message.type]) | |
this._subscriptionStopHandlers[message.type](); | |
} | |
}, | |
_onAddRequestHeaders: function(message) | |
{ | |
var id = message.extensionId; | |
if (typeof id !== "string") | |
return this._status.E_BADARGTYPE("extensionId", typeof id, "string"); | |
var extensionHeaders = this._extraHeaders[id]; | |
if (!extensionHeaders) { | |
extensionHeaders = {}; | |
this._extraHeaders[id] = extensionHeaders; | |
} | |
for (var name in message.headers) | |
extensionHeaders[name] = message.headers[name]; | |
var allHeaders = {}; | |
for (var extension in this._extraHeaders) { | |
var headers = this._extraHeaders[extension]; | |
for (name in headers) { | |
if (typeof headers[name] === "string") | |
allHeaders[name] = headers[name]; | |
} | |
} | |
NetworkAgent.setExtraHTTPHeaders(allHeaders); | |
}, | |
_onCreatePanel: function(message, port) | |
{ | |
var id = message.id; | |
if (id in this._clientObjects || id in WebInspector.panels) | |
return this._status.E_EXISTS(id); | |
var page = this._expandResourcePath(port._extensionOrigin, message.page); | |
var panelDescriptor = new WebInspector.PanelDescriptor(id, message.title, undefined, undefined, new WebInspector.ExtensionPanel(id, page)); | |
panelDescriptor.setIconURL(this._expandResourcePath(port._extensionOrigin, message.icon)); | |
this._clientObjects[id] = panelDescriptor.panel(); | |
WebInspector.inspectorView.addPanel(panelDescriptor); | |
return this._status.OK(); | |
}, | |
_onShowPanel: function(message) | |
{ | |
WebInspector.showPanel(message.id); | |
}, | |
_onCreateStatusBarButton: function(message, port) | |
{ | |
var panel = this._clientObjects[message.panel]; | |
if (!panel || !(panel instanceof WebInspector.ExtensionPanel)) | |
return this._status.E_NOTFOUND(message.panel); | |
var button = new WebInspector.ExtensionButton(message.id, this._expandResourcePath(port._extensionOrigin, message.icon), message.tooltip, message.disabled); | |
this._clientObjects[message.id] = button; | |
panel.addStatusBarItem(button.element); | |
return this._status.OK(); | |
}, | |
_onUpdateButton: function(message, port) | |
{ | |
var button = this._clientObjects[message.id]; | |
if (!button || !(button instanceof WebInspector.ExtensionButton)) | |
return this._status.E_NOTFOUND(message.id); | |
button.update(this._expandResourcePath(port._extensionOrigin, message.icon), message.tooltip, message.disabled); | |
return this._status.OK(); | |
}, | |
_onCreateSidebarPane: function(message) | |
{ | |
var panel = WebInspector.panel(message.panel); | |
if (!panel) | |
return this._status.E_NOTFOUND(message.panel); | |
if (!panel.sidebarElement || !panel.sidebarPanes) | |
return this._status.E_NOTSUPPORTED(); | |
var id = message.id; | |
var sidebar = new WebInspector.ExtensionSidebarPane(message.title, message.id); | |
this._clientObjects[id] = sidebar; | |
panel.sidebarPanes[id] = sidebar; | |
panel.sidebarElement.appendChild(sidebar.element); | |
return this._status.OK(); | |
}, | |
_onSetSidebarHeight: function(message) | |
{ | |
var sidebar = this._clientObjects[message.id]; | |
if (!sidebar) | |
return this._status.E_NOTFOUND(message.id); | |
sidebar.setHeight(message.height); | |
return this._status.OK(); | |
}, | |
_onSetSidebarContent: function(message, port) | |
{ | |
var sidebar = this._clientObjects[message.id]; | |
if (!sidebar) | |
return this._status.E_NOTFOUND(message.id); | |
function callback(error) | |
{ | |
var result = error ? this._status.E_FAILED(error) : this._status.OK(); | |
this._dispatchCallback(message.requestId, port, result); | |
} | |
if (message.evaluateOnPage) | |
return sidebar.setExpression(message.expression, message.rootTitle, message.evaluateOptions, port._extensionOrigin, callback.bind(this)); | |
sidebar.setObject(message.expression, message.rootTitle, callback.bind(this)); | |
}, | |
_onSetSidebarPage: function(message, port) | |
{ | |
var sidebar = this._clientObjects[message.id]; | |
if (!sidebar) | |
return this._status.E_NOTFOUND(message.id); | |
sidebar.setPage(this._expandResourcePath(port._extensionOrigin, message.page)); | |
}, | |
_onSetOpenResourceHandler: function(message, port) | |
{ | |
var name = this._registeredExtensions[port._extensionOrigin].name || ("Extension " + port._extensionOrigin); | |
if (message.handlerPresent) | |
WebInspector.openAnchorLocationRegistry.registerHandler(name, this._handleOpenURL.bind(this, port)); | |
else | |
WebInspector.openAnchorLocationRegistry.unregisterHandler(name); | |
}, | |
_handleOpenURL: function(port, details) | |
{ | |
var url = details.url; | |
var contentProvider = WebInspector.workspace.uiSourceCodeForURL(url) || WebInspector.resourceForURL(url); | |
if (!contentProvider) | |
return false; | |
var lineNumber = details.lineNumber; | |
if (typeof lineNumber === "number") | |
lineNumber += 1; | |
port.postMessage({ | |
command: "open-resource", | |
resource: this._makeResource(contentProvider), | |
lineNumber: lineNumber | |
}); | |
return true; | |
}, | |
_onLog: function(message) | |
{ | |
WebInspector.log(message.message); | |
}, | |
_onReload: function(message) | |
{ | |
var options = (message.options || {}); | |
NetworkAgent.setUserAgentOverride(typeof options.userAgent === "string" ? options.userAgent : ""); | |
var injectedScript; | |
if (options.injectedScript) { | |
injectedScript = "((function(){" + options.injectedScript + "})(),function(){return {}})"; | |
} | |
PageAgent.reload(!!options.ignoreCache, injectedScript); | |
return this._status.OK(); | |
}, | |
_onEvaluateOnInspectedPage: function(message, port) | |
{ | |
function callback(error, resultPayload, wasThrown) | |
{ | |
var result = {}; | |
if (error) { | |
result.isException = true; | |
result.value = error.toString(); | |
} else | |
result.value = resultPayload.value; | |
if (wasThrown) | |
result.isException = true; | |
this._dispatchCallback(message.requestId, port, result); | |
} | |
return this.evaluate(message.expression, true, true, message.evaluateOptions, port._extensionOrigin, callback.bind(this)); | |
}, | |
_onGetConsoleMessages: function() | |
{ | |
return WebInspector.console.messages.map(this._makeConsoleMessage); | |
}, | |
_onAddConsoleMessage: function(message) | |
{ | |
function convertSeverity(level) | |
{ | |
switch (level) { | |
case WebInspector.extensionAPI.console.Severity.Tip: | |
return WebInspector.ConsoleMessage.MessageLevel.Tip; | |
case WebInspector.extensionAPI.console.Severity.Log: | |
return WebInspector.ConsoleMessage.MessageLevel.Log; | |
case WebInspector.extensionAPI.console.Severity.Warning: | |
return WebInspector.ConsoleMessage.MessageLevel.Warning; | |
case WebInspector.extensionAPI.console.Severity.Error: | |
return WebInspector.ConsoleMessage.MessageLevel.Error; | |
case WebInspector.extensionAPI.console.Severity.Debug: | |
return WebInspector.ConsoleMessage.MessageLevel.Debug; | |
} | |
} | |
var level = convertSeverity(message.severity); | |
if (!level) | |
return this._status.E_BADARG("message.severity", message.severity); | |
var consoleMessage = WebInspector.ConsoleMessage.create( | |
WebInspector.ConsoleMessage.MessageSource.JS, | |
level, | |
message.text, | |
WebInspector.ConsoleMessage.MessageType.Log, | |
message.url, | |
message.line); | |
WebInspector.console.addMessage(consoleMessage); | |
}, | |
_makeConsoleMessage: function(message) | |
{ | |
function convertLevel(level) | |
{ | |
if (!level) | |
return; | |
switch (level) { | |
case WebInspector.ConsoleMessage.MessageLevel.Tip: | |
return WebInspector.extensionAPI.console.Severity.Tip; | |
case WebInspector.ConsoleMessage.MessageLevel.Log: | |
return WebInspector.extensionAPI.console.Severity.Log; | |
case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
return WebInspector.extensionAPI.console.Severity.Warning; | |
case WebInspector.ConsoleMessage.MessageLevel.Error: | |
return WebInspector.extensionAPI.console.Severity.Error; | |
case WebInspector.ConsoleMessage.MessageLevel.Debug: | |
return WebInspector.extensionAPI.console.Severity.Debug; | |
default: | |
return WebInspector.extensionAPI.console.Severity.Log; | |
} | |
} | |
var result = { | |
severity: convertLevel(message.level), | |
text: message.text, | |
}; | |
if (message.url) | |
result.url = message.url; | |
if (message.line) | |
result.line = message.line; | |
return result; | |
}, | |
_onGetHAR: function() | |
{ | |
var requests = WebInspector.networkLog.requests; | |
var harLog = (new WebInspector.HARLog(requests)).build(); | |
for (var i = 0; i < harLog.entries.length; ++i) | |
harLog.entries[i]._requestId = this._requestId(requests[i]); | |
return harLog; | |
}, | |
_makeResource: function(contentProvider) | |
{ | |
return { | |
url: contentProvider.contentURL(), | |
type: contentProvider.contentType().name() | |
}; | |
}, | |
_onGetPageResources: function() | |
{ | |
var resources = {}; | |
function pushResourceData(contentProvider) | |
{ | |
if (!resources[contentProvider.contentURL()]) | |
resources[contentProvider.contentURL()] = this._makeResource(contentProvider); | |
} | |
WebInspector.workspace.uiSourceCodes().forEach(pushResourceData.bind(this)); | |
WebInspector.resourceTreeModel.forAllResources(pushResourceData.bind(this)); | |
return Object.values(resources); | |
}, | |
_getResourceContent: function(contentProvider, message, port) | |
{ | |
function onContentAvailable(content, contentEncoded, mimeType) | |
{ | |
var response = { | |
encoding: contentEncoded ? "base64" : "", | |
content: content | |
}; | |
this._dispatchCallback(message.requestId, port, response); | |
} | |
contentProvider.requestContent(onContentAvailable.bind(this)); | |
}, | |
_onGetRequestContent: function(message, port) | |
{ | |
var request = this._requestById(message.id); | |
if (!request) | |
return this._status.E_NOTFOUND(message.id); | |
this._getResourceContent(request, message, port); | |
}, | |
_onGetResourceContent: function(message, port) | |
{ | |
var url = message.url; | |
var contentProvider = WebInspector.workspace.uiSourceCodeForURL(url) || WebInspector.resourceForURL(url); | |
if (!contentProvider) | |
return this._status.E_NOTFOUND(url); | |
this._getResourceContent(contentProvider, message, port); | |
}, | |
_onSetResourceContent: function(message, port) | |
{ | |
function callbackWrapper(error) | |
{ | |
var response = error ? this._status.E_FAILED(error) : this._status.OK(); | |
this._dispatchCallback(message.requestId, port, response); | |
} | |
var url = message.url; | |
var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(url); | |
if (!uiSourceCode) { | |
var resource = WebInspector.resourceTreeModel.resourceForURL(url); | |
if (!resource) | |
return this._status.E_NOTFOUND(url); | |
return this._status.E_NOTSUPPORTED("Resource is not editable") | |
} | |
uiSourceCode.setWorkingCopy(message.content); | |
if (message.commit) | |
uiSourceCode.commitWorkingCopy(callbackWrapper.bind(this)); | |
else | |
callbackWrapper.call(this, null); | |
}, | |
_requestId: function(request) | |
{ | |
if (!request._extensionRequestId) { | |
request._extensionRequestId = ++this._lastRequestId; | |
this._requests[request._extensionRequestId] = request; | |
} | |
return request._extensionRequestId; | |
}, | |
_requestById: function(id) | |
{ | |
return this._requests[id]; | |
}, | |
_onAddAuditCategory: function(message, port) | |
{ | |
var category = new WebInspector.ExtensionAuditCategory(port._extensionOrigin, message.id, message.displayName, message.resultCount); | |
if (WebInspector.panel("audits").getCategory(category.id)) | |
return this._status.E_EXISTS(category.id); | |
this._clientObjects[message.id] = category; | |
WebInspector.panel("audits").addCategory(category); | |
}, | |
_onAddAuditResult: function(message) | |
{ | |
var auditResult = this._clientObjects[message.resultId]; | |
if (!auditResult) | |
return this._status.E_NOTFOUND(message.resultId); | |
try { | |
auditResult.addResult(message.displayName, message.description, message.severity, message.details); | |
} catch (e) { | |
return e; | |
} | |
return this._status.OK(); | |
}, | |
_onUpdateAuditProgress: function(message) | |
{ | |
var auditResult = this._clientObjects[message.resultId]; | |
if (!auditResult) | |
return this._status.E_NOTFOUND(message.resultId); | |
auditResult.updateProgress(Math.min(Math.max(0, message.progress), 1)); | |
}, | |
_onStopAuditCategoryRun: function(message) | |
{ | |
var auditRun = this._clientObjects[message.resultId]; | |
if (!auditRun) | |
return this._status.E_NOTFOUND(message.resultId); | |
auditRun.done(); | |
}, | |
_dispatchCallback: function(requestId, port, result) | |
{ | |
if (requestId) | |
port.postMessage({ command: "callback", requestId: requestId, result: result }); | |
}, | |
initExtensions: function() | |
{ | |
this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ConsoleMessageAdded, | |
WebInspector.console, WebInspector.ConsoleModel.Events.MessageAdded, this._notifyConsoleMessageAdded); | |
this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.NetworkRequestFinished, | |
WebInspector.networkManager, WebInspector.NetworkManager.EventTypes.RequestFinished, this._notifyRequestFinished); | |
this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ResourceAdded, | |
WebInspector.workspace, | |
WebInspector.UISourceCodeProvider.Events.UISourceCodeAdded, | |
this._notifyResourceAdded); | |
this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ElementsPanelObjectSelected, | |
WebInspector.notifications, | |
WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, | |
this._notifyElementsSelectionChanged); | |
this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ResourceContentCommitted, | |
WebInspector.workspace, | |
WebInspector.Workspace.Events.UISourceCodeContentCommitted, | |
this._notifyUISourceCodeContentCommitted); | |
function onTimelineSubscriptionStarted() | |
{ | |
WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, | |
this._notifyTimelineEventRecorded, this); | |
WebInspector.timelineManager.start(); | |
} | |
function onTimelineSubscriptionStopped() | |
{ | |
WebInspector.timelineManager.stop(); | |
WebInspector.timelineManager.removeEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, | |
this._notifyTimelineEventRecorded, this); | |
} | |
this._registerSubscriptionHandler(WebInspector.extensionAPI.Events.TimelineEventRecorded, | |
onTimelineSubscriptionStarted.bind(this), onTimelineSubscriptionStopped.bind(this)); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, | |
this._inspectedURLChanged, this); | |
WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this); | |
this._initDone = true; | |
if (this._pendingExtensions) { | |
this._pendingExtensions.forEach(this._innerAddExtension, this); | |
delete this._pendingExtensions; | |
} | |
InspectorExtensionRegistry.getExtensionsAsync(); | |
}, | |
_notifyConsoleMessageAdded: function(event) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.ConsoleMessageAdded, this._makeConsoleMessage(event.data)); | |
}, | |
_notifyResourceAdded: function(event) | |
{ | |
var uiSourceCode = event.data; | |
this._postNotification(WebInspector.extensionAPI.Events.ResourceAdded, this._makeResource(uiSourceCode)); | |
}, | |
_notifyUISourceCodeContentCommitted: function(event) | |
{ | |
var uiSourceCode = event.data.uiSourceCode; | |
var content = event.data.content; | |
this._postNotification(WebInspector.extensionAPI.Events.ResourceContentCommitted, this._makeResource(uiSourceCode), content); | |
}, | |
_notifyRequestFinished: function(event) | |
{ | |
var request = event.data; | |
this._postNotification(WebInspector.extensionAPI.Events.NetworkRequestFinished, this._requestId(request), (new WebInspector.HAREntry(request)).build()); | |
}, | |
_notifyElementsSelectionChanged: function() | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.ElementsPanelObjectSelected); | |
}, | |
_notifyTimelineEventRecorded: function(event) | |
{ | |
this._postNotification(WebInspector.extensionAPI.Events.TimelineEventRecorded, event.data); | |
}, | |
_addExtensions: function(extensions) | |
{ | |
extensions.forEach(this._addExtension, this); | |
}, | |
_addExtension: function(extensionInfo) | |
{ | |
if (this._initDone) { | |
this._innerAddExtension(extensionInfo); | |
return; | |
} | |
if (this._pendingExtensions) | |
this._pendingExtensions.push(extensionInfo); | |
else | |
this._pendingExtensions = [extensionInfo]; | |
}, | |
_innerAddExtension: function(extensionInfo) | |
{ | |
const urlOriginRegExp = new RegExp("([^:]+:\/\/[^/]*)\/"); | |
var startPage = extensionInfo.startPage; | |
var name = extensionInfo.name; | |
try { | |
var originMatch = urlOriginRegExp.exec(startPage); | |
if (!originMatch) { | |
console.error("Skipping extension with invalid URL: " + startPage); | |
return false; | |
} | |
var extensionOrigin = originMatch[1]; | |
if (!this._registeredExtensions[extensionOrigin]) { | |
InspectorFrontendHost.setInjectedScriptForOrigin(extensionOrigin, buildExtensionAPIInjectedScript(extensionInfo)); | |
this._registeredExtensions[extensionOrigin] = { name: name }; | |
} | |
var iframe = document.createElement("iframe"); | |
iframe.src = startPage; | |
iframe.style.display = "none"; | |
document.body.appendChild(iframe); | |
} catch (e) { | |
console.error("Failed to initialize extension " + startPage + ":" + e); | |
return false; | |
} | |
return true; | |
}, | |
_onWindowMessage: function(event) | |
{ | |
if (event.data === "registerExtension") | |
this._registerExtension(event.origin, event.ports[0]); | |
}, | |
_registerExtension: function(origin, port) | |
{ | |
if (!this._registeredExtensions.hasOwnProperty(origin)) { | |
if (origin !== window.location.origin) | |
console.error("Ignoring unauthorized client request from " + origin); | |
return; | |
} | |
port._extensionOrigin = origin; | |
port.addEventListener("message", this._onmessage.bind(this), false); | |
port.start(); | |
}, | |
_onmessage: function(event) | |
{ | |
var message = event.data; | |
var result; | |
if (message.command in this._handlers) | |
result = this._handlers[message.command](message, event.target); | |
else | |
result = this._status.E_NOTSUPPORTED(message.command); | |
if (result && message.requestId) | |
this._dispatchCallback(message.requestId, event.target, result); | |
}, | |
_registerHandler: function(command, callback) | |
{ | |
this._handlers[command] = callback; | |
}, | |
_registerSubscriptionHandler: function(eventTopic, onSubscribeFirst, onUnsubscribeLast) | |
{ | |
this._subscriptionStartHandlers[eventTopic] = onSubscribeFirst; | |
this._subscriptionStopHandlers[eventTopic] = onUnsubscribeLast; | |
}, | |
_registerAutosubscriptionHandler: function(eventTopic, eventTarget, frontendEventType, handler) | |
{ | |
this._registerSubscriptionHandler(eventTopic, | |
eventTarget.addEventListener.bind(eventTarget, frontendEventType, handler, this), | |
eventTarget.removeEventListener.bind(eventTarget, frontendEventType, handler, this)); | |
}, | |
_expandResourcePath: function(extensionPath, resourcePath) | |
{ | |
if (!resourcePath) | |
return; | |
return extensionPath + this._normalizePath(resourcePath); | |
}, | |
_normalizePath: function(path) | |
{ | |
var source = path.split("/"); | |
var result = []; | |
for (var i = 0; i < source.length; ++i) { | |
if (source[i] === ".") | |
continue; | |
if (source[i] === "") | |
continue; | |
if (source[i] === "..") | |
result.pop(); | |
else | |
result.push(source[i]); | |
} | |
return "/" + result.join("/"); | |
}, | |
evaluate: function(expression, exposeCommandLineAPI, returnByValue, options, securityOrigin, callback) | |
{ | |
var contextId; | |
if (typeof options === "object" && options["useContentScriptContext"]) { | |
var mainFrame = WebInspector.resourceTreeModel.mainFrame; | |
if (!mainFrame) | |
return this._status.E_FAILED("main frame not available yet"); | |
var context = WebInspector.runtimeModel.contextByFrameAndSecurityOrigin(mainFrame, securityOrigin); | |
if (!context) | |
return this._status.E_NOTFOUND(securityOrigin); | |
contextId = context.id; | |
} | |
RuntimeAgent.evaluate(expression, "extension", exposeCommandLineAPI, true, contextId, returnByValue, callback); | |
} | |
} | |
WebInspector.ExtensionStatus = function() | |
{ | |
function makeStatus(code, description) | |
{ | |
var details = Array.prototype.slice.call(arguments, 2); | |
var status = { code: code, description: description, details: details }; | |
if (code !== "OK") { | |
status.isError = true; | |
console.log("Extension server error: " + String.vsprintf(description, details)); | |
} | |
return status; | |
} | |
this.OK = makeStatus.bind(null, "OK", "OK"); | |
this.E_EXISTS = makeStatus.bind(null, "E_EXISTS", "Object already exists: %s"); | |
this.E_BADARG = makeStatus.bind(null, "E_BADARG", "Invalid argument %s: %s"); | |
this.E_BADARGTYPE = makeStatus.bind(null, "E_BADARGTYPE", "Invalid type for argument %s: got %s, expected %s"); | |
this.E_NOTFOUND = makeStatus.bind(null, "E_NOTFOUND", "Object not found: %s"); | |
this.E_NOTSUPPORTED = makeStatus.bind(null, "E_NOTSUPPORTED", "Object does not support requested operation: %s"); | |
this.E_FAILED = makeStatus.bind(null, "E_FAILED", "Operation failed: %s"); | |
} | |
WebInspector.addExtensions = function(extensions) | |
{ | |
WebInspector.extensionServer._addExtensions(extensions); | |
} | |
WebInspector.extensionAPI = {}; | |
defineCommonExtensionSymbols(WebInspector.extensionAPI); | |
WebInspector.extensionServer = new WebInspector.ExtensionServer(); | |
window.addExtension = function(page, name) | |
{ | |
WebInspector.extensionServer._addExtension({ | |
startPage: page, | |
name: name, | |
}); | |
} | |
WebInspector.ExtensionView = function(id, src, className) | |
{ | |
WebInspector.View.call(this); | |
this.element.className = "fill"; | |
this._id = id; | |
this._iframe = document.createElement("iframe"); | |
this._iframe.addEventListener("load", this._onLoad.bind(this), false); | |
this._iframe.src = src; | |
this._iframe.className = className; | |
this.setDefaultFocusedElement(this._iframe); | |
this.element.appendChild(this._iframe); | |
} | |
WebInspector.ExtensionView.prototype = { | |
wasShown: function() | |
{ | |
if (typeof this._frameIndex === "number") | |
WebInspector.extensionServer.notifyViewShown(this._id, this._frameIndex); | |
}, | |
willHide: function() | |
{ | |
if (typeof this._frameIndex === "number") | |
WebInspector.extensionServer.notifyViewHidden(this._id); | |
}, | |
_onLoad: function() | |
{ | |
this._frameIndex = Array.prototype.indexOf.call(window.frames, this._iframe.contentWindow); | |
if (this.isShowing()) | |
WebInspector.extensionServer.notifyViewShown(this._id, this._frameIndex); | |
} | |
} | |
WebInspector.ExtensionView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.ExtensionNotifierView = function(id) | |
{ | |
WebInspector.View.call(this); | |
this._id = id; | |
} | |
WebInspector.ExtensionNotifierView.prototype = { | |
wasShown: function() | |
{ | |
WebInspector.extensionServer.notifyViewShown(this._id); | |
}, | |
willHide: function() | |
{ | |
WebInspector.extensionServer.notifyViewHidden(this._id); | |
} | |
} | |
WebInspector.ExtensionNotifierView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.ExtensionPanel = function(id, pageURL) | |
{ | |
WebInspector.Panel.call(this, id); | |
this.setHideOnDetach(); | |
this._statusBarItems = []; | |
var extensionView = new WebInspector.ExtensionView(id, pageURL, "extension panel"); | |
extensionView.show(this.element); | |
this.setDefaultFocusedElement(extensionView.defaultFocusedElement()); | |
} | |
WebInspector.ExtensionPanel.prototype = { | |
defaultFocusedElement: function() | |
{ | |
return WebInspector.View.prototype.defaultFocusedElement.call(this); | |
}, | |
get statusBarItems() | |
{ | |
return this._statusBarItems; | |
}, | |
addStatusBarItem: function(element) | |
{ | |
this._statusBarItems.push(element); | |
}, | |
searchCanceled: function(startingNewSearch) | |
{ | |
WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.CancelSearch); | |
WebInspector.Panel.prototype.searchCanceled.apply(this, arguments); | |
}, | |
performSearch: function(query) | |
{ | |
WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.PerformSearch, query); | |
WebInspector.Panel.prototype.performSearch.apply(this, arguments); | |
}, | |
jumpToNextSearchResult: function() | |
{ | |
WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.NextSearchResult); | |
WebInspector.Panel.prototype.jumpToNextSearchResult.call(this); | |
}, | |
jumpToPreviousSearchResult: function() | |
{ | |
WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.PreviousSearchResult); | |
WebInspector.Panel.prototype.jumpToPreviousSearchResult.call(this); | |
} | |
} | |
WebInspector.ExtensionPanel.prototype.__proto__ = WebInspector.Panel.prototype; | |
WebInspector.ExtensionButton = function(id, iconURL, tooltip, disabled) | |
{ | |
this._id = id; | |
this.element = document.createElement("button"); | |
this.element.className = "status-bar-item extension"; | |
this.element.addEventListener("click", this._onClicked.bind(this), false); | |
this.update(iconURL, tooltip, disabled); | |
} | |
WebInspector.ExtensionButton.prototype = { | |
update: function(iconURL, tooltip, disabled) | |
{ | |
if (typeof iconURL === "string") | |
this.element.style.backgroundImage = "url(" + iconURL + ")"; | |
if (typeof tooltip === "string") | |
this.element.title = tooltip; | |
if (typeof disabled === "boolean") | |
this.element.disabled = disabled; | |
}, | |
_onClicked: function() | |
{ | |
WebInspector.extensionServer.notifyButtonClicked(this._id); | |
} | |
} | |
WebInspector.ExtensionSidebarPane = function(title, id) | |
{ | |
WebInspector.SidebarPane.call(this, title); | |
this._id = id; | |
} | |
WebInspector.ExtensionSidebarPane.prototype = { | |
setObject: function(object, title, callback) | |
{ | |
this._createObjectPropertiesView(); | |
this._setObject(WebInspector.RemoteObject.fromLocalObject(object), title, callback); | |
}, | |
setExpression: function(expression, title, evaluateOptions, securityOrigin, callback) | |
{ | |
this._createObjectPropertiesView(); | |
return WebInspector.extensionServer.evaluate(expression, true, false, evaluateOptions, securityOrigin, this._onEvaluate.bind(this, title, callback)); | |
}, | |
setPage: function(url) | |
{ | |
if (this._objectPropertiesView) { | |
this._objectPropertiesView.detach(); | |
delete this._objectPropertiesView; | |
} | |
if (this._extensionView) | |
this._extensionView.detach(true); | |
this._extensionView = new WebInspector.ExtensionView(this._id, url, "extension fill"); | |
this._extensionView.show(this.bodyElement); | |
if (!this.bodyElement.style.height) | |
this.setHeight("150px"); | |
}, | |
setHeight: function(height) | |
{ | |
this.bodyElement.style.height = height; | |
}, | |
_onEvaluate: function(title, callback, error, result, wasThrown) | |
{ | |
if (error) | |
callback(error.toString()); | |
else | |
this._setObject(WebInspector.RemoteObject.fromPayload(result), title, callback); | |
}, | |
_createObjectPropertiesView: function() | |
{ | |
if (this._objectPropertiesView) | |
return; | |
if (this._extensionView) { | |
this._extensionView.detach(true); | |
delete this._extensionView; | |
} | |
this._objectPropertiesView = new WebInspector.ExtensionNotifierView(this._id); | |
this._objectPropertiesView.show(this.bodyElement); | |
}, | |
_setObject: function(object, title, callback) | |
{ | |
if (!this._objectPropertiesView) { | |
callback("operation cancelled"); | |
return; | |
} | |
this._objectPropertiesView.element.removeChildren(); | |
var section = new WebInspector.ObjectPropertiesSection(object, title); | |
if (!title) | |
section.headerElement.addStyleClass("hidden"); | |
section.expanded = true; | |
section.editable = false; | |
this._objectPropertiesView.element.appendChild(section.element); | |
callback(); | |
} | |
} | |
WebInspector.ExtensionSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; | |
WebInspector.EmptyView = function(text) | |
{ | |
WebInspector.View.call(this); | |
this._text = text; | |
} | |
WebInspector.EmptyView.prototype = { | |
wasShown: function() | |
{ | |
this.element.className = "storage-empty-view"; | |
this.element.textContent = this._text; | |
}, | |
set text(text) | |
{ | |
this._text = text; | |
if (this.isShowing()) | |
this.element.textContent = this._text; | |
}, | |
} | |
WebInspector.EmptyView.prototype.__proto__ = WebInspector.View.prototype; | |
WebInspector.Formatter = function() | |
{ | |
} | |
WebInspector.Formatter.createFormatter = function(contentType) | |
{ | |
if (contentType === WebInspector.resourceTypes.Script || contentType === WebInspector.resourceTypes.Document) | |
return new WebInspector.ScriptFormatter(); | |
return new WebInspector.IdentityFormatter(); | |
} | |
WebInspector.Formatter.locationToPosition = function(lineEndings, lineNumber, columnNumber) | |
{ | |
var position = lineNumber ? lineEndings[lineNumber - 1] + 1 : 0; | |
return position + columnNumber; | |
} | |
WebInspector.Formatter.positionToLocation = function(lineEndings, position) | |
{ | |
var lineNumber = lineEndings.upperBound(position - 1); | |
if (!lineNumber) | |
var columnNumber = position; | |
else | |
var columnNumber = position - lineEndings[lineNumber - 1] - 1; | |
return [lineNumber, columnNumber]; | |
} | |
WebInspector.Formatter.prototype = { | |
formatContent: function(mimeType, content, callback) | |
{ | |
} | |
} | |
WebInspector.ScriptFormatter = function() | |
{ | |
this._tasks = []; | |
} | |
WebInspector.ScriptFormatter.prototype = { | |
formatContent: function(mimeType, content, callback) | |
{ | |
content = content.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''); | |
const method = "format"; | |
var parameters = { mimeType: mimeType, content: content, indentString: WebInspector.settings.textEditorIndent.get() }; | |
this._tasks.push({ data: parameters, callback: callback }); | |
this._worker.postMessage({ method: method, params: parameters }); | |
}, | |
_didFormatContent: function(event) | |
{ | |
var task = this._tasks.shift(); | |
var originalContent = task.data.content; | |
var formattedContent = event.data.content; | |
var mapping = event.data["mapping"]; | |
var sourceMapping = new WebInspector.FormatterSourceMappingImpl(originalContent.lineEndings(), formattedContent.lineEndings(), mapping); | |
task.callback(formattedContent, sourceMapping); | |
}, | |
get _worker() | |
{ | |
if (!this._cachedWorker) { | |
this._cachedWorker = new Worker("ScriptFormatterWorker.js"); | |
this._cachedWorker.onmessage = this._didFormatContent.bind(this); | |
} | |
return this._cachedWorker; | |
} | |
} | |
WebInspector.IdentityFormatter = function() | |
{ | |
this._tasks = []; | |
} | |
WebInspector.IdentityFormatter.prototype = { | |
formatContent: function(mimeType, content, callback) | |
{ | |
callback(content, new WebInspector.IdentityFormatterSourceMapping()); | |
} | |
} | |
WebInspector.FormatterMappingPayload = function() | |
{ | |
this.original = []; | |
this.formatted = []; | |
} | |
WebInspector.FormatterSourceMapping = function() | |
{ | |
} | |
WebInspector.FormatterSourceMapping.prototype = { | |
originalToFormatted: function(lineNumber, columnNumber) { }, | |
formattedToOriginal: function(lineNumber, columnNumber) { } | |
} | |
WebInspector.IdentityFormatterSourceMapping = function() | |
{ | |
} | |
WebInspector.IdentityFormatterSourceMapping.prototype = { | |
originalToFormatted: function(lineNumber, columnNumber) | |
{ | |
return [lineNumber, columnNumber || 0]; | |
}, | |
formattedToOriginal: function(lineNumber, columnNumber) | |
{ | |
return [lineNumber, columnNumber || 0]; | |
} | |
} | |
WebInspector.FormatterSourceMappingImpl = function(originalLineEndings, formattedLineEndings, mapping) | |
{ | |
this._originalLineEndings = originalLineEndings; | |
this._formattedLineEndings = formattedLineEndings; | |
this._mapping = mapping; | |
} | |
WebInspector.FormatterSourceMappingImpl.prototype = { | |
originalToFormatted: function(lineNumber, columnNumber) | |
{ | |
var originalPosition = WebInspector.Formatter.locationToPosition(this._originalLineEndings, lineNumber, columnNumber || 0); | |
var formattedPosition = this._convertPosition(this._mapping.original, this._mapping.formatted, originalPosition || 0); | |
return WebInspector.Formatter.positionToLocation(this._formattedLineEndings, formattedPosition); | |
}, | |
formattedToOriginal: function(lineNumber, columnNumber) | |
{ | |
var formattedPosition = WebInspector.Formatter.locationToPosition(this._formattedLineEndings, lineNumber, columnNumber || 0); | |
var originalPosition = this._convertPosition(this._mapping.formatted, this._mapping.original, formattedPosition); | |
return WebInspector.Formatter.positionToLocation(this._originalLineEndings, originalPosition || 0); | |
}, | |
_convertPosition: function(positions1, positions2, position) | |
{ | |
var index = positions1.upperBound(position) - 1; | |
var convertedPosition = positions2[index] + position - positions1[index]; | |
if (index < positions2.length - 1 && convertedPosition > positions2[index + 1]) | |
convertedPosition = positions2[index + 1]; | |
return convertedPosition; | |
} | |
} | |
WebInspector.DOMSyntaxHighlighter = function(mimeType, stripExtraWhitespace) | |
{ | |
this._tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer(mimeType); | |
this._stripExtraWhitespace = stripExtraWhitespace; | |
} | |
WebInspector.DOMSyntaxHighlighter.prototype = { | |
createSpan: function(content, className) | |
{ | |
var span = document.createElement("span"); | |
span.className = "webkit-" + className; | |
if (this._stripExtraWhitespace) | |
content = content.replace(/^[\n\r]*/, "").replace(/\s*$/, ""); | |
span.appendChild(document.createTextNode(content)); | |
return span; | |
}, | |
syntaxHighlightNode: function(node) | |
{ | |
this._tokenizer.condition = this._tokenizer.createInitialCondition(); | |
var lines = node.textContent.split("\n"); | |
node.removeChildren(); | |
for (var i = lines[0].length ? 0 : 1; i < lines.length; ++i) { | |
var line = lines[i]; | |
var plainTextStart = 0; | |
this._tokenizer.line = line; | |
var column = 0; | |
do { | |
var newColumn = this._tokenizer.nextToken(column); | |
var tokenType = this._tokenizer.tokenType; | |
if (tokenType) { | |
if (column > plainTextStart) { | |
var plainText = line.substring(plainTextStart, column); | |
node.appendChild(document.createTextNode(plainText)); | |
} | |
var token = line.substring(column, newColumn); | |
node.appendChild(this.createSpan(token, tokenType)); | |
plainTextStart = newColumn; | |
} | |
column = newColumn; | |
} while (column < line.length) | |
if (plainTextStart < line.length) { | |
var plainText = line.substring(plainTextStart, line.length); | |
node.appendChild(document.createTextNode(plainText)); | |
} | |
if (i < lines.length - 1) | |
node.appendChild(document.createElement("br")); | |
} | |
} | |
} | |
WebInspector.TextRange = function(startLine, startColumn, endLine, endColumn) | |
{ | |
this.startLine = startLine; | |
this.startColumn = startColumn; | |
this.endLine = endLine; | |
this.endColumn = endColumn; | |
} | |
WebInspector.TextRange.createFromLocation = function(line, column) | |
{ | |
return new WebInspector.TextRange(line, column, line, column); | |
} | |
WebInspector.TextRange.fromObject = function (serializedTextRange) | |
{ | |
return new WebInspector.TextRange(serializedTextRange.startLine, serializedTextRange.startColumn, serializedTextRange.endLine, serializedTextRange.endColumn); | |
} | |
WebInspector.TextRange.prototype = { | |
isEmpty: function() | |
{ | |
return this.startLine === this.endLine && this.startColumn === this.endColumn; | |
}, | |
get linesCount() | |
{ | |
return this.endLine - this.startLine; | |
}, | |
collapseToEnd: function() | |
{ | |
return new WebInspector.TextRange(this.endLine, this.endColumn, this.endLine, this.endColumn); | |
}, | |
normalize: function() | |
{ | |
if (this.startLine > this.endLine || (this.startLine === this.endLine && this.startColumn > this.endColumn)) | |
return new WebInspector.TextRange(this.endLine, this.endColumn, this.startLine, this.startColumn); | |
else | |
return this; | |
}, | |
clone: function() | |
{ | |
return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn); | |
}, | |
serializeToObject: function() | |
{ | |
var serializedTextRange = {}; | |
serializedTextRange.startLine = this.startLine; | |
serializedTextRange.startColumn = this.startColumn; | |
serializedTextRange.endLine = this.endLine; | |
serializedTextRange.endColumn = this.endColumn; | |
return serializedTextRange; | |
}, | |
compareTo: function(other) | |
{ | |
if (this.startLine > other.startLine) | |
return 1; | |
if (this.startLine < other.startLine) | |
return -1; | |
if (this.startColumn > other.startColumn) | |
return 1; | |
if (this.startColumn < other.startColumn) | |
return -1; | |
return 0; | |
} | |
} | |
WebInspector.TextEditorCommand = function(newRange, originalText) | |
{ | |
this.newRange = newRange; | |
this.originalText = originalText; | |
} | |
WebInspector.TextEditorModel = function() | |
{ | |
this._lines = [""]; | |
this._attributes = []; | |
this._undoStack = []; | |
this._noPunctuationRegex = /[^ !%&()*+,-.:;<=>?\[\]\^{|}~]+/; | |
this._lineBreak = "\n"; | |
} | |
WebInspector.TextEditorModel.Indent = { | |
TwoSpaces: " ", | |
FourSpaces: " ", | |
EightSpaces: " ", | |
TabCharacter: "\t" | |
} | |
WebInspector.TextEditorModel.Events = { | |
TextChanged: "TextChanged" | |
} | |
WebInspector.TextEditorModel.endsWithBracketRegex = /[{(\[]\s*$/; | |
WebInspector.TextEditorModel.prototype = { | |
get linesCount() | |
{ | |
return this._lines.length; | |
}, | |
text: function() | |
{ | |
return this._lines.join(this._lineBreak); | |
}, | |
range: function() | |
{ | |
return new WebInspector.TextRange(0, 0, this._lines.length - 1, this._lines[this._lines.length - 1].length); | |
}, | |
get lineBreak() | |
{ | |
return this._lineBreak; | |
}, | |
line: function(lineNumber) | |
{ | |
if (lineNumber >= this._lines.length) | |
throw "Out of bounds:" + lineNumber; | |
return this._lines[lineNumber]; | |
}, | |
lineLength: function(lineNumber) | |
{ | |
return this._lines[lineNumber].length; | |
}, | |
setText: function(text) | |
{ | |
text = text || ""; | |
var range = this.range(); | |
this._lineBreak = /\r\n/.test(text) ? "\r\n" : "\n"; | |
var newRange = this._innerSetText(range, text); | |
this.dispatchEventToListeners(WebInspector.TextEditorModel.Events.TextChanged, { oldRange: range, newRange: newRange}); | |
}, | |
editRange: function(range, text) | |
{ | |
var originalText = this.copyRange(range); | |
if (text === originalText) | |
return range; | |
var newRange = this._innerSetText(range, text); | |
this._pushUndoableCommand(newRange, originalText); | |
this.dispatchEventToListeners(WebInspector.TextEditorModel.Events.TextChanged, { oldRange: range, newRange: newRange }); | |
return newRange; | |
}, | |
_innerSetText: function(range, text) | |
{ | |
this._eraseRange(range); | |
if (text === "") | |
return new WebInspector.TextRange(range.startLine, range.startColumn, range.startLine, range.startColumn); | |
var newLines = text.split(/\r?\n/); | |
var prefix = this._lines[range.startLine].substring(0, range.startColumn); | |
var suffix = this._lines[range.startLine].substring(range.startColumn); | |
var postCaret = prefix.length; | |
if (newLines.length === 1) { | |
this._setLine(range.startLine, prefix + newLines[0] + suffix); | |
postCaret += newLines[0].length; | |
} else { | |
this._setLine(range.startLine, prefix + newLines[0]); | |
this._insertLines(range, newLines); | |
this._setLine(range.startLine + newLines.length - 1, newLines[newLines.length - 1] + suffix); | |
postCaret = newLines[newLines.length - 1].length; | |
} | |
return new WebInspector.TextRange(range.startLine, range.startColumn, | |
range.startLine + newLines.length - 1, postCaret); | |
}, | |
_insertLines: function(range, newLines) | |
{ | |
var lines = new Array(this._lines.length + newLines.length - 1); | |
for (var i = 0; i <= range.startLine; ++i) | |
lines[i] = this._lines[i]; | |
for (var i = 1; i < newLines.length; ++i) | |
lines[range.startLine + i] = newLines[i]; | |
for (var i = range.startLine + newLines.length; i < lines.length; ++i) | |
lines[i] = this._lines[i - newLines.length + 1]; | |
this._lines = lines; | |
var attributes = new Array(lines.length); | |
var insertionIndex = range.startColumn ? range.startLine + 1 : range.startLine; | |
for (var i = 0; i < insertionIndex; ++i) | |
attributes[i] = this._attributes[i]; | |
for (var i = insertionIndex + newLines.length - 1; i < attributes.length; ++i) | |
attributes[i] = this._attributes[i - newLines.length + 1]; | |
this._attributes = attributes; | |
}, | |
_eraseRange: function(range) | |
{ | |
if (range.isEmpty()) | |
return; | |
var prefix = this._lines[range.startLine].substring(0, range.startColumn); | |
var suffix = this._lines[range.endLine].substring(range.endColumn); | |
if (range.endLine > range.startLine) { | |
this._lines.splice(range.startLine + 1, range.endLine - range.startLine); | |
this._attributes.splice(range.startColumn ? range.startLine + 1 : range.startLine, range.endLine - range.startLine); | |
} | |
this._setLine(range.startLine, prefix + suffix); | |
}, | |
_setLine: function(lineNumber, text) | |
{ | |
this._lines[lineNumber] = text; | |
}, | |
wordRange: function(lineNumber, column) | |
{ | |
return new WebInspector.TextRange(lineNumber, this.wordStart(lineNumber, column, true), lineNumber, this.wordEnd(lineNumber, column, true)); | |
}, | |
wordStart: function(lineNumber, column, gapless) | |
{ | |
var line = this._lines[lineNumber]; | |
var prefix = line.substring(0, column).split("").reverse().join(""); | |
var prefixMatch = this._noPunctuationRegex.exec(prefix); | |
return prefixMatch && (!gapless || prefixMatch.index === 0) ? column - prefixMatch.index - prefixMatch[0].length : column; | |
}, | |
wordEnd: function(lineNumber, column, gapless) | |
{ | |
var line = this._lines[lineNumber]; | |
var suffix = line.substring(column); | |
var suffixMatch = this._noPunctuationRegex.exec(suffix); | |
return suffixMatch && (!gapless || suffixMatch.index === 0) ? column + suffixMatch.index + suffixMatch[0].length : column; | |
}, | |
copyRange: function(range) | |
{ | |
if (!range) | |
range = this.range(); | |
var clip = []; | |
if (range.startLine === range.endLine) { | |
clip.push(this._lines[range.startLine].substring(range.startColumn, range.endColumn)); | |
return clip.join(this._lineBreak); | |
} | |
clip.push(this._lines[range.startLine].substring(range.startColumn)); | |
for (var i = range.startLine + 1; i < range.endLine; ++i) | |
clip.push(this._lines[i]); | |
clip.push(this._lines[range.endLine].substring(0, range.endColumn)); | |
return clip.join(this._lineBreak); | |
}, | |
setAttribute: function(line, name, value) | |
{ | |
var attrs = this._attributes[line]; | |
if (!attrs) { | |
attrs = {}; | |
this._attributes[line] = attrs; | |
} | |
attrs[name] = value; | |
}, | |
getAttribute: function(line, name) | |
{ | |
var attrs = this._attributes[line]; | |
return attrs ? attrs[name] : null; | |
}, | |
removeAttribute: function(line, name) | |
{ | |
var attrs = this._attributes[line]; | |
if (attrs) | |
delete attrs[name]; | |
}, | |
_pushUndoableCommand: function(newRange, originalText) | |
{ | |
var command = new WebInspector.TextEditorCommand(newRange.clone(), originalText); | |
if (this._inUndo) | |
this._redoStack.push(command); | |
else { | |
if (!this._inRedo) | |
this._redoStack = []; | |
this._undoStack.push(command); | |
} | |
return command; | |
}, | |
undo: function(beforeCallback, afterCallback) | |
{ | |
if (!this._undoStack.length) | |
return null; | |
this._markRedoableState(); | |
this._inUndo = true; | |
var range = this._doUndo(this._undoStack, beforeCallback, afterCallback); | |
delete this._inUndo; | |
return range; | |
}, | |
redo: function(beforeCallback, afterCallback) | |
{ | |
if (!this._redoStack || !this._redoStack.length) | |
return null; | |
this.markUndoableState(); | |
this._inRedo = true; | |
var range = this._doUndo(this._redoStack, beforeCallback, afterCallback); | |
delete this._inRedo; | |
return range; | |
}, | |
_doUndo: function(stack, beforeCallback, afterCallback) | |
{ | |
var range = null; | |
for (var i = stack.length - 1; i >= 0; --i) { | |
var command = stack[i]; | |
stack.length = i; | |
if (beforeCallback) | |
beforeCallback(); | |
range = this.editRange(command.newRange, command.originalText); | |
if (afterCallback) | |
afterCallback(command.newRange, range); | |
if (i > 0 && stack[i - 1].explicit) | |
return range; | |
} | |
return range; | |
}, | |
markUndoableState: function() | |
{ | |
if (this._undoStack.length) | |
this._undoStack[this._undoStack.length - 1].explicit = true; | |
}, | |
_markRedoableState: function() | |
{ | |
if (this._redoStack.length) | |
this._redoStack[this._redoStack.length - 1].explicit = true; | |
}, | |
resetUndoStack: function() | |
{ | |
this._undoStack = []; | |
} | |
} | |
WebInspector.TextEditorModel.prototype.__proto__ = WebInspector.Object.prototype; | |
WebInspector.TextEditorHighlighter = function(textModel, damageCallback) | |
{ | |
this._textModel = textModel; | |
this._tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/html"); | |
this._damageCallback = damageCallback; | |
this._highlightChunkLimit = 1000; | |
} | |
WebInspector.TextEditorHighlighter._MaxLineCount = 10000; | |
WebInspector.TextEditorHighlighter.prototype = { | |
set mimeType(mimeType) | |
{ | |
var tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer(mimeType); | |
if (tokenizer) | |
this._tokenizer = tokenizer; | |
}, | |
set highlightChunkLimit(highlightChunkLimit) | |
{ | |
this._highlightChunkLimit = highlightChunkLimit; | |
}, | |
highlight: function(endLine, forceRun) | |
{ | |
if (this._textModel.linesCount > WebInspector.TextEditorHighlighter._MaxLineCount) | |
return; | |
var state = this._textModel.getAttribute(endLine - 1, "highlight"); | |
if (state && state.postConditionStringified) { | |
return; | |
} | |
this._requestedEndLine = endLine; | |
if (this._highlightTimer && !forceRun) { | |
return; | |
} | |
var startLine = endLine; | |
while (startLine > 0) { | |
state = this._textModel.getAttribute(startLine - 1, "highlight"); | |
if (state && state.postConditionStringified) | |
break; | |
startLine--; | |
} | |
this._highlightInChunks(startLine, endLine); | |
}, | |
updateHighlight: function(startLine, endLine) | |
{ | |
if (this._textModel.linesCount > WebInspector.TextEditorHighlighter._MaxLineCount) | |
return; | |
this._clearHighlightState(startLine); | |
if (startLine) { | |
var state = this._textModel.getAttribute(startLine - 1, "highlight"); | |
if (!state || !state.postConditionStringified) { | |
return false; | |
} | |
} | |
var restored = this._highlightLines(startLine, endLine); | |
if (!restored) { | |
for (var i = this._lastHighlightedLine; i < this._textModel.linesCount; ++i) { | |
var state = this._textModel.getAttribute(i, "highlight"); | |
if (!state && i > endLine) | |
break; | |
this._textModel.setAttribute(i, "highlight-outdated", state); | |
this._textModel.removeAttribute(i, "highlight"); | |
} | |
if (this._highlightTimer) { | |
clearTimeout(this._highlightTimer); | |
this._requestedEndLine = endLine; | |
this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, this._lastHighlightedLine, this._requestedEndLine), 10); | |
} | |
} | |
return restored; | |
}, | |
_highlightInChunks: function(startLine, endLine) | |
{ | |
delete this._highlightTimer; | |
var state = this._textModel.getAttribute(this._requestedEndLine - 1, "highlight"); | |
if (state && state.postConditionStringified) | |
return; | |
if (this._requestedEndLine !== endLine) { | |
this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, startLine, this._requestedEndLine), 100); | |
return; | |
} | |
if (this._requestedEndLine > this._textModel.linesCount) | |
this._requestedEndLine = this._textModel.linesCount; | |
this._highlightLines(startLine, this._requestedEndLine); | |
if (this._lastHighlightedLine < this._requestedEndLine) | |
this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, this._lastHighlightedLine, this._requestedEndLine), 10); | |
}, | |
_highlightLines: function(startLine, endLine) | |
{ | |
var state = this._textModel.getAttribute(startLine - 1, "highlight"); | |
var postConditionStringified = state ? state.postConditionStringified : JSON.stringify(this._tokenizer.createInitialCondition()); | |
var tokensCount = 0; | |
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) { | |
state = this._selectHighlightState(lineNumber, postConditionStringified); | |
if (state.postConditionStringified) { | |
postConditionStringified = state.postConditionStringified; | |
} else { | |
var lastHighlightedColumn = 0; | |
if (state.midConditionStringified) { | |
lastHighlightedColumn = state.lastHighlightedColumn; | |
postConditionStringified = state.midConditionStringified; | |
} | |
var line = this._textModel.line(lineNumber); | |
this._tokenizer.line = line; | |
this._tokenizer.condition = JSON.parse(postConditionStringified); | |
do { | |
var newColumn = this._tokenizer.nextToken(lastHighlightedColumn); | |
var tokenType = this._tokenizer.tokenType; | |
if (tokenType) | |
state[lastHighlightedColumn] = { length: newColumn - lastHighlightedColumn, tokenType: tokenType }; | |
lastHighlightedColumn = newColumn; | |
if (++tokensCount > this._highlightChunkLimit) | |
break; | |
} while (lastHighlightedColumn < line.length); | |
postConditionStringified = JSON.stringify(this._tokenizer.condition); | |
if (lastHighlightedColumn < line.length) { | |
state.lastHighlightedColumn = lastHighlightedColumn; | |
state.midConditionStringified = postConditionStringified; | |
break; | |
} else { | |
delete state.lastHighlightedColumn; | |
delete state.midConditionStringified; | |
state.postConditionStringified = postConditionStringified; | |
} | |
} | |
var nextLineState = this._textModel.getAttribute(lineNumber + 1, "highlight"); | |
if (nextLineState && nextLineState.preConditionStringified === state.postConditionStringified) { | |
++lineNumber; | |
this._damageCallback(startLine, lineNumber); | |
for (; lineNumber < endLine; ++lineNumber) { | |
state = this._textModel.getAttribute(lineNumber, "highlight"); | |
if (!state || !state.postConditionStringified) | |
break; | |
} | |
this._lastHighlightedLine = lineNumber; | |
return true; | |
} | |
} | |
this._damageCallback(startLine, lineNumber); | |
this._lastHighlightedLine = lineNumber; | |
return false; | |
}, | |
_selectHighlightState: function(lineNumber, preConditionStringified) | |
{ | |
var state = this._textModel.getAttribute(lineNumber, "highlight"); | |
if (state && state.preConditionStringified === preConditionStringified) | |
return state; | |
var outdatedState = this._textModel.getAttribute(lineNumber, "highlight-outdated"); | |
if (outdatedState && outdatedState.preConditionStringified === preConditionStringified) { | |
this._textModel.setAttribute(lineNumber, "highlight", outdatedState); | |
this._textModel.setAttribute(lineNumber, "highlight-outdated", state); | |
return outdatedState; | |
} | |
if (state) | |
this._textModel.setAttribute(lineNumber, "highlight-outdated", state); | |
state = {}; | |
state.preConditionStringified = preConditionStringified; | |
this._textModel.setAttribute(lineNumber, "highlight", state); | |
return state; | |
}, | |
_clearHighlightState: function(lineNumber) | |
{ | |
this._textModel.removeAttribute(lineNumber, "highlight"); | |
this._textModel.removeAttribute(lineNumber, "highlight-outdated"); | |
} | |
} | |
WebInspector.SourceTokenizer = function() | |
{ | |
} | |
WebInspector.SourceTokenizer.prototype = { | |
set line(line) { | |
this._line = line; | |
}, | |
set condition(condition) | |
{ | |
this._condition = condition; | |
}, | |
get condition() | |
{ | |
return this._condition; | |
}, | |
getLexCondition: function() | |
{ | |
return this.condition.lexCondition; | |
}, | |
setLexCondition: function(lexCondition) | |
{ | |
this.condition.lexCondition = lexCondition; | |
}, | |
_charAt: function(cursor) | |
{ | |
return cursor < this._line.length ? this._line.charAt(cursor) : "\n"; | |
}, | |
createInitialCondition: function() | |
{ | |
}, | |
nextToken: function(cursor) | |
{ | |
} | |
} | |
WebInspector.SourceTokenizer.Registry = function() { | |
this._tokenizers = {}; | |
this._tokenizerConstructors = { | |
"text/css": "SourceCSSTokenizer", | |
"text/html": "SourceHTMLTokenizer", | |
"text/javascript": "SourceJavaScriptTokenizer", | |
"text/x-scss": "SourceCSSTokenizer" | |
}; | |
} | |
WebInspector.SourceTokenizer.Registry.getInstance = function() | |
{ | |
if (!WebInspector.SourceTokenizer.Registry._instance) | |
WebInspector.SourceTokenizer.Registry._instance = new WebInspector.SourceTokenizer.Registry(); | |
return WebInspector.SourceTokenizer.Registry._instance; | |
} | |
WebInspector.SourceTokenizer.Registry.prototype = { | |
getTokenizer: function(mimeType) | |
{ | |
if (!this._tokenizerConstructors[mimeType]) | |
return null; | |
var tokenizerClass = this._tokenizerConstructors[mimeType]; | |
var tokenizer = this._tokenizers[tokenizerClass]; | |
if (!tokenizer) { | |
tokenizer = new WebInspector[tokenizerClass](); | |
this._tokenizers[tokenizerClass] = tokenizer; | |
} | |
return tokenizer; | |
} | |
} | |
WebInspector.SourceCSSTokenizer = function() | |
{ | |
WebInspector.SourceTokenizer.call(this); | |
this._propertyKeywords = WebInspector.CSSCompletions.cssPropertiesMetainfoKeySet(); | |
this._colorKeywords = WebInspector.CSSKeywordCompletions.colors(); | |
this._valueKeywords = [ | |
"above", "absolute", "activeborder", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll", | |
"alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", "arabic-indic", "armenian", "asterisks", | |
"auto", "avoid", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "blink", | |
"block", "block-axis", "bold", "bolder", "border", "border-box", "both", "bottom", "break-all", "break-word", "button", | |
"button-bevel", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", "capitalize", "caps-lock-indicator", | |
"caption", "captiontext", "caret", "cell", "center", "checkbox", "circle", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", | |
"clear", "clip", "close-quote", "col-resize", "collapse", "compact", "condensed", "contain", "content", "content-box", "context-menu", | |
"continuous", "copy", "cover", "crop", "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", "decimal-leading-zero", "default", | |
"default-button", "destination-atop", "destination-in", "destination-out", "destination-over", "devanagari", "disc", "discard", "document", | |
"dot-dash", "dot-dot-dash", "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "element", | |
"ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", "ethiopic-abegede-am-et", "ethiopic-abegede-gez", | |
"ethiopic-abegede-ti-er", "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", "ethiopic-halehame-aa-et", | |
"ethiopic-halehame-am-et", "ethiopic-halehame-gez", "ethiopic-halehame-om-et", "ethiopic-halehame-sid-et", | |
"ethiopic-halehame-so-et", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ew-resize", "expanded", | |
"extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes", "forwards", "from", "geometricPrecision", | |
"georgian", "graytext", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", "help", | |
"hidden", "hide", "higher", "highlight", "highlighttext", "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", | |
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", | |
"inline-axis", "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert", "italic", "justify", "kannada", "katakana", | |
"katakana-iroha", "khmer", "landscape", "lao", "large", "larger", "left", "level", "lighter", "line-through", "linear", "lines", | |
"list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "lower-greek", | |
"lower-hexadecimal", "lower-latin", "lower-norwegian", "lower-roman", "lowercase", "ltr", "malayalam", "match", "media-controls-background", | |
"media-current-time-display", "media-fullscreen-button", "media-mute-button", "media-play-button", "media-return-to-realtime-button", | |
"media-rewind-button", "media-seek-back-button", "media-seek-forward-button", "media-slider", "media-sliderthumb", "media-time-remaining-display", | |
"media-volume-slider", "media-volume-slider-container", "media-volume-sliderthumb", "medium", "menu", "menulist", "menulist-button", | |
"menulist-text", "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", "mix", "mongolian", "monospace", "move", "multiple", | |
"myanmar", "n-resize", "narrower", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", | |
"normal", "not-allowed", "nowrap", "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", "optimizeLegibility", | |
"optimizeSpeed", "oriya", "oromo", "outset", "outside", "overlay", "overline", "padding", "padding-box", "painted", "paused", | |
"persian", "plus-darker", "plus-lighter", "pointer", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", | |
"push-button", "radio", "read-only", "read-write", "read-write-plaintext-only", "relative", "repeat", "repeat-x", | |
"repeat-y", "reset", "reverse", "rgb", "rgba", "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", "s-resize", "sans-serif", | |
"scroll", "scrollbar", "se-resize", "searchfield", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", | |
"searchfield-results-decoration", "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", "single", | |
"skip-white-space", "slide", "slider-horizontal", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", | |
"small", "small-caps", "small-caption", "smaller", "solid", "somali", "source-atop", "source-in", "source-out", "source-over", | |
"space", "square", "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", "subpixel-antialiased", "super", | |
"sw-resize", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", | |
"table-row", "table-row-group", "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", "thick", "thin", | |
"threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", | |
"tigrinya-et", "tigrinya-et-abegede", "to", "top", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-armenian", | |
"upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", "vertical", "vertical-text", "visible", | |
"visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", "window", "windowframe", "windowtext", | |
"x-large", "x-small", "xor", "xx-large", "xx-small", "yellow", "-wap-marquee", "-webkit-activelink", "-webkit-auto", "-webkit-baseline-middle", | |
"-webkit-body", "-webkit-box", "-webkit-center", "-webkit-control", "-webkit-focus-ring-color", "-webkit-grab", "-webkit-grabbing", | |
"-webkit-gradient", "-webkit-inline-box", "-webkit-left", "-webkit-link", "-webkit-marquee", "-webkit-mini-control", "-webkit-nowrap", "-webkit-pictograph", | |
"-webkit-right", "-webkit-small-control", "-webkit-text", "-webkit-xxx-large", "-webkit-zoom-in", "-webkit-zoom-out", | |
].keySet(); | |
this._scssValueKeywords = [ | |
"abs", "adjust-color", "adjust-hue", "alpha", "append", "ceil", "change-color", "comparable", "complement", "darken", "desaturate", | |
"fade-in", "fade-out", "floor", "grayscale", "hue", "ie-hex-str", "invert", "join", "length", "lighten", | |
"lightness", "max", "min", "mix", "nth", "opacify", "opacity", "percentage", "quote", "round", "saturate", | |
"saturation", "scale-color", "transparentize", "type-of", "unit", "unitless", "unquote", "zip" | |
].keySet(); | |
this._lexConditions = { | |
INITIAL: 0, | |
COMMENT: 1, | |
DSTRING: 2, | |
SSTRING: 3 | |
}; | |
this._parseConditions = { | |
INITIAL: 0, | |
PROPERTY: 1, | |
PROPERTY_VALUE: 2, | |
AT_RULE: 3, | |
AT_MEDIA_RULE: 4 | |
}; | |
this.case_INITIAL = 1000; | |
this.case_COMMENT = 1002; | |
this.case_DSTRING = 1003; | |
this.case_SSTRING = 1004; | |
this.condition = this.createInitialCondition(); | |
} | |
WebInspector.SourceCSSTokenizer.SCSSAtRelatedKeywords = ["from", "if", "in", "through"].keySet(); | |
WebInspector.SourceCSSTokenizer.MediaTypes = ["all", "aural", "braille", "embossed", "handheld", "import", "print", "projection", "screen", "tty", "tv"].keySet(); | |
WebInspector.SourceCSSTokenizer.prototype = { | |
createInitialCondition: function() | |
{ | |
return { lexCondition: this._lexConditions.INITIAL, parseCondition: this._parseConditions.INITIAL }; | |
}, | |
_stringToken: function(cursor, stringEnds) | |
{ | |
if (this._isPropertyValue()) | |
this.tokenType = "css-string"; | |
else | |
this.tokenType = null; | |
return cursor; | |
}, | |
_isPropertyValue: function() | |
{ | |
return this._condition.parseCondition === this._parseConditions.PROPERTY_VALUE || this._condition.parseCondition === this._parseConditions.AT_RULE; | |
}, | |
_setParseCondition: function(condition) | |
{ | |
this._condition.parseCondition = condition; | |
}, | |
nextToken: function(cursor) | |
{ | |
var cursorOnEnter = cursor; | |
var gotoCase = 1; | |
var YYMARKER; | |
while (1) { | |
switch (gotoCase) | |
{ | |
case 1: var yych; | |
var yyaccept = 0; | |
if (this.getLexCondition() < 2) { | |
if (this.getLexCondition() < 1) { | |
{ gotoCase = this.case_INITIAL; continue; }; | |
} else { | |
{ gotoCase = this.case_COMMENT; continue; }; | |
} | |
} else { | |
if (this.getLexCondition() < 3) { | |
{ gotoCase = this.case_DSTRING; continue; }; | |
} else { | |
{ gotoCase = this.case_SSTRING; continue; }; | |
} | |
} | |
case this.case_COMMENT: | |
yych = this._charAt(cursor); | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 4; continue; }; | |
{ gotoCase = 3; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 4; continue; }; | |
if (yych == '*') { gotoCase = 6; continue; }; | |
{ gotoCase = 3; continue; }; | |
} | |
case 2: | |
{ this.tokenType = "css-comment"; return cursor; } | |
case 3: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
{ gotoCase = 12; continue; }; | |
case 4: | |
++cursor; | |
{ this.tokenType = null; return cursor; } | |
case 6: | |
yyaccept = 1; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych == '*') { gotoCase = 9; continue; }; | |
if (yych != '/') { gotoCase = 11; continue; }; | |
case 7: | |
++cursor; | |
this.setLexCondition(this._lexConditions.INITIAL); | |
{ this.tokenType = "css-comment"; return cursor; } | |
case 9: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych == '*') { gotoCase = 9; continue; }; | |
if (yych == '/') { gotoCase = 7; continue; }; | |
case 11: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
case 12: | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 2; continue; }; | |
{ gotoCase = 11; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 2; continue; }; | |
if (yych == '*') { gotoCase = 9; continue; }; | |
{ gotoCase = 11; continue; }; | |
} | |
case this.case_DSTRING: | |
yych = this._charAt(cursor); | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 17; continue; }; | |
if (yych <= '\f') { gotoCase = 16; continue; }; | |
{ gotoCase = 17; continue; }; | |
} else { | |
if (yych <= '"') { | |
if (yych <= '!') { gotoCase = 16; continue; }; | |
{ gotoCase = 19; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 21; continue; }; | |
{ gotoCase = 16; continue; }; | |
} | |
} | |
case 15: | |
{ return this._stringToken(cursor); } | |
case 16: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
{ gotoCase = 23; continue; }; | |
case 17: | |
++cursor; | |
case 18: | |
{ this.tokenType = null; return cursor; } | |
case 19: | |
++cursor; | |
case 20: | |
this.setLexCondition(this._lexConditions.INITIAL); | |
{ return this._stringToken(cursor, true); } | |
case 21: | |
yych = this._charAt(++cursor); | |
if (yych <= 'e') { | |
if (yych <= '\'') { | |
if (yych == '"') { gotoCase = 22; continue; }; | |
if (yych <= '&') { gotoCase = 18; continue; }; | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '[') { gotoCase = 18; continue; }; | |
} else { | |
if (yych != 'b') { gotoCase = 18; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'r') { | |
if (yych <= 'm') { | |
if (yych >= 'g') { gotoCase = 18; continue; }; | |
} else { | |
if (yych <= 'n') { gotoCase = 22; continue; }; | |
if (yych <= 'q') { gotoCase = 18; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych <= 's') { gotoCase = 18; continue; }; | |
} else { | |
if (yych != 'v') { gotoCase = 18; continue; }; | |
} | |
} | |
} | |
case 22: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
case 23: | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 15; continue; }; | |
if (yych <= '\f') { gotoCase = 22; continue; }; | |
{ gotoCase = 15; continue; }; | |
} else { | |
if (yych <= '"') { | |
if (yych <= '!') { gotoCase = 22; continue; }; | |
{ gotoCase = 26; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 22; continue; }; | |
} | |
} | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= 'e') { | |
if (yych <= '\'') { | |
if (yych == '"') { gotoCase = 22; continue; }; | |
if (yych >= '\'') { gotoCase = 22; continue; }; | |
} else { | |
if (yych <= '\\') { | |
if (yych >= '\\') { gotoCase = 22; continue; }; | |
} else { | |
if (yych == 'b') { gotoCase = 22; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'r') { | |
if (yych <= 'm') { | |
if (yych <= 'f') { gotoCase = 22; continue; }; | |
} else { | |
if (yych <= 'n') { gotoCase = 22; continue; }; | |
if (yych >= 'r') { gotoCase = 22; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych >= 't') { gotoCase = 22; continue; }; | |
} else { | |
if (yych == 'v') { gotoCase = 22; continue; }; | |
} | |
} | |
} | |
cursor = YYMARKER; | |
{ gotoCase = 15; continue; }; | |
case 26: | |
++cursor; | |
yych = this._charAt(cursor); | |
{ gotoCase = 20; continue; }; | |
case this.case_INITIAL: | |
yych = this._charAt(cursor); | |
if (yych <= ':') { | |
if (yych <= '&') { | |
if (yych <= '"') { | |
if (yych <= ' ') { gotoCase = 29; continue; }; | |
if (yych <= '!') { gotoCase = 31; continue; }; | |
{ gotoCase = 33; continue; }; | |
} else { | |
if (yych <= '#') { gotoCase = 34; continue; }; | |
if (yych <= '$') { gotoCase = 35; continue; }; | |
if (yych >= '&') { gotoCase = 31; continue; }; | |
} | |
} else { | |
if (yych <= '-') { | |
if (yych <= '\'') { gotoCase = 36; continue; }; | |
if (yych >= '-') { gotoCase = 37; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 38; continue; }; | |
if (yych <= '/') { gotoCase = 39; continue; }; | |
if (yych <= '9') { gotoCase = 40; continue; }; | |
{ gotoCase = 42; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '=') { | |
if (yych <= ';') { gotoCase = 44; continue; }; | |
if (yych >= '=') { gotoCase = 31; continue; }; | |
} else { | |
if (yych <= '?') { gotoCase = 29; continue; }; | |
if (yych != '\\') { gotoCase = 31; continue; }; | |
} | |
} else { | |
if (yych <= 'z') { | |
if (yych == '_') { gotoCase = 31; continue; }; | |
if (yych >= 'a') { gotoCase = 31; continue; }; | |
} else { | |
if (yych <= '{') { gotoCase = 46; continue; }; | |
if (yych == '}') { gotoCase = 48; continue; }; | |
} | |
} | |
} | |
case 29: | |
++cursor; | |
case 30: | |
{ this.tokenType = null; return cursor; } | |
case 31: | |
++cursor; | |
yych = this._charAt(cursor); | |
{ gotoCase = 51; continue; }; | |
case 32: | |
{ | |
var token = this._line.substring(cursorOnEnter, cursor); | |
this.tokenType = null; | |
if (this._condition.parseCondition === this._parseConditions.INITIAL || this._condition.parseCondition === this._parseConditions.PROPERTY) { | |
if (token.charAt(0) === "@") { | |
this.tokenType = "css-at-rule"; | |
this._setParseCondition(token === "@media" ? this._parseConditions.AT_MEDIA_RULE : this._parseConditions.AT_RULE); | |
this._condition.atKeyword = token; | |
} else if (this._condition.parseCondition === this._parseConditions.INITIAL) | |
this.tokenType = "css-selector"; | |
else if (this._propertyKeywords.hasOwnProperty(token)) | |
this.tokenType = "css-property"; | |
} else if (this._condition.parseCondition === this._parseConditions.AT_MEDIA_RULE || this._condition.parseCondition === this._parseConditions.AT_RULE) { | |
if (WebInspector.SourceCSSTokenizer.SCSSAtRelatedKeywords.hasOwnProperty(token)) | |
this.tokenType = "css-at-rule"; | |
else if (WebInspector.SourceCSSTokenizer.MediaTypes.hasOwnProperty(token)) | |
this.tokenType = "css-keyword"; | |
} | |
if (this.tokenType) | |
return cursor; | |
if (this._isPropertyValue()) { | |
var firstChar = token.charAt(0); | |
if (firstChar === "$") | |
this.tokenType = "scss-variable"; | |
else if (firstChar === "!") | |
this.tokenType = "css-bang-keyword"; | |
else if (this._condition.atKeyword === "@extend") | |
this.tokenType = "css-selector"; | |
else if (this._valueKeywords.hasOwnProperty(token) || this._scssValueKeywords.hasOwnProperty(token)) | |
this.tokenType = "css-keyword"; | |
else if (this._colorKeywords.hasOwnProperty(token)) { | |
this.tokenType = "css-color"; | |
} | |
} else if (this._condition.parseCondition !== this._parseConditions.PROPERTY_VALUE) | |
this.tokenType = "css-selector"; | |
return cursor; | |
} | |
case 33: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych <= '.') { | |
if (yych <= '!') { | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 32; continue; }; | |
{ gotoCase = 132; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 32; continue; }; | |
if (yych <= ' ') { gotoCase = 132; continue; }; | |
{ gotoCase = 130; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '"') { gotoCase = 116; continue; }; | |
if (yych <= '%') { gotoCase = 132; continue; }; | |
{ gotoCase = 130; continue; }; | |
} else { | |
if (yych == '-') { gotoCase = 130; continue; }; | |
{ gotoCase = 132; continue; }; | |
} | |
} | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '=') { | |
if (yych <= '9') { gotoCase = 130; continue; }; | |
if (yych <= '<') { gotoCase = 132; continue; }; | |
{ gotoCase = 130; continue; }; | |
} else { | |
if (yych <= '?') { gotoCase = 132; continue; }; | |
if (yych <= '[') { gotoCase = 130; continue; }; | |
{ gotoCase = 134; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych == '^') { gotoCase = 132; continue; }; | |
{ gotoCase = 130; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 132; continue; }; | |
if (yych <= 'z') { gotoCase = 130; continue; }; | |
{ gotoCase = 132; continue; }; | |
} | |
} | |
} | |
case 34: | |
yych = this._charAt(++cursor); | |
if (yych <= '@') { | |
if (yych <= '/') { gotoCase = 30; continue; }; | |
if (yych <= '9') { gotoCase = 127; continue; }; | |
{ gotoCase = 30; continue; }; | |
} else { | |
if (yych <= 'Z') { gotoCase = 127; continue; }; | |
if (yych <= '`') { gotoCase = 30; continue; }; | |
if (yych <= 'z') { gotoCase = 127; continue; }; | |
{ gotoCase = 30; continue; }; | |
} | |
case 35: | |
yych = this._charAt(++cursor); | |
if (yych <= '<') { | |
if (yych <= '\'') { | |
if (yych <= ' ') { gotoCase = 30; continue; }; | |
if (yych <= '"') { gotoCase = 124; continue; }; | |
if (yych <= '%') { gotoCase = 30; continue; }; | |
{ gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '-') { | |
if (yych <= ',') { gotoCase = 30; continue; }; | |
{ gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 30; continue; }; | |
if (yych <= '9') { gotoCase = 124; continue; }; | |
{ gotoCase = 30; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '?') { | |
if (yych <= '=') { gotoCase = 124; continue; }; | |
{ gotoCase = 30; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 30; continue; }; | |
{ gotoCase = 124; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych <= '^') { gotoCase = 30; continue; }; | |
{ gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 30; continue; }; | |
if (yych <= 'z') { gotoCase = 124; continue; }; | |
{ gotoCase = 30; continue; }; | |
} | |
} | |
} | |
case 36: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych <= '.') { | |
if (yych <= '"') { | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 32; continue; }; | |
{ gotoCase = 118; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 32; continue; }; | |
if (yych <= ' ') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '%') { gotoCase = 118; continue; }; | |
if (yych <= '&') { gotoCase = 114; continue; }; | |
{ gotoCase = 116; continue; }; | |
} else { | |
if (yych == '-') { gotoCase = 114; continue; }; | |
{ gotoCase = 118; continue; }; | |
} | |
} | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '=') { | |
if (yych <= '9') { gotoCase = 114; continue; }; | |
if (yych <= '<') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} else { | |
if (yych <= '?') { gotoCase = 118; continue; }; | |
if (yych <= '[') { gotoCase = 114; continue; }; | |
{ gotoCase = 120; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych == '^') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 118; continue; }; | |
if (yych <= 'z') { gotoCase = 114; continue; }; | |
{ gotoCase = 118; continue; }; | |
} | |
} | |
} | |
case 37: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych == '.') { gotoCase = 67; continue; }; | |
if (yych <= '/') { gotoCase = 51; continue; }; | |
if (yych <= '9') { gotoCase = 52; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 38: | |
yych = this._charAt(++cursor); | |
if (yych <= '/') { gotoCase = 30; continue; }; | |
if (yych <= '9') { gotoCase = 70; continue; }; | |
{ gotoCase = 30; continue; }; | |
case 39: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych == '*') { gotoCase = 106; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 40: | |
yyaccept = 1; | |
yych = this._charAt(YYMARKER = ++cursor); | |
switch (yych) { | |
case '!': | |
case '"': | |
case '&': | |
case '\'': | |
case '-': | |
case '/': | |
case '=': | |
case '@': | |
case 'A': | |
case 'B': | |
case 'C': | |
case 'D': | |
case 'E': | |
case 'F': | |
case 'G': | |
case 'I': | |
case 'J': | |
case 'K': | |
case 'L': | |
case 'M': | |
case 'N': | |
case 'O': | |
case 'P': | |
case 'Q': | |
case 'R': | |
case 'S': | |
case 'T': | |
case 'U': | |
case 'V': | |
case 'W': | |
case 'X': | |
case 'Y': | |
case 'Z': | |
case '[': | |
case ']': | |
case 'a': | |
case 'b': | |
case 'f': | |
case 'h': | |
case 'j': | |
case 'l': | |
case 'n': | |
case 'o': | |
case 'q': | |
case 'u': | |
case 'v': | |
case 'w': | |
case 'x': | |
case 'y': | |
case 'z': { gotoCase = 50; continue; }; | |
case '%': { gotoCase = 69; continue; }; | |
case '.': { gotoCase = 67; continue; }; | |
case '0': | |
case '1': | |
case '2': | |
case '3': | |
case '4': | |
case '5': | |
case '6': | |
case '7': | |
case '8': | |
case '9': { gotoCase = 52; continue; }; | |
case 'H': { gotoCase = 54; continue; }; | |
case '_': { gotoCase = 55; continue; }; | |
case 'c': { gotoCase = 56; continue; }; | |
case 'd': { gotoCase = 57; continue; }; | |
case 'e': { gotoCase = 58; continue; }; | |
case 'g': { gotoCase = 59; continue; }; | |
case 'i': { gotoCase = 60; continue; }; | |
case 'k': { gotoCase = 61; continue; }; | |
case 'm': { gotoCase = 62; continue; }; | |
case 'p': { gotoCase = 63; continue; }; | |
case 'r': { gotoCase = 64; continue; }; | |
case 's': { gotoCase = 65; continue; }; | |
case 't': { gotoCase = 66; continue; }; | |
default: { gotoCase = 41; continue; }; | |
} | |
case 41: | |
{ | |
if (this._isPropertyValue()) | |
this.tokenType = "css-number"; | |
else | |
this.tokenType = null; | |
return cursor; | |
} | |
case 42: | |
++cursor; | |
{ | |
this.tokenType = null; | |
if (this._condition.parseCondition === this._parseConditions.PROPERTY || this._condition.parseCondition === this._parseConditions.INITIAL) | |
this._setParseCondition(this._parseConditions.PROPERTY_VALUE); | |
return cursor; | |
} | |
case 44: | |
++cursor; | |
{ | |
this.tokenType = null; | |
this._setParseCondition(this._condition.openBraces ? this._parseConditions.PROPERTY : this._parseConditions.INITIAL); | |
delete this._condition.atKeyword; | |
return cursor; | |
} | |
case 46: | |
++cursor; | |
{ | |
this.tokenType = "block-start"; | |
this._condition.openBraces = (this._condition.openBraces || 0) + 1; | |
if (this._condition.parseCondition === this._parseConditions.AT_MEDIA_RULE) | |
this._setParseCondition(this._parseConditions.INITIAL); | |
else | |
this._setParseCondition(this._parseConditions.PROPERTY); | |
return cursor; | |
} | |
case 48: | |
++cursor; | |
{ | |
this.tokenType = "block-end"; | |
if (this._condition.openBraces > 0) | |
--this._condition.openBraces; | |
this._setParseCondition(this._condition.openBraces ? this._parseConditions.PROPERTY : this._parseConditions.INITIAL); | |
delete this._condition.atKeyword; | |
return cursor; | |
} | |
case 50: | |
++cursor; | |
yych = this._charAt(cursor); | |
case 51: | |
if (yych <= '<') { | |
if (yych <= '\'') { | |
if (yych <= ' ') { gotoCase = 32; continue; }; | |
if (yych <= '"') { gotoCase = 50; continue; }; | |
if (yych <= '%') { gotoCase = 32; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '-') { | |
if (yych <= ',') { gotoCase = 32; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 32; continue; }; | |
if (yych <= '9') { gotoCase = 50; continue; }; | |
{ gotoCase = 32; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '?') { | |
if (yych <= '=') { gotoCase = 50; continue; }; | |
{ gotoCase = 32; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 32; continue; }; | |
{ gotoCase = 50; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych <= '^') { gotoCase = 32; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 32; continue; }; | |
if (yych <= 'z') { gotoCase = 50; continue; }; | |
{ gotoCase = 32; continue; }; | |
} | |
} | |
} | |
case 52: | |
yyaccept = 1; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
switch (yych) { | |
case '!': | |
case '"': | |
case '&': | |
case '\'': | |
case '-': | |
case '/': | |
case '=': | |
case '@': | |
case 'A': | |
case 'B': | |
case 'C': | |
case 'D': | |
case 'E': | |
case 'F': | |
case 'G': | |
case 'I': | |
case 'J': | |
case 'K': | |
case 'L': | |
case 'M': | |
case 'N': | |
case 'O': | |
case 'P': | |
case 'Q': | |
case 'R': | |
case 'S': | |
case 'T': | |
case 'U': | |
case 'V': | |
case 'W': | |
case 'X': | |
case 'Y': | |
case 'Z': | |
case '[': | |
case ']': | |
case 'a': | |
case 'b': | |
case 'f': | |
case 'h': | |
case 'j': | |
case 'l': | |
case 'n': | |
case 'o': | |
case 'q': | |
case 'u': | |
case 'v': | |
case 'w': | |
case 'x': | |
case 'y': | |
case 'z': { gotoCase = 50; continue; }; | |
case '%': { gotoCase = 69; continue; }; | |
case '.': { gotoCase = 67; continue; }; | |
case '0': | |
case '1': | |
case '2': | |
case '3': | |
case '4': | |
case '5': | |
case '6': | |
case '7': | |
case '8': | |
case '9': { gotoCase = 52; continue; }; | |
case 'H': { gotoCase = 54; continue; }; | |
case '_': { gotoCase = 55; continue; }; | |
case 'c': { gotoCase = 56; continue; }; | |
case 'd': { gotoCase = 57; continue; }; | |
case 'e': { gotoCase = 58; continue; }; | |
case 'g': { gotoCase = 59; continue; }; | |
case 'i': { gotoCase = 60; continue; }; | |
case 'k': { gotoCase = 61; continue; }; | |
case 'm': { gotoCase = 62; continue; }; | |
case 'p': { gotoCase = 63; continue; }; | |
case 'r': { gotoCase = 64; continue; }; | |
case 's': { gotoCase = 65; continue; }; | |
case 't': { gotoCase = 66; continue; }; | |
default: { gotoCase = 41; continue; }; | |
} | |
case 54: | |
yych = this._charAt(++cursor); | |
if (yych == 'z') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 55: | |
yych = this._charAt(++cursor); | |
if (yych == '_') { gotoCase = 103; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 56: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 57: | |
yych = this._charAt(++cursor); | |
if (yych == 'e') { gotoCase = 102; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 58: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 65; continue; }; | |
if (yych == 'x') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 59: | |
yych = this._charAt(++cursor); | |
if (yych == 'r') { gotoCase = 100; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 60: | |
yych = this._charAt(++cursor); | |
if (yych == 'n') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 61: | |
yych = this._charAt(++cursor); | |
if (yych == 'H') { gotoCase = 99; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 62: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 65; continue; }; | |
if (yych == 's') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 63: | |
yych = this._charAt(++cursor); | |
if (yych <= 's') { | |
if (yych == 'c') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
} else { | |
if (yych <= 't') { gotoCase = 65; continue; }; | |
if (yych == 'x') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
} | |
case 64: | |
yych = this._charAt(++cursor); | |
if (yych == 'a') { gotoCase = 97; continue; }; | |
if (yych == 'e') { gotoCase = 98; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 65: | |
yych = this._charAt(++cursor); | |
if (yych <= '<') { | |
if (yych <= '\'') { | |
if (yych <= ' ') { gotoCase = 41; continue; }; | |
if (yych <= '"') { gotoCase = 50; continue; }; | |
if (yych <= '%') { gotoCase = 41; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '-') { | |
if (yych <= ',') { gotoCase = 41; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 41; continue; }; | |
if (yych <= '9') { gotoCase = 50; continue; }; | |
{ gotoCase = 41; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '?') { | |
if (yych <= '=') { gotoCase = 50; continue; }; | |
{ gotoCase = 41; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 41; continue; }; | |
{ gotoCase = 50; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych <= '^') { gotoCase = 41; continue; }; | |
{ gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 41; continue; }; | |
if (yych <= 'z') { gotoCase = 50; continue; }; | |
{ gotoCase = 41; continue; }; | |
} | |
} | |
} | |
case 66: | |
yych = this._charAt(++cursor); | |
if (yych == 'u') { gotoCase = 95; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 67: | |
yych = this._charAt(++cursor); | |
if (yych <= '/') { gotoCase = 68; continue; }; | |
if (yych <= '9') { gotoCase = 70; continue; }; | |
case 68: | |
cursor = YYMARKER; | |
if (yyaccept <= 0) { | |
{ gotoCase = 32; continue; }; | |
} else { | |
{ gotoCase = 41; continue; }; | |
} | |
case 69: | |
yych = this._charAt(++cursor); | |
{ gotoCase = 41; continue; }; | |
case 70: | |
yyaccept = 1; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= 'f') { | |
if (yych <= 'H') { | |
if (yych <= '/') { | |
if (yych == '%') { gotoCase = 69; continue; }; | |
{ gotoCase = 41; continue; }; | |
} else { | |
if (yych <= '9') { gotoCase = 70; continue; }; | |
if (yych <= 'G') { gotoCase = 41; continue; }; | |
{ gotoCase = 82; continue; }; | |
} | |
} else { | |
if (yych <= 'b') { | |
if (yych == '_') { gotoCase = 74; continue; }; | |
{ gotoCase = 41; continue; }; | |
} else { | |
if (yych <= 'c') { gotoCase = 76; continue; }; | |
if (yych <= 'd') { gotoCase = 79; continue; }; | |
if (yych >= 'f') { gotoCase = 41; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'm') { | |
if (yych <= 'i') { | |
if (yych <= 'g') { gotoCase = 80; continue; }; | |
if (yych <= 'h') { gotoCase = 41; continue; }; | |
{ gotoCase = 78; continue; }; | |
} else { | |
if (yych == 'k') { gotoCase = 83; continue; }; | |
if (yych <= 'l') { gotoCase = 41; continue; }; | |
{ gotoCase = 77; continue; }; | |
} | |
} else { | |
if (yych <= 'q') { | |
if (yych == 'p') { gotoCase = 75; continue; }; | |
{ gotoCase = 41; continue; }; | |
} else { | |
if (yych <= 'r') { gotoCase = 73; continue; }; | |
if (yych <= 's') { gotoCase = 69; continue; }; | |
if (yych <= 't') { gotoCase = 81; continue; }; | |
{ gotoCase = 41; continue; }; | |
} | |
} | |
} | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 69; continue; }; | |
if (yych == 'x') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 73: | |
yych = this._charAt(++cursor); | |
if (yych == 'a') { gotoCase = 93; continue; }; | |
if (yych == 'e') { gotoCase = 94; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 74: | |
yych = this._charAt(++cursor); | |
if (yych == '_') { gotoCase = 90; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 75: | |
yych = this._charAt(++cursor); | |
if (yych <= 's') { | |
if (yych == 'c') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
} else { | |
if (yych <= 't') { gotoCase = 69; continue; }; | |
if (yych == 'x') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
case 76: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 77: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 69; continue; }; | |
if (yych == 's') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 78: | |
yych = this._charAt(++cursor); | |
if (yych == 'n') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 79: | |
yych = this._charAt(++cursor); | |
if (yych == 'e') { gotoCase = 89; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 80: | |
yych = this._charAt(++cursor); | |
if (yych == 'r') { gotoCase = 87; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 81: | |
yych = this._charAt(++cursor); | |
if (yych == 'u') { gotoCase = 85; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 82: | |
yych = this._charAt(++cursor); | |
if (yych == 'z') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 83: | |
yych = this._charAt(++cursor); | |
if (yych != 'H') { gotoCase = 68; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'z') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 85: | |
yych = this._charAt(++cursor); | |
if (yych != 'r') { gotoCase = 68; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'n') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 87: | |
yych = this._charAt(++cursor); | |
if (yych != 'a') { gotoCase = 68; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'd') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 89: | |
yych = this._charAt(++cursor); | |
if (yych == 'g') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 90: | |
yych = this._charAt(++cursor); | |
if (yych != 'q') { gotoCase = 68; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych != 'e') { gotoCase = 68; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 93: | |
yych = this._charAt(++cursor); | |
if (yych == 'd') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 94: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 69; continue; }; | |
{ gotoCase = 68; continue; }; | |
case 95: | |
yych = this._charAt(++cursor); | |
if (yych != 'r') { gotoCase = 51; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'n') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 97: | |
yych = this._charAt(++cursor); | |
if (yych == 'd') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 98: | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 99: | |
yych = this._charAt(++cursor); | |
if (yych == 'z') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 100: | |
yych = this._charAt(++cursor); | |
if (yych != 'a') { gotoCase = 51; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'd') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 102: | |
yych = this._charAt(++cursor); | |
if (yych == 'g') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 103: | |
yych = this._charAt(++cursor); | |
if (yych != 'q') { gotoCase = 51; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych != 'e') { gotoCase = 51; continue; }; | |
yych = this._charAt(++cursor); | |
if (yych == 'm') { gotoCase = 65; continue; }; | |
{ gotoCase = 51; continue; }; | |
case 106: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 110; continue; }; | |
{ gotoCase = 106; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 110; continue; }; | |
if (yych != '*') { gotoCase = 106; continue; }; | |
} | |
case 108: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych == '*') { gotoCase = 108; continue; }; | |
if (yych == '/') { gotoCase = 112; continue; }; | |
{ gotoCase = 106; continue; }; | |
case 110: | |
++cursor; | |
this.setLexCondition(this._lexConditions.COMMENT); | |
{ this.tokenType = "css-comment"; return cursor; } | |
case 112: | |
++cursor; | |
{ this.tokenType = "css-comment"; return cursor; } | |
case 114: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '.') { | |
if (yych <= '"') { | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 32; continue; }; | |
{ gotoCase = 118; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 32; continue; }; | |
if (yych <= ' ') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '%') { gotoCase = 118; continue; }; | |
if (yych <= '&') { gotoCase = 114; continue; }; | |
} else { | |
if (yych == '-') { gotoCase = 114; continue; }; | |
{ gotoCase = 118; continue; }; | |
} | |
} | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '=') { | |
if (yych <= '9') { gotoCase = 114; continue; }; | |
if (yych <= '<') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} else { | |
if (yych <= '?') { gotoCase = 118; continue; }; | |
if (yych <= '[') { gotoCase = 114; continue; }; | |
{ gotoCase = 120; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych == '^') { gotoCase = 118; continue; }; | |
{ gotoCase = 114; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 118; continue; }; | |
if (yych <= 'z') { gotoCase = 114; continue; }; | |
{ gotoCase = 118; continue; }; | |
} | |
} | |
} | |
case 116: | |
++cursor; | |
if ((yych = this._charAt(cursor)) <= '<') { | |
if (yych <= '\'') { | |
if (yych <= ' ') { gotoCase = 117; continue; }; | |
if (yych <= '"') { gotoCase = 50; continue; }; | |
if (yych >= '&') { gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '-') { | |
if (yych >= '-') { gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 117; continue; }; | |
if (yych <= '9') { gotoCase = 50; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '?') { | |
if (yych <= '=') { gotoCase = 50; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 50; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych >= '_') { gotoCase = 50; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 117; continue; }; | |
if (yych <= 'z') { gotoCase = 50; continue; }; | |
} | |
} | |
} | |
case 117: | |
{ return this._stringToken(cursor, true); } | |
case 118: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 68; continue; }; | |
if (yych <= '\f') { gotoCase = 118; continue; }; | |
{ gotoCase = 68; continue; }; | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '&') { gotoCase = 118; continue; }; | |
{ gotoCase = 123; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 118; continue; }; | |
} | |
} | |
case 120: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= 'a') { | |
if (yych <= '!') { | |
if (yych <= '\n') { | |
if (yych <= '\t') { gotoCase = 68; continue; }; | |
} else { | |
if (yych != '\r') { gotoCase = 68; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '"') { gotoCase = 118; continue; }; | |
if (yych <= '&') { gotoCase = 68; continue; }; | |
{ gotoCase = 118; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 118; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'q') { | |
if (yych <= 'f') { | |
if (yych <= 'b') { gotoCase = 118; continue; }; | |
if (yych <= 'e') { gotoCase = 68; continue; }; | |
{ gotoCase = 118; continue; }; | |
} else { | |
if (yych == 'n') { gotoCase = 118; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych == 's') { gotoCase = 68; continue; }; | |
{ gotoCase = 118; continue; }; | |
} else { | |
if (yych == 'v') { gotoCase = 118; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} | |
} | |
++cursor; | |
this.setLexCondition(this._lexConditions.SSTRING); | |
{ return this._stringToken(cursor); } | |
case 123: | |
yych = this._charAt(++cursor); | |
{ gotoCase = 117; continue; }; | |
case 124: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '<') { | |
if (yych <= '\'') { | |
if (yych <= ' ') { gotoCase = 126; continue; }; | |
if (yych <= '"') { gotoCase = 124; continue; }; | |
if (yych >= '&') { gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '-') { | |
if (yych >= '-') { gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '.') { gotoCase = 126; continue; }; | |
if (yych <= '9') { gotoCase = 124; continue; }; | |
} | |
} | |
} else { | |
if (yych <= ']') { | |
if (yych <= '?') { | |
if (yych <= '=') { gotoCase = 124; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 124; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych >= '_') { gotoCase = 124; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 126; continue; }; | |
if (yych <= 'z') { gotoCase = 124; continue; }; | |
} | |
} | |
} | |
case 126: | |
{ | |
if (this._condition.parseCondition === this._condition.parseCondition.INITIAL || this._condition.parseCondition === this._condition.parseCondition.AT_RULE) | |
this._setParseCondition(this._parseConditions.PROPERTY); | |
this.tokenType = "scss-variable"; | |
return cursor; | |
} | |
case 127: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '@') { | |
if (yych <= '/') { gotoCase = 129; continue; }; | |
if (yych <= '9') { gotoCase = 127; continue; }; | |
} else { | |
if (yych <= 'Z') { gotoCase = 127; continue; }; | |
if (yych <= '`') { gotoCase = 129; continue; }; | |
if (yych <= 'z') { gotoCase = 127; continue; }; | |
} | |
case 129: | |
{ | |
if (this._isPropertyValue()) | |
this.tokenType = "css-color"; | |
else if (this._condition.parseCondition === this._parseConditions.INITIAL) | |
this.tokenType = "css-selector"; | |
else | |
this.tokenType = null; | |
return cursor; | |
} | |
case 130: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '.') { | |
if (yych <= '!') { | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 32; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 32; continue; }; | |
if (yych >= '!') { gotoCase = 130; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '"') { gotoCase = 116; continue; }; | |
if (yych >= '&') { gotoCase = 130; continue; }; | |
} else { | |
if (yych == '-') { gotoCase = 130; continue; }; | |
} | |
} | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '=') { | |
if (yych <= '9') { gotoCase = 130; continue; }; | |
if (yych >= '=') { gotoCase = 130; continue; }; | |
} else { | |
if (yych <= '?') { gotoCase = 132; continue; }; | |
if (yych <= '[') { gotoCase = 130; continue; }; | |
{ gotoCase = 134; continue; }; | |
} | |
} else { | |
if (yych <= '_') { | |
if (yych != '^') { gotoCase = 130; continue; }; | |
} else { | |
if (yych <= '`') { gotoCase = 132; continue; }; | |
if (yych <= 'z') { gotoCase = 130; continue; }; | |
} | |
} | |
} | |
case 132: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 68; continue; }; | |
if (yych <= '\f') { gotoCase = 132; continue; }; | |
{ gotoCase = 68; continue; }; | |
} else { | |
if (yych <= '"') { | |
if (yych <= '!') { gotoCase = 132; continue; }; | |
{ gotoCase = 123; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 132; continue; }; | |
} | |
} | |
case 134: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= 'a') { | |
if (yych <= '!') { | |
if (yych <= '\n') { | |
if (yych <= '\t') { gotoCase = 68; continue; }; | |
} else { | |
if (yych != '\r') { gotoCase = 68; continue; }; | |
} | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '"') { gotoCase = 132; continue; }; | |
if (yych <= '&') { gotoCase = 68; continue; }; | |
{ gotoCase = 132; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 132; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'q') { | |
if (yych <= 'f') { | |
if (yych <= 'b') { gotoCase = 132; continue; }; | |
if (yych <= 'e') { gotoCase = 68; continue; }; | |
{ gotoCase = 132; continue; }; | |
} else { | |
if (yych == 'n') { gotoCase = 132; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych == 's') { gotoCase = 68; continue; }; | |
{ gotoCase = 132; continue; }; | |
} else { | |
if (yych == 'v') { gotoCase = 132; continue; }; | |
{ gotoCase = 68; continue; }; | |
} | |
} | |
} | |
++cursor; | |
this.setLexCondition(this._lexConditions.DSTRING); | |
{ return this._stringToken(cursor); } | |
case this.case_SSTRING: | |
yych = this._charAt(cursor); | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 141; continue; }; | |
if (yych <= '\f') { gotoCase = 140; continue; }; | |
{ gotoCase = 141; continue; }; | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '&') { gotoCase = 140; continue; }; | |
{ gotoCase = 143; continue; }; | |
} else { | |
if (yych == '\\') { gotoCase = 145; continue; }; | |
{ gotoCase = 140; continue; }; | |
} | |
} | |
case 139: | |
{ return this._stringToken(cursor); } | |
case 140: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
{ gotoCase = 147; continue; }; | |
case 141: | |
++cursor; | |
case 142: | |
{ this.tokenType = null; return cursor; } | |
case 143: | |
++cursor; | |
case 144: | |
this.setLexCondition(this._lexConditions.INITIAL); | |
{ return this._stringToken(cursor, true); } | |
case 145: | |
yych = this._charAt(++cursor); | |
if (yych <= 'e') { | |
if (yych <= '\'') { | |
if (yych == '"') { gotoCase = 146; continue; }; | |
if (yych <= '&') { gotoCase = 142; continue; }; | |
} else { | |
if (yych <= '\\') { | |
if (yych <= '[') { gotoCase = 142; continue; }; | |
} else { | |
if (yych != 'b') { gotoCase = 142; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'r') { | |
if (yych <= 'm') { | |
if (yych >= 'g') { gotoCase = 142; continue; }; | |
} else { | |
if (yych <= 'n') { gotoCase = 146; continue; }; | |
if (yych <= 'q') { gotoCase = 142; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych <= 's') { gotoCase = 142; continue; }; | |
} else { | |
if (yych != 'v') { gotoCase = 142; continue; }; | |
} | |
} | |
} | |
case 146: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
case 147: | |
if (yych <= '\r') { | |
if (yych == '\n') { gotoCase = 139; continue; }; | |
if (yych <= '\f') { gotoCase = 146; continue; }; | |
{ gotoCase = 139; continue; }; | |
} else { | |
if (yych <= '\'') { | |
if (yych <= '&') { gotoCase = 146; continue; }; | |
{ gotoCase = 150; continue; }; | |
} else { | |
if (yych != '\\') { gotoCase = 146; continue; }; | |
} | |
} | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych <= 'e') { | |
if (yych <= '\'') { | |
if (yych == '"') { gotoCase = 146; continue; }; | |
if (yych >= '\'') { gotoCase = 146; continue; }; | |
} else { | |
if (yych <= '\\') { | |
if (yych >= '\\') { gotoCase = 146; continue; }; | |
} else { | |
if (yych == 'b') { gotoCase = 146; continue; }; | |
} | |
} | |
} else { | |
if (yych <= 'r') { | |
if (yych <= 'm') { | |
if (yych <= 'f') { gotoCase = 146; continue; }; | |
} else { | |
if (yych <= 'n') { gotoCase = 146; continue; }; | |
if (yych >= 'r') { gotoCase = 146; continue; }; | |
} | |
} else { | |
if (yych <= 't') { | |
if (yych >= 't') { gotoCase = 146; continue; }; | |
} else { | |
if (yych == 'v') { gotoCase = 146; continue; }; | |
} | |
} | |
} | |
cursor = YYMARKER; | |
{ gotoCase = 139; continue; }; | |
case 150: | |
++cursor; | |
yych = this._charAt(cursor); | |
{ gotoCase = 144; continue; }; | |
} | |
} | |
} | |
} | |
WebInspector.SourceCSSTokenizer.prototype.__proto__ = WebInspector.SourceTokenizer.prototype; | |
WebInspector.SourceHTMLTokenizer = function() | |
{ | |
WebInspector.SourceTokenizer.call(this); | |
this._lexConditions = { | |
INITIAL: 0, | |
COMMENT: 1, | |
DOCTYPE: 2, | |
TAG: 3, | |
DSTRING: 4, | |
SSTRING: 5 | |
}; | |
this.case_INITIAL = 1000; | |
this.case_COMMENT = 1001; | |
this.case_DOCTYPE = 1002; | |
this.case_TAG = 1003; | |
this.case_DSTRING = 1004; | |
this.case_SSTRING = 1005; | |
this._parseConditions = { | |
INITIAL: 0, | |
ATTRIBUTE: 1, | |
ATTRIBUTE_VALUE: 2, | |
LINKIFY: 4, | |
A_NODE: 8, | |
SCRIPT: 16, | |
STYLE: 32 | |
}; | |
this.condition = this.createInitialCondition(); | |
} | |
WebInspector.SourceHTMLTokenizer.prototype = { | |
createInitialCondition: function() | |
{ | |
return { lexCondition: this._lexConditions.INITIAL, parseCondition: this._parseConditions.INITIAL }; | |
}, | |
set line(line) { | |
if (this._condition.internalJavaScriptTokenizerCondition) { | |
var match = /<\/script/i.exec(line); | |
if (match) { | |
this._internalJavaScriptTokenizer.line = line.substring(0, match.index); | |
} else | |
this._internalJavaScriptTokenizer.line = line; | |
} else if (this._condition.internalCSSTokenizerCondition) { | |
var match = /<\/style/i.exec(line); | |
if (match) { | |
this._internalCSSTokenizer.line = line.substring(0, match.index); | |
} else | |
this._internalCSSTokenizer.line = line; | |
} | |
this._line = line; | |
}, | |
_isExpectingAttribute: function() | |
{ | |
return this._condition.parseCondition & this._parseConditions.ATTRIBUTE; | |
}, | |
_isExpectingAttributeValue: function() | |
{ | |
return this._condition.parseCondition & this._parseConditions.ATTRIBUTE_VALUE; | |
}, | |
_setExpectingAttribute: function() | |
{ | |
if (this._isExpectingAttributeValue()) | |
this._condition.parseCondition ^= this._parseConditions.ATTRIBUTE_VALUE; | |
this._condition.parseCondition |= this._parseConditions.ATTRIBUTE; | |
}, | |
_setExpectingAttributeValue: function() | |
{ | |
if (this._isExpectingAttribute()) | |
this._condition.parseCondition ^= this._parseConditions.ATTRIBUTE; | |
this._condition.parseCondition |= this._parseConditions.ATTRIBUTE_VALUE; | |
}, | |
_stringToken: function(cursor, stringEnds) | |
{ | |
if (!this._isExpectingAttributeValue()) { | |
this.tokenType = null; | |
return cursor; | |
} | |
this.tokenType = this._attrValueTokenType(); | |
if (stringEnds) | |
this._setExpectingAttribute(); | |
return cursor; | |
}, | |
_attrValueTokenType: function() | |
{ | |
if (this._condition.parseCondition & this._parseConditions.LINKIFY) { | |
if (this._condition.parseCondition & this._parseConditions.A_NODE) | |
return "html-external-link"; | |
return "html-resource-link"; | |
} | |
return "html-attribute-value"; | |
}, | |
get _internalJavaScriptTokenizer() | |
{ | |
return WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/javascript"); | |
}, | |
get _internalCSSTokenizer() | |
{ | |
return WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/css"); | |
}, | |
scriptStarted: function(cursor) | |
{ | |
this._condition.internalJavaScriptTokenizerCondition = this._internalJavaScriptTokenizer.createInitialCondition(); | |
}, | |
scriptEnded: function(cursor) | |
{ | |
}, | |
styleSheetStarted: function(cursor) | |
{ | |
this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.createInitialCondition(); | |
}, | |
styleSheetEnded: function(cursor) | |
{ | |
}, | |
nextToken: function(cursor) | |
{ | |
if (this._condition.internalJavaScriptTokenizerCondition) { | |
this.line = this._line; | |
if (cursor !== this._internalJavaScriptTokenizer._line.length) { | |
this._internalJavaScriptTokenizer.condition = this._condition.internalJavaScriptTokenizerCondition; | |
var result = this._internalJavaScriptTokenizer.nextToken(cursor); | |
this.tokenType = this._internalJavaScriptTokenizer.tokenType; | |
this._condition.internalJavaScriptTokenizerCondition = this._internalJavaScriptTokenizer.condition; | |
return result; | |
} else if (cursor !== this._line.length) | |
delete this._condition.internalJavaScriptTokenizerCondition; | |
} else if (this._condition.internalCSSTokenizerCondition) { | |
this.line = this._line; | |
if (cursor !== this._internalCSSTokenizer._line.length) { | |
this._internalCSSTokenizer.condition = this._condition.internalCSSTokenizerCondition; | |
var result = this._internalCSSTokenizer.nextToken(cursor); | |
this.tokenType = this._internalCSSTokenizer.tokenType; | |
this._condition.internalCSSTokenizerCondition = this._internalCSSTokenizer.condition; | |
return result; | |
} else if (cursor !== this._line.length) | |
delete this._condition.internalCSSTokenizerCondition; | |
} | |
var cursorOnEnter = cursor; | |
var gotoCase = 1; | |
var YYMARKER; | |
while (1) { | |
switch (gotoCase) | |
{ | |
case 1: var yych; | |
var yyaccept = 0; | |
if (this.getLexCondition() < 3) { | |
if (this.getLexCondition() < 1) { | |
{ gotoCase = this.case_INITIAL; continue; }; | |
} else { | |
if (this.getLexCondition() < 2) { | |
{ gotoCase = this.case_COMMENT; continue; }; | |
} else { | |
{ gotoCase = this.case_DOCTYPE; continue; }; | |
} | |
} | |
} else { | |
if (this.getLexCondition() < 4) { | |
{ gotoCase = this.case_TAG; continue; }; | |
} else { | |
if (this.getLexCondition() < 5) { | |
{ gotoCase = this.case_DSTRING; continue; }; | |
} else { | |
{ gotoCase = this.case_SSTRING; continue; }; | |
} | |
} | |
} | |
case this.case_COMMENT: | |
yych = this._charAt(cursor); | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 4; continue; }; | |
{ gotoCase = 3; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 4; continue; }; | |
if (yych == '-') { gotoCase = 6; continue; }; | |
{ gotoCase = 3; continue; }; | |
} | |
case 2: | |
{ this.tokenType = "html-comment"; return cursor; } | |
case 3: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
{ gotoCase = 9; continue; }; | |
case 4: | |
++cursor; | |
case 5: | |
{ this.tokenType = null; return cursor; } | |
case 6: | |
yyaccept = 1; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych != '-') { gotoCase = 5; continue; }; | |
case 7: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych == '>') { gotoCase = 10; continue; }; | |
case 8: | |
yyaccept = 0; | |
YYMARKER = ++cursor; | |
yych = this._charAt(cursor); | |
case 9: | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 2; continue; }; | |
{ gotoCase = 8; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 2; continue; }; | |
if (yych == '-') { gotoCase = 12; continue; }; | |
{ gotoCase = 8; continue; }; | |
} | |
case 10: | |
++cursor; | |
this.setLexCondition(this._lexConditions.INITIAL); | |
{ this.tokenType = "html-comment"; return cursor; } | |
case 12: | |
++cursor; | |
yych = this._charAt(cursor); | |
if (yych == '-') { gotoCase = 7; continue; }; | |
cursor = YYMARKER; | |
if (yyaccept <= 0) { | |
{ gotoCase = 2; continue; }; | |
} else { | |
{ gotoCase = 5; continue; }; | |
} | |
case this.case_DOCTYPE: | |
yych = this._charAt(cursor); | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 18; continue; }; | |
{ gotoCase = 17; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 18; continue; }; | |
if (yych == '>') { gotoCase = 20; continue; }; | |
{ gotoCase = 17; continue; }; | |
} | |
case 16: | |
{ this.tokenType = "html-doctype"; return cursor; } | |
case 17: | |
yych = this._charAt(++cursor); | |
{ gotoCase = 23; continue; }; | |
case 18: | |
++cursor; | |
{ this.tokenType = null; return cursor; } | |
case 20: | |
++cursor; | |
this.setLexCondition(this._lexConditions.INITIAL); | |
{ this.tokenType = "html-doctype"; return cursor; } | |
case 22: | |
++cursor; | |
yych = this._charAt(cursor); | |
case 23: | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 16; continue; }; | |
{ gotoCase = 22; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 16; continue; }; | |
if (yych == '>') { gotoCase = 16; continue; }; | |
{ gotoCase = 22; continue; }; | |
} | |
case this.case_DSTRING: | |
yych = this._charAt(cursor); | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 28; continue; }; | |
{ gotoCase = 27; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 28; continue; }; | |
if (yych == '"') { gotoCase = 30; continue; }; | |
{ gotoCase = 27; continue; }; | |
} | |
case 26: | |
{ return this._stringToken(cursor); } | |
case 27: | |
yych = this._charAt(++cursor); | |
{ gotoCase = 34; continue; }; | |
case 28: | |
++cursor; | |
{ this.tokenType = null; return cursor; } | |
case 30: | |
++cursor; | |
case 31: | |
this.setLexCondition(this._lexConditions.TAG); | |
{ return this._stringToken(cursor, true); } | |
case 32: | |
yych = this._charAt(++cursor); | |
{ gotoCase = 31; continue; }; | |
case 33: | |
++cursor; | |
yych = this._charAt(cursor); | |
case 34: | |
if (yych <= '\f') { | |
if (yych == '\n') { gotoCase = 26; continue; }; | |
{ gotoCase = 33; continue; }; | |
} else { | |
if (yych <= '\r') { gotoCase = 26; continue; }; | |
if (yych == '"') { gotoCase = 32; continue; }; | |
{ gotoCase = 33; continue; }; | |
} | |
case this.case_INITIAL: | |
yych = this._charAt(cursor); | |
if (yych == '<') { gotoCase = 39; continue; }; | |
++cursor; | |
{ this.tokenType = null; return cursor; } | |
case 39: | |
yyaccept = 0; | |
yych = this._charAt(YYMARKER = ++cursor); | |
if (yych <= '/') { | |
if (yych == '!') { gotoCase = 44; continue; }; | |
if (yych >= '/') { gotoCase = 41; continue; }; | |
} else { | |
if (yych <= 'S') { | |
if (yych >= 'S') { gotoCase = 42; continue; }; | |
} else { | |
if (yych == 's') { gotoCase = 42; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment