diff options
author | Kristian Monsen <kristianm@google.com> | 2010-09-30 15:42:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-10-07 10:59:29 +0100 |
commit | bec39347bb3bb5bf1187ccaf471d26247f28b585 (patch) | |
tree | 56bdc4c2978fbfd3d79d0d36d5d6c640ecc09cc8 /WebCore/inspector | |
parent | 90b7966e7815b262cd19ac25f03aaad9b21fdc06 (diff) | |
download | external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.zip external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.tar.gz external_webkit-bec39347bb3bb5bf1187ccaf471d26247f28b585.tar.bz2 |
Merge WebKit at r68651 : Initial merge by git.
Change-Id: I3d6bff59f17eedd6722723354f386fec9be8ad12
Diffstat (limited to 'WebCore/inspector')
32 files changed, 3008 insertions, 735 deletions
diff --git a/WebCore/inspector/Inspector.idl b/WebCore/inspector/Inspector.idl index ae136b2..a08a622 100644 --- a/WebCore/inspector/Inspector.idl +++ b/WebCore/inspector/Inspector.idl @@ -37,9 +37,11 @@ module core { [notify] void addNodesToSearchResult(out Array nodeIds); [notify] void attributesUpdated(out long id, out Array attributes); [notify] void bringToFront(); + [notify] void characterDataModified(out long id, out String newValue); [notify] void childNodeCountUpdated(out long id, out int newValue); [notify] void childNodeInserted(out long parentId, out long prevId, out Object node); [notify] void childNodeRemoved(out long parentId, out long id); + [notify] void consoleMessagesCleared(); [notify] void didCommitLoad(); [notify] void evaluateForTestInFrontend(out long testCallId, out String script); [notify] void disconnectFromBackend(); @@ -47,8 +49,6 @@ module core { [notify] void removeResource(out unsigned long identifier); [notify] void reset(); [notify] void resetProfilesPanel(); - [notify] void searchingForNodeWasEnabled(); - [notify] void searchingForNodeWasDisabled(); [notify] void setChildNodes(out long parentId, out Array nodes); [notify] void setDetachedRoot(out Object root); [notify] void setDocument(out Value root); @@ -59,7 +59,6 @@ module core { [notify] void updateConsoleMessageRepeatCount(out unsigned long count); [notify] void updateFocusedNode(out long nodeId); [notify] void updateResource(out Value resource); - [notify] void consoleMessagesCleared(); #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [notify] void addProfileHeader(out Object header); @@ -104,8 +103,7 @@ module core { [handler=Controller] void saveApplicationSettings(in String settings); [handler=Controller] void saveSessionSettings(in String settings); - [handler=Controller] void enableSearchingForNode(); - [handler=Controller] void disableSearchingForNode(); + [handler=Controller] void setSearchingForNode(in boolean enabled, out boolean newState); [handler=Controller] void setMonitoringXHREnabled(in boolean enable, out boolean newState); @@ -132,11 +130,14 @@ module core { [handler=Debug] void stepIntoStatement(); [handler=Debug] void stepOutOfFunction(); - [handler=Debug] void setPauseOnExceptionsState(in long pauseOnExceptionsState); + [handler=Debug] void setPauseOnExceptionsState(in long pauseOnExceptionsState, out long newState); [handler=Debug] void editScriptSource(in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames); [handler=Debug] void getScriptSource(in String sourceID, out String scriptSource); + [handler=Controller] void setNativeBreakpoint(in Object breakpoint, out unsigned int breakpointId); + [handler=Controller] void removeNativeBreakpoint(in unsigned int breakpointId); + [handler=Controller] void enableProfiler(in boolean always); [handler=Controller] void disableProfiler(in boolean always); diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index 5f8f190..f2ee2c1 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -111,10 +111,6 @@ #include "StorageArea.h" #endif -#if ENABLE(JAVASCRIPT_DEBUGGER) -#include "ScriptDebugServer.h" -#endif - using namespace std; namespace WebCore { @@ -127,9 +123,11 @@ static const char* const monitoringXHRSettingName = "xhrMonitor"; static const char* const resourceTrackingAlwaysEnabledSettingName = "resourceTrackingEnabled"; static const char* const profilerAlwaysEnabledSettingName = "profilerEnabled"; -static const char* const timelineProfilerEnabledStateName = "timelineProfilerEnabled"; -static const char* const resourceTrackingEnabledStateName = "resourceTrackingEnabled"; static const char* const monitoringXHRStateName = "monitoringXHREnabled"; +static const char* const resourceTrackingEnabledStateName = "resourceTrackingEnabled"; +static const char* const searchingForNodeEnabledStateName = "searchingForNodeEnabled"; +static const char* const timelineProfilerEnabledStateName = "timelineProfilerEnabled"; +static const char* const pauseOnExceptionsStateStateName = "pauseOnExceptionsState"; static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight"; @@ -153,7 +151,7 @@ static const float maximumAttachedHeightRatio = 0.75f; static const unsigned maximumConsoleMessages = 1000; static const unsigned expireConsoleMessagesStep = 100; -static unsigned s_inspectorControllerCount; +unsigned InspectorController::s_inspectorControllerCount = 0; InspectorController::InspectorController(Page* page, InspectorClient* client) : m_inspectedPage(page) @@ -174,6 +172,7 @@ InspectorController::InspectorController(Page* page, InspectorClient* client) , m_injectedScriptHost(InjectedScriptHost::create(this)) #if ENABLE(JAVASCRIPT_DEBUGGER) , m_attachDebuggerWhenShown(false) + , m_lastBreakpointId(0) , m_profilerAgent(InspectorProfilerAgent::create(this)) #endif { @@ -256,6 +255,10 @@ void InspectorController::getInspectorState(RefPtr<InspectorObject>* state) { (*state)->setBoolean(monitoringXHRStateName, m_monitoringXHR); (*state)->setBoolean(resourceTrackingEnabledStateName, m_resourceTrackingEnabled); +#if ENABLE(JAVASCRIPT_DEBUGGER) + if (m_debuggerAgent) + (*state)->setNumber(pauseOnExceptionsStateStateName, m_debuggerAgent->pauseOnExceptionsState()); +#endif } void InspectorController::updateInspectorStateCookie() @@ -264,6 +267,7 @@ void InspectorController::updateInspectorStateCookie() state->setBoolean(monitoringXHRStateName, m_monitoringXHR); state->setBoolean(resourceTrackingEnabledStateName, m_resourceTrackingEnabled); state->setBoolean(timelineProfilerEnabledStateName, m_timelineAgent); + state->setBoolean(searchingForNodeEnabledStateName, m_searchingForNode); m_client->updateInspectorStateCookie(state->toJSONString()); } @@ -279,6 +283,7 @@ void InspectorController::restoreInspectorStateFromCookie(const String& inspecto inspectorState->getBoolean(monitoringXHRStateName, &m_monitoringXHR); inspectorState->getBoolean(resourceTrackingEnabledStateName, &m_resourceTrackingEnabled); + inspectorState->getBoolean(searchingForNodeEnabledStateName, &m_searchingForNode); bool timelineProfilerEnabled = false; inspectorState->getBoolean(timelineProfilerEnabledStateName, &timelineProfilerEnabled); @@ -492,12 +497,13 @@ void InspectorController::setSearchingForNode(bool enabled) m_searchingForNode = enabled; if (!m_searchingForNode) hideHighlight(); - if (m_frontend) { - if (enabled) - m_frontend->searchingForNodeWasEnabled(); - else - m_frontend->searchingForNodeWasDisabled(); - } + updateInspectorStateCookie(); +} + +void InspectorController::setSearchingForNode(bool enabled, bool* newState) +{ + *newState = enabled; + setSearchingForNode(enabled); } void InspectorController::setMonitoringXHREnabled(bool enabled, bool* newState) @@ -650,10 +656,6 @@ void InspectorController::populateScriptObjects() showPanel(m_showAfterVisible); - if (m_searchingForNode) - m_frontend->searchingForNodeWasEnabled(); - - #if ENABLE(JAVASCRIPT_DEBUGGER) if (m_profilerAgent->enabled()) m_frontend->profilerWasEnabled(); @@ -674,10 +676,6 @@ void InspectorController::populateScriptObjects() for (unsigned i = 0; i < messageCount; ++i) m_consoleMessages[i]->addToFrontend(m_frontend.get(), m_injectedScriptHost.get()); -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (debuggerEnabled()) - m_frontend->updatePauseOnExceptionsState(ScriptDebugServer::shared().pauseOnExceptionsState()); -#endif #if ENABLE(DATABASE) DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end(); for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) @@ -790,6 +788,8 @@ void InspectorController::didCommitLoad(DocumentLoader* loader) #if ENABLE(JAVASCRIPT_DEBUGGER) if (m_debuggerAgent) m_debuggerAgent->clearForPageNavigation(); + + m_XHRBreakpoints.clear(); #endif #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) m_profilerAgent->resetState(); @@ -1672,6 +1672,29 @@ void InspectorController::resume() m_debuggerAgent->resume(); } +void InspectorController::setNativeBreakpoint(PassRefPtr<InspectorObject> breakpoint, unsigned int* breakpointId) +{ + *breakpointId = 0; + String type; + if (!breakpoint->getString("type", &type)) + return; + if (type == "XHR") { + RefPtr<InspectorObject> condition = breakpoint->getObject("condition"); + if (!condition) + return; + String url; + if (!condition->getString("url", &url)) + return; + *breakpointId = ++m_lastBreakpointId; + m_XHRBreakpoints.set(*breakpointId, url); + } +} + +void InspectorController::removeNativeBreakpoint(unsigned int breakpointId) +{ + m_XHRBreakpoints.remove(breakpointId); +} + #endif void InspectorController::evaluateForTestInFrontend(long callId, const String& script) @@ -2085,9 +2108,9 @@ void InspectorController::willInsertDOMNodeImpl(Node* node, Node* parent) #if ENABLE(JAVASCRIPT_DEBUGGER) if (!m_debuggerAgent || !m_domAgent) return; - PassRefPtr<InspectorValue> details; - if (m_domAgent->shouldBreakOnNodeInsertion(node, parent, &details)) - m_debuggerAgent->breakProgram(details); + PassRefPtr<InspectorValue> eventData; + if (m_domAgent->shouldBreakOnNodeInsertion(node, parent, &eventData)) + m_debuggerAgent->breakProgram(DOMBreakpointDebuggerEventType, eventData); #endif } @@ -2102,9 +2125,9 @@ void InspectorController::willRemoveDOMNodeImpl(Node* node) #if ENABLE(JAVASCRIPT_DEBUGGER) if (!m_debuggerAgent || !m_domAgent) return; - PassRefPtr<InspectorValue> details; - if (m_domAgent->shouldBreakOnNodeRemoval(node, &details)) - m_debuggerAgent->breakProgram(details); + PassRefPtr<InspectorValue> eventData; + if (m_domAgent->shouldBreakOnNodeRemoval(node, &eventData)) + m_debuggerAgent->breakProgram(DOMBreakpointDebuggerEventType, eventData); #endif } @@ -2119,9 +2142,9 @@ void InspectorController::willModifyDOMAttrImpl(Element* element) #if ENABLE(JAVASCRIPT_DEBUGGER) if (!m_debuggerAgent || !m_domAgent) return; - PassRefPtr<InspectorValue> details; - if (m_domAgent->shouldBreakOnAttributeModification(element, &details)) - m_debuggerAgent->breakProgram(details); + PassRefPtr<InspectorValue> eventData; + if (m_domAgent->shouldBreakOnAttributeModification(element, &eventData)) + m_debuggerAgent->breakProgram(DOMBreakpointDebuggerEventType, eventData); #endif } @@ -2131,6 +2154,31 @@ void InspectorController::didModifyDOMAttrImpl(Element* element) m_domAgent->didModifyDOMAttr(element); } +void InspectorController::characterDataModifiedImpl(CharacterData* characterData) +{ + if (m_domAgent) + m_domAgent->characterDataModified(characterData); +} + +void InspectorController::instrumentWillSendXMLHttpRequestImpl(const KURL& url) +{ +#if ENABLE(JAVASCRIPT_DEBUGGER) + if (m_debuggerAgent) { + if (!m_XHRBreakpoints.size()) + return; + for (HashMap<unsigned int, String>::iterator it = m_XHRBreakpoints.begin(); it != m_XHRBreakpoints.end(); ++it) { + if (!url.string().contains(it->second)) + continue; + RefPtr<InspectorObject> eventData = InspectorObject::create(); + eventData->setString("type", "XHR"); + eventData->setString("url", url); + m_debuggerAgent->breakProgram(NativeBreakpointDebuggerEventType, eventData); + break; + } + } +#endif +} + } // namespace WebCore diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h index 6752044..9e63f01 100644 --- a/WebCore/inspector/InspectorController.h +++ b/WebCore/inspector/InspectorController.h @@ -29,6 +29,7 @@ #ifndef InspectorController_h #define InspectorController_h +#include "CharacterData.h" #include "Console.h" #include "Cookie.h" #include "Element.h" @@ -45,6 +46,7 @@ namespace WebCore { class CachedResource; +class CharacterData; class ConsoleMessage; class Database; class Document; @@ -201,6 +203,9 @@ public: static void willRemoveDOMNode(Node*); static void willModifyDOMAttr(Element*); static void didModifyDOMAttr(Element*); + static void characterDataModified(CharacterData*); + + static void instrumentWillSendXMLHttpRequest(ScriptExecutionContext*, const KURL&); #if ENABLE(WORKERS) enum WorkerAction { WorkerCreated, WorkerDestroyed }; @@ -264,6 +269,10 @@ public: bool debuggerEnabled() const { return m_debuggerAgent; } InspectorDebuggerAgent* debuggerAgent() const { return m_debuggerAgent.get(); } void resume(); + + void setNativeBreakpoint(PassRefPtr<InspectorObject> breakpoint, unsigned int* breakpointId); + void removeNativeBreakpoint(unsigned int breakpointId); + #endif void evaluateForTestInFrontend(long testCallId, const String& script); @@ -288,11 +297,10 @@ private: void restoreDebugger(); void restoreProfiler(); void unbindAllResources(); + void setSearchingForNode(bool enabled); // Following are used from InspectorBackend and internally. - void setSearchingForNode(bool enabled); - void enableSearchingForNode() { setSearchingForNode(true); } - void disableSearchingForNode() { setSearchingForNode(false); } + void setSearchingForNode(bool enabled, bool* newState); void setMonitoringXHREnabled(bool enabled, bool* newState); void storeLastActivePanel(const String& panelName); @@ -331,13 +339,19 @@ private: void didEvaluateForTestInFrontend(long callId, const String& jsonResult); + static InspectorController* inspectorControllerForScriptExecutionContext(ScriptExecutionContext* context); static InspectorController* inspectorControllerForNode(Node*); + static InspectorController* inspectorControllerForDocument(Document* document); + void willInsertDOMNodeImpl(Node* node, Node* parent); void didInsertDOMNodeImpl(Node*); void willRemoveDOMNodeImpl(Node*); void didRemoveDOMNodeImpl(Node*); void willModifyDOMAttrImpl(Element*); void didModifyDOMAttrImpl(Element*); + void characterDataModifiedImpl(CharacterData*); + + void instrumentWillSendXMLHttpRequestImpl(const KURL&); #if ENABLE(JAVASCRIPT_DEBUGGER) friend class InspectorDebuggerAgent; @@ -346,6 +360,8 @@ private: void saveBreakpoints(PassRefPtr<InspectorObject> breakpoints); #endif + static unsigned s_inspectorControllerCount; + Page* m_inspectedPage; InspectorClient* m_client; OwnPtr<InspectorFrontendClient> m_inspectorFrontendClient; @@ -400,6 +416,9 @@ private: bool m_attachDebuggerWhenShown; OwnPtr<InspectorDebuggerAgent> m_debuggerAgent; + HashMap<unsigned int, String> m_XHRBreakpoints; + unsigned int m_lastBreakpointId; + OwnPtr<InspectorProfilerAgent> m_profilerAgent; #endif #if ENABLE(WORKERS) @@ -451,18 +470,48 @@ inline void InspectorController::didModifyDOMAttr(Element* element) #endif } -inline InspectorController* InspectorController::inspectorControllerForNode(Node* node) +inline void InspectorController::characterDataModified(CharacterData* characterData) { #if ENABLE(INSPECTOR) - if (Page* page = node->document()->page()) { - if (InspectorController* inspectorController = page->inspectorController()) { - if (inspectorController->hasFrontend()) - return inspectorController; - } - } + if (InspectorController* inspectorController = inspectorControllerForNode(characterData)) + inspectorController->characterDataModifiedImpl(characterData); #endif +} - return 0; +inline void InspectorController::instrumentWillSendXMLHttpRequest(ScriptExecutionContext* context, const KURL& url) +{ +#if ENABLE(INSPECTOR) + if (InspectorController* inspectorController = inspectorControllerForScriptExecutionContext(context)) + inspectorController->instrumentWillSendXMLHttpRequestImpl(url); +#endif +} + +inline InspectorController* InspectorController::inspectorControllerForScriptExecutionContext(ScriptExecutionContext* context) +{ + if (!s_inspectorControllerCount || !context || !context->isDocument()) + return 0; + return inspectorControllerForDocument(static_cast<Document*>(context)); +} + +inline InspectorController* InspectorController::inspectorControllerForNode(Node* node) +{ + if (!s_inspectorControllerCount) + return 0; + return inspectorControllerForDocument(node->document()); +} + +inline InspectorController* InspectorController::inspectorControllerForDocument(Document* document) +{ + ASSERT(document); + Page* page = document->page(); + if (!page) + return 0; + InspectorController* inspectorController = page->inspectorController(); + if (!inspectorController) + return 0; + if (!inspectorController->hasFrontend()) + return 0; + return inspectorController; } } // namespace WebCore diff --git a/WebCore/inspector/InspectorDOMAgent.cpp b/WebCore/inspector/InspectorDOMAgent.cpp index f1df5b0..f51da73 100644 --- a/WebCore/inspector/InspectorDOMAgent.cpp +++ b/WebCore/inspector/InspectorDOMAgent.cpp @@ -43,6 +43,7 @@ #include "CSSStyleRule.h" #include "CSSStyleSelector.h" #include "CSSStyleSheet.h" +#include "CharacterData.h" #include "ContainerNode.h" #include "Cookie.h" #include "CookieJar.h" @@ -1120,6 +1121,14 @@ void InspectorDOMAgent::didModifyDOMAttr(Element* element) m_frontend->attributesUpdated(id, buildArrayForElementAttributes(element)); } +void InspectorDOMAgent::characterDataModified(CharacterData* characterData) +{ + long id = m_documentNodeToIdMap.get(characterData); + if (!id) + return; + m_frontend->characterDataModified(id, characterData->data()); +} + bool InspectorDOMAgent::hasBreakpoint(Node* node, long type) { uint32_t rootBit = 1 << type; diff --git a/WebCore/inspector/InspectorDOMAgent.h b/WebCore/inspector/InspectorDOMAgent.h index 7d86997..89c6fd0 100644 --- a/WebCore/inspector/InspectorDOMAgent.h +++ b/WebCore/inspector/InspectorDOMAgent.h @@ -53,6 +53,7 @@ namespace WebCore { class CSSStyleDeclaration; class CSSStyleRule; class CSSStyleSheet; + class CharacterData; class Element; class Event; class InspectorDOMAgent; @@ -139,6 +140,7 @@ namespace WebCore { void didInsertDOMNode(Node*); void didRemoveDOMNode(Node*); void didModifyDOMAttr(Element*); + void characterDataModified(CharacterData*); Node* nodeForId(long nodeId); long pushNodePathToFrontend(Node* node); diff --git a/WebCore/inspector/InspectorDebuggerAgent.cpp b/WebCore/inspector/InspectorDebuggerAgent.cpp index 3875be0..4964c09 100644 --- a/WebCore/inspector/InspectorDebuggerAgent.cpp +++ b/WebCore/inspector/InspectorDebuggerAgent.cpp @@ -64,7 +64,6 @@ InspectorDebuggerAgent::InspectorDebuggerAgent(InspectorController* inspectorCon , m_frontend(frontend) , m_pausedScriptState(0) , m_breakpointsLoaded(false) - , m_breakProgramReason(InspectorValue::null()) { } @@ -173,10 +172,15 @@ void InspectorDebuggerAgent::stepOutOfFunction() ScriptDebugServer::shared().stepOutOfFunction(); } -void InspectorDebuggerAgent::setPauseOnExceptionsState(long pauseState) +void InspectorDebuggerAgent::setPauseOnExceptionsState(long pauseState, long* newState) { ScriptDebugServer::shared().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState)); - m_frontend->updatePauseOnExceptionsState(ScriptDebugServer::shared().pauseOnExceptionsState()); + *newState = ScriptDebugServer::shared().pauseOnExceptionsState(); +} + +long InspectorDebuggerAgent::pauseOnExceptionsState() +{ + return ScriptDebugServer::shared().pauseOnExceptionsState(); } void InspectorDebuggerAgent::clearForPageNavigation() @@ -289,12 +293,13 @@ void InspectorDebuggerAgent::failedToParseSource(const String& url, const String void InspectorDebuggerAgent::didPause(ScriptState* scriptState) { ASSERT(scriptState && !m_pausedScriptState); - ASSERT(m_breakProgramReason); m_pausedScriptState = scriptState; - RefPtr<InspectorObject> details = InspectorObject::create(); - details->setValue("callFrames", currentCallFrames()); - details->setValue("status", m_breakProgramReason); - m_frontend->pausedScript(details); + + if (!m_breakProgramDetails) + m_breakProgramDetails = InspectorObject::create(); + m_breakProgramDetails->setValue("callFrames", currentCallFrames()); + + m_frontend->pausedScript(m_breakProgramDetails); } void InspectorDebuggerAgent::didContinue() @@ -303,17 +308,19 @@ void InspectorDebuggerAgent::didContinue() m_frontend->resumedScript(); } -void InspectorDebuggerAgent::breakProgram(PassRefPtr<InspectorValue> reason) +void InspectorDebuggerAgent::breakProgram(DebuggerEventType type, PassRefPtr<InspectorValue> data) { + m_breakProgramDetails = InspectorObject::create(); + m_breakProgramDetails->setNumber("eventType", type); + m_breakProgramDetails->setValue("eventData", data); s_debuggerAgentOnBreakpoint = this; - m_breakProgramReason = reason; ScriptDebugServer::shared().breakProgram(); if (!s_debuggerAgentOnBreakpoint) return; s_debuggerAgentOnBreakpoint = 0; - m_breakProgramReason = InspectorValue::null(); + m_breakProgramDetails = 0; } } // namespace WebCore diff --git a/WebCore/inspector/InspectorDebuggerAgent.h b/WebCore/inspector/InspectorDebuggerAgent.h index 79b0a0e..8a5379d 100644 --- a/WebCore/inspector/InspectorDebuggerAgent.h +++ b/WebCore/inspector/InspectorDebuggerAgent.h @@ -43,8 +43,14 @@ namespace WebCore { class InjectedScriptHost; class InspectorController; class InspectorFrontend; +class InspectorObject; class InspectorValue; +enum DebuggerEventType { + DOMBreakpointDebuggerEventType, + NativeBreakpointDebuggerEventType +}; + class InspectorDebuggerAgent : public ScriptDebugListener, public Noncopyable { public: static PassOwnPtr<InspectorDebuggerAgent> create(InspectorController*, InspectorFrontend*); @@ -61,13 +67,14 @@ public: void getScriptSource(const String& sourceID, String* scriptSource); void pause(); - void breakProgram(PassRefPtr<InspectorValue> reason); + void breakProgram(DebuggerEventType type, PassRefPtr<InspectorValue> data); void resume(); void stepOverStatement(); void stepIntoStatement(); void stepOutOfFunction(); - void setPauseOnExceptionsState(long pauseState); + void setPauseOnExceptionsState(long pauseState, long* newState); + long pauseOnExceptionsState(); void clearForPageNavigation(); @@ -95,7 +102,7 @@ private: HashMap<String, unsigned> m_breakpointsMapping; bool m_breakpointsLoaded; static InspectorDebuggerAgent* s_debuggerAgentOnBreakpoint; - RefPtr<InspectorValue> m_breakProgramReason; + RefPtr<InspectorObject> m_breakProgramDetails; }; } // namespace WebCore diff --git a/WebCore/inspector/front-end/AbstractTimelinePanel.js b/WebCore/inspector/front-end/AbstractTimelinePanel.js deleted file mode 100644 index 187ef86..0000000 --- a/WebCore/inspector/front-end/AbstractTimelinePanel.js +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org> - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -WebInspector.AbstractTimelinePanel = function(name) -{ - WebInspector.Panel.call(this, name); - this._items = []; - this._staleItems = []; -} - -WebInspector.AbstractTimelinePanel.prototype = { - get categories() - { - // Should be implemented by the concrete subclasses. - return {}; - }, - - populateSidebar: function() - { - // Should be implemented by the concrete subclasses. - }, - - createItemTreeElement: function(item) - { - // Should be implemented by the concrete subclasses. - }, - - createItemGraph: function(item) - { - // Should be implemented by the concrete subclasses. - }, - - get items() - { - return this._items; - }, - - createInterface: function() - { - this.containerElement = document.createElement("div"); - this.containerElement.id = "resources-container"; - this.containerElement.addEventListener("scroll", this._updateDividersLabelBarPosition.bind(this), false); - this.element.appendChild(this.containerElement); - - this.createSidebar(this.containerElement, this.element); - this.sidebarElement.id = "resources-sidebar"; - this.populateSidebar(); - - this._containerContentElement = document.createElement("div"); - this._containerContentElement.id = "resources-container-content"; - this.containerElement.appendChild(this._containerContentElement); - - this.summaryBar = new WebInspector.SummaryBar(this.categories); - this.summaryBar.element.id = "resources-summary"; - this._containerContentElement.appendChild(this.summaryBar.element); - - this._timelineGrid = new WebInspector.TimelineGrid(); - this._containerContentElement.appendChild(this._timelineGrid.element); - this.itemsGraphsElement = this._timelineGrid.itemsGraphsElement; - }, - - createFilterPanel: function() - { - this.filterBarElement = document.createElement("div"); - this.filterBarElement.id = "resources-filter"; - this.filterBarElement.className = "scope-bar"; - this.element.appendChild(this.filterBarElement); - - function createFilterElement(category) - { - if (category === "all") - var label = WebInspector.UIString("All"); - else if (this.categories[category]) - var label = this.categories[category].title; - - var categoryElement = document.createElement("li"); - categoryElement.category = category; - categoryElement.addStyleClass(category); - categoryElement.appendChild(document.createTextNode(label)); - categoryElement.addEventListener("click", this._updateFilter.bind(this), false); - this.filterBarElement.appendChild(categoryElement); - - return categoryElement; - } - - this.filterAllElement = createFilterElement.call(this, "all"); - - // Add a divider - var dividerElement = document.createElement("div"); - dividerElement.addStyleClass("divider"); - this.filterBarElement.appendChild(dividerElement); - - for (var category in this.categories) - createFilterElement.call(this, category); - }, - - showCategory: function(category) - { - var filterClass = "filter-" + category.toLowerCase(); - this.itemsGraphsElement.addStyleClass(filterClass); - this.itemsTreeElement.childrenListElement.addStyleClass(filterClass); - }, - - hideCategory: function(category) - { - var filterClass = "filter-" + category.toLowerCase(); - this.itemsGraphsElement.removeStyleClass(filterClass); - this.itemsTreeElement.childrenListElement.removeStyleClass(filterClass); - }, - - 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 === 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); - } - }, - - _updateFilter: function(e) - { - var isMac = WebInspector.isMac(); - var selectMultiple = false; - if (isMac && e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) - selectMultiple = true; - if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey) - selectMultiple = true; - - this.filter(e.target, selectMultiple); - - // 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; - - var searchField = document.getElementById("search"); - WebInspector.doPerformSearch(searchField.value, WebInspector.shortSearchWasForcedByKeyEvent, false, true); - }, - - updateGraphDividersIfNeeded: function(force) - { - if (!this.visible) { - this.needsRefresh = true; - return false; - } - return this._timelineGrid.updateDividers(force, this.calculator); - }, - - _updateDividersLabelBarPosition: function() - { - const scrollTop = this.containerElement.scrollTop; - const offsetHeight = this.summaryBar.element.offsetHeight; - const dividersTop = (scrollTop < offsetHeight ? offsetHeight : scrollTop); - this._timelineGrid.setScrollAndDividerTop(scrollTop, dividersTop); - }, - - get needsRefresh() - { - return this._needsRefresh; - }, - - set needsRefresh(x) - { - if (this._needsRefresh === x) - return; - - this._needsRefresh = x; - - if (x) { - if (this.visible && !("_refreshTimeout" in this)) - this._refreshTimeout = setTimeout(this.refresh.bind(this), 500); - } else { - if ("_refreshTimeout" in this) { - clearTimeout(this._refreshTimeout); - delete this._refreshTimeout; - } - } - }, - - refreshIfNeeded: function() - { - if (this.needsRefresh) - this.refresh(); - }, - - show: function() - { - WebInspector.Panel.prototype.show.call(this); - - this._updateDividersLabelBarPosition(); - this.refreshIfNeeded(); - }, - - resize: function() - { - WebInspector.Panel.prototype.resize.call(this); - - this.updateGraphDividersIfNeeded(); - }, - - updateMainViewWidth: function(width) - { - this._containerContentElement.style.left = width + "px"; - this.resize(); - }, - - invalidateAllItems: function() - { - this._staleItems = this._items.slice(); - }, - - refresh: function() - { - this.needsRefresh = false; - - var staleItemsLength = this._staleItems.length; - - var boundariesChanged = false; - - for (var i = 0; i < staleItemsLength; ++i) { - var item = this._staleItems[i]; - if (!item._itemsTreeElement) { - // Create the timeline tree element and graph. - item._itemsTreeElement = this.createItemTreeElement(item); - item._itemsTreeElement._itemGraph = this.createItemGraph(item); - - this.itemsTreeElement.appendChild(item._itemsTreeElement); - this.itemsGraphsElement.appendChild(item._itemsTreeElement._itemGraph.graphElement); - } - - if (item._itemsTreeElement.refresh) - item._itemsTreeElement.refresh(); - - if (this.calculator.updateBoundaries(item)) - boundariesChanged = true; - } - - if (boundariesChanged) { - // The boundaries changed, so all item graphs are stale. - this._staleItems = this._items.slice(); - staleItemsLength = this._staleItems.length; - } - - - const isBarOpaqueAtLeft = this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.isBarOpaqueAtLeft; - for (var i = 0; i < staleItemsLength; ++i) - this._staleItems[i]._itemsTreeElement._itemGraph.refresh(this.calculator, isBarOpaqueAtLeft); - - this._staleItems = []; - - this.updateGraphDividersIfNeeded(); - }, - - reset: function() - { - this.containerElement.scrollTop = 0; - - if (this._calculator) - this._calculator.reset(); - - if (this._items) { - var itemsLength = this._items.length; - for (var i = 0; i < itemsLength; ++i) { - var item = this._items[i]; - delete item._itemsTreeElement; - } - } - - this._items = []; - this._staleItems = []; - - this.itemsTreeElement.removeChildren(); - this.itemsGraphsElement.removeChildren(); - - this.updateGraphDividersIfNeeded(true); - }, - - get calculator() - { - return this._calculator; - }, - - set calculator(x) - { - if (!x || this._calculator === x) - return; - - this._calculator = x; - this._calculator.reset(); - - this._staleItems = this._items.slice(); - this.refresh(); - }, - - addItem: function(item) - { - this._items.push(item); - this.refreshItem(item); - }, - - removeItem: function(item) - { - this._items.remove(item, true); - - if (item._itemsTreeElement) { - this.itemsTreeElement.removeChild(item._itemsTreeElement); - this.itemsGraphsElement.removeChild(item._itemsTreeElement._itemGraph.graphElement); - } - - delete item._itemsTreeElement; - this.adjustScrollPosition(); - }, - - refreshItem: function(item) - { - this._staleItems.push(item); - this.needsRefresh = true; - }, - - revealAndSelectItem: function(item) - { - if (item._itemsTreeElement) { - item._itemsTreeElement.reveal(); - item._itemsTreeElement.select(true); - } - }, - - sortItems: function(sortingFunction) - { - var sortedElements = [].concat(this.itemsTreeElement.children); - sortedElements.sort(sortingFunction); - - var sortedElementsLength = sortedElements.length; - for (var i = 0; i < sortedElementsLength; ++i) { - var treeElement = sortedElements[i]; - if (treeElement === this.itemsTreeElement.children[i]) - continue; - - var wasSelected = treeElement.selected; - this.itemsTreeElement.removeChild(treeElement); - this.itemsTreeElement.insertChild(treeElement, i); - if (wasSelected) - treeElement.select(true); - - var graphElement = treeElement._itemGraph.graphElement; - this.itemsGraphsElement.insertBefore(graphElement, this.itemsGraphsElement.children[i]); - } - }, - - adjustScrollPosition: function() - { - // Prevent the container from being scrolled off the end. - if ((this.containerElement.scrollTop + this.containerElement.offsetHeight) > this.sidebarElement.offsetHeight) - this.containerElement.scrollTop = (this.sidebarElement.offsetHeight - this.containerElement.offsetHeight); - }, - - addEventDivider: function(divider) - { - this._timelineGrid.addEventDivider(divider); - }, - - hideEventDividers: function() - { - this._timelineGrid.hideEventDividers(); - }, - - showEventDividers: function() - { - this._timelineGrid.showEventDividers(); - } -} - -WebInspector.AbstractTimelinePanel.prototype.__proto__ = WebInspector.Panel.prototype; - -WebInspector.AbstractTimelineCalculator = function() -{ -} - -WebInspector.AbstractTimelineCalculator.prototype = { - computeSummaryValues: function(items) - { - var total = 0; - var categoryValues = {}; - - var itemsLength = items.length; - for (var i = 0; i < itemsLength; ++i) { - var item = items[i]; - var value = this._value(item); - if (typeof value === "undefined") - continue; - if (!(item.category.name in categoryValues)) - categoryValues[item.category.name] = 0; - categoryValues[item.category.name] += value; - total += value; - } - - return {categoryValues: categoryValues, total: total}; - }, - - computeBarGraphPercentages: function(item) - { - return {start: 0, middle: 0, end: (this._value(item) / this.boundarySpan) * 100}; - }, - - computeBarGraphLabels: function(item) - { - const label = this.formatValue(this._value(item)); - return {left: label, right: label, tooltip: label}; - }, - - get boundarySpan() - { - return this.maximumBoundary - this.minimumBoundary; - }, - - updateBoundaries: function(item) - { - this.minimumBoundary = 0; - - var value = this._value(item); - if (typeof this.maximumBoundary === "undefined" || value > this.maximumBoundary) { - this.maximumBoundary = value; - return true; - } - return false; - }, - - reset: function() - { - delete this.minimumBoundary; - delete this.maximumBoundary; - }, - - _value: function(item) - { - return 0; - }, - - formatValue: function(value) - { - return value.toString(); - } -} - -WebInspector.AbstractTimelineCategory = function(name, title, color) -{ - this.name = name; - this.title = title; - this.color = color; -} - -WebInspector.AbstractTimelineCategory.prototype = { - toString: function() - { - return this.title; - } -} diff --git a/WebCore/inspector/front-end/AuditLauncherView.js b/WebCore/inspector/front-end/AuditLauncherView.js index 18daee6..a922715 100644 --- a/WebCore/inspector/front-end/AuditLauncherView.js +++ b/WebCore/inspector/front-end/AuditLauncherView.js @@ -190,7 +190,8 @@ WebInspector.AuditLauncherView.prototype = { var element = document.createElement("input"); element.type = "checkbox"; - element.addEventListener("click", this._boundCategoryClickListener, false); + if (id !== "") + element.addEventListener("click", this._boundCategoryClickListener, false); labelElement.appendChild(element); labelElement.appendChild(document.createTextNode(title)); diff --git a/WebCore/inspector/front-end/BreakpointManager.js b/WebCore/inspector/front-end/BreakpointManager.js index 8518618..ec4e7cf 100644 --- a/WebCore/inspector/front-end/BreakpointManager.js +++ b/WebCore/inspector/front-end/BreakpointManager.js @@ -27,6 +27,7 @@ WebInspector.BreakpointManager = function() { this._breakpoints = {}; + this._xhrBreakpoints = {}; } WebInspector.BreakpointManager.prototype = { @@ -124,6 +125,22 @@ WebInspector.BreakpointManager.prototype = { } } InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition, didSetBreakpoint.bind(this)); + }, + + createXHRBreakpoint: function(url) + { + if (url in this._xhrBreakpoints) + return; + this._xhrBreakpoints[url] = true; + + var breakpoint = new WebInspector.XHRBreakpoint(url); + breakpoint.addEventListener("removed", this._xhrBreakpointRemoved.bind(this)); + this.dispatchEventToListeners("xhr-breakpoint-added", breakpoint); + }, + + _xhrBreakpointRemoved: function(event) + { + delete this._xhrBreakpoints[event.target.url]; } } @@ -189,6 +206,15 @@ WebInspector.Breakpoint.prototype = { this.dispatchEventToListeners("condition-changed"); }, + compareTo: function(other) + { + if (this.url != other.url) + return this.url < other.url ? -1 : 1; + if (this.line != other.line) + return this.line < other.line ? -1 : 1; + return 0; + }, + remove: function() { InspectorBackend.removeBreakpoint(this.sourceID, this.line); @@ -199,3 +225,83 @@ WebInspector.Breakpoint.prototype = { } WebInspector.Breakpoint.prototype.__proto__ = WebInspector.Object.prototype; + +WebInspector.XHRBreakpoint = function(url) +{ + this._url = url; + this._locked = false; + this.enabled = true; +} + +WebInspector.XHRBreakpoint.prototype = { + get enabled() + { + return "_id" in this; + }, + + set enabled(enabled) + { + if (this._locked) + return; + if (this.enabled === enabled) + return; + if (enabled) + this._setOnBackend(); + else + this._removeFromBackend(); + }, + + get url() + { + return this._url; + }, + + formatLabel: function() + { + var label = ""; + if (!this.url.length) + label = WebInspector.UIString("Any XHR"); + else + label = WebInspector.UIString("URL contains \"%s\"", this.url); + return label; + }, + + compareTo: function(other) + { + if (this.url != other.url) + return this.url < other.url ? -1 : 1; + return 0; + }, + + remove: function() + { + if (this._locked) + return; + if (this.enabled) + this._removeFromBackend(); + this.dispatchEventToListeners("removed"); + }, + + _setOnBackend: function() + { + this._locked = true; + var data = { type: "XHR", condition: { url: this.url } }; + InspectorBackend.setNativeBreakpoint(data, didSet.bind(this)); + + function didSet(breakpointId) + { + this._locked = false; + this._id = breakpointId; + this.dispatchEventToListeners("enable-changed"); + } + }, + + _removeFromBackend: function() + { + InspectorBackend.removeNativeBreakpoint(this._id); + delete this._id; + this.dispatchEventToListeners("enable-changed"); + } +} + +WebInspector.XHRBreakpoint.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js index 9688f3e..16ab041 100644 --- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -92,6 +92,42 @@ WebInspector.BreakpointsSidebarPane.prototype = { WebInspector.BreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; +WebInspector.XHRBreakpointsSidebarPane = function() +{ + WebInspector.BreakpointsSidebarPane.call(this, WebInspector.UIString("XHR Breakpoints")); + + var addButton = document.createElement("button"); + addButton.className = "add"; + addButton.addEventListener("click", this._showEditBreakpointDialog.bind(this), false); + this.titleElement.appendChild(addButton); + + this.urlInputElement = document.createElement("span"); + this.urlInputElement.className = "breakpoint-condition editing"; +} + +WebInspector.XHRBreakpointsSidebarPane.prototype = { + _showEditBreakpointDialog: function(event) + { + event.stopPropagation(); + + if (this.urlInputElement.parentElement) + return; + + 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)); + }, + + _hideEditBreakpointDialog: function(discard) + { + if (!discard) + WebInspector.breakpointManager.createXHRBreakpoint(this.urlInputElement.textContent.toLowerCase()); + this.bodyElement.removeChild(this.urlInputElement); + } +} + +WebInspector.XHRBreakpointsSidebarPane.prototype.__proto__ = WebInspector.BreakpointsSidebarPane.prototype; + WebInspector.BreakpointItem = function(breakpoint) { this._breakpoint = breakpoint; @@ -116,6 +152,11 @@ WebInspector.BreakpointItem.prototype = { return this._element; }, + compareTo: function(other) + { + return this._breakpoint.compareTo(other._breakpoint); + }, + remove: function() { this._breakpoint.remove(); @@ -125,7 +166,7 @@ WebInspector.BreakpointItem.prototype = { { this._breakpoint.enabled = !this._breakpoint.enabled; - // without this, we'd switch to the source of the clicked breakpoint + // Breakpoint element may have it's own click handler. event.stopPropagation(); }, @@ -133,6 +174,10 @@ WebInspector.BreakpointItem.prototype = { { var checkbox = this._element.firstChild; checkbox.checked = this._breakpoint.enabled; + }, + + _breakpointClicked: function(event) + { } } @@ -155,15 +200,6 @@ WebInspector.JSBreakpointItem = function(breakpoint) } WebInspector.JSBreakpointItem.prototype = { - compareTo: function(other) - { - if (this._breakpoint.url != other._breakpoint.url) - return this._breakpoint.url < other._breakpoint.url ? -1 : 1; - if (this._breakpoint.line != other._breakpoint.line) - return this._breakpoint.line < other._breakpoint.line ? -1 : 1; - return 0; - }, - _breakpointClicked: function() { WebInspector.panels.scripts.showSourceLine(this._breakpoint.url, this._breakpoint.line); @@ -191,13 +227,6 @@ WebInspector.DOMBreakpointItem = function(breakpoint) } WebInspector.DOMBreakpointItem.prototype = { - compareTo: function(other) - { - if (this._breakpoint.type != other._breakpoint.type) - return this._breakpoint.type < other._breakpoint.type ? -1 : 1; - return 0; - }, - _breakpointClicked: function() { WebInspector.updateFocusedNode(this._breakpoint.nodeId); @@ -205,3 +234,13 @@ WebInspector.DOMBreakpointItem.prototype = { } WebInspector.DOMBreakpointItem.prototype.__proto__ = WebInspector.BreakpointItem.prototype; + +WebInspector.XHRBreakpointItem = function(breakpoint) +{ + WebInspector.BreakpointItem.call(this, breakpoint); + + var label = document.createTextNode(this._breakpoint.formatLabel()); + this._element.appendChild(label); +} + +WebInspector.XHRBreakpointItem.prototype.__proto__ = WebInspector.BreakpointItem.prototype; diff --git a/WebCore/inspector/front-end/CallStackSidebarPane.js b/WebCore/inspector/front-end/CallStackSidebarPane.js index 91f35a6..6212ea1 100644 --- a/WebCore/inspector/front-end/CallStackSidebarPane.js +++ b/WebCore/inspector/front-end/CallStackSidebarPane.js @@ -28,6 +28,11 @@ WebInspector.CallStackSidebarPane = function() WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack")); } +WebInspector.CallStackSidebarPane.DebuggerEventType = { + DOMBreakpoint: 0, + NativeBreakpoint: 1 +}; + WebInspector.CallStackSidebarPane.prototype = { update: function(callFrames, sourceIDMap) { @@ -82,36 +87,41 @@ WebInspector.CallStackSidebarPane.prototype = { } }, - updateStatus: function(status) + updateStatus: function(eventType, eventData) { var statusElement = document.createElement("div"); - statusElement.className = "info"; - - var breakpointType = status.breakpoint.type; - var substitutions = [WebInspector.DOMBreakpoint.labelForType(breakpointType), WebInspector.panels.elements.linkifyNodeById(status.breakpoint.nodeId)]; - var formatters = { - s: function(substitution) + 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) { - return substitution; + if (typeof b === "string") + b = document.createTextNode(b); + statusElement.appendChild(b); } - }; - function append(a, b) - { - if (typeof b === "string") - b = document.createTextNode(b); - statusElement.appendChild(b); - } - if (breakpointType === WebInspector.DOMBreakpoint.Types.SubtreeModified) { - var targetNode = WebInspector.panels.elements.linkifyNodeById(status.targetNodeId); - if (status.insertion) { - if (status.targetNodeId !== status.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); + 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, 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); + 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); }, diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js index 9b386c3..279852e 100644 --- a/WebCore/inspector/front-end/DOMAgent.js +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -98,13 +98,7 @@ WebInspector.DOMNode.prototype = { set nodeValue(value) { if (this.nodeType != Node.TEXT_NODE) return; - var self = this; - var callback = function() - { - self._nodeValue = value; - self.textContent = value; - }; - this.ownerDocument._domAgent.setTextNodeValueAsync(this, value, callback); + this.ownerDocument._domAgent.setTextNodeValueAsync(this, value, function() {}); }, getAttribute: function(name) @@ -384,6 +378,15 @@ WebInspector.DOMAgent.prototype = { this.document._fireDomEvent("DOMAttrModified", event); }, + _characterDataModified: function(nodeId, newValue) + { + var node = this._idToDOMNode[nodeId]; + node._nodeValue = newValue; + node.textContent = newValue; + var event = { target : node }; + this.document._fireDomEvent("DOMCharacterDataModified", event); + }, + nodeForId: function(nodeId) { return this._idToDOMNode[nodeId]; @@ -691,6 +694,11 @@ WebInspector.attributesUpdated = function() this.domAgent._attributesUpdated.apply(this.domAgent, arguments); } +WebInspector.characterDataModified = function() +{ + this.domAgent._characterDataModified.apply(this.domAgent, arguments); +} + WebInspector.setDocument = function() { this.domAgent._setDocument.apply(this.domAgent, arguments); @@ -866,6 +874,13 @@ WebInspector.DOMBreakpoint.prototype = { 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) diff --git a/WebCore/inspector/front-end/DataGrid.js b/WebCore/inspector/front-end/DataGrid.js index 1ecc4f2..f68fe48 100644 --- a/WebCore/inspector/front-end/DataGrid.js +++ b/WebCore/inspector/front-end/DataGrid.js @@ -92,10 +92,8 @@ WebInspector.DataGrid = function(columns, editCallback, deleteCallback) cell.addStyleClass("sortable"); } - if (column.aligned) { - cell.addStyleClass(column.aligned); + if (column.aligned) this.aligned[columnIdentifier] = column.aligned; - } headerRow.appendChild(cell); @@ -412,6 +410,7 @@ WebInspector.DataGrid.prototype = { resizer.style.left = left + "px"; } + this.dispatchEventToListeners("width changed"); }, addCreationNode: function(hasChildren) @@ -535,6 +534,35 @@ WebInspector.DataGrid.prototype = { this.children = []; }, + sortNodes: function(comparator, descending) + { + function comparatorWrapper(a, b) + { + 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); + } + + var tbody = this.dataTableBody; + var tbodyParent = tbody.parentElement; + tbodyParent.removeChild(tbody); + + var childNodes = tbody.childNodes; + var sortedNodes = Array.prototype.slice.call(childNodes); + sortedNodes.sort(comparatorWrapper.bind(this)); + + var sortedNodesLength = sortedNodes.length; + tbody.removeChildren(); + for (var i = 0; i < sortedNodesLength; ++i) { + var node = sortedNodes[i]; + tbody.appendChild(node); + } + tbodyParent.appendChild(tbody); + }, _keyDown: function(event) { @@ -772,12 +800,14 @@ WebInspector.DataGrid.prototype = { this._dataTableColumnGroup.children[resizer.rightNeighboringColumnID].style.width = percentRightColumn; event.preventDefault(); + this.dispatchEventToListeners("width changed"); }, _endResizerDragging: function(event) { WebInspector.elementDragEnd(event); this.currentResizer = null; + this.dispatchEventToListeners("width changed"); }, ColumnResizePadding: 10, @@ -825,12 +855,16 @@ WebInspector.DataGridNode.prototype = { if (this.revealed) this._element.addStyleClass("revealed"); + this.createCells(); + return this._element; + }, + + createCells: function() + { for (var columnIdentifier in this.dataGrid.columns) { var cell = this.createCell(columnIdentifier); this._element.appendChild(cell); } - - return this._element; }, get data() @@ -964,11 +998,7 @@ WebInspector.DataGridNode.prototype = { return; this._element.removeChildren(); - - for (var columnIdentifier in this.dataGrid.columns) { - var cell = this.createCell(columnIdentifier); - this._element.appendChild(cell); - } + this.createCells(); }, createCell: function(columnIdentifier) diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index 72b23e1..d6437fc 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -74,7 +74,7 @@ WebInspector.ElementsPanel = function() this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(this.sidebarPanes.computedStyle); this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane(); this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane(); - if (Preferences.domBreakpointsEnabled) + if (Preferences.nativeInstrumentationEnabled) this.sidebarPanes.domBreakpoints = WebInspector.createDOMBreakpointsSidebarPane(); this.sidebarPanes.eventListeners = new WebInspector.EventListenersSidebarPane(); @@ -148,7 +148,7 @@ WebInspector.ElementsPanel.prototype = { WebInspector.Panel.prototype.hide.call(this); WebInspector.highlightDOMNode(0); - InspectorBackend.disableSearchingForNode(); + this.setSearchingForNode(false); }, resize: function() @@ -171,7 +171,7 @@ WebInspector.ElementsPanel.prototype = { delete this.currentQuery; - if (Preferences.domBreakpointsEnabled) + if (Preferences.nativeInstrumentationEnabled) this.sidebarPanes.domBreakpoints.reset(); }, @@ -186,6 +186,7 @@ WebInspector.ElementsPanel.prototype = { inspectedRootDocument.addEventListener("DOMNodeInserted", this._nodeInserted.bind(this)); inspectedRootDocument.addEventListener("DOMNodeRemoved", this._nodeRemoved.bind(this)); inspectedRootDocument.addEventListener("DOMAttrModified", this._attributesUpdated.bind(this)); + inspectedRootDocument.addEventListener("DOMCharacterDataModified", this._characterDataModified.bind(this)); this.rootDOMNode = inspectedRootDocument; @@ -247,16 +248,6 @@ WebInspector.ElementsPanel.prototype = { InspectorBackend.performSearch(whitespaceTrimmedQuery, false); }, - searchingForNodeWasEnabled: function() - { - this._nodeSearchButton.toggled = true; - }, - - searchingForNodeWasDisabled: function() - { - this._nodeSearchButton.toggled = false; - }, - populateHrefContextMenu: function(contextMenu, event, anchorElement) { if (!anchorElement.href) @@ -491,6 +482,13 @@ WebInspector.ElementsPanel.prototype = { this._updateModifiedNodesSoon(); }, + _characterDataModified: function(event) + { + this.recentlyModifiedNodes.push({node: event.target, updated: true}); + if (this.visible) + this._updateModifiedNodesSoon(); + }, + _nodeInserted: function(event) { this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, inserted: true}); @@ -1152,12 +1150,29 @@ WebInspector.ElementsPanel.prototype = { this.treeOutline.updateSelection(); }, + updateFocusedNode: function(nodeId) + { + var node = WebInspector.domAgent.nodeForId(nodeId); + if (!node) + return; + + this.focusedDOMNode = node; + this._nodeSearchButton.toggled = false; + }, + + _setSearchingForNode: function(enabled) + { + this._nodeSearchButton.toggled = enabled; + }, + + setSearchingForNode: function(enabled) + { + InspectorBackend.setSearchingForNode(enabled, this._setSearchingForNode.bind(this)); + }, + toggleSearchingForNode: function() { - if (!this._nodeSearchButton.toggled) - InspectorBackend.enableSearchingForNode(); - else - InspectorBackend.disableSearchingForNode(); + this.setSearchingForNode(!this._nodeSearchButton.toggled); }, elementsToRestoreScrollPositionsFor: function() diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index e261234..1479c9a 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -637,10 +637,12 @@ WebInspector.ElementsTreeElement.prototype = { this.listItemElement.scrollIntoViewIfNeeded(false); }, - onselect: function() + onselect: function(treeElement, selectedByUser) { this.treeOutline.suppressRevealAndSelect = true; this.treeOutline.focusedDOMNode = this.representedObject; + if (selectedByUser) + WebInspector.highlightDOMNode(this.representedObject.id); this.updateSelection(); this.treeOutline.suppressRevealAndSelect = false; }, @@ -752,7 +754,7 @@ WebInspector.ElementsTreeElement.prototype = { contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); contextMenu.appendItem(WebInspector.UIString("Delete Node"), this.remove.bind(this)); - if (Preferences.domBreakpointsEnabled) { + if (Preferences.nativeInstrumentationEnabled) { // Add debbuging-related actions contextMenu.appendSeparator(); @@ -1125,7 +1127,7 @@ WebInspector.ElementsTreeElement.prototype = { delete this._editing; var textNode; - if (this.representedObject.nodeType == Node.ELEMENT_NODE) { + if (this.representedObject.nodeType === Node.ELEMENT_NODE) { // We only show text nodes inline in elements if the element only // has a single child, and that child is a text node. textNode = this.representedObject.firstChild; @@ -1133,9 +1135,6 @@ WebInspector.ElementsTreeElement.prototype = { textNode = this.representedObject; textNode.nodeValue = newText; - - // Need to restore attributes / node structure. - this.updateTitle(); }, _editingCancelled: function(element, context) diff --git a/WebCore/inspector/front-end/GoToLineDialog.js b/WebCore/inspector/front-end/GoToLineDialog.js new file mode 100644 index 0000000..c96344c --- /dev/null +++ b/WebCore/inspector/front-end/GoToLineDialog.js @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.GoToLineDialog = function(view) +{ + this._element = document.createElement("div"); + this._element.className = "go-to-line-dialog"; + this._element.addEventListener("keydown", this._onKeyDown.bind(this), false); + this._closeKeys = [ + WebInspector.KeyboardShortcut.Keys.Enter.code, + WebInspector.KeyboardShortcut.Keys.Esc.code, + ]; + + var dialogWindow = this._element; + + dialogWindow.createChild("label").innerText = WebInspector.UIString("Go to line: "); + + this._input = dialogWindow.createChild("input"); + this._input.setAttribute("type", "text"); + this._input.setAttribute("size", 6); + var linesCount = view.sourceFrame.textModel.linesCount; + if (linesCount) + this._input.setAttribute("title", WebInspector.UIString("1 - %d", linesCount)); + var blurHandler = this._onBlur.bind(this); + this._input.addEventListener("blur", blurHandler, false); + + + var go = dialogWindow.createChild("button"); + go.innerText = WebInspector.UIString("Go"); + go.addEventListener("click", this._onClick.bind(this), false); + go.addEventListener("mousedown", function(e) { + // Ok button click will close the dialog, removing onBlur listener + // to let click event be handled. + this._input.removeEventListener("blur", blurHandler, false); + }.bind(this), false); + + this._view = view; + view.element.appendChild(this._element); + + this._previousFocusElement = WebInspector.currentFocusElement; + WebInspector.currentFocusElement = this._input; + this._input.select(); +} + +WebInspector.GoToLineDialog.show = function(sourceView) +{ + if (this._instance) + return; + this._instance = new WebInspector.GoToLineDialog(sourceView); +} + +WebInspector.GoToLineDialog.prototype = { + _hide: function() + { + if (this._isHiding) + return; + this._isHiding = true; + + WebInspector.currentFocusElement = this._previousFocusElement; + WebInspector.GoToLineDialog._instance = null; + this._element.parentElement.removeChild(this._element); + }, + + _onBlur: function(event) + { + this._hide(); + }, + + _onKeyDown: function(event) + { + if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) { + event.preventDefault(); + return; + } + + if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code) + this._highlightSelectedLine(); + + if (this._closeKeys.indexOf(event.keyCode) >= 0) { + this._hide(); + event.stopPropagation(); + } + }, + + _onClick: function(event) + { + this._highlightSelectedLine(); + this._hide(); + }, + + _highlightSelectedLine: function() + { + var value = this._input.value; + var lineNumber = parseInt(value, 10); + if (!isNaN(lineNumber) && lineNumber > 0) { + lineNumber = Math.min(lineNumber, this._view.sourceFrame.textModel.linesCount); + this._view.highlightLine(lineNumber); + } + } +}; diff --git a/WebCore/inspector/front-end/Images/networkIcon.png b/WebCore/inspector/front-end/Images/networkIcon.png Binary files differnew file mode 100644 index 0000000..982424d --- /dev/null +++ b/WebCore/inspector/front-end/Images/networkIcon.png diff --git a/WebCore/inspector/front-end/Images/paneAddButtons.png b/WebCore/inspector/front-end/Images/paneAddButtons.png Binary files differnew file mode 100644 index 0000000..f1c0047 --- /dev/null +++ b/WebCore/inspector/front-end/Images/paneAddButtons.png diff --git a/WebCore/inspector/front-end/NetworkPanel.js b/WebCore/inspector/front-end/NetworkPanel.js new file mode 100644 index 0000000..f07b3b0 --- /dev/null +++ b/WebCore/inspector/front-end/NetworkPanel.js @@ -0,0 +1,1414 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org> + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.NetworkPanel = function() +{ + WebInspector.Panel.call(this, "network"); + + this._resources = []; + this._staleResources = []; + this._resourceGridNodes = {}; + this._mainResourceLoadTime = -1; + this._mainResourceDOMContentTime = -1; + + this._viewsContainerElement = document.createElement("div"); + this._viewsContainerElement.id = "network-views"; + this.element.appendChild(this._viewsContainerElement); + + this._createSortingFunctions(); + this._createTimelineGrid(); + this._createTable(); + this._createStatusbarButtons(); + + 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); +} + +WebInspector.NetworkPanel.prototype = { + get toolbarItemLabel() + { + return WebInspector.UIString("Network"); + }, + + get statusBarItems() + { + return [this._largerResourcesButton.element, this._clearButton.element]; + }, + + isCategoryVisible: function(categoryName) + { + return true; + }, + + elementsToRestoreScrollPositionsFor: function() + { + return [this.containerElement]; + }, + + resize: function() + { + WebInspector.Panel.prototype.resize.call(this); + this._dataGrid.updateWidths(); + }, + + _createTimelineGrid: function() + { + this._timelineGrid = new WebInspector.TimelineGrid(); + this._timelineGrid.element.addStyleClass("network-timeline-grid"); + this.element.appendChild(this._timelineGrid.element); + }, + + _createTable: function() + { + this.containerElement = document.createElement("div"); + this.containerElement.id = "network-container"; + this.element.appendChild(this.containerElement); + + 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.sortable = true; + columns.status.width = "8%"; + + columns.type.title = WebInspector.UIString("Type"); + columns.type.sortable = true; + columns.type.width = "7%"; + + columns.size.title = WebInspector.UIString("Size"); + columns.size.sortable = true; + columns.size.width = "10%"; + columns.size.aligned = "right"; + + columns.time.title = WebInspector.UIString("Time"); + columns.time.sortable = true; + columns.time.width = "10%"; + columns.time.aligned = "right"; + + columns.timeline.title = ""; + columns.timeline.sortable = true; + columns.timeline.width = "40%"; + columns.timeline.sort = true; + + this._dataGrid = new WebInspector.DataGrid(columns); + this.element.appendChild(this._dataGrid.element); + this._dataGrid.addEventListener("sorting changed", this._sortItems, this); + this._dataGrid.addEventListener("width changed", this._updateDividersIfNeeded, this); + }, + + _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"); + }, + + filter: function(target, selectMultiple) + { + }, + + _updateFilter: function(e) + { + var isMac = WebInspector.isMac(); + var selectMultiple = false; + if (isMac && e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) + selectMultiple = true; + if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey) + selectMultiple = true; + + this.filter(e.target, selectMultiple); + + // 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; + + var searchField = document.getElementById("search"); + WebInspector.doPerformSearch(searchField.value, WebInspector.shortSearchWasForcedByKeyEvent, false, true); + }, + + _scheduleRefresh: function() + { + if (this._needsRefresh) + return; + + this._needsRefresh = true; + + if (this.visible && !("_refreshTimeout" in this)) + 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 proceed = true; + if (!this.visible) { + this._scheduleRefresh(); + proceed = false; + } else + proceed = this._timelineGrid.updateDividers(force, this.calculator); + + if (!proceed) + return; + + if (this.calculator.startAtZero || !this.calculator.computePercentageFromEventTime) { + // If our current sorting method starts at zero, that means it shows all + // resources starting at the same point, and so onLoad event and DOMContent + // event lines really wouldn't make much sense here, so don't render them. + // Additionally, if the calculator doesn't have the computePercentageFromEventTime + // function defined, we are probably sorting by size, and event times aren't relevant + // in this case. + return; + } + + this._timelineGrid.removeEventDividers(); + if (this._mainResourceLoadTime !== -1) { + var percent = this.calculator.computePercentageFromEventTime(this._mainResourceLoadTime); + + var loadDivider = document.createElement("div"); + loadDivider.className = "network-event-divider network-red-divider"; + + var loadDividerPadding = document.createElement("div"); + loadDividerPadding.className = "network-event-divider-padding"; + loadDividerPadding.title = WebInspector.UIString("Load event fired"); + loadDividerPadding.appendChild(loadDivider); + loadDividerPadding.style.left = percent + "%"; + this._timelineGrid.addEventDivider(loadDividerPadding); + } + + if (this._mainResourceDOMContentTime !== -1) { + var percent = this.calculator.computePercentageFromEventTime(this._mainResourceDOMContentTime); + + var domContentDivider = document.createElement("div"); + domContentDivider.className = "network-event-divider network-blue-divider"; + + var domContentDividerPadding = document.createElement("div"); + domContentDividerPadding.className = "network-event-divider-padding"; + domContentDividerPadding.title = WebInspector.UIString("DOMContent event fired"); + domContentDividerPadding.appendChild(domContentDivider); + domContentDividerPadding.style.left = percent + "%"; + this._timelineGrid.addEventDivider(domContentDividerPadding); + } + }, + + _refreshIfNeeded: function() + { + if (this._needsRefresh) + this.refresh(); + }, + + _invalidateAllItems: function() + { + this._staleResources = this._resources.slice(); + }, + + get calculator() + { + return this._calculator; + }, + + set calculator(x) + { + if (!x || this._calculator === x) + return; + + this._calculator = x; + this._calculator.reset(); + + this._invalidateAllItems(); + this.refresh(); + }, + + _resourceGridNode: function(resource) + { + return this._resourceGridNodes[resource.identifier]; + }, + + revealAndSelectItem: function(resource) + { + var node = this._resourceGridNode(resource); + if (node) { + node.reveal(); + node.select(true); + } + }, + + addEventDivider: function(divider) + { + this._timelineGrid.addEventDivider(divider); + }, + + get resourceTrackingEnabled() + { + return this._resourceTrackingEnabled; + }, + + _createStatusbarButtons: function() + { + this._clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-status-bar-item"); + 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); + this._largerResourcesButton.addEventListener("click", this._toggleLargerResources.bind(this), false); + }, + + _settingsLoaded: function() + { + this._largerResourcesButton.toggled = WebInspector.applicationSettings.resourcesLargeRows; + if (!WebInspector.applicationSettings.resourcesLargeRows) + this._setLargerResources(WebInspector.applicationSettings.resourcesLargeRows); + }, + + set mainResourceLoadTime(x) + { + if (this._mainResourceLoadTime === x) + return; + + this._mainResourceLoadTime = x || -1; + // Update the dividers to draw the new line + this._updateDividersIfNeeded(true); + }, + + set mainResourceDOMContentTime(x) + { + if (this._mainResourceDOMContentTime === x) + return; + + this._mainResourceDOMContentTime = x || -1; + this._updateDividersIfNeeded(true); + }, + + show: function() + { + WebInspector.Panel.prototype.show.call(this); + + this._refreshIfNeeded(); + + var visibleView = this.visibleView; + if (this.visibleResource) { + this.visibleView.headersVisible = true; + this.visibleView.show(this._viewsContainerElement); + } else if (visibleView) + visibleView.show(); + + // Hide any views that are visible that are not this panel's current visible view. + // This can happen when a ResourceView is visible in the Scripts panel then switched + // to the this panel. + var resourcesLength = this._resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = this._resources[i]; + var view = resource._resourcesView; + if (!view || view === visibleView) + continue; + view.visible = false; + } + this._dataGrid.updateWidths(); + }, + + 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; + }, + + searchMatchFound: function(view, matches) + { + this._resourceGridNode(view.resource).searchMatches = matches; + }, + + searchCanceled: function(startingNewSearch) + { + WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch); + + if (startingNewSearch || !this._resources) + return; + }, + + performSearch: function(query) + { + WebInspector.Panel.prototype.performSearch.call(this, query); + }, + + get visibleView() + { + if (this.visibleResource) + return this.visibleResource._resourcesView; + return null; + }, + + refresh: function() + { + this._needsRefresh = false; + if ("_refreshTimeout" in this) { + clearTimeout(this._refreshTimeout); + delete this._refreshTimeout; + } + + var staleItemsLength = this._staleResources.length; + + var boundariesChanged = false; + + for (var i = 0; i < staleItemsLength; ++i) { + var resource = this._staleResources[i]; + var node = this._resourceGridNode(resource); + if (!node) { + // Create the timeline tree element and graph. + node = new WebInspector.NetworkDataGridNode(resource); + this._resourceGridNodes[resource.identifier] = node; + this._dataGrid.appendChild(node); + } + node.refreshResource(); + + if (this.calculator.updateBoundaries(resource)) + boundariesChanged = true; + } + + if (boundariesChanged) { + // The boundaries changed, so all item graphs are stale. + this._invalidateAllItems(); + staleItemsLength = this._staleResources.length; + } + + for (var i = 0; i < staleItemsLength; ++i) + this._resourceGridNode(this._staleResources[i]).refreshGraph(this.calculator); + + this._staleResources = []; + this._sortItems(); + this._dataGrid.updateWidths(); + }, + + reset: function() + { + this._popoverHelper.hidePopup(); + 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; + } + } + + // 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(); + this._updateDividersIfNeeded(true); + // End reset timeline. + + this._mainResourceLoadTime = -1; + this._mainResourceDOMContentTime = -1; + + this._viewsContainerElement.removeChildren(); + }, + + addResource: function(resource) + { + this._resources.push(resource); + this.refreshResource(resource); + }, + + refreshResource: function(resource) + { + this._staleResources.push(resource); + this._scheduleRefresh(); + }, + + recreateViewForResourceIfNeeded: function(resource) + { + if (!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; + + resource._resourcesView.detach(); + delete resource._resourcesView; + + resource._resourcesView = newView; + + newView.headersVisible = oldView.headersVisible; + + if (oldViewParentNode) + newView.show(oldViewParentNode); + + WebInspector.panels.scripts.viewRecreated(oldView, newView); + }, + + canShowSourceLine: function(url, line) + { + return this._resourceTrackingEnabled && !!WebInspector.resourceForURL(url); + }, + + showSourceLine: function(url, line) + { + this.showResource(WebInspector.resourceForURL(url), line); + }, + + showResource: function(resource, line) + { + if (!resource) + return; + + this._popoverHelper.hidePopup(); + + this.containerElement.addStyleClass("viewing-resource"); + + if (this.visibleResource && this.visibleResource._resourcesView) + this.visibleResource._resourcesView.hide(); + + var view = this.resourceViewForResource(resource); + view.headersVisible = true; + view.show(this._viewsContainerElement); + + if (line) { + view.selectContentTab(true); + if (view.revealLine) + view.revealLine(line); + if (view.highlightLine) + view.highlightLine(line); + } + + this.revealAndSelectItem(resource); + + this.visibleResource = resource; + + this.updateSidebarWidth(); + }, + + showView: function(view) + { + if (!view) + return; + this.showResource(view.resource); + }, + + closeVisibleResource: function() + { + this.containerElement.removeStyleClass("viewing-resource"); + + if (this.visibleResource && this.visibleResource._resourcesView) + this.visibleResource._resourcesView.hide(); + delete this.visibleResource; + + if (this._lastSelectedGraphTreeElement) + this._lastSelectedGraphTreeElement.select(true); + + this.updateSidebarWidth(); + }, + + resourceViewForResource: function(resource) + { + if (!resource) + return null; + if (!resource._resourcesView) + resource._resourcesView = this._createResourceView(resource); + 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; + this._setLargerResources(WebInspector.applicationSettings.resourcesLargeRows); + }, + + _setLargerResources: function(enabled) + { + this._largerResourcesButton.toggled = enabled; + if (!enabled) { + this._largerResourcesButton.title = WebInspector.UIString("Use large resource rows."); + this._dataGrid.element.addStyleClass("small"); + } else { + this._largerResourcesButton.title = WebInspector.UIString("Use small resource rows."); + this._dataGrid.element.removeStyleClass("small"); + } + }, + + _createResourceView: function(resource) + { + switch (resource.category) { + case WebInspector.resourceCategories.documents: + case WebInspector.resourceCategories.stylesheets: + case WebInspector.resourceCategories.scripts: + case WebInspector.resourceCategories.xhr: + return new WebInspector.SourceView(resource); + case WebInspector.resourceCategories.images: + return new WebInspector.ImageView(resource); + case WebInspector.resourceCategories.fonts: + return new WebInspector.FontView(resource); + default: + return new WebInspector.ResourceView(resource); + } + }, + + _getPopoverAnchor: function(element) + { + var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label"); + if (!anchor) + return null; + var resource = anchor.parentElement.resource; + return resource && resource.timing ? anchor : null; + }, + + _showPopover: function(anchor) + { + var tableElement = document.createElement("table"); + var resource = anchor.parentElement.resource; + var rows = []; + + function addRow(title, start, end, color) + { + var row = {}; + row.title = title; + row.start = start; + row.end = end; + rows.push(row); + } + + if (resource.timing.proxyStart !== -1) + addRow(WebInspector.UIString("Proxy"), resource.timing.proxyStart, resource.timing.proxyEnd); + + if (resource.timing.dnsStart !== -1) + addRow(WebInspector.UIString("DNS Lookup"), resource.timing.dnsStart, resource.timing.dnsEnd); + + if (resource.timing.connectStart !== -1) { + if (resource.connectionReused) + addRow(WebInspector.UIString("Blocking"), resource.timing.connectStart, resource.timing.connectEnd); + else { + var connectStart = resource.timing.connectStart; + // Connection includes DNS, subtract it here. + if (resource.timing.dnsStart !== -1) + connectStart += resource.timing.dnsEnd - resource.timing.dnsStart; + addRow(WebInspector.UIString("Connecting"), connectStart, resource.timing.connectEnd); + } + } + + if (resource.timing.sslStart !== -1) + addRow(WebInspector.UIString("SSL"), resource.timing.sslStart, resource.timing.sslEnd); + + var sendStart = resource.timing.sendStart; + if (resource.timing.sslStart !== -1) + sendStart += resource.timing.sslEnd - resource.timing.sslStart; + + addRow(WebInspector.UIString("Sending"), resource.timing.sendStart, resource.timing.sendEnd); + addRow(WebInspector.UIString("Waiting"), resource.timing.sendEnd, resource.timing.receiveHeadersEnd); + addRow(WebInspector.UIString("Receiving"), (resource.responseReceivedTime - resource.timing.requestTime) * 1000, (resource.endTime - resource.timing.requestTime) * 1000); + + const chartWidth = 200; + var total = (resource.endTime - resource.timing.requestTime) * 1000; + var scale = chartWidth / total; + + for (var i = 0; i < rows.length; ++i) { + var tr = document.createElement("tr"); + tableElement.appendChild(tr); + + var td = document.createElement("td"); + td.textContent = rows[i].title; + tr.appendChild(td); + + td = document.createElement("td"); + td.width = chartWidth + "px"; + + var row = document.createElement("div"); + row.className = "network-timing-row"; + td.appendChild(row); + + var bar = document.createElement("span"); + bar.className = "network-timing-bar"; + bar.style.left = scale * rows[i].start + "px"; + bar.style.right = scale * (total - rows[i].end) + "px"; + bar.style.backgroundColor = rows[i].color; + bar.textContent = "\u200B"; // Important for 0-time items to have 0 width. + row.appendChild(bar); + + var title = document.createElement("span"); + title.className = "network-timing-bar-title"; + if (total - rows[i].end < rows[i].start) + title.style.right = (scale * (total - rows[i].end) + 3) + "px"; + else + title.style.left = (scale * rows[i].start + 3) + "px"; + title.textContent = Number.millisToString(rows[i].end - rows[i].start); + row.appendChild(title); + + tr.appendChild(td); + } + + var popover = new WebInspector.Popover(tableElement); + popover.show(anchor); + return popover; + }, + + hide: function() + { + WebInspector.Panel.prototype.hide.call(this); + this._popoverHelper.hidePopup(); + } +} + +WebInspector.NetworkPanel.prototype.__proto__ = WebInspector.Panel.prototype; + +WebInspector.getResourceContent = function(identifier, callback) +{ + InspectorBackend.getResourceContent(identifier, callback); +} + +WebInspector.NetworkBaseCalculator = function() +{ +} + +WebInspector.NetworkBaseCalculator.prototype = { + computeSummaryValues: function(items) + { + var total = 0; + var categoryValues = {}; + + var itemsLength = items.length; + for (var i = 0; i < itemsLength; ++i) { + var item = items[i]; + var value = this._value(item); + if (typeof value === "undefined") + continue; + if (!(item.category.name in categoryValues)) + categoryValues[item.category.name] = 0; + categoryValues[item.category.name] += value; + total += value; + } + + return {categoryValues: categoryValues, total: total}; + }, + + computeBarGraphPercentages: function(item) + { + return {start: 0, middle: 0, end: (this._value(item) / this.boundarySpan) * 100}; + }, + + computeBarGraphLabels: function(item) + { + const label = this.formatValue(this._value(item)); + return {left: label, right: label, tooltip: label}; + }, + + get boundarySpan() + { + return this.maximumBoundary - this.minimumBoundary; + }, + + updateBoundaries: function(item) + { + this.minimumBoundary = 0; + + var value = this._value(item); + if (typeof this.maximumBoundary === "undefined" || value > this.maximumBoundary) { + this.maximumBoundary = value; + return true; + } + return false; + }, + + reset: function() + { + delete this.minimumBoundary; + delete this.maximumBoundary; + }, + + _value: function(item) + { + return 0; + }, + + formatValue: function(value) + { + return value.toString(); + } +} + +WebInspector.NetworkTimeCalculator = function(startAtZero) +{ + WebInspector.NetworkBaseCalculator.call(this); + this.startAtZero = startAtZero; +} + +WebInspector.NetworkTimeCalculator.prototype = { + computeSummaryValues: function(resources) + { + var resourcesByCategory = {}; + var resourcesLength = resources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = resources[i]; + if (!(resource.category.name in resourcesByCategory)) + resourcesByCategory[resource.category.name] = []; + resourcesByCategory[resource.category.name].push(resource); + } + + var earliestStart; + var latestEnd; + var categoryValues = {}; + for (var category in resourcesByCategory) { + resourcesByCategory[category].sort(WebInspector.Resource.CompareByTime); + categoryValues[category] = 0; + + var segment = {start: -1, end: -1}; + + var categoryResources = resourcesByCategory[category]; + var resourcesLength = categoryResources.length; + for (var i = 0; i < resourcesLength; ++i) { + var resource = categoryResources[i]; + if (resource.startTime === -1 || resource.endTime === -1) + continue; + + if (typeof earliestStart === "undefined") + earliestStart = resource.startTime; + else + earliestStart = Math.min(earliestStart, resource.startTime); + + if (typeof latestEnd === "undefined") + latestEnd = resource.endTime; + else + latestEnd = Math.max(latestEnd, resource.endTime); + + if (resource.startTime <= segment.end) { + segment.end = Math.max(segment.end, resource.endTime); + continue; + } + + categoryValues[category] += segment.end - segment.start; + + segment.start = resource.startTime; + segment.end = resource.endTime; + } + + // Add the last segment + categoryValues[category] += segment.end - segment.start; + } + + return {categoryValues: categoryValues, total: latestEnd - earliestStart}; + }, + + computeBarGraphPercentages: function(resource) + { + if (resource.startTime !== -1) + var start = ((resource.startTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var start = 0; + + if (resource.responseReceivedTime !== -1) + var middle = ((resource.responseReceivedTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var middle = (this.startAtZero ? start : 100); + + if (resource.endTime !== -1) + var end = ((resource.endTime - this.minimumBoundary) / this.boundarySpan) * 100; + else + var end = (this.startAtZero ? middle : 100); + + if (this.startAtZero) { + end -= start; + middle -= start; + start = 0; + } + + return {start: start, middle: middle, end: end}; + }, + + computePercentageFromEventTime: function(eventTime) + { + // This function computes a percentage in terms of the total loading time + // of a specific event. If startAtZero is set, then this is useless, and we + // want to return 0. + if (eventTime !== -1 && !this.startAtZero) + return ((eventTime - this.minimumBoundary) / this.boundarySpan) * 100; + + return 0; + }, + + computeBarGraphLabels: function(resource) + { + var rightLabel = ""; + if (resource.responseReceivedTime !== -1 && resource.endTime !== -1) + rightLabel = this.formatValue(resource.endTime - resource.responseReceivedTime); + + var hasLatency = resource.latency > 0; + if (hasLatency) + var leftLabel = this.formatValue(resource.latency); + else + var leftLabel = rightLabel; + + if (resource.timing) + return {left: leftLabel, right: rightLabel}; + + if (hasLatency && rightLabel) { + var total = this.formatValue(resource.duration); + var tooltip = WebInspector.UIString("%s latency, %s download (%s total)", leftLabel, rightLabel, total); + } else if (hasLatency) + var tooltip = WebInspector.UIString("%s latency", leftLabel); + else if (rightLabel) + var tooltip = WebInspector.UIString("%s download", rightLabel); + + if (resource.cached) + tooltip = WebInspector.UIString("%s (from cache)", tooltip); + return {left: leftLabel, right: rightLabel, tooltip: tooltip}; + }, + + updateBoundaries: function(resource) + { + var didChange = false; + + var lowerBound; + if (this.startAtZero) + lowerBound = 0; + else + lowerBound = this._lowerBound(resource); + + if (lowerBound !== -1 && (typeof this.minimumBoundary === "undefined" || lowerBound < this.minimumBoundary)) { + this.minimumBoundary = lowerBound; + didChange = true; + } + + var upperBound = this._upperBound(resource); + if (upperBound !== -1 && (typeof this.maximumBoundary === "undefined" || upperBound > this.maximumBoundary)) { + this.maximumBoundary = upperBound; + didChange = true; + } + + return didChange; + }, + + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString); + }, + + _lowerBound: function(resource) + { + return 0; + }, + + _upperBound: function(resource) + { + return 0; + } +} + +WebInspector.NetworkTimeCalculator.prototype.__proto__ = WebInspector.NetworkBaseCalculator.prototype; + +WebInspector.NetworkTransferTimeCalculator = function() +{ + WebInspector.NetworkTimeCalculator.call(this, false); +} + +WebInspector.NetworkTransferTimeCalculator.prototype = { + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString); + }, + + _lowerBound: function(resource) + { + return resource.startTime; + }, + + _upperBound: function(resource) + { + return resource.endTime; + } +} + +WebInspector.NetworkTransferTimeCalculator.prototype.__proto__ = WebInspector.NetworkTimeCalculator.prototype; + +WebInspector.NetworkTransferDurationCalculator = function() +{ + WebInspector.NetworkTimeCalculator.call(this, true); +} + +WebInspector.NetworkTransferDurationCalculator.prototype = { + formatValue: function(value) + { + return Number.secondsToString(value, WebInspector.UIString); + }, + + _upperBound: function(resource) + { + return resource.duration; + } +} + +WebInspector.NetworkTransferDurationCalculator.prototype.__proto__ = WebInspector.NetworkTimeCalculator.prototype; + +WebInspector.NetworkTransferSizeCalculator = function() +{ + WebInspector.NetworkBaseCalculator.call(this); +} + +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) + { + 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}; + }, + + _value: function(resource) + { + return resource.resourceSize; + }, + + _networkBytes: function(resource) + { + return resource.transferSize; + }, + + 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() + { + 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; + var div = document.createElement("div"); + td.appendChild(div); + this._element.appendChild(td); + return div; + }, + + + _createTimelineCell: function() + { + this._graphElement = document.createElement("div"); + this._graphElement.className = "network-graph-side"; + this._graphElement.addEventListener("mouseover", this._refreshLabelPositions.bind(this), false); + + this._barAreaElement = document.createElement("div"); + // this._barAreaElement.className = "network-graph-bar-area hidden"; + this._barAreaElement.className = "network-graph-bar-area"; + this._barAreaElement.resource = this._resource; + this._graphElement.appendChild(this._barAreaElement); + + this._barLeftElement = document.createElement("div"); + this._barLeftElement.className = "network-graph-bar waiting"; + this._barAreaElement.appendChild(this._barLeftElement); + + this._barRightElement = document.createElement("div"); + this._barRightElement.className = "network-graph-bar"; + this._barAreaElement.appendChild(this._barRightElement); + + this._labelLeftElement = document.createElement("div"); + this._labelLeftElement.className = "network-graph-label waiting"; + this._barAreaElement.appendChild(this._labelLeftElement); + + this._labelRightElement = document.createElement("div"); + this._labelRightElement.className = "network-graph-label"; + this._barAreaElement.appendChild(this._labelRightElement); + + this._timelineCell = document.createElement("td"); + this._element.appendChild(this._timelineCell); + this._timelineCell.appendChild(this._graphElement); + }, + + refreshResource: function() + { + this._refreshURLCell(); + + this._methodCell.textContent = this._resource.requestMethod; + + this._refreshStatusCell(); + + if (this._resource.mimeType) { + this._typeCell.removeStyleClass("network-dim-cell"); + this._typeCell.textContent = this._resource.mimeType; + } else { + this._typeCell.addStyleClass("network-dim-cell"); + this._typeCell.textContent = WebInspector.UIString("Pending"); + } + + this._refreshSizeCell(); + this._refreshTimeCell(); + + if (this._resource.cached) + this._graphElement.addStyleClass("resource-cached"); + + if (!this._element.hasStyleClass("network-category-" + this._resource.category.name)) { + this._element.removeMatchingStyleClasses("network-category-\\w+"); + this._element.addStyleClass("network-category-" + this._resource.category.name); + } + }, + + _refreshURLCell: function() + { + this._urlCell.removeChildren(); + + if (this._resource.category === WebInspector.resourceCategories.images) { + var previewImage = document.createElement("img"); + previewImage.className = "image-network-icon-preview"; + previewImage.src = this._resource.url; + + var iconElement = document.createElement("div"); + iconElement.className = "icon"; + iconElement.appendChild(previewImage); + } else { + var iconElement = document.createElement("img"); + iconElement.className = "icon"; + } + this._urlCell.appendChild(iconElement); + this._urlCell.appendChild(document.createTextNode(this._fileName())); + + + var subtitle = this._resource.displayDomain; + + if (this._resource.path && this._resource.lastPathComponent) { + var lastPathComponentIndex = this._resource.path.lastIndexOf("/" + this._resource.lastPathComponent); + if (lastPathComponentIndex != -1) + 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; + }, + + _fileName: function() + { + var fileName = this._resource.displayName; + if (this._resource.queryString) + fileName += "?" + this._resource.queryString; + return fileName; + }, + + _refreshStatusCell: function() + { + 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); + this._statusCell.title = this._resource.statusCode + " " + this._resource.statusText; + } else { + this._statusCell.addStyleClass("network-dim-cell"); + this._statusCell.textContent = WebInspector.UIString("Pending"); + } + }, + + _refreshSizeCell: function() + { + var resourceSize = typeof this._resource.resourceSize === "number" ? Number.bytesToString(this._resource.resourceSize) : "?"; + var transferSize = typeof this._resource.transferSize === "number" ? Number.bytesToString(this._resource.transferSize) : "?"; + var fromCache = this._resource.cached; + this._sizeCell.textContent = !fromCache ? resourceSize : WebInspector.UIString("(from cache)"); + if (fromCache) + this._sizeCell.addStyleClass("network-dim-cell"); + else + this._sizeCell.removeStyleClass("network-dim-cell"); + if (!fromCache) + this._appendSubtitle(this._sizeCell, transferSize); + }, + + _refreshTimeCell: function() + { + if (this._resource.duration > 0) { + this._timeCell.removeStyleClass("network-dim-cell"); + this._timeCell.textContent = Number.secondsToString(this._resource.duration); + this._appendSubtitle(this._timeCell, Number.secondsToString(this._resource.latency)); + } else { + this._timeCell.addStyleClass("network-dim-cell"); + this._timeCell.textContent = WebInspector.UIString("Pending"); + } + }, + + _appendSubtitle: function(cellElement, subtitleText) + { + var subtitleElement = document.createElement("div"); + subtitleElement.className = "network-grid-subtitle"; + subtitleElement.textContent = subtitleText; + cellElement.appendChild(subtitleElement); + }, + + refreshGraph: function(calculator) + { + var percentages = calculator.computeBarGraphPercentages(this._resource); + var labels = calculator.computeBarGraphLabels(this._resource); + + this._percentages = percentages; + + this._barAreaElement.removeStyleClass("hidden"); + + if (!this._graphElement.hasStyleClass("network-category-" + this._resource.category.name)) { + this._graphElement.removeMatchingStyleClasses("network-category-\\w+"); + this._graphElement.addStyleClass("network-category-" + this._resource.category.name); + } + + this._barLeftElement.style.setProperty("left", percentages.start + "%"); + this._barRightElement.style.setProperty("right", (100 - percentages.end) + "%"); + + this._barLeftElement.style.setProperty("right", (100 - percentages.end) + "%"); + this._barRightElement.style.setProperty("left", percentages.middle + "%"); + + this._labelLeftElement.textContent = labels.left; + this._labelRightElement.textContent = labels.right; + + var tooltip = (labels.tooltip || ""); + this._barLeftElement.title = tooltip; + this._labelLeftElement.title = tooltip; + this._labelRightElement.title = tooltip; + this._barRightElement.title = tooltip; + }, + + _refreshLabelPositions: function() + { + this._labelLeftElement.style.removeProperty("left"); + this._labelLeftElement.style.removeProperty("right"); + this._labelLeftElement.removeStyleClass("before"); + this._labelLeftElement.removeStyleClass("hidden"); + + this._labelRightElement.style.removeProperty("left"); + this._labelRightElement.style.removeProperty("right"); + this._labelRightElement.removeStyleClass("after"); + this._labelRightElement.removeStyleClass("hidden"); + + const labelPadding = 10; + const barRightElementOffsetWidth = this._barRightElement.offsetWidth; + const barLeftElementOffsetWidth = this._barLeftElement.offsetWidth; + + if (this._barLeftElement) { + var leftBarWidth = barLeftElementOffsetWidth - labelPadding; + var rightBarWidth = (barRightElementOffsetWidth - barLeftElementOffsetWidth) - labelPadding; + } else { + var leftBarWidth = (barLeftElementOffsetWidth - barRightElementOffsetWidth) - labelPadding; + var rightBarWidth = barRightElementOffsetWidth - labelPadding; + } + + const labelLeftElementOffsetWidth = this._labelLeftElement.offsetWidth; + const labelRightElementOffsetWidth = this._labelRightElement.offsetWidth; + + const labelBefore = (labelLeftElementOffsetWidth > leftBarWidth); + const labelAfter = (labelRightElementOffsetWidth > rightBarWidth); + const graphElementOffsetWidth = this._graphElement.offsetWidth; + + if (labelBefore && (graphElementOffsetWidth * (this._percentages.start / 100)) < (labelLeftElementOffsetWidth + 10)) + var leftHidden = true; + + if (labelAfter && (graphElementOffsetWidth * ((100 - this._percentages.end) / 100)) < (labelRightElementOffsetWidth + 10)) + var rightHidden = true; + + if (barLeftElementOffsetWidth == barRightElementOffsetWidth) { + // The left/right label data are the same, so a before/after label can be replaced by an on-bar label. + if (labelBefore && !labelAfter) + leftHidden = true; + else if (labelAfter && !labelBefore) + rightHidden = true; + } + + if (labelBefore) { + if (leftHidden) + this._labelLeftElement.addStyleClass("hidden"); + this._labelLeftElement.style.setProperty("right", (100 - this._percentages.start) + "%"); + this._labelLeftElement.addStyleClass("before"); + } else { + this._labelLeftElement.style.setProperty("left", this._percentages.start + "%"); + this._labelLeftElement.style.setProperty("right", (100 - this._percentages.middle) + "%"); + } + + if (labelAfter) { + if (rightHidden) + this._labelRightElement.addStyleClass("hidden"); + this._labelRightElement.style.setProperty("left", this._percentages.end + "%"); + this._labelRightElement.addStyleClass("after"); + } else { + this._labelRightElement.style.setProperty("left", this._percentages.middle + "%"); + this._labelRightElement.style.setProperty("right", (100 - this._percentages.end) + "%"); + } + } +} + +WebInspector.NetworkDataGridNode.URLComparator = 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 : ""); + if (aFileName > bFileName) + return 1; + if (bFileName > aFileName) + return -1; + return 0; +} + +WebInspector.NetworkDataGridNode.ResourcePropertyComparator = function(propertyName, a, b) +{ + var aValue = a._resource[propertyName]; + var bValue = b._resource[propertyName]; + if (aValue > bValue) + return 1; + if (bValue > aValue) + return -1; + return 0; +} + +WebInspector.NetworkDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; diff --git a/WebCore/inspector/front-end/ResourceCategory.js b/WebCore/inspector/front-end/ResourceCategory.js index 6e94265..84f2cf9 100644 --- a/WebCore/inspector/front-end/ResourceCategory.js +++ b/WebCore/inspector/front-end/ResourceCategory.js @@ -28,12 +28,19 @@ WebInspector.ResourceCategory = function(name, title, color) { - WebInspector.AbstractTimelineCategory.call(this, name, title, color); + this.name = name; + this.title = title; + this.color = color; this.resources = []; } WebInspector.ResourceCategory.prototype = { + toString: function() + { + return this.title; + }, + addResource: function(resource) { var a = resource; @@ -61,5 +68,3 @@ WebInspector.ResourceCategory.prototype = { this.resources = []; } } - -WebInspector.ResourceCategory.prototype.__proto__ = WebInspector.AbstractTimelineCategory.prototype; diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js index f329b1a..aa021ff 100644 --- a/WebCore/inspector/front-end/ResourcesPanel.js +++ b/WebCore/inspector/front-end/ResourcesPanel.js @@ -29,7 +29,10 @@ WebInspector.ResourcesPanel = function() { - WebInspector.AbstractTimelinePanel.call(this, "resources"); + WebInspector.Panel.call(this, "resources"); + + this._items = []; + this._staleItems = []; this._createPanelEnabler(); @@ -82,6 +85,299 @@ WebInspector.ResourcesPanel.prototype = { return (this.itemsGraphsElement.hasStyleClass("filter-all") || this.itemsGraphsElement.hasStyleClass("filter-" + categoryName.toLowerCase())); }, + get items() + { + return this._items; + }, + + createInterface: function() + { + this.containerElement = document.createElement("div"); + this.containerElement.id = "resources-container"; + this.containerElement.addEventListener("scroll", this._updateDividersLabelBarPosition.bind(this), false); + this.element.appendChild(this.containerElement); + + this.createSidebar(this.containerElement, this.element); + this.sidebarElement.id = "resources-sidebar"; + this.populateSidebar(); + + this._containerContentElement = document.createElement("div"); + this._containerContentElement.id = "resources-container-content"; + this.containerElement.appendChild(this._containerContentElement); + + this.summaryBar = new WebInspector.SummaryBar(this.categories); + this.summaryBar.element.id = "resources-summary"; + this._containerContentElement.appendChild(this.summaryBar.element); + + this._timelineGrid = new WebInspector.TimelineGrid(); + this._containerContentElement.appendChild(this._timelineGrid.element); + this.itemsGraphsElement = this._timelineGrid.itemsGraphsElement; + }, + + createFilterPanel: function() + { + this.filterBarElement = document.createElement("div"); + this.filterBarElement.id = "resources-filter"; + this.filterBarElement.className = "scope-bar"; + this.element.appendChild(this.filterBarElement); + + function createFilterElement(category) + { + if (category === "all") + var label = WebInspector.UIString("All"); + else if (this.categories[category]) + var label = this.categories[category].title; + + var categoryElement = document.createElement("li"); + categoryElement.category = category; + categoryElement.addStyleClass(category); + categoryElement.appendChild(document.createTextNode(label)); + categoryElement.addEventListener("click", this._updateFilter.bind(this), false); + this.filterBarElement.appendChild(categoryElement); + + return categoryElement; + } + + this.filterAllElement = createFilterElement.call(this, "all"); + + // Add a divider + var dividerElement = document.createElement("div"); + dividerElement.addStyleClass("divider"); + this.filterBarElement.appendChild(dividerElement); + + for (var category in this.categories) + createFilterElement.call(this, category); + }, + + showCategory: function(category) + { + var filterClass = "filter-" + category.toLowerCase(); + this.itemsGraphsElement.addStyleClass(filterClass); + this.itemsTreeElement.childrenListElement.addStyleClass(filterClass); + }, + + hideCategory: function(category) + { + var filterClass = "filter-" + category.toLowerCase(); + this.itemsGraphsElement.removeStyleClass(filterClass); + this.itemsTreeElement.childrenListElement.removeStyleClass(filterClass); + }, + + 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 === 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); + } + }, + + _updateFilter: function(e) + { + var isMac = WebInspector.isMac(); + var selectMultiple = false; + if (isMac && e.metaKey && !e.ctrlKey && !e.altKey && !e.shiftKey) + selectMultiple = true; + if (!isMac && e.ctrlKey && !e.metaKey && !e.altKey && !e.shiftKey) + selectMultiple = true; + + this.filter(e.target, selectMultiple); + + // 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; + + var searchField = document.getElementById("search"); + WebInspector.doPerformSearch(searchField.value, WebInspector.shortSearchWasForcedByKeyEvent, false, true); + }, + + _updateDividersLabelBarPosition: function() + { + const scrollTop = this.containerElement.scrollTop; + const offsetHeight = this.summaryBar.element.offsetHeight; + const dividersTop = (scrollTop < offsetHeight ? offsetHeight : scrollTop); + this._timelineGrid.setScrollAndDividerTop(scrollTop, dividersTop); + }, + + get needsRefresh() + { + return this._needsRefresh; + }, + + set needsRefresh(x) + { + if (this._needsRefresh === x) + return; + + this._needsRefresh = x; + + if (x) { + if (this.visible && !("_refreshTimeout" in this)) + this._refreshTimeout = setTimeout(this.refresh.bind(this), 500); + } else { + if ("_refreshTimeout" in this) { + clearTimeout(this._refreshTimeout); + delete this._refreshTimeout; + } + } + }, + + refreshIfNeeded: function() + { + if (this.needsRefresh) + this.refresh(); + }, + + resize: function() + { + WebInspector.Panel.prototype.resize.call(this); + + this.updateGraphDividersIfNeeded(); + }, + + invalidateAllItems: function() + { + this._staleItems = this._items.slice(); + }, + + get calculator() + { + return this._calculator; + }, + + set calculator(x) + { + if (!x || this._calculator === x) + return; + + this._calculator = x; + this._calculator.reset(); + + this._staleItems = this._items.slice(); + this.refresh(); + }, + + addItem: function(item) + { + this._items.push(item); + this.refreshItem(item); + }, + + removeItem: function(item) + { + this._items.remove(item, true); + + if (item._itemsTreeElement) { + this.itemsTreeElement.removeChild(item._itemsTreeElement); + this.itemsGraphsElement.removeChild(item._itemsTreeElement._itemGraph.graphElement); + } + + delete item._itemsTreeElement; + this.adjustScrollPosition(); + }, + + refreshItem: function(item) + { + this._staleItems.push(item); + this.needsRefresh = true; + }, + + revealAndSelectItem: function(item) + { + if (item._itemsTreeElement) { + item._itemsTreeElement.reveal(); + item._itemsTreeElement.select(true); + } + }, + + sortItems: function(sortingFunction) + { + var sortedElements = [].concat(this.itemsTreeElement.children); + sortedElements.sort(sortingFunction); + + var sortedElementsLength = sortedElements.length; + for (var i = 0; i < sortedElementsLength; ++i) { + var treeElement = sortedElements[i]; + if (treeElement === this.itemsTreeElement.children[i]) + continue; + + var wasSelected = treeElement.selected; + this.itemsTreeElement.removeChild(treeElement); + this.itemsTreeElement.insertChild(treeElement, i); + if (wasSelected) + treeElement.select(true); + + var graphElement = treeElement._itemGraph.graphElement; + this.itemsGraphsElement.insertBefore(graphElement, this.itemsGraphsElement.children[i]); + } + }, + + adjustScrollPosition: function() + { + // Prevent the container from being scrolled off the end. + if ((this.containerElement.scrollTop + this.containerElement.offsetHeight) > this.sidebarElement.offsetHeight) + this.containerElement.scrollTop = (this.sidebarElement.offsetHeight - this.containerElement.offsetHeight); + }, + + addEventDivider: function(divider) + { + this._timelineGrid.addEventDivider(divider); + }, + + hideEventDividers: function() + { + this._timelineGrid.hideEventDividers(); + }, + + showEventDividers: function() + { + this._timelineGrid.showEventDividers(); + }, + populateSidebar: function() { this.timeGraphItem = new WebInspector.SidebarTreeElement("resources-time-graph-sidebar-item", WebInspector.UIString("Time")); @@ -223,7 +519,10 @@ WebInspector.ResourcesPanel.prototype = { show: function() { - WebInspector.AbstractTimelinePanel.prototype.show.call(this); + WebInspector.Panel.prototype.show.call(this); + + this._updateDividersLabelBarPosition(); + this.refreshIfNeeded(); var visibleView = this.visibleView; if (this.visibleResource) { @@ -329,7 +628,44 @@ WebInspector.ResourcesPanel.prototype = { refresh: function() { - WebInspector.AbstractTimelinePanel.prototype.refresh.call(this); + this.needsRefresh = false; + + var staleItemsLength = this._staleItems.length; + + var boundariesChanged = false; + + for (var i = 0; i < staleItemsLength; ++i) { + var item = this._staleItems[i]; + if (!item._itemsTreeElement) { + // Create the timeline tree element and graph. + item._itemsTreeElement = this.createItemTreeElement(item); + item._itemsTreeElement._itemGraph = this.createItemGraph(item); + + this.itemsTreeElement.appendChild(item._itemsTreeElement); + this.itemsGraphsElement.appendChild(item._itemsTreeElement._itemGraph.graphElement); + } + + if (item._itemsTreeElement.refresh) + item._itemsTreeElement.refresh(); + + if (this.calculator.updateBoundaries(item)) + boundariesChanged = true; + } + + if (boundariesChanged) { + // The boundaries changed, so all item graphs are stale. + this._staleItems = this._items.slice(); + staleItemsLength = this._staleItems.length; + } + + + const isBarOpaqueAtLeft = this.sidebarTree.selectedTreeElement && this.sidebarTree.selectedTreeElement.isBarOpaqueAtLeft; + for (var i = 0; i < staleItemsLength; ++i) + this._staleItems[i]._itemsTreeElement._itemGraph.refresh(this.calculator, isBarOpaqueAtLeft); + + this._staleItems = []; + + this.updateGraphDividersIfNeeded(); this._sortResourcesIfNeeded(); this._updateSummaryGraph(); @@ -373,7 +709,28 @@ WebInspector.ResourcesPanel.prototype = { } } - WebInspector.AbstractTimelinePanel.prototype.reset.call(this); + // Begin reset timeline + this.containerElement.scrollTop = 0; + + if (this._calculator) + this._calculator.reset(); + + if (this._items) { + var itemsLength = this._items.length; + for (var i = 0; i < itemsLength; ++i) { + var item = this._items[i]; + delete item._itemsTreeElement; + } + } + + this._items = []; + this._staleItems = []; + + this.itemsTreeElement.removeChildren(); + this.itemsGraphsElement.removeChildren(); + + this.updateGraphDividersIfNeeded(true); + // End reset timeline. this.mainResourceLoadTime = -1; this.mainResourceDOMContentTime = -1; @@ -585,7 +942,12 @@ WebInspector.ResourcesPanel.prototype = { updateGraphDividersIfNeeded: function(force) { - var proceed = WebInspector.AbstractTimelinePanel.prototype.updateGraphDividersIfNeeded.call(this, force); + var proceed = true; + if (!this.visible) { + this.needsRefresh = true; + proceed = false; + } else + proceed = this._timelineGrid.updateDividers(force, this.calculator); if (!proceed) return; @@ -739,8 +1101,7 @@ WebInspector.ResourcesPanel.prototype = { updateMainViewWidth: function(width) { this.viewsContainerElement.style.left = width + "px"; - - WebInspector.AbstractTimelinePanel.prototype.updateMainViewWidth.call(this, width); + this._containerContentElement.style.left = width + "px"; this.resize(); }, @@ -918,16 +1279,86 @@ WebInspector.ResourcesPanel.prototype = { } } -WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.AbstractTimelinePanel.prototype; +WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype; WebInspector.getResourceContent = function(identifier, callback) { InspectorBackend.getResourceContent(identifier, callback); } +WebInspector.ResourceBaseCalculator = function() +{ +} + +WebInspector.ResourceBaseCalculator.prototype = { + computeSummaryValues: function(items) + { + var total = 0; + var categoryValues = {}; + + var itemsLength = items.length; + for (var i = 0; i < itemsLength; ++i) { + var item = items[i]; + var value = this._value(item); + if (typeof value === "undefined") + continue; + if (!(item.category.name in categoryValues)) + categoryValues[item.category.name] = 0; + categoryValues[item.category.name] += value; + total += value; + } + + return {categoryValues: categoryValues, total: total}; + }, + + computeBarGraphPercentages: function(item) + { + return {start: 0, middle: 0, end: (this._value(item) / this.boundarySpan) * 100}; + }, + + computeBarGraphLabels: function(item) + { + const label = this.formatValue(this._value(item)); + return {left: label, right: label, tooltip: label}; + }, + + get boundarySpan() + { + return this.maximumBoundary - this.minimumBoundary; + }, + + updateBoundaries: function(item) + { + this.minimumBoundary = 0; + + var value = this._value(item); + if (typeof this.maximumBoundary === "undefined" || value > this.maximumBoundary) { + this.maximumBoundary = value; + return true; + } + return false; + }, + + reset: function() + { + delete this.minimumBoundary; + delete this.maximumBoundary; + }, + + _value: function(item) + { + return 0; + }, + + formatValue: function(value) + { + return value.toString(); + } +} + WebInspector.ResourceTimeCalculator = function(startAtZero) { - WebInspector.AbstractTimelineCalculator.call(this); + WebInspector.ResourceBaseCalculator.call(this); this.startAtZero = startAtZero; } @@ -1092,7 +1523,7 @@ WebInspector.ResourceTimeCalculator.prototype = { } } -WebInspector.ResourceTimeCalculator.prototype.__proto__ = WebInspector.AbstractTimelineCalculator.prototype; +WebInspector.ResourceTimeCalculator.prototype.__proto__ = WebInspector.ResourceBaseCalculator.prototype; WebInspector.ResourceTransferTimeCalculator = function() { @@ -1139,7 +1570,7 @@ WebInspector.ResourceTransferDurationCalculator.prototype.__proto__ = WebInspect WebInspector.ResourceTransferSizeCalculator = function() { - WebInspector.AbstractTimelineCalculator.call(this); + WebInspector.ResourceBaseCalculator.call(this); } WebInspector.ResourceTransferSizeCalculator.prototype = { @@ -1186,7 +1617,7 @@ WebInspector.ResourceTransferSizeCalculator.prototype = { } } -WebInspector.ResourceTransferSizeCalculator.prototype.__proto__ = WebInspector.AbstractTimelineCalculator.prototype; +WebInspector.ResourceTransferSizeCalculator.prototype.__proto__ = WebInspector.ResourceBaseCalculator.prototype; WebInspector.ResourceSidebarTreeElement = function(resource) { diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 715339d..8283528 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -104,7 +104,6 @@ WebInspector.ScriptsPanel = function() this.sidebarButtonsElement.appendChild(this.stepOutButton); this.toggleBreakpointsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Deactivate all breakpoints."), "toggle-breakpoints"); - // Breakpoints should be activated by default, so emulate a click to toggle on. this.toggleBreakpointsButton.toggled = true; this.toggleBreakpointsButton.addEventListener("click", this.toggleBreakpointsClicked.bind(this), false); this.sidebarButtonsElement.appendChild(this.toggleBreakpointsButton.element); @@ -133,8 +132,13 @@ WebInspector.ScriptsPanel = function() this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); this.sidebarPanes.jsBreakpoints = WebInspector.createJSBreakpointsSidebarPane(); - if (Preferences.domBreakpointsEnabled) + 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.workers = new WebInspector.WorkersSidebarPane(); for (var pane in this.sidebarPanes) @@ -145,8 +149,6 @@ WebInspector.ScriptsPanel = function() this.sidebarPanes.scopechain.expanded = true; this.sidebarPanes.jsBreakpoints.expanded = true; - if (Preferences.domBreakpointsEnabled) - this.sidebarPanes.domBreakpoints.expanded = true; var panelEnablerHeading = WebInspector.UIString("You need to enable debugging before you can use the Scripts panel."); var panelEnablerDisclaimer = WebInspector.UIString("Enabling debugging will make scripts run slower."); @@ -387,8 +389,8 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.callstack.update(details.callFrames, this._sourceIDMap); this.sidebarPanes.callstack.selectedCallFrame = details.callFrames[0]; - if (details.status) - this.sidebarPanes.callstack.updateStatus(details.status); + if ("eventType" in details) + this.sidebarPanes.callstack.updateStatus(details.eventType, details.eventData); WebInspector.currentPanel = this; window.focus(); @@ -467,8 +469,10 @@ WebInspector.ScriptsPanel.prototype = { this.sidebarPanes.watchExpressions.refreshExpressions(); if (!preserveItems) { this.sidebarPanes.jsBreakpoints.reset(); - if (Preferences.domBreakpointsEnabled) + if (Preferences.nativeInstrumentationEnabled) { this.sidebarPanes.domBreakpoints.reset(); + this.sidebarPanes.xhrBreakpoints.reset(); + } this.sidebarPanes.workers.reset(); } }, @@ -891,7 +895,7 @@ WebInspector.ScriptsPanel.prototype = { _togglePauseOnExceptions: function() { - InspectorBackend.setPauseOnExceptionsState((this._pauseOnExceptionButton.state + 1) % this._pauseOnExceptionButton.states); + InspectorBackend.setPauseOnExceptionsState((this._pauseOnExceptionButton.state + 1) % this._pauseOnExceptionButton.states, this.updatePauseOnExceptionsState.bind(this)); }, _togglePause: function() @@ -998,6 +1002,9 @@ WebInspector.ScriptsPanel.prototype = { this._shortcuts[shortcut2.key] = handler; section.addAlternateKeys([ shortcut1.name, shortcut2.name ], WebInspector.UIString("Step out")); + shortcut1 = WebInspector.KeyboardShortcut.makeDescriptor("g", platformSpecificModifier); + this._shortcuts[shortcut1.key] = this.showGoToLineDialog.bind(this); + section.addAlternateKeys([ shortcut1.name ], WebInspector.UIString("Go to Line")); this.sidebarPanes.callstack.registerShortcuts(section); }, @@ -1067,6 +1074,13 @@ WebInspector.ScriptsPanel.prototype = { this._searchView.jumpToLastSearchResult(); else this._searchView.jumpToPreviousSearchResult(); + }, + + showGoToLineDialog: function(e) + { + var view = this.visibleView; + if (view) + WebInspector.GoToLineDialog.show(view); } } diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js index 63f2641..c6da14d 100644 --- a/WebCore/inspector/front-end/Settings.js +++ b/WebCore/inspector/front-end/Settings.js @@ -42,10 +42,10 @@ var Preferences = { showColorNicknames: true, debuggerAlwaysEnabled: false, profilerAlwaysEnabled: false, - auditsPanelEnabled: true, onlineDetectionEnabled: true, - domBreakpointsEnabled: false, - resourceExportEnabled: false + nativeInstrumentationEnabled: false, + resourceExportEnabled: false, + networkPanelEnabled: false } WebInspector.Settings = function(sessionScope) diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index a9033f2..aecd57b 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -498,7 +498,8 @@ WebInspector.SourceFrame.prototype = { self._hidePopup(); delete self._hidePopupTimer; } - this._hidePopupTimer = setTimeout(doHide, 500); + if (!("_hidePopupTimer" in this)) + this._hidePopupTimer = setTimeout(doHide, 500); } this._hoverElement = event.target; diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index c222f0e..11382cd 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -1,7 +1,6 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/webkit/inspector"> <file>inspector.html</file> - <file>AbstractTimelinePanel.js</file> <file>ApplicationCacheItemsView.js</file> <file>AuditCategories.js</file> <file>AuditFormatters.js</file> @@ -42,6 +41,7 @@ <file>ExtensionRegistryStub.js</file> <file>ExtensionServer.js</file> <file>FontView.js</file> + <file>GoToLineDialog.js</file> <file>HAREntry.js</file> <file>HeapSnapshotView.js</file> <file>HelpScreen.js</file> @@ -53,6 +53,7 @@ <file>InspectorFrontendHostStub.js</file> <file>KeyboardShortcut.js</file> <file>MetricsSidebarPane.js</file> + <file>NetworkPanel.js</file> <file>Object.js</file> <file>ObjectPropertiesSection.js</file> <file>Panel.js</file> @@ -106,10 +107,12 @@ <file>WelcomeView.js</file> <file>WorkersSidebarPane.js</file> <file>audits.css</file> + <file>goToLineDialog.css</file> <file>heapProfiler.css</file> <file>helpScreen.css</file> <file>inspector.css</file> <file>inspectorSyntaxHighlight.css</file> + <file>networkPanel.css</file> <file>popover.css</file> <file>textViewer.css</file> <file>Images/applicationCache.png</file> @@ -164,7 +167,9 @@ <file>Images/grayConnectorPoint.png</file> <file>Images/largerResourcesButtonGlyph.png</file> <file>Images/localStorage.png</file> + <file>Images/networkIcon.png</file> <file>Images/nodeSearchButtonGlyph.png</file> + <file>Images/paneAddButtons.png</file> <file>Images/paneBottomGrow.png</file> <file>Images/paneBottomGrowActive.png</file> <file>Images/paneGrowHandleLine.png</file> diff --git a/WebCore/inspector/front-end/goToLineDialog.css b/WebCore/inspector/front-end/goToLineDialog.css new file mode 100644 index 0000000..725e4c8 --- /dev/null +++ b/WebCore/inspector/front-end/goToLineDialog.css @@ -0,0 +1,39 @@ +.go-to-line-dialog { + position: absolute; + top: 40%; + left: 40%; + z-index: 1900; + + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#E9E9E9), to(#CFCFCF)); + display: -webkit-box; + -webkit-box-orient: vertical; + padding: 10px; + border-radius: 10px; + border: 1px solid gray; + -webkit-box-shadow: rgb(40,40,40) 0px 0px 50px; + + font-size: 11px; + font-family: 'Lucida Grande', sans-serif; +} + +.go-to-line-dialog input { + font-size: 11px; +} + +.go-to-line-dialog button { + font-size: 11px; + color: rgb(6, 6, 6); + border: 1px solid rgb(165, 165, 165); + background-color: rgb(237, 237, 237); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223))); + -webkit-border-radius: 12px; + -webkit-appearance: none; + + padding: 3px 20px; + margin: 0 0 0 10px; +} + +.go-to-line-dialog button:active { + background-color: rgb(215, 215, 215); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(194, 194, 194)), to(rgb(239, 239, 239))); +} diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 6d8571c..848afdc 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -207,6 +207,10 @@ body.attached #search-results-matches { background-image: url(Images/resourcesIcon.png); } +.toolbar-item.network .toolbar-icon { + background-image: url(Images/networkIcon.png); +} + .toolbar-item.scripts .toolbar-icon { background-image: url(Images/scriptsIcon.png); } @@ -1677,6 +1681,29 @@ li.editing .swatch, li.editing .enabled-button, li.editing-sub-part .delete-but color: black; } +.pane > .title > button.add { + float: right; + width: 23px; + height: 17px; + color: transparent; + background-color: transparent; + border: none; + background-image: url(Images/paneAddButtons.png); + background-repeat: no-repeat; + margin: 1px 0 0 0; + padding: 0; + -webkit-border-radius: 0; + -webkit-appearance: none; +} + +.pane > .title > button.add:hover { + background-position: -23px 0px; +} + +.pane > .title > button.add:active { + background-position: -46px 0px; +} + .pane > .body { position: relative; display: none; @@ -1701,6 +1728,14 @@ li.editing .swatch, li.editing .enabled-button, li.editing-sub-part .delete-but display: block; } +.pane > .body .breakpoint-condition { + display: block; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 25px; + margin-right: 10px; +} + .pane.expanded:nth-last-of-type(1) { border-bottom: 1px solid rgb(189, 189, 189); } @@ -1950,8 +1985,6 @@ body.inactive .sidebar { padding-right: 14px; overflow-x: hidden; overflow-y: overlay; - background-image: -webkit-gradient(linear, left top, left bottom, from(white), color-stop(0.5, white), color-stop(0.5, rgb(234, 243, 255)), to(rgb(234, 243, 255))); - -webkit-background-size: 1px 32px; } .data-grid.inline .data-container { diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 0536ee6..949b18f 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -30,9 +30,11 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <link rel="stylesheet" type="text/css" href="audits.css"> + <link rel="stylesheet" type="text/css" href="goToLineDialog.css"> <link rel="stylesheet" type="text/css" href="heapProfiler.css"> <link rel="stylesheet" type="text/css" href="inspector.css"> <link rel="stylesheet" type="text/css" href="inspectorSyntaxHighlight.css"> + <link rel="stylesheet" type="text/css" href="networkPanel.css"> <link rel="stylesheet" type="text/css" href="popover.css"> <link rel="stylesheet" type="text/css" href="textViewer.css"> <script type="text/javascript" src="utilities.js"></script> @@ -58,7 +60,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ConsoleView.js"></script> <script type="text/javascript" src="Panel.js"></script> <script type="text/javascript" src="TimelineGrid.js"></script> - <script type="text/javascript" src="AbstractTimelinePanel.js"></script> <script type="text/javascript" src="Resource.js"></script> <script type="text/javascript" src="ResourceCategory.js"></script> <script type="text/javascript" src="Database.js"></script> @@ -92,6 +93,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="StatusBarButton.js"></script> <script type="text/javascript" src="SummaryBar.js"></script> <script type="text/javascript" src="ElementsPanel.js"></script> + <script type="text/javascript" src="NetworkPanel.js"></script> <script type="text/javascript" src="ResourcesPanel.js"></script> <script type="text/javascript" src="InjectedFakeWorker.js"></script> <script type="text/javascript" src="ScriptsPanel.js"></script> @@ -138,6 +140,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="TimelineOverviewPane.js"></script> <script type="text/javascript" src="TestController.js"></script> <script type="text/javascript" src="HelpScreen.js"></script> + <script type="text/javascript" src="GoToLineDialog.js"></script> <script type="text/javascript" src="ShortcutsHelp.js"></script> <script type="text/javascript" src="HAREntry.js"></script> </head> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index f6fa06b..3edae8f 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -219,11 +219,24 @@ var WebInspector = { return pane; }, + createXHRBreakpointsSidebarPane: function() + { + var pane = new WebInspector.XHRBreakpointsSidebarPane(); + function breakpointAdded(event) + { + pane.addBreakpoint(new WebInspector.XHRBreakpointItem(event.data)); + } + WebInspector.breakpointManager.addEventListener("xhr-breakpoint-added", breakpointAdded); + return pane; + }, + _createPanels: function() { var hiddenPanels = (InspectorFrontendHost.hiddenPanels() || "").split(','); if (hiddenPanels.indexOf("elements") === -1) this.panels.elements = new WebInspector.ElementsPanel(); + if (Preferences.networkPanelEnabled && hiddenPanels.indexOf("network") === -1) + this.panels.network = new WebInspector.NetworkPanel(); if (hiddenPanels.indexOf("resources") === -1) this.panels.resources = new WebInspector.ResourcesPanel(); if (hiddenPanels.indexOf("scripts") === -1) @@ -238,7 +251,7 @@ var WebInspector = { } if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("databases") === -1) this.panels.storage = new WebInspector.StoragePanel(); - if (Preferences.auditsPanelEnabled && hiddenPanels.indexOf("audits") === -1) + if (hiddenPanels.indexOf("audits") === -1) this.panels.audits = new WebInspector.AuditsPanel(); if (hiddenPanels.indexOf("console") === -1) this.panels.console = new WebInspector.ConsolePanel(); @@ -435,12 +448,8 @@ var WebInspector = { _updateFocusedNode: function(nodeId) { - var node = WebInspector.domAgent.nodeForId(nodeId); - if (!node) - return; - this.currentPanel = this.panels.elements; - this.panels.elements.focusedDOMNode = node; + this.panels.elements.updateFocusedNode(nodeId); } } @@ -585,6 +594,8 @@ WebInspector.doLoadedDone = function() function populateInspectorState(inspectorState) { WebInspector.monitoringXHREnabled = inspectorState.monitoringXHREnabled; + if ("pauseOnExceptionsState" in inspectorState) + WebInspector.panels.scripts.updatePauseOnExceptionsState(inspectorState.pauseOnExceptionsState); if (inspectorState.resourceTrackingEnabled) WebInspector.panels.resources.resourceTrackingWasEnabled(); else @@ -677,8 +688,8 @@ WebInspector.dispatchMessageFromBackend = function(messageObject) WebInspector.reportProtocolError = function(messageObject) { console.error("Protocol Error: InspectorBackend request with seq = %d failed.", messageObject.seq); - for (var error in messageObject.errors) - console.error(" " + error); + for (var i = 0; i < messageObject.errors.length; ++i) + console.error(" " + messageObject.errors[i]); WebInspector.removeResponseCallbackEntry(messageObject.seq); } @@ -1216,10 +1227,10 @@ WebInspector.updateResource = function(payload) resource = new WebInspector.Resource(identifier, payload.url); this.resources[identifier] = resource; this.resourceURLMap[resource.url] = resource; - if (this.panels.resources) - this.panels.resources.addResource(resource); - if (this.panels.audits) - this.panels.audits.resourceStarted(resource); + this.panels.resources.addResource(resource); + this.panels.audits.resourceStarted(resource); + if (this.panels.network) + this.panels.network.addResource(resource); } if (payload.didRequestChange) { @@ -1261,13 +1272,11 @@ WebInspector.updateResource = function(payload) resource.webSocketChallengeResponse = payload.webSocketChallengeResponse; } - if (payload.didTypeChange) { + if (payload.didTypeChange) resource.type = payload.type; - } - if (payload.didLengthChange) { + if (payload.didLengthChange) resource.resourceSize = payload.resourceSize; - } if (payload.didCompletionChange) { resource.failed = payload.failed; @@ -1289,21 +1298,24 @@ WebInspector.updateResource = function(payload) // 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. - if (this.panels.resources) - this.panels.resources.mainResourceLoadTime = payload.loadEventTime; - if (this.panels.audits) - this.panels.audits.mainResourceLoadTime = payload.loadEventTime; + 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. - if (this.panels.resources) - this.panels.resources.mainResourceDOMContentTime = payload.domContentEventTime; - if (this.panels.audits) - this.panels.audits.mainResourceDOMContentTime = payload.domContentEventTime; + this.panels.resources.mainResourceDOMContentTime = payload.domContentEventTime; + this.panels.audits.mainResourceDOMContentTime = payload.domContentEventTime; + if (this.panels.network) + this.panels.network.mainResourceDOMContentTime = payload.domContentEventTime; } } + + if (this.panels.network) + this.panels.network.refreshResource(resource); } WebInspector.removeResource = function(identifier) @@ -1402,11 +1414,6 @@ WebInspector.debuggerWasEnabled = function() this.panels.scripts.debuggerWasEnabled(); } -WebInspector.updatePauseOnExceptionsState = function(pauseOnExceptionsState) -{ - this.panels.scripts.updatePauseOnExceptionsState(pauseOnExceptionsState); -} - WebInspector.debuggerWasDisabled = function() { this.panels.scripts.debuggerWasDisabled(); diff --git a/WebCore/inspector/front-end/networkPanel.css b/WebCore/inspector/front-end/networkPanel.css new file mode 100644 index 0000000..cdea7fe --- /dev/null +++ b/WebCore/inspector/front-end/networkPanel.css @@ -0,0 +1,383 @@ +.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;
+}
diff --git a/WebCore/inspector/front-end/treeoutline.js b/WebCore/inspector/front-end/treeoutline.js index c2a3fe7..e2f879c 100644 --- a/WebCore/inspector/front-end/treeoutline.js +++ b/WebCore/inspector/front-end/treeoutline.js @@ -399,7 +399,7 @@ TreeOutline.prototype._treeKeyDown = function(event) if (nextSelectedElement) { nextSelectedElement.reveal(); - nextSelectedElement.select(); + nextSelectedElement.select(false, true); } if (handled) { @@ -794,10 +794,10 @@ TreeElement.prototype.revealed = function() TreeElement.prototype.selectOnMouseDown = function(event) { - this.select(); + this.select(false, true); } -TreeElement.prototype.select = function(supressOnSelect) +TreeElement.prototype.select = function(supressOnSelect, selectedByUser) { if (!this.treeOutline || !this.selectable || this.selected) return; @@ -812,7 +812,7 @@ TreeElement.prototype.select = function(supressOnSelect) this._listItemNode.addStyleClass("selected"); if (this.onselect && !supressOnSelect) - this.onselect(this); + this.onselect(this, selectedByUser); } TreeElement.prototype.deselect = function(supressOnDeselect) |