summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector/front-end
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/inspector/front-end')
-rw-r--r--WebCore/inspector/front-end/AuditCategories.js70
-rw-r--r--WebCore/inspector/front-end/AuditLauncherView.js11
-rw-r--r--WebCore/inspector/front-end/AuditRules.js1213
-rw-r--r--WebCore/inspector/front-end/AuditsPanel.js38
-rw-r--r--WebCore/inspector/front-end/CookieItemsView.js300
-rw-r--r--WebCore/inspector/front-end/DOMStorageItemsView.js21
-rw-r--r--WebCore/inspector/front-end/DataGrid.js74
-rw-r--r--WebCore/inspector/front-end/DatabaseQueryView.js1
-rw-r--r--WebCore/inspector/front-end/DatabaseTableView.js1
-rw-r--r--WebCore/inspector/front-end/ElementsTreeOutline.js4
-rw-r--r--WebCore/inspector/front-end/InjectedScript.js306
-rw-r--r--WebCore/inspector/front-end/InjectedScriptAccess.js2
-rw-r--r--WebCore/inspector/front-end/NativeTextViewer.js258
-rw-r--r--WebCore/inspector/front-end/ScriptView.js3
-rw-r--r--WebCore/inspector/front-end/Settings.js5
-rw-r--r--WebCore/inspector/front-end/SourceCSSTokenizer.re2js56
-rw-r--r--WebCore/inspector/front-end/SourceFrame.js425
-rw-r--r--WebCore/inspector/front-end/SourceView.js22
-rw-r--r--WebCore/inspector/front-end/StoragePanel.js56
-rw-r--r--WebCore/inspector/front-end/StylesSidebarPane.js17
-rw-r--r--WebCore/inspector/front-end/TextEditor.js1168
-rw-r--r--WebCore/inspector/front-end/TextEditorModel.js23
-rw-r--r--WebCore/inspector/front-end/TextViewer.js666
-rw-r--r--WebCore/inspector/front-end/WebKit.qrc7
-rw-r--r--WebCore/inspector/front-end/audits.css4
-rw-r--r--WebCore/inspector/front-end/inspector.css6
-rw-r--r--WebCore/inspector/front-end/inspector.html7
-rw-r--r--WebCore/inspector/front-end/inspector.js46
-rw-r--r--WebCore/inspector/front-end/textEditor.css90
-rw-r--r--WebCore/inspector/front-end/textViewer.css149
-rw-r--r--WebCore/inspector/front-end/utilities.js24
31 files changed, 2751 insertions, 2322 deletions
diff --git a/WebCore/inspector/front-end/AuditCategories.js b/WebCore/inspector/front-end/AuditCategories.js
new file mode 100644
index 0000000..6931b5f
--- /dev/null
+++ b/WebCore/inspector/front-end/AuditCategories.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+WebInspector.AuditCategories.PagePerformance = function() {
+ WebInspector.AuditCategory.call(this, WebInspector.AuditCategories.PagePerformance.AuditCategoryName);
+}
+
+WebInspector.AuditCategories.PagePerformance.AuditCategoryName = "Web Page Performance";
+
+WebInspector.AuditCategories.PagePerformance.prototype = {
+ initialize: function()
+ {
+ this.addRule(new WebInspector.AuditRules.UnusedCssRule());
+ this.addRule(new WebInspector.AuditRules.CssInHeadRule({InlineURLScore: 6, InlineStylesheetScore: 21}));
+ this.addRule(new WebInspector.AuditRules.StylesScriptsOrderRule({CSSAfterJSURLScore: 11, InlineBetweenResourcesScore: 21}));
+ }
+}
+
+WebInspector.AuditCategories.PagePerformance.prototype.__proto__ = WebInspector.AuditCategory.prototype;
+
+WebInspector.AuditCategories.NetworkUtilization = function() {
+ WebInspector.AuditCategory.call(this, WebInspector.AuditCategories.NetworkUtilization.AuditCategoryName);
+}
+
+WebInspector.AuditCategories.NetworkUtilization.AuditCategoryName = "Network Utilization";
+
+WebInspector.AuditCategories.NetworkUtilization.prototype = {
+ initialize: function()
+ {
+ this.addRule(new WebInspector.AuditRules.GzipRule());
+ this.addRule(new WebInspector.AuditRules.ImageDimensionsRule({ScorePerImageUse: 5}));
+ this.addRule(new WebInspector.AuditRules.CookieSizeRule({MinBytesThreshold: 400, MaxBytesThreshold: 1000}));
+ this.addRule(new WebInspector.AuditRules.StaticCookielessRule({MinResources: 5}));
+ this.addRule(new WebInspector.AuditRules.CombineJsResourcesRule({AllowedPerDomain: 2, ScorePerResource: 11}));
+ this.addRule(new WebInspector.AuditRules.CombineCssResourcesRule({AllowedPerDomain: 2, ScorePerResource: 11}));
+ this.addRule(new WebInspector.AuditRules.MinimizeDnsLookupsRule({HostCountThreshold: 4, ViolationDomainScore: 6}));
+ this.addRule(new WebInspector.AuditRules.ParallelizeDownloadRule({OptimalHostnameCount: 4, MinRequestThreshold: 10, MinBalanceThreshold: 0.5}));
+ this.addRule(new WebInspector.AuditRules.BrowserCacheControlRule());
+ this.addRule(new WebInspector.AuditRules.ProxyCacheControlRule());
+ }
+}
+
+WebInspector.AuditCategories.NetworkUtilization.prototype.__proto__ = WebInspector.AuditCategory.prototype;
diff --git a/WebCore/inspector/front-end/AuditLauncherView.js b/WebCore/inspector/front-end/AuditLauncherView.js
index 79fbb92..f2a2fd2 100644
--- a/WebCore/inspector/front-end/AuditLauncherView.js
+++ b/WebCore/inspector/front-end/AuditLauncherView.js
@@ -63,11 +63,11 @@ WebInspector.AuditLauncherView = function(categoriesById, runnerCallback)
}
WebInspector.AuditLauncherView.prototype = {
- updateResourceTrackingState: function()
+ updateResourceTrackingState: function(isTracking)
{
if (!this._auditPresentStateLabelElement)
return;
- if (InspectorBackend.resourceTrackingEnabled()) {
+ if (isTracking) {
this._auditPresentStateLabelElement.nodeValue = WebInspector.UIString("Audit Present State");
this._auditPresentStateElement.disabled = false;
this._auditPresentStateElement.parentElement.removeStyleClass("disabled");
@@ -197,7 +197,6 @@ WebInspector.AuditLauncherView.prototype = {
this._selectAllClicked(this._selectAllCheckboxElement.checked);
this.updateResourceTrackingState();
this._updateButton();
- this.resize();
},
_updateButton: function()
@@ -209,6 +208,12 @@ WebInspector.AuditLauncherView.prototype = {
this._launchButton.textContent = WebInspector.UIString("Run");
},
+ show: function(parentElement)
+ {
+ WebInspector.View.prototype.show.call(this, parentElement);
+ setTimeout(this.resize(), 0);
+ },
+
resize: function()
{
if (this._categoriesElement)
diff --git a/WebCore/inspector/front-end/AuditRules.js b/WebCore/inspector/front-end/AuditRules.js
new file mode 100644
index 0000000..210b8a9
--- /dev/null
+++ b/WebCore/inspector/front-end/AuditRules.js
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+WebInspector.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
+
+WebInspector.AuditRules.CacheableResponseCodes =
+{
+ 200: true,
+ 203: true,
+ 206: true,
+ 300: true,
+ 301: true,
+ 410: true,
+
+ 304: true // Underlying resource is cacheable
+}
+
+/**
+ * @param {Array} array Array of Elements (outerHTML is used) or strings (plain value is used as innerHTML)
+ */
+WebInspector.AuditRules.arrayAsUL = function(array, shouldLinkify)
+{
+ if (!array.length)
+ return "";
+ var ulElement = document.createElement("ul");
+ for (var i = 0; i < array.length; ++i) {
+ var liElement = document.createElement("li");
+ if (array[i] instanceof Element)
+ liElement.appendChild(array[i]);
+ else if (shouldLinkify)
+ liElement.appendChild(WebInspector.linkifyURLAsNode(array[i]));
+ else
+ liElement.innerHTML = array[i];
+ ulElement.appendChild(liElement);
+ }
+ return ulElement.outerHTML;
+}
+
+WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, regexp, needFullResources)
+{
+ var domainToResourcesMap = {};
+ for (var i = 0, size = resources.length; i < size; ++i) {
+ var resource = resources[i];
+ if (types && types.indexOf(resource.type) === -1)
+ continue;
+ var match = resource.url.match(regexp);
+ if (!match)
+ continue;
+ var domain = match[2];
+ var domainResources = domainToResourcesMap[domain];
+ if (domainResources === undefined) {
+ domainResources = [];
+ domainToResourcesMap[domain] = domainResources;
+ }
+ domainResources.push(needFullResources ? resource : resource.url);
+ }
+ return domainToResourcesMap;
+}
+
+WebInspector.AuditRules.evaluateInTargetWindow = function(func, callback)
+{
+ InjectedScriptAccess.getDefault().evaluateOnSelf(func.toString(), callback);
+}
+
+
+WebInspector.AuditRules.GzipRule = function()
+{
+ WebInspector.AuditRule.call(this, "network-gzip", "Enable gzip compression");
+}
+
+WebInspector.AuditRules.GzipRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ try {
+ var commonMessage = undefined;
+ var totalSavings = 0;
+ var compressedSize = 0
+ var candidateSize = 0
+ var outputResources = [];
+ for (var i = 0, length = resources.length; i < length; ++i) {
+ var resource = resources[i];
+ if (this._shouldCompress(resource)) {
+ var size = resource.contentLength;
+ candidateSize += size;
+ if (this._isCompressed(resource)) {
+ compressedSize += size;
+ continue;
+ }
+ if (!commonMessage)
+ commonMessage = result.appendChild("");
+ var savings = 2 * size / 3;
+ totalSavings += savings;
+ outputResources.push(
+ String.sprintf("Compressing %s could save ~%s",
+ WebInspector.linkifyURL(resource.url), Number.bytesToString(savings)));
+ }
+ }
+ if (commonMessage) {
+ commonMessage.value =
+ String.sprintf("Compressing the following resources with gzip could reduce their " +
+ "transfer size by about two thirds (~%s):", Number.bytesToString(totalSavings));
+ commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources));
+ result.score = 100 * compressedSize / candidateSize;
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ }
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ },
+
+ _isCompressed: function(resource)
+ {
+ var encoding = resource.responseHeaders["Content-Encoding"];
+ return encoding === "gzip" || encoding === "deflate";
+ },
+
+ _shouldCompress: function(resource)
+ {
+ return WebInspector.Resource.Type.isTextType(resource.type) && resource.domain && resource.contentLength !== undefined && resource.contentLength > 150;
+ }
+}
+
+WebInspector.AuditRules.GzipRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, resourceTypeName, parametersObject)
+{
+ WebInspector.AuditRule.call(this, id, name, parametersObject);
+ this._type = type;
+ this._resourceTypeName = resourceTypeName;
+}
+
+WebInspector.AuditRules.CombineExternalResourcesRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ try {
+ var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [this._type], WebInspector.URLRegExp);
+ var penalizedResourceCount = 0;
+ // TODO: refactor according to the chosen i18n approach
+ for (var domain in domainToResourcesMap) {
+ var domainResources = domainToResourcesMap[domain];
+ var extraResourceCount = domainResources.length - this.getValue("AllowedPerDomain");
+ if (extraResourceCount <= 0)
+ continue;
+ penalizedResourceCount += extraResourceCount - 1;
+ result.appendChild(
+ String.sprintf("There are %d %s files served from %s. Consider combining them into as few files as possible.",
+ domainResources.length, this._resourceTypeName, domain));
+ }
+ result.score = 100 - (penalizedResourceCount * this.getValue("ScorePerResource"));
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+};
+
+WebInspector.AuditRules.CombineExternalResourcesRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CombineJsResourcesRule = function(parametersObject) {
+ WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externaljs", "Combine external JavaScript", WebInspector.Resource.Type.Script, "JS", parametersObject);
+}
+
+WebInspector.AuditRules.CombineJsResourcesRule.prototype.__proto__ = WebInspector.AuditRules.CombineExternalResourcesRule.prototype;
+
+
+WebInspector.AuditRules.CombineCssResourcesRule = function(parametersObject) {
+ WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externalcss", "Combine external CSS", WebInspector.Resource.Type.Stylesheet, "CSS", parametersObject);
+}
+
+WebInspector.AuditRules.CombineCssResourcesRule.prototype.__proto__ = WebInspector.AuditRules.CombineExternalResourcesRule.prototype;
+
+
+WebInspector.AuditRules.MinimizeDnsLookupsRule = function(parametersObject) {
+ WebInspector.AuditRule.call(this, "network-minimizelookups", "Minimize DNS lookups", parametersObject);
+}
+
+WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ try {
+ var violationDomains = [];
+ var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, undefined, WebInspector.URLRegExp);
+ for (var domain in domainToResourcesMap) {
+ if (domainToResourcesMap[domain].length > 1)
+ continue;
+ var match = domain.match(WebInspector.URLRegExp);
+ if (!match)
+ continue;
+ if (!match[2].search(WebInspector.AuditRules.IPAddressRegexp))
+ continue; // an IP address
+ violationDomains.push(match[2]);
+ }
+ if (violationDomains.length <= this.getValue("HostCountThreshold"))
+ return;
+ var commonMessage = result.appendChild(
+ "The following domains only serve one resource each. If possible, avoid the extra DNS " +
+ "lookups by serving these resources from existing domains.");
+ commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(violationDomains));
+ result.score = 100 - violationDomains.length * this.getValue("ViolationDomainScore");
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+}
+
+WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.ParallelizeDownloadRule = function(parametersObject)
+{
+ WebInspector.AuditRule.call(this, "network-parallelizehosts", "Parallelize downloads across hostnames", parametersObject);
+}
+
+
+WebInspector.AuditRules.ParallelizeDownloadRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ function hostSorter(a, b)
+ {
+ var aCount = domainToResourcesMap[a].length;
+ var bCount = domainToResourcesMap[b].length;
+ return (aCount < bCount) ? 1 : (aCount == bCount) ? 0 : -1;
+ }
+
+ try {
+ var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(
+ resources,
+ [WebInspector.Resource.Type.Stylesheet, WebInspector.Resource.Type.Image],
+ WebInspector.URLRegExp,
+ true);
+
+ var hosts = [];
+ for (var url in domainToResourcesMap)
+ hosts.push(url);
+
+ if (!hosts.length)
+ return; // no hosts (local file or something)
+
+ hosts.sort(hostSorter);
+
+ var optimalHostnameCount = this.getValue("OptimalHostnameCount");
+ if (hosts.length > optimalHostnameCount)
+ hosts.splice(optimalHostnameCount);
+
+ var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
+ var resourceCountAboveThreshold = busiestHostResourceCount - this.getValue("MinRequestThreshold");
+ if (resourceCountAboveThreshold <= 0)
+ return;
+
+ var avgResourcesPerHost = 0;
+ for (var i = 0, size = hosts.length; i < size; ++i)
+ avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
+
+ // Assume optimal parallelization.
+ avgResourcesPerHost /= optimalHostnameCount;
+
+ avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
+
+ var pctAboveAvg = (resourceCountAboveThreshold / avgResourcesPerHost) - 1.0;
+
+ var minBalanceThreshold = this.getValue("MinBalanceThreshold");
+ if (pctAboveAvg < minBalanceThreshold) {
+ result.score = 100;
+ return;
+ }
+
+ result.score = (1 - (pctAboveAvg - minBalanceThreshold)) * 100;
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+
+ var resourcesOnBusiestHost = domainToResourcesMap[hosts[0]];
+ var commonMessage = result.appendChild(
+ String.sprintf("This page makes %d parallelizable requests to %s" +
+ ". Increase download parallelization by distributing the following" +
+ " requests across multiple hostnames.", busiestHostResourceCount, hosts[0]));
+ var outputResources = [];
+ for (var i = 0, size = resourcesOnBusiestHost.length; i < size; ++i)
+ outputResources.push(resourcesOnBusiestHost[i].url);
+ commonMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources, true));
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+}
+
+WebInspector.AuditRules.ParallelizeDownloadRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+// The reported CSS rule size is incorrect (parsed != original in WebKit),
+// so use percentages instead, which gives a better approximation.
+WebInspector.AuditRules.UnusedCssRule = function(parametersObject)
+{
+ WebInspector.AuditRule.call(this, "page-unusedcss", "Remove unused CSS", parametersObject);
+}
+
+WebInspector.AuditRules.UnusedCssRule.prototype = {
+ _getUnusedStylesheetRatioMessage: function(unusedLength, type, location, styleSheetLength)
+ {
+ var url = type === "href"
+ ? WebInspector.linkifyURL(location)
+ : String.sprintf("Inline block #%s", location);
+ var pctUnused = Math.round(unusedLength / styleSheetLength * 100);
+ return String.sprintf("%s: %f%% (estimated) is not used by the current page.", url, pctUnused);
+ },
+
+ _getUnusedTotalRatioMessage: function(unusedLength, totalLength)
+ {
+ var pctUnused = Math.round(unusedLength / totalLength * 100);
+ return String.sprintf("%d%% of CSS (estimated) is not used by the current page.", pctUnused);
+ },
+
+ doRun: function(resources, result, callback)
+ {
+ var self = this;
+ function evalCallback(evalResult, isException) {
+ try {
+ if (isException)
+ return;
+
+ var totalLength = 0;
+ var totalUnusedLength = 0;
+ var topMessage;
+ var styleSheetMessage;
+ for (var i = 0; i < evalResult.length; ) {
+ var type = evalResult[i++];
+ if (type === "totalLength") {
+ totalLength = evalResult[i++];
+ continue;
+ }
+
+ var styleSheetLength = evalResult[i++];
+ var location = evalResult[i++];
+ var unusedRules = evalResult[i++];
+ styleSheetMessage = undefined;
+ if (!topMessage)
+ topMessage = result.appendChild("");
+
+ var totalUnusedRuleLength = 0;
+ var ruleSelectors = [];
+ for (var j = 0; j < unusedRules.length; ++j) {
+ var rule = unusedRules[j];
+ totalUnusedRuleLength += parseInt(rule[1]);
+ if (!styleSheetMessage)
+ styleSheetMessage = result.appendChild("");
+ ruleSelectors.push(rule[0]);
+ }
+ styleSheetMessage.appendChild(WebInspector.AuditRules.arrayAsUL(ruleSelectors));
+
+ styleSheetMessage.value = self._getUnusedStylesheetRatioMessage(totalUnusedRuleLength, type, location, styleSheetLength);
+ totalUnusedLength += totalUnusedRuleLength;
+ }
+ if (totalUnusedLength) {
+ var totalUnusedPercent = totalUnusedLength / totalLength;
+ topMessage.value = self._getUnusedTotalRatioMessage(totalUnusedLength, totalLength);
+ var pctMultiplier = Math.log(Math.max(200, totalUnusedLength - 800)) / 7 - 0.6;
+ result.score = (1 - totalUnusedPercent * pctMultiplier) * 100;
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ } else
+ result.score = 100;
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+
+ function routine()
+ {
+ var styleSheets = document.styleSheets;
+ if (!styleSheets)
+ return {};
+ var styleSheetToUnusedRules = [];
+ var inlineBlockOrdinal = 0;
+ var totalCSSLength = 0;
+ var pseudoSelectorRegexp = /:hover|:link|:active|:visited|:focus/;
+ for (var i = 0; i < styleSheets.length; ++i) {
+ var styleSheet = styleSheets[i];
+ if (!styleSheet.cssRules)
+ continue;
+ var currentStyleSheetSize = 0;
+ var unusedRules = [];
+ for (var curRule = 0; curRule < styleSheet.cssRules.length; ++curRule) {
+ var rule = styleSheet.cssRules[curRule];
+ var textLength = rule.cssText ? rule.cssText.length : 0;
+ currentStyleSheetSize += textLength;
+ totalCSSLength += textLength;
+ if (rule.type !== 1 || rule.selectorText.match(pseudoSelectorRegexp))
+ continue;
+ var nodes = document.querySelectorAll(rule.selectorText);
+ if (nodes && nodes.length)
+ continue;
+ unusedRules.push([rule.selectorText, textLength]);
+ }
+ if (unusedRules.length) {
+ styleSheetToUnusedRules.push(styleSheet.href ? "href" : "inline");
+ styleSheetToUnusedRules.push(currentStyleSheetSize);
+ styleSheetToUnusedRules.push(styleSheet.href ? styleSheet.href : ++inlineBlockOrdinal);
+ styleSheetToUnusedRules.push(unusedRules);
+ }
+ }
+ styleSheetToUnusedRules.push("totalLength");
+ styleSheetToUnusedRules.push(totalCSSLength);
+ return styleSheetToUnusedRules;
+ }
+
+ WebInspector.AuditRules.evaluateInTargetWindow(routine, evalCallback);
+ }
+}
+
+WebInspector.AuditRules.UnusedCssRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CacheControlRule = function(id, name, parametersObject)
+{
+ WebInspector.AuditRule.call(this, id, name, parametersObject);
+}
+
+WebInspector.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 * 30;
+
+WebInspector.AuditRules.CacheControlRule.prototype = {
+
+ InfoCheck: -1,
+ FailCheck: 0,
+ WarningCheck: 1,
+ SevereCheck: 2,
+
+ doRun: function(resources, result, callback)
+ {
+ try {
+ var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(resources);
+ if (cacheableAndNonCacheableResources[0].length) {
+ result.score = 100;
+ this.runChecks(cacheableAndNonCacheableResources[0], result);
+ }
+ this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ },
+
+ handleNonCacheableResources: function()
+ {
+ },
+
+ _cacheableAndNonCacheableResources: function(resources)
+ {
+ var processedResources = [[], []];
+ for (var i = 0; i < resources.length; ++i) {
+ var resource = resources[i];
+ if (!this.isCacheableResource(resource))
+ continue;
+ if (this._isExplicitlyNonCacheable(resource))
+ processedResources[1].push(resource);
+ else
+ processedResources[0].push(resource);
+ }
+ return processedResources;
+ },
+
+ execCheck: function(messageText, resourceCheckFunction, resources, severity, result)
+ {
+ var topMessage;
+ var failingResources = 0;
+ var resourceCount = resources.length;
+ var outputResources = [];
+ for (var i = 0; i < resourceCount; ++i) {
+ if (resourceCheckFunction.call(this, resources[i])) {
+ ++failingResources;
+ if (!topMessage)
+ topMessage = result.appendChild(messageText);
+ outputResources.push(resources[i].url);
+ }
+ }
+ if (topMessage)
+ topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources, true));
+ if (failingResources) {
+ switch (severity) {
+ case this.FailCheck:
+ result.score = 0;
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ break;
+ case this.SevereCheck:
+ case this.WarningCheck:
+ result.score -= 50 * severity * failingResources / resourceCount;
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ break;
+ }
+ }
+ return topMessage;
+ },
+
+ freshnessLifetimeGreaterThan: function(resource, timeMs)
+ {
+ var dateHeader = this.responseHeader(resource, "Date");
+ if (!dateHeader)
+ return false;
+
+ var dateHeaderMs = Date.parse(dateHeader);
+ if (isNaN(dateHeaderMs))
+ return false;
+
+ var freshnessLifetimeMs;
+ var maxAgeMatch = this.responseHeaderMatch(resource, "Cache-Control", "max-age=(\\d+)");
+
+ if (maxAgeMatch)
+ freshnessLifetimeMs = (maxAgeMatch[1]) ? 1000 * maxAgeMatch[1] : 0;
+ else {
+ var expiresHeader = this.responseHeader(resource, "Expires");
+ if (expiresHeader) {
+ var expDate = Date.parse(expiresHeader);
+ if (!isNaN(expDate))
+ freshnessLifetimeMs = expDate - dateHeaderMs;
+ }
+ }
+
+ return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs;
+ },
+
+ responseHeader: function(resource, header)
+ {
+ return resource.responseHeaders[header];
+ },
+
+ hasResponseHeader: function(resource, header)
+ {
+ return resource.responseHeaders[header] !== undefined;
+ },
+
+ isCompressible: function(resource)
+ {
+ return WebInspector.Resource.Type.isTextType(resource.type);
+ },
+
+ isPubliclyCacheable: function(resource)
+ {
+ if (this._isExplicitlyNonCacheable(resource))
+ return false;
+
+ if (this.responseHeaderMatch(resource, "Cache-Control", "public"))
+ return true;
+
+ return resource.url.indexOf("?") == -1 && !this.responseHeaderMatch(resource, "Cache-Control", "private");
+ },
+
+ responseHeaderMatch: function(resource, header, regexp)
+ {
+ return resource.responseHeaders[header]
+ ? resource.responseHeaders[header].match(new RegExp(regexp, "im"))
+ : undefined;
+ },
+
+ hasExplicitExpiration: function(resource)
+ {
+ return this.hasResponseHeader(resource, "Date") &&
+ (this.hasResponseHeader(resource, "Expires") || this.responseHeaderMatch(resource, "Cache-Control", "max-age"));
+ },
+
+ _isExplicitlyNonCacheable: function(resource)
+ {
+ var hasExplicitExp = this.hasExplicitExpiration(resource);
+ return this.responseHeaderMatch(resource, "Cache-Control", "(no-cache|no-store|must-revalidate)") ||
+ this.responseHeaderMatch(resource, "Pragma", "no-cache") ||
+ (hasExplicitExp && !this.freshnessLifetimeGreaterThan(resource, 0)) ||
+ (!hasExplicitExp && resource.url && resource.url.indexOf("?") >= 0) ||
+ (!hasExplicitExp && !this.isCacheableResource(resource));
+ },
+
+ isCacheableResource: function(resource)
+ {
+ return resource.statusCode !== undefined && WebInspector.AuditRules.CacheableResponseCodes[resource.statusCode];
+ }
+}
+
+WebInspector.AuditRules.CacheControlRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.BrowserCacheControlRule = function(parametersObject)
+{
+ WebInspector.AuditRules.CacheControlRule.call(this, "http-browsercache", "Leverage browser caching", parametersObject);
+}
+
+WebInspector.AuditRules.BrowserCacheControlRule.prototype = {
+ handleNonCacheableResources: function(resources, result)
+ {
+ if (resources.length) {
+ var message = result.appendChild(
+ "The following resources are explicitly non-cacheable. Consider making them cacheable if possible:");
+ var resourceOutput = [];
+ for (var i = 0; i < resources.length; ++i)
+ resourceOutput.push(resources[i].url);
+ message.appendChild(WebInspector.AuditRules.arrayAsUL(resourceOutput, true));
+ }
+ },
+
+ runChecks: function(resources, result, callback)
+ {
+ this.execCheck(
+ "The following resources are missing a cache expiration." +
+ " Resources that do not specify an expiration may not be" +
+ " cached by browsers:",
+ this._missingExpirationCheck, resources, this.SevereCheck, result);
+ this.execCheck(
+ "The following resources specify a \"Vary\" header that" +
+ " disables caching in most versions of Internet Explorer:",
+ this._varyCheck, resources, this.SevereCheck, result);
+ this.execCheck(
+ "The following cacheable resources have a short" +
+ " freshness lifetime:",
+ this._oneMonthExpirationCheck, resources, this.WarningCheck, result);
+
+ // Unable to implement the favicon check due to the WebKit limitations.
+
+ this.execCheck(
+ "To further improve cache hit rate, specify an expiration" +
+ " one year in the future for the following cacheable" +
+ " resources:",
+ this._oneYearExpirationCheck, resources, this.InfoCheck, result);
+ },
+
+ _missingExpirationCheck: function(resource)
+ {
+ return this.isCacheableResource(resource) && !this.hasResponseHeader(resource, "Set-Cookie") && !this.hasExplicitExpiration(resource);
+ },
+
+ _varyCheck: function(resource)
+ {
+ var varyHeader = this.responseHeader(resource, "Vary");
+ if (varyHeader) {
+ varyHeader = varyHeader.replace(/User-Agent/gi, "");
+ varyHeader = varyHeader.replace(/Accept-Encoding/gi, "");
+ varyHeader = varyHeader.replace(/[, ]*/g, "");
+ }
+ return varyHeader && varyHeader.length && this.isCacheableResource(resource) && this.freshnessLifetimeGreaterThan(resource, 0);
+ },
+
+ _oneMonthExpirationCheck: function(resource)
+ {
+ return this.isCacheableResource(resource) &&
+ !this.hasResponseHeader(resource, "Set-Cookie") &&
+ !this.freshnessLifetimeGreaterThan(resource, WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
+ this.freshnessLifetimeGreaterThan(resource, 0);
+ },
+
+ _oneYearExpirationCheck: function(resource)
+ {
+ return this.isCacheableResource(resource) &&
+ !this.hasResponseHeader(resource, "Set-Cookie") &&
+ !this.freshnessLifetimeGreaterThan(resource, 11 * WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
+ this.freshnessLifetimeGreaterThan(resource, WebInspector.AuditRules.CacheControlRule.MillisPerMonth);
+ }
+}
+
+WebInspector.AuditRules.BrowserCacheControlRule.prototype.__proto__ = WebInspector.AuditRules.CacheControlRule.prototype;
+
+
+WebInspector.AuditRules.ProxyCacheControlRule = function(parametersObject) {
+ WebInspector.AuditRules.CacheControlRule.call(this, "http-proxycache", "Leverage proxy caching", parametersObject);
+}
+
+WebInspector.AuditRules.ProxyCacheControlRule.prototype = {
+ runChecks: function(resources, result, callback)
+ {
+ this.execCheck(
+ "Resources with a \"?\" in the URL are not cached by most" +
+ " proxy caching servers:",
+ this._questionMarkCheck, resources, this.WarningCheck, result);
+ this.execCheck(
+ "Consider adding a \"Cache-Control: public\" header to the" +
+ " following resources:",
+ this._publicCachingCheck, resources, this.InfoCheck, result);
+ this.execCheck(
+ "The following publicly cacheable resources contain" +
+ " a Set-Cookie header. This security vulnerability" +
+ " can cause cookies to be shared by multiple users.",
+ this._setCookieCacheableCheck, resources, this.FailCheck, result);
+ },
+
+ _questionMarkCheck: function(resource)
+ {
+ return resource.url.indexOf("?") >= 0 && !this.hasResponseHeader(resource, "Set-Cookie") && this.isPubliclyCacheable(resource);
+ },
+
+ _publicCachingCheck: function(resource)
+ {
+ return this.isCacheableResource(resource) &&
+ !this.isCompressible(resource) &&
+ !this.responseHeaderMatch(resource, "Cache-Control", "public") &&
+ !this.hasResponseHeader(resource, "Set-Cookie");
+ },
+
+ _setCookieCacheableCheck: function(resource)
+ {
+ return this.hasResponseHeader(resource, "Set-Cookie") && this.isPubliclyCacheable(resource);
+ }
+}
+
+WebInspector.AuditRules.ProxyCacheControlRule.prototype.__proto__ = WebInspector.AuditRules.CacheControlRule.prototype;
+
+
+WebInspector.AuditRules.ImageDimensionsRule = function(parametersObject)
+{
+ WebInspector.AuditRule.call(this, "page-imagedims", "Specify image dimensions", parametersObject);
+}
+
+WebInspector.AuditRules.ImageDimensionsRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ function evalCallback(evalResult, isException)
+ {
+ try {
+ if (isException)
+ return;
+ if (!evalResult || !evalResult.totalImages)
+ return;
+ result.score = 100;
+ var topMessage = result.appendChild(
+ "A width and height should be specified for all images in order to " +
+ "speed up page display. The following image(s) are missing a width and/or height:");
+ var map = evalResult.map;
+ var outputResources = [];
+ for (var url in map) {
+ var value = WebInspector.linkifyURL(url);
+ if (map[url] > 1)
+ value += " (" + map[url] + " uses)";
+ outputResources.push(value);
+ result.score -= this.getValue("ScorePerImageUse") * map[url];
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ }
+ topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputResources));
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+
+ function routine()
+ {
+ var images = document.getElementsByTagName("img");
+ const widthRegExp = /width[^:;]*:/gim;
+ const heightRegExp = /height[^:;]*:/gim;
+
+ function hasDimension(element, cssText, rules, regexp, attributeName) {
+ if (element.attributes.getNamedItem(attributeName) != null || (cssText && cssText.match(regexp)))
+ return true;
+
+ if (!rules)
+ return false;
+ for (var i = 0; i < rules.length; ++i) {
+ if (rules.item(i).style.cssText.match(regexp))
+ return true;
+ }
+ return false;
+ }
+
+ function hasWidth(element, cssText, rules) {
+ return hasDimension(element, cssText, rules, widthRegExp, "width");
+ }
+
+ function hasHeight(element, cssText, rules) {
+ return hasDimension(element, cssText, rules, heightRegExp, "height");
+ }
+
+ var urlToNoDimensionCount = {};
+ var found = false;
+ for (var i = 0; i < images.length; ++i) {
+ var image = images[i];
+ if (!image.src)
+ continue;
+ var position = document.defaultView.getComputedStyle(image).getPropertyValue("position");
+ if (position === "absolute")
+ continue;
+ var cssText = (image.style && image.style.cssText) ? image.style.cssText : "";
+ var rules = document.defaultView.getMatchedCSSRules(image, "", true);
+ if (!hasWidth(image, cssText, rules) || !hasHeight(image, cssText, rules)) {
+ found = true;
+ if (urlToNoDimensionCount.hasOwnProperty(image.src))
+ ++urlToNoDimensionCount[image.src];
+ else
+ urlToNoDimensionCount[image.src] = 1;
+ }
+ }
+ return found ? {totalImages: images.length, map: urlToNoDimensionCount} : null;
+ }
+
+ WebInspector.AuditRules.evaluateInTargetWindow(routine, evalCallback.bind(this));
+ }
+}
+
+WebInspector.AuditRules.ImageDimensionsRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CssInHeadRule = function(parametersObject)
+{
+ WebInspector.AuditRule.call(this, "page-cssinhead", "Put CSS in the document head", parametersObject);
+}
+
+WebInspector.AuditRules.CssInHeadRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ function evalCallback(evalResult, isException)
+ {
+ try {
+ if (isException)
+ return;
+ if (!evalResult)
+ return;
+ result.score = 100;
+ var outputMessages = [];
+ for (var url in evalResult) {
+ var urlViolations = evalResult[url];
+ var topMessage = result.appendChild(
+ String.sprintf("CSS in the %s document body adversely impacts rendering performance.",
+ WebInspector.linkifyURL(url)));
+ if (urlViolations[0]) {
+ outputMessages.push(
+ String.sprintf("%s style block(s) in the body should be moved to the document head.", urlViolations[0]));
+ result.score -= this.getValue("InlineURLScore") * urlViolations[0];
+ }
+ for (var i = 0; i < urlViolations[1].length; ++i) {
+ outputMessages.push(
+ String.sprintf("Link node %s should be moved to the document head", WebInspector.linkifyURL(urlViolations[1])));
+ }
+ result.score -= this.getValue("InlineStylesheetScore") * urlViolations[1];
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ }
+ topMessage.appendChild(WebInspector.AuditRules.arrayAsUL(outputMessages));
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+
+ function routine()
+ {
+ function allViews() {
+ var views = [document.defaultView];
+ var curView = 0;
+ while (curView < views.length) {
+ var view = views[curView];
+ var frames = view.frames;
+ for (var i = 0; i < frames.length; ++i) {
+ if (frames[i] !== view)
+ views.push(frames[i]);
+ }
+ ++curView;
+ }
+ return views;
+ }
+
+ var views = allViews();
+ var urlToViolationsArray = {};
+ var found = false;
+ for (var i = 0; i < views.length; ++i) {
+ var view = views[i];
+ if (!view.document)
+ continue;
+
+ var inlineStyles = view.document.querySelectorAll("body style");
+ var inlineStylesheets = view.document.querySelectorAll(
+ "body link[rel~='stylesheet'][href]");
+ if (!inlineStyles.length && !inlineStylesheets.length)
+ continue;
+
+ found = true;
+ var inlineStylesheetHrefs = [];
+ for (var j = 0; j < inlineStylesheets.length; ++j)
+ inlineStylesheetHrefs.push(inlineStylesheets[j].href);
+
+ urlToViolationsArray[view.location.href] =
+ [inlineStyles.length, inlineStylesheetHrefs];
+ }
+ return found ? urlToViolationsArray : null;
+ }
+
+ WebInspector.AuditRules.evaluateInTargetWindow(routine, evalCallback);
+ }
+}
+
+WebInspector.AuditRules.CssInHeadRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.StylesScriptsOrderRule = function(parametersObject)
+{
+ WebInspector.AuditRule.call(this, "page-stylescriptorder", "Optimize the order of styles and scripts", parametersObject);
+}
+
+WebInspector.AuditRules.StylesScriptsOrderRule.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ function evalCallback(evalResult, isException)
+ {
+ try {
+ if (isException)
+ return;
+ if (!evalResult)
+ return;
+
+ result.score = 100;
+ var lateCssUrls = evalResult['late'];
+ if (lateCssUrls) {
+ var lateMessage = result.appendChild(
+ 'The following external CSS files were included after ' +
+ 'an external JavaScript file in the document head. To ' +
+ 'ensure CSS files are downloaded in parallel, always ' +
+ 'include external CSS before external JavaScript.');
+ lateMessage.appendChild(WebInspector.AuditRules.arrayAsUL(lateCssUrls, true));
+ result.score -= this.getValue("InlineBetweenResourcesScore") * lateCssUrls.length;
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ }
+ if (evalResult['cssBeforeInlineCount']) {
+ var count = evalResult['cssBeforeInlineCount'];
+ result.appendChild(count + ' inline script block' +
+ (count > 1 ? 's were' : ' was') + ' found in the head between an ' +
+ 'external CSS file and another resource. To allow parallel ' +
+ 'downloading, move the inline script before the external CSS ' +
+ 'file, or after the next resource.');
+ result.score -= this.getValue("CSSAfterJSURLScore") * count;
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ }
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+
+ function routine()
+ {
+ var lateStyles = document.querySelectorAll(
+ "head script[src] ~ link[rel~='stylesheet'][href]");
+ var stylesBeforeInlineScript = document.querySelectorAll(
+ "head link[rel~='stylesheet'][href] ~ script:not([src])");
+
+ var resultObject;
+ if (!lateStyles.length && !stylesBeforeInlineScript.length)
+ resultObject = null;
+ else {
+ resultObject = {};
+ if (lateStyles.length) {
+ lateStyleUrls = [];
+ for (var i = 0; i < lateStyles.length; ++i)
+ lateStyleUrls.push(lateStyles[i].href);
+ resultObject["late"] = lateStyleUrls;
+ }
+ resultObject["cssBeforeInlineCount"] = stylesBeforeInlineScript.length;
+ }
+ return resultObject;
+ }
+
+ WebInspector.AuditRules.evaluateInTargetWindow(routine, evalCallback.bind(this));
+ }
+}
+
+WebInspector.AuditRules.StylesScriptsOrderRule.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CookieRuleBase = function(id, name, parametersObject)
+{
+ WebInspector.AuditRule.call(this, id, name, parametersObject);
+}
+
+WebInspector.AuditRules.CookieRuleBase.prototype = {
+ doRun: function(resources, result, callback)
+ {
+ var self = this;
+ function resultCallback(receivedCookies, isAdvanced) {
+ try {
+ self.processCookies(isAdvanced ? receivedCookies : [], resources, result);
+ } catch(e) {
+ console.log(e);
+ } finally {
+ callback(result);
+ }
+ }
+ WebInspector.Cookies.getCookiesAsync(resultCallback);
+ },
+
+ mapResourceCookies: function(resourcesByDomain, allCookies, callback)
+ {
+ for (var i = 0; i < allCookies.length; ++i) {
+ for (var resourceDomain in resourcesByDomain) {
+ if (WebInspector.Cookies.cookieDomainMatchesResourceDomain(allCookies[i].domain, resourceDomain))
+ this._callbackForResourceCookiePairs(resourcesByDomain[resourceDomain], allCookies[i], callback);
+ }
+ }
+ },
+
+ _callbackForResourceCookiePairs: function(resources, cookie, callback)
+ {
+ if (!resources)
+ return;
+ for (var i = 0; i < resources.length; ++i) {
+ if (WebInspector.Cookies.cookieMatchesResourceURL(cookie, resources[i].url))
+ callback(resources[i], cookie);
+ }
+ }
+}
+
+WebInspector.AuditRules.CookieRuleBase.prototype.__proto__ = WebInspector.AuditRule.prototype;
+
+
+WebInspector.AuditRules.CookieSizeRule = function(parametersObject)
+{
+ WebInspector.AuditRules.CookieRuleBase.call(this, "http-cookiesize", "Minimize cookie size", parametersObject);
+}
+
+WebInspector.AuditRules.CookieSizeRule.prototype = {
+ _average: function(cookieArray)
+ {
+ var total = 0;
+ for (var i = 0; i < cookieArray.length; ++i)
+ total += cookieArray[i].size;
+ return cookieArray.length ? Math.round(total / cookieArray.length) : 0;
+ },
+
+ _max: function(cookieArray)
+ {
+ var result = 0;
+ for (var i = 0; i < cookieArray.length; ++i)
+ result = Math.max(cookieArray[i].size, result);
+ return result;
+ },
+
+ processCookies: function(allCookies, resources, result)
+ {
+ function maxSizeSorter(a, b)
+ {
+ return b.maxCookieSize - a.maxCookieSize;
+ }
+
+ function avgSizeSorter(a, b)
+ {
+ return b.avgCookieSize - a.avgCookieSize;
+ }
+
+ var cookiesPerResourceDomain = {};
+
+ function collectorCallback(resource, cookie)
+ {
+ var cookies = cookiesPerResourceDomain[resource.domain];
+ if (!cookies) {
+ cookies = [];
+ cookiesPerResourceDomain[resource.domain] = cookies;
+ }
+ cookies.push(cookie);
+ }
+
+ if (!allCookies.length)
+ return;
+
+ var sortedCookieSizes = [];
+
+ var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources,
+ null,
+ WebInspector.URLRegExp,
+ true);
+ var matchingResourceData = {};
+ this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback.bind(this));
+
+ result.score = 100;
+ for (var resourceDomain in cookiesPerResourceDomain) {
+ var cookies = cookiesPerResourceDomain[resourceDomain];
+ sortedCookieSizes.push({
+ domain: resourceDomain,
+ avgCookieSize: this._average(cookies),
+ maxCookieSize: this._max(cookies)
+ });
+ }
+ var avgAllCookiesSize = this._average(allCookies);
+
+ var hugeCookieDomains = [];
+ sortedCookieSizes.sort(maxSizeSorter);
+
+ var maxBytesThreshold = this.getValue("MaxBytesThreshold");
+ var minBytesThreshold = this.getValue("MinBytesThreshold");
+
+ for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
+ var maxCookieSize = sortedCookieSizes[i].maxCookieSize;
+ if (maxCookieSize > maxBytesThreshold)
+ hugeCookieDomains.push(sortedCookieSizes[i].domain + ": " + Number.bytesToString(maxCookieSize));
+ }
+
+ var bigAvgCookieDomains = [];
+ sortedCookieSizes.sort(avgSizeSorter);
+ for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
+ var domain = sortedCookieSizes[i].domain;
+ var avgCookieSize = sortedCookieSizes[i].avgCookieSize;
+ if (avgCookieSize > minBytesThreshold && avgCookieSize < maxBytesThreshold)
+ bigAvgCookieDomains.push(domain + ": " + Number.bytesToString(avgCookieSize));
+ }
+ result.appendChild("The average cookie size for all requests on this page is " + Number.bytesToString(avgAllCookiesSize));
+
+ var message;
+ if (hugeCookieDomains.length) {
+ result.score = 75;
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ message = result.appendChild(
+ String.sprintf("The following domains have a cookie size in excess of %d " +
+ " bytes. This is harmful because requests with cookies larger than 1KB" +
+ " typically cannot fit into a single network packet.", maxBytesThreshold));
+ message.appendChild(WebInspector.AuditRules.arrayAsUL(hugeCookieDomains));
+ }
+
+ if (bigAvgCookieDomains.length) {
+ this.score -= Math.max(0, avgAllCookiesSize - minBytesThreshold) /
+ (minBytesThreshold - minBytesThreshold) / this.getValue("TotalPoints");
+ if (!result.type)
+ result.type = WebInspector.AuditRuleResult.Type.Hint;
+ message = result.appendChild(
+ String.sprintf("The following domains have an average cookie size in excess of %d" +
+ " bytes. Reducing the size of cookies" +
+ " for these domains can reduce the time it takes to send requests.", minBytesThreshold));
+ message.appendChild(WebInspector.AuditRules.arrayAsUL(bigAvgCookieDomains));
+ }
+
+ if (!bigAvgCookieDomains.length && !hugeCookieDomains.length)
+ result.score = WebInspector.AuditCategoryResult.ScoreNA;
+ }
+}
+
+WebInspector.AuditRules.CookieSizeRule.prototype.__proto__ = WebInspector.AuditRules.CookieRuleBase.prototype;
+
+
+WebInspector.AuditRules.StaticCookielessRule = function(parametersObject)
+{
+ WebInspector.AuditRules.CookieRuleBase.call(this, "http-staticcookieless", "Serve static content from a cookieless domain", parametersObject);
+}
+
+WebInspector.AuditRules.StaticCookielessRule.prototype = {
+ processCookies: function(allCookies, resources, result)
+ {
+ var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources,
+ [WebInspector.Resource.Type.Stylesheet,
+ WebInspector.Resource.Type.Image],
+ WebInspector.URLRegExp,
+ true);
+ var totalStaticResources = 0;
+ var minResources = this.getValue("MinResources");
+ for (var domain in domainToResourcesMap)
+ totalStaticResources += domainToResourcesMap[domain].length;
+ if (totalStaticResources < minResources)
+ return;
+ var matchingResourceData = {};
+ this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCallback.bind(this, matchingResourceData));
+
+ var badUrls = [];
+ var cookieBytes = 0;
+ for (var url in matchingResourceData) {
+ badUrls.push(url);
+ cookieBytes += matchingResourceData[url]
+ }
+ if (badUrls.length < minResources)
+ return;
+
+ result.score = 100;
+ var badPoints = cookieBytes / 75;
+ var violationPct = Math.max(badUrls.length / totalStaticResources, 0.6);
+ badPoints *= violationPct;
+ result.score -= badPoints;
+ result.score = Math.max(result.score, 0);
+ result.type = WebInspector.AuditRuleResult.Type.Violation;
+ result.appendChild(String.sprintf("%s of cookies were sent with the following static resources.", Number.bytesToString(cookieBytes)));
+ var message = result.appendChild("Serve these static resources from a domain that does not set cookies:");
+ message.appendChild(WebInspector.AuditRules.arrayAsUL(badUrls, true));
+ },
+
+ _collectorCallback: function(matchingResourceData, resource, cookie)
+ {
+ matchingResourceData[resource.url] = (matchingResourceData[resource.url] || 0) + cookie.size;
+ }
+}
+
+WebInspector.AuditRules.StaticCookielessRule.prototype.__proto__ = WebInspector.AuditRules.CookieRuleBase.prototype;
diff --git a/WebCore/inspector/front-end/AuditsPanel.js b/WebCore/inspector/front-end/AuditsPanel.js
index 696d132..fcadb82 100644
--- a/WebCore/inspector/front-end/AuditsPanel.js
+++ b/WebCore/inspector/front-end/AuditsPanel.js
@@ -105,7 +105,8 @@ WebInspector.AuditsPanel.prototype = {
this._auditCategoriesById = {};
for (var categoryCtorID in WebInspector.AuditCategories) {
var auditCategory = new WebInspector.AuditCategories[categoryCtorID]();
- this.categoriesById[auditCategory.id] = auditCategory;
+ auditCategory._id = categoryCtorID;
+ this.categoriesById[categoryCtorID] = auditCategory;
}
},
@@ -185,15 +186,13 @@ WebInspector.AuditsPanel.prototype = {
_reloadResources: function(callback)
{
- function nullCallback()
- {
- }
this._resourceTrackingCallback = callback;
+
if (!InspectorBackend.resourceTrackingEnabled()) {
InspectorBackend.enableResourceTracking(false);
- this._updateLauncherViewControls();
+ this._updateLauncherViewControls(true);
} else
- InjectedScriptAccess.getDefault().evaluate("window.location.reload()", nullCallback);
+ InjectedScriptAccess.getDefault().evaluate("window.location.reload()", switchCallback);
},
_didMainResourceLoad: function()
@@ -239,7 +238,7 @@ WebInspector.AuditsPanel.prototype = {
WebInspector.Panel.prototype.show.call(this);
this.showView();
- this._updateLauncherViewControls();
+ this._updateLauncherViewControls(InspectorBackend.resourceTrackingEnabled());
},
attach: function()
@@ -254,10 +253,10 @@ WebInspector.AuditsPanel.prototype = {
this.viewsContainerElement.style.left = width + "px";
},
- _updateLauncherViewControls: function()
+ _updateLauncherViewControls: function(isTracking)
{
if (this._launcherView)
- this._launcherView.updateResourceTrackingState();
+ this._launcherView.updateResourceTrackingState(isTracking);
},
_clearButtonClicked: function()
@@ -278,9 +277,8 @@ WebInspector.AuditsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
-WebInspector.AuditCategory = function(id, displayName)
+WebInspector.AuditCategory = function(displayName)
{
- this._id = id;
this._displayName = displayName;
this._rules = [];
}
@@ -288,6 +286,7 @@ WebInspector.AuditCategory = function(id, displayName)
WebInspector.AuditCategory.prototype = {
get id()
{
+ // this._id value is injected at construction time.
return this._id;
},
@@ -298,6 +297,7 @@ WebInspector.AuditCategory.prototype = {
get ruleCount()
{
+ this._ensureInitialized();
return this._rules.length;
},
@@ -308,8 +308,18 @@ WebInspector.AuditCategory.prototype = {
runRules: function(resources, callback)
{
+ this._ensureInitialized();
for (var i = 0; i < this._rules.length; ++i)
this._rules[i].run(resources, callback);
+ },
+
+ _ensureInitialized: function()
+ {
+ if (!this._initialized) {
+ if ("initialize" in this)
+ this.initialize();
+ this._initialized = true;
+ }
}
}
@@ -354,7 +364,6 @@ WebInspector.AuditRule.prototype = {
WebInspector.AuditCategoryResult = function(category)
{
- this.categoryId = category.id;
this.title = category.displayName;
this.entries = [];
}
@@ -378,8 +387,13 @@ WebInspector.AuditRuleResult = function(value)
}
WebInspector.AuditRuleResult.Type = {
+ // Does not denote a discovered flaw but rather represents an informational message.
NA: 0,
+
+ // Denotes a minor impact on the checked metric.
Hint: 1,
+
+ // Denotes a major impact on the checked metric.
Violation: 2
}
diff --git a/WebCore/inspector/front-end/CookieItemsView.js b/WebCore/inspector/front-end/CookieItemsView.js
index b31b7ea..b5674b8 100644
--- a/WebCore/inspector/front-end/CookieItemsView.js
+++ b/WebCore/inspector/front-end/CookieItemsView.js
@@ -27,7 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-WebInspector.CookieItemsView = function(cookieDomain)
+WebInspector.CookieItemsView = function(treeElement, cookieDomain)
{
WebInspector.View.call(this);
@@ -41,7 +41,13 @@ WebInspector.CookieItemsView = function(cookieDomain)
this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
+ this._treeElement = treeElement;
this._cookieDomain = cookieDomain;
+
+ this._emptyMsgElement = document.createElement("div");
+ this._emptyMsgElement.className = "storage-table-empty";
+ this._emptyMsgElement.textContent = WebInspector.UIString("This site has no cookies.");
+ this.element.appendChild(this._emptyMsgElement);
}
WebInspector.CookieItemsView.prototype = {
@@ -53,7 +59,7 @@ WebInspector.CookieItemsView.prototype = {
show: function(parentElement)
{
WebInspector.View.prototype.show.call(this, parentElement);
- this.update();
+ this._update();
},
hide: function()
@@ -62,37 +68,57 @@ WebInspector.CookieItemsView.prototype = {
this.deleteButton.visible = false;
},
- update: function()
+ _update: function()
{
- this.element.removeChildren();
-
- var self = this;
- function callback(allCookies, isAdvanced) {
- var cookies = self._cookiesForDomain(allCookies);
- var dataGrid = (isAdvanced ? self.dataGridForCookies(cookies) : self.simpleDataGridForCookies(cookies));
- if (dataGrid) {
- self._dataGrid = dataGrid;
- self.element.appendChild(dataGrid.element);
- self._dataGrid.updateWidths();
- if (isAdvanced)
- self.deleteButton.visible = true;
+ WebInspector.Cookies.getCookiesAsync(this._updateWithCookies.bind(this));
+ },
+
+ _updateWithCookies: function(allCookies, isAdvanced)
+ {
+ if (isAdvanced)
+ this._filterCookiesForDomain(allCookies);
+ else
+ this._cookies = allCookies;
+
+ if (!this._cookies.length) {
+ // Nothing to show.
+ this._emptyMsgElement.removeStyleClass("hidden");
+ this.deleteButton.visible = false;
+ if (this._dataGrid)
+ this._dataGrid.element.addStyleClass("hidden");
+ return;
+ }
+
+ if (!this._dataGrid) {
+ if (isAdvanced) {
+ this._createDataGrid();
+ this._populateDataGrid();
+ this._dataGrid.autoSizeColumns(6, 33);
+ this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length,
+ Number.bytesToString(this._totalSize, WebInspector.UIString));
} else {
- var emptyMsgElement = document.createElement("div");
- emptyMsgElement.className = "storage-table-empty";
- emptyMsgElement.textContent = WebInspector.UIString("This site has no cookies.");
- self.element.appendChild(emptyMsgElement);
- self._dataGrid = null;
- self.deleteButton.visible = false;
+ this._createSimpleDataGrid();
+ this._populateSimpleDataGrid();
+ this._dataGrid.autoSizeColumns(20, 80);
}
+ } else {
+ if (isAdvanced)
+ this._populateDataGrid();
+ else
+ this._populateSimpleDataGrid();
}
- WebInspector.Cookies.getCookiesAsync(callback);
+ this._dataGrid.element.removeStyleClass("hidden");
+ this._emptyMsgElement.addStyleClass("hidden");
+ if (isAdvanced)
+ this.deleteButton.visible = true;
},
- _cookiesForDomain: function(allCookies)
+ _filterCookiesForDomain: function(allCookies)
{
- var cookiesForDomain = [];
+ this._cookies = [];
var resourceURLsForDocumentURL = [];
+ this._totalSize = 0;
for (var id in WebInspector.resources) {
var resource = WebInspector.resources[id];
@@ -102,179 +128,151 @@ WebInspector.CookieItemsView.prototype = {
}
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)) {
- cookiesForDomain.push(allCookies[i]);
- break;
+ this._totalSize += size;
+ if (!pushed) {
+ pushed = true;
+ this._cookies.push(allCookies[i]);
+ }
}
}
}
- return cookiesForDomain;
},
- dataGridForCookies: function(cookies)
+ _createDataGrid: function()
{
- if (!cookies.length)
- return null;
-
- for (var i = 0; i < cookies.length; ++i)
- cookies[i].expires = new Date(cookies[i].expires);
-
var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} };
columns[0].title = WebInspector.UIString("Name");
- columns[0].width = columns[0].title.length;
+ columns[0].sortable = true;
columns[1].title = WebInspector.UIString("Value");
- columns[1].width = columns[1].title.length;
+ columns[1].sortable = true;
columns[2].title = WebInspector.UIString("Domain");
- columns[2].width = columns[2].title.length;
+ columns[2].sortable = true;
columns[3].title = WebInspector.UIString("Path");
- columns[3].width = columns[3].title.length;
+ columns[3].sortable = true;
columns[4].title = WebInspector.UIString("Expires");
- columns[4].width = columns[4].title.length;
+ columns[4].sortable = true;
columns[5].title = WebInspector.UIString("Size");
- columns[5].width = columns[5].title.length;
columns[5].aligned = "right";
+ columns[5].sortable = true;
columns[6].title = WebInspector.UIString("HTTP");
- columns[6].width = columns[6].title.length;
columns[6].aligned = "centered";
+ columns[6].sortable = true;
columns[7].title = WebInspector.UIString("Secure");
- columns[7].width = columns[7].title.length;
columns[7].aligned = "centered";
+ columns[7].sortable = true;
- function updateDataAndColumn(index, value) {
- data[index] = value;
- if (value.length > columns[index].width)
- columns[index].width = value.length;
- }
+ this._dataGrid = new WebInspector.DataGrid(columns, null, this._deleteCookieCallback.bind(this));
+ this._dataGrid.addEventListener("sorting changed", this._populateDataGrid, this);
+ this.element.appendChild(this._dataGrid.element);
+ this._dataGrid.updateWidths();
+ },
- var data;
- var nodes = [];
- for (var i = 0; i < cookies.length; ++i) {
- var cookie = cookies[i];
- data = {};
-
- updateDataAndColumn(0, cookie.name);
- updateDataAndColumn(1, cookie.value);
- updateDataAndColumn(2, cookie.domain);
- updateDataAndColumn(3, cookie.path);
- updateDataAndColumn(4, (cookie.session ? WebInspector.UIString("Session") : cookie.expires.toGMTString()));
- updateDataAndColumn(5, Number.bytesToString(cookie.size, WebInspector.UIString));
- updateDataAndColumn(6, (cookie.httpOnly ? "\u2713" : "")); // Checkmark
- updateDataAndColumn(7, (cookie.secure ? "\u2713" : "")); // Checkmark
+ _populateDataGrid: function()
+ {
+ var selectedCookie = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.cookie : null;
+ var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1;
- var node = new WebInspector.DataGridNode(data, false);
- node.cookie = cookie;
- node.selectable = true;
- nodes.push(node);
+ function localeCompare(field, cookie1, cookie2)
+ {
+ return sortDirection * (cookie1[field] + "").localeCompare(cookie2[field] + "")
}
- var totalColumnWidths = 0;
- for (var columnIdentifier in columns)
- totalColumnWidths += columns[columnIdentifier].width;
-
- // Enforce the Value column (the 2nd column) to be a max of 33%
- // tweaking the raw total width because may massively outshadow the others
- var valueColumnWidth = columns[1].width;
- if (valueColumnWidth / totalColumnWidths > 0.33) {
- totalColumnWidths -= valueColumnWidth;
- totalColumnWidths *= 1.33;
- columns[1].width = totalColumnWidths * 0.33;
+ function numberCompare(field, cookie1, cookie2)
+ {
+ return sortDirection * (cookie1[field] - cookie2[field]);
}
- // Calculate the percentage width for the columns.
- const minimumPrecent = 6;
- var recoupPercent = 0;
- for (var columnIdentifier in columns) {
- var width = columns[columnIdentifier].width;
- width = Math.round((width / totalColumnWidths) * 100);
- if (width < minimumPrecent) {
- recoupPercent += (minimumPrecent - width);
- width = minimumPrecent;
- }
- columns[columnIdentifier].width = width;
- }
+ function expiresCompare(cookie1, cookie2)
+ {
+ if (cookie1.session !== cookie2.session)
+ return sortDirection * (cookie1.session ? 1 : -1);
- // Enforce the minimum percentage width. (need to narrow total percentage due to earlier additions)
- while (recoupPercent > 0) {
- for (var columnIdentifier in columns) {
- if (columns[columnIdentifier].width > minimumPrecent) {
- --columns[columnIdentifier].width;
- --recoupPercent;
- if (!recoupPercent)
- break;
- }
- }
+ if (cookie1.session)
+ return 0;
+
+ return sortDirection * (cookie1.expires - cookie2.expires);
}
- for (var columnIdentifier in columns)
- columns[columnIdentifier].width += "%";
+ var comparator;
+ switch (parseInt(this._dataGrid.sortColumnIdentifier)) {
+ 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");
+ }
- var dataGrid = new WebInspector.DataGrid(columns, null, this._deleteCookieCallback.bind(this));
- var length = nodes.length;
- for (var i = 0; i < length; ++i)
- dataGrid.appendChild(nodes[i]);
- if (length > 0)
- nodes[0].selected = true;
+ this._cookies.sort(comparator);
- return dataGrid;
+ this._dataGrid.removeChildren();
+ var nodeToSelect;
+ for (var i = 0; i < this._cookies.length; ++i) {
+ var data = {};
+ var cookie = this._cookies[i];
+ data[0] = cookie.name;
+ data[1] = cookie.value;
+ data[2] = cookie.domain;
+ data[3] = cookie.path;
+ data[4] = (cookie.session ? WebInspector.UIString("Session") : new Date(cookie.expires).toGMTString());
+ data[5] = Number.bytesToString(cookie.size, WebInspector.UIString);
+ data[6] = (cookie.httpOnly ? "\u2713" : ""); // Checkmark
+ data[7] = (cookie.secure ? "\u2713" : ""); // Checkmark
+
+ var node = new WebInspector.DataGridNode(data);
+ node.cookie = cookie;
+ node.selectable = true;
+ this._dataGrid.appendChild(node);
+ if (cookie === selectedCookie)
+ nodeToSelect = node;
+ }
+ if (nodeToSelect)
+ nodeToSelect.selected = true;
+ else
+ this._dataGrid.children[0].selected = true;
},
- simpleDataGridForCookies: function(cookies)
+ _createSimpleDataGrid: function()
{
- if (!cookies.length)
- return null;
-
var columns = {};
columns[0] = {};
columns[1] = {};
columns[0].title = WebInspector.UIString("Name");
- columns[0].width = columns[0].title.length;
columns[1].title = WebInspector.UIString("Value");
- columns[1].width = columns[1].title.length;
- var nodes = [];
+ this._dataGrid = new WebInspector.DataGrid(columns);
+ this.element.appendChild(this._dataGrid.element);
+ this._dataGrid.updateWidths();
+ },
+
+ _populateSimpleDataGrid: function()
+ {
+ var cookies = this._cookies;
+ this._dataGrid.removeChildren();
+ var addedCookies = {};
for (var i = 0; i < cookies.length; ++i) {
- var cookie = cookies[i];
+ if (addedCookies[cookies[i].name])
+ continue;
+ addedCookies[cookies[i].name] = true;
var data = {};
-
- var name = cookie.name;
- data[0] = name;
- if (name.length > columns[0].width)
- columns[0].width = name.length;
-
- var value = cookie.value;
- data[1] = value;
- if (value.length > columns[1].width)
- columns[1].width = value.length;
+ data[0] = cookies[i].name;
+ data[1] = cookies[i].value;
var node = new WebInspector.DataGridNode(data, false);
node.selectable = true;
- nodes.push(node);
+ this._dataGrid.appendChild(node);
}
-
- var totalColumnWidths = columns[0].width + columns[1].width;
- var width = Math.round((columns[0].width * 100) / totalColumnWidths);
- const minimumPrecent = 20;
- if (width < minimumPrecent)
- width = minimumPrecent;
- if (width > 100 - minimumPrecent)
- width = 100 - minimumPrecent;
- columns[0].width = width;
- columns[1].width = 100 - width;
- columns[0].width += "%";
- columns[1].width += "%";
-
- var dataGrid = new WebInspector.DataGrid(columns);
- var length = nodes.length;
- for (var i = 0; i < length; ++i)
- dataGrid.appendChild(nodes[i]);
- if (length > 0)
- nodes[0].selected = true;
-
- return dataGrid;
+ this._dataGrid.children[0].selected = true;
},
-
+
resize: function()
{
if (this._dataGrid)
@@ -288,17 +286,17 @@ WebInspector.CookieItemsView.prototype = {
this._deleteCookieCallback(this._dataGrid.selectedNode);
},
-
+
_deleteCookieCallback: function(node)
{
var cookie = node.cookie;
InspectorBackend.deleteCookie(cookie.name, this._cookieDomain);
- this.update();
+ this._update();
},
_refreshButtonClicked: function(event)
{
- this.update();
+ this._update();
}
}
diff --git a/WebCore/inspector/front-end/DOMStorageItemsView.js b/WebCore/inspector/front-end/DOMStorageItemsView.js
index 7441f2e..dbd736b 100644
--- a/WebCore/inspector/front-end/DOMStorageItemsView.js
+++ b/WebCore/inspector/front-end/DOMStorageItemsView.js
@@ -69,7 +69,7 @@ WebInspector.DOMStorageItemsView.prototype = {
{
this._dataGrid = this._dataGridForDOMStorageEntries(entries);
this.element.appendChild(this._dataGrid.element);
- this._dataGrid.updateWidths();
+ this._dataGrid.autoSizeColumns(10);
this.deleteButton.visible = true;
},
@@ -85,9 +85,7 @@ WebInspector.DOMStorageItemsView.prototype = {
columns[0] = {};
columns[1] = {};
columns[0].title = WebInspector.UIString("Key");
- columns[0].width = columns[0].title.length;
columns[1].title = WebInspector.UIString("Value");
- columns[1].width = columns[1].title.length;
var nodes = [];
@@ -98,31 +96,14 @@ WebInspector.DOMStorageItemsView.prototype = {
var key = entries[i][0];
data[0] = key;
- if (key.length > columns[0].width)
- columns[0].width = key.length;
-
var value = entries[i][1];
data[1] = value;
- if (value.length > columns[1].width)
- columns[1].width = value.length;
var node = new WebInspector.DataGridNode(data, false);
node.selectable = true;
nodes.push(node);
keys.push(key);
}
- var totalColumnWidths = columns[0].width + columns[1].width;
- var width = Math.round((columns[0].width * 100) / totalColumnWidths);
- const minimumPrecent = 10;
- if (width < minimumPrecent)
- width = minimumPrecent;
- if (width > 100 - minimumPrecent)
- width = 100 - minimumPrecent;
- columns[0].width = width;
- columns[1].width = 100 - width;
- columns[0].width += "%";
- columns[1].width += "%";
-
var dataGrid = new WebInspector.DataGrid(columns, this._editingCallback.bind(this), this._deleteCallback.bind(this));
var length = nodes.length;
for (var i = 0; i < length; ++i)
diff --git a/WebCore/inspector/front-end/DataGrid.js b/WebCore/inspector/front-end/DataGrid.js
index 3eca9e4..1ecc4f2 100644
--- a/WebCore/inspector/front-end/DataGrid.js
+++ b/WebCore/inspector/front-end/DataGrid.js
@@ -61,7 +61,7 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
var headerRow = document.createElement("tr");
var columnGroup = document.createElement("colgroup");
- var columnCount = 0;
+ this._columnCount = 0;
for (var columnIdentifier in columns) {
var column = columns[columnIdentifier];
@@ -71,6 +71,7 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
var col = document.createElement("col");
if (column.width)
col.style.width = column.width;
+ column.element = col;
columnGroup.appendChild(col);
var cell = document.createElement("th");
@@ -98,10 +99,10 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
headerRow.appendChild(cell);
- ++columnCount;
+ ++this._columnCount;
}
- columnGroup.span = columnCount;
+ columnGroup.span = this._columnCount;
var cell = document.createElement("th");
cell.className = "corner";
@@ -114,7 +115,7 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
var fillerRow = document.createElement("tr");
fillerRow.className = "filler";
- for (var i = 0; i < columnCount; ++i) {
+ for (var i = 0; i < this._columnCount; ++i) {
var cell = document.createElement("td");
fillerRow.appendChild(cell);
}
@@ -292,7 +293,70 @@ WebInspector.DataGrid.prototype = {
return this._dataTableBody;
},
-
+
+ autoSizeColumns: function(minPercent, maxPercent)
+ {
+ 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;
+
+ for (var i = 0; i < this.children.length; ++i) {
+ var node = this.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();
+ },
+
// Updates the widths of the table, including the positions of the column
// resizers.
//
diff --git a/WebCore/inspector/front-end/DatabaseQueryView.js b/WebCore/inspector/front-end/DatabaseQueryView.js
index 2656842..cc902e7 100644
--- a/WebCore/inspector/front-end/DatabaseQueryView.js
+++ b/WebCore/inspector/front-end/DatabaseQueryView.js
@@ -144,6 +144,7 @@ WebInspector.DatabaseQueryView.prototype = {
return;
dataGrid.element.addStyleClass("inline");
this._appendQueryResult(query, dataGrid.element);
+ dataGrid.autoSizeColumns(5);
if (query.match(/^create /i) || query.match(/^drop table /i))
WebInspector.panels.storage.updateDatabaseTables(this.database);
diff --git a/WebCore/inspector/front-end/DatabaseTableView.js b/WebCore/inspector/front-end/DatabaseTableView.js
index aa76794..cd66ab7 100644
--- a/WebCore/inspector/front-end/DatabaseTableView.js
+++ b/WebCore/inspector/front-end/DatabaseTableView.js
@@ -68,6 +68,7 @@ WebInspector.DatabaseTableView.prototype = {
}
this.element.appendChild(dataGrid.element);
+ dataGrid.autoSizeColumns(5);
},
_queryError: function(error)
diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js
index 8d8d5db..4a8dae0 100644
--- a/WebCore/inspector/front-end/ElementsTreeOutline.js
+++ b/WebCore/inspector/front-end/ElementsTreeOutline.js
@@ -925,6 +925,10 @@ WebInspector.ElementsTreeElement.prototype = {
info.title = "Document";
break;
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ info.title = "Document Fragment";
+ break;
+
case Node.ELEMENT_NODE:
info.title = "<span class=\"webkit-html-tag\">&lt;" + node.nodeName.toLowerCase().escapeHTML();
diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js
index 337628f..95867c4 100644
--- a/WebCore/inspector/front-end/InjectedScript.js
+++ b/WebCore/inspector/front-end/InjectedScript.js
@@ -52,11 +52,6 @@ InjectedScript.wrapObject = function(object, objectGroupName)
return InjectedScript.createProxyObject(object, objectId);
};
-InjectedScript.wrapAndStringifyObject = function(object, objectGroupName) {
- var r = InjectedScript.wrapObject(object, objectGroupName);
- return InjectedScript.JSON.stringify(r);
-};
-
InjectedScript.unwrapObject = function(objectId) {
return InjectedScript.idToWrappedObject[objectId];
};
@@ -85,7 +80,7 @@ InjectedScript.reset();
InjectedScript.dispatch = function(methodName, args, callId)
{
- var argsArray = InjectedScript.JSON.parse(args);
+ var argsArray = eval("(" + args + ")");
if (callId)
argsArray.splice(0, 0, callId); // Methods that run asynchronously have a call back id parameter.
var result = InjectedScript[methodName].apply(InjectedScript, argsArray);
@@ -93,7 +88,7 @@ InjectedScript.dispatch = function(methodName, args, callId)
InjectedScript._window().console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName);
result = null;
}
- return InjectedScript.JSON.stringify(result);
+ return result;
}
InjectedScript.getStyles = function(nodeId, authorOnly)
@@ -935,7 +930,7 @@ InjectedScript.callFrames = function()
result.push(new InjectedScript.CallFrameProxy(depth++, callFrame));
callFrame = callFrame.caller;
} while (callFrame);
- return InjectedScript.JSON.stringify(result);
+ return result;
}
InjectedScript.evaluateInCallFrame = function(callFrameId, code, objectGroup)
@@ -1220,12 +1215,12 @@ InjectedScript.executeSql = function(callId, databaseId, query)
data[columnIdentifier] = String(text);
}
}
- InjectedScriptHost.reportDidDispatchOnInjectedScript(callId, InjectedScript.JSON.stringify(result), false);
+ InjectedScriptHost.reportDidDispatchOnInjectedScript(callId, result, false);
}
function errorCallback(tx, error)
{
- InjectedScriptHost.reportDidDispatchOnInjectedScript(callId, InjectedScript.JSON.stringify(error), false);
+ InjectedScriptHost.reportDidDispatchOnInjectedScript(callId, error, false);
}
function queryTransaction(tx)
@@ -1339,296 +1334,5 @@ InjectedScript._escapeCharacters = function(str, chars)
return result;
}
-InjectedScript.JSON = {};
-
-// The following code is a slightly modified version of http://www.json.org/json2.js last modified on 2009-09-29.
-// Compared to the original version it ignores toJSON method on objects it serializes.
-// It's done to avoid weird behaviour when inspected application provides it's own implementation
-// of toJSON methods to the Object and other intrinsic types. We use InjectedScript.JSON implementation
-// instead of global JSON object since it can have been modified by the inspected code.
-(function() {
-
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
-
-
- function quote(string) {
-
-// If the string contains no control characters, no quote characters, and no
-// backslash characters, then we can safely slap some quotes around it.
-// Otherwise we must also replace the offending characters with safe escape
-// sequences.
-
- escapable.lastIndex = 0;
- return escapable.test(string) ?
- '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string' ? c :
- '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' :
- '"' + string + '"';
- }
-
-
- function str(key, holder) {
-
-// Produce a string from holder[key].
-
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
-
-// If we were called with a replacer function, then call the replacer to
-// obtain a replacement value.
-
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
-
-// What happens next depends on the value's type.
-
- switch (typeof value) {
- case 'string':
- return quote(value);
-
- case 'number':
-
-// JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
-
-// If the value is a boolean or null, convert it to a string. Note:
-// typeof null does not produce 'null'. The case is included here in
-// the remote chance that this gets fixed someday.
-
- return String(value);
-
-// If the type is 'object', we might be dealing with an object or an array or
-// null.
-
- case 'object':
-
-// Due to a specification blunder in ECMAScript, typeof null is 'object',
-// so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
-// Make an array to hold the partial results of stringifying this object value.
-
- gap += indent;
- partial = [];
-
-// Is the value an array?
-
- if (Object.prototype.toString.apply(value) === '[object Array]') {
-
-// The value is an array. Stringify every element. Use null as a placeholder
-// for non-JSON values.
-
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
-
-// Join all of the elements together, separated with commas, and wrap them in
-// brackets.
-
- v = partial.length === 0 ? '[]' :
- gap ? '[\n' + gap +
- partial.join(',\n' + gap) + '\n' +
- mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
-
-// If the replacer is an array, use it to select the members to be stringified.
-
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
-
-// Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
-
-// Join all of the member texts together, separated with commas,
-// and wrap them in braces.
-
- v = partial.length === 0 ? '{}' :
- gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
- mind + '}' : '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
-
- InjectedScript.JSON.stringify = function (value, replacer, space) {
-
-// The stringify method takes a value and an optional replacer, and an optional
-// space parameter, and returns a JSON text. The replacer can be a function
-// that can replace values, or an array of strings that will select the keys.
-// A default replacer method can be provided. Use of the space parameter can
-// produce text that is more easily readable.
-
- var i;
- gap = '';
- indent = '';
-
-// If the space parameter is a number, make an indent string containing that
-// many spaces.
-
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
-
-// If there is a replacer, it must be a function or an array.
-// Otherwise, throw an error.
-
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
-
-// Make a fake root object containing our value under the key of ''.
-// Return the result of stringifying the value.
-
- return str('', {'': value});
- };
-
-
-// If the JSON object does not yet have a parse method, give it one.
-
- InjectedScript.JSON.parse = function (text, reviver) {
-
-// The parse method takes a text and an optional reviver function, and returns
-// a JavaScript value if the text is a valid JSON text.
-
- var j;
-
- function walk(holder, key) {
-
-// The walk method is used to recursively walk the resulting structure so
-// that modifications can be made.
-
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
-
-
-// Parsing happens in four stages. In the first stage, we replace certain
-// Unicode characters with escape sequences. JavaScript handles many characters
-// incorrectly, either silently deleting them, or treating them as line endings.
-
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- });
- }
-
-// In the second stage, we run the text against regular expressions that look
-// for non-JSON patterns. We are especially concerned with '()' and 'new'
-// because they can cause invocation, and '=' because it can cause mutation.
-// But just to be safe, we want to reject all unexpected forms.
-
-// We split the second stage into 4 regexp operations in order to work around
-// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
-// replace all simple value tokens with ']' characters. Third, we delete all
-// open brackets that follow a colon or comma or that begin the text. Finally,
-// we look to see that the remaining characters are only whitespace or ']' or
-// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
- if (/^[\],:{}\s]*$/.
-test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
-replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
-replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
-// In the third stage we use the eval function to compile the text into a
-// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
-// in JavaScript: it can begin a block or an object literal. We wrap the text
-// in parens to eliminate the ambiguity.
-
- j = eval('(' + text + ')');
-
-// In the optional fourth stage, we recursively walk the new structure, passing
-// each name/value pair to a reviver function for possible transformation.
-
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
-
-// If the text is not JSON parseable, then a SyntaxError is thrown.
-
- throw new SyntaxError('JSON.parse');
- };
-}());
-
return InjectedScript;
});
diff --git a/WebCore/inspector/front-end/InjectedScriptAccess.js b/WebCore/inspector/front-end/InjectedScriptAccess.js
index 2dd2908..2558267 100644
--- a/WebCore/inspector/front-end/InjectedScriptAccess.js
+++ b/WebCore/inspector/front-end/InjectedScriptAccess.js
@@ -56,7 +56,7 @@ InjectedScriptAccess._installHandler = function(methodName, async)
function myCallback(result, isException)
{
if (!isException)
- callback(JSON.parse(result));
+ callback(result);
else
WebInspector.console.addMessage(new WebInspector.ConsoleTextMessage("Error dispatching: " + methodName));
}
diff --git a/WebCore/inspector/front-end/NativeTextViewer.js b/WebCore/inspector/front-end/NativeTextViewer.js
deleted file mode 100644
index 5e7db27..0000000
--- a/WebCore/inspector/front-end/NativeTextViewer.js
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-WebInspector.NativeTextViewer = function(textModel, platform, url)
-{
- WebInspector.TextEditor.call(this, textModel, platform);
- this._sheet.tabIndex = 0;
- this._canvas.style.zIndex = 0;
- this._createLineDivs();
- this._url = url;
- this._selectionColor = "rgb(241, 234, 0)";
-}
-
-WebInspector.NativeTextViewer.prototype = {
- // WebInspector.TextModel listener
- _textChanged: function(oldRange, newRange, oldText, newText)
- {
- this._createLineDivs();
- WebInspector.TextEditor.prototype._textChanged.call(this, oldRange, newRange, oldText, newText);
- },
-
- _createLineDivs: function()
- {
- this._container.removeChild(this._sheet);
- this._sheet.removeChildren();
- for (var i = 0; i < this._textModel.linesCount; ++i) {
- var lineDiv = document.createElement("div");
- lineDiv.className = "native-text-editor-line";
- var text = this._textModel.line(i);
- lineDiv.textContent = text;
- if (!text)
- lineDiv.style.minHeight = this._textLineHeight + "px";
- this._sheet.appendChild(lineDiv);
- this._textModel.setAttribute(i, "line-div", lineDiv);
- this._textModel.removeAttribute(i, "div-highlighted");
- }
- this._container.appendChild(this._sheet);
- },
-
- _updatePreferredSize: function(startLine, endLine)
- {
- // Preferred size is automatically calculated based on the line divs.
- // Only handle line numbers here.
-
- this.setCoalescingUpdate(true);
- var newLineNumberDigits = this._decimalDigits(this._textModel.linesCount);
- this._lineNumberWidth = (newLineNumberDigits + 2) * this._digitWidth;
-
- this._container.style.left = this._lineNumberWidth + "px";
-
- this._lineNumberDigits = newLineNumberDigits;
- this.repaintAll();
-
- // Changes to size can change the client area (scrollers can appear/disappear)
- this.resize();
- this.setCoalescingUpdate(false);
- },
-
- _scroll: function(e)
- {
- // Do instant repaint so that offset of canvas was in sync with the sheet.
- this._repaintOnScroll();
- },
-
- _registerMouseListeners: function()
- {
- this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
- this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
- },
-
- _registerKeyboardListeners: function()
- {
- // Noop - let browser take care of this.
- },
-
- _registerClipboardListeners: function()
- {
- // Noop - let browser take care of this.
- },
-
- _positionDivDecoration: function()
- {
- // Div decorations have fixed positions in our case.
- },
-
- _registerShortcuts: function()
- {
- // Noop.
- },
-
- _mouseDown: function(e)
- {
- if (e.target !== this.element || e.button === 2 || (this._isMac && e.ctrlKey))
- return;
- this._lineNumberDecorator.mouseDown(this._lineForMouseEvent(e), e);
- },
-
- _contextMenu: function(e)
- {
- if (e.target !== this.element)
- return;
- this._lineNumberDecorator.contextMenu(this._lineForMouseEvent(e), e);
- },
-
- _lineForMouseEvent: function(e)
- {
- return Math.max(0, this._offsetToLine(e.offsetY + this._scrollTop) - 1);
- },
-
- _lineHeight: function(lineNumber)
- {
- // Use cached value first.
- if (this._lineOffsetsCache[lineNumber + 1])
- return this._lineOffsetsCache[lineNumber + 1] - this._lineOffsetsCache[lineNumber];
-
- // Get metrics from the browser.
- var element = this._textModel.getAttribute(lineNumber, "line-div");
- if (lineNumber + 1 < this._textModel.linesCount) {
- var nextElement = this._textModel.getAttribute(lineNumber + 1, "line-div");
- return nextElement.offsetTop - element.offsetTop;
- }
- return element.parentElement.offsetHeight - element.offsetTop;
- },
-
- _paintLine: function(lineNumber, lineOffset)
- {
- var divHighlighted = this._textModel.getAttribute(lineNumber, "div-highlighted");
- if (divHighlighted)
- return;
-
- var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
- if (!highlighterState)
- return;
-
- var line = this._textModel.line(lineNumber);
- var element = this._textModel.getAttribute(lineNumber, "line-div");
- element.removeChildren();
-
- var plainTextStart = -1;
- for (var j = 0; j < line.length;) {
- if (j > 1000) {
- // This line is too long - do not waste cycles on minified js highlighting.
- break;
- }
- var attribute = highlighterState && highlighterState.attributes[j];
- if (!attribute || !attribute.style) {
- if (plainTextStart === -1)
- plainTextStart = j;
- j++;
- } else {
- if (plainTextStart !== -1) {
- element.appendChild(document.createTextNode(line.substring(plainTextStart, j)));
- plainTextStart = -1;
- }
- element.appendChild(this._createSpan(line.substring(j, j + attribute.length), attribute.tokenType));
- j += attribute.length;
- }
- }
- if (plainTextStart !== -1)
- element.appendChild(document.createTextNode(line.substring(plainTextStart, line.length)));
-
- this._textModel.setAttribute(lineNumber, "div-highlighted", true);
- },
-
- _createSpan: function(content, className)
- {
- if (className === "html-resource-link" || className === "html-external-link")
- return this._createLink(content, className === "html-external-link");
-
- var span = document.createElement("span");
- span.className = "webkit-" + className;
- span.appendChild(document.createTextNode(content));
- return span;
- },
-
- _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 a = WebInspector.linkifyURLAsNode(this._rewriteHref(content), content, null, isExternal);
- var span = document.createElement("span");
- span.className = "webkit-html-attribute-value";
- if (quote)
- span.appendChild(document.createTextNode(quote));
- span.appendChild(a);
- if (quote)
- span.appendChild(document.createTextNode(quote));
- return span;
- },
-
- _rewriteHref: function(hrefValue, isExternal)
- {
- if (!this._url || !hrefValue || hrefValue.indexOf("://") > 0)
- return hrefValue;
- return WebInspector.completeURL(this._url, hrefValue);
- },
-
- setDivDecoration: function(lineNumber, element)
- {
- var existingElement = this._textModel.getAttribute(lineNumber, "div-decoration");
- if (existingElement && existingElement.parentNode)
- existingElement.parentNode.removeChild(existingElement);
- this._textModel.removeAttribute(lineNumber, "div-decoration");
-
- if (element) {
- if (lineNumber < this._textModel.linesCount - 1) {
- var lineDiv = this._textModel.getAttribute(lineNumber + 1, "line-div");
- this._sheet.insertBefore(element, lineDiv);
- } else
- this._sheet.appendChild(element);
- this._textModel.setAttribute(lineNumber, "div-decoration", element);
- }
- this.revalidateDecorationsAndPaint();
- },
-
- initFontMetrics: function()
- {
- WebInspector.TextEditor.prototype.initFontMetrics.call(this);
- for (var i = 0; i < this._textModel.linesCount; ++i) {
- var lineDiv = this._textModel.getAttribute(i, "line-div");
- if (!this._textModel.line(i))
- lineDiv.style.minHeight = this._textLineHeight + "px";
- }
- }
-}
-
-WebInspector.NativeTextViewer.prototype.__proto__ = WebInspector.TextEditor.prototype;
diff --git a/WebCore/inspector/front-end/ScriptView.js b/WebCore/inspector/front-end/ScriptView.js
index cf7f1b1..c5a8b81 100644
--- a/WebCore/inspector/front-end/ScriptView.js
+++ b/WebCore/inspector/front-end/ScriptView.js
@@ -33,7 +33,7 @@ WebInspector.ScriptView = function(script)
this._frameNeedsSetup = true;
this._sourceFrameSetup = false;
- this.sourceFrame = new WebInspector.SourceFrame(this.element, this._addBreakpoint.bind(this));
+ this.sourceFrame = new WebInspector.SourceFrame(this.element, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this));
}
WebInspector.ScriptView.prototype = {
@@ -87,6 +87,7 @@ WebInspector.ScriptView.prototype = {
showingLastSearchResult: WebInspector.SourceView.prototype.showingLastSearchResult,
_jumpToSearchResult: WebInspector.SourceView.prototype._jumpToSearchResult,
_sourceFrameSetupFinished: WebInspector.SourceView.prototype._sourceFrameSetupFinished,
+ _removeBreakpoint: WebInspector.SourceView.prototype._removeBreakpoint,
resize: WebInspector.SourceView.prototype.resize
}
diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js
index bc0daa5..e6fc0c3 100644
--- a/WebCore/inspector/front-end/Settings.js
+++ b/WebCore/inspector/front-end/Settings.js
@@ -38,8 +38,7 @@ var Preferences = {
styleRulesExpandedState: {},
showMissingLocalizedStrings: false,
samplingCPUProfiler: false,
- showColorNicknames: true,
- useCanvasBasedEditor: false
+ showColorNicknames: true
}
WebInspector.populateFrontendSettings = function(settingsString)
@@ -68,7 +67,7 @@ WebInspector.Settings.prototype = {
this._installSetting("lastViewedScriptFile", "last-viewed-script-file");
this._installSetting("showInheritedComputedStyleProperties", "show-inherited-computed-style-properties", false);
this._installSetting("showUserAgentStyles", "show-user-agent-styles", true);
- this._installSetting("resourceViewTab", "resource-view-tab", "headers");
+ this._installSetting("resourceViewTab", "resource-view-tab", "content");
this.dispatchEventToListeners("loaded");
},
diff --git a/WebCore/inspector/front-end/SourceCSSTokenizer.re2js b/WebCore/inspector/front-end/SourceCSSTokenizer.re2js
index 8d6c5f1..ac22bd4 100644
--- a/WebCore/inspector/front-end/SourceCSSTokenizer.re2js
+++ b/WebCore/inspector/front-end/SourceCSSTokenizer.re2js
@@ -98,35 +98,35 @@ WebInspector.SourceCSSTokenizer = function()
this._valueKeywords = [
"above", "absolute", "activeborder", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll",
- "alternate", "always","amharic", "amharic-abegede", "antialiased", "appworkspace", "aqua", "armenian", "auto", "avoid",
- "background", "backwards", "baseline", "below", "bidi-override", "black", "blink", "block", "block-axis", "blue", "bold",
- "bolder", "border", "border-box", "both", "bottom", "break-all", "break-word", "button", "button-bevel", "buttonface",
- "buttonhighlight", "buttonshadow", "buttontext", "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", "disc", "discard", "document",
+ "alternate", "always","amharic", "amharic-abegede", "antialiased", "appworkspace", "aqua", "arabic-indic", "armenian",
+ "auto", "avoid", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "black", "blink",
+ "block", "block-axis", "blue", "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", "forwards", "from", "fuchsia", "geometricPrecision",
- "georgian", "gray", "graytext", "green", "grey", "groove", "hand", "hangul", "hangul-consonant", "hebrew", "help", "hidden", "hide",
- "higher", "highlight", "highlighttext", "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
+ "georgian", "gray", "graytext", "green", "grey", "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", "katakana",
- "katakana-iroha", "landscape", "large", "larger", "left", "level", "lighter", "lime", "line-through", "linear", "lines",
- "list-button", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-greek", "lower-latin",
- "lower-norwegian", "lower-roman", "lowercase", "ltr", "maroon", "match", "media-controls-background", "media-current-time-display",
+ "inline-axis", "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert", "italic", "justify", "kannada", "katakana",
+ "katakana-iroha", "khmer", "landscape", "lao", "large", "larger", "left", "level", "lighter", "lime", "line-through", "linear", "lines",
+ "list-button", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-greek", "lower-hexadecimal", "lower-latin",
+ "lower-norwegian", "lower-roman", "lowercase", "ltr", "malayalam", "maroon", "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", "monospace", "move", "multiple",
- "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", "olive", "open-quote", "optimizeLegibility",
- "optimizeSpeed", "orange", "oromo", "outset", "outside", "overlay", "overline", "padding", "padding-box", "painted", "paused",
- "plus-darker", "plus-lighter", "pointer", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "purple",
+ "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", "olive", "open-quote", "optimizeLegibility",
+ "optimizeSpeed", "orange", "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", "purple",
"push-button", "radio", "read-only", "read-write", "read-write-plaintext-only", "red", "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",
@@ -135,15 +135,15 @@ WebInspector.SourceCSSTokenizer = function()
"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", "teal", "text", "text-bottom", "text-top", "textarea", "textfield", "thick", "thin", "threeddarkshadow",
- "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et",
- "tigrinya-et-abegede", "to", "top", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-greek",
- "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "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-right", "-webkit-small-control",
- "-webkit-text", "-webkit-xxx-large", "-webkit-zoom-in", "-webkit-zoom-out",
+ "table-row", "table-row-group", "teal", "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-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-right",
+ "-webkit-small-control", "-webkit-text", "-webkit-xxx-large", "-webkit-zoom-in", "-webkit-zoom-out",
].keySet();
this._mediaTypes = ["all", "aural", "braille", "embossed", "handheld", "import", "print", "projection", "screen", "tty", "tv"].keySet();
diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js
index e30dbdb..0f90700 100644
--- a/WebCore/inspector/front-end/SourceFrame.js
+++ b/WebCore/inspector/front-end/SourceFrame.js
@@ -28,11 +28,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate)
+WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate, removeBreakpointDelegate)
{
this._parentElement = parentElement;
this._textModel = new WebInspector.TextEditorModel();
+ this._textModel.replaceTabsWithSpaces = true;
this._messages = [];
this._rowMessages = {};
@@ -43,6 +44,7 @@ WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate)
this._loaded = false;
this._addBreakpointDelegate = addBreakpointDelegate;
+ this._removeBreakpointDelegate = removeBreakpointDelegate;
}
WebInspector.SourceFrame.prototype = {
@@ -50,7 +52,7 @@ WebInspector.SourceFrame.prototype = {
set visible(visible)
{
this._visible = visible;
- this._createEditorIfNeeded();
+ this._createViewerIfNeeded();
},
get executionLine()
@@ -62,15 +64,18 @@ WebInspector.SourceFrame.prototype = {
{
if (this._executionLine === x)
return;
+
+ var previousLine = this._executionLine;
this._executionLine = x;
- if (this._editor)
- this._editor.repaintAll();
+
+ if (this._textViewer)
+ this._updateExecutionLine(previousLine);
},
revealLine: function(lineNumber)
{
- if (this._editor)
- this._editor.reveal(lineNumber - 1, 0);
+ if (this._textViewer)
+ this._textViewer.revealLine(lineNumber - 1, 0);
else
this._lineNumberToReveal = lineNumber;
},
@@ -81,7 +86,8 @@ WebInspector.SourceFrame.prototype = {
breakpoint.addEventListener("enabled", this._breakpointChanged, this);
breakpoint.addEventListener("disabled", this._breakpointChanged, this);
breakpoint.addEventListener("condition-changed", this._breakpointChanged, this);
- this._addBreakpointToSource(breakpoint);
+ if (this._textViewer)
+ this._addBreakpointToSource(breakpoint);
},
removeBreakpoint: function(breakpoint)
@@ -90,7 +96,8 @@ WebInspector.SourceFrame.prototype = {
breakpoint.removeEventListener("enabled", null, this);
breakpoint.removeEventListener("disabled", null, this);
breakpoint.removeEventListener("condition-changed", null, this);
- this._removeBreakpointFromSource(breakpoint);
+ if (this._textViewer)
+ this._removeBreakpointFromSource(breakpoint);
},
addMessage: function(msg)
@@ -99,7 +106,7 @@ WebInspector.SourceFrame.prototype = {
if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning())
return;
this._messages.push(msg)
- if (this._editor)
+ if (this._textViewer)
this._addMessageToSource(msg);
},
@@ -113,14 +120,14 @@ WebInspector.SourceFrame.prototype = {
this._messages = [];
this._rowMessages = {};
this._messageBubbles = {};
- if (this._editor)
- this._editor.revalidateDecorationsAndPaint();
+ if (this._textViewer)
+ this._textViewer.resize();
},
sizeToFitContentHeight: function()
{
- if (this._editor)
- this._editor.revalidateDecorationsAndPaint();
+ if (this._textViewer)
+ this._textViewer.revalidateDecorationsAndPaint();
},
setContent: function(mimeType, content, url)
@@ -129,47 +136,56 @@ WebInspector.SourceFrame.prototype = {
this._textModel.setText(null, content);
this._mimeType = mimeType;
this._url = url;
- this._createEditorIfNeeded();
+ this._createViewerIfNeeded();
+ },
+
+ highlightLine: function(line)
+ {
+ if (this._textViewer)
+ this._textViewer.highlightLine(line - 1);
+ else
+ this._lineToHighlight = line;
},
- _createEditorIfNeeded: function()
+ _createViewerIfNeeded: function()
{
- if (!this._visible || !this._loaded || this._editor)
+ if (!this._visible || !this._loaded || this._textViewer)
return;
- var editorConstructor = Preferences.useCanvasBasedEditor ? WebInspector.TextEditor : WebInspector.NativeTextViewer;
- this._editor = new editorConstructor(this._textModel, WebInspector.platform, this._url);
- this._editor.lineNumberDecorator = new WebInspector.BreakpointLineNumberDecorator(this, this._editor.textModel);
- this._editor.lineDecorator = new WebInspector.ExecutionLineDecorator(this);
- this._editor.readOnly = true;
- this._element = this._editor.element;
- this._element.addEventListener("keydown", this._keyDown.bind(this), true);
- this._parentElement.appendChild(this._element);
- this._editor.initFontMetrics();
+ this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url);
+ var element = this._textViewer.element;
+ element.addEventListener("keydown", this._keyDown.bind(this), true);
+ element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
+ element.addEventListener("mousedown", this._mouseDown.bind(this), true);
+ this._parentElement.appendChild(element);
- this._editor.mimeType = this._mimeType;
+ this._needsProgramCounterImage = true;
+ this._needsBreakpointImages = true;
+ this._textViewer.beginUpdates();
+
+ this._textViewer.mimeType = this._mimeType;
this._addExistingMessagesToSource();
this._addExistingBreakpointsToSource();
-
- this._editor.setCoalescingUpdate(true);
- this._editor.resize();
- this._editor.revalidateDecorationsAndPaint();
-
- if (this._executionLine)
- this.revealLine(this._executionLine);
+ this._updateExecutionLine();
+ this._textViewer.resize();
if (this._lineNumberToReveal) {
this.revealLine(this._lineNumberToReveal);
delete this._lineNumberToReveal;
}
- if (this._pendingSelectionRange) {
- var range = this._pendingSelectionRange;
- this._editor.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
- delete this._pendingSelectionRange;
+ if (this._pendingMarkRange) {
+ var range = this._pendingMarkRange;
+ this.markAndRevealRange(range);
+ delete this._pendingMarkRange;
}
- this._editor.setCoalescingUpdate(false);
+
+ if (this._lineToHighlight) {
+ this.highlightLine(this._lineToHighlight);
+ delete this._lineToHighlight;
+ }
+ this._textViewer.endUpdates();
},
findSearchMatches: function(query)
@@ -214,21 +230,20 @@ WebInspector.SourceFrame.prototype = {
return ranges;
},
- setSelection: function(range)
+ markAndRevealRange: function(range)
{
- if (this._editor)
- this._editor.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
+ if (this._textViewer)
+ this._textViewer.markAndRevealRange(range);
else
- this._pendingSelectionRange = range;
+ this._pendingMarkRange = range;
},
- clearSelection: function()
+ clearMarkedRange: function()
{
- if (this._editor) {
- var range = this._editor.selection;
- this._editor.setSelection(range.endLine, range.endColumn, range.endLine, range.endColumn);
+ if (this._textViewer) {
+ this._textViewer.markAndRevealRange(null);
} else
- delete this._pendingSelectionRange;
+ delete this._pendingMarkRange;
},
_incrementMessageRepeatCount: function(msg, repeatDelta)
@@ -246,6 +261,40 @@ WebInspector.SourceFrame.prototype = {
msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount);
},
+ _breakpointChanged: function(event)
+ {
+ var breakpoint = event.target;
+ var lineNumber = breakpoint.line - 1;
+ if (lineNumber >= this._textModel.linesCount)
+ return;
+
+ if (breakpoint.enabled)
+ this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
+ else
+ this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
+
+ if (breakpoint.condition)
+ this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
+ else
+ this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
+ },
+
+ _updateExecutionLine: function(previousLine)
+ {
+ if (previousLine) {
+ if (previousLine - 1 < this._textModel.linesCount)
+ this._textViewer.removeDecoration(previousLine - 1, "webkit-execution-line");
+ }
+
+ if (!this._executionLine)
+ return;
+
+ this._drawProgramCounterImageIfNeeded();
+
+ if (this._executionLine < this._textModel.linesCount)
+ this._textViewer.addDecoration(this._executionLine - 1, "webkit-execution-line");
+ },
+
_addExistingMessagesToSource: function()
{
var length = this._messages.length;
@@ -263,7 +312,7 @@ WebInspector.SourceFrame.prototype = {
messageBubbleElement = document.createElement("div");
messageBubbleElement.className = "webkit-html-message-bubble";
this._messageBubbles[msg.line] = messageBubbleElement;
- this._editor.setDivDecoration(msg.line - 1, messageBubbleElement);
+ this._textViewer.addDecoration(msg.line - 1, messageBubbleElement);
}
var rowMessages = this._rowMessages[msg.line];
@@ -275,7 +324,6 @@ WebInspector.SourceFrame.prototype = {
for (var i = 0; i < rowMessages.length; ++i) {
if (rowMessages[i].isEqual(msg, true)) {
this._incrementMessageRepeatCount(rowMessages[i], msg.repeatDelta);
- this._editor.revalidateDecorationsAndPaint();
return;
}
}
@@ -306,35 +354,51 @@ WebInspector.SourceFrame.prototype = {
messageLineElement.appendChild(document.createTextNode(msg.message));
msg._resourceMessageLineElement = messageLineElement;
-
- this._editor.revalidateDecorationsAndPaint();
},
_addExistingBreakpointsToSource: function()
{
- var length = this.breakpoints.length;
- for (var i = 0; i < length; ++i)
+ for (var i = 0; i < this.breakpoints.length; ++i)
this._addBreakpointToSource(this.breakpoints[i]);
},
_addBreakpointToSource: function(breakpoint)
{
- this._textModel.setAttribute(breakpoint.line - 1, "breakpoint", breakpoint);
+ var lineNumber = breakpoint.line - 1;
+ if (lineNumber >= this._textModel.linesCount)
+ return;
+
+ this._textModel.setAttribute(lineNumber, "breakpoint", breakpoint);
breakpoint.sourceText = this._textModel.line(breakpoint.line - 1);
- this._editor.paintLineNumbers();
+ this._drawBreakpointImagesIfNeeded();
+
+ this._textViewer.beginUpdates();
+ this._textViewer.addDecoration(lineNumber, "webkit-breakpoint");
+ if (!breakpoint.enabled)
+ this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
+ if (breakpoint.condition)
+ this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
+ this._textViewer.endUpdates();
},
_removeBreakpointFromSource: function(breakpoint)
{
- this._textModel.removeAttribute(breakpoint.line - 1, "breakpoint");
- this._editor.paintLineNumbers();
+ var lineNumber = breakpoint.line - 1;
+ this._textViewer.beginUpdates();
+ this._textModel.removeAttribute(lineNumber, "breakpoint");
+ this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint");
+ this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
+ this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
+ this._textViewer.endUpdates();
},
- _contextMenu: function(lineNumber, event)
+ _contextMenu: function(event)
{
- if (!this._addBreakpointDelegate)
+ if (event.target.className !== "webkit-line-number")
return;
+ var row = event.target.parentElement;
+ var lineNumber = row.lineNumber;
var contextMenu = new WebInspector.ContextMenu();
var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
@@ -363,13 +427,19 @@ WebInspector.SourceFrame.prototype = {
contextMenu.show(event);
},
- _toggleBreakpoint: function(lineNumber, event)
+ _mouseDown: function(event)
{
if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
return;
+ if (event.target.className !== "webkit-line-number")
+ return;
+ var row = event.target.parentElement;
+
+ var lineNumber = row.lineNumber;
+
var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
if (breakpoint)
- WebInspector.panels.scripts.removeBreakpoint(breakpoint);
+ this._removeBreakpointDelegate(breakpoint);
else if (this._addBreakpointDelegate)
this._addBreakpointDelegate(lineNumber + 1);
event.preventDefault();
@@ -382,14 +452,15 @@ WebInspector.SourceFrame.prototype = {
function committed(element, newText)
{
breakpoint.condition = newText;
- this._editor.paintLineNumbers();
dismissed.call(this);
}
function dismissed()
{
- this._editor.setDivDecoration(breakpoint.line - 1, null);
+ if (this._conditionElement)
+ this._textViewer.removeDecoration(breakpoint.line - 1, this._conditionElement);
delete this._conditionEditorElement;
+ delete this._conditionElement;
}
var dismissedHandler = dismissed.bind(this);
@@ -402,23 +473,23 @@ WebInspector.SourceFrame.prototype = {
_showBreakpointConditionPopup: function(lineNumber)
{
- var conditionElement = this._createConditionElement(lineNumber);
- this._editor.setDivDecoration(lineNumber - 1, conditionElement);
+ this._conditionElement = this._createConditionElement(lineNumber);
+ this._textViewer.addDecoration(lineNumber - 1, this._conditionElement);
},
_createConditionElement: function(lineNumber)
{
var conditionElement = document.createElement("div");
- conditionElement.className = "source-breakpoint-condition";
+ conditionElement.className = "source-frame-breakpoint-condition";
var labelElement = document.createElement("label");
- labelElement.className = "source-breakpoint-message";
- labelElement.htmlFor = "source-breakpoint-condition";
+ labelElement.className = "source-frame-breakpoint-message";
+ labelElement.htmlFor = "source-frame-breakpoint-condition";
labelElement.appendChild(document.createTextNode(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber)));
conditionElement.appendChild(labelElement);
var editorElement = document.createElement("input");
- editorElement.id = "source-breakpoint-condition";
+ editorElement.id = "source-frame-breakpoint-condition";
editorElement.className = "monospace";
editorElement.type = "text"
conditionElement.appendChild(editorElement);
@@ -434,9 +505,8 @@ WebInspector.SourceFrame.prototype = {
if (handler) {
handler(event);
event.preventDefault();
- } else {
+ } else
WebInspector.documentKeyDown(event);
- }
},
_evalSelectionInCallFrame: function(event)
@@ -457,146 +527,139 @@ WebInspector.SourceFrame.prototype = {
});
},
- _breakpointChanged: function(event)
+ resize: function()
{
- this._editor.paintLineNumbers();
+ if (this._textViewer)
+ this._textViewer.resize();
},
- resize: function()
+ _drawProgramCounterInContext: function(ctx, glow)
{
- if (this._editor)
- this._editor.resize();
- }
-}
+ if (glow)
+ ctx.save();
-WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;
+ ctx.beginPath();
+ ctx.moveTo(17, 2);
+ ctx.lineTo(19, 2);
+ ctx.lineTo(19, 0);
+ ctx.lineTo(21, 0);
+ ctx.lineTo(26, 5.5);
+ ctx.lineTo(21, 11);
+ ctx.lineTo(19, 11);
+ ctx.lineTo(19, 9);
+ ctx.lineTo(17, 9);
+ ctx.closePath();
+ ctx.fillStyle = "rgb(142, 5, 4)";
-WebInspector.BreakpointLineNumberDecorator = function(sourceFrame, textModel)
-{
- this._sourceFrame = sourceFrame;
- this._textModel = textModel;
-}
+ if (glow) {
+ ctx.shadowBlur = 4;
+ ctx.shadowColor = "rgb(255, 255, 255)";
+ ctx.shadowOffsetX = -1;
+ ctx.shadowOffsetY = 0;
+ }
-WebInspector.BreakpointLineNumberDecorator.prototype = {
- decorate: function(lineNumber, ctx, x, y, width, height, lineHeight)
- {
- var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
- var isExecutionLine = lineNumber + 1 === this._sourceFrame._executionLine;
- if (breakpoint || isExecutionLine) {
- ctx.save();
- ctx.translate(x + 4, y + 2);
- var breakpointWidth = width - 6;
- var breakpointHeight = lineHeight - 4;
-
- if (breakpoint)
- this._paintBreakpoint(ctx, breakpointWidth, breakpointHeight, breakpoint);
-
- if (isExecutionLine)
- this._paintProgramCounter(ctx, breakpointWidth, breakpointHeight, false);
+ ctx.fill();
+ ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels.
+ if (glow)
ctx.restore();
- }
+ },
- if (isExecutionLine) {
- // Override default behavior.
- return true;
- }
+ _drawProgramCounterImageIfNeeded: function()
+ {
+ if (!this._needsProgramCounterImage)
+ return;
+
+ var ctx = document.getCSSCanvasContext("2d", "program-counter", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ this._drawProgramCounterInContext(ctx, true);
- ctx.fillStyle = breakpoint ? "rgb(255,255,255)" : "rgb(155,155,155)";
- return false;
+ delete this._needsProgramCounterImage;
},
- _paintBreakpoint: function(ctx, width, height, breakpoint)
+ _drawBreakpointImagesIfNeeded: function(conditional)
{
- ctx.beginPath();
- ctx.moveTo(0, 2);
- ctx.lineTo(2, 0);
- ctx.lineTo(width - 5, 0);
- ctx.lineTo(width, height / 2);
- ctx.lineTo(width - 5, height);
- ctx.lineTo(2, height);
- ctx.lineTo(0, height - 2);
- ctx.closePath();
- ctx.fillStyle = breakpoint.condition ? "rgb(217, 142, 1)" : "rgb(1, 142, 217)";
- ctx.strokeStyle = breakpoint.condition ? "rgb(205, 103, 0)" : "rgb(0, 103, 205)";
- ctx.lineWidth = 3;
- ctx.fill();
+ if (!this._needsBreakpointImages)
+ return;
+
+ function drawBreakpoint(ctx, disabled, conditional)
+ {
+ ctx.beginPath();
+ ctx.moveTo(0, 2);
+ ctx.lineTo(2, 0);
+ ctx.lineTo(21, 0);
+ ctx.lineTo(26, 5.5);
+ ctx.lineTo(21, 11);
+ ctx.lineTo(2, 11);
+ ctx.lineTo(0, 9);
+ ctx.closePath();
+ ctx.fillStyle = conditional ? "rgb(217, 142, 1)" : "rgb(1, 142, 217)";
+ ctx.strokeStyle = conditional ? "rgb(205, 103, 0)" : "rgb(0, 103, 205)";
+ ctx.lineWidth = 3;
+ ctx.fill();
+ ctx.save();
+ ctx.clip();
+ ctx.stroke();
+ ctx.restore();
- ctx.save();
- ctx.clip();
- ctx.stroke();
- ctx.restore();
+ if (!disabled)
+ return;
- if (!breakpoint.enabled) {
ctx.save();
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
- ctx.fillRect(0, 0, width, height);
+ ctx.fillRect(0, 0, 26, 11);
ctx.restore();
}
- },
- _paintProgramCounter: function(ctx, width, height)
- {
- ctx.save();
- ctx.beginPath();
- ctx.moveTo(width - 9, 2);
- ctx.lineTo(width - 7, 2);
- ctx.lineTo(width - 7, 0);
- ctx.lineTo(width - 5, 0);
- ctx.lineTo(width, height / 2);
- ctx.lineTo(width - 5, height);
- ctx.lineTo(width - 7, height);
- ctx.lineTo(width - 7, height - 2);
- ctx.lineTo(width - 9, height - 2);
- ctx.closePath();
- ctx.fillStyle = "rgb(142, 5, 4)";
+ // Unconditional breakpoints.
- ctx.shadowBlur = 4;
- ctx.shadowColor = "rgb(255, 255, 255)";
- ctx.shadowOffsetX = -1;
- ctx.shadowOffsetY = 0;
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx);
- ctx.fill();
- ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels.
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-program-counter", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx);
+ ctx.clearRect(20, 0, 6, 11);
+ this._drawProgramCounterInContext(ctx, true);
- ctx.restore();
- },
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, true);
- mouseDown: function(lineNumber, e)
- {
- this._sourceFrame._toggleBreakpoint(lineNumber, e);
- return true;
- },
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-program-counter", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, true);
+ ctx.clearRect(20, 0, 6, 11);
+ this._drawProgramCounterInContext(ctx, true);
- contextMenu: function(lineNumber, e)
- {
- this._sourceFrame._contextMenu(lineNumber, e);
- return true;
- }
-}
-WebInspector.ExecutionLineDecorator = function(sourceFrame)
-{
- this._sourceFrame = sourceFrame;
-}
+ // Conditional breakpoints.
-WebInspector.ExecutionLineDecorator.prototype = {
- decorate: function(lineNumber, ctx, x, y, width, height, lineHeight)
- {
- if (this._sourceFrame._executionLine !== lineNumber + 1)
- return;
- ctx.save();
- ctx.fillStyle = "rgb(171, 191, 254)";
- ctx.fillRect(x, y, width, height);
-
- ctx.beginPath();
- ctx.rect(x - 1, y, width + 2, height);
- ctx.clip();
- ctx.strokeStyle = "rgb(64, 115, 244)";
- ctx.stroke();
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-conditional", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, false, true);
- ctx.restore();
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-conditional-program-counter", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, false, true);
+ ctx.clearRect(20, 0, 6, 11);
+ this._drawProgramCounterInContext(ctx, true);
+
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-conditional", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, true, true);
+
+ var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-conditional-program-counter", 26, 11);
+ ctx.clearRect(0, 0, 26, 11);
+ drawBreakpoint(ctx, true, true);
+ ctx.clearRect(20, 0, 6, 11);
+ this._drawProgramCounterInContext(ctx, true);
+
+ delete this._needsBreakpointImages;
}
}
+
+WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;
diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js
index 7fc8499..b401c12 100644
--- a/WebCore/inspector/front-end/SourceView.js
+++ b/WebCore/inspector/front-end/SourceView.js
@@ -32,7 +32,7 @@ WebInspector.SourceView = function(resource)
this.element.addStyleClass("source");
- this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this));
+ this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this));
resource.addEventListener("finished", this._resourceLoadingFinished, this);
this._frameNeedsSetup = true;
}
@@ -58,16 +58,6 @@ WebInspector.SourceView.prototype = {
this.sourceFrame.resize();
},
- detach: function()
- {
- WebInspector.ResourceView.prototype.detach.call(this);
-
- // FIXME: We need to mark the frame for setup on detach because the frame DOM is cleared
- // when it is removed from the document. Is this a bug?
- this._frameNeedsSetup = true;
- this._sourceFrameSetup = false;
- },
-
setupSourceFrameIfNeeded: function()
{
if (!this._frameNeedsSetup)
@@ -118,6 +108,12 @@ WebInspector.SourceView.prototype = {
}
},
+ _removeBreakpoint: function(breakpoint)
+ {
+ if (WebInspector.panels.scripts)
+ WebInspector.panels.scripts.removeBreakpoint(breakpoint);
+ },
+
// The rest of the methods in this prototype need to be generic enough to work with a ScriptView.
// The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code.
@@ -125,7 +121,7 @@ WebInspector.SourceView.prototype = {
{
this._currentSearchResultIndex = -1;
this._searchResults = [];
- this.sourceFrame.clearSelection();
+ this.sourceFrame.clearMarkedRange();
delete this._delayedFindSearchMatches;
},
@@ -225,7 +221,7 @@ WebInspector.SourceView.prototype = {
if (!foundRange)
return;
- this.sourceFrame.setSelection(foundRange);
+ this.sourceFrame.markAndRevealRange(foundRange);
},
_sourceFrameSetupFinished: function()
diff --git a/WebCore/inspector/front-end/StoragePanel.js b/WebCore/inspector/front-end/StoragePanel.js
index dee4442..ca1b276 100644
--- a/WebCore/inspector/front-end/StoragePanel.js
+++ b/WebCore/inspector/front-end/StoragePanel.js
@@ -220,14 +220,14 @@ WebInspector.StoragePanel.prototype = {
this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
},
- showCookies: function(cookieDomain)
+ showCookies: function(treeElement, cookieDomain)
{
if (this.visibleView)
this.visibleView.hide();
var view = this._cookieViews[cookieDomain];
if (!view) {
- view = new WebInspector.CookieItemsView(cookieDomain);
+ view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
this._cookieViews[cookieDomain] = view;
}
@@ -300,52 +300,14 @@ WebInspector.StoragePanel.prototype = {
var data = {};
var row = rows[i];
- for (var columnIdentifier in row) {
- var text = row[columnIdentifier];
- data[columnIdentifier] = text;
- if (text.length > columns[columnIdentifier].width)
- columns[columnIdentifier].width = text.length;
- }
+ for (var columnIdentifier in row)
+ data[columnIdentifier] = row[columnIdentifier];
var node = new WebInspector.DataGridNode(data, false);
node.selectable = false;
nodes.push(node);
}
- var totalColumnWidths = 0;
- for (var columnIdentifier in columns)
- totalColumnWidths += columns[columnIdentifier].width;
-
- // Calculate the percentage width for the columns.
- const minimumPrecent = Math.min(5, Math.floor(100/numColumns));
- var recoupPercent = 0;
- for (var columnIdentifier in columns) {
- var width = columns[columnIdentifier].width;
- width = Math.round((width / totalColumnWidths) * 100);
- if (width < minimumPrecent) {
- recoupPercent += (minimumPrecent - width);
- width = minimumPrecent;
- }
-
- columns[columnIdentifier].width = width;
- }
-
- // Enforce the minimum percentage width.
- while (recoupPercent > 0) {
- for (var columnIdentifier in columns) {
- if (columns[columnIdentifier].width > minimumPrecent) {
- --columns[columnIdentifier].width;
- --recoupPercent;
- if (!recoupPercent)
- break;
- }
- }
- }
-
- // Change the width property to a string suitable for a style width.
- for (var columnIdentifier in columns)
- columns[columnIdentifier].width += "%";
-
var dataGrid = new WebInspector.DataGrid(columns);
var length = nodes.length;
for (var i = 0; i < length; ++i)
@@ -507,6 +469,7 @@ WebInspector.CookieSidebarTreeElement = function(cookieDomain)
{
WebInspector.SidebarTreeElement.call(this, "cookie-sidebar-tree-item", cookieDomain, "", null, false);
this._cookieDomain = cookieDomain;
+ this._subtitle = "";
this.refreshTitles();
}
@@ -514,9 +477,9 @@ WebInspector.CookieSidebarTreeElement = function(cookieDomain)
WebInspector.CookieSidebarTreeElement.prototype = {
onselect: function()
{
- WebInspector.panels.storage.showCookies(this._cookieDomain);
+ WebInspector.panels.storage.showCookies(this, this._cookieDomain);
},
-
+
get mainTitle()
{
return this._cookieDomain ? this._cookieDomain : WebInspector.UIString("Local Files");
@@ -529,12 +492,13 @@ WebInspector.CookieSidebarTreeElement.prototype = {
get subtitle()
{
- return "";
+ return this._subtitle;
},
set subtitle(x)
{
- // Do nothing.
+ this._subtitle = x;
+ this.refreshTitles();
}
}
diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js
index f04cb66..265e488 100644
--- a/WebCore/inspector/front-end/StylesSidebarPane.js
+++ b/WebCore/inspector/front-end/StylesSidebarPane.js
@@ -60,8 +60,8 @@ WebInspector.StylesSidebarPane = function()
this.settingsSelectElement.addEventListener("click", function(event) { event.stopPropagation() }, false);
this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false);
- WebInspector.settings.addEventListener("loaded", this._settingsLoaded, this);
-
+ WebInspector.settings.addEventListener("loaded", this._settingsLoaded, this);
+
this.titleElement.appendChild(this.settingsSelectElement);
}
@@ -354,7 +354,7 @@ WebInspector.StylesSidebarPane.prototype = {
var blankSection = new WebInspector.BlankStylePropertiesSection(appropriateSelectorForNode(this.node, true));
blankSection.pane = this;
- var elementStyleSection = this.sections[1];
+ var elementStyleSection = this.sections[1];
this.bodyElement.insertBefore(blankSection.element, elementStyleSection.element.nextSibling);
this.sections.splice(2, 0, blankSection);
@@ -445,7 +445,7 @@ WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyl
this.identifier = styleRule.selectorText;
if (this.subtitle)
- this.identifier += ":" + this.subtitleElement.textContent;
+ this.identifier += ":" + this.subtitleElement.textContent;
}
WebInspector.StylePropertiesSection.prototype = {
@@ -530,6 +530,11 @@ WebInspector.StylePropertiesSection.prototype = {
}
}
+ this.afterUpdate();
+ },
+
+ afterUpdate: function()
+ {
if (this._afterUpdate) {
this._afterUpdate(this);
delete this._afterUpdate;
@@ -1296,8 +1301,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
if (alreadyNew && !valueChanged)
return;
- var item = section.addNewBlankProperty();
- item.startEditing();
+ section.addNewBlankProperty().startEditing();
return;
}
@@ -1315,6 +1319,7 @@ WebInspector.StylePropertyTreeElement.prototype = {
if (this._newProperty) {
// The user deleted everything, so remove the tree element and update.
this.parent.removeChild(this);
+ section.afterUpdate();
return;
} else {
delete section._afterUpdate;
diff --git a/WebCore/inspector/front-end/TextEditor.js b/WebCore/inspector/front-end/TextEditor.js
deleted file mode 100644
index 9268280..0000000
--- a/WebCore/inspector/front-end/TextEditor.js
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-WebInspector.TextEditor = function(textModel, platform)
-{
- this._textModel = textModel;
- this._textModel.changeListener = this._textChanged.bind(this);
- this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightChanged.bind(this));
-
- this.element = document.createElement("div");
- this.element.className = "text-editor monospace";
- this.element.tabIndex = 0;
-
- this._canvas = document.createElement("canvas");
- this._canvas.className = "text-editor-canvas";
- this.element.appendChild(this._canvas);
-
- this._container = document.createElement("div");
- this._container.className = "text-editor-container";
- this.element.appendChild(this._container);
-
- this._sheet = document.createElement("div");
- this._container.appendChild(this._sheet);
-
- var cursorElement = document.createElement("div");
- cursorElement.className = "text-editor-cursor";
- this._container.appendChild(cursorElement);
- this._cursor = new WebInspector.TextCursor(cursorElement);
-
- this._container.addEventListener("scroll", this._scroll.bind(this), false);
-
- this._registerMouseListeners();
- this._registerKeyboardListeners();
- this._registerClipboardListeners();
-
- this._desiredCaretColumn = 0;
- this._scrollLeft = 0;
- this._scrollTop = 0;
-
- this._ctx = this._canvas.getContext("2d");
- this._selection = new WebInspector.TextSelectionModel(this._selectionChanged.bind(this));
-
- this._isMac = platform && (platform.indexOf("mac") === 0);
- this._paintCoalescingLevel = 0;
-
- this._registerShortcuts();
- // Debugging flags, allow disabling / enabling highlights and track repaints.
- this._highlightingEnabled = true;
- this._debugMode = false;
-
- this._textWidth = 0;
- this._longestLineNumber = 0;
-
- this._lineOffsetsCache = [0];
- this._readOnly = false;
- this._selectionColor = "rgb(181, 213, 255)";
-}
-
-WebInspector.TextEditor.prototype = {
- set text(text)
- {
- var lastLine = this._textModel.linesCount - 1;
- this._textModel.setText(null, text);
- this._textModel.resetUndoStack();
- this._setCaretLocation(0, 0);
- },
-
- set mimeType(mimeType)
- {
- this._highlighter.mimeType = mimeType;
- },
-
- get textModel()
- {
- return this._textModel;
- },
-
- set readOnly(readOnly)
- {
- this._readOnly = readOnly;
- if (readOnly)
- this.element.addStyleClass("text-editor-readonly")
- else
- this.element.removeStyleClass("text-editor-readonly")
- },
-
- set lineNumberDecorator(lineNumberDecorator)
- {
- this._lineNumberDecorator = lineNumberDecorator;
- },
-
- set lineDecorator(lineDecorator)
- {
- this._lineDecorator = lineDecorator;
- },
-
- get selection()
- {
- return this._selection.range();
- },
-
- setSelection: function(startLine, startColumn, endLine, endColumn)
- {
- var start = this._fit(startLine, startColumn);
- this._selection.setStart(start.line, start.column);
- this._setSelectionEnd(endLine, endColumn);
- },
-
- setDivDecoration: function(lineNumber, element)
- {
- var existingElement = this._textModel.getAttribute(lineNumber, "div-decoration");
- if (existingElement && existingElement.parentNode)
- existingElement.parentNode.removeChild(existingElement);
- this._textModel.removeAttribute(lineNumber, "div-decoration");
-
- if (element) {
- this.element.appendChild(element);
- this._textModel.setAttribute(lineNumber, "div-decoration", element);
- }
- this.revalidateDecorationsAndPaint();
- },
-
- _registerMouseListeners: function()
- {
- this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
- this.element.addEventListener("mouseup", this._mouseUp.bind(this), false);
- this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
- this.element.addEventListener("mousemove", this._mouseMove.bind(this), false);
- this.element.addEventListener("mouseout", this._mouseOut.bind(this), false);
- this.element.addEventListener("dblclick", this._dblClick.bind(this), false);
- },
-
- _registerKeyboardListeners: function()
- {
- this._container.addEventListener("keydown", this._keyDown.bind(this), false);
- this._container.addEventListener("textInput", this._textInput.bind(this), false);
- },
-
- _registerClipboardListeners: function()
- {
- this._container.addEventListener("beforecopy", this._beforeCopy.bind(this), false);
- this._container.addEventListener("copy", this._copy.bind(this), false);
- this._container.addEventListener("beforecut", this._beforeCut.bind(this), false);
- this._container.addEventListener("cut", this._cut.bind(this), false);
- this._container.addEventListener("beforepaste", this._beforePaste.bind(this), false);
- this._container.addEventListener("paste", this._paste.bind(this), false);
- },
-
- _offsetToLine: function(offset)
- {
- if (offset > this._lineOffsetsCache[this._lineOffsetsCache.length - 1]) {
- // Seeking outside cached area. Fill the cache.
- var lineNumber = this._lineOffsetsCache.length;
- while (lineNumber < this._textModel.linesCount && this._lineToOffset(lineNumber) < offset)
- lineNumber++;
- return lineNumber;
- }
-
- // Bisect.
- var from = 0;
- var to = this._lineOffsetsCache.length;
- while (to > from + 1) {
- var mid = Math.floor((from + to) / 2);
- if (this._lineOffsetsCache[mid] > offset)
- to = mid;
- else
- from = mid;
- }
- return to;
- },
-
- _lineToOffset: function(lineNumber)
- {
- var offset = this._lineOffsetsCache[lineNumber];
- if (offset)
- return offset;
- for (var line = lineNumber; line > 0; --line) {
- if (this._lineOffsetsCache[line])
- break;
- }
- offset = this._lineOffsetsCache[line];
- for (var i = line + 1; i <= lineNumber; ++i) {
- offset += this._lineHeight(i - 1);
- this._lineOffsetsCache[i] = offset;
- }
- return offset;
- },
-
- _lineHeight: function(lineNumber)
- {
- // Use cached value first.
- if (this._lineOffsetsCache[lineNumber + 1])
- return this._lineOffsetsCache[lineNumber + 1] - this._lineOffsetsCache[lineNumber];
-
- var element = this._textModel.getAttribute(lineNumber, "div-decoration");
- if (element)
- return 2 * this._textLineHeight + element.clientHeight;
- return this._textLineHeight;
- },
-
- reveal: function(line, column)
- {
- this._scrollTop = this._container.scrollTop;
- this._scrollLeft = this._container.scrollLeft;
-
- var maxScrollTop = this._lineToOffset(line);
- var minScrollTop = maxScrollTop + this._lineHeight(line) - this._canvas.height;
- if (this._scrollTop > maxScrollTop)
- this._container.scrollTop = maxScrollTop - this._textLineHeight * 2;
- else if (this._scrollTop < minScrollTop)
- this._container.scrollTop = minScrollTop + this._textLineHeight * 2;
-
- var firstColumn = this._columnForOffset(line, this._scrollLeft);
- var maxScrollLeft = this._columnToOffset(line, column);
- var minScrollLeft = maxScrollLeft - this._container.clientWidth + this._lineNumberWidth;
- if (this._scrollLeft < minScrollLeft)
- this._container.scrollLeft = minScrollLeft + 100;
- else if (this._scrollLeft > maxScrollLeft)
- this._container.scrollLeft = maxScrollLeft;
- else if (minScrollLeft < 0 && maxScrollLeft > 0)
- this._container.scrollLeft = 0;
- },
-
- // WebInspector.TextModel listener
- _textChanged: function(oldRange, newRange, oldText, newText)
- {
- if (newRange.linesCount == oldRange.linesCount)
- this._invalidateLines(newRange.startLine, newRange.endLine + 1);
- else
- // Lines shifted, invalidate all under start line. Also clear lines that now are outside model range.
- this._invalidateLines(newRange.startLine, this._textModel.linesCount + Math.max(0, oldRange.endLine - newRange.endLine));
-
- if (this._highlightingEnabled) {
- var lastVisibleLine = Math.min(this._textModel.linesCount, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
- this._highlighter.updateHighlight(newRange.startLine, lastVisibleLine);
- }
-
- this._updatePreferredSize(newRange.startLine, Math.max(newRange.endLine, oldRange.endLine));
- if (oldRange.linesCount !== newRange.linesCount) {
- // Invalidate offset cache.
- this._lineOffsetsCache.length = oldRange.startLine + 1;
- // Force linenumber cache to be continuous.
- this._lineToOffset(oldRange.startLine);
- this.paintLineNumbers();
- }
- this._paint();
- },
-
- // WebInspector.TextSelectionModel listener
- _selectionChanged: function(oldRange, newRange)
- {
- if (oldRange.isEmpty() && newRange.isEmpty() && oldRange.startLine === newRange.startLine) {
- // Nothing to repaint.
- return;
- }
-
- this._invalidateLines(oldRange.startLine, oldRange.endLine + 1);
- this._invalidateLines(newRange.startLine, newRange.endLine + 1);
- this._paint();
- },
-
- _highlightChanged: function(fromLine, toLine)
- {
- if (this._muteHighlightListener)
- return;
-
- this._invalidateLines(fromLine, toLine);
- this._paint();
- },
-
- revalidateDecorationsAndPaint: function()
- {
- this.setCoalescingUpdate(true);
- this._lineOffsetsCache = [0];
- this._updatePreferredSize(0, this._textModel.linesCount);
- this.repaintAll();
- this.setCoalescingUpdate(false);
- },
-
- _updatePreferredSize: function(startLine, endLine)
- {
- this._ctx.font = this._font;
- this.setCoalescingUpdate(true);
- var guardedEndLine = Math.min(this._textModel.linesCount, endLine + 1);
- var newMaximum = false;
- for (var i = startLine; i < guardedEndLine; ++i) {
- var lineWidth = this._ctx.measureText(this._textModel.line(i)).width;
- if (lineWidth > this._textWidth) {
- this._textWidth = lineWidth;
- this._longestLineNumber = i;
- newMaximum = true;
- }
- }
-
- if (!newMaximum && startLine <= this._longestLineNumber && this._longestLineNumber <= endLine) {
- this._textWidth = 0;
- this._longestLineNumber = 0;
- for (var i = 0; i < this._textModel.linesCount; ++i) {
- var lineWidth = this._ctx.measureText(this._textModel.line(i)).width;
- if (lineWidth > this._textWidth) {
- this._textWidth = lineWidth;
- this._longestLineNumber = i;
- }
- }
- }
-
- var newLineNumberDigits = this._decimalDigits(this._textModel.linesCount);
- this._lineNumberWidth = (newLineNumberDigits + 2) * this._digitWidth;
- this._container.style.left = this._lineNumberWidth + "px";
-
- var newWidth = this._textWidth + "px";
- var newHeight = this._lineToOffset(this._textModel.linesCount) + "px";
- this._sheet.style.width = newWidth;
- this._sheet.style.height = newHeight;
-
- if (newLineNumberDigits !== this._lineNumberDigits) {
- this._lineNumberDigits = newLineNumberDigits;
- this.repaintAll();
- }
-
- // Changes to size can change the client area (scrollers can appear/disappear)
- this.resize();
- this.setCoalescingUpdate(false);
- },
-
- resize: function()
- {
- if (this._canvas.width !== this._container.clientWidth || this._canvas.height !== this._container.clientHeight) {
- this._canvas.width = this._container.clientWidth + this._lineNumberWidth;
- this._canvas.height = this._container.clientHeight;
- this.repaintAll();
- }
- },
-
- repaintAll: function()
- {
- this._invalidateLines(0, this._textModel.linesCount);
- this._paint();
- },
-
- _invalidateLines: function(startLine, endLine)
- {
- if (!this._damage)
- this._damage = [ { startLine: startLine, endLine: endLine } ];
- else {
- for (var i = 0; i < this._damage.length; ++i) {
- var chunk = this._damage[i];
- if (chunk.startLine <= endLine && chunk.endLine >= startLine) {
- chunk.startLine = Math.min(chunk.startLine, startLine);
- chunk.endLine = Math.max(chunk.endLine, endLine);
- return;
- }
- }
- this._damage.push({ startLine: startLine, endLine: endLine });
- }
- },
-
- _paint: function()
- {
- this._scrollTop = this._container.scrollTop;
- this._scrollLeft = this._container.scrollLeft;
-
- if (this._paintCoalescingLevel)
- return;
-
- this._updateDivDecorations();
-
- this.paintLineNumbers();
-
- for (var i = 0; this._damage && i < this._damage.length; ++i)
- this._paintLines(this._damage[i].startLine, this._damage[i].endLine);
- delete this._damage;
-
- this._updateCursor(this._selection.endLine, this._selection.endColumn);
- },
-
- _paintLines: function(firstLine, lastLine)
- {
- this._ctx.font = this._font;
- this._ctx.textBaseline = "bottom";
-
- firstLine = Math.max(firstLine, this._offsetToLine(this._scrollTop) - 1);
- lastLine = Math.min(lastLine, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
- if (firstLine > lastLine)
- return;
-
- if (this._debugMode) {
- WebInspector.log("Repaint %d:%d", firstLine, lastLine);
- this._ctx.fillStyle = "rgb(255,255,0)";
- var fromOffset = this._lineToOffset(firstLine);
- var toOffset = this._lineToOffset(lastLine);
- this._ctx.fillRect(this._lineNumberWidth - 1, fromOffset - this._scrollTop, this._canvas.width - this._lineNumberWidth + 1, toOffset - fromOffset);
- setTimeout(this._paintLinesContinuation.bind(this, firstLine, lastLine), 100);
- } else
- this._paintLinesContinuation(firstLine, lastLine);
- },
-
- _paintLinesContinuation: function(firstLine, lastLine) {
- // Clip editor area.
- this._ctx.save();
- this._ctx.beginPath();
- this._ctx.rect(this._lineNumberWidth - 1, 0, this._canvas.width - this._lineNumberWidth + 1, this._canvas.height);
- this._ctx.clip();
-
- // First clear the region, then update last line to fit model (this clears removed lines from the end of the document).
- var fromOffset = this._lineToOffset(firstLine);
- var toOffset = lastLine < this._textModel.linesCount ? this._lineToOffset(lastLine) : this._canvas.height + this._scrollTop;
-
- // Do not clear region when paintCurrentLine is likely to do all the necessary work.
- if (this._readOnly || firstLine + 1 != lastLine || this._selection.endLine != firstLine) {
- this._ctx.fillStyle = "rgb(255,255,255)";
- this._ctx.fillRect(0, fromOffset - this._scrollTop, this._canvas.width, toOffset - fromOffset);
- }
- lastLine = Math.min(lastLine, this._textModel.linesCount);
-
- // Paint current line for editable mode only.
- if (!this._readOnly && this._selection.startLine === this._selection.endLine && firstLine <= this._selection.startLine && this._selection.startLine < lastLine)
- this._paintCurrentLine(this._selection.startLine);
-
- this._paintSelection(firstLine, lastLine);
-
- if (this._highlightingEnabled) {
- this._muteHighlightListener = true;
- this._highlighter.highlight(lastLine);
- delete this._muteHighlightListener;
- }
- for (var i = firstLine; i < lastLine; ++i) {
- var lineOffset = this._lineToOffset(i) - this._scrollTop;
-
- if (this._lineDecorator)
- this._lineDecorator.decorate(i, this._ctx, this._lineNumberWidth - 1, lineOffset, this._canvas.width - this._lineNumberWidth + 1, this._lineHeight(i), this._textLineHeight);
-
- var element = this._textModel.getAttribute(i, "div-decoration");
- if (element)
- this._positionDivDecoration(i, element, true);
-
- this._paintLine(i, lineOffset);
- }
- this._ctx.restore();
- },
-
- _paintLine: function(lineNumber, lineOffset)
- {
- var line = this._textModel.line(lineNumber);
- if (!this._highlightingEnabled) {
- this._ctx.fillStyle = "rgb(0,0,0)";
- this._ctx.fillText(line, this._lineNumberWidth - this._scrollLeft, lineOffset + this._textLineHeight);
- return;
- }
-
- if (line.length > 1000) {
- // Optimization: no need to paint decorations outside visible area.
- var firstColumn = this._columnForOffset(lineNumber, this._scrollLeft);
- var lastColumn = this._columnForOffset(lineNumber, this._scrollLeft + this._canvas.width);
- }
- var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
- var plainTextStart = -1;
- for (var j = 0; j < line.length;) {
- var attribute = highlighterState && highlighterState.attributes[j];
- if (attribute && firstColumn && j + attribute.length < firstColumn) {
- j += attribute.length;
- continue;
- }
- if (attribute && lastColumn && j > lastColumn)
- break;
- if (!attribute || !attribute.style) {
- if (plainTextStart === -1)
- plainTextStart = j;
- j++;
- } else {
- if (plainTextStart !== -1) {
- this._ctx.fillStyle = "rgb(0,0,0)";
- this._ctx.fillText(line.substring(plainTextStart, j), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, plainTextStart), lineOffset + this._textLineHeight);
- plainTextStart = -1;
- }
- this._ctx.fillStyle = attribute.style;
- this._ctx.fillText(line.substring(j, j + attribute.length), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, j), lineOffset + this._textLineHeight);
- j += attribute.length;
- }
- }
- if (plainTextStart !== -1) {
- this._ctx.fillStyle = "rgb(0,0,0)";
- this._ctx.fillText(line.substring(plainTextStart, j), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, plainTextStart), lineOffset + this._textLineHeight);
- }
- },
-
- paintLineNumbers: function()
- {
- this._ctx.font = this._font;
- this._ctx.textBaseline = "bottom";
-
- this._ctx.fillStyle = "rgb(255,255,255)";
- this._ctx.fillRect(0, 0, this._lineNumberWidth - 2, this._canvas.height);
-
- this._ctx.fillStyle = "rgb(235,235,235)";
- this._ctx.fillRect(this._lineNumberWidth - 2, 0, 1, this._canvas.height);
-
- var firstLine = Math.max(0, this._offsetToLine(this._scrollTop) - 1);
- var lastLine = Math.min(this._textModel.linesCount, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
-
- for (var i = firstLine; i < lastLine; ++i) {
- var lineOffset = this._lineToOffset(i) - this._scrollTop;
- this._ctx.fillStyle = "rgb(155,155,155)";
- if (this._lineNumberDecorator && this._lineNumberDecorator.decorate(i, this._ctx, 0, lineOffset, this._lineNumberWidth, this._lineHeight(i), this._textLineHeight))
- continue;
- this._ctx.fillText(i + 1, (this._lineNumberDigits - this._decimalDigits(i + 1) + 1) * this._digitWidth, lineOffset + this._textLineHeight);
- }
- },
-
- _paintCurrentLine: function(line)
- {
- this._ctx.fillStyle = "rgb(232, 242, 254)";
- this._ctx.fillRect(0, this._lineToOffset(line) - this._scrollTop, this._canvas.width, this._lineHeight(line));
- },
-
- _scroll: function(e)
- {
- // Hide div-based cursor first.
- this._cursor._cursorElement.style.display = "none";
- setTimeout(this._repaintOnScroll.bind(this), 10);
- },
-
- _repaintOnScroll: function()
- {
- if (this._scrollTop !== this._container.scrollTop || this._scrollLeft !== this._container.scrollLeft) {
- this._scrollTop = this._container.scrollTop;
- this._scrollLeft = this._container.scrollLeft;
- this.repaintAll();
- }
- },
-
- _mouseUp: function(e)
- {
- this._isDragging = false;
- },
-
- _mouseDown: function(e)
- {
- if (e.button === 2 || (this._isMac && e.ctrlKey))
- return;
-
- var location = this._caretForMouseEvent(e);
-
- if (e.target === this.element && this._lineNumberDecorator) {
- if (this._lineNumberDecorator.mouseDown(location.line, e))
- return;
- }
-
- if (e.shiftKey)
- this._setSelectionEnd(location.line, location.column);
- else
- this._setCaretLocation(location.line, location.column);
- this._isDragging = true;
- this._textModel.markUndoableState();
- },
-
- _mouseMove: function(e)
- {
- if (!this._isDragging)
- return;
- var location = this._caretForMouseEvent(e);
- this._setSelectionEnd(location.line, location.column)
- },
-
- _mouseOut: function(e)
- {
- },
-
- _dblClick: function(e)
- {
- var location = this._caretForMouseEvent(e);
- var range = this._textModel.wordRange(location.line, location.column);
- this.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
- },
-
- _contextMenu: function(e)
- {
- if (e.target === this.element && this._lineNumberDecorator) {
- var location = this._caretForMouseEvent(e);
- if (this._lineNumberDecorator.contextMenu(location.line, e))
- return;
- } else {
- var range = this._selection.range();
- if (!range.isEmpty()) {
- var text = this._textModel.copyRange(range);
- var contextMenu = new WebInspector.ContextMenu();
- contextMenu.appendItem(WebInspector.UIString("Copy"), this._copy.bind(this));
- contextMenu.show(event);
- }
- }
- },
-
- _caretForMouseEvent: function(e)
- {
- var lineNumber = Math.max(0, this._offsetToLine(e.offsetY + (e.target === this.element ? this._scrollTop : 0)) - 1);
- var offset = e.offsetX + this._scrollLeft;
- return { line: lineNumber, column: this._columnForOffset(lineNumber, offset) };
- },
-
- _columnForOffset: function(lineNumber, offset)
- {
- var length = 0;
- var line = this._textModel.line(lineNumber);
-
- // First pretend it is monospace to get a quick guess.
- var charWidth = this._ctx.measureText("a").width;
- var index = Math.floor(offset / charWidth);
- var indexOffset = this._ctx.measureText(line.substring(0, index)).width;
- if (offset >= indexOffset && index < line.length && offset < indexOffset + this._ctx.measureText(line.charAt(index)).width)
- return index;
-
- // Fallback to non-monospace.
- var delta = indexOffset < offset ? 1 : -1;
- while (index >=0 && index < line.length) {
- index += delta;
- indexOffset += delta * this._ctx.measureText(line.charAt(index)).width;
- if (offset >= indexOffset && offset < indexOffset + charWidth)
- return index;
- }
- return line.length;
- },
-
- _columnToOffset: function(lineNumber, column)
- {
- var line = this._textModel.line(lineNumber);
- return this._ctx.measureText(line.substring(0, column)).width;
- },
-
- _keyDown: function(e)
- {
- var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(e);
- var handler = this._shortcuts[shortcutKey];
- if (handler) {
- handler.call(this);
- e.preventDefault();
- e.stopPropagation();
- return;
- }
-
- if (this._handleNavigationKey(e)) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
-
- if (this._readOnly)
- return;
-
- var keyCodes = WebInspector.KeyboardShortcut.KeyCodes;
- switch (e.keyCode) {
- case keyCodes.Backspace:
- this._handleBackspaceKey();
- break;
- case keyCodes.Delete:
- this._handleDeleteKey();
- break;
- case keyCodes.Tab:
- this._replaceSelectionWith("\t");
- break;
- case keyCodes.Enter:
- this._replaceSelectionWith("\n");
- break;
- default:
- return;
- }
-
- e.preventDefault();
- e.stopPropagation();
- },
-
- _handleNavigationKey: function(e)
- {
- var caretLine = this._selection.endLine;
- var caretColumn = this._selection.endColumn;
- var arrowAction = e.shiftKey ? this._setSelectionEnd : this._setCaretLocation;
-
- var keyCodes = WebInspector.KeyboardShortcut.KeyCodes;
- switch (e.keyCode) {
- case keyCodes.Up:
- case keyCodes.PageUp:
- if (e.metaKey)
- arrowAction.call(this, 0, 0, true);
- else if (e.ctrlKey)
- this._container.scrollTop -= this._lineHeight(caretLine);
- else {
- if (e.keyCode === keyCodes.Up)
- arrowAction.call(this, caretLine - 1, this._desiredCaretColumn, true);
- else {
- var offset = Math.max(0, this._lineToOffset(caretLine) - this._canvas.height);
- arrowAction.call(this, this._offsetToLine(offset), this._desiredCaretColumn, true);
- }
- }
- break;
- case keyCodes.Down:
- case keyCodes.PageDown:
- if (e.metaKey)
- arrowAction.call(this, this._textModel.linesCount - 1, this._textModel.lineLength(this._textModel.linesCount - 1), true);
- else if (e.ctrlKey)
- this._container.scrollTop += this._lineHeight(caretLine);
- else {
- if (e.keyCode === keyCodes.Down)
- arrowAction.call(this, caretLine + 1, this._desiredCaretColumn, true);
- else {
- var offset = this._lineToOffset(caretLine) + this._canvas.height;
- arrowAction.call(this, this._offsetToLine(offset), this._desiredCaretColumn, true);
- }
- }
- break;
- case keyCodes.Home:
- if (this._isMetaCtrl(e))
- arrowAction.call(this, 0, 0, true);
- else
- arrowAction.call(this, this._selection.endLine, 0);
- break;
- case keyCodes.End:
- if (this._isMetaCtrl(e))
- arrowAction.call(this, this._textModel.linesCount - 1, this._textModel.lineLength(this._textModel.linesCount - 1), true);
- else
- arrowAction.call(this, this._selection.endLine, this._textModel.lineLength(this._selection.endLine));
- break;
- case keyCodes.Left:
- if (!e.shiftKey && !e.metaKey && !this._isAltCtrl(e) && !this._selection.isEmpty()) {
- // Reset selection
- var range = this._selection.range();
- this._setCaretLocation(range.startLine, range.startColumn);
- } else if (e.metaKey)
- arrowAction.call(this, this._selection.endLine, 0);
- else if (caretColumn === 0 && caretLine > 0)
- arrowAction.call(this, caretLine - 1, this._textModel.lineLength(caretLine - 1));
- else if (this._isAltCtrl(e)) {
- caretColumn = this._textModel.wordStart(this._selection.endLine, this._selection.endColumn);
- if (caretColumn === this._selection.endColumn)
- caretColumn = 0;
- arrowAction.call(this, caretLine, caretColumn);
- } else
- arrowAction.call(this, caretLine, caretColumn - 1);
- break;
- case keyCodes.Right:
- var line = this._textModel.line(caretLine);
- if (!e.shiftKey && !e.metaKey && !this._isAltCtrl(e) && !this._selection.isEmpty()) {
- // Reset selection
- var range = this._selection.range();
- this._setCaretLocation(range.endLine, range.endColumn);
- } else if (e.metaKey)
- arrowAction.call(this, this._selection.endLine, this._textModel.lineLength(this._selection.endLine));
- else if (caretColumn === line.length && caretLine < this._textModel.linesCount - 1)
- arrowAction.call(this, caretLine + 1, 0);
- else if (this._isAltCtrl(e)) {
- caretColumn = this._textModel.wordEnd(this._selection.endLine, this._selection.endColumn);
- if (caretColumn === this._selection.endColumn)
- caretColumn = line.length;
- arrowAction.call(this, caretLine, caretColumn);
- } else
- arrowAction.call(this, caretLine, caretColumn + 1);
- break;
- default:
- return false;
- }
- this._textModel.markUndoableState();
- return true;
- },
-
- _textInput: function(e)
- {
- if (this._readOnly)
- return;
-
- if (e.data && !e.altKey && !e.ctrlKey && !e.metaKey) {
- this._replaceSelectionWith(e.data);
- e.preventDefault();
- e.stopPropagation();
- }
- },
-
- _setCaretLocation: function(line, column, updown)
- {
- this.setSelection(line, column, line, column, updown);
- },
-
- _setSelectionEnd: function(line, column, updown)
- {
- if (!updown)
- this._desiredCaretColumn = column;
-
- var end = this._fit(line, column);
- this._selection.setEnd(end.line, end.column);
- this.reveal(this._selection.endLine, this._selection.endColumn);
- this._updateCursor(end.line, end.column);
- },
-
- _updateDivDecorations: function()
- {
- var firstLine = this._offsetToLine(this._scrollTop) - 1;
- var lastLine = this._offsetToLine(this._scrollTop + this._canvas.height) + 1;
-
- var linesCount = this._textModel.linesCount;
- for (var i = 0; i < linesCount; ++i) {
- var element = this._textModel.getAttribute(i, "div-decoration");
- if (element) {
- this._lineOffsetsCache.length = Math.min(this._lineOffsetsCache.length, i + 1);
- this._positionDivDecoration(i, element, i > firstLine && i < lastLine);
- }
- }
- },
-
- _positionDivDecoration: function(lineNumber, element, visible)
- {
- element.style.position = "absolute";
- element.style.top = this._lineToOffset(lineNumber) - this._scrollTop + this._textLineHeight + "px";
- element.style.left = this._lineNumberWidth + "px";
- element.style.setProperty("max-width", this._canvas.width + "px");
- },
-
- _updateCursor: function(line, column)
- {
- if (line >= this._textModel.linesCount)
- return;
- var offset = this._columnToOffset(line, column);
- if (offset >= this._container.scrollLeft && !this._readOnly)
- this._cursor.setLocation(this._lineNumberWidth + offset - 1, this._lineToOffset(line));
- else
- this._cursor.hide();
- },
-
- _fit: function(line, column)
- {
- line = Math.max(0, Math.min(line, this._textModel.linesCount - 1));
- var lineLength = this._textModel.lineLength(line);
- column = Math.max(0, Math.min(column, lineLength));
- return { line: line, column: column };
- },
-
- _paintSelection: function(firstLine, lastLine)
- {
- if (this._selection.isEmpty())
- return;
- var range = this._selection.range();
- this._ctx.fillStyle = this._selectionColor;
-
- firstLine = Math.max(firstLine, range.startLine);
- endLine = Math.min(lastLine, range.endLine + 1);
-
- for (var i = firstLine; i < endLine; ++i) {
- var line = this._textModel.line(i);
- var from, to;
-
- if (i === range.startLine) {
- var offset = this._columnToOffset(range.startLine, range.startColumn);
- from = offset - this._scrollLeft + this._lineNumberWidth - 1;
- } else
- from = 0;
-
- if (i === range.endLine) {
- var offset = this._columnToOffset(range.endLine, range.endColumn);
- to = offset - this._scrollLeft + this._lineNumberWidth - 1;
- } else
- to = this._canvas.width;
-
- this._ctx.fillRect(from, this._lineToOffset(i) - this._scrollTop, to - from, this._lineHeight(i));
- }
- this._ctx.fillStyle = "rgb(0, 0, 0)";
- },
-
- _beforeCopy: function(e)
- {
- if (!this._selection.isEmpty())
- e.preventDefault();
- },
-
- _copy: function(e)
- {
- var range = this._selection.range();
- var text = this._textModel.copyRange(range);
-
- function delayCopy()
- {
- InspectorFrontendHost.copyText(text);
- }
-
- setTimeout(delayCopy);
- if (e)
- e.preventDefault();
- },
-
- _beforeCut: function(e)
- {
- if (!this._selection.isEmpty())
- e.preventDefault();
- },
-
- _cut: function(e)
- {
- if (this._readOnly) {
- e.preventDefault();
- return;
- }
-
- this._textModel.markUndoableState();
- this._copy(e);
- this._replaceSelectionWith("");
- },
-
- _beforePaste: function(e)
- {
- e.preventDefault();
- },
-
- _paste: function(e)
- {
- if (this._readOnly) {
- e.preventDefault();
- return;
- }
-
- var text = e.clipboardData.getData("Text");
- if (!text)
- return;
-
- this._textModel.markUndoableState();
- this._replaceSelectionWith(text);
- e.preventDefault();
- },
-
- _replaceSelectionWith: function(newText, overrideRange)
- {
- var range = overrideRange || this._selection.range();
- this.setCoalescingUpdate(true);
- var newRange = this._textModel.setText(range, newText);
- this._setCaretLocation(newRange.endLine, newRange.endColumn);
- this.setCoalescingUpdate(false);
- },
-
- setCoalescingUpdate: function(enabled)
- {
- if (enabled)
- this._paintCoalescingLevel++;
- else
- this._paintCoalescingLevel--;
- if (!this._paintCoalescingLevel)
- this._paint();
- },
-
- _selectAll: function()
- {
- // No need to reveal last selection line in select all.
- this._selection.setStart(0, 0);
- var lastLineNum = this._textModel.linesCount - 1;
- this._selection.setEnd(lastLineNum, this._textModel.lineLength(lastLineNum));
- this._updateCursor(this._selection.endLine, this._selection.endColumn);
- },
-
- initFontMetrics: function()
- {
- var computedStyle = window.getComputedStyle(this.element);
- this._font = computedStyle.fontSize + " " + computedStyle.fontFamily;
- this._ctx.font = this._font;
- this._digitWidth = this._ctx.measureText("0").width;
- this._textLineHeight = Math.floor(parseInt(this._ctx.font) * 1.4);
- this._cursor.setTextLineHeight(this._textLineHeight);
- },
-
- _registerShortcuts: function()
- {
- var modifiers = WebInspector.KeyboardShortcut.Modifiers;
- this._shortcuts = {};
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._handleUndo.bind(this);
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", modifiers.Shift | (this._isMac ? modifiers.Meta : modifiers.Ctrl))] = this._handleRedo.bind(this);
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("a", this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._selectAll.bind(this);
- if (this._isMac)
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("d", modifiers.Ctrl)] = this._handleDeleteKey.bind(this);
-
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("d", modifiers.Ctrl | modifiers.Alt)] = this._handleToggleDebugMode.bind(this);
- this._shortcuts[WebInspector.KeyboardShortcut.makeKey("h", modifiers.Ctrl | modifiers.Alt)] = this._handleToggleHighlightMode.bind(this);
- },
-
- _handleUndo: function()
- {
- this.setCoalescingUpdate(true);
- var range = this._textModel.undo();
- if (range)
- this._setCaretLocation(range.endLine, range.endColumn);
- this.setCoalescingUpdate(false);
- },
-
- _handleRedo: function()
- {
- this.setCoalescingUpdate(true);
- var range = this._textModel.redo();
- if (range)
- this._setCaretLocation(range.endLine, range.endColumn);
- this.setCoalescingUpdate(false);
- },
-
- _handleDeleteKey: function()
- {
- var range = this._selection.range();
- if (range.isEmpty()) {
- if (range.endColumn < this._textModel.lineLength(range.startLine))
- range.endColumn++;
- else if (range.endLine < this._textModel.linesCount) {
- range.endLine++;
- range.endColumn = 0;
- } else
- return;
- } else
- this._textModel.markUndoableState();
- this._replaceSelectionWith("", range);
- },
-
- _handleBackspaceKey: function()
- {
- var range = this._selection.range();
- if (range.isEmpty()) {
- if (range.startColumn > 0)
- range.startColumn--;
- else if (range.startLine > 0) {
- range.startLine--;
- range.startColumn = this._textModel.lineLength(range.startLine);
- } else
- return;
- } else
- this._textModel.markUndoableState();
- this._replaceSelectionWith("", range);
- },
-
- _handleToggleDebugMode: function()
- {
- this._debugMode = !this._debugMode;
- },
-
- _handleToggleHighlightMode: function()
- {
- this._highlightingEnabled = !this._highlightingEnabled;
- },
-
- _isMetaCtrl: function(e)
- {
- return this._isMac ? e.metaKey : e.ctrlKey;
- },
-
- _isAltCtrl: function(e)
- {
- return this._isMac ? e.altKey : e.ctrlKey;
- },
-
- _decimalDigits: function(number)
- {
- return Math.ceil(Math.log(number + 1) / Math.log(10));
- }
-}
-
-WebInspector.TextSelectionModel = function(changeListener)
-{
- this.startLine = 0;
- this.startColumn = 0;
- this.endLine = 0;
- this.endColumn = 0;
- this._changeListener = changeListener;
-}
-
-WebInspector.TextSelectionModel.prototype = {
- setStart: function(line, column)
- {
- var oldRange = this.range();
-
- this.startLine = line;
- this.startColumn = column;
- this.endLine = line;
- this.endColumn = column;
-
- this._changeListener(oldRange, this.range());
- },
-
- setEnd: function(line, column)
- {
- var oldRange = this.range();
-
- this.endLine = line;
- this.endColumn = column;
-
- this._changeListener(oldRange, this.range(), this.endLine, this.endColumn);
- },
-
- range: function()
- {
- if (this.startLine < this.endLine || (this.startLine === this.endLine && this.startColumn <= this.endColumn))
- return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn);
- else
- return new WebInspector.TextRange(this.endLine, this.endColumn, this.startLine, this.startColumn);
- },
-
- isEmpty: function()
- {
- return this.startLine === this.endLine && this.startColumn === this.endColumn;
- }
-}
-
-WebInspector.TextCursor = function(cursorElement)
-{
- this._visible = false;
- this._cursorElement = cursorElement;
-}
-
-WebInspector.TextCursor.prototype = {
- setLocation: function(x, y)
- {
- this._x = x;
- this._y = y;
- if (this._paintInterval) {
- window.clearInterval(this._paintInterval);
- delete this._paintInterval;
- }
- this._paintInterval = window.setInterval(this._paint.bind(this, false), 500);
- this._paint(true);
- },
-
- hide: function()
- {
- if (this._paintInterval) {
- window.clearInterval(this._paintInterval);
- delete this._paintInterval;
- }
- this._cursorElement.style.display = "none";
- },
-
- setTextLineHeight: function(textLineHeight)
- {
- this._cursorElement.style.height = textLineHeight + "px";
- },
-
- _paint: function(force)
- {
- if (force)
- this._visible = true;
- else
- this._visible = !this._visible;
- this._cursorElement.style.left = this._x + "px";
- this._cursorElement.style.top = this._y + "px";
- this._cursorElement.style.display = this._visible ? "block" : "none";
- }
-}
diff --git a/WebCore/inspector/front-end/TextEditorModel.js b/WebCore/inspector/front-end/TextEditorModel.js
index fc56026..e56c269 100644
--- a/WebCore/inspector/front-end/TextEditorModel.js
+++ b/WebCore/inspector/front-end/TextEditorModel.js
@@ -97,6 +97,11 @@ WebInspector.TextEditorModel.prototype = {
return newRange;
},
+ set replaceTabsWithSpaces(replaceTabsWithSpaces)
+ {
+ this._replaceTabsWithSpaces = replaceTabsWithSpaces;
+ },
+
_innerSetText: function(range, text)
{
this._eraseRange(range);
@@ -104,6 +109,8 @@ WebInspector.TextEditorModel.prototype = {
return new WebInspector.TextRange(range.startLine, range.startColumn, range.startLine, range.startColumn);
var newLines = text.split("\n");
+ this._replaceTabsIfNeeded(newLines);
+
var prefix = this._lines[range.startLine].substring(0, range.startColumn);
var prefixArguments = this._arguments
var suffix = this._lines[range.startLine].substring(range.startColumn);
@@ -124,6 +131,22 @@ WebInspector.TextEditorModel.prototype = {
range.startLine + newLines.length - 1, postCaret);
},
+ _replaceTabsIfNeeded: function(lines)
+ {
+ if (!this._replaceTabsWithSpaces)
+ return;
+ var spaces = [ " ", " ", " ", " "];
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i];
+ var index = line.indexOf("\t");
+ while (index !== -1) {
+ line = line.substring(0, index) + spaces[index % 4] + line.substring(index + 1);
+ index = line.indexOf("\t", index + 1);
+ }
+ lines[i] = line;
+ }
+ },
+
_eraseRange: function(range)
{
if (range.isEmpty())
diff --git a/WebCore/inspector/front-end/TextViewer.js b/WebCore/inspector/front-end/TextViewer.js
new file mode 100644
index 0000000..096464f
--- /dev/null
+++ b/WebCore/inspector/front-end/TextViewer.js
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+WebInspector.TextViewer = function(textModel, platform, url)
+{
+ this._textModel = textModel;
+ this._textModel.changeListener = this._buildChunks.bind(this);
+ this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightDataReady.bind(this));
+
+ this.element = document.createElement("div");
+ this.element.className = "text-editor monospace";
+ this.element.tabIndex = 0;
+
+ this.element.addEventListener("scroll", this._scroll.bind(this), false);
+
+ this._url = url;
+
+ this._linesContainerElement = document.createElement("table");
+ this._linesContainerElement.className = "text-editor-lines";
+ this._linesContainerElement.setAttribute("cellspacing", 0);
+ this._linesContainerElement.setAttribute("cellpadding", 0);
+ this.element.appendChild(this._linesContainerElement);
+
+ this._defaultChunkSize = 50;
+ this._paintCoalescingLevel = 0;
+}
+
+WebInspector.TextViewer.prototype = {
+ set mimeType(mimeType)
+ {
+ this._highlighter.mimeType = mimeType;
+ },
+
+ get textModel()
+ {
+ return this._textModel;
+ },
+
+ revealLine: function(lineNumber)
+ {
+ if (lineNumber >= this._textModel.linesCount)
+ return;
+
+ var chunk = this._makeLineAChunk(lineNumber);
+ chunk.element.scrollIntoViewIfNeeded();
+ },
+
+ addDecoration: function(lineNumber, decoration)
+ {
+ var chunk = this._makeLineAChunk(lineNumber);
+ chunk.addDecoration(decoration);
+ },
+
+ removeDecoration: function(lineNumber, decoration)
+ {
+ var chunk = this._makeLineAChunk(lineNumber);
+ chunk.removeDecoration(decoration);
+ },
+
+ markAndRevealRange: function(range)
+ {
+ if (this._rangeToMark) {
+ var markedLine = this._rangeToMark.startLine;
+ this._rangeToMark = null;
+ this._paintLines(markedLine, markedLine + 1);
+ }
+
+ if (range) {
+ this._rangeToMark = range;
+ this.revealLine(range.startLine);
+ this._paintLines(range.startLine, range.startLine + 1);
+ }
+ },
+
+ highlightLine: function(lineNumber)
+ {
+ if (typeof this._highlightedLine === "number") {
+ var chunk = this._makeLineAChunk(this._highlightedLine);
+ chunk.removeDecoration("webkit-highlighted-line");
+ }
+ this._highlightedLine = lineNumber;
+ this.revealLine(lineNumber);
+ var chunk = this._makeLineAChunk(lineNumber);
+ chunk.addDecoration("webkit-highlighted-line");
+ },
+
+ _buildChunks: function()
+ {
+ this._linesContainerElement.removeChildren();
+
+ var paintLinesCallback = this._paintLines.bind(this);
+ this._textChunks = [];
+ for (var i = 0; i < this._textModel.linesCount; i += this._defaultChunkSize) {
+ var chunk = new WebInspector.TextChunk(this._textModel, i, i + this._defaultChunkSize, paintLinesCallback);
+ this._textChunks.push(chunk);
+ this._linesContainerElement.appendChild(chunk.element);
+ }
+ this._indexChunks();
+ this._repaintAll();
+ },
+
+ _makeLineAChunk: function(lineNumber)
+ {
+ if (!this._textChunks)
+ this._buildChunks();
+
+ var chunkNumber = this._chunkNumberForLine(lineNumber);
+ var oldChunk = this._textChunks[chunkNumber];
+ if (oldChunk.linesCount === 1)
+ return oldChunk;
+
+ var wasExpanded = oldChunk.expanded;
+ oldChunk.expanded = false;
+
+ var insertIndex = oldChunk.chunkNumber + 1;
+ var paintLinesCallback = this._paintLines.bind(this);
+
+ // Prefix chunk.
+ if (lineNumber > oldChunk.startLine) {
+ var prefixChunk = new WebInspector.TextChunk(this._textModel, oldChunk.startLine, lineNumber, paintLinesCallback);
+ this._textChunks.splice(insertIndex++, 0, prefixChunk);
+ this._linesContainerElement.insertBefore(prefixChunk.element, oldChunk.element);
+ }
+
+ // Line chunk.
+ var lineChunk = new WebInspector.TextChunk(this._textModel, lineNumber, lineNumber + 1, paintLinesCallback);
+ this._textChunks.splice(insertIndex++, 0, lineChunk);
+ this._linesContainerElement.insertBefore(lineChunk.element, oldChunk.element);
+
+ // Suffix chunk.
+ if (oldChunk.startLine + oldChunk.linesCount > lineNumber + 1) {
+ var suffixChunk = new WebInspector.TextChunk(this._textModel, lineNumber + 1, oldChunk.startLine + oldChunk.linesCount, paintLinesCallback);
+ this._textChunks.splice(insertIndex, 0, suffixChunk);
+ this._linesContainerElement.insertBefore(suffixChunk.element, oldChunk.element);
+ }
+
+ // Remove enclosing chunk.
+ this._textChunks.splice(oldChunk.chunkNumber, 1);
+ this._linesContainerElement.removeChild(oldChunk.element);
+ this._indexChunks();
+
+ if (wasExpanded) {
+ if (prefixChunk)
+ prefixChunk.expanded = true;
+ lineChunk.expanded = true;
+ if (suffixChunk)
+ suffixChunk.expanded = true;
+ }
+
+ return lineChunk;
+ },
+
+ _indexChunks: function()
+ {
+ for (var i = 0; i < this._textChunks.length; ++i)
+ this._textChunks[i].chunkNumber = i;
+ },
+
+ _scroll: function()
+ {
+ this._repaintAll();
+ },
+
+ beginUpdates: function(enabled)
+ {
+ this._paintCoalescingLevel++;
+ },
+
+ endUpdates: function(enabled)
+ {
+ this._paintCoalescingLevel--;
+ if (!this._paintCoalescingLevel)
+ this._repaintAll();
+ },
+
+ _chunkForOffset: function(offset)
+ {
+ var currentOffset = 0;
+ var row = this._linesContainerElement.firstChild;
+ while (row) {
+ var rowHeight = row.offsetHeight;
+ if (offset >= currentOffset && offset < currentOffset + rowHeight)
+ return row.chunkNumber;
+ row = row.nextSibling;
+ currentOffset += rowHeight;
+ }
+ return this._textChunks.length - 1;
+ },
+
+ _chunkNumberForLine: function(lineNumber)
+ {
+ for (var i = 0; i < this._textChunks.length; ++i) {
+ var line = this._textChunks[i].startLine;
+ if (lineNumber >= this._textChunks[i].startLine && lineNumber < this._textChunks[i].startLine + this._textChunks[i].linesCount)
+ return i;
+ }
+ return this._textChunks.length - 1;
+ },
+
+ _chunkForLine: function(lineNumber)
+ {
+ return this._textChunks[this._chunkNumberForLine(lineNumber)];
+ },
+
+ _chunkStartLine: function(chunkNumber)
+ {
+ var lineNumber = 0;
+ for (var i = 0; i < chunkNumber && i < this._textChunks.length; ++i)
+ lineNumber += this._textChunks[i].linesCount;
+ return lineNumber;
+ },
+
+ _repaintAll: function()
+ {
+ if (this._paintCoalescingLevel)
+ return;
+
+ if (!this._textChunks)
+ this._buildChunks();
+
+ var visibleFrom = this.element.scrollTop;
+ var visibleTo = this.element.scrollTop + this.element.clientHeight;
+
+ var offset = 0;
+ var firstVisibleLine = -1;
+ var lastVisibleLine = 0;
+ var toExpand = [];
+ var toCollapse = [];
+ for (var i = 0; i < this._textChunks.length; ++i) {
+ var chunk = this._textChunks[i];
+ var chunkHeight = chunk.height;
+ if (offset + chunkHeight > visibleFrom && offset < visibleTo) {
+ toExpand.push(chunk);
+ if (firstVisibleLine === -1)
+ firstVisibleLine = chunk.startLine;
+ lastVisibleLine = chunk.startLine + chunk.linesCount;
+ } else {
+ toCollapse.push(chunk);
+ if (offset >= visibleTo)
+ break;
+ }
+ offset += chunkHeight;
+ }
+
+ for (var j = i; j < this._textChunks.length; ++j)
+ toCollapse.push(this._textChunks[i]);
+
+ var selection = this._getSelection();
+
+ this._muteHighlightListener = true;
+ this._highlighter.highlight(lastVisibleLine);
+ delete this._muteHighlightListener;
+
+ for (var i = 0; i < toCollapse.length; ++i)
+ toCollapse[i].expanded = false;
+ for (var i = 0; i < toExpand.length; ++i)
+ toExpand[i].expanded = true;
+
+ this._restoreSelection(selection);
+ },
+
+ _highlightDataReady: function(fromLine, toLine)
+ {
+ if (this._muteHighlightListener)
+ return;
+
+ var selection;
+ for (var i = fromLine; i < toLine; ++i) {
+ var lineRow = this._textModel.getAttribute(i, "line-row");
+ if (!lineRow || lineRow.highlighted)
+ continue;
+ if (!selection)
+ selection = this._getSelection();
+ this._paintLine(lineRow, i);
+ }
+ this._restoreSelection(selection);
+ },
+
+ _paintLines: function(fromLine, toLine)
+ {
+ for (var i = fromLine; i < toLine; ++i) {
+ var lineRow = this._textModel.getAttribute(i, "line-row");
+ if (lineRow)
+ this._paintLine(lineRow, i);
+ }
+ },
+
+ _paintLine: function(lineRow, lineNumber)
+ {
+ var element = lineRow.lastChild;
+ var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
+ var line = this._textModel.line(lineNumber);
+
+ if (!highlighterState) {
+ if (this._rangeToMark && this._rangeToMark.startLine === lineNumber)
+ this._markRange(element, line, this._rangeToMark.startColumn, this._rangeToMark.endColumn);
+ return;
+ }
+
+ element.removeChildren();
+
+ var plainTextStart = -1;
+ for (var j = 0; j < line.length;) {
+ if (j > 1000) {
+ // This line is too long - do not waste cycles on minified js highlighting.
+ break;
+ }
+ var attribute = highlighterState && highlighterState.attributes[j];
+ if (!attribute || !attribute.style) {
+ if (plainTextStart === -1)
+ plainTextStart = j;
+ j++;
+ } else {
+ if (plainTextStart !== -1) {
+ element.appendChild(document.createTextNode(line.substring(plainTextStart, j)));
+ plainTextStart = -1;
+ }
+ element.appendChild(this._createSpan(line.substring(j, j + attribute.length), attribute.tokenType));
+ j += attribute.length;
+ }
+ }
+ if (plainTextStart !== -1)
+ element.appendChild(document.createTextNode(line.substring(plainTextStart, line.length)));
+ if (this._rangeToMark && this._rangeToMark.startLine === lineNumber)
+ this._markRange(element, line, this._rangeToMark.startColumn, this._rangeToMark.endColumn);
+ if (lineRow.decorationsElement)
+ element.appendChild(lineRow.decorationsElement);
+ },
+
+ _getSelection: function()
+ {
+ var selection = window.getSelection();
+ if (selection.isCollapsed)
+ return null;
+ var selectionRange = selection.getRangeAt(0);
+ var start = this._selectionToPosition(selectionRange.startContainer, selectionRange.startOffset);
+ var end = this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset);
+ return new WebInspector.TextRange(start.line, start.column, end.line, end.column);
+ },
+
+ _restoreSelection: function(range)
+ {
+ if (!range)
+ return;
+ var startRow = this._textModel.getAttribute(range.startLine, "line-row");
+ if (startRow)
+ var start = startRow.lastChild.rangeBoundaryForOffset(range.startColumn);
+ else {
+ var offset = range.startColumn;
+ var chunkNumber = this._chunkNumberForLine(range.startLine);
+ for (var i = this._chunkStartLine(chunkNumber); i < range.startLine; ++i)
+ offset += this._textModel.line(i).length + 1; // \n
+ var lineCell = this._textChunks[chunkNumber].element.lastChild;
+ if (lineCell.firstChild)
+ var start = { container: lineCell.firstChild, offset: offset };
+ else
+ var start = { container: lineCell, offset: 0 };
+ }
+
+ var endRow = this._textModel.getAttribute(range.endLine, "line-row");
+ if (endRow)
+ var end = endRow.lastChild.rangeBoundaryForOffset(range.endColumn);
+ else {
+ var offset = range.endColumn;
+ var chunkNumber = this._chunkNumberForLine(range.endLine);
+ for (var i = this._chunkStartLine(chunkNumber); i < range.endLine; ++i)
+ offset += this._textModel.line(i).length + 1; // \n
+ var lineCell = this._textChunks[chunkNumber].element.lastChild;
+ if (lineCell.firstChild)
+ var end = { container: lineCell.firstChild, offset: offset };
+ else
+ var end = { container: lineCell, offset: 0 };
+ }
+
+ var selectionRange = document.createRange();
+ selectionRange.setStart(start.container, start.offset);
+ selectionRange.setEnd(end.container, end.offset);
+
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(selectionRange);
+ },
+
+ _selectionToPosition: function(container, offset)
+ {
+ if (container === this.element && offset === 0)
+ return { line: 0, column: 0 };
+ if (container === this.element && offset === 1)
+ return { line: this._textModel.linesCount - 1, column: this._textModel.lineLength(this._textModel.linesCount - 1) };
+
+ var lineRow = container.enclosingNodeOrSelfWithNodeName("tr");
+ var lineNumber = lineRow.lineNumber;
+ if (container.nodeName === "TD" && offset === 0)
+ return { line: lineNumber, column: 0 };
+ if (container.nodeName === "TD" && offset === 1)
+ return { line: lineNumber, column: this._textModel.lineLength(lineNumber) };
+
+ var column = 0;
+ if (lineRow.chunk) {
+ // This is chunk.
+ var text = lineRow.lastChild.textContent;
+ for (var i = 0; i < offset; ++i) {
+ if (text.charAt(i) === "\n") {
+ lineNumber++;
+ column = 0;
+ } else
+ column++;
+ }
+ return { line: lineNumber, column: column };
+ }
+
+ // This is individul line.
+ var column = 0;
+ var node = lineRow.lastChild.traverseNextTextNode(lineRow.lastChild);
+ while (node && node !== container) {
+ column += node.textContent.length;
+ node = node.traverseNextTextNode(lineRow.lastChild);
+ }
+ column += offset;
+ return { line: lineRow.lineNumber, column: column };
+ },
+
+ _createSpan: function(content, className)
+ {
+ if (className === "html-resource-link" || className === "html-external-link")
+ return this._createLink(content, className === "html-external-link");
+
+ var span = document.createElement("span");
+ span.className = "webkit-" + className;
+ span.appendChild(document.createTextNode(content));
+ return span;
+ },
+
+ _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 a = WebInspector.linkifyURLAsNode(this._rewriteHref(content), content, null, isExternal);
+ var span = document.createElement("span");
+ span.className = "webkit-html-attribute-value";
+ if (quote)
+ span.appendChild(document.createTextNode(quote));
+ span.appendChild(a);
+ if (quote)
+ span.appendChild(document.createTextNode(quote));
+ return span;
+ },
+
+ _rewriteHref: function(hrefValue, isExternal)
+ {
+ if (!this._url || !hrefValue || hrefValue.indexOf("://") > 0)
+ return hrefValue;
+ return WebInspector.completeURL(this._url, hrefValue);
+ },
+
+ _markRange: function(element, lineText, startOffset, endOffset)
+ {
+ var markNode = document.createElement("span");
+ markNode.className = "webkit-markup";
+ markNode.textContent = lineText.substring(startOffset, endOffset);
+
+ var markLength = endOffset - startOffset;
+ var boundary = element.rangeBoundaryForOffset(startOffset);
+ var textNode = boundary.container;
+ var text = textNode.textContent;
+
+ if (boundary.offset + markLength < text.length) {
+ // Selection belong to a single split mode.
+ textNode.textContent = text.substring(boundary.offset + markLength);
+ textNode.parentElement.insertBefore(markNode, textNode);
+ var prefixNode = document.createTextNode(text.substring(0, boundary.offset));
+ textNode.parentElement.insertBefore(prefixNode, markNode);
+ return;
+ }
+
+ var parentElement = textNode.parentElement;
+ var anchorElement = textNode.nextSibling;
+
+ markLength -= text.length - boundary.offset;
+ textNode.textContent = text.substring(0, boundary.offset);
+ textNode = textNode.traverseNextTextNode(element);
+
+ while (textNode) {
+ var text = textNode.textContent;
+ if (markLength < text.length) {
+ textNode.textContent = text.substring(markLength);
+ break;
+ }
+
+ markLength -= text.length;
+ textNode.textContent = "";
+ textNode = textNode.traverseNextTextNode(element);
+ }
+
+ parentElement.insertBefore(markNode, anchorElement);
+ },
+
+ resize: function()
+ {
+ this._repaintAll();
+ }
+}
+
+WebInspector.TextChunk = function(textModel, startLine, endLine, paintLinesCallback)
+{
+ this.element = document.createElement("tr");
+ this._textModel = textModel;
+ this.element.chunk = this;
+ this.element.lineNumber = startLine;
+
+ this.startLine = startLine;
+ endLine = Math.min(this._textModel.linesCount, endLine);
+ this.linesCount = endLine - startLine;
+
+ this._lineNumberElement = document.createElement("td");
+ this._lineNumberElement.className = "webkit-line-number";
+ this._lineNumberElement.textContent = this._lineNumberText(this.startLine);
+ this.element.appendChild(this._lineNumberElement);
+
+ this._lineContentElement = document.createElement("td");
+ this._lineContentElement.className = "webkit-line-content";
+ this.element.appendChild(this._lineContentElement);
+
+ this._expanded = false;
+
+ var lines = [];
+ for (var i = this.startLine; i < this.startLine + this.linesCount; ++i)
+ lines.push(this._textModel.line(i));
+ this._lineContentElement.textContent = lines.join("\n");
+ this._paintLines = paintLinesCallback;
+}
+
+WebInspector.TextChunk.prototype = {
+ addDecoration: function(decoration)
+ {
+ if (typeof decoration === "string") {
+ this.element.addStyleClass(decoration);
+ return;
+ }
+ if (!this.element.decorationsElement) {
+ this.element.decorationsElement = document.createElement("div");
+ this._lineContentElement.appendChild(this.element.decorationsElement);
+ }
+ this.element.decorationsElement.appendChild(decoration);
+ },
+
+ removeDecoration: function(decoration)
+ {
+ if (typeof decoration === "string") {
+ this.element.removeStyleClass(decoration);
+ return;
+ }
+ if (!this.element.decorationsElement)
+ return;
+ this.element.decorationsElement.removeChild(decoration);
+ },
+
+ get expanded()
+ {
+ return this._expanded;
+ },
+
+ set expanded(expanded)
+ {
+ if (this._expanded === expanded)
+ return;
+
+ this._expanded = expanded;
+
+ if (this.linesCount === 1) {
+ this._textModel.setAttribute(this.startLine, "line-row", this.element);
+ if (expanded)
+ this._paintLines(this.startLine, this.startLine + 1);
+ return;
+ }
+
+ if (expanded) {
+ var parentElement = this.element.parentElement;
+ for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+ var lineRow = document.createElement("tr");
+ lineRow.lineNumber = i;
+
+ var lineNumberElement = document.createElement("td");
+ lineNumberElement.className = "webkit-line-number";
+ lineNumberElement.textContent = this._lineNumberText(i);
+ lineRow.appendChild(lineNumberElement);
+
+ var lineContentElement = document.createElement("td");
+ lineContentElement.className = "webkit-line-content";
+ lineContentElement.textContent = this._textModel.line(i);
+ lineRow.appendChild(lineContentElement);
+
+ this._textModel.setAttribute(i, "line-row", lineRow);
+ parentElement.insertBefore(lineRow, this.element);
+ }
+ parentElement.removeChild(this.element);
+
+ this._paintLines(this.startLine, this.startLine + this.linesCount);
+ } else {
+ var firstLine = this._textModel.getAttribute(this.startLine, "line-row");
+ var parentElement = firstLine.parentElement;
+
+ parentElement.insertBefore(this.element, firstLine);
+ for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+ var lineRow = this._textModel.getAttribute(i, "line-row");
+ this._textModel.removeAttribute(i, "line-row");
+ parentElement.removeChild(lineRow);
+ }
+ }
+ },
+
+ get height()
+ {
+ if (!this._expanded)
+ return this.element.offsetHeight;
+ var result = 0;
+ for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+ var lineRow = this._textModel.getAttribute(i, "line-row");
+ result += lineRow.offsetHeight;
+ }
+ return result;
+ },
+
+ _lineNumberText: function(lineNumber)
+ {
+ var totalDigits = Math.ceil(Math.log(this._textModel.linesCount + 1) / Math.log(10));
+ var digits = Math.ceil(Math.log(lineNumber + 2) / Math.log(10));
+
+ var text = "";
+ for (var i = digits; i < totalDigits; ++i)
+ text += " ";
+ text += lineNumber + 1;
+ return text;
+ }
+}
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 20e9aa2..efa2bfc 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -2,8 +2,10 @@
<qresource prefix="/webkit/inspector">
<file>inspector.html</file>
<file>AbstractTimelinePanel.js</file>
+ <file>AuditCategories.js</file>
<file>AuditLauncherView.js</file>
<file>AuditResultView.js</file>
+ <file>AuditRules.js</file>
<file>AuditsPanel.js</file>
<file>BottomUpProfileDataGridTree.js</file>
<file>Breakpoint.js</file>
@@ -37,7 +39,6 @@
<file>InspectorFrontendHostStub.js</file>
<file>KeyboardShortcut.js</file>
<file>MetricsSidebarPane.js</file>
- <file>NativeTextViewer.js</file>
<file>Object.js</file>
<file>ObjectPropertiesSection.js</file>
<file>ObjectProxy.js</file>
@@ -73,10 +74,10 @@
<file>StylesSidebarPane.js</file>
<file>SummaryBar.js</file>
<file>TestController.js</file>
- <file>TextEditor.js</file>
<file>TextEditorHighlighter.js</file>
<file>TextEditorModel.js</file>
<file>TextPrompt.js</file>
+ <file>TextViewer.js</file>
<file>TimelineAgent.js</file>
<file>TimelineGrid.js</file>
<file>TimelineOverviewPane.js</file>
@@ -90,7 +91,7 @@
<file>audits.css</file>
<file>inspector.css</file>
<file>inspectorSyntaxHighlight.css</file>
- <file>textEditor.css</file>
+ <file>textViewer.css</file>
<file>Images/back.png</file>
<file>Images/checker.png</file>
<file>Images/clearConsoleButtonGlyph.png</file>
diff --git a/WebCore/inspector/front-end/audits.css b/WebCore/inspector/front-end/audits.css
index 35db76b..9d02c80 100644
--- a/WebCore/inspector/front-end/audits.css
+++ b/WebCore/inspector/front-end/audits.css
@@ -262,11 +262,11 @@ body.inactive .audit-launcher-view button, .audit-launcher-view button:disabled
margin: 0 5px 5px 0;
}
-.audit-launcher-view input[type="radio"]:active {
+.audit-launcher-view input[type="radio"]:active:not(:disabled) {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(194, 194, 194)), to(rgb(239, 239, 239)));
}
-.audit-launcher-view input[type="radio"]:checked {
+.audit-launcher-view input[type="radio"]:checked:not(:disabled), .audit-launcher-view input[type="radio"]:checked:disabled {
background: url(Images/radioDot.png) center no-repeat,
-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)));
}
diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
index 45b8ec3..53f1e4b 100644
--- a/WebCore/inspector/front-end/inspector.css
+++ b/WebCore/inspector/front-end/inspector.css
@@ -3772,7 +3772,7 @@ ol.breakpoint-list {
white-space: pre;
}
-.source-breakpoint-condition {
+.source-frame-breakpoint-condition {
z-index: 30;
padding: 4px;
background-color: rgb(203, 226, 255);
@@ -3781,7 +3781,7 @@ ol.breakpoint-list {
width: 90%;
}
-.source-breakpoint-message {
+.source-frame-breakpoint-message {
background-color: transparent;
font-family: Lucida Grande, sans-serif;
font-weight: normal;
@@ -3793,7 +3793,7 @@ ol.breakpoint-list {
margin: 0 0 2px 0;
}
-#source-breakpoint-condition {
+#source-frame-breakpoint-condition {
margin: 0;
border: 1px inset rgb(190, 190, 190) !important;
width: 100%;
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index 26264dc..4ddd10e 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -30,7 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="audits.css">
- <link rel="stylesheet" type="text/css" href="textEditor.css">
+ <link rel="stylesheet" type="text/css" href="textViewer.css">
<link rel="stylesheet" type="text/css" href="inspector.css">
<link rel="stylesheet" type="text/css" href="inspectorSyntaxHighlight.css">
<script type="text/javascript" src="utilities.js"></script>
@@ -91,13 +91,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<script type="text/javascript" src="AuditsPanel.js"></script>
<script type="text/javascript" src="AuditResultView.js"></script>
<script type="text/javascript" src="AuditLauncherView.js"></script>
+ <script type="text/javascript" src="AuditRules.js"></script>
+ <script type="text/javascript" src="AuditCategories.js"></script>
<script type="text/javascript" src="ResourceView.js"></script>
<script type="text/javascript" src="SourceFrame.js"></script>
<script type="text/javascript" src="DOMSyntaxHighlighter.js"></script>
<script type="text/javascript" src="TextEditorModel.js"></script>
- <script type="text/javascript" src="TextEditor.js"></script>
<script type="text/javascript" src="TextEditorHighlighter.js"></script>
- <script type="text/javascript" src="NativeTextViewer.js"></script>
+ <script type="text/javascript" src="TextViewer.js"></script>
<script type="text/javascript" src="SourceTokenizer.js"></script>
<script type="text/javascript" src="SourceCSSTokenizer.js"></script>
<script type="text/javascript" src="SourceHTMLTokenizer.js"></script>
diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js
index de20739..77d3f42 100644
--- a/WebCore/inspector/front-end/inspector.js
+++ b/WebCore/inspector/front-end/inspector.js
@@ -468,17 +468,8 @@ WebInspector.loaded = function()
var previousToolbarItem = toolbarElement.children[0];
this.panelOrder = [];
- for (var panelName in this.panels) {
- var panel = this.panels[panelName];
- var panelToolbarItem = panel.toolbarItem;
- this.panelOrder.push(panel);
- panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this));
- if (previousToolbarItem)
- toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling);
- else
- toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild);
- previousToolbarItem = panelToolbarItem;
- }
+ for (var panelName in this.panels)
+ previousToolbarItem = WebInspector.addPanelToolbarIcon(toolbarElement, this.panels[panelName], previousToolbarItem);
this.Tips = {
ResourceNotCompressed: {id: 0, message: WebInspector.UIString("You could save bandwidth by having your web server compress this transfer with gzip or zlib.")}
@@ -529,6 +520,18 @@ WebInspector.loaded = function()
InspectorFrontendHost.loaded();
}
+WebInspector.addPanelToolbarIcon = function(toolbarElement, panel, previousToolbarItem)
+{
+ var panelToolbarItem = panel.toolbarItem;
+ this.panelOrder.push(panel);
+ panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this));
+ if (previousToolbarItem)
+ toolbarElement.insertBefore(panelToolbarItem, previousToolbarItem.nextSibling);
+ else
+ toolbarElement.insertBefore(panelToolbarItem, toolbarElement.firstChild);
+ return panelToolbarItem;
+}
+
var windowLoaded = function()
{
var localizedStringsURL = InspectorFrontendHost.localizedStringsURL();
@@ -749,8 +752,11 @@ WebInspector.documentKeyDown = function(event)
var shouldShowAuditsPanel = event.ctrlKey && !event.shiftKey && !event.metaKey && event.altKey;
if (shouldShowAuditsPanel) {
- if (!this.panels.audits)
+ if (!this.panels.audits) {
this.panels.audits = new WebInspector.AuditsPanel();
+ var toolbarElement = document.getElementById("toolbar");
+ WebInspector.addPanelToolbarIcon(toolbarElement, this.panels.audits, this.panels.console.toolbarItem);
+ }
this.currentPanel = this.panels.audits;
}
@@ -1050,7 +1056,7 @@ WebInspector.updateResource = function(identifier, payload)
if (match) {
var protocol = match[1].toLowerCase();
if (protocol.indexOf("http") === 0 || protocol === "file")
- this.addCookieDomain(protocol === "file" ? "" : match[2]);
+ this._addCookieDomain(protocol === "file" ? "" : match[2]);
}
}
@@ -1131,7 +1137,7 @@ WebInspector.addDatabase = function(payload)
this.panels.storage.addDatabase(database);
}
-WebInspector.addCookieDomain = function(domain)
+WebInspector._addCookieDomain = function(domain)
{
// Eliminate duplicate domains from the list.
if (domain in this.cookieDomains)
@@ -1208,7 +1214,6 @@ WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLin
WebInspector.pausedScript = function(callFrames)
{
- callFrames = JSON.parse(callFrames);
this.panels.scripts.debuggerPaused(callFrames);
}
@@ -1265,7 +1270,7 @@ WebInspector.updateConsoleMessageExpiredCount = function(count)
WebInspector.console.addMessage(new WebInspector.ConsoleTextMessage(message, WebInspector.ConsoleMessage.MessageLevel.Warning));
}
-WebInspector.addConsoleMessage = function(payload, argumentsStringified, opt_args)
+WebInspector.addConsoleMessage = function(payload, opt_args)
{
var consoleMessage = new WebInspector.ConsoleMessage(
payload.source,
@@ -1275,14 +1280,7 @@ WebInspector.addConsoleMessage = function(payload, argumentsStringified, opt_arg
payload.url,
payload.groupLevel,
payload.repeatCount);
- var parsedArguments = [];
- for (var i = 2; i < arguments.length; i++) {
- if (argumentsStringified)
- parsedArguments.push(JSON.parse(arguments[i]));
- else
- parsedArguments.push(arguments[i]);
- }
- consoleMessage.setMessageBody(parsedArguments);
+ consoleMessage.setMessageBody(Array.prototype.slice.call(arguments, 1));
this.console.addMessage(consoleMessage);
}
diff --git a/WebCore/inspector/front-end/textEditor.css b/WebCore/inspector/front-end/textEditor.css
deleted file mode 100644
index 93495f2..0000000
--- a/WebCore/inspector/front-end/textEditor.css
+++ /dev/null
@@ -1,90 +0,0 @@
-.text-editor {
- position: absolute;
- top:0;
- left:0;
- right:0;
- bottom:0;
- -webkit-user-select: text;
- -webkit-user-modify: read-write-plaintext-only;
-}
-
-.text-editor-readonly {
- -webkit-user-modify: read-only;
-}
-
-.text-editor-canvas {
- position: absolute;
- top:0;
- left:0;
- right:0;
- bottom:0;
- z-index: 10;
- pointer-events: none;
-}
-
-.text-editor-container {
- position: absolute;
- top:0;
- left:0;
- right:0;
- bottom:0;
- overflow: auto;
-}
-
-.text-editor-cursor {
- -webkit-user-select: none;
- -webkit-user-modify: none;
- position: absolute;
- top:0;
- left:0;
- width:1px;
- height: 14px;
- z-index: 20;
- background-color: black;
- pointer-events: none;
-}
-
-.native-text-editor-line {
- white-space: pre;
-}
-
-.webkit-html-message-bubble {
- -webkit-box-shadow: black 0px 2px 5px;
- -webkit-border-radius: 9px;
- -webkit-border-fit: lines;
- font-size: 10px;
- font-family: Lucida Grande, sans-serif;
- font-weight: bold;
- margin: 6px 25px;
- padding: 0 7px 1px;
- z-index:20;
-}
-
-.webkit-html-warning-message {
- background-color: rgb(100%, 62%, 42%);
- border: 2px solid rgb(100%, 52%, 21%);
-}
-
-.webkit-html-error-message {
- background-color: rgb(100%, 42%, 42%);
- border: 2px solid rgb(100%, 31%, 31%);
-}
-
-.webkit-html-message-line {
- padding-left: 23px;
- text-indent: -20px;
-}
-
-.webkit-html-message-line-hover {
- padding-left: 23px;
- text-indent: -20px;
- white-space: auto;
- text-overflow: auto;
- overflow: auto;
-}
-
-.webkit-html-message-icon {
- position: relative;
- top: 2px;
- margin: 0 4px;
-}
diff --git a/WebCore/inspector/front-end/textViewer.css b/WebCore/inspector/front-end/textViewer.css
new file mode 100644
index 0000000..af079bc
--- /dev/null
+++ b/WebCore/inspector/front-end/textViewer.css
@@ -0,0 +1,149 @@
+.text-editor {
+ position: absolute;
+ top:0;
+ left:0;
+ right:0;
+ bottom:0;
+ white-space: pre-wrap;
+ overflow: auto;
+}
+
+.text-editor-lines {
+ border: 0;
+ width: 100%;
+ vertical-align: baseline;
+ -webkit-border-horizontal-spacing: 0;
+ -webkit-border-vertical-spacing: 0;
+ -webkit-user-select: text;
+}
+
+.webkit-html-message-bubble {
+ -webkit-box-shadow: black 0px 2px 5px;
+ -webkit-border-radius: 9px;
+ -webkit-border-fit: lines;
+ font-size: 10px;
+ font-family: Lucida Grande, sans-serif;
+ font-weight: bold;
+ margin: 6px 25px;
+ padding: 0 7px 1px;
+ z-index:20;
+ max-width: 80%;
+
+}
+
+.webkit-html-warning-message {
+ background-color: rgb(100%, 62%, 42%);
+ border: 2px solid rgb(100%, 52%, 21%);
+}
+
+.webkit-html-error-message {
+ background-color: rgb(100%, 42%, 42%);
+ border: 2px solid rgb(100%, 31%, 31%);
+}
+
+.webkit-html-message-line {
+ padding-left: 23px;
+ text-indent: -20px;
+}
+
+.webkit-html-message-line-hover {
+ padding-left: 23px;
+ text-indent: -20px;
+ white-space: auto;
+ text-overflow: auto;
+ overflow: auto;
+}
+
+.webkit-html-message-icon {
+ position: relative;
+ top: 2px;
+ margin: 0 4px;
+}
+
+.webkit-line-number {
+ color: rgb(128, 128, 128);
+ text-align: right;
+ white-space: pre;
+ word-break: normal;
+ -webkit-user-select: none;
+ background-color: rgb(240, 240, 240);
+ border-right: 1px solid rgb(187, 187, 187) !important;
+ padding-left: 2px;
+ padding-right: 2px;
+ vertical-align: top;
+ background-repeat: no-repeat;
+ background-position: right 1px;
+}
+
+.webkit-line-content {
+ white-space: pre-wrap;
+ padding-left: 2px;
+}
+
+.webkit-execution-line .webkit-line-number {
+ color: transparent;
+ background-image: -webkit-canvas(program-counter);
+}
+
+.webkit-breakpoint .webkit-line-number {
+ color: white;
+ background-image: -webkit-canvas(breakpoint);
+}
+
+.webkit-breakpoint-disabled .webkit-line-number {
+ color: white;
+ background-image: -webkit-canvas(breakpoint-disabled);
+}
+
+.webkit-breakpoint.webkit-execution-line .webkit-line-number {
+ color: transparent;
+ background-image: -webkit-canvas(breakpoint-program-counter);
+}
+
+.webkit-breakpoint-disabled.webkit-execution-line .webkit-line-number {
+ color: transparent;
+ background-image: -webkit-canvas(breakpoint-disabled-program-counter);
+}
+
+.webkit-breakpoint.webkit-breakpoint-conditional .webkit-line-number {
+ color: white;
+ background-image: -webkit-canvas(breakpoint-conditional);
+}
+
+.webkit-breakpoint-disabled.webkit-breakpoint-conditional .webkit-line-number {
+ color: white;
+ background-image: -webkit-canvas(breakpoint-disabled-conditional);
+}
+
+.webkit-breakpoint.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number {
+ color: transparent;
+ background-image: -webkit-canvas(breakpoint-conditional-program-counter);
+}
+
+.webkit-breakpoint-disabled.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number {
+ color: transparent;
+ background-image: -webkit-canvas(breakpoint-disabled-conditional-program-counter);
+}
+
+.webkit-execution-line .webkit-line-content {
+ background-color: rgb(171, 191, 254);
+ outline: 1px solid rgb(64, 115, 244);
+}
+
+.webkit-markup {
+ -webkit-border-radius: 4px;
+ padding: 2px 1px 2px 3px;
+ margin-left: -4px;
+ margin-top: -2px;
+ -webkit-box-shadow: rgba(0, 0, 0, .5) 3px 3px 4px;
+ background-color: rgb(241, 234, 0);
+}
+
+.webkit-highlighted-line .webkit-line-content {
+ -webkit-animation: "fadeout" 2s 0s;
+}
+
+@-webkit-keyframes fadeout {
+ from {background-color: rgb(255, 255, 120); }
+ to { background-color: white; }
+}
diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js
index d54005a..60d3b45 100644
--- a/WebCore/inspector/front-end/utilities.js
+++ b/WebCore/inspector/front-end/utilities.js
@@ -145,6 +145,30 @@ Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, di
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)
{
// Test for the simple case first.