diff options
Diffstat (limited to 'WebCore/inspector/front-end')
40 files changed, 2753 insertions, 1413 deletions
diff --git a/WebCore/inspector/front-end/AuditRules.js b/WebCore/inspector/front-end/AuditRules.js index a72de56..cd9f13e 100644 --- a/WebCore/inspector/front-end/AuditRules.js +++ b/WebCore/inspector/front-end/AuditRules.js @@ -42,17 +42,17 @@ WebInspector.AuditRules.CacheableResponseCodes = 304: true // Underlying resource is cacheable } -WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, regexp, needFullResources) +WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, 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) + var parsedURL = resource.url.asParsedURL(); + if (!parsedURL) continue; - var domain = match[2]; + var domain = parsedURL.host; var domainResources = domainToResourcesMap[domain]; if (domainResources === undefined) { domainResources = []; @@ -128,7 +128,7 @@ WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, WebInspector.AuditRules.CombineExternalResourcesRule.prototype = { doRun: function(resources, result, callback) { - var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [this._type], WebInspector.URLRegExp); + var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [this._type]); var penalizedResourceCount = 0; // TODO: refactor according to the chosen i18n approach var summary = result.addChild("", true); @@ -175,14 +175,14 @@ WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype = { doRun: function(resources, result, callback) { var summary = result.addChild(""); - var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, undefined, WebInspector.URLRegExp); + var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, undefined); for (var domain in domainToResourcesMap) { if (domainToResourcesMap[domain].length > 1) continue; - var match = domain.match(WebInspector.URLRegExp); - if (!match) + var parsedURL = domain.asParsedURL(); + if (!parsedURL) continue; - if (!match[2].search(WebInspector.AuditRules.IPAddressRegexp)) + if (!parsedURL.host.search(WebInspector.AuditRules.IPAddressRegexp)) continue; // an IP address summary.addSnippet(match[2]); result.violationCount++; @@ -220,7 +220,6 @@ WebInspector.AuditRules.ParallelizeDownloadRule.prototype = { var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap( resources, [WebInspector.Resource.Type.Stylesheet, WebInspector.Resource.Type.Image], - WebInspector.URLRegExp, true); var hosts = []; @@ -647,7 +646,7 @@ WebInspector.AuditRules.ImageDimensionsRule.prototype = { const node = WebInspector.domAgent.nodeForId(imageId); var src = node.getAttribute("src"); - if (!WebInspector.URLRegExp.test(src)) { + if (!src.asParsedURL()) { for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) { if (frameOwnerCandidate.documentURL) { var completeSrc = WebInspector.completeURL(frameOwnerCandidate.documentURL, src); @@ -934,7 +933,6 @@ WebInspector.AuditRules.CookieSizeRule.prototype = { var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, null, - WebInspector.URLRegExp, true); var matchingResourceData = {}; this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback.bind(this)); @@ -998,7 +996,6 @@ WebInspector.AuditRules.StaticCookielessRule.prototype = { var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(resources, [WebInspector.Resource.Type.Stylesheet, WebInspector.Resource.Type.Image], - WebInspector.URLRegExp, true); var totalStaticResources = 0; for (var domain in domainToResourcesMap) diff --git a/WebCore/inspector/front-end/BreakpointManager.js b/WebCore/inspector/front-end/BreakpointManager.js index ec4e7cf..77ba89d 100644 --- a/WebCore/inspector/front-end/BreakpointManager.js +++ b/WebCore/inspector/front-end/BreakpointManager.js @@ -27,7 +27,8 @@ WebInspector.BreakpointManager = function() { this._breakpoints = {}; - this._xhrBreakpoints = {}; + this._nativeBreakpoints = {}; + this._domBreakpoints = {}; } WebInspector.BreakpointManager.prototype = { @@ -87,6 +88,7 @@ WebInspector.BreakpointManager.prototype = { { this._breakpoints = {}; delete this._oneTimeBreakpoint; + this._nativeBreakpoints = {}; }, _setBreakpoint: function(sourceID, url, line, enabled, condition) @@ -127,20 +129,144 @@ WebInspector.BreakpointManager.prototype = { InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition, didSetBreakpoint.bind(this)); }, - createXHRBreakpoint: function(url) + createDOMBreakpoint: function(nodeId, domEventType, disabled) { - if (url in this._xhrBreakpoints) + var frontendId = "dom:" + nodeId + ":" + domEventType; + if (frontendId in this._nativeBreakpoints) return; - this._xhrBreakpoints[url] = true; - var breakpoint = new WebInspector.XHRBreakpoint(url); - breakpoint.addEventListener("removed", this._xhrBreakpointRemoved.bind(this)); + var breakpoint = new WebInspector.DOMBreakpoint(this, frontendId, nodeId, domEventType); + this._nativeBreakpoints[frontendId] = breakpoint; + this._domBreakpoints[frontendId] = breakpoint; + this.dispatchEventToListeners("dom-breakpoint-added", breakpoint); + breakpoint.enabled = !disabled; + return breakpoint; + }, + + createEventListenerBreakpoint: function(eventName, disabled) + { + var frontendId = eventName; + if (frontendId in this._nativeBreakpoints) + return; + + var breakpoint = new WebInspector.EventListenerBreakpoint(this, frontendId, eventName); + this._nativeBreakpoints[frontendId] = breakpoint; + breakpoint.enabled = !disabled; + return breakpoint; + }, + + createXHRBreakpoint: function(url, disabled) + { + var frontendId = url; + if (frontendId in this._nativeBreakpoints) + return; + + var breakpoint = new WebInspector.XHRBreakpoint(this, frontendId, url); + this._nativeBreakpoints[frontendId] = breakpoint; this.dispatchEventToListeners("xhr-breakpoint-added", breakpoint); + breakpoint.enabled = !disabled + return breakpoint; }, - _xhrBreakpointRemoved: function(event) + _removeNativeBreakpoint: function(breakpoint) { - delete this._xhrBreakpoints[event.target.url]; + if (breakpoint._beingSetOnBackend) + return; + if (breakpoint.enabled) + this._removeNativeBreakpointFromBackend(breakpoint); + delete this._nativeBreakpoints[breakpoint._frontendId]; + if (breakpoint._type === "DOM") + delete this._domBreakpoints[breakpoint._frontendId]; + breakpoint.dispatchEventToListeners("removed"); + }, + + _setNativeBreakpointEnabled: function(breakpoint, enabled) + { + if (breakpoint._beingSetOnBackend) + return; + if (breakpoint.enabled === enabled) + return; + if (enabled) + this._setNativeBreakpointOnBackend(breakpoint); + else + this._removeNativeBreakpointFromBackend(breakpoint); + }, + + _setNativeBreakpointOnBackend: function(breakpoint) + { + breakpoint._beingSetOnBackend = true; + var data = { type: breakpoint._type, condition: breakpoint._condition() }; + InspectorBackend.setNativeBreakpoint(data, didSetNativeBreakpoint.bind(this)); + + function didSetNativeBreakpoint(backendBreakpointId) + { + breakpoint._beingSetOnBackend = false; + if (backendBreakpointId !== "") { + breakpoint._backendId = backendBreakpointId; + this._breakpoints[backendBreakpointId] = breakpoint; + } + breakpoint.dispatchEventToListeners("enable-changed"); + } + }, + + _removeNativeBreakpointFromBackend: function(breakpoint) + { + InspectorBackend.removeNativeBreakpoint(breakpoint._backendId); + delete this._breakpoints[breakpoint._backendId] + delete breakpoint._backendId; + breakpoint.dispatchEventToListeners("enable-changed"); + }, + + debuggerPaused: function(details) + { + if (details.eventType !== WebInspector.DebuggerEventTypes.NativeBreakpoint) + return; + + var breakpoint = this._breakpoints[details.eventData.breakpointId]; + if (!breakpoint) + return; + + breakpoint.hit = true; + breakpoint.dispatchEventToListeners("hit-state-changed"); + this._lastHitBreakpoint = breakpoint; + + this.dispatchEventToListeners("breakpoint-hit", { breakpoint: breakpoint, eventData: details.eventData }); + }, + + debuggerResumed: function() + { + if (!this._lastHitBreakpoint) + return; + this._lastHitBreakpoint.hit = false; + this._lastHitBreakpoint.dispatchEventToListeners("hit-state-changed"); + delete this._lastHitBreakpoint; + }, + + restoreDOMBreakpoints: function() + { + var domBreakpoints = this._domBreakpoints; + this._domBreakpoints = {}; + + var breakpointsToRestore = {}; + for (var frontendId in domBreakpoints) { + var breakpoint = domBreakpoints[frontendId]; + var path = breakpoint._path; + if (!path) + continue; + if (!breakpointsToRestore[path]) { + breakpointsToRestore[path] = []; + InspectorBackend.pushNodeByPathToFrontend(path, restoreBreakpointsForNode.bind(this, breakpointsToRestore[path])); + } + breakpointsToRestore[path].push(breakpoint); + } + + function restoreBreakpointsForNode(breakpoints, nodeId) + { + if (!nodeId) + return; + for (var i = 0; i < breakpoints.length; ++i) + this.createDOMBreakpoint(nodeId, breakpoints[i]._domEventType, !breakpoints[i].enabled); + } } } @@ -226,82 +352,237 @@ WebInspector.Breakpoint.prototype = { WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; -WebInspector.XHRBreakpoint = function(url) +WebInspector.NativeBreakpoint = function(manager, frontendId, type) { - this._url = url; - this._locked = false; - this.enabled = true; + this._manager = manager; + this.__frontendId = frontendId; + this.__type = type; } -WebInspector.XHRBreakpoint.prototype = { +WebInspector.NativeBreakpoint.prototype = { get enabled() { - return "_id" in this; + return "_backendId" in this; }, set enabled(enabled) { - if (this._locked) - return; - if (this.enabled === enabled) - return; - if (enabled) - this._setOnBackend(); - else - this._removeFromBackend(); + this._manager._setNativeBreakpointEnabled(this, enabled); }, - get url() + remove: function() { - return this._url; + this._manager._removeNativeBreakpoint(this); + this._onRemove(); }, - formatLabel: function() + get _frontendId() { - var label = ""; - if (!this.url.length) - label = WebInspector.UIString("Any XHR"); - else - label = WebInspector.UIString("URL contains \"%s\"", this.url); - return label; + return this.__frontendId; }, - compareTo: function(other) + get _type() { - if (this.url != other.url) - return this.url < other.url ? -1 : 1; + return this.__type; + }, + + _compare: function(x, y) + { + if (x !== y) + return x < y ? -1 : 1; return 0; }, - remove: function() + _onRemove: function() { - if (this._locked) - return; - if (this.enabled) - this._removeFromBackend(); - this.dispatchEventToListeners("removed"); + } +} + +WebInspector.NativeBreakpoint.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.DOMBreakpoint = function(manager, frontendId, nodeId, domEventType) +{ + WebInspector.NativeBreakpoint.call(this, manager, frontendId, "DOM"); + this._nodeId = nodeId; + this._domEventType = domEventType; + + var node = WebInspector.domAgent.nodeForId(this._nodeId); + if (node) { + node.breakpoints[this._domEventType] = this; + this._path = node.path(); + } +} + +WebInspector.DOMBreakpoint.prototype = { + click: function() + { + WebInspector.updateFocusedNode(this._nodeId); }, - _setOnBackend: function() + compareTo: function(other) { - this._locked = true; - var data = { type: "XHR", condition: { url: this.url } }; - InspectorBackend.setNativeBreakpoint(data, didSet.bind(this)); + return this._compare(this._domEventType, other._domEventType); + }, - function didSet(breakpointId) + populateLabelElement: function(element) + { + element.appendChild(WebInspector.panels.elements.linkifyNodeById(this._nodeId)); + element.appendChild(document.createTextNode(" - ")); + element.appendChild(document.createTextNode(WebInspector.domBreakpointTypeLabel(this._domEventType))); + }, + + populateStatusMessageElement: function(element, eventData) + { + var substitutions = [WebInspector.domBreakpointTypeLabel(this._domEventType), WebInspector.panels.elements.linkifyNodeById(this._nodeId)]; + var formatters = { + s: function(substitution) + { + return substitution; + } + }; + function append(a, b) { - this._locked = false; - this._id = breakpointId; - this.dispatchEventToListeners("enable-changed"); + if (typeof b === "string") + b = document.createTextNode(b); + element.appendChild(b); } + if (this._domEventType === WebInspector.DOMBreakpointTypes.SubtreeModified) { + var targetNode = WebInspector.panels.elements.linkifyNodeById(eventData.targetNodeId); + if (eventData.insertion) { + if (eventData.targetNodeId !== this._nodeId) + WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", substitutions.concat(targetNode), formatters, "", append); + else + WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.", substitutions, formatters, "", append); + } else + WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", substitutions.concat(targetNode), formatters, "", append); + } else + WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s.", substitutions, formatters, "", append); }, - _removeFromBackend: function() + _condition: function() { - InspectorBackend.removeNativeBreakpoint(this._id); - delete this._id; - this.dispatchEventToListeners("enable-changed"); + return { nodeId: this._nodeId, type: this._domEventType }; + }, + + _onRemove: function() + { + var node = WebInspector.domAgent.nodeForId(this._nodeId); + if (node) + delete node.breakpoints[this._domEventType]; } } -WebInspector.XHRBreakpoint.prototype.__proto__ = WebInspector.Object.prototype; +WebInspector.DOMBreakpoint.prototype.__proto__ = WebInspector.NativeBreakpoint.prototype; + +WebInspector.EventListenerBreakpoint = function(manager, frontendId, eventName) +{ + WebInspector.NativeBreakpoint.call(this, manager, frontendId, "EventListener"); + this._eventName = eventName; +} + +WebInspector.EventListenerBreakpoint.prototype = { + compareTo: function(other) + { + return this._compare(this._eventName, other._eventName); + }, + + populateLabelElement: function(element) + { + element.appendChild(document.createTextNode(this._uiEventName())); + }, + + populateStatusMessageElement: function(element, eventData) + { + var status = WebInspector.UIString("Paused on a \"%s\" Event Listener.", this._uiEventName()); + element.appendChild(document.createTextNode(status)); + }, + + _condition: function() + { + return { eventName: this._eventName }; + }, + + _uiEventName: function() + { + if (!WebInspector.EventListenerBreakpoint._uiEventNames) { + WebInspector.EventListenerBreakpoint._uiEventNames = { + "instrumentation:setTimer": WebInspector.UIString("Set Timer"), + "instrumentation:clearTimer": WebInspector.UIString("Clear Timer"), + "instrumentation:timerFired": WebInspector.UIString("Timer Fired") + }; + } + return WebInspector.EventListenerBreakpoint._uiEventNames[this._eventName] || this._eventName.substring(this._eventName.indexOf(":") + 1); + } +} + +WebInspector.EventListenerBreakpoint.prototype.__proto__ = WebInspector.NativeBreakpoint.prototype; + +WebInspector.XHRBreakpoint = function(manager, frontendId, url) +{ + WebInspector.NativeBreakpoint.call(this, manager, frontendId, "XHR"); + this._url = url; +} + +WebInspector.XHRBreakpoint.prototype = { + compareTo: function(other) + { + return this._compare(this._url, other._url); + }, + + populateLabelElement: function(element) + { + var label; + if (!this._url.length) + label = WebInspector.UIString("Any XHR"); + else + label = WebInspector.UIString("URL contains \"%s\"", this._url); + element.appendChild(document.createTextNode(label)); + }, + + populateStatusMessageElement: function(element) + { + var status = WebInspector.UIString("Paused on a XMLHttpRequest."); + element.appendChild(document.createTextNode(status)); + }, + + _condition: function() + { + return { url: this._url }; + } +} + +WebInspector.XHRBreakpoint.prototype.__proto__ = WebInspector.NativeBreakpoint.prototype; + +WebInspector.DebuggerEventTypes = { + JavaScriptPause: 0, + JavaScriptBreakpoint: 1, + NativeBreakpoint: 2 +}; + +WebInspector.DOMBreakpointTypes = { + SubtreeModified: 0, + AttributeModified: 1, + NodeRemoved: 2 +}; + +WebInspector.domBreakpointTypeLabel = function(type) +{ + if (!WebInspector._DOMBreakpointTypeLabels) { + WebInspector._DOMBreakpointTypeLabels = {}; + WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.SubtreeModified] = WebInspector.UIString("Subtree Modified"); + WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.AttributeModified] = WebInspector.UIString("Attribute Modified"); + WebInspector._DOMBreakpointTypeLabels[WebInspector.DOMBreakpointTypes.NodeRemoved] = WebInspector.UIString("Node Removed"); + } + return WebInspector._DOMBreakpointTypeLabels[type]; +} + +WebInspector.domBreakpointTypeContextMenuLabel = function(type) +{ + if (!WebInspector._DOMBreakpointTypeContextMenuLabels) { + WebInspector._DOMBreakpointTypeContextMenuLabels = {}; + WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.SubtreeModified] = WebInspector.UIString("Break on Subtree Modifications"); + WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.AttributeModified] = WebInspector.UIString("Break on Attributes Modifications"); + WebInspector._DOMBreakpointTypeContextMenuLabels[WebInspector.DOMBreakpointTypes.NodeRemoved] = WebInspector.UIString("Break on Node Removal"); + } + return WebInspector._DOMBreakpointTypeContextMenuLabels[type]; +} diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js index 16ab041..2151137 100644 --- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -113,6 +113,9 @@ WebInspector.XHRBreakpointsSidebarPane.prototype = { if (this.urlInputElement.parentElement) return; + if (!this.expanded) + this.expanded = true; + this.urlInputElement.textContent = ""; this.bodyElement.insertBefore(this.urlInputElement, this.bodyElement.firstChild); WebInspector.startEditing(this.urlInputElement, this._hideEditBreakpointDialog.bind(this, false), this._hideEditBreakpointDialog.bind(this, true)); @@ -142,7 +145,11 @@ WebInspector.BreakpointItem = function(breakpoint) checkboxElement.addEventListener("click", this._checkboxClicked.bind(this), false); this._element.appendChild(checkboxElement); + if ("populateLabelElement" in this._breakpoint) + this._breakpoint.populateLabelElement(this._element); + this._breakpoint.addEventListener("enable-changed", this._enableChanged, this); + this._breakpoint.addEventListener("hit-state-changed", this._hitStateChanged, this); this._breakpoint.addEventListener("removed", this.dispatchEventToListeners.bind(this, "removed")); } @@ -162,6 +169,12 @@ WebInspector.BreakpointItem.prototype = { this._breakpoint.remove(); }, + _breakpointClicked: function(event) + { + if ("click" in this._breakpoint) + this._breakpoint.click(); + }, + _checkboxClicked: function(event) { this._breakpoint.enabled = !this._breakpoint.enabled; @@ -176,8 +189,12 @@ WebInspector.BreakpointItem.prototype = { checkbox.checked = this._breakpoint.enabled; }, - _breakpointClicked: function(event) + _hitStateChanged: function(event) { + if (event.target.hit) + this._element.addStyleClass("breakpoint-hit"); + else + this._element.removeStyleClass("breakpoint-hit"); } } @@ -214,33 +231,119 @@ WebInspector.JSBreakpointItem.prototype = { WebInspector.JSBreakpointItem.prototype.__proto__ = WebInspector.BreakpointItem.prototype; -WebInspector.DOMBreakpointItem = function(breakpoint) +WebInspector.EventListenerBreakpointsSidebarPane = function() { - WebInspector.BreakpointItem.call(this, breakpoint); + WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listener Breakpoints")); - var link = WebInspector.panels.elements.linkifyNodeById(this._breakpoint.nodeId); - this._element.appendChild(link); - - var type = WebInspector.DOMBreakpoint.labelForType(this._breakpoint.type); - var typeElement = document.createTextNode(" - " + type); - this._element.appendChild(typeElement); + this.categoriesElement = document.createElement("ol"); + this.categoriesElement.tabIndex = 0; + this.categoriesElement.addStyleClass("properties-tree event-listener-breakpoints"); + this.categoriesTreeOutline = new TreeOutline(this.categoriesElement); + this.bodyElement.appendChild(this.categoriesElement); } -WebInspector.DOMBreakpointItem.prototype = { - _breakpointClicked: function() +WebInspector.EventListenerBreakpointsSidebarPane.prototype = { + _populate: function() { - WebInspector.updateFocusedNode(this._breakpoint.nodeId); - } -} + var categories = { + "Mouse": { type: "listener", eventNames: ["click", "dblclick", "mousedown", "mouseup", "mouseover", "mousemove", "mouseout", "mousewheel"] }, + "Keyboard": { type: "listener", eventNames: ["keydown", "keypress", "keyup"] }, + "HTML frame/object": { type: "listener", eventNames: ["load", "error", "resize", "scroll"] }, + "Timer": { type: "instrumentation", eventNames: ["setTimer", "clearTimer", "timerFired"] } + }; + + for (var category in categories) { + var categoryTreeElement = new TreeElement(WebInspector.UIString(category)); + this.categoriesTreeOutline.appendChild(categoryTreeElement); + categoryTreeElement.listItemElement.addStyleClass("event-category"); + categoryTreeElement.selectable = true; + + var categoryItem = {}; + categoryItem.checkbox = this._createCheckbox(categoryTreeElement, this._categoryCheckboxClicked.bind(this, categoryItem)); + categoryItem.children = {}; + + var categoryType = categories[category].type; + var eventNames = categories[category].eventNames; + for (var i = 0; i < eventNames.length; ++i) { + var eventName = categoryType + ":" + eventNames[i]; + + var breakpoint = WebInspector.breakpointManager.createEventListenerBreakpoint(eventName, true); + if (!breakpoint) + continue; + + var labelElement = document.createElement("div"); + breakpoint.populateLabelElement(labelElement); + var eventNameTreeElement = new TreeElement(labelElement); + categoryTreeElement.appendChild(eventNameTreeElement); + eventNameTreeElement.listItemElement.addStyleClass("source-code"); + eventNameTreeElement.selectable = true; + + var eventNameItem = {}; + eventNameItem.checkbox = this._createCheckbox(eventNameTreeElement, this._eventNameCheckboxClicked.bind(this, categoryItem, eventNameItem)); + eventNameItem.breakpoint = breakpoint; + + breakpoint.addEventListener("enable-changed", this._breakpointEnableChanged.bind(this, categoryItem, eventNameItem), true); + + categoryItem.children[eventName] = eventNameItem; + } + } + }, -WebInspector.DOMBreakpointItem.prototype.__proto__ = WebInspector.BreakpointItem.prototype; + _createCheckbox: function(treeElement, checkboxClickedDelegate) + { + var checkbox = document.createElement("input"); + checkbox.className = "checkbox-elem"; + checkbox.type = "checkbox"; + checkbox.addEventListener("click", checkboxClickedDelegate, true); + treeElement.listItemElement.insertBefore(checkbox, treeElement.listItemElement.firstChild); + return checkbox; + }, -WebInspector.XHRBreakpointItem = function(breakpoint) -{ - WebInspector.BreakpointItem.call(this, breakpoint); + _categoryCheckboxClicked: function(categoryItem) + { + var checkbox = categoryItem.checkbox; + checkbox.indeterminate = false; + for (var eventName in categoryItem.children) { + var eventNameItem = categoryItem.children[eventName]; + eventNameItem.checkbox.checked = checkbox.checked; + eventNameItem.breakpoint.enabled = checkbox.checked; + } + }, + + _eventNameCheckboxClicked: function(categoryItem, eventNameItem) + { + this._updateCategoryCheckbox(categoryItem); + eventNameItem.breakpoint.enabled = eventNameItem.checkbox.checked; + }, + + _breakpointEnableChanged: function(categoryItem, eventNameItem) + { + if (eventNameItem.checkbox.checked === eventNameItem.breakpoint.enabled) + return; - var label = document.createTextNode(this._breakpoint.formatLabel()); - this._element.appendChild(label); + eventNameItem.checkbox.checked = eventNameItem.breakpoint.enabled; + this._updateCategoryCheckbox(categoryItem); + }, + + _updateCategoryCheckbox: function(categoryItem) + { + var hasEnabled = false, hasDisabled = false; + for (var eventName in categoryItem.children) { + var eventNameItem = categoryItem.children[eventName]; + if (eventNameItem.checkbox.checked) + hasEnabled = true; + else + hasDisabled = true; + } + categoryItem.checkbox.checked = hasEnabled; + categoryItem.checkbox.indeterminate = hasEnabled && hasDisabled; + }, + + reset: function() + { + this.categoriesTreeOutline.removeChildren(); + this._populate(); + } } -WebInspector.XHRBreakpointItem.prototype.__proto__ = WebInspector.BreakpointItem.prototype; +WebInspector.EventListenerBreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; diff --git a/WebCore/inspector/front-end/CSSStyleModel.js b/WebCore/inspector/front-end/CSSStyleModel.js index bda4064..e3e9b4f 100644 --- a/WebCore/inspector/front-end/CSSStyleModel.js +++ b/WebCore/inspector/front-end/CSSStyleModel.js @@ -96,13 +96,13 @@ WebInspector.CSSStyleModel.prototype = { applyStyleText: function(styleId, styleText, propertyName, successCallback, failureCallback) { - function callback(success, newPayload, changedProperties) + function callback(success, newPayload) { if (!success) failureCallback(); else { var newStyle = newPayload ? WebInspector.CSSStyleDeclaration.parseStyle(newPayload) : null; - successCallback(newStyle, changedProperties); + successCallback(newStyle); } } diff --git a/WebCore/inspector/front-end/CallStackSidebarPane.js b/WebCore/inspector/front-end/CallStackSidebarPane.js index 6212ea1..08c1942 100644 --- a/WebCore/inspector/front-end/CallStackSidebarPane.js +++ b/WebCore/inspector/front-end/CallStackSidebarPane.js @@ -26,13 +26,9 @@ WebInspector.CallStackSidebarPane = function() { WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); + WebInspector.breakpointManager.addEventListener("breakpoint-hit", this._breakpointHit, this); } -WebInspector.CallStackSidebarPane.DebuggerEventType = { - DOMBreakpoint: 0, - NativeBreakpoint: 1 -}; - WebInspector.CallStackSidebarPane.prototype = { update: function(callFrames, sourceIDMap) { @@ -87,44 +83,6 @@ WebInspector.CallStackSidebarPane.prototype = { } }, - updateStatus: function(eventType, eventData) - { - var statusElement = document.createElement("div"); - if (eventType === WebInspector.CallStackSidebarPane.DebuggerEventType.DOMBreakpoint) { - var breakpoint = eventData.breakpoint; - var substitutions = [WebInspector.DOMBreakpoint.labelForType(breakpoint.type), WebInspector.panels.elements.linkifyNodeById(breakpoint.nodeId)]; - var formatters = { - s: function(substitution) - { - return substitution; - } - }; - function append(a, b) - { - if (typeof b === "string") - b = document.createTextNode(b); - statusElement.appendChild(b); - } - if (breakpoint.type === WebInspector.DOMBreakpoint.Types.SubtreeModified) { - var targetNode = WebInspector.panels.elements.linkifyNodeById(eventData.targetNodeId); - if (eventData.insertion) { - if (eventData.targetNodeId !== breakpoint.nodeId) - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.", substitutions.concat(targetNode), formatters, "", append); - else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.", substitutions, formatters, "", append); - } else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.", substitutions.concat(targetNode), formatters, "", append); - } else - WebInspector.formatLocalized("Paused on a \"%s\" breakpoint set on %s.", substitutions, formatters, "", append); - } else if (eventType === WebInspector.CallStackSidebarPane.DebuggerEventType.NativeBreakpoint && eventData.type === "XHR") - statusElement.appendChild(document.createTextNode(WebInspector.UIString("Paused on XMLHttpRequest."))); - else - return; - - statusElement.className = "info"; - this.bodyElement.appendChild(statusElement); - }, - get selectedCallFrame() { return this._selectedCallFrame; @@ -210,6 +168,16 @@ WebInspector.CallStackSidebarPane.prototype = { this._shortcuts[prevCallFrame.key] = this._selectPreviousCallFrameOnStack.bind(this); section.addRelatedKeys([ nextCallFrame.name, prevCallFrame.name ], WebInspector.UIString("Next/previous call frame")); + }, + + _breakpointHit: function(event) + { + var breakpoint = event.data.breakpoint; + + var statusMessageElement = document.createElement("div"); + statusMessageElement.className = "info"; + breakpoint.populateStatusMessageElement(statusMessageElement, event.data.eventData); + this.bodyElement.appendChild(statusMessageElement); } } diff --git a/WebCore/inspector/front-end/ConsoleView.js b/WebCore/inspector/front-end/ConsoleView.js index 6f8bd8b..8cd5d52 100644 --- a/WebCore/inspector/front-end/ConsoleView.js +++ b/WebCore/inspector/front-end/ConsoleView.js @@ -64,7 +64,7 @@ WebInspector.ConsoleView = function(drawer) function createDividerElement() { var dividerElement = document.createElement("div"); - dividerElement.addStyleClass("divider"); + dividerElement.addStyleClass("scope-bar-divider"); this.filterBarElement.appendChild(dividerElement); } @@ -360,7 +360,7 @@ WebInspector.ConsoleView.prototype = { } var results = []; - var properties = Object.sortedProperties(result); + var properties = Object.keys(result).sort(); for (var i = 0; i < properties.length; ++i) { var property = properties[i]; @@ -679,25 +679,22 @@ WebInspector.ConsoleMessage.prototype = { case WebInspector.ConsoleMessage.MessageType.UncaughtException: var ol = document.createElement("ol"); ol.addStyleClass("stack-trace"); - if (this.type === WebInspector.ConsoleMessage.MessageType.Trace) - ol.addStyleClass("trace-message"); var treeOutline = new TreeOutline(ol); + var messageText; + if (this.type === WebInspector.ConsoleMessage.MessageType.Assert) + messageText = this._format(this._parameters); + else if (this.type === WebInspector.ConsoleMessage.MessageType.Trace) + messageText = document.createTextNode("console.trace()"); + else + messageText = document.createTextNode(this._messageText); - var root = treeOutline; - if (this.type === WebInspector.ConsoleMessage.MessageType.UncaughtException || - this.type === WebInspector.ConsoleMessage.MessageType.Assert) { - var messageText; - if (this.type === WebInspector.ConsoleMessage.MessageType.Assert) - messageText = this._format(this._parameters); - else - messageText = document.createTextNode(this._messageText); - - var content = document.createElement("div"); - this._addMessageHeader(content, messageText); - root = new TreeElement(content, null, true); - content.treeElementForTest = root; - treeOutline.appendChild(root); - } + var content = document.createElement("div"); + this._addMessageHeader(content, messageText); + var root = new TreeElement(content, null, true); + content.treeElementForTest = root; + treeOutline.appendChild(root); + if (this.type === WebInspector.ConsoleMessage.MessageType.Trace) + root.expand(); this._populateStackTraceTreeElement(root); this.formattedMessage = ol; diff --git a/WebCore/inspector/front-end/CookieItemsView.js b/WebCore/inspector/front-end/CookieItemsView.js index 1baf4a6..88cbe05 100644 --- a/WebCore/inspector/front-end/CookieItemsView.js +++ b/WebCore/inspector/front-end/CookieItemsView.js @@ -122,8 +122,8 @@ WebInspector.CookieItemsView.prototype = { for (var id in WebInspector.resources) { var resource = WebInspector.resources[id]; - var match = resource.documentURL.match(WebInspector.GenericURLRegExp); - if (match && match[2] === this._cookieDomain) + var url = resource.documentURL.asParsedURL(); + if (url && url.host == this._cookieDomain) resourceURLsForDocumentURL.push(resource.url); } diff --git a/WebCore/inspector/front-end/CookieParser.js b/WebCore/inspector/front-end/CookieParser.js new file mode 100755 index 0000000..2be5df7 --- /dev/null +++ b/WebCore/inspector/front-end/CookieParser.js @@ -0,0 +1,204 @@ +/* + * 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. + */ + +// Ideally, we would rely on platform support for parsing a cookie, since +// this would save us from any potential inconsistency. However, exposing +// platform cookie parsing logic would require quite a bit of additional +// plumbing, and at least some platforms lack support for parsing Cookie, +// which is in a format slightly different from Set-Cookie and is normally +// only required on the server side. + +WebInspector.CookieParser = function() +{ +} + +WebInspector.CookieParser.prototype = { + get cookies() + { + return this._cookies; + }, + + parseCookie: function(cookieHeader) + { + if (!this._initialize(cookieHeader)) + return; + + for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) { + if (kv.key.charAt(0) === "$" && this._lastCookie) + this._lastCookie.addAttribute(kv.key.slice(1), kv.value); + else if (kv.key.toLowerCase() !== "$version" && typeof kv.value === "string") + this._addCookie(kv); + this._advanceAndCheckCookieDelimiter(); + } + this._flushCookie(); + return this._cookies; + }, + + parseSetCookie: function(setCookieHeader) + { + if (!this._initialize(setCookieHeader)) + return; + for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) { + if (this._lastCookie) + this._lastCookie.addAttribute(kv.key, kv.value); + else + this._addCookie(kv); + if (this._advanceAndCheckCookieDelimiter()) + this._flushCookie(); + } + this._flushCookie(); + return this._cookies; + }, + + _initialize: function(headerValue) + { + this._input = headerValue; + if (typeof headerValue !== "string") + return false; + this._cookies = []; + this._lastCookie = null; + this._originalInputLength = this._input.length; + return true; + }, + + _flushCookie: function() + { + if (this._lastCookie) + this._lastCookie.size = this._originalInputLength - this._input.length - this._lastCookiePosition; + this._lastCookie = null; + }, + + _extractKeyValue: function() + { + if (!this._input || !this._input.length) + return null; + // Note: RFCs offer an option for quoted values that may contain commas and semicolons. + // Many browsers/platforms do not support this, however (see http://webkit.org/b/16699 + // and http://crbug.com/12361). The logic below matches latest versions of IE, Firefox, + // Chrome and Safari on some old platforms. The latest version of Safari supports quoted + // cookie values, though. + var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this._input); + if (!keyValueMatch) { + console.log("Failed parsing cookie header before: " + this._input); + return null; + } + + var result = { + key: keyValueMatch[1], + value: keyValueMatch[2] && keyValueMatch[2].trim(), + position: this._originalInputLength - this._input.length + }; + this._input = this._input.slice(keyValueMatch[0].length); + return result; + }, + + _advanceAndCheckCookieDelimiter: function() + { + var match = /^\s*[\n;]\s*/.exec(this._input); + if (!match) + return false; + this._input = this._input.slice(match[0].length); + return match[0].match("\n") !== null; + }, + + _addCookie: function(keyValue) + { + if (this._lastCookie) + this._lastCookie.size = keyValue.position - this._lastCookiePosition; + // Mozilla bug 169091: Mozilla, IE and Chrome treat signle token (w/o "=") as + // specifying a value for a cookie with empty name. + this._lastCookie = keyValue.value ? new WebInspector.Cookie(keyValue.key, keyValue.value) : + new WebInspector.Cookie("", keyValue.key); + this._lastCookiePosition = keyValue.position; + this._cookies.push(this._lastCookie); + } +}; + +WebInspector.CookieParser.parseCookie = function(header) +{ + return (new WebInspector.CookieParser()).parseCookie(header); +} + +WebInspector.CookieParser.parseSetCookie = function(header) +{ + return (new WebInspector.CookieParser()).parseSetCookie(header); +} + +WebInspector.Cookie = function(name, value) +{ + this.name = name; + this.value = value; + this._attributes = {}; +} + +WebInspector.Cookie.prototype = { + get httpOnly() + { + return "httponly" in this._attributes; + }, + + get secure() + { + return "secure" in this._attributes; + }, + + get session() + { + // RFC 2965 suggests using Discard attribute to mark session cookies, but this does not seem to be widely used. + // Check for absence of explicity max-age or expiry date instead. + return !("expries" in this._attributes || "max-age" in this._attributes); + }, + + get path() + { + return this._attributes.path; + }, + + get domain() + { + return this._attributes.domain; + }, + + expires: function(requestDate) + { + return this._attributes.expires ? new Date(this._attributes.expires) : + (this._attributes["max-age"] ? new Date(requestDate.getTime() + 1000 * this._attributes["max-age"]) : null); + }, + + get attributes() + { + return this._attributes; + }, + + addAttribute: function(key, value) + { + this._attributes[key.toLowerCase()] = value; + } +} diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js index 279852e..5153fb1 100644 --- a/WebCore/inspector/front-end/DOMAgent.js +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -60,6 +60,8 @@ WebInspector.DOMNode = function(doc, payload) { this.style = null; this._matchedCSSRules = []; + this.breakpoints = {}; + if (this.nodeType === Node.ELEMENT_NODE) { // HTML and BODY from internal iframes should not overwrite top-level ones. if (!this.ownerDocument.documentElement && this.nodeName === "HTML") @@ -149,28 +151,6 @@ WebInspector.DOMNode.prototype = { return path.join(","); }, - setBreakpoint: function(type) - { - return WebInspector.domBreakpointManager.setBreakpoint(this.id, type, true, this.path()); - }, - - hasBreakpoint: function(type) - { - return !!WebInspector.domBreakpointManager.findBreakpoint(this.id, type); - }, - - removeBreakpoint: function(type) - { - var breakpoint = WebInspector.domBreakpointManager.findBreakpoint(this.id, type); - if (breakpoint) - breakpoint.remove(); - }, - - removeBreakpoints: function() - { - WebInspector.domBreakpointManager.removeBreakpointsForNode(this.id); - }, - _setAttributesPayload: function(attrs) { this.attributes = []; @@ -399,7 +379,7 @@ WebInspector.DOMAgent.prototype = { this.document = new WebInspector.DOMDocument(this, this._window, payload); this._idToDOMNode[payload.id] = this.document; this._bindNodes(this.document.children); - WebInspector.domBreakpointManager.restoreBreakpoints(); + WebInspector.breakpointManager.restoreDOMBreakpoints(); } else this.document = null; WebInspector.panels.elements.setDocument(this.document); @@ -461,12 +441,13 @@ WebInspector.DOMAgent.prototype = { _removeBreakpoints: function(node) { - node.removeBreakpoints(); + for (var type in node.breakpoints) + node.breakpoints[type].remove(); if (!node.children) return; for (var i = 0; i < node.children.length; ++i) this._removeBreakpoints(node.children[i]); - } + } } WebInspector.ApplicationCache = {} @@ -519,17 +500,12 @@ WebInspector.Cookies.buildCookiesFromString = function(rawCookieString) WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) { - var match = resourceURL.match(WebInspector.GenericURLRegExp); - if (!match) + var url = resourceURL.asParsedURL(); + if (!url || !this.cookieDomainMatchesResourceDomain(cookie.domain, url.host)) return false; - // See WebInspector.URLRegExp for definitions of the group index constants. - if (!this.cookieDomainMatchesResourceDomain(cookie.domain, match[2])) - return false; - var resourcePort = match[3] ? match[3] : undefined; - var resourcePath = match[4] ? match[4] : '/'; - return (resourcePath.indexOf(cookie.path) === 0 - && (!cookie.port || resourcePort == cookie.port) - && (!cookie.secure || match[1].toLowerCase() === 'https')); + return (url.path.indexOf(cookie.path) === 0 + && (!cookie.port || url.port == cookie.port) + && (!cookie.secure || url.scheme === "https")); } WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain) @@ -728,166 +704,3 @@ WebInspector.childNodeRemoved = function() { this.domAgent._childNodeRemoved.apply(this.domAgent, arguments); } - -WebInspector.DOMBreakpointManager = function() -{ - this._breakpoints = {}; - this._pathCache = {}; -} - -WebInspector.DOMBreakpointManager.prototype = { - setBreakpoint: function(nodeId, type, enabled, path) - { - if (!(nodeId in this._breakpoints)) - this._breakpoints[nodeId] = {}; - else if (type in this._breakpoints[nodeId]) - return; - - var breakpoint = new WebInspector.DOMBreakpoint(nodeId, type, enabled); - this._breakpoints[nodeId][type] = breakpoint; - breakpoint.addEventListener("removed", this._breakpointRemoved, this); - - if (!(nodeId in this._pathCache)) - this._pathCache[nodeId] = path; - - this.dispatchEventToListeners("dom-breakpoint-added", breakpoint); - }, - - findBreakpoint: function(nodeId, type) - { - var nodeBreakpoints = this._breakpoints[nodeId]; - if (nodeBreakpoints && type in nodeBreakpoints) - return nodeBreakpoints[type]; - }, - - removeBreakpointsForNode: function(nodeId) - { - var nodeBreakpoints = this._breakpoints[nodeId]; - for (var type in nodeBreakpoints) - nodeBreakpoints[type].remove(); - }, - - _breakpointRemoved: function(event) - { - var breakpoint = event.target; - - var nodeBreakpoints = this._breakpoints[breakpoint.nodeId]; - delete nodeBreakpoints[breakpoint.type]; - for (var type in nodeBreakpoints) - return; - - delete this._breakpoints[breakpoint.nodeId]; - delete this._pathCache[breakpoint.nodeId]; - }, - - restoreBreakpoints: function() - { - var breakpoints = this._breakpoints; - this._breakpoints = {}; - var pathCache = this._pathCache; - this._pathCache = {}; - - for (var oldNodeId in breakpoints) { - var path = pathCache[oldNodeId]; - InspectorBackend.pushNodeByPathToFrontend(path, restoreBreakpointsForNode.bind(this, breakpoints[oldNodeId], path)); - } - - function restoreBreakpointsForNode(nodeBreakpoints, path, nodeId) - { - if (!nodeId) - return; - for (var type in nodeBreakpoints) { - var breakpoint = nodeBreakpoints[type]; - this.setBreakpoint(nodeId, breakpoint.type, breakpoint.enabled, path); - } - } - } -} - -WebInspector.DOMBreakpointManager.prototype.__proto__ = WebInspector.Object.prototype; - -WebInspector.DOMBreakpoint = function(nodeId, type, enabled) -{ - this._nodeId = nodeId; - this._type = type; - this._enabled = enabled; - - if (this.enabled) - InspectorBackend.setDOMBreakpoint(this.nodeId, this.type); -} - -WebInspector.DOMBreakpoint.Types = { - SubtreeModified: 0, - AttributeModified: 1, - NodeRemoved: 2 -}; - -WebInspector.DOMBreakpoint.labelForType = function(type) -{ - if (!WebInspector.DOMBreakpoint._labels) { - WebInspector.DOMBreakpoint._labels = {}; - WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.SubtreeModified] = WebInspector.UIString("Subtree Modified"); - WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.AttributeModified] = WebInspector.UIString("Attribute Modified"); - WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.NodeRemoved] = WebInspector.UIString("Node Removed"); - } - return WebInspector.DOMBreakpoint._labels[type]; -} - -WebInspector.DOMBreakpoint.contextMenuLabelForType = function(type) -{ - if (!WebInspector.DOMBreakpoint._contextMenuLabels) { - WebInspector.DOMBreakpoint._contextMenuLabels = {}; - WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.SubtreeModified] = WebInspector.UIString("Break on Subtree Modifications"); - WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.AttributeModified] = WebInspector.UIString("Break on Attributes Modifications"); - WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.NodeRemoved] = WebInspector.UIString("Break on Node Removal"); - } - return WebInspector.DOMBreakpoint._contextMenuLabels[type]; -} - -WebInspector.DOMBreakpoint.prototype = { - get nodeId() - { - return this._nodeId; - }, - - get type() - { - return this._type; - }, - - get enabled() - { - return this._enabled; - }, - - set enabled(enabled) - { - if (this._enabled === enabled) - return; - - this._enabled = enabled; - if (this.enabled) - InspectorBackend.setDOMBreakpoint(this.nodeId, this.type); - else - InspectorBackend.removeDOMBreakpoint(this.nodeId, this.type); - - this.dispatchEventToListeners("enable-changed"); - }, - - compareTo: function(other) - { - if (this.type != other.type) - return this.type < other.type ? -1 : 1; - return 0; - }, - - remove: function() - { - if (this.enabled) - InspectorBackend.removeDOMBreakpoint(this.nodeId, this.type); - this.dispatchEventToListeners("removed"); - } -} - -WebInspector.DOMBreakpoint.prototype.__proto__ = WebInspector.Object.prototype; - diff --git a/WebCore/inspector/front-end/DataGrid.js b/WebCore/inspector/front-end/DataGrid.js index f68fe48..3007497 100644 --- a/WebCore/inspector/front-end/DataGrid.js +++ b/WebCore/inspector/front-end/DataGrid.js @@ -32,6 +32,7 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback) this._headerTable = document.createElement("table"); this._headerTable.className = "header"; + this._headerTableHeaders = {}; this._dataTable = document.createElement("table"); this._dataTable.className = "data"; @@ -77,9 +78,13 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback) var cell = document.createElement("th"); cell.className = columnIdentifier + "-column"; cell.columnIdentifier = columnIdentifier; + this._headerTableHeaders[columnIdentifier] = cell; var div = document.createElement("div"); - div.textContent = column.title; + if (column.titleDOMFragment) + div.appendChild(column.titleDOMFragment); + else + div.textContent = column.title; cell.appendChild(div); if (column.sort) { @@ -113,16 +118,27 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback) var fillerRow = document.createElement("tr"); fillerRow.className = "filler"; - for (var i = 0; i < this._columnCount; ++i) { + for (var columnIdentifier in columns) { + var column = columns[columnIdentifier]; var cell = document.createElement("td"); + cell.className = columnIdentifier + "-column"; fillerRow.appendChild(cell); } - + this._dataTableColumnGroup = columnGroup.cloneNode(true); this._dataTable.appendChild(this._dataTableColumnGroup); this.dataTableBody.appendChild(fillerRow); this.columns = columns || {}; + this._columnsArray = []; + for (var columnIdentifier in columns) { + columns[columnIdentifier].ordinal = this._columnsArray.length; + this._columnsArray.push(columns[columnIdentifier]); + } + + for (var i = 0; i < this._columnsArray.length; ++i) + this._columnsArray[i].bodyElement = this._dataTableColumnGroup.children[i]; + this.children = []; this.selectedNode = null; this.expandNodesWhenArrowing = false; @@ -134,7 +150,7 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback) this.dataGrid = this; this.indentWidth = 15; this.resizers = []; - this.columnWidthsInitialized = false; + this._columnWidthsInitialized = false; } WebInspector.DataGrid.prototype = { @@ -351,7 +367,7 @@ WebInspector.DataGrid.prototype = { for (var columnIdentifier in columns) columns[columnIdentifier].element.style.width = widths[columnIdentifier] + "%"; - this.columnWidthsInitialized = false; + this._columnWidthsInitialized = false; this.updateWidths(); }, @@ -369,11 +385,10 @@ WebInspector.DataGrid.prototype = { { var headerTableColumns = this._headerTableColumnGroup.children; - var left = 0; var tableWidth = this._dataTable.offsetWidth; var numColumns = headerTableColumns.length; - if (!this.columnWidthsInitialized) { + if (!this._columnWidthsInitialized) { // Give all the columns initial widths now so that during a resize, // when the two columns that get resized get a percent value for // their widths, all the other columns already have percent values @@ -384,9 +399,86 @@ WebInspector.DataGrid.prototype = { this._headerTableColumnGroup.children[i].style.width = percentWidth; this._dataTableColumnGroup.children[i].style.width = percentWidth; } - this.columnWidthsInitialized = true; + this._columnWidthsInitialized = true; } - + this._positionResizers(); + this.dispatchEventToListeners("width changed"); + }, + + columnWidthsMap: function() + { + var result = {}; + for (var i = 0; i < this._columnsArray.length; ++i) { + var width = this._headerTableColumnGroup.children[i].style.width; + result[this._columnsArray[i].columnIdentifier] = parseFloat(width); + } + return result; + }, + + applyColumnWidthsMap: function(columnWidthsMap) + { + for (var columnIdentifier in this.columns) { + var column = this.columns[columnIdentifier]; + var width = (columnWidthsMap[columnIdentifier] || 0) + "%"; + this._headerTableColumnGroup.children[column.ordinal].style.width = width; + this._dataTableColumnGroup.children[column.ordinal].style.width = width; + } + + // Normalize widths + delete this._columnWidthsInitialized; + this.updateWidths(); + }, + + isColumnVisible: function(columnIdentifier) + { + var column = this.columns[columnIdentifier]; + var columnElement = column.element; + return !columnElement.hidden; + }, + + showColumn: function(columnIdentifier) + { + var column = this.columns[columnIdentifier]; + var columnElement = column.element; + if (!columnElement.hidden) + return; + + columnElement.hidden = false; + columnElement.removeStyleClass("hidden"); + + var columnBodyElement = column.bodyElement; + columnBodyElement.hidden = false; + columnBodyElement.removeStyleClass("hidden"); + }, + + hideColumn: function(columnIdentifier) + { + var column = this.columns[columnIdentifier]; + var columnElement = column.element; + if (columnElement.hidden) + return; + + var oldWidth = parseFloat(columnElement.style.width); + + columnElement.hidden = true; + columnElement.addStyleClass("hidden"); + columnElement.style.width = 0; + + var columnBodyElement = column.bodyElement; + columnBodyElement.hidden = true; + columnBodyElement.addStyleClass("hidden"); + columnBodyElement.style.width = 0; + + this._columnWidthsInitialized = false; + }, + + _positionResizers: function() + { + var headerTableColumns = this._headerTableColumnGroup.children; + var numColumns = headerTableColumns.length; + var left = 0; + var previousResizer = null; + // Make n - 1 resizers for n columns. for (var i = 0; i < numColumns - 1; i++) { var resizer = this.resizers[i]; @@ -397,7 +489,6 @@ WebInspector.DataGrid.prototype = { resizer = document.createElement("div"); resizer.addStyleClass("data-grid-resizer"); // This resizer is associated with the column to its right. - resizer.rightNeighboringColumnID = i + 1; resizer.addEventListener("mousedown", this._startResizerDragging.bind(this), false); this.element.appendChild(resizer); this.resizers[i] = resizer; @@ -407,10 +498,23 @@ WebInspector.DataGrid.prototype = { // header table in order to determine the width of the column, since // it is not possible to query a column for its width. left += this.headerTableBody.rows[0].cells[i].offsetWidth; - - resizer.style.left = left + "px"; + + var columnIsVisible = !this._headerTableColumnGroup.children[i].hidden; + if (columnIsVisible) { + resizer.style.removeProperty("display"); + resizer.style.left = left + "px"; + resizer.leftNeighboringColumnID = i; + if (previousResizer) + previousResizer.rightNeighboringColumnID = i; + previousResizer = resizer; + } else { + resizer.style.setProperty("display", "none"); + resizer.leftNeighboringColumnID = 0; + resizer.rightNeighboringColumnID = 0; + } } - this.dispatchEventToListeners("width changed"); + if (previousResizer) + previousResizer.rightNeighboringColumnID = numColumns - 1; }, addCreationNode: function(hasChildren) @@ -474,6 +578,7 @@ WebInspector.DataGrid.prototype = { throw("removeChild: Node is not a child of this node."); child.deselect(); + child._detach(); this.children.remove(child, true); @@ -534,17 +639,18 @@ WebInspector.DataGrid.prototype = { this.children = []; }, - sortNodes: function(comparator, descending) + sortNodes: function(comparator, reverseMode) { function comparatorWrapper(a, b) { + if (a._dataGridNode._data.summaryRow) + return 1; + if (b._dataGridNode._data.summaryRow) + return -1; + var aDataGirdNode = a._dataGridNode; var bDataGirdNode = b._dataGridNode; - if (!aDataGirdNode) - return 1; // Filler row. - if (!bDataGirdNode) - return -1; // Filler row. - return descending ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode); + return reverseMode ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode); } var tbody = this.dataTableBody; @@ -552,15 +658,27 @@ WebInspector.DataGrid.prototype = { tbodyParent.removeChild(tbody); var childNodes = tbody.childNodes; - var sortedNodes = Array.prototype.slice.call(childNodes); - sortedNodes.sort(comparatorWrapper.bind(this)); + var fillerRow = childNodes[childNodes.length - 1]; + + var sortedRows = Array.prototype.slice.call(childNodes, 0, childNodes.length - 1); + sortedRows.sort(comparatorWrapper); + var sortedRowsLength = sortedRows.length; - var sortedNodesLength = sortedNodes.length; tbody.removeChildren(); - for (var i = 0; i < sortedNodesLength; ++i) { - var node = sortedNodes[i]; - tbody.appendChild(node); + var previousSiblingNode = null; + for (var i = 0; i < sortedRowsLength; ++i) { + var row = sortedRows[i]; + var node = row._dataGridNode; + node.previousSibling = previousSiblingNode; + if (previousSiblingNode) + previousSiblingNode.nextSibling = node; + tbody.appendChild(row); + previousSiblingNode = node; } + if (previousSiblingNode) + previousSiblingNode.nextSibling = null; + + tbody.appendChild(fillerRow); tbodyParent.appendChild(tbody); }, @@ -673,13 +791,11 @@ WebInspector.DataGrid.prototype = { var sortOrder = this.sortOrder; - if (this._sortColumnCell) { - this._sortColumnCell.removeStyleClass("sort-ascending"); - this._sortColumnCell.removeStyleClass("sort-descending"); - } + if (this._sortColumnCell) + this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+"); if (cell == this._sortColumnCell) { - if (sortOrder == "ascending") + if (sortOrder === "ascending") sortOrder = "descending"; else sortOrder = "ascending"; @@ -692,6 +808,19 @@ WebInspector.DataGrid.prototype = { this.dispatchEventToListeners("sorting changed"); }, + markColumnAsSortedBy: function(columnIdentifier, sortOrder) + { + if (this._sortColumnCell) + this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+"); + this._sortColumnCell = this._headerTableHeaders[columnIdentifier]; + this._sortColumnCell.addStyleClass("sort-" + sortOrder); + }, + + headerTableHeader: function(columnIdentifier) + { + return this._headerTableHeaders[columnIdentifier]; + }, + _mouseDownInDataTable: function(event) { var gridNode = this.dataGridNodeFromNode(event.target); @@ -778,27 +907,28 @@ WebInspector.DataGrid.prototype = { // column directly to the left and the column directly to the right. var leftEdgeOfPreviousColumn = 0; var firstRowCells = this.headerTableBody.rows[0].cells; - for (var i = 0; i < resizer.rightNeighboringColumnID - 1; i++) + for (var i = 0; i < resizer.leftNeighboringColumnID; i++) leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth; - var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[resizer.rightNeighboringColumnID - 1].offsetWidth + firstRowCells[resizer.rightNeighboringColumnID].offsetWidth; - - // Give each column some padding so that they don't disappear. + var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[resizer.leftNeighboringColumnID].offsetWidth + firstRowCells[resizer.rightNeighboringColumnID].offsetWidth; + + // Give each column some padding so that they don't disappear. var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding; var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding; - + dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum); - + resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px"; - + var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + "%"; - this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn; - this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID - 1].style.width = percentLeftColumn; - + this._headerTableColumnGroup.children[resizer.leftNeighboringColumnID].style.width = percentLeftColumn; + this._dataTableColumnGroup.children[resizer.leftNeighboringColumnID].style.width = percentLeftColumn; + var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + "%"; this._headerTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn; this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn; - + + this._positionResizers(); event.preventDefault(); this.dispatchEventToListeners("width changed"); }, diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index d6437fc..76c22c5 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -107,7 +107,6 @@ WebInspector.ElementsPanel = function() this.element.appendChild(this.sidebarResizeElement); this._registerShortcuts(); - this._changedStyles = {}; this.reset(); } @@ -346,115 +345,6 @@ WebInspector.ElementsPanel.prototype = { // TODO: Implement Shifting the oldSelector, and its contents to a newSelector }, - addStyleChange: function(identifier, style, property) - { - if (!style.parentRule) - return; - - var selector = style.parentRule.selectorText; - if (!this._changedStyles[identifier]) - this._changedStyles[identifier] = {}; - - if (!this._changedStyles[identifier][selector]) - this._changedStyles[identifier][selector] = {}; - - if (!this._changedStyles[identifier][selector][property]) - WebInspector.styleChanges += 1; - - this._changedStyles[identifier][selector][property] = style.getPropertyValue(property); - }, - - removeStyleChange: function(identifier, style, property) - { - if (!style.parentRule) - return; - - var selector = style.parentRule.selectorText; - if (!this._changedStyles[identifier] || !this._changedStyles[identifier][selector]) - return; - - if (this._changedStyles[identifier][selector][property]) { - delete this._changedStyles[identifier][selector][property]; - WebInspector.styleChanges -= 1; - } - }, - - generateStylesheet: function() - { - if (!WebInspector.styleChanges) - return; - - // Merge Down to Just Selectors - var mergedSelectors = {}; - for (var identifier in this._changedStyles) { - for (var selector in this._changedStyles[identifier]) { - if (!mergedSelectors[selector]) - mergedSelectors[selector] = this._changedStyles[identifier][selector]; - else { // merge on selector - var merge = {}; - for (var property in mergedSelectors[selector]) - merge[property] = mergedSelectors[selector][property]; - for (var property in this._changedStyles[identifier][selector]) { - if (!merge[property]) - merge[property] = this._changedStyles[identifier][selector][property]; - else { // merge on property within a selector, include comment to notify user - var value1 = merge[property]; - var value2 = this._changedStyles[identifier][selector][property]; - - if (value1 === value2) - merge[property] = [value1]; - else if (value1 instanceof Array) - merge[property].push(value2); - else - merge[property] = [value1, value2]; - } - } - mergedSelectors[selector] = merge; - } - } - } - - var builder = []; - builder.push("/**"); - builder.push(" * Inspector Generated Stylesheet"); // UIString? - builder.push(" */\n"); - - var indent = " "; - function displayProperty(property, value, comment) { - if (comment) - return indent + "/* " + property + ": " + value + "; */"; - else - return indent + property + ": " + value + ";"; - } - - for (var selector in mergedSelectors) { - var psuedoStyle = mergedSelectors[selector]; - var properties = Object.properties(psuedoStyle); - if (properties.length) { - builder.push(selector + " {"); - for (var i = 0; i < properties.length; ++i) { - var property = properties[i]; - var value = psuedoStyle[property]; - if (!(value instanceof Array)) - builder.push(displayProperty(property, value)); - else { - if (value.length === 1) - builder.push(displayProperty(property, value) + " /* merged from equivalent edits */"); // UIString? - else { - builder.push(indent + "/* There was a Conflict... There were Multiple Edits for '" + property + "' */"); // UIString? - for (var j = 0; j < value.length; ++j) - builder.push(displayProperty(property, value, true)); - } - } - } - builder.push("}\n"); - } - } - - WebInspector.showConsole(); - WebInspector.console.addMessage(WebInspector.ConsoleMessage.createTextMessage(builder.join("\n"))); - }, - get rootDOMNode() { return this.treeOutline.rootDOMNode; diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index 1479c9a..1d546c2 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -759,15 +759,15 @@ WebInspector.ElementsTreeElement.prototype = { contextMenu.appendSeparator(); var node = this.representedObject; - for (var key in WebInspector.DOMBreakpoint.Types) { - var type = WebInspector.DOMBreakpoint.Types[key]; - var label = WebInspector.DOMBreakpoint.contextMenuLabelForType(type); - var hasBreakpoint = node.hasBreakpoint(type); - if (!hasBreakpoint) - var handler = node.setBreakpoint.bind(node, type); + for (var key in WebInspector.DOMBreakpointTypes) { + var type = WebInspector.DOMBreakpointTypes[key]; + var label = WebInspector.domBreakpointTypeContextMenuLabel(type); + var breakpoint = node.breakpoints[type]; + if (!breakpoint) + var handler = WebInspector.breakpointManager.createDOMBreakpoint.bind(WebInspector.breakpointManager, node.id, type); else - var handler = node.removeBreakpoint.bind(node, type); - contextMenu.appendCheckboxItem(label, handler, hasBreakpoint); + var handler = breakpoint.remove.bind(breakpoint); + contextMenu.appendCheckboxItem(label, handler, !!breakpoint); } } }, diff --git a/WebCore/inspector/front-end/EventListenersSidebarPane.js b/WebCore/inspector/front-end/EventListenersSidebarPane.js index 34dea00..e2ad259 100644 --- a/WebCore/inspector/front-end/EventListenersSidebarPane.js +++ b/WebCore/inspector/front-end/EventListenersSidebarPane.js @@ -183,7 +183,7 @@ WebInspector.EventListenerBar = function(eventListener, nodeId) this._setFunctionSubtitle(); this.editable = false; this.element.className = "event-bar"; /* Changed from "section" */ - this.propertiesElement.className = "event-properties source-code"; /* Changed from "properties" */ + this.propertiesElement.className = "event-properties properties-tree source-code"; /* Changed from "properties" */ } WebInspector.EventListenerBar.prototype = { diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js index 64f5482..5d090b0 100644 --- a/WebCore/inspector/front-end/ExtensionAPI.js +++ b/WebCore/inspector/front-end/ExtensionAPI.js @@ -123,6 +123,16 @@ Resources.prototype = { get: function(id, callback) { return extensionServer.sendRequest({ command: "getResources", id: id }, callback); + }, + + getPageTimings: function(callback) + { + return extensionServer.sendRequest({ command: "getPageTimings" }, callback); + }, + + getContent: function(ids, callback) + { + return extensionServer.sendRequest({ command: "getResourceContent", ids: ids }, callback); } } diff --git a/WebCore/inspector/front-end/ExtensionServer.js b/WebCore/inspector/front-end/ExtensionServer.js index bdf3a25..9ab4c0c 100644 --- a/WebCore/inspector/front-end/ExtensionServer.js +++ b/WebCore/inspector/front-end/ExtensionServer.js @@ -38,6 +38,8 @@ WebInspector.ExtensionServer = function() this._registerHandler("subscribe", this._onSubscribe.bind(this)); this._registerHandler("unsubscribe", this._onUnsubscribe.bind(this)); this._registerHandler("getResources", this._onGetResources.bind(this)); + this._registerHandler("getResourceContent", this._onGetResourceContent.bind(this)); + this._registerHandler("getPageTimings", this._onGetPageTimings.bind(this)); this._registerHandler("createPanel", this._onCreatePanel.bind(this)); this._registerHandler("createSidebarPane", this._onCreateSidebar.bind(this)); this._registerHandler("log", this._onLog.bind(this)); @@ -238,7 +240,7 @@ WebInspector.ExtensionServer.prototype = { var id = message.id; var resource = null; - resource = typeof id === "number" ? WebInspector.resources[id] : WebInspector.resourceForURL(id); + resource = WebInspector.resources[id] || WebInspector.resourceForURL(id); if (!resource) return this._status.E_NOTFOUND(typeof id + ": " + id); WebInspector.panels.resources.showResource(resource, message.line); @@ -261,10 +263,53 @@ WebInspector.ExtensionServer.prototype = { if (request.id) response = WebInspector.resources[request.id] ? resourceWrapper(request.id) : this._status.E_NOTFOUND(request.id); else - response = Object.properties(WebInspector.resources).map(resourceWrapper); + response = Object.keys(WebInspector.resources).map(resourceWrapper); return response; }, + _onGetResourceContent: function(message, port) + { + var ids; + var response = []; + + function onContentAvailable(id, encoded, content) + { + var resourceContent = { + id: id, + encoding: encoded ? "base64" : "", + content: content + }; + response.push(resourceContent); + if (response.length === ids.length) + this._dispatchCallback(message.requestId, port, response); + } + + if (typeof message.ids === "number") + ids = [ message.ids ]; + else if (message.ids instanceof Array) + ids = message.ids; + else + return this._status.E_BADARGTYPE("message.ids", "Array", typeof message.ids); + + for (var i = 0; i < ids.length; ++i) { + var id = ids[i]; + var resource = WebInspector.resources[id]; + if (!resource) + response.push(this._status.E_NOTFOUND(id)); + else { + var encode = !WebInspector.Resource.Type.isTextType(resource.type); + WebInspector.getEncodedResourceContent(id, encode, onContentAvailable.bind(this, id, encode)); + } + } + if (response.length === ids.length) + this._dispatchCallback(message.requestId, port, response); + }, + + _onGetPageTimings: function() + { + return (new WebInspector.HARLog()).buildMainResourceTimings(); + }, + _onAddAuditCategory: function(request) { var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.ruleCount); @@ -329,12 +374,13 @@ WebInspector.ExtensionServer.prototype = { if (typeof propValue === "number") resourceTypes[propName] = WebInspector.Resource.Type.toString(propValue); } - + var platformAPI = WebInspector.buildPlatformExtensionAPI ? WebInspector.buildPlatformExtensionAPI() : ""; return "(function(){ " + "var private = {};" + "(" + WebInspector.commonExtensionSymbols.toString() + ")(private);" + "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" + "webInspector.resources.Types = " + JSON.stringify(resourceTypes) + ";" + + platformAPI + "})"; }, @@ -400,3 +446,8 @@ WebInspector.addExtensions = function(extensions) } WebInspector.extensionServer = new WebInspector.ExtensionServer(); + +WebInspector.getEncodedResourceContent = function(identifier, encode, callback) +{ + InspectorBackend.getResourceContent(identifier, encode, callback); +} diff --git a/WebCore/inspector/front-end/HAREntry.js b/WebCore/inspector/front-end/HAREntry.js index 85e4f59..2b8f41b 100644 --- a/WebCore/inspector/front-end/HAREntry.js +++ b/WebCore/inspector/front-end/HAREntry.js @@ -56,7 +56,6 @@ WebInspector.HAREntry.prototype = { method: this._resource.requestMethod, url: this._resource.url, // httpVersion: "HTTP/1.1" -- Not available. - // cookies: [] -- Not available. headers: this._buildHeaders(this._resource.requestHeaders), headersSize: -1, // Not available. bodySize: -1 // Not available. @@ -65,22 +64,26 @@ WebInspector.HAREntry.prototype = { res.queryString = this._buildParameters(this._resource.queryParameters); if (this._resource.requestFormData) res.postData = this._buildPostData(); + if (this._resource.requestCookies) + res.cookies = this._buildCookies(this._resource.requestCookies); return res; }, _buildResponse: function() { - return { + var res = { status: this._resource.statusCode, statusText: this._resource.statusText, // "httpVersion": "HTTP/1.1" -- Not available. - // "cookies": [], -- Not available. headers: this._buildHeaders(this._resource.responseHeaders), content: this._buildContent(), redirectURL: this._resource.responseHeaderValue("Location") || "", headersSize: -1, // Not available. bodySize: this._resource.resourceSize }; + if (this._resource.responseCookies) + res.cookies = this._buildCookies(this._resource.responseCookies); + return res; }, _buildContent: function() @@ -150,6 +153,25 @@ WebInspector.HAREntry.prototype = { return parameters.slice(); }, + _buildCookies: function(cookies) + { + return cookies.map(this._buildCookie.bind(this)); + }, + + _buildCookie: function(cookie) + { + + return { + name: cookie.name, + value: cookie.value, + path: cookie.path, + domain: cookie.domain, + expires: cookie.expires(new Date(this._resource.startTime * 1000)), + httpOnly: cookie.httpOnly, + secure: cookie.secure + }; + }, + _interval: function(start, end) { var timing = this._resource.timing; @@ -181,7 +203,7 @@ WebInspector.HARLog.prototype = { version: webKitVersion ? webKitVersion[1] : "n/a" }, pages: this._buildPages(), - entries: Object.properties(WebInspector.resources).map(this._convertResource) + entries: Object.keys(WebInspector.resources).map(this._convertResource) } }, @@ -192,23 +214,31 @@ WebInspector.HARLog.prototype = { startedDateTime: new Date(WebInspector.mainResource.startTime * 1000), id: WebInspector.mainResource.documentURL, title: "", - pageTimings: this._buildMainResourceTimings() + pageTimings: this.buildMainResourceTimings() } ]; }, - _buildMainResourceTimings: function() + buildMainResourceTimings: function() { var resourcesPanel = WebInspector.panels.resources; var startTime = WebInspector.mainResource.startTime; return { - onContentLoad: WebInspector.HAREntry._toMilliseconds(resourcesPanel.mainResourceDOMContentTime - startTime), - onLoad: WebInspector.HAREntry._toMilliseconds(resourcesPanel.mainResourceLoadTime - startTime), + onContentLoad: this._pageEventTime(resourcesPanel.mainResourceDOMContentTime), + onLoad: this._pageEventTime(resourcesPanel.mainResourceLoadTime), } }, _convertResource: function(id) { return (new WebInspector.HAREntry(WebInspector.resources[id])).build(); + }, + + _pageEventTime: function(time) + { + var startTime = WebInspector.mainResource.startTime; + if (time === -1 || startTime === -1) + return -1; + return WebInspector.HAREntry._toMilliseconds(time - startTime); } }; diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js index 5544ed5..24b270b 100644 --- a/WebCore/inspector/front-end/InjectedScript.js +++ b/WebCore/inspector/front-end/InjectedScript.js @@ -220,7 +220,7 @@ InjectedScript.prototype = { if (!callFrame) return props; if (expression) - expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression); + expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true); else { // Evaluate into properties in scope of the selected call frame. var scopeChain = callFrame.scopeChain; @@ -230,7 +230,7 @@ InjectedScript.prototype = { } else { if (!expression) expression = "this"; - expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression); + expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); } if (typeof expressionResult === "object") this._populatePropertyNames(expressionResult, props); @@ -246,26 +246,29 @@ InjectedScript.prototype = { evaluate: function(expression, objectGroup) { - return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup); + return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup, false); }, - _evaluateAndWrap: function(evalFunction, object, expression, objectGroup) + _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame) { try { - return this._wrapObject(this._evaluateOn(evalFunction, object, expression), objectGroup); + return this._wrapObject(this._evaluateOn(evalFunction, object, expression, isEvalOnCallFrame), objectGroup); } catch (e) { return InjectedScript.RemoteObject.fromException(e); } }, - _evaluateOn: function(evalFunction, object, expression) + _evaluateOn: function(evalFunction, object, expression, isEvalOnCallFrame) { // Only install command line api object for the time of evaluation. // Surround the expression in with statements to inject our command line API so that // the window object properties still take more precedent than our API functions. inspectedWindow.console._commandLineAPI = this._commandLineAPI; - expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }"; + // We don't want local variables to be shadowed by global ones when evaluating on CallFrame. + if (!isEvalOnCallFrame) + expression = "with (window) {\n" + expression + "\n} "; + expression = "with (window.console._commandLineAPI) {\n" + expression + "\n}"; var value = evalFunction.call(object, expression); delete inspectedWindow.console._commandLineAPI; @@ -303,7 +306,7 @@ InjectedScript.prototype = { var callFrame = this._callFrameForId(callFrameId); if (!callFrame) return false; - return this._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup); + return this._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true); }, _callFrameForId: function(id) diff --git a/WebCore/inspector/front-end/NetworkPanel.js b/WebCore/inspector/front-end/NetworkPanel.js index f07b3b0..8eed425 100644 --- a/WebCore/inspector/front-end/NetworkPanel.js +++ b/WebCore/inspector/front-end/NetworkPanel.js @@ -32,25 +32,41 @@ WebInspector.NetworkPanel = function() { WebInspector.Panel.call(this, "network"); + this.createSidebar(); + this.sidebarElement.className = "network-sidebar"; + this._resources = []; this._staleResources = []; this._resourceGridNodes = {}; this._mainResourceLoadTime = -1; this._mainResourceDOMContentTime = -1; + this._hiddenCategories = {}; + + this._categories = WebInspector.resourceCategories; + + this.containerElement = document.createElement("div"); + this.containerElement.id = "network-container"; + this.sidebarElement.appendChild(this.containerElement); this._viewsContainerElement = document.createElement("div"); this._viewsContainerElement.id = "network-views"; + this._viewsContainerElement.className = "hidden"; + this.element.appendChild(this._viewsContainerElement); this._createSortingFunctions(); - this._createTimelineGrid(); this._createTable(); + this._createTimelineGrid(); this._createStatusbarButtons(); + this._createFilterStatusBarItems(); + this._createSummaryBar(); this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), true); this.calculator = new WebInspector.NetworkTransferTimeCalculator(); - this.filter(this.filterAllElement, false); + this._filter(this._filterAllElement, false); + + this._toggleGridMode(); } WebInspector.NetworkPanel.prototype = { @@ -61,7 +77,7 @@ WebInspector.NetworkPanel.prototype = { get statusBarItems() { - return [this._largerResourcesButton.element, this._clearButton.element]; + return [this._largerResourcesButton.element, this._clearButton.element, this._filterBarElement]; }, isCategoryVisible: function(categoryName) @@ -78,32 +94,87 @@ WebInspector.NetworkPanel.prototype = { { WebInspector.Panel.prototype.resize.call(this); this._dataGrid.updateWidths(); + this._positionSummaryBar(); + }, + + updateSidebarWidth: function() + { + if (!this._viewingResourceMode) + return; + WebInspector.Panel.prototype.updateSidebarWidth.apply(this, arguments); + }, + + updateMainViewWidth: function(width) + { + this._viewsContainerElement.style.left = width + "px"; + }, + + handleShortcut: function(event) + { + if (this._viewingResourceMode && event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) { + this._toggleGridMode(); + event.handled = true; + } + }, + + _positionSummaryBar: function() + { + // Position the total bar. + const rowHeight = 22; + const summaryBarHeight = 22; + var offsetHeight = this.element.offsetHeight; + + var parentElement = this._summaryBarElement.parentElement; + + if (this._summaryBarElement.parentElement !== this.element && offsetHeight > (this._dataGrid.children.length - 1) * rowHeight + summaryBarHeight) { + // Glue status to bottom. + if (this._summaryBarRowNode) { + this._dataGrid.removeChild(this._summaryBarRowNode); + delete this._summaryBarRowNode; + } + this._summaryBarElement.addStyleClass("network-summary-bar-bottom"); + this.element.appendChild(this._summaryBarElement); + this._dataGrid.element.style.bottom = "20px"; + return; + } + + if (!this._summaryBarRowNode && offsetHeight - summaryBarHeight < this._dataGrid.children.length * rowHeight) { + // Glue status to table. + this._summaryBarRowNode = new WebInspector.NetworkTotalGridNode(this._summaryBarElement); + this._summaryBarElement.removeStyleClass("network-summary-bar-bottom"); + this._dataGrid.appendChild(this._summaryBarRowNode); + this._dataGrid.element.style.bottom = 0; + this._sortItems(); + } + }, + + _resetSummaryBar: function() + { + delete this._summaryBarRowNode; + this._summaryBarElement.parentElement.removeChild(this._summaryBarElement); + this._updateSummaryBar(); }, _createTimelineGrid: function() { this._timelineGrid = new WebInspector.TimelineGrid(); this._timelineGrid.element.addStyleClass("network-timeline-grid"); - this.element.appendChild(this._timelineGrid.element); + this._dataGrid.element.appendChild(this._timelineGrid.element); }, _createTable: function() { - this.containerElement = document.createElement("div"); - this.containerElement.id = "network-container"; - this.element.appendChild(this.containerElement); + var columns = {name: {}, method: {}, status: {}, type: {}, size: {}, time: {}, timeline: {}}; + columns.name.titleDOMFragment = this._makeHeaderFragment(WebInspector.UIString("Name"), WebInspector.UIString("Path")); + columns.name.sortable = true; + columns.name.width = "20%"; + columns.name.disclosure = true; - var columns = {url: {}, method: {}, status: {}, type: {}, size: {}, time: {}, timeline: {}}; - columns.url.title = WebInspector.UIString("URL"); - columns.url.sortable = true; - columns.url.width = "20%"; - columns.url.disclosure = true; - columns.method.title = WebInspector.UIString("Method"); columns.method.sortable = true; columns.method.width = "7%"; - columns.status.title = WebInspector.UIString("Status"); + columns.status.titleDOMFragment = this._makeHeaderFragment(WebInspector.UIString("Status"), WebInspector.UIString("Text")); columns.status.sortable = true; columns.status.width = "8%"; @@ -111,41 +182,233 @@ WebInspector.NetworkPanel.prototype = { columns.type.sortable = true; columns.type.width = "7%"; - columns.size.title = WebInspector.UIString("Size"); + columns.size.titleDOMFragment = this._makeHeaderFragment(WebInspector.UIString("Size"), WebInspector.UIString("Transfer")); columns.size.sortable = true; columns.size.width = "10%"; columns.size.aligned = "right"; - columns.time.title = WebInspector.UIString("Time"); + columns.time.titleDOMFragment = this._makeHeaderFragment(WebInspector.UIString("Time"), WebInspector.UIString("Duration")); columns.time.sortable = true; columns.time.width = "10%"; columns.time.aligned = "right"; columns.timeline.title = ""; - columns.timeline.sortable = true; + columns.timeline.sortable = false; columns.timeline.width = "40%"; - columns.timeline.sort = true; + columns.timeline.sort = "ascending"; this._dataGrid = new WebInspector.DataGrid(columns); - this.element.appendChild(this._dataGrid.element); + this.containerElement.appendChild(this._dataGrid.element); this._dataGrid.addEventListener("sorting changed", this._sortItems, this); this._dataGrid.addEventListener("width changed", this._updateDividersIfNeeded, this); + + this._patchTimelineHeader(); + }, + + _makeHeaderFragment: function(title, subtitle) + { + var fragment = document.createDocumentFragment(); + fragment.appendChild(document.createTextNode(title)); + var subtitleDiv = document.createElement("div"); + subtitleDiv.className = "network-header-subtitle"; + subtitleDiv.textContent = subtitle; + fragment.appendChild(subtitleDiv); + return fragment; + }, + + _patchTimelineHeader: function() + { + var timelineSorting = document.createElement("select"); + + var option = document.createElement("option"); + option.value = "startTime"; + option.label = WebInspector.UIString("Timeline"); + timelineSorting.appendChild(option); + + option = document.createElement("option"); + option.value = "startTime"; + option.label = WebInspector.UIString("Start Time"); + timelineSorting.appendChild(option); + + option = document.createElement("option"); + option.value = "responseTime"; + option.label = WebInspector.UIString("Response Time"); + timelineSorting.appendChild(option); + + option = document.createElement("option"); + option.value = "endTime"; + option.label = WebInspector.UIString("End Time"); + timelineSorting.appendChild(option); + + option = document.createElement("option"); + option.value = "duration"; + option.label = WebInspector.UIString("Duration"); + timelineSorting.appendChild(option); + + option = document.createElement("option"); + option.value = "latency"; + option.label = WebInspector.UIString("Latency"); + timelineSorting.appendChild(option); + + var header = this._dataGrid.headerTableHeader("timeline"); + header.firstChild.appendChild(timelineSorting); + + timelineSorting.addEventListener("click", function(event) { event.stopPropagation() }, false); + timelineSorting.addEventListener("change", this._sortByTimeline.bind(this), false); + this._timelineSortSelector = timelineSorting; }, _createSortingFunctions: function() { this._sortingFunctions = {}; - this._sortingFunctions.url = WebInspector.NetworkDataGridNode.URLComparator; - this._sortingFunctions.method = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "method"); - this._sortingFunctions.status = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "statusCode"); - this._sortingFunctions.type = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "mimeType"); - this._sortingFunctions.size = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "resourceSize"); - this._sortingFunctions.time = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "duration"); - this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "startTime"); + this._sortingFunctions.name = WebInspector.NetworkDataGridNode.NameComparator; + this._sortingFunctions.method = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "method", false); + this._sortingFunctions.status = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "statusCode", false); + this._sortingFunctions.type = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "mimeType", false); + this._sortingFunctions.size = WebInspector.NetworkDataGridNode.SizeComparator; + this._sortingFunctions.time = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "duration", false); + this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "startTime", false); + this._sortingFunctions.startTime = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "startTime", false); + this._sortingFunctions.endTime = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "endTime", false); + this._sortingFunctions.responseTime = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "responseReceivedTime", false); + this._sortingFunctions.duration = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "duration", true); + this._sortingFunctions.latency = WebInspector.NetworkDataGridNode.ResourcePropertyComparator.bind(null, "latency", true); + + var timeCalculator = new WebInspector.NetworkTransferTimeCalculator(); + var durationCalculator = new WebInspector.NetworkTransferDurationCalculator(); + + this._calculators = {}; + this._calculators.timeline = timeCalculator; + this._calculators.startTime = timeCalculator; + this._calculators.endTime = timeCalculator; + this._calculators.responseTime = timeCalculator; + this._calculators.duration = durationCalculator; + this._calculators.latency = durationCalculator; }, - filter: function(target, selectMultiple) + _sortItems: function() { + var columnIdentifier = this._dataGrid.sortColumnIdentifier; + if (columnIdentifier === "timeline") { + this._sortByTimeline(); + return; + } + var sortingFunction = this._sortingFunctions[columnIdentifier]; + if (!sortingFunction) + return; + + this._dataGrid.sortNodes(sortingFunction, this._dataGrid.sortOrder === "descending"); + this._timelineSortSelector.selectedIndex = 0; + }, + + _sortByTimeline: function() + { + var selectedIndex = this._timelineSortSelector.selectedIndex; + if (!selectedIndex) + selectedIndex = 1; // Sort by start time by default. + var selectedOption = this._timelineSortSelector[selectedIndex]; + var value = selectedOption.value; + + var sortingFunction = this._sortingFunctions[value]; + this._dataGrid.sortNodes(sortingFunction); + this.calculator = this._calculators[value]; + if (this.calculator.startAtZero) + this._timelineGrid.hideEventDividers(); + else + this._timelineGrid.showEventDividers(); + this._dataGrid.markColumnAsSortedBy("timeline", "ascending"); + }, + + _createFilterStatusBarItems: function() + { + var filterBarElement = document.createElement("div"); + filterBarElement.className = "scope-bar status-bar-item"; + filterBarElement.id = "network-filter"; + + function createFilterElement(category, label) + { + var categoryElement = document.createElement("li"); + categoryElement.category = category; + categoryElement.className = category; + categoryElement.appendChild(document.createTextNode(label)); + categoryElement.addEventListener("click", this._updateFilter.bind(this), false); + filterBarElement.appendChild(categoryElement); + + return categoryElement; + } + + this._filterAllElement = createFilterElement.call(this, "all", WebInspector.UIString("All")); + + // Add a divider + var dividerElement = document.createElement("div"); + dividerElement.addStyleClass("scope-bar-divider"); + filterBarElement.appendChild(dividerElement); + + for (var category in this._categories) + createFilterElement.call(this, category, this._categories[category].title); + this._filterBarElement = filterBarElement; + }, + + _createSummaryBar: function() + { + this._summaryBarElement = document.createElement("div"); + this._summaryBarElement.className = "network-summary-bar"; + this.containerElement.appendChild(this._summaryBarElement); + }, + + _updateSummaryBar: function() + { + this._positionSummaryBar(); // Grid is growing. + var numRequests = this._resources.length; + + if (!numRequests) { + if (this._summaryBarElement._isDisplayingWarning) + return; + this._summaryBarElement._isDisplayingWarning = true; + + var img = document.createElement("img"); + img.src = "Images/warningIcon.png"; + this._summaryBarElement.removeChildren(); + this._summaryBarElement.appendChild(img); + this._summaryBarElement.appendChild(document.createTextNode(" ")); + this._summaryBarElement.appendChild(document.createTextNode( + WebInspector.UIString("No requests captured. Reload the page to see detailed information on the network activity."))); + return; + } + delete this._summaryBarElement._isDisplayingWarning; + + var transferSize = 0; + var baseTime = -1; + var maxTime = -1; + for (var i = 0; i < this._resources.length; ++i) { + var resource = this._resources[i]; + transferSize += resource.cached ? 0 : resource.transferSize; + if (resource.isMainResource) + baseTime = resource.startTime; + if (resource.endTime > maxTime) + maxTime = resource.endTime; + } + var text = String.sprintf(WebInspector.UIString("%d requests"), numRequests); + text += " \u2758 " + String.sprintf(WebInspector.UIString("%s transferred"), Number.bytesToString(transferSize)); + if (baseTime !== -1 && this._mainResourceLoadTime !== -1 && this._mainResourceDOMContentTime !== -1 && this._mainResourceDOMContentTime > baseTime) { + text += " \u2758 " + String.sprintf(WebInspector.UIString("%s (onload: %s, DOMContentLoaded: %s)"), + Number.secondsToString(maxTime - baseTime), + Number.secondsToString(this._mainResourceLoadTime - baseTime), + Number.secondsToString(this._mainResourceDOMContentTime - baseTime)); + } + this._summaryBarElement.textContent = text; + }, + + _showCategory: function(category) + { + this._dataGrid.element.addStyleClass("filter-" + category); + delete this._hiddenCategories[category]; + }, + + _hideCategory: function(category) + { + this._dataGrid.element.removeStyleClass("filter-" + category); + this._hiddenCategories[category] = true; }, _updateFilter: function(e) @@ -157,16 +420,65 @@ WebInspector.NetworkPanel.prototype = { if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey) selectMultiple = true; - this.filter(e.target, selectMultiple); - - // When we are updating our filtering, scroll to the top so we don't end up - // in blank graph under all the resources. - this.containerElement.scrollTop = 0; + this._filter(e.target, selectMultiple); var searchField = document.getElementById("search"); WebInspector.doPerformSearch(searchField.value, WebInspector.shortSearchWasForcedByKeyEvent, false, true); }, + _filter: function(target, selectMultiple) + { + function unselectAll() + { + for (var i = 0; i < this._filterBarElement.childNodes.length; ++i) { + var child = this._filterBarElement.childNodes[i]; + if (!child.category) + continue; + + child.removeStyleClass("selected"); + this._hideCategory(child.category); + } + } + + if (target.category === this._filterAllElement) { + if (target.hasStyleClass("selected")) { + // We can't unselect All, so we break early here + return; + } + + // If All wasn't selected, and now is, unselect everything else. + unselectAll.call(this); + } else { + // Something other than All is being selected, so we want to unselect All. + if (this._filterAllElement.hasStyleClass("selected")) { + this._filterAllElement.removeStyleClass("selected"); + this._hideCategory("all"); + } + } + + if (!selectMultiple) { + // If multiple selection is off, we want to unselect everything else + // and just select ourselves. + unselectAll.call(this); + + target.addStyleClass("selected"); + this._showCategory(target.category); + return; + } + + if (target.hasStyleClass("selected")) { + // If selectMultiple is turned on, and we were selected, we just + // want to unselect ourselves. + target.removeStyleClass("selected"); + this._hideCategory(target.category); + } else { + // If selectMultiple is turned on, and we weren't selected, we just + // want to select ourselves. + target.addStyleClass("selected"); + this._showCategory(target.category); + } + }, + _scheduleRefresh: function() { if (this._needsRefresh) @@ -178,18 +490,16 @@ WebInspector.NetworkPanel.prototype = { this._refreshTimeout = setTimeout(this.refresh.bind(this), 500); }, - _sortItems: function() - { - var columnIdentifier = this._dataGrid.sortColumnIdentifier; - var sortingFunction = this._sortingFunctions[columnIdentifier]; - if (!sortingFunction) - return; - this._dataGrid.sortNodes(sortingFunction, this._dataGrid.sortOrder === "descending"); - }, - _updateDividersIfNeeded: function(force) { - this._timelineGrid.element.style.left = this._dataGrid.resizers[this._dataGrid.resizers.length - 1].style.left; + var timelineColumn = this._dataGrid.columns.timeline; + for (var i = 0; i < this._dataGrid.resizers.length; ++i) { + if (timelineColumn.ordinal === this._dataGrid.resizers[i].rightNeighboringColumnID) { + // Position timline grid location. + this._timelineGrid.element.style.left = this._dataGrid.resizers[i].style.left; + this._timelineGrid.element.style.right = "18px"; + } + } var proceed = true; if (!this.visible) { @@ -296,7 +606,7 @@ WebInspector.NetworkPanel.prototype = { _createStatusbarButtons: function() { this._clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item"); - this._clearButton.addEventListener("click", this.reset.bind(this), false); + this._clearButton.addEventListener("click", this._reset.bind(this), false); this._largerResourcesButton = new WebInspector.StatusBarButton(WebInspector.UIString("Use small resource rows."), "network-larger-resources-status-bar-item"); WebInspector.applicationSettings.addEventListener("loaded", this._settingsLoaded, this); @@ -354,27 +664,18 @@ WebInspector.NetworkPanel.prototype = { view.visible = false; } this._dataGrid.updateWidths(); + this._positionSummaryBar(); + }, + + hide: function() + { + WebInspector.Panel.prototype.hide.call(this); + this._popoverHelper.hidePopup(); }, get searchableViews() { var views = []; - - const visibleView = this.visibleView; - if (visibleView && visibleView.performSearch) - views.push(visibleView); - - var resourcesLength = this._resources.length; - for (var i = 0; i < resourcesLength; ++i) { - var resource = this._resources[i]; - if (!this._resourceGridNode(resource) || !this._resourceGridNode(resource).selectable) - continue; - var resourceView = this.resourceViewForResource(resource); - if (!resourceView.performSearch || resourceView === visibleView) - continue; - views.push(resourceView); - } - return views; }, @@ -420,7 +721,7 @@ WebInspector.NetworkPanel.prototype = { var node = this._resourceGridNode(resource); if (!node) { // Create the timeline tree element and graph. - node = new WebInspector.NetworkDataGridNode(resource); + node = new WebInspector.NetworkDataGridNode(this, resource); this._resourceGridNodes[resource.identifier] = node; this._dataGrid.appendChild(node); } @@ -441,54 +742,35 @@ WebInspector.NetworkPanel.prototype = { this._staleResources = []; this._sortItems(); + this._updateSummaryBar(); this._dataGrid.updateWidths(); }, - reset: function() + _reset: function() { this._popoverHelper.hidePopup(); - this.closeVisibleResource(); + this._closeVisibleResource(); - delete this.currentQuery; - this.searchCanceled(); - - if (this._resources) { - var resourcesLength = this._resources.length; - for (var i = 0; i < resourcesLength; ++i) { - var resource = this._resources[i]; - - resource.warnings = 0; - resource.errors = 0; - - delete resource._resourcesView; - } - } + this._toggleGridMode(); // Begin reset timeline - this.containerElement.scrollTop = 0; - if (this._calculator) this._calculator.reset(); - if (this._resources) { - var itemsLength = this._resources.length; - for (var i = 0; i < itemsLength; ++i) { - var item = this._resources[i]; - } - } - this._resources = []; this._staleResources = []; this._resourceGridNodes = {}; this._dataGrid.removeChildren(); + delete this._summaryBarRowNode; this._updateDividersIfNeeded(true); // End reset timeline. - + this._mainResourceLoadTime = -1; this._mainResourceDOMContentTime = -1; this._viewsContainerElement.removeChildren(); + this._resetSummaryBar(); }, addResource: function(resource) @@ -501,20 +783,17 @@ WebInspector.NetworkPanel.prototype = { { this._staleResources.push(resource); this._scheduleRefresh(); - }, - recreateViewForResourceIfNeeded: function(resource) - { if (!resource || !resource._resourcesView) return; + if (this._resourceViewTypeMatchesResource(resource, resource._resourcesView)) + return; + var newView = this._createResourceView(resource); if (newView.__proto__ === resource._resourcesView.__proto__) return; - if (!this.currentQuery && this._resourceGridNode(resource)) - this._resourceGridNode(resource).updateErrorsAndWarnings(); - var oldView = resource._resourcesView; var oldViewParentNode = oldView.visible ? oldView.element.parentNode : null; @@ -533,27 +812,26 @@ WebInspector.NetworkPanel.prototype = { canShowSourceLine: function(url, line) { - return this._resourceTrackingEnabled && !!WebInspector.resourceForURL(url); + return false; }, showSourceLine: function(url, line) { - this.showResource(WebInspector.resourceForURL(url), line); }, - showResource: function(resource, line) + _showResource: function(resource, line) { if (!resource) return; this._popoverHelper.hidePopup(); - this.containerElement.addStyleClass("viewing-resource"); + this._toggleViewingResourceMode(); if (this.visibleResource && this.visibleResource._resourcesView) this.visibleResource._resourcesView.hide(); - var view = this.resourceViewForResource(resource); + var view = this._resourceViewForResource(resource); view.headersVisible = true; view.show(this._viewsContainerElement); @@ -565,23 +843,13 @@ WebInspector.NetworkPanel.prototype = { view.highlightLine(line); } - this.revealAndSelectItem(resource); - this.visibleResource = resource; - this.updateSidebarWidth(); }, - showView: function(view) - { - if (!view) - return; - this.showResource(view.resource); - }, - - closeVisibleResource: function() + _closeVisibleResource: function() { - this.containerElement.removeStyleClass("viewing-resource"); + this.element.removeStyleClass("viewing-resource"); if (this.visibleResource && this.visibleResource._resourcesView) this.visibleResource._resourcesView.hide(); @@ -593,7 +861,7 @@ WebInspector.NetworkPanel.prototype = { this.updateSidebarWidth(); }, - resourceViewForResource: function(resource) + _resourceViewForResource: function(resource) { if (!resource) return null; @@ -602,23 +870,6 @@ WebInspector.NetworkPanel.prototype = { return resource._resourcesView; }, - sourceFrameForResource: function(resource) - { - var view = this.resourceViewForResource(resource); - if (!view) - return null; - - if (!view.setupSourceFrameIfNeeded) - return null; - - // Setting up the source frame requires that we be attached. - if (!this.element.parentNode) - this.attach(); - - view.setupSourceFrameIfNeeded(); - return view.sourceFrame; - }, - _toggleLargerResources: function() { WebInspector.applicationSettings.resourcesLargeRows = !WebInspector.applicationSettings.resourcesLargeRows; @@ -631,9 +882,11 @@ WebInspector.NetworkPanel.prototype = { if (!enabled) { this._largerResourcesButton.title = WebInspector.UIString("Use large resource rows."); this._dataGrid.element.addStyleClass("small"); + this._timelineGrid.element.addStyleClass("small"); } else { this._largerResourcesButton.title = WebInspector.UIString("Use small resource rows."); this._dataGrid.element.removeStyleClass("small"); + this._timelineGrid.element.removeStyleClass("small"); } }, @@ -654,6 +907,24 @@ WebInspector.NetworkPanel.prototype = { } }, + _resourceViewTypeMatchesResource: function(resource, resourceView) + { + switch (resource.category) { + case WebInspector.resourceCategories.documents: + case WebInspector.resourceCategories.stylesheets: + case WebInspector.resourceCategories.scripts: + case WebInspector.resourceCategories.xhr: + return resourceView instanceof WebInspector.SourceView; + case WebInspector.resourceCategories.images: + return resourceView instanceof WebInspector.ImageView; + case WebInspector.resourceCategories.fonts: + return resourceView instanceof WebInspector.FontView; + default: + return resourceView instanceof WebInspector.ResourceView; + } + return false; + }, + _getPopoverAnchor: function(element) { var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label"); @@ -751,20 +1022,85 @@ WebInspector.NetworkPanel.prototype = { return popover; }, - hide: function() + _toggleGridMode: function() { - WebInspector.Panel.prototype.hide.call(this); - this._popoverHelper.hidePopup(); + if (this._viewingResourceMode) { + this._viewingResourceMode = false; + this.element.removeStyleClass("viewing-resource"); + this._dataGrid.element.removeStyleClass("viewing-resource-mode"); + this._viewsContainerElement.addStyleClass("hidden"); + this.sidebarElement.style.right = 0; + this.sidebarElement.style.removeProperty("width"); + } + + if (this._briefGrid) { + this._dataGrid.element.removeStyleClass("full-grid-mode"); + this._dataGrid.element.addStyleClass("brief-grid-mode"); + + this._dataGrid.hideColumn("method"); + this._dataGrid.hideColumn("status"); + this._dataGrid.hideColumn("type"); + this._dataGrid.hideColumn("size"); + this._dataGrid.hideColumn("time"); + + var widths = {}; + widths.name = 20; + widths.timeline = 80; + } else { + this._dataGrid.element.addStyleClass("full-grid-mode"); + this._dataGrid.element.removeStyleClass("brief-grid-mode"); + + this._dataGrid.showColumn("method"); + this._dataGrid.showColumn("status"); + this._dataGrid.showColumn("type"); + this._dataGrid.showColumn("size"); + this._dataGrid.showColumn("time"); + + var widths = {}; + widths.name = 20; + widths.method = 7; + widths.status = 8; + widths.type = 7; + widths.size = 10; + widths.time = 10; + widths.timeline = 40; + } + + this._dataGrid.showColumn("timeline"); + this._dataGrid.applyColumnWidthsMap(widths); + + }, + + _toggleViewingResourceMode: function() + { + if (this._viewingResourceMode) + return; + this._viewingResourceMode = true; + this._preservedColumnWidths = this._dataGrid.columnWidthsMap(); + + this.element.addStyleClass("viewing-resource"); + this._dataGrid.element.addStyleClass("viewing-resource-mode"); + this._dataGrid.element.removeStyleClass("full-grid-mode"); + this._dataGrid.element.removeStyleClass("brief-grid-mode"); + + this._dataGrid.hideColumn("method"); + this._dataGrid.hideColumn("status"); + this._dataGrid.hideColumn("type"); + this._dataGrid.hideColumn("size"); + this._dataGrid.hideColumn("time"); + this._dataGrid.hideColumn("timeline"); + + this._viewsContainerElement.removeStyleClass("hidden"); + this.updateSidebarWidth(200); + + var widths = {}; + widths.name = 100; + this._dataGrid.applyColumnWidthsMap(widths); } } WebInspector.NetworkPanel.prototype.__proto__ = WebInspector.Panel.prototype; -WebInspector.getResourceContent = function(identifier, callback) -{ - InspectorBackend.getResourceContent(identifier, callback); -} - WebInspector.NetworkBaseCalculator = function() { } @@ -1047,86 +1383,50 @@ WebInspector.NetworkTransferDurationCalculator.prototype = { WebInspector.NetworkTransferDurationCalculator.prototype.__proto__ = WebInspector.NetworkTimeCalculator.prototype; -WebInspector.NetworkTransferSizeCalculator = function() +WebInspector.NetworkDataGridNode = function(panel, resource) { - WebInspector.NetworkBaseCalculator.call(this); + WebInspector.DataGridNode.call(this, {}); + this._panel = panel; + this._resource = resource; } -WebInspector.NetworkTransferSizeCalculator.prototype = { - computeBarGraphLabels: function(resource) - { - var networkBytes = this._networkBytes(resource); - var resourceBytes = this._value(resource); - if (networkBytes && networkBytes !== resourceBytes) { - // Transferred size is not the same as reported resource length. - var networkBytesString = this.formatValue(networkBytes); - var left = networkBytesString; - var right = this.formatValue(resourceBytes); - var tooltip = right ? WebInspector.UIString("%s (%s transferred)", right, networkBytesString) : right; - } else { - var left = this.formatValue(resourceBytes); - var right = left; - var tooltip = left; - } - if (resource.cached) - tooltip = WebInspector.UIString("%s (from cache)", tooltip); - return {left: left, right: right, tooltip: tooltip}; - }, - - computeBarGraphPercentages: function(item) +WebInspector.NetworkDataGridNode.prototype = { + createCells: function() { - const resourceBytesAsPercent = (this._value(item) / this.boundarySpan) * 100; - const networkBytesAsPercent = this._networkBytes(item) ? (this._networkBytes(item) / this.boundarySpan) * 100 : resourceBytesAsPercent; - return {start: 0, middle: networkBytesAsPercent, end: resourceBytesAsPercent}; + this._nameCell = this._createDivInTD("name"); + this._methodCell = this._createDivInTD("method"); + this._statusCell = this._createDivInTD("status"); + this._typeCell = this._createDivInTD("type"); + this._sizeCell = this._createDivInTD("size"); + this._timeCell = this._createDivInTD("time"); + this._createTimelineCell(); }, - _value: function(resource) + select: function() { - return resource.resourceSize; + WebInspector.DataGridNode.prototype.select.apply(this, arguments); + this._panel._showResource(this._resource); }, - _networkBytes: function(resource) + get selectable() { - return resource.transferSize; + if (!this._panel._hiddenCategories.all) + return true; + if (this._panel._hiddenCategories[this._resource.category.name]) + return false; + return true; }, - formatValue: function(value) - { - return Number.bytesToString(value, WebInspector.UIString); - } -} - -WebInspector.NetworkTransferSizeCalculator.prototype.__proto__ = WebInspector.NetworkBaseCalculator.prototype; - -WebInspector.NetworkDataGridNode = function(resource) -{ - WebInspector.DataGridNode.call(this, {}); - this._resource = resource; -} - -WebInspector.NetworkDataGridNode.prototype = { - createCells: function() + _createDivInTD: function(columnIdentifier) { - this._urlCell = this._createDivInTD("url-column"); - this._methodCell = this._createDivInTD("optional-column"); - this._statusCell = this._createDivInTD("optional-column"); - this._typeCell = this._createDivInTD("optional-column"); - this._sizeCell = this._createDivInTD("optional-column right"); - this._timeCell = this._createDivInTD("optional-column right"); - this._createTimelineCell(); - }, - - _createDivInTD: function(className) { var td = document.createElement("td"); - if (className) - td.className = className; + td.className = columnIdentifier + "-column"; var div = document.createElement("div"); td.appendChild(div); this._element.appendChild(td); return div; }, - _createTimelineCell: function() { this._graphElement = document.createElement("div"); @@ -1156,13 +1456,14 @@ WebInspector.NetworkDataGridNode.prototype = { this._barAreaElement.appendChild(this._labelRightElement); this._timelineCell = document.createElement("td"); + this._timelineCell.className = "timeline-column"; this._element.appendChild(this._timelineCell); this._timelineCell.appendChild(this._graphElement); }, refreshResource: function() { - this._refreshURLCell(); + this._refreshNameCell(); this._methodCell.textContent = this._resource.requestMethod; @@ -1188,9 +1489,9 @@ WebInspector.NetworkDataGridNode.prototype = { } }, - _refreshURLCell: function() + _refreshNameCell: function() { - this._urlCell.removeChildren(); + this._nameCell.removeChildren(); if (this._resource.category === WebInspector.resourceCategories.images) { var previewImage = document.createElement("img"); @@ -1204,8 +1505,8 @@ WebInspector.NetworkDataGridNode.prototype = { var iconElement = document.createElement("img"); iconElement.className = "icon"; } - this._urlCell.appendChild(iconElement); - this._urlCell.appendChild(document.createTextNode(this._fileName())); + this._nameCell.appendChild(iconElement); + this._nameCell.appendChild(document.createTextNode(this._fileName())); var subtitle = this._resource.displayDomain; @@ -1216,13 +1517,8 @@ WebInspector.NetworkDataGridNode.prototype = { subtitle += this._resource.path.substring(0, lastPathComponentIndex); } - var subtitleElement = document.createElement("div"); - subtitleElement.className = "network-grid-subtitle"; - subtitleElement.textContent = subtitle; - this._urlCell.appendChild(subtitleElement); - - - this._urlCell.title = this._resource.url; + this._appendSubtitle(this._nameCell, subtitle); + this._nameCell.title = this._resource.url; }, _fileName: function() @@ -1238,16 +1534,6 @@ WebInspector.NetworkDataGridNode.prototype = { this._statusCell.removeChildren(); if (this._resource.statusCode) { - var img = document.createElement("img"); - if (this._resource.statusCode < 300) - img.src = "Images/successGreenDot.png"; - else if (this._resource.statusCode < 400) - img.src = "Images/warningOrangeDot.png"; - else - img.src = "Images/errorRedDot.png"; - - img.className = "resource-status-image"; - this._statusCell.appendChild(img); this._statusCell.appendChild(document.createTextNode(this._resource.statusCode)); this._statusCell.removeStyleClass("network-dim-cell"); this._appendSubtitle(this._statusCell, this._resource.statusText); @@ -1287,7 +1573,7 @@ WebInspector.NetworkDataGridNode.prototype = { _appendSubtitle: function(cellElement, subtitleText) { var subtitleElement = document.createElement("div"); - subtitleElement.className = "network-grid-subtitle"; + subtitleElement.className = "network-cell-subtitle"; subtitleElement.textContent = subtitleText; cellElement.appendChild(subtitleElement); }, @@ -1324,6 +1610,8 @@ WebInspector.NetworkDataGridNode.prototype = { _refreshLabelPositions: function() { + if (!this._percentages) + return; this._labelLeftElement.style.removeProperty("left"); this._labelLeftElement.style.removeProperty("right"); this._labelLeftElement.removeStyleClass("before"); @@ -1389,7 +1677,7 @@ WebInspector.NetworkDataGridNode.prototype = { } } -WebInspector.NetworkDataGridNode.URLComparator = function(a, b) +WebInspector.NetworkDataGridNode.NameComparator = function(a, b) { var aFileName = a._resource.displayName + (a._resource.queryString ? a._resource.queryString : ""); var bFileName = b._resource.displayName + (b._resource.queryString ? b._resource.queryString : ""); @@ -1400,15 +1688,47 @@ WebInspector.NetworkDataGridNode.URLComparator = function(a, b) return 0; } -WebInspector.NetworkDataGridNode.ResourcePropertyComparator = function(propertyName, a, b) +WebInspector.NetworkDataGridNode.SizeComparator = function(a, b) +{ + if (b._resource.cached && !a._resource.cached) + return 1; + if (a._resource.cached && !b._resource.cached) + return -1; + + if (a._resource.resourceSize === b._resource.resourceSize) + return 0; + + return a._resource.resourceSize - b._resource.resourceSize; +} + +WebInspector.NetworkDataGridNode.ResourcePropertyComparator = function(propertyName, revert, a, b) { var aValue = a._resource[propertyName]; var bValue = b._resource[propertyName]; if (aValue > bValue) - return 1; + return revert ? -1 : 1; if (bValue > aValue) - return -1; + return revert ? 1 : -1; return 0; } WebInspector.NetworkDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; + +WebInspector.NetworkTotalGridNode = function(element) +{ + this._summaryBarElement = element; + WebInspector.DataGridNode.call(this, {summaryRow: true}); +} + +WebInspector.NetworkTotalGridNode.prototype = { + createCells: function() + { + var td = document.createElement("td"); + td.setAttribute("colspan", 7); + td.className = "network-summary"; + td.appendChild(this._summaryBarElement); + this._element.appendChild(td); + } +} + +WebInspector.NetworkTotalGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index 2bd76f9..ca02f9e 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -116,7 +116,7 @@ WebInspector.ProfilesPanel = function() this.clearResultsButton.addEventListener("click", this._clearProfiles.bind(this), false); this.profileViewStatusBarItemsContainer = document.createElement("div"); - this.profileViewStatusBarItemsContainer.id = "profile-view-status-bar-items"; + this.profileViewStatusBarItemsContainer.className = "status-bar-items"; this.welcomeView = new WebInspector.WelcomeView("profiles", WebInspector.UIString("Welcome to the Profiles panel")); this.element.appendChild(this.welcomeView.element); @@ -550,7 +550,7 @@ WebInspector.ProfilesPanel.prototype = { { this.welcomeView.element.style.left = width + "px"; this.profileViews.style.left = width + "px"; - this.profileViewStatusBarItemsContainer.style.left = width + "px"; + this.profileViewStatusBarItemsContainer.style.left = Math.max(155, width) + "px"; this.resize(); } } diff --git a/WebCore/inspector/front-end/PropertiesSection.js b/WebCore/inspector/front-end/PropertiesSection.js index 5ced9ef..1ca52ce 100644 --- a/WebCore/inspector/front-end/PropertiesSection.js +++ b/WebCore/inspector/front-end/PropertiesSection.js @@ -32,7 +32,7 @@ WebInspector.PropertiesSection = function(title, subtitle) WebInspector.Section.call(this, title, subtitle); this.propertiesElement = document.createElement("ol"); - this.propertiesElement.className = "properties source-code"; + this.propertiesElement.className = "properties properties-tree source-code"; this.propertiesElement.tabIndex = 0; this.propertiesTreeOutline = new TreeOutline(this.propertiesElement); this.propertiesTreeOutline.section = this; diff --git a/WebCore/inspector/front-end/Resource.js b/WebCore/inspector/front-end/Resource.js index ea9052d..fe2f7d2 100644 --- a/WebCore/inspector/front-end/Resource.js +++ b/WebCore/inspector/front-end/Resource.js @@ -29,7 +29,7 @@ WebInspector.Resource = function(identifier, url) { this.identifier = identifier; - this._url = url; + this.url = url; this._startTime = -1; this._endTime = -1; this._requestMethod = ""; @@ -97,14 +97,19 @@ WebInspector.Resource.prototype = { if (this._url === x) return; - var oldURL = this._url; this._url = x; delete this._parsedQueryParameters; - // FIXME: We should make the WebInspector object listen for the "url changed" event. - // Then resourceURLChanged can be removed. - WebInspector.resourceURLChanged(this, oldURL); - this.dispatchEventToListeners("url changed"); + var parsedURL = x.asParsedURL(); + this.domain = parsedURL ? parsedURL.host : ""; + this.path = parsedURL ? parsedURL.path : ""; + this.lastPathComponent = ""; + if (parsedURL && parsedURL.path) { + var lastSlashIndex = parsedURL.path.lastIndexOf("/"); + if (lastSlashIndex !== -1) + this.lastPathComponent = parsedURL.path.substring(lastSlashIndex + 1); + } + this.lastPathComponentLowerCase = this.lastPathComponent.toLowerCase(); }, get documentURL() @@ -114,46 +119,21 @@ WebInspector.Resource.prototype = { set documentURL(x) { - if (this._documentURL === x) - return; this._documentURL = x; }, - get domain() - { - return this._domain; - }, - - set domain(x) - { - if (this._domain === x) - return; - this._domain = x; - }, - - get lastPathComponent() - { - return this._lastPathComponent; - }, - - set lastPathComponent(x) - { - if (this._lastPathComponent === x) - return; - this._lastPathComponent = x; - this._lastPathComponentLowerCase = x ? x.toLowerCase() : null; - }, - get displayName() { - var title = this.lastPathComponent; - if (!title) - title = this.displayDomain; - if (!title && this.url) - title = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : ""); - if (title === "/") - title = this.url; - return title; + if (this._displayName) + return this._displayName; + this._displayName = this.lastPathComponent; + if (!this._displayName) + this._displayName = this.displayDomain; + if (!this._displayName && this.url) + this._displayName = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : ""); + if (this._displayName === "/") + this._displayName = this.url; + return this._displayName; }, get displayDomain() @@ -171,29 +151,22 @@ WebInspector.Resource.prototype = { set startTime(x) { - if (this._startTime === x) - return; - this._startTime = x; - - if (WebInspector.panels.resources) - WebInspector.panels.resources.refreshResource(this); }, get responseReceivedTime() { + if (this.timing && this.timing.requestTime) { + // Calculate responseReceivedTime from timing data for better accuracy. + // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis. + return this.timing.requestTime + this.timing.receiveHeadersEnd / 1000.0; + } return this._responseReceivedTime || -1; }, set responseReceivedTime(x) { - if (this._responseReceivedTime === x) - return; - this._responseReceivedTime = x; - - if (WebInspector.panels.resources) - WebInspector.panels.resources.refreshResource(this); }, get endTime() @@ -203,13 +176,13 @@ WebInspector.Resource.prototype = { set endTime(x) { - if (this._endTime === x) - return; + // In case of fast load (or in case of cached resources), endTime on network stack + // can be less then m_responseReceivedTime measured in WebCore. Normalize it here, + // prefer actualEndTime to m_responseReceivedTime. + if (x < this.responseReceivedTime) + this.responseReceivedTime = x; this._endTime = x; - - if (WebInspector.panels.resources) - WebInspector.panels.resources.refreshResource(this); }, get duration() @@ -240,13 +213,7 @@ WebInspector.Resource.prototype = { set resourceSize(x) { - if (this._resourceSize === x) - return; - this._resourceSize = x; - - if (WebInspector.panels.resources) - WebInspector.panels.resources.refreshResource(this); }, get transferSize() @@ -262,8 +229,6 @@ WebInspector.Resource.prototype = { set expectedContentLength(x) { - if (this._expectedContentLength === x) - return; this._expectedContentLength = x; }, @@ -313,11 +278,6 @@ WebInspector.Resource.prototype = { if (this._category) this._category.addResource(this); - - if (WebInspector.panels.resources) { - WebInspector.panels.resources.refreshResource(this); - WebInspector.panels.resources.recreateViewForResourceIfNeeded(this); - } }, get cached() @@ -328,7 +288,6 @@ WebInspector.Resource.prototype = { set cached(x) { this._cached = x; - this.dispatchEventToListeners("cached changed"); }, get mimeType() @@ -338,9 +297,6 @@ WebInspector.Resource.prototype = { set mimeType(x) { - if (this._mimeType === x) - return; - this._mimeType = x; }, @@ -387,18 +343,14 @@ WebInspector.Resource.prototype = { get requestHeaders() { - if (this._requestHeaders === undefined) - this._requestHeaders = {}; - return this._requestHeaders; + return this._requestHeaders || {}; }, set requestHeaders(x) { - if (this._requestHeaders === x) - return; - this._requestHeaders = x; delete this._sortedRequestHeaders; + delete this._requestCookies; this.dispatchEventToListeners("requestHeaders changed"); }, @@ -421,6 +373,13 @@ WebInspector.Resource.prototype = { return this._headerValue(this.requestHeaders, headerName); }, + get requestCookies() + { + if (!this._requestCookies) + this._requestCookies = WebInspector.CookieParser.parseCookie(this.requestHeaderValue("Cookie")); + return this._requestCookies; + }, + get requestFormData() { return this._requestFormData; @@ -434,18 +393,14 @@ WebInspector.Resource.prototype = { get responseHeaders() { - if (this._responseHeaders === undefined) - this._responseHeaders = {}; - return this._responseHeaders; + return this._responseHeaders || {}; }, set responseHeaders(x) { - if (this._responseHeaders === x) - return; - this._responseHeaders = x; delete this._sortedResponseHeaders; + delete this._responseCookies; this.dispatchEventToListeners("responseHeaders changed"); }, @@ -468,6 +423,13 @@ WebInspector.Resource.prototype = { return this._headerValue(this.responseHeaders, headerName); }, + get responseCookies() + { + if (!this._responseCookies) + this._responseCookies = WebInspector.CookieParser.parseSetCookie(this.responseHeaderValue("Set-Cookie")); + return this._responseCookies; + }, + get queryParameters() { if (this._parsedQueryParameters) @@ -627,6 +589,15 @@ WebInspector.Resource.prototype = { if (msg) WebInspector.console.addMessage(msg); + }, + + getContents: function(callback) + { + // FIXME: eventually, cached resources will have no identifiers. + if (this.frameID) + InspectorBackend.resourceContent(this.frameID, this.url, callback); + else + InspectorBackend.getResourceContent(this.identifier, false, callback); } } diff --git a/WebCore/inspector/front-end/ResourceCategory.js b/WebCore/inspector/front-end/ResourceCategory.js index 84f2cf9..7d95a1f 100644 --- a/WebCore/inspector/front-end/ResourceCategory.js +++ b/WebCore/inspector/front-end/ResourceCategory.js @@ -47,8 +47,8 @@ WebInspector.ResourceCategory.prototype = { var resourcesLength = this.resources.length; for (var i = 0; i < resourcesLength; ++i) { var b = this.resources[i]; - if (a._lastPathComponentLowerCase && b._lastPathComponentLowerCase) - if (a._lastPathComponentLowerCase < b._lastPathComponentLowerCase) + if (a.lastPathComponentLowerCase && b.lastPathComponentLowerCase) + if (a.lastPathComponentLowerCase < b.lastPathComponentLowerCase) break; else if (a.name && b.name) if (a.name < b.name) diff --git a/WebCore/inspector/front-end/ResourceManager.js b/WebCore/inspector/front-end/ResourceManager.js new file mode 100644 index 0000000..7244cea --- /dev/null +++ b/WebCore/inspector/front-end/ResourceManager.js @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2009, 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.ResourceManager = function() +{ + this._registerNotifyHandlers( + "identifierForInitialRequest", + "willSendRequest", + "markResourceAsCached", + "didReceiveResponse", + "didReceiveContentLength", + "didFinishLoading", + "didFailLoading", + "didLoadResourceFromMemoryCache", + "setOverrideContent", + "didCommitLoad", + "frameDetachedFromParent", + "didCreateWebSocket", + "willSendWebSocketHandshakeRequest", + "didReceiveWebSocketHandshakeResponse", + "didCloseWebSocket"); + + this._resources = {}; + this._resourcesByFrame = {}; + this._lastCachedId = 0; +} + +WebInspector.ResourceManager.prototype = { + _registerNotifyHandlers: function() + { + for (var i = 0; i < arguments.length; ++i) + WebInspector[arguments[i]] = this[arguments[i]].bind(this); + }, + + identifierForInitialRequest: function(identifier, url, frameID, isMainResource) + { + var resource = new WebInspector.Resource(identifier, url); + if (isMainResource) + resource.isMainResource = true; + this._resources[identifier] = resource; + + if (frameID) { + resource.frameID = frameID; + var resourcesForFrame = this._resourcesByFrame[frameID]; + if (!resourcesForFrame) { + resourcesForFrame = []; + this._resourcesByFrame[frameID] = resourcesForFrame; + } + resourcesForFrame.push(resource); + } + + if (WebInspector.panels.network) + WebInspector.panels.network.addResource(resource); + }, + + willSendRequest: function(identifier, time, request, redirectResponse) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + // Redirect may have empty URL and we'd like to not crash with invalid HashMap entry. + // See http/tests/misc/will-send-request-returns-null-on-redirect.html + if (!redirectResponse.isNull && request.url.length) { + resource.endTime = time; + this.didReceiveResponse(identifier, time, "Other", redirectResponse); + resource = this._appendRedirect(resource.identifier, request.url); + } + + resource.requestMethod = request.httpMethod; + resource.requestHeaders = request.httpHeaderFields; + resource.requestFormData = request.requestFormData; + resource.startTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + _appendRedirect: function(identifier, redirectURL) + { + // We always store last redirect by the original id key. Rest of the redirects are referenced from within the last one. + + var originalResource = this._resources[identifier]; + var redirectIdentifier = originalResource.identifier + ":" + (originalResource.redirects ? originalResource.redirects.length : 0); + originalResource.identifier = redirectIdentifier; + this._resources[redirectIdentifier] = originalResource; + + this.identifierForInitialRequest(identifier, redirectURL, originalResource.frameID); + + var newResource = this._resources[identifier]; + newResource.redirects = originalResource.redirects || []; + delete originalResource.redirects; + newResource.redirects.push(originalResource); + return newResource; + }, + + markResourceAsCached: function(identifier) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.cached = true; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didReceiveResponse: function(identifier, time, resourceType, response) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.type = WebInspector.Resource.Type[resourceType]; + resource.mimeType = response.mimeType; + resource.expectedContentLength = response.expectedContentLength; + resource.textEncodingName = response.textEncodingName; + resource.suggestedFilename = response.suggestedFilename; + resource.statusCode = response.httpStatusCode; + resource.statusText = response.httpStatusText; + + resource.responseHeaders = response.httpHeaderFields; + resource.connectionReused = response.connectionReused; + resource.connectionID = response.connectionID; + resource.responseReceivedTime = time; + + if (response.wasCached) + resource.cached = true; + else + resource.timing = response.timing; + + if (response.rawHeaders) { + resource.requestHeaders = response.rawHeaders.requestHeaders; + resource.responseHeaders = response.rawHeaders.responseHeaders; + } + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didReceiveContentLength: function(identifier, time, lengthReceived) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.resourceSize += lengthReceived; + resource.endTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didFinishLoading: function(identifier, finishTime) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.finished = true; + resource.endTime = finishTime; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didFailLoading: function(identifier, time, localizedDescription) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.failed = true; + resource.endTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didLoadResourceFromMemoryCache: function(time, frameID, cachedResource) + { + var identifier = "cached:" + this._lastCachedId++; + this.identifierForInitialRequest(identifier, cachedResource.url, frameID); + + var resource = this._resources[identifier]; + resource.cached = true; + resource.startTime = resource.responseReceivedTime = time; + resource.resourceSize = cachedResource.encodedSize(); + + this.didReceiveResponse(identifier, time, cachedResource.response); + }, + + setOverrideContent: function(identifier, sourceString, type) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.type = WebInspector.Resource.Type[type]; + resource.overridenContent = sourceString; + + if (WebInspector.panels.network) + WebInspector.panels.network.addResource(resource); + }, + + didCommitLoad: function(frameID) + { + }, + + frameDetachedFromParent: function(frameID) + { + var resourcesForFrame = this._resourcesByFrame[frameID]; + for (var i = 0; resourcesForFrame && i < resourcesForFrame.length; ++i) + delete this._resources[resourcesForFrame[i].identifier]; + delete this._resourcesByFrame[frameID]; + }, + + didCreateWebSocket: function(identifier, requestURL) + { + this.identifierForInitialRequest(identifier, requestURL); + var resource = this._resources[identifier]; + resource.type = WebInspector.Resource.Type.WebSocket; + + if (WebInspector.panels.network) + WebInspector.panels.network.addResource(resource); + }, + + willSendWebSocketHandshakeRequest: function(identifier, time, request) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.requestMethod = "GET"; + resource.requestHeaders = request.webSocketHeaderFields; + resource.webSocketRequestKey3 = request.webSocketRequestKey3; + resource.startTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didReceiveWebSocketHandshakeResponse: function(identifier, time, response) + { + var resource = this._resources[identifier]; + if (!resource) + return; + + resource.statusCode = response.statusCode; + resource.statusText = response.statusText; + resource.responseHeaders = response.webSocketHeaderFields; + resource.webSocketChallengeResponse = response.webSocketChallengeResponse; + resource.responseReceivedTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + }, + + didCloseWebSocket: function(identifier, time) + { + var resource = this._resources[identifier]; + if (!resource) + return; + resource.endTime = time; + + if (WebInspector.panels.network) + WebInspector.panels.network.refreshResource(resource); + } +} diff --git a/WebCore/inspector/front-end/ResourceView.js b/WebCore/inspector/front-end/ResourceView.js index 1c2574f..862569f 100644 --- a/WebCore/inspector/front-end/ResourceView.js +++ b/WebCore/inspector/front-end/ResourceView.js @@ -99,7 +99,6 @@ WebInspector.ResourceView = function(resource) this.headersVisible = true; - resource.addEventListener("url changed", this._refreshURL, this); resource.addEventListener("requestHeaders changed", this._refreshRequestHeaders, this); resource.addEventListener("responseHeaders changed", this._refreshResponseHeaders, this); resource.addEventListener("finished", this._refreshHTTPInformation, this); diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js index aa021ff..ae67bef 100644 --- a/WebCore/inspector/front-end/ResourcesPanel.js +++ b/WebCore/inspector/front-end/ResourcesPanel.js @@ -142,7 +142,7 @@ WebInspector.ResourcesPanel.prototype = { // Add a divider var dividerElement = document.createElement("div"); - dividerElement.addStyleClass("divider"); + dividerElement.addStyleClass("scope-bar-divider"); this.filterBarElement.appendChild(dividerElement); for (var category in this.categories) @@ -757,7 +757,6 @@ WebInspector.ResourcesPanel.prototype = { addResource: function(resource) { this._resources.push(resource); - this.refreshResource(resource); }, removeResource: function(resource) @@ -815,18 +814,19 @@ WebInspector.ResourcesPanel.prototype = { refreshResource: function(resource) { + this._recreateViewForResourceIfNeeded(resource); this.refreshItem(resource); }, - recreateViewForResourceIfNeeded: function(resource) + _recreateViewForResourceIfNeeded: function(resource) { if (!resource || !resource._resourcesView) return; - var newView = this._createResourceView(resource); - if (newView.__proto__ === resource._resourcesView.__proto__) + if (this._resourceViewIsConsistentWithCategory(resource, resource._resourcesView)) return; + var newView = this._createResourceView(resource); if (!this.currentQuery && resource._itemsTreeElement) resource._itemsTreeElement.updateErrorsAndWarnings(); @@ -1068,6 +1068,23 @@ WebInspector.ResourcesPanel.prototype = { this.calculator = this.summaryBar.calculator = selectedOption.calculator; }, + _resourceViewIsConsistentWithCategory: function(resource, resourceView) + { + switch (resource.category) { + case WebInspector.resourceCategories.documents: + case WebInspector.resourceCategories.stylesheets: + case WebInspector.resourceCategories.scripts: + case WebInspector.resourceCategories.xhr: + return resourceView.__proto__ === WebInspector.SourceView.prototype; + case WebInspector.resourceCategories.images: + return resourceView.__proto__ === WebInspector.ImageView.prototype; + case WebInspector.resourceCategories.fonts: + return resourceView.__proto__ === WebInspector.FontView.prototype; + default: + return resourceView.__proto__ === WebInspector.ResourceView.prototype; + } + }, + _createResourceView: function(resource) { switch (resource.category) { @@ -1250,17 +1267,27 @@ WebInspector.ResourcesPanel.prototype = { _contextMenu: function(event) { - // createBlobURL is enabled conditionally, do not expose resource export if it's not available. - if (typeof window.createBlobURL !== "function" || !Preferences.resourceExportEnabled) - return; - var contextMenu = new WebInspector.ContextMenu(); var resourceTreeItem = event.target.enclosingNodeOrSelfWithClass("resource-sidebar-tree-item"); - if (resourceTreeItem && resourceTreeItem.treeElement) { - var resource = resourceTreeItem.treeElement.representedObject; - contextMenu.appendItem(WebInspector.UIString("Export to HAR"), this._exportResource.bind(this, resource)); + var resource; + if (resourceTreeItem && resourceTreeItem.treeElement) + resource = resourceTreeItem.treeElement.representedObject; + + var needSeparator = false; + // createObjectURL is enabled conditionally, do not expose resource export if it's not available. + if (typeof window.createObjectURL === "function" && Preferences.resourceExportEnabled) { + if (resource) + contextMenu.appendItem(WebInspector.UIString("Export to HAR"), this._exportResource.bind(this, resource)); + contextMenu.appendItem(WebInspector.UIString("Export all to HAR"), this._exportAll.bind(this)); + needSeparator = true; } - contextMenu.appendItem(WebInspector.UIString("Export all to HAR"), this._exportAll.bind(this)); + + if (resource && resource.category === WebInspector.resourceCategories.xhr) { + if (needSeparator) + contextMenu.appendSeparator(); + contextMenu.appendItem(WebInspector.UIString("Set XHR Breakpoint"), WebInspector.breakpointManager.createXHRBreakpoint.bind(WebInspector.breakpointManager, resource.url)); + } + contextMenu.show(event); }, @@ -1281,11 +1308,6 @@ WebInspector.ResourcesPanel.prototype = { WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype; -WebInspector.getResourceContent = function(identifier, callback) -{ - InspectorBackend.getResourceContent(identifier, callback); -} - WebInspector.ResourceBaseCalculator = function() { } @@ -1814,7 +1836,8 @@ WebInspector.ResourceGraph = function(resource) this._graphElement.className = "resources-graph-side"; this._graphElement.addEventListener("mouseover", this.refreshLabelPositions.bind(this), false); - this._cachedChanged(); + if (this.resource.cached) + this._graphElement.addStyleClass("resource-cached"); this._barAreaElement = document.createElement("div"); this._barAreaElement.className = "resources-graph-bar-area hidden"; @@ -1838,8 +1861,6 @@ WebInspector.ResourceGraph = function(resource) this._barAreaElement.appendChild(this._labelRightElement); this._graphElement.addStyleClass("resources-category-" + resource.category.name); - - resource.addEventListener("cached changed", this._cachedChanged, this); } WebInspector.ResourceGraph.prototype = { @@ -1963,11 +1984,8 @@ WebInspector.ResourceGraph.prototype = { this._labelLeftElement.title = tooltip; this._labelRightElement.title = tooltip; this._barRightElement.title = tooltip; - }, - _cachedChanged: function() - { - if (this.resource.cached) + if (this.resource.cached && !this._graphElement.hasStyleClass("resource-cached")) this._graphElement.addStyleClass("resource-cached"); } } diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 8283528..0a653c9 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -134,10 +134,9 @@ WebInspector.ScriptsPanel = function() this.sidebarPanes.jsBreakpoints = WebInspector.createJSBreakpointsSidebarPane(); if (Preferences.nativeInstrumentationEnabled) { this.sidebarPanes.domBreakpoints = WebInspector.createDOMBreakpointsSidebarPane(); - this.sidebarPanes.domBreakpoints.expanded = true; this.sidebarPanes.xhrBreakpoints = WebInspector.createXHRBreakpointsSidebarPane(); - this.sidebarPanes.xhrBreakpoints.expanded = true; } + this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane(); this.sidebarPanes.workers = new WebInspector.WorkersSidebarPane(); @@ -389,9 +388,6 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.callstack.update(details.callFrames, this._sourceIDMap); this.sidebarPanes.callstack.selectedCallFrame = details.callFrames[0]; - if ("eventType" in details) - this.sidebarPanes.callstack.updateStatus(details.eventType, details.eventData); - WebInspector.currentPanel = this; window.focus(); }, @@ -439,13 +435,7 @@ WebInspector.ScriptsPanel.prototype = { delete this.currentQuery; this.searchCanceled(); - if (!this._debuggerEnabled) { - this._paused = false; - this._waitingToPause = false; - this._stepping = false; - } - - this._clearInterface(); + this.debuggerResumed(); this._backForwardList = []; this._currentBackForwardIndex = -1; @@ -473,6 +463,7 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.domBreakpoints.reset(); this.sidebarPanes.xhrBreakpoints.reset(); } + this.sidebarPanes.eventListenerBreakpoints.reset(); this.sidebarPanes.workers.reset(); } }, diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index aecd57b..4b391ac 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -169,6 +169,14 @@ WebInspector.SourceFrame.prototype = { this._lineToHighlight = line; }, + clearLineHighlight: function() + { + if (this._textViewer) + this._textViewer.clearLineHighlight(); + else + delete this._lineToHighlight; + }, + _createViewerIfNeeded: function() { if (!this._visible || !this._loaded || this._textViewer) diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js index 3f762cc..8092505 100644 --- a/WebCore/inspector/front-end/SourceView.js +++ b/WebCore/inspector/front-end/SourceView.js @@ -59,6 +59,8 @@ WebInspector.SourceView.prototype = { hide: function() { this.sourceFrame.visible = false; + if (!this._frameNeedsSetup) + this.sourceFrame.clearLineHighlight(); WebInspector.View.prototype.hide.call(this); if (this.localSourceFrame) this.localSourceFrame.visible = false; @@ -81,7 +83,7 @@ WebInspector.SourceView.prototype = { this.attach(); delete this._frameNeedsSetup; - WebInspector.getResourceContent(this.resource.identifier, this._contentLoaded.bind(this)); + this.resource.getContents(this._contentLoaded.bind(this)); }, hasContentTab: function() diff --git a/WebCore/inspector/front-end/StoragePanel.js b/WebCore/inspector/front-end/StoragePanel.js index 2d17989..e033b57 100644 --- a/WebCore/inspector/front-end/StoragePanel.js +++ b/WebCore/inspector/front-end/StoragePanel.js @@ -59,7 +59,7 @@ WebInspector.StoragePanel = function(database) this.element.appendChild(this.storageViews); this.storageViewStatusBarItemsContainer = document.createElement("div"); - this.storageViewStatusBarItemsContainer.id = "storage-view-status-bar-items"; + this.storageViewStatusBarItemsContainer.className = "status-bar-items"; this.reset(); } diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js index 6aff37d..36d854c 100644 --- a/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/WebCore/inspector/front-end/StylesSidebarPane.js @@ -1695,17 +1695,13 @@ WebInspector.StylePropertyTreeElement.prototype = { self.updateTitle(); } - function successCallback(newStyle, changedProperties) + function successCallback(newStyle) { - elementsPanel.removeStyleChange(section.identifier, self.style, self.name); - if (!styleTextLength) { // Do remove ourselves from UI when the property removal is confirmed. self.parent.removeChild(self); } else { self.style = newStyle; - for (var i = 0; i < changedProperties.length; ++i) - elementsPanel.addStyleChange(section.identifier, self.style, changedProperties[i]); self._styleRule.style = self.style; } diff --git a/WebCore/inspector/front-end/TabbedPane.js b/WebCore/inspector/front-end/TabbedPane.js index 6acd163..dec3a0b 100644 --- a/WebCore/inspector/front-end/TabbedPane.js +++ b/WebCore/inspector/front-end/TabbedPane.js @@ -33,7 +33,7 @@ WebInspector.TabbedPane = function(element) this.element = element || document.createElement("div"); this.tabsElement = document.createElement("div"); - this.tabsElement.className = "scope-bar"; + this.tabsElement.className = "tabbed-pane-header"; this.element.appendChild(this.tabsElement); this._tabObjects = {}; diff --git a/WebCore/inspector/front-end/TextViewer.js b/WebCore/inspector/front-end/TextViewer.js index 13b2836..9ad5e49 100644 --- a/WebCore/inspector/front-end/TextViewer.js +++ b/WebCore/inspector/front-end/TextViewer.js @@ -117,16 +117,22 @@ WebInspector.TextViewer.prototype = { highlightLine: function(lineNumber) { - if (typeof this._highlightedLine === "number") { - var chunk = this._makeLineAChunk(this._highlightedLine); - chunk.removeDecoration("webkit-highlighted-line"); - } + this.clearLineHighlight(); this._highlightedLine = lineNumber; this.revealLine(lineNumber); var chunk = this._makeLineAChunk(lineNumber); chunk.addDecoration("webkit-highlighted-line"); }, + clearLineHighlight: function() + { + if (typeof this._highlightedLine === "number") { + var chunk = this._makeLineAChunk(this._highlightedLine); + chunk.removeDecoration("webkit-highlighted-line"); + delete this._highlightedLine; + } + }, + freeCachedElements: function() { this._cachedSpans = []; diff --git a/WebCore/inspector/front-end/TimelineGrid.js b/WebCore/inspector/front-end/TimelineGrid.js index ad7e769..adc8e47 100644 --- a/WebCore/inspector/front-end/TimelineGrid.js +++ b/WebCore/inspector/front-end/TimelineGrid.js @@ -55,6 +55,7 @@ WebInspector.TimelineGrid.prototype = { return this._itemsGraphsElement; }, + updateDividers: function(force, calculator, paddingLeft) { var dividerCount = Math.round(this._dividersElement.offsetWidth / 64); @@ -88,10 +89,21 @@ WebInspector.TimelineGrid.prototype = { dividersLabelBarElementClientWidth = this._dividersLabelBarElement.clientWidth; } - if (i === dividerCount) + if (i === (paddingLeft ? 0 : 1)) { + divider.addStyleClass("first"); + dividerLabelBar.addStyleClass("first"); + } else { + divider.removeStyleClass("first"); + dividerLabelBar.removeStyleClass("first"); + } + + if (i === dividerCount) { divider.addStyleClass("last"); - else + dividerLabelBar.addStyleClass("last"); + } else { divider.removeStyleClass("last"); + dividerLabelBar.removeStyleClass("last"); + } var left = paddingLeft + clientWidth * (i / dividerCount); var percentLeft = 100 * left / dividersLabelBarElementClientWidth; diff --git a/WebCore/inspector/front-end/TimelineOverviewPane.js b/WebCore/inspector/front-end/TimelineOverviewPane.js index 3e83f62..55e24c5 100644 --- a/WebCore/inspector/front-end/TimelineOverviewPane.js +++ b/WebCore/inspector/front-end/TimelineOverviewPane.js @@ -33,8 +33,7 @@ WebInspector.TimelineOverviewPane = function(categories) this._categories = categories; this.statusBarFilters = document.createElement("div"); - this.statusBarFilters.id = "timeline-view-status-bar-items"; - this.statusBarFilters.addStyleClass("status-bar-item"); + this.statusBarFilters.className = "status-bar-items"; for (var categoryName in this._categories) { var category = this._categories[categoryName]; this.statusBarFilters.appendChild(this._createTimelineCategoryStatusBarCheckbox(category, this._onCheckboxClicked.bind(this, category))); @@ -197,6 +196,7 @@ WebInspector.TimelineOverviewPane.prototype = { updateMainViewWidth: function(width, records) { this._overviewGrid.element.style.left = width + "px"; + this.statusBarFilters.style.left = Math.max(155, width) + "px"; }, reset: function() diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 11382cd..1e5a508 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -20,6 +20,7 @@ <file>ConsoleView.js</file> <file>ContextMenu.js</file> <file>CookieItemsView.js</file> + <file>CookieParser.js</file> <file>CSSCompletions.js</file> <file>CSSStyleModel.js</file> <file>Database.js</file> @@ -68,6 +69,7 @@ <file>RemoteObject.js</file> <file>Resource.js</file> <file>ResourceCategory.js</file> + <file>ResourceManager.js</file> <file>ResourcesPanel.js</file> <file>ResourceView.js</file> <file>ScopeChainSidebarPane.js</file> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 848afdc..0662954 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -810,6 +810,7 @@ body.platform-linux .monospace, body.platform-linux .source-code { .resource-view { display: none; position: absolute; + background: white; top: 0; left: 0; right: 0; @@ -820,7 +821,7 @@ body.platform-linux .monospace, body.platform-linux .source-code { display: block; } -.resource-view .scope-bar { +.resource-view .tabbed-pane-header { display: none; position: absolute; height: 20px; @@ -831,7 +832,7 @@ body.platform-linux .monospace, body.platform-linux .source-code { border-bottom: 1px solid rgb(163, 163, 163); } -.resource-view.headers-visible .scope-bar { +.resource-view.headers-visible .tabbed-pane-header { display: block; } @@ -1373,10 +1374,10 @@ body.inactive .placard.selected { .section .properties, .event-bar .event-properties { display: none; - margin: 0; - padding: 2px 6px 3px; - list-style: none; - min-height: 18px; +} + +.section.expanded .properties, .event-bar.expanded .event-properties { + display: block; } .section.no-affect .properties li { @@ -1387,11 +1388,14 @@ body.inactive .placard.selected { opacity: 1.0; } -.section.expanded .properties, .event-bar.expanded .event-properties { - display: block; +.properties-tree { + margin: 0; + padding: 2px 6px 3px; + list-style: none; + min-height: 18px; } -.section .properties li, .event-properties li { +.properties-tree li { margin-left: 12px; white-space: nowrap; text-overflow: ellipsis; @@ -1400,26 +1404,11 @@ body.inactive .placard.selected { cursor: auto; } -.section .properties li.parent, .event-properties li.parent { +.properties-tree li.parent { margin-left: 1px; } -.section .properties ol, .event-properties ol, .stack-trace ol, ol.stack-trace { - display: none; - margin: 0; - -webkit-padding-start: 12px; - list-style: none; -} - -ol.stack-trace { - -webkit-padding-start: 0px; -} - -.section .properties ol.expanded, .event-properties ol.expanded, .stack-trace ol, ol.stack-trace { - display: block; -} - -.section .properties li.parent::before, .event-properties li.parent::before { +.properties-tree li.parent::before { content: url(Images/treeRightTriangleBlack.png); opacity: 0.75; float: left; @@ -1431,16 +1420,47 @@ ol.stack-trace { cursor: default; } -.section .properties li.parent.expanded::before, .event-properties li.parent.expanded::before { +.properties-tree li.parent.expanded::before { content: url(Images/treeDownTriangleBlack.png); margin-top: 1px; } -.section .properties li .info, .event-properties li .info { +.properties-tree li .info { padding-top: 4px; padding-bottom: 3px; } +.properties-tree ol, .stack-trace ol, ol.stack-trace { + display: none; + margin: 0; + -webkit-padding-start: 12px; + list-style: none; +} + +.properties-tree ol.expanded, .stack-trace ol, ol.stack-trace { + display: block; +} + +ol.stack-trace { + -webkit-padding-start: 0px; +} + +.event-listener-breakpoints .event-category { + font-size: 12px; + font-weight: bold; + color: rgb(110, 110, 110); +} + +.event-listener-breakpoints.properties-tree .children li { + margin-left: 17px; +} + +.event-listener-breakpoints .checkbox-elem { + float: left; + margin-top: 1px; + margin-left: 0px; +} + .section .event-bars { display: none; } @@ -2086,22 +2106,27 @@ body.inactive .sidebar { background-image: url(Images/glossyHeaderSelectedPressed.png); } -.data-grid th.sort-ascending div::after { +.data-grid th.sort-ascending > div::after { position: absolute; top: 0; + bottom: 0; right: 0; + height: 12px; + margin-bottom: auto; + margin-top: auto; width: 8px; - height: 8px; content: url(Images/treeUpTriangleBlack.png); } -.data-grid th.sort-descending div::after { +.data-grid th.sort-descending > div::after { position: absolute; top: 0; + bottom: 0; right: 0; - margin-top: 1px; - width: 8px; height: 8px; + margin-bottom: auto; + margin-top: auto; + width: 8px; content: url(Images/treeDownTriangleBlack.png); } @@ -2560,6 +2585,33 @@ button.enable-toggle-status-bar-item.toggled-on .glyph { margin-top: 1px; } +.tabbed-pane-header { + height: 23px; + padding: 0 10px; + border-bottom: 1px solid rgb(163, 163, 163); +} + +.tabbed-pane-header li { + display: inline-block; + margin-top: 2px; + font-size: 11px; + font-weight: bold; + color: rgb(46, 46, 46); + background: transparent; + text-shadow: rgba(255, 255, 255, 0.5) 0 1px 0; + vertical-align: middle; + padding: 1px 7px 2px; + height: 18px; + border: 1px solid transparent; + border-bottom: none; +} + +.tabbed-pane-header li.selected { + background-color: white; + border: 1px solid rgb(163, 163, 163); + border-bottom: none; +} + .scope-bar { height: 23px; padding: 2px 10px 0; @@ -2580,7 +2632,7 @@ button.enable-toggle-status-bar-item.toggled-on .glyph { vertical-align: middle; } -.scope-bar .divider { +.scope-bar-divider { margin: 1px 9px 0 8px; background-color: rgba(0, 0, 0, 0.4); height: 16px; @@ -2718,7 +2770,7 @@ button.enable-toggle-status-bar-item.toggled-on .glyph { .resources-event-dividers { position: absolute; left: 0; - right: 0; + right: 5px; height: 100%; top: 0; z-index: 300; @@ -3837,8 +3889,7 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { bottom: 0; } -#timeline-view-status-bar-items, -#profile-view-status-bar-items { +.status-bar-items { position: absolute; top: 0; bottom: 0; @@ -3962,30 +4013,10 @@ button.enable-toggle-status-bar-item .glyph { -webkit-mask-image: url(Images/excludeButtonGlyph.png); } -#storage-view-status-bar-items { - position: absolute; - top: 0; - bottom: 0; - left: 200px; - overflow: hidden; - border-left: 1px solid rgb(184, 184, 184); - margin-left: -1px; -} - .refresh-storage-status-bar-item .glyph { -webkit-mask-image: url(Images/reloadButtonGlyph.png); } -#storage-view-status-bar-items { - position: absolute; - top: 0; - bottom: 0; - left: 200px; - overflow: hidden; - border-left: 1px solid rgb(184, 184, 184); - margin-left: -1px; -} - ol.breakpoint-list { -webkit-padding-start: 2px; list-style: none; @@ -4020,6 +4051,10 @@ ol.breakpoint-list { margin: 2px 0 0px 20px; } +.breakpoint-list .breakpoint-hit { + background-color: yellow; +} + .webkit-html-js-node, .webkit-html-css-node { white-space: pre; } diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 949b18f..96d0cfe 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -61,6 +61,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="Panel.js"></script> <script type="text/javascript" src="TimelineGrid.js"></script> <script type="text/javascript" src="Resource.js"></script> + <script type="text/javascript" src="ResourceManager.js"></script> <script type="text/javascript" src="ResourceCategory.js"></script> <script type="text/javascript" src="Database.js"></script> <script type="text/javascript" src="DOMStorage.js"></script> @@ -143,6 +144,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="GoToLineDialog.js"></script> <script type="text/javascript" src="ShortcutsHelp.js"></script> <script type="text/javascript" src="HAREntry.js"></script> + <script type="text/javascript" src="CookieParser.js"></script> </head> <body class="detached"> <div id="toolbar"> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index 3edae8f..9bd88d6 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -56,15 +56,6 @@ var WebInspector = { missingLocalizedStrings: {}, pendingDispatches: 0, - // RegExp groups: - // 1 - scheme - // 2 - hostname - // 3 - ?port - // 4 - ?path - // 5 - ?fragment - URLRegExp: /^(http[s]?|file):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i, - GenericURLRegExp: /^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i, - get platform() { if (!("_platform" in this)) @@ -213,9 +204,9 @@ var WebInspector = { var pane = new WebInspector.BreakpointsSidebarPane(WebInspector.UIString("DOM Breakpoints")); function breakpointAdded(event) { - pane.addBreakpoint(new WebInspector.DOMBreakpointItem(event.data)); + pane.addBreakpoint(new WebInspector.BreakpointItem(event.data)); } - WebInspector.domBreakpointManager.addEventListener("dom-breakpoint-added", breakpointAdded); + WebInspector.breakpointManager.addEventListener("dom-breakpoint-added", breakpointAdded); return pane; }, @@ -224,7 +215,7 @@ var WebInspector = { var pane = new WebInspector.XHRBreakpointsSidebarPane(); function breakpointAdded(event) { - pane.addBreakpoint(new WebInspector.XHRBreakpointItem(event.data)); + pane.addBreakpoint(new WebInspector.BreakpointItem(event.data)); } WebInspector.breakpointManager.addEventListener("xhr-breakpoint-added", breakpointAdded); return pane; @@ -516,6 +507,8 @@ WebInspector.doLoadedDone = function() // this.changes = new WebInspector.ChangesView(this.drawer); // TODO: Remove class="hidden" from inspector.html on button#changes-status-bar-item this.drawer.visibleView = this.console; + // FIXME: uncomment when ready. + // this.resourceManager = new WebInspector.ResourceManager(); this.domAgent = new WebInspector.DOMAgent(); this.resourceCategories = { @@ -530,7 +523,6 @@ WebInspector.doLoadedDone = function() }; this.breakpointManager = new WebInspector.BreakpointManager(); - this.domBreakpointManager = new WebInspector.DOMBreakpointManager(); this.cssModel = new WebInspector.CSSStyleModel(); this.panels = {}; @@ -604,6 +596,7 @@ WebInspector.doLoadedDone = function() InspectorBackend.getInspectorState(populateInspectorState); InspectorBackend.populateScriptObjects(); + InspectorBackend.setConsoleMessagesEnabled(true); // As a DOMAgent method, this needs to happen after the frontend has loaded and the agent is available. InspectorBackend.getSupportedCSSProperties(WebInspector.CSSCompletions._load); @@ -770,10 +763,10 @@ WebInspector.documentClick = function(event) return; } - const urlMatch = WebInspector.GenericURLRegExp.exec(anchor.href); - if (urlMatch && urlMatch[1] === "webkit-link-action") { - if (urlMatch[2] === "show-panel") { - const panel = urlMatch[4].substring(1); + var parsedURL = anchor.href.asParsedURL(); + if (parsedURL && parsedURL.scheme === "webkit-link-action") { + if (parsedURL.host === "show-panel") { + var panel = parsedURL.path.substring(1); if (WebInspector.panels[panel]) WebInspector.currentPanel = WebInspector.panels[panel]; } @@ -1229,14 +1222,9 @@ WebInspector.updateResource = function(payload) this.resourceURLMap[resource.url] = resource; this.panels.resources.addResource(resource); this.panels.audits.resourceStarted(resource); - if (this.panels.network) - this.panels.network.addResource(resource); } if (payload.didRequestChange) { - resource.domain = payload.host; - resource.path = payload.path; - resource.lastPathComponent = payload.lastPathComponent; resource.requestHeaders = payload.requestHeaders; resource.mainResource = payload.mainResource; resource.requestMethod = payload.requestMethod; @@ -1248,11 +1236,10 @@ WebInspector.updateResource = function(payload) if (resource.mainResource) this.mainResource = resource; - var match = payload.documentURL.match(WebInspector.GenericURLRegExp); - if (match) { - var protocol = match[1].toLowerCase(); - this._addCookieDomain(match[2]); - this._addAppCacheDomain(match[2]); + var parsedURL = payload.documentURL.asParsedURL(); + if (parsedURL) { + this._addCookieDomain(parsedURL.host); + this._addAppCacheDomain(parsedURL.host); } } @@ -1293,29 +1280,24 @@ WebInspector.updateResource = function(payload) resource.responseReceivedTime = payload.responseReceivedTime; if (payload.endTime) resource.endTime = payload.endTime; - - if (payload.loadEventTime) { - // This loadEventTime is for the main resource, and we want to show it - // for all resources on this page. This means we want to set it as a member - // of the resources panel instead of the individual resource. - this.panels.resources.mainResourceLoadTime = payload.loadEventTime; - this.panels.audits.mainResourceLoadTime = payload.loadEventTime; - if (this.panels.network) - this.panels.network.mainResourceLoadTime = payload.loadEventTime; - } - - if (payload.domContentEventTime) { - // This domContentEventTime is for the main resource, so it should go in - // the resources panel for the same reasons as above. - this.panels.resources.mainResourceDOMContentTime = payload.domContentEventTime; - this.panels.audits.mainResourceDOMContentTime = payload.domContentEventTime; - if (this.panels.network) - this.panels.network.mainResourceDOMContentTime = payload.domContentEventTime; - } } + this.panels.resources.refreshResource(resource); +} +WebInspector.domContentEventFired = function(time) +{ + this.panels.resources.mainResourceDOMContentTime = time; + this.panels.audits.mainResourceDOMContentTime = time; if (this.panels.network) - this.panels.network.refreshResource(resource); + this.panels.network.mainResourceDOMContentTime = time; +} + +WebInspector.loadEventFired = function(time) +{ + this.panels.resources.mainResourceLoadTime = time; + this.panels.audits.mainResourceLoadTime = time; + if (this.panels.network) + this.panels.network.mainResourceLoadTime = time; } WebInspector.removeResource = function(identifier) @@ -1447,16 +1429,20 @@ WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLin WebInspector.pausedScript = function(details) { this.panels.scripts.debuggerPaused(details); + this.breakpointManager.debuggerPaused(details); InspectorFrontendHost.bringToFront(); } WebInspector.resumedScript = function() { + this.breakpointManager.debuggerResumed(); this.panels.scripts.debuggerResumed(); } WebInspector.reset = function() { + this.breakpointManager.reset(); + for (var panelName in this.panels) { var panel = this.panels[panelName]; if ("reset" in panel) @@ -1464,7 +1450,6 @@ WebInspector.reset = function() } this.sessionSettings.reset(); - this.breakpointManager.reset(); for (var category in this.resourceCategories) this.resourceCategories[category].removeAllResources(); @@ -1498,12 +1483,6 @@ WebInspector.inspectedURLChanged = function(url) this.extensionServer.notifyInspectedURLChanged(); } -WebInspector.resourceURLChanged = function(resource, oldURL) -{ - delete this.resourceURLMap[oldURL]; - this.resourceURLMap[resource.url] = resource; -} - WebInspector.didCommitLoad = function() { // Cleanup elements panel early on inspected page refresh. @@ -1837,8 +1816,8 @@ WebInspector.resourceURLForRelatedNode = function(node, url) // documentURL not found or has bad value for (var resourceURL in WebInspector.resourceURLMap) { - var match = resourceURL.match(WebInspector.URLRegExp); - if (match && match[4] === url) + var parsedURL = resourceURL.asParsedURL(); + if (parsedURL && parsedURL.path === url) return resourceURL; } return url; @@ -1846,17 +1825,17 @@ WebInspector.resourceURLForRelatedNode = function(node, url) WebInspector.completeURL = function(baseURL, href) { - var match = baseURL.match(WebInspector.URLRegExp); - if (match) { + var parsedURL = baseURL.asParsedURL(); + if (parsedURL) { var path = href; if (path.charAt(0) !== "/") { - var basePath = match[4] || "/"; + var basePath = parsedURL.path; path = basePath.substring(0, basePath.lastIndexOf("/")) + "/" + path; } else if (path.length > 1 && path.charAt(1) === "/") { // href starts with "//" which is a full URL with the protocol dropped (use the baseURL protocol). - return match[1] + ":" + path; + return parsedURL.scheme + ":" + path; } - return match[1] + "://" + match[2] + (match[3] ? (":" + match[3]) : "") + path; + return parsedURL.scheme + "://" + parsedURL.host + (parsedURL.port ? (":" + parsedURL.port) : "") + path; } return null; } diff --git a/WebCore/inspector/front-end/networkPanel.css b/WebCore/inspector/front-end/networkPanel.css index cdea7fe..773fe99 100644 --- a/WebCore/inspector/front-end/networkPanel.css +++ b/WebCore/inspector/front-end/networkPanel.css @@ -1,383 +1,601 @@ -.network-larger-resources-status-bar-item .glyph {
- -webkit-mask-image: url(Images/largerResourcesButtonGlyph.png);
-}
-
-.network.panel .data-grid {
- border: none;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- font-size: 11px;
-}
-
-.network.panel .data-grid table.data {
- -webkit-background-size: 1px 82px;
- background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), color-stop(0.5, rgba(0, 0, 0, 0)), color-stop(0.5, rgba(0, 0, 0, 0.05)), to(rgba(0, 0, 0, 0.05)));
- font-size: 11px;
-}
-
-.network.panel .data-grid.small table.data {
- -webkit-background-size: 1px 42px;
-}
-
-.network.panel .data-grid td {
- line-height: 17px;
- border-right: 1px solid rgb(210, 210, 210);
- -webkit-user-select: none;
-}
-
-.network.panel .data-grid th {
- border-bottom: 1px solid rgb(64%, 64%, 64%);
- height: 22px;
-}
-
-.network.panel .data-grid th, .network.panel .data-grid th.sort-descending, .network.panel .data-grid th.sort-ascending {
- background: -webkit-gradient(linear, left top, left bottom, from(rgb(236, 236, 236)), to(rgb(217, 217, 217)));
-}
-
-.network.panel .data-grid .data-container {
- top: 23px;
-}
-
-.network.panel .data-grid td.url-column {
- font-weight: bold;
-}
-
-.network.panel .data-grid td.optional-column {
- background-color: rgba(0, 0, 0, 0.07);
-}
-
-.network.panel .small .network-graph-side {
- height: 14px;
-}
-
-.network.panel .data-grid th.sortable:active {
- background-image: none;
-}
-
-.network-grid-subtitle {
- font-weight: normal;
- color: grey;
-}
-
-.network.panel .data-grid.small .network-grid-subtitle {
- display: none;
-}
-
-/* Resource preview icons */
-
-.network.panel .data-grid .icon {
- content: url(Images/resourcePlainIcon.png);
-}
-
-.network.panel .data-grid.small .icon {
- content: url(Images/resourcePlainIconSmall.png);
-}
-
-.network.panel .network-category-scripts .icon {
- content: url(Images/resourceJSIcon.png);
-}
-
-.network.panel .data-grid.small .network-category-scripts .icon {
- content: url(Images/resourceDocumentIconSmall.png);
-}
-
-.network.panel .network-category-documents .icon {
- content: url(Images/resourceDocumentIcon.png);
-}
-
-.network.panel .data-grid.small .network-category-documents .icon {
- content: url(Images/resourceDocumentIconSmall.png);
-}
-
-.network.panel .network-category-stylesheets .icon {
- content: url(Images/resourceCSSIcon.png);
-}
-
-.network.panel .data-grid.small .network-category-stylesheets .icon {
- content: url(Images/resourceDocumentIconSmall.png);
-}
-
-.network.panel .network-category-images .icon {
- position: relative;
- background-image: url(Images/resourcePlainIcon.png);
- background-repeat: no-repeat;
- content: "";
-}
-
-.network.panel .network-category-images .icon {
- position: relative;
- background-image: url(Images/resourcePlainIcon.png);
- background-repeat: no-repeat;
- content: "";
-}
-
-.network.panel .data-grid.small .network-category-images .icon {
- background-image: url(Images/resourcePlainIconSmall.png);
- content: "";
-}
-
-.network.panel .data-grid .icon {
- float: left;
- width: 32px;
- height: 32px;
- margin-top: 1px;
- margin-right: 3px;
-}
-
-.network.panel .data-grid.small .icon {
- width: 16px;
- height: 16px;
-}
-
-.network.panel .image-network-icon-preview {
- position: absolute;
- margin: auto;
- top: 3px;
- bottom: 4px;
- left: 5px;
- right: 5px;
- max-width: 18px;
- max-height: 21px;
- min-width: 1px;
- min-height: 1px;
-}
-
-.network.panel .data-grid.small .image-network-icon-preview {
- top: 2px;
- bottom: 1px;
- left: 3px;
- right: 3px;
- max-width: 8px;
- max-height: 11px;
-}
-
-/* Graph styles */
-
-.network-graph-side {
- position: relative;
- height: 36px;
- padding: 0 5px;
- white-space: nowrap;
- margin-top: 1px;
- border-top: 1px solid transparent;
- overflow: hidden;
-}
-
-.network-graph-bar-area {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 8px;
- left: 9px;
-}
-
-.network-graph-label {
- position: absolute;
- top: 0;
- bottom: 0;
- margin: auto -7px;
- height: 13px;
- line-height: 13px;
- font-size: 9px;
- color: rgba(0, 0, 0, 0.75);
- text-shadow: rgba(255, 255, 255, 0.25) 1px 0 0, rgba(255, 255, 255, 0.25) -1px 0 0, rgba(255, 255, 255, 0.333) 0 1px 0, rgba(255, 255, 255, 0.25) 0 -1px 0;
- z-index: 150;
- overflow: hidden;
- text-align: center;
- font-weight: bold;
- opacity: 0;
- -webkit-transition: opacity 250ms ease-in-out;
-}
-
-.network-graph-side:hover .network-graph-label {
- opacity: 1;
-}
-
-.network-graph-label:empty {
- display: none;
-}
-
-.network-graph-label.waiting {
- margin-right: 5px;
-}
-
-.network-graph-label.waiting-right {
- margin-left: 5px;
-}
-
-.network-graph-label.before {
- color: rgba(0, 0, 0, 0.7);
- text-shadow: none;
- text-align: right;
- margin-right: 2px;
-}
-
-.network-graph-label.before::after {
- padding-left: 2px;
- height: 6px;
- content: url(Images/graphLabelCalloutLeft.png);
-}
-
-.network-graph-label.after {
- color: rgba(0, 0, 0, 0.7);
- text-shadow: none;
- text-align: left;
- margin-left: 2px;
-}
-
-.network-graph-label.after::before {
- padding-right: 2px;
- height: 6px;
- content: url(Images/graphLabelCalloutRight.png);
-}
-
-.network-graph-bar {
- position: absolute;
- top: 0;
- bottom: 0;
- margin: auto -7px;
- border-width: 6px 7px;
- height: 13px;
- min-width: 14px;
- opacity: 0.65;
- -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7;
-}
-
-.network-graph-bar.waiting, .network-graph-bar.waiting-right {
- opacity: 0.35;
-}
-
-/* Resource categories */
-
-
-.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7;
-}
-
-.network-category-documents .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillBlue.png) 6 7 6 7;
-}
-
-.network-category-documents.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillBlue.png) 6 7 6 7;
-}
-
-.network-category-stylesheets .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillGreen.png) 6 7 6 7;
-}
-
-.network-category-stylesheets.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillGreen.png) 6 7 6 7;
-}
-
-.network-category-images .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillPurple.png) 6 7 6 7;
-}
-
-.network-category-images.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillPurple.png) 6 7 6 7;
-}
-
-.network-category-fonts .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillRed.png) 6 7 6 7;
-}
-
-.network-category-fonts.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillRed.png) 6 7 6 7;
-}
-
-.network-category-scripts .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillOrange.png) 6 7 6 7;
-}
-
-.network-category-scripts.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillOrange.png) 6 7 6 7;
-}
-
-.network-category-xhr .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillYellow.png) 6 7 6 7;
-}
-
-.network-category-xhr.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillYellow.png) 6 7 6 7;
-}
-
-.network-category-websockets .network-graph-bar {
- -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7;
-}
-
-.network-category-websockets.resource-cached .network-graph-bar {
- -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7;
-}
-
-
-/* Popover */
-
-.network-timing-row {
- position: relative;
- height: 12px;
-}
-
-.network-timing-bar {
- position: absolute;
- background-color: red;
- border-left: 1px solid red;
- opacity: 0.4;
-}
-
-.network-timing-bar-title {
- position: absolute;
-}
-
-.network-dim-cell {
- color: grey;
-}
-
-/* Dividers */
-
-.network-timeline-grid {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
-}
-
-.network-event-divider-padding {
- position: absolute;
- width: 8px;
- top: 0;
- bottom: 0;
- pointer-events: auto;
-}
-
-.network-event-divider {
- position: absolute;
- width: 2px;
- top: 0;
- bottom: 0;
- z-index: 300;
-}
-
-.network-red-divider {
- background-color: rgba(255, 0, 0, 0.5);
-}
-
-.network-blue-divider {
- background-color: rgba(0, 0, 255, 0.5);
-}
-
-.network.panel .resources-dividers-label-bar {
- background-color: transparent;
- border: none;
- height: 23px;
- pointer-events: none;
-}
-
-.network.panel .resources-divider-label {
- top: 6px;
- color: black;
-}
+.network-larger-resources-status-bar-item .glyph { + -webkit-mask-image: url(Images/largerResourcesButtonGlyph.png); +} + +.network.panel .data-grid { + border: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + font-size: 11px; +} + +.network.panel .data-grid table.data { + -webkit-background-size: 1px 82px; + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), color-stop(0.5, rgba(0, 0, 0, 0)), color-stop(0.5, rgba(0, 0, 0, 0.05)), to(rgba(0, 0, 0, 0.05))); + font-size: 11px; +} + +.network.panel .data-grid.small table.data { + -webkit-background-size: 1px 42px; +} + +.network.panel .data-grid td { + line-height: 17px; + border-right: 1px solid rgb(210, 210, 210); + -webkit-user-select: none; + vertical-align: middle; +} + +.network.panel .data-grid th { + border-bottom: 1px solid rgb(64%, 64%, 64%); + height: 30px; + font-size: 11px; + font-weight: bold; +} + +.network.panel .data-grid.small th { + height: 22px; +} + +.network.panel .data-grid th, .network.panel .data-grid th.sort-descending, .network.panel .data-grid th.sort-ascending { + background: -webkit-gradient(linear, left top, left bottom, from(rgb(236, 236, 236)), to(rgb(217, 217, 217))); +} + +.network.panel .data-grid .data-container { + top: 31px; +} + +.network.panel .data-grid.small .data-container { + top: 23px; +} + +.network.panel .data-grid select { + -webkit-appearance: none; + background-color: transparent; + border: none; + width: 100%; + font-size: 11px; + font-weight: bold; +} + +.network.panel .data-grid tr.filler { + background-color: white; +} + +.network.panel .data-grid td.name-column { + font-weight: bold; +} + +.network.panel .data-grid td.method-column, +.network.panel .data-grid td.status-column, +.network.panel .data-grid td.type-column, +.network.panel .data-grid td.size-column, +.network.panel .data-grid td.time-column { + background-color: rgba(0, 0, 0, 0.07); +} + +.network.panel .data-grid td.size-column, +.network.panel .data-grid td.time-column { + text-align: right; +} + +.network.panel .small .network-graph-side { + height: 14px; +} + +.network.panel .data-grid th.sortable:active { + background-image: none; +} + +.network-cell-subtitle { + font-weight: normal; + color: grey; +} + +.network-header-subtitle { + color: grey; +} + +.network.panel .data-grid.small .network-cell-subtitle, +.network.panel .data-grid.small .network-header-subtitle +{ + display: none; +} + +/* Resource preview icons */ + +.network.panel .data-grid .icon { + content: url(Images/resourcePlainIcon.png); +} + +.network.panel .data-grid.small .icon { + content: url(Images/resourcePlainIconSmall.png); +} + +.network.panel .network-category-scripts .icon { + content: url(Images/resourceJSIcon.png); +} + +.network.panel .data-grid.small .network-category-scripts .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.network.panel .network-category-documents .icon { + content: url(Images/resourceDocumentIcon.png); +} + +.network.panel .data-grid.small .network-category-documents .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.network.panel .network-category-stylesheets .icon { + content: url(Images/resourceCSSIcon.png); +} + +.network.panel .data-grid.small .network-category-stylesheets .icon { + content: url(Images/resourceDocumentIconSmall.png); +} + +.network.panel .network-category-images .icon { + position: relative; + background-image: url(Images/resourcePlainIcon.png); + background-repeat: no-repeat; + content: ""; +} + +.network.panel .network-category-images .icon { + position: relative; + background-image: url(Images/resourcePlainIcon.png); + background-repeat: no-repeat; + content: ""; +} + +.network.panel .data-grid.small .network-category-images .icon { + background-image: url(Images/resourcePlainIconSmall.png); + content: ""; +} + +.network.panel .data-grid .icon { + float: left; + width: 32px; + height: 32px; + margin-top: 1px; + margin-right: 3px; +} + +.network.panel .data-grid.small .icon { + width: 16px; + height: 16px; +} + +.network.panel .image-network-icon-preview { + position: absolute; + margin: auto; + top: 3px; + bottom: 4px; + left: 5px; + right: 5px; + max-width: 18px; + max-height: 21px; + min-width: 1px; + min-height: 1px; +} + +.network.panel .data-grid.small .image-network-icon-preview { + top: 2px; + bottom: 1px; + left: 3px; + right: 3px; + max-width: 8px; + max-height: 11px; +} + +/* Graph styles */ + +.network-graph-side { + position: relative; + height: 36px; + padding: 0 5px; + white-space: nowrap; + margin-top: 1px; + border-top: 1px solid transparent; + overflow: hidden; +} + +.network-graph-bar-area { + position: absolute; + top: 0; + bottom: 0; + right: 8px; + left: 9px; +} + +.network-graph-label { + position: absolute; + top: 0; + bottom: 0; + margin: auto -7px; + height: 13px; + line-height: 13px; + font-size: 9px; + color: rgba(0, 0, 0, 0.75); + text-shadow: rgba(255, 255, 255, 0.25) 1px 0 0, rgba(255, 255, 255, 0.25) -1px 0 0, rgba(255, 255, 255, 0.333) 0 1px 0, rgba(255, 255, 255, 0.25) 0 -1px 0; + z-index: 150; + overflow: hidden; + text-align: center; + font-weight: bold; + opacity: 0; + -webkit-transition: opacity 250ms ease-in-out; +} + +.network-graph-side:hover .network-graph-label { + opacity: 1; +} + +.network-graph-label:empty { + display: none; +} + +.network-graph-label.waiting { + margin-right: 5px; +} + +.network-graph-label.waiting-right { + margin-left: 5px; +} + +.network-graph-label.before { + color: rgba(0, 0, 0, 0.7); + text-shadow: none; + text-align: right; + margin-right: 2px; +} + +.network-graph-label.before::after { + padding-left: 2px; + height: 6px; + content: url(Images/graphLabelCalloutLeft.png); +} + +.network-graph-label.after { + color: rgba(0, 0, 0, 0.7); + text-shadow: none; + text-align: left; + margin-left: 2px; +} + +.network-graph-label.after::before { + padding-right: 2px; + height: 6px; + content: url(Images/graphLabelCalloutRight.png); +} + +.network-graph-bar { + position: absolute; + top: 0; + bottom: 0; + margin: auto -7px; + border-width: 6px 7px; + height: 13px; + min-width: 14px; + opacity: 0.65; + -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7; +} + +.network-graph-bar.waiting, .network-graph-bar.waiting-right { + opacity: 0.35; +} + +/* Resource categories */ + + +.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7; +} + +.network-category-documents .network-graph-bar { + -webkit-border-image: url(Images/timelinePillBlue.png) 6 7 6 7; +} + +.network-category-documents.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillBlue.png) 6 7 6 7; +} + +.network-category-stylesheets .network-graph-bar { + -webkit-border-image: url(Images/timelinePillGreen.png) 6 7 6 7; +} + +.network-category-stylesheets.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillGreen.png) 6 7 6 7; +} + +.network-category-images .network-graph-bar { + -webkit-border-image: url(Images/timelinePillPurple.png) 6 7 6 7; +} + +.network-category-images.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillPurple.png) 6 7 6 7; +} + +.network-category-fonts .network-graph-bar { + -webkit-border-image: url(Images/timelinePillRed.png) 6 7 6 7; +} + +.network-category-fonts.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillRed.png) 6 7 6 7; +} + +.network-category-scripts .network-graph-bar { + -webkit-border-image: url(Images/timelinePillOrange.png) 6 7 6 7; +} + +.network-category-scripts.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillOrange.png) 6 7 6 7; +} + +.network-category-xhr .network-graph-bar { + -webkit-border-image: url(Images/timelinePillYellow.png) 6 7 6 7; +} + +.network-category-xhr.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillYellow.png) 6 7 6 7; +} + +.network-category-websockets .network-graph-bar { + -webkit-border-image: url(Images/timelinePillGray.png) 6 7 6 7; +} + +.network-category-websockets.resource-cached .network-graph-bar { + -webkit-border-image: url(Images/timelineHollowPillGray.png) 6 7 6 7; +} + + +/* Popover */ + +.network-timing-row { + position: relative; + height: 12px; +} + +.network-timing-bar { + position: absolute; + background-color: red; + border-left: 1px solid red; + opacity: 0.4; +} + +.network-timing-bar-title { + position: absolute; +} + +.network-dim-cell { + color: grey; +} + +/* Dividers */ + +.network-timeline-grid { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + pointer-events: none; +} + +.network-event-divider-padding { + position: absolute; + width: 8px; + top: 0; + bottom: 0; + pointer-events: auto; +} + +.network-event-divider { + position: absolute; + width: 2px; + top: 31px; + bottom: 0; + z-index: 300; +} + +.network.panel .network-timeline-grid.small .network-event-divider { + top: 23px; +} + +.network-red-divider { + background-color: rgba(255, 0, 0, 0.5); +} + +.network-blue-divider { + background-color: rgba(0, 0, 255, 0.5); +} + +.network.panel .resources-dividers-label-bar { + background-color: transparent; + border: none; + height: 30px; + pointer-events: none; +} + +.network.panel .network-timeline-grid.small .resources-dividers-label-bar { + height: 23px; +} + +.network.panel .resources-divider-label { + top: 0px; + margin-top: -4px; + color: black; +} + +.network.panel .resources-dividers-label-bar .resources-divider { + top: 23px; +} + +.network.panel .network-timeline-grid.small .resources-dividers-label-bar .resources-divider { + top: 15px; +} + +.network.panel .resources-divider.first .resources-divider-label { + display: none; +} + +.network.panel .resources-dividers-label-bar .resources-divider.first { + background-color: transparent; +} + +/* Filters */ +#network-filter { + margin-top: 1px; +} + +.data-grid table.data tr.revealed.network-category-documents, .data-grid table.data tr.revealed.network-category-stylesheets, +.data-grid table.data tr.revealed.network-category-images, .data-grid table.data tr.revealed.network-category-scripts, +.data-grid table.data tr.revealed.network-category-xhr, .data-grid table.data tr.revealed.network-category-fonts, +.data-grid table.data tr.revealed.network-category-websockets, .data-grid table.data tr.revealed.network-category-other { + display: none; +} + +.data-grid.filter-all table.data tr.revealed.network-category-documents, .data-grid.filter-documents table.data tr.revealed.network-category-documents, +.data-grid.filter-all table.data tr.revealed.network-category-stylesheets, .data-grid.filter-stylesheets table.data tr.revealed.network-category-stylesheets, +.data-grid.filter-all table.data tr.revealed.network-category-images, .data-grid.filter-images table.data tr.revealed.network-category-images, +.data-grid.filter-all table.data tr.revealed.network-category-scripts, .data-grid.filter-scripts table.data tr.revealed.network-category-scripts, +.data-grid.filter-all table.data tr.revealed.network-category-xhr, .data-grid.filter-xhr table.data tr.revealed.network-category-xhr, +.data-grid.filter-all table.data tr.revealed.network-category-fonts, .data-grid.filter-fonts table.data tr.revealed.network-category-fonts, +.data-grid.filter-all table.data tr.revealed.network-category-websockets, .data-grid.filter-websockets table.data tr.revealed.network-category-websockets, +.data-grid.filter-all table.data tr.revealed.network-category-other, .data-grid.filter-other table.data tr.revealed.network-category-other { + display: table-row; +} + +/* Summary */ + +.network-summary-bar { + background-color: rgb(101, 111, 130); + color: white; + height: 20px; + font-size: 11px; + font-weight: bold; + padding-top: 1px; + padding-left: 10px; + z-index: 2000; + white-space: pre; +} + +.network-summary-bar-bottom { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding-top: 3px; +} + +.data-grid td .network-summary-bar { + white-space: pre; +} + +.network.panel .data-grid td.network-summary { + padding: 0; +} + +/* Viewer */ + +.network.panel.viewing-resource .data-grid td, +.network.panel.viewing-resource .data-grid th { + border-right: none; +} + +.network.panel.viewing-resource .data-grid th.corner { + display: none; +} + +#network-container { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + border-right: 0 none transparent; + overflow-y: auto; + overflow-x: hidden; +} + +.network.panel.viewing-resource #network-container { + border-right: 1px solid rgb(163, 163, 163); +} + +#network-views { + position: absolute; + background: rgb(203, 203, 203); + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.network.panel .data-grid.full-grid-mode .viewer-column { + display: none; +} + +.network.panel .data-grid.brief-grid-mode .viewer-column, +.network.panel .data-grid.brief-grid-mode .method-column, +.network.panel .data-grid.brief-grid-mode .status-column, +.network.panel .data-grid.brief-grid-mode .type-column, +.network.panel .data-grid.brief-grid-mode .size-column, +.network.panel .data-grid.brief-grid-mode .time-column { + display: none; +} + +.network.panel.viewing-resource .network-timeline-grid { + display: none; +} + +.network.panel .data-grid.viewing-resource-mode .method-column, +.network.panel .data-grid.viewing-resource-mode .status-column, +.network.panel .data-grid.viewing-resource-mode .type-column, +.network.panel .data-grid.viewing-resource-mode .size-column, +.network.panel .data-grid.viewing-resource-mode .time-column, +.network.panel .data-grid.viewing-resource-mode .timeline-column { + display: none; +} + +.network.panel .network-sidebar { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.network.panel:not(.viewing-resource) .sidebar-resizer-vertical { + display: none; +} + +.network.panel.viewing-resource .data-grid-resizer { + display: none; +} + +.network.panel .scope-bar { + height: 23px; + padding-top: 5px; +} + +.network.panel .resource-view.headers-visible .resource-view-content { + top: 23px; +} + +.network.panel:not(.viewing-resource) .data-grid tr.selected { + background-color: transparent; + color: black; +} + +.network.panel .resource-view .tabbed-pane-header { + height: 23px; + padding-top: 3px; +} + +.network.panel.viewing-resource .data-grid .data-container { + padding-right: 0; +} diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index 5e41da6..3aff6bb 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -26,19 +26,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -Object.properties = function(obj) -{ - var properties = []; - for (var prop in obj) - properties.push(prop); - return properties; -} - -Object.sortedProperties = function(obj, sortFunc) -{ - return Object.properties(obj).sort(sortFunc); -} - Function.prototype.bind = function(thisObject) { var func = this; @@ -393,6 +380,26 @@ String.prototype.hasSubstring = function(string, caseInsensitive) return this.match(new RegExp(string.escapeForRegExp(), "i")); } +String.prototype.asParsedURL = function() +{ + // RegExp groups: + // 1 - scheme + // 2 - hostname + // 3 - ?port + // 4 - ?path + // 5 - ?fragment + var match = this.match(/^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i); + if (!match) + return null; + var result = {}; + result.scheme = match[1].toLowerCase(); + result.host = match[2]; + result.port = match[3]; + result.path = match[4] || "/"; + result.fragment = match[5]; + return result; +} + String.prototype.escapeCharacters = function(chars) { var foundChar = false; @@ -990,6 +997,6 @@ function offerFileForDownload(contents) var builder = new BlobBuilder(); builder.append(contents); var blob = builder.getBlob("application/octet-stream"); - var url = window.createBlobURL(blob); + var url = window.createObjectURL(blob); window.open(url); } |