diff options
Diffstat (limited to 'WebCore/inspector')
40 files changed, 1127 insertions, 367 deletions
diff --git a/WebCore/inspector/InjectedScriptHost.cpp b/WebCore/inspector/InjectedScriptHost.cpp index 4c3c7ae..e8a9fee 100644 --- a/WebCore/inspector/InjectedScriptHost.cpp +++ b/WebCore/inspector/InjectedScriptHost.cpp @@ -110,17 +110,13 @@ long InjectedScriptHost::pushNodePathToFrontend(Node* node, bool withChildren, b return id; } -long InjectedScriptHost::pushNodeByPathToFrontend(const String& path) +long InjectedScriptHost::inspectedNode(unsigned long num) { InspectorDOMAgent* domAgent = inspectorDOMAgent(); if (!domAgent) return 0; - Node* node = domAgent->nodeForPath(path); - if (!node) - return 0; - - return domAgent->pushNodePathToFrontend(node); + return domAgent->inspectedNode(num); } #if ENABLE(DATABASE) diff --git a/WebCore/inspector/InjectedScriptHost.h b/WebCore/inspector/InjectedScriptHost.h index 66cf41e..b942148 100644 --- a/WebCore/inspector/InjectedScriptHost.h +++ b/WebCore/inspector/InjectedScriptHost.h @@ -68,8 +68,7 @@ public: void copyText(const String& text); Node* nodeForId(long nodeId); long pushNodePathToFrontend(Node* node, bool withChildren, bool selectInUI); - - long pushNodeByPathToFrontend(const String& path); + long inspectedNode(unsigned long num); #if ENABLE(DATABASE) Database* databaseForId(long databaseId); diff --git a/WebCore/inspector/InjectedScriptHost.idl b/WebCore/inspector/InjectedScriptHost.idl index 5a4ce19..21af938 100644 --- a/WebCore/inspector/InjectedScriptHost.idl +++ b/WebCore/inspector/InjectedScriptHost.idl @@ -37,8 +37,7 @@ module core { void copyText(in DOMString text); [Custom] DOMObject nodeForId(in long nodeId); [Custom] int pushNodePathToFrontend(in DOMObject node, in boolean withChildren, in boolean selectInUI); - - long pushNodeByPathToFrontend(in DOMString path); + long inspectedNode(in unsigned long num); #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [Custom] DOMObject currentCallFrame(); diff --git a/WebCore/inspector/InspectorBackend.cpp b/WebCore/inspector/InspectorBackend.cpp index 1eedda1..8e9e330 100644 --- a/WebCore/inspector/InspectorBackend.cpp +++ b/WebCore/inspector/InspectorBackend.cpp @@ -109,6 +109,18 @@ void InspectorBackend::disableSearchingForNode() m_inspectorController->setSearchingForNode(false); } +void InspectorBackend::enableMonitoringXHR() +{ + if (m_inspectorController) + m_inspectorController->setMonitoringXHR(true); +} + +void InspectorBackend::disableMonitoringXHR() +{ + if (m_inspectorController) + m_inspectorController->setMonitoringXHR(false); +} + void InspectorBackend::enableResourceTracking(bool always) { if (m_inspectorController) @@ -280,6 +292,12 @@ void InspectorBackend::clearProfiles() if (m_inspectorController) m_inspectorController->clearProfiles(); } + +void InspectorBackend::takeHeapSnapshot() +{ + if (m_inspectorController) + m_inspectorController->takeHeapSnapshot(); +} #endif void InspectorBackend::setInjectedScriptSource(const String& source) @@ -359,10 +377,28 @@ void InspectorBackend::removeNode(long callId, long nodeId) domAgent->removeNode(callId, nodeId); } -void InspectorBackend::changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded) +void InspectorBackend::changeTagName(long callId, long nodeId, const String& tagName) +{ + if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) + domAgent->changeTagName(callId, nodeId, tagName); +} + +void InspectorBackend::getOuterHTML(long callId, long nodeId) { if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) - domAgent->changeTagName(callId, nodeId, tagName, expanded); + domAgent->getOuterHTML(callId, nodeId); +} + +void InspectorBackend::setOuterHTML(long callId, long nodeId, const String& outerHTML) +{ + if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) + domAgent->setOuterHTML(callId, nodeId, outerHTML); +} + +void InspectorBackend::addInspectedNode(long nodeId) +{ + if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) + domAgent->addInspectedNode(nodeId); } void InspectorBackend::performSearch(const String& query, bool runSynchronously) @@ -377,6 +413,23 @@ void InspectorBackend::searchCanceled() domAgent->searchCanceled(); } +void InspectorBackend::pushNodeByPathToFrontend(long callId, const String& path) +{ + InspectorDOMAgent* domAgent = inspectorDOMAgent(); + InspectorFrontend* frontend = inspectorFrontend(); + if (!domAgent || !frontend) + return; + + long id = domAgent->pushNodeByPathToFrontend(path); + frontend->didPushNodeByPathToFrontend(callId, id); +} + +void InspectorBackend::clearConsoleMessages() +{ + if (m_inspectorController) + m_inspectorController->clearConsoleMessages(); +} + void InspectorBackend::getStyles(long callId, long nodeId, bool authorOnly) { if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) diff --git a/WebCore/inspector/InspectorBackend.h b/WebCore/inspector/InspectorBackend.h index 61d73b8..ce5dd99 100644 --- a/WebCore/inspector/InspectorBackend.h +++ b/WebCore/inspector/InspectorBackend.h @@ -65,6 +65,9 @@ public: void enableSearchingForNode(); void disableSearchingForNode(); + void enableMonitoringXHR(); + void disableMonitoringXHR(); + void enableResourceTracking(bool always); void disableResourceTracking(bool always); void getResourceContent(long callId, unsigned long identifier); @@ -105,6 +108,8 @@ public: void removeProfile(unsigned uid); void clearProfiles(); + + void takeHeapSnapshot(); #endif void setInjectedScriptSource(const String& source); @@ -119,9 +124,15 @@ public: void getEventListenersForNode(long callId, long nodeId); void copyNode(long nodeId); void removeNode(long callId, long nodeId); - void changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded); + void changeTagName(long callId, long nodeId, const String& tagName); + void getOuterHTML(long callId, long nodeId); + void setOuterHTML(long callId, long nodeId, const String& outerHTML); + void addInspectedNode(long nodeId); void performSearch(const String& query, bool runSynchronously); void searchCanceled(); + void pushNodeByPathToFrontend(long callId, const String& path); + + void clearConsoleMessages(); void getStyles(long callId, long nodeId, bool authOnly); void getAllStyles(long callId); diff --git a/WebCore/inspector/InspectorBackend.idl b/WebCore/inspector/InspectorBackend.idl index c0078ee..eaacaf0 100644 --- a/WebCore/inspector/InspectorBackend.idl +++ b/WebCore/inspector/InspectorBackend.idl @@ -40,6 +40,9 @@ module core { void enableSearchingForNode(); void disableSearchingForNode(); + void enableMonitoringXHR(); + void disableMonitoringXHR(); + void enableResourceTracking(in boolean always); void disableResourceTracking(in boolean always); void getResourceContent(in long callId, in unsigned long identifier); @@ -80,6 +83,8 @@ module core { void removeProfile(in unsigned long uid); void clearProfiles(); + + void takeHeapSnapshot(); #endif void setInjectedScriptSource(in DOMString scriptSource); void dispatchOnInjectedScript(in long callId, in long injectedScriptId, in DOMString methodName, in DOMString arguments, in boolean async); @@ -94,9 +99,15 @@ module core { void getEventListenersForNode(in long callId, in long nodeId); void copyNode(in long nodeId); void removeNode(in long callId, in long nodeId); - void changeTagName(in long callId, in long nodeId, in DOMString newTagName, in boolean expanded); + void changeTagName(in long callId, in long nodeId, in DOMString newTagName); + void getOuterHTML(in long callId, in long nodeId); + void setOuterHTML(in long callId, in long nodeId, in DOMString outerHTML); + void addInspectedNode(in long nodeId); void performSearch(in DOMString query, in boolean runSynchronously); void searchCanceled(); + void pushNodeByPathToFrontend(in long callId, in DOMString path); + + void clearConsoleMessages(); void highlightDOMNode(in long nodeId); void hideDOMNodeHighlight(); diff --git a/WebCore/inspector/InspectorCSSStore.cpp b/WebCore/inspector/InspectorCSSStore.cpp index a080eda..7bc947a 100644 --- a/WebCore/inspector/InspectorCSSStore.cpp +++ b/WebCore/inspector/InspectorCSSStore.cpp @@ -29,6 +29,8 @@ #include "config.h" #include "InspectorCSSStore.h" +#if ENABLE(INSPECTOR) + #include "CSSMutableStyleDeclaration.h" #include "CSSParser.h" #include "CSSRuleList.h" @@ -220,3 +222,5 @@ long InspectorCSSStore::bindRule(CSSStyleRule* rule) } } // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/inspector/InspectorClient.h b/WebCore/inspector/InspectorClient.h index 2ce3a09..61900bb 100644 --- a/WebCore/inspector/InspectorClient.h +++ b/WebCore/inspector/InspectorClient.h @@ -50,6 +50,14 @@ public: virtual void storeSetting(const String& key, const String& value) = 0; virtual bool sendMessageToFrontend(const String& message) = 0; + + // Navigation can cause some WebKit implementations to change the view / page / inspector controller instance. + // However, there are some inspector controller states that should survive navigation (such as tracking resources + // or recording timeline). Following callbacks allow embedders to track these states. + virtual void resourceTrackingWasEnabled() { }; + virtual void resourceTrackingWasDisabled() { }; + virtual void timelineProfilerWasStarted() { }; + virtual void timelineProfilerWasStopped() { }; }; } // namespace WebCore diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index 7916cd0..5020634 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -62,6 +62,7 @@ #include "InspectorDatabaseResource.h" #include "InspectorFrontend.h" #include "InspectorResource.h" +#include "InspectorValues.h" #include "InspectorWorkerResource.h" #include "InspectorTimelineAgent.h" #include "Page.h" @@ -86,6 +87,7 @@ #include <wtf/text/CString.h> #include <wtf/CurrentTime.h> #include <wtf/ListHashSet.h> +#include <wtf/MD5.h> #include <wtf/RefCounted.h> #include <wtf/StdLibExtras.h> @@ -120,6 +122,7 @@ static const char* const debuggerEnabledSettingName = "debuggerEnabled"; static const char* const profilerEnabledSettingName = "profilerEnabled"; static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight"; static const char* const lastActivePanelSettingName = "lastActivePanel"; +static const char* const monitoringXHRSettingName = "xhrMonitor"; const String& InspectorController::frontendSettingsSettingName() { @@ -141,6 +144,27 @@ static const unsigned expireConsoleMessagesStep = 100; static unsigned s_inspectorControllerCount; +namespace { + +String md5Base16(const String& string) +{ + static const char digits[] = "0123456789abcdef"; + + MD5 md5; + md5.addBytes(reinterpret_cast<const uint8_t*>(string.characters()), string.length() * 2); + Vector<uint8_t, 16> digest; + md5.checksum(digest); + + Vector<char, 32> result; + for (int i = 0; i < 16; ++i) { + result.append(digits[(digest[i] >> 4) & 0xf]); + result.append(digits[digest[i] & 0xf]); + } + return String(result.data(), result.size()); +} + +} + InspectorController::InspectorController(Page* page, InspectorClient* client) : m_inspectedPage(page) , m_client(client) @@ -151,15 +175,17 @@ InspectorController::InspectorController(Page* page, InspectorClient* client) , m_sessionSettings(InspectorObject::create()) , m_groupLevel(0) , m_searchingForNode(false) + , m_monitoringXHR(false) , m_previousMessage(0) , m_resourceTrackingEnabled(false) - , m_resourceTrackingSettingsLoaded(false) + , m_settingsLoaded(false) , m_inspectorBackend(InspectorBackend::create(this)) , m_injectedScriptHost(InjectedScriptHost::create(this)) #if ENABLE(JAVASCRIPT_DEBUGGER) , m_debuggerEnabled(false) , m_attachDebuggerWhenShown(false) , m_pausedScriptState(0) + , m_breakpointsLoaded(false) , m_profilerEnabled(!WTF_USE_JSC) , m_recordingUserInitiatedProfile(false) , m_currentUserInitiatedProfileNumber(-1) @@ -232,7 +258,7 @@ void InspectorController::setSetting(const String& key, const String& value) void InspectorController::setSessionSettings(const String& settingsJSON) { - m_sessionSettings = InspectorValue::readJSON(settingsJSON); + m_sessionSettings = InspectorValue::parseJSON(settingsJSON); } void InspectorController::inspect(Node* node) @@ -431,6 +457,20 @@ void InspectorController::setSearchingForNode(bool enabled) } } +void InspectorController::setMonitoringXHR(bool enabled) +{ + if (m_monitoringXHR == enabled) + return; + m_monitoringXHR = enabled; + setSetting(monitoringXHRSettingName, enabled ? "true" : "false"); + if (m_frontend) { + if (enabled) + m_frontend->monitoringXHRWasEnabled(); + else + m_frontend->monitoringXHRWasDisabled(); + } +} + void InspectorController::connectFrontend(const ScriptObject& webInspector) { m_openingFrontend = false; @@ -439,6 +479,12 @@ void InspectorController::connectFrontend(const ScriptObject& webInspector) m_domAgent = InspectorDOMAgent::create(m_cssStore.get(), m_frontend.get()); if (m_timelineAgent) m_timelineAgent->resetFrontendProxyObject(m_frontend.get()); + + // Initialize Web Inspector title. + m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string()); + + populateScriptObjects(); + #if ENABLE(JAVASCRIPT_DEBUGGER) if (ScriptDebugServer::shared().isDebuggerAlwaysEnabled()) { // FIXME (40364): This will force pushing script sources to frontend even if script @@ -446,7 +492,7 @@ void InspectorController::connectFrontend(const ScriptObject& webInspector) enableDebuggerFromFrontend(false); } else { String debuggerEnabled = setting(debuggerEnabledSettingName); - if (debuggerEnabled == "true") + if (debuggerEnabled == "true" || m_attachDebuggerWhenShown) enableDebugger(); String profilerEnabled = setting(profilerEnabledSettingName); if (profilerEnabled == "true") @@ -454,11 +500,6 @@ void InspectorController::connectFrontend(const ScriptObject& webInspector) } #endif - // Initialize Web Inspector title. - m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string()); - - populateScriptObjects(); - if (m_showAfterVisible == CurrentPanel) { String lastActivePanelSetting = setting(lastActivePanelSettingName); m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting); @@ -466,10 +507,6 @@ void InspectorController::connectFrontend(const ScriptObject& webInspector) if (m_nodeToFocus) focusNode(); -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (m_attachDebuggerWhenShown) - enableDebugger(); -#endif showPanel(m_showAfterVisible); } @@ -526,8 +563,7 @@ void InspectorController::disconnectFrontend() // opening. bool debuggerWasEnabled = m_debuggerEnabled; disableDebugger(); - if (debuggerWasEnabled) - m_attachDebuggerWhenShown = true; + m_attachDebuggerWhenShown = debuggerWasEnabled; #endif setSearchingForNode(false); unbindAllResources(); @@ -567,8 +603,9 @@ void InspectorController::populateScriptObjects() if (m_searchingForNode) m_frontend->searchingForNodeWasEnabled(); - else - m_frontend->searchingForNodeWasDisabled(); + + if (m_monitoringXHR) + m_frontend->monitoringXHRWasEnabled(); #if ENABLE(JAVASCRIPT_DEBUGGER) if (m_profilerEnabled) @@ -674,11 +711,15 @@ void InspectorController::didCommitLoad(DocumentLoader* loader) #if ENABLE(JAVASCRIPT_DEBUGGER) m_sourceIDToURL.clear(); m_scriptIDToContent.clear(); + m_stickyBreakpoints.clear(); + m_breakpointsLoaded = false; #endif #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) m_profiles.clear(); m_currentUserInitiatedProfileNumber = 1; m_nextUserInitiatedProfileNumber = 1; + if (m_frontend) + m_frontend->resetProfilesPanel(); #endif // unbindAllResources should be called before database and DOM storage // resources are cleared so that it has a chance to unbind them. @@ -812,7 +853,7 @@ void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, ASSERT(m_inspectedPage); bool isMainResource = isMainResourceLoader(loader, KURL(ParsedURLString, cachedResource->url())); - ensureResourceTrackingSettingsLoaded(); + ensureSettingsLoaded(); if (!isMainResource && !m_resourceTrackingEnabled) return; @@ -836,7 +877,7 @@ void InspectorController::identifierForInitialRequest(unsigned long identifier, ASSERT(m_inspectedPage); bool isMainResource = isMainResourceLoader(loader, request.url()); - ensureResourceTrackingSettingsLoaded(); + ensureSettingsLoaded(); if (!isMainResource && !m_resourceTrackingEnabled) return; @@ -1006,9 +1047,15 @@ void InspectorController::didFailLoading(unsigned long identifier, const Resourc resource->updateScriptObject(m_frontend.get()); } -void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString) +void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber) { - if (!enabled() || !m_resourceTrackingEnabled) + if (!enabled()) + return; + + if (m_monitoringXHR) + addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL); + + if (!m_resourceTrackingEnabled) return; InspectorResource* resource = m_resources.get(identifier).get(); @@ -1051,6 +1098,7 @@ void InspectorController::enableResourceTracking(bool always, bool reload) m_resourceTrackingEnabled = true; if (m_frontend) m_frontend->resourceTrackingWasEnabled(); + m_client->resourceTrackingWasEnabled(); if (reload) m_inspectedPage->mainFrame()->redirectScheduler()->scheduleRefresh(true); @@ -1068,17 +1116,23 @@ void InspectorController::disableResourceTracking(bool always) m_resourceTrackingEnabled = false; if (m_frontend) m_frontend->resourceTrackingWasDisabled(); + m_client->resourceTrackingWasDisabled(); } -void InspectorController::ensureResourceTrackingSettingsLoaded() +void InspectorController::ensureSettingsLoaded() { - if (m_resourceTrackingSettingsLoaded) + if (m_settingsLoaded) return; - m_resourceTrackingSettingsLoaded = true; + m_settingsLoaded = true; String resourceTracking = setting(resourceTrackingEnabledSettingName); if (resourceTracking == "true") m_resourceTrackingEnabled = true; + m_client->resourceTrackingWasEnabled(); + + String monitoringXHR = setting(monitoringXHRSettingName); + if (monitoringXHR == "true") + m_monitoringXHR = true; } void InspectorController::startTimelineProfiler() @@ -1092,6 +1146,7 @@ void InspectorController::startTimelineProfiler() m_timelineAgent = new InspectorTimelineAgent(m_frontend.get()); if (m_frontend) m_frontend->timelineProfilerWasStarted(); + m_client->timelineProfilerWasStarted(); } void InspectorController::stopTimelineProfiler() @@ -1105,6 +1160,7 @@ void InspectorController::stopTimelineProfiler() m_timelineAgent = 0; if (m_frontend) m_frontend->timelineProfilerWasStopped(); + m_client->timelineProfilerWasStopped(); } #if ENABLE(WORKERS) @@ -1580,18 +1636,27 @@ void InspectorController::disableProfiler(bool always) if (m_frontend) m_frontend->profilerWasDisabled(); } + +void InspectorController::takeHeapSnapshot() +{ + if (!enabled()) + return; + + ScriptProfiler::takeHeapSnapshot(); +} #endif #if ENABLE(JAVASCRIPT_DEBUGGER) void InspectorController::enableDebuggerFromFrontend(bool always) { + ASSERT(!m_debuggerEnabled); if (always) setSetting(debuggerEnabledSettingName, "true"); ASSERT(m_inspectedPage); - ScriptDebugServer::shared().addListener(this, m_inspectedPage); ScriptDebugServer::shared().clearBreakpoints(); + ScriptDebugServer::shared().addListener(this, m_inspectedPage); m_debuggerEnabled = true; m_frontend->debuggerWasEnabled(); @@ -1678,10 +1743,12 @@ void InspectorController::setBreakpoint(const String& sourceID, unsigned lineNum if (url.isEmpty()) return; - HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(url); + String key = md5Base16(url); + HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(key); if (it == m_stickyBreakpoints.end()) - it = m_stickyBreakpoints.set(url, SourceBreakpoints()).first; + it = m_stickyBreakpoints.set(key, SourceBreakpoints()).first; it->second.set(lineNumber, breakpoint); + saveBreakpoints(); } void InspectorController::removeBreakpoint(const String& sourceID, unsigned lineNumber) @@ -1692,9 +1759,10 @@ void InspectorController::removeBreakpoint(const String& sourceID, unsigned line if (url.isEmpty()) return; - HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(url); + HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url)); if (it != m_stickyBreakpoints.end()) it->second.remove(lineNumber); + saveBreakpoints(); } // JavaScriptDebugListener functions @@ -1704,10 +1772,13 @@ void InspectorController::didParseSource(const String& sourceID, const String& u // Don't send script content to the front end until it's really needed. m_frontend->parsedScriptSource(sourceID, url, "", firstLine, worldType); + m_scriptIDToContent.set(sourceID, data); + if (url.isEmpty()) return; - HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(url); + loadBreakpoints(); + HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url)); if (it != m_stickyBreakpoints.end()) { for (SourceBreakpoints::iterator breakpointIt = it->second.begin(); breakpointIt != it->second.end(); ++breakpointIt) { if (firstLine <= breakpointIt->first) { @@ -1716,9 +1787,7 @@ void InspectorController::didParseSource(const String& sourceID, const String& u } } } - m_sourceIDToURL.set(sourceID, url); - m_scriptIDToContent.set(sourceID, data); } void InspectorController::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) @@ -1761,6 +1830,47 @@ void InspectorController::didEvaluateForTestInFrontend(long callId, const String function.call(); } +#if ENABLE(JAVASCRIPT_DEBUGGER) +String InspectorController::breakpointsSettingKey() +{ + DEFINE_STATIC_LOCAL(String, keyPrefix, ("breakpoints:")); + return keyPrefix + md5Base16(m_mainResource->requestURL()); +} + +void InspectorController::loadBreakpoints() +{ + if (m_breakpointsLoaded) + return; + m_breakpointsLoaded = true; + + RefPtr<InspectorValue> parsedSetting = InspectorValue::parseJSON(setting(breakpointsSettingKey())); + if (!parsedSetting) + return; + RefPtr<InspectorObject> breakpoints = parsedSetting->asObject(); + if (!breakpoints) + return; + for (InspectorObject::iterator it = breakpoints->begin(); it != breakpoints->end(); ++it) { + RefPtr<InspectorObject> breakpointsForURL = it->second->asObject(); + if (!breakpointsForURL) + continue; + HashMap<String, SourceBreakpoints>::iterator sourceBreakpointsIt = m_stickyBreakpoints.set(it->first, SourceBreakpoints()).first; + ScriptBreakpoint::sourceBreakpointsFromInspectorObject(breakpointsForURL, &sourceBreakpointsIt->second); + } +} + +void InspectorController::saveBreakpoints() +{ + RefPtr<InspectorObject> breakpoints = InspectorObject::create(); + for (HashMap<String, SourceBreakpoints>::iterator it(m_stickyBreakpoints.begin()); it != m_stickyBreakpoints.end(); ++it) { + if (it->second.isEmpty()) + continue; + RefPtr<InspectorObject> breakpointsForURL = ScriptBreakpoint::inspectorObjectFromSourceBreakpoints(it->second); + breakpoints->set(it->first, breakpointsForURL); + } + setSetting(breakpointsSettingKey(), breakpoints->toJSONString()); +} +#endif + static Path quadToPath(const FloatQuad& quad) { Path quadPath; @@ -1826,7 +1936,7 @@ static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& conte drawOutlinedQuad(context, contentQuad, contentBoxColor); } -static void drawHighlightForLineBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads) +static void drawHighlightForLineBoxesOrSVGRenderer(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads) { static const Color lineBoxColor(125, 173, 217, 128); @@ -1867,7 +1977,14 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const overlayRect = view->visibleContentRect(); context.translate(-overlayRect.x(), -overlayRect.y()); - if (renderer->isBox()) { + // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads(). +#if ENABLE(SVG) + bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot(); +#else + bool isSVGRenderer = false; +#endif + + if (renderer->isBox() && !isSVGRenderer) { RenderBox* renderBox = toRenderBox(renderer); IntRect contentBox = renderBox->contentBoxRect(); @@ -1890,16 +2007,14 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const absMarginQuad.move(mainFrameOffset); drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad); - } else if (renderer->isRenderInline()) { - RenderInline* renderInline = toRenderInline(renderer); - + } else if (renderer->isRenderInline() || isSVGRenderer) { // FIXME: We should show margins/padding/border for inlines. Vector<FloatQuad> lineBoxQuads; - renderInline->absoluteQuads(lineBoxQuads); + renderer->absoluteQuads(lineBoxQuads); for (unsigned i = 0; i < lineBoxQuads.size(); ++i) lineBoxQuads[i] += mainFrameOffset; - drawHighlightForLineBoxes(context, lineBoxQuads); + drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads); } } diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h index 346a8dc..b2d1d5a 100644 --- a/WebCore/inspector/InspectorController.h +++ b/WebCore/inspector/InspectorController.h @@ -170,13 +170,14 @@ public: void didReceiveContentLength(unsigned long identifier, int lengthReceived); void didFinishLoading(unsigned long identifier); void didFailLoading(unsigned long identifier, const ResourceError&); - void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString); + void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber); void scriptImported(unsigned long identifier, const String& sourceString); void enableResourceTracking(bool always = false, bool reload = true); void disableResourceTracking(bool always = false); bool resourceTrackingEnabled() const { return m_resourceTrackingEnabled; } - void ensureResourceTrackingSettingsLoaded(); + + void ensureSettingsLoaded(); void startTimelineProfiler(); void stopTimelineProfiler(); @@ -240,6 +241,8 @@ public: void enableProfiler(bool always = false, bool skipRecompile = false); void disableProfiler(bool always = false); bool profilerEnabled() const { return enabled() && m_profilerEnabled; } + + void takeHeapSnapshot(); #endif #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -278,6 +281,7 @@ private: // Following are used from InspectorBackend and internally. void setSearchingForNode(bool enabled); + void setMonitoringXHR(bool enabled); void storeLastActivePanel(const String& panelName); InspectorDOMAgent* domAgent() { return m_domAgent.get(); } void releaseDOMAgent(); @@ -325,6 +329,12 @@ private: void didEvaluateForTestInFrontend(long callId, const String& jsonResult); +#if ENABLE(JAVASCRIPT_DEBUGGER) + String breakpointsSettingKey(); + void loadBreakpoints(); + void saveBreakpoints(); +#endif + Page* m_inspectedPage; InspectorClient* m_client; OwnPtr<InspectorFrontendClient> m_inspectorFrontendClient; @@ -350,12 +360,15 @@ private: #endif SpecialPanels m_showAfterVisible; RefPtr<Node> m_highlightedNode; +#if ENABLE(INSPECTOR) RefPtr<InspectorValue> m_sessionSettings; +#endif unsigned m_groupLevel; bool m_searchingForNode; + bool m_monitoringXHR; ConsoleMessage* m_previousMessage; bool m_resourceTrackingEnabled; - bool m_resourceTrackingSettingsLoaded; + bool m_settingsLoaded; RefPtr<InspectorBackend> m_inspectorBackend; RefPtr<InjectedScriptHost> m_injectedScriptHost; @@ -371,6 +384,7 @@ private: HashMap<String, String> m_sourceIDToURL; HashMap<String, String> m_scriptIDToContent; HashMap<String, SourceBreakpoints> m_stickyBreakpoints; + bool m_breakpointsLoaded; bool m_profilerEnabled; bool m_recordingUserInitiatedProfile; diff --git a/WebCore/inspector/InspectorDOMAgent.cpp b/WebCore/inspector/InspectorDOMAgent.cpp index b152dc3..a2f2e15 100644 --- a/WebCore/inspector/InspectorDOMAgent.cpp +++ b/WebCore/inspector/InspectorDOMAgent.cpp @@ -53,9 +53,9 @@ #include "EventTarget.h" #include "Frame.h" #include "FrameTree.h" +#include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" #include "InspectorFrontend.h" -#include "markup.h" #include "MutationEvent.h" #include "Node.h" #include "NodeList.h" @@ -355,12 +355,28 @@ void InspectorDOMAgent::pushChildNodesToFrontend(long nodeId) m_frontend->setChildNodes(nodeId, children); } +long InspectorDOMAgent::pushNodeByPathToFrontend(const String& path) +{ + Node* node = nodeForPath(path); + if (!node) + return 0; + return pushNodePathToFrontend(node); +} + +long InspectorDOMAgent::inspectedNode(unsigned long num) +{ + if (num < m_inspectedNodes.size()) + return m_inspectedNodes[num]; + return 0; +} + void InspectorDOMAgent::discardBindings() { m_documentNodeToIdMap.clear(); m_idToNode.clear(); releaseDanglingNodes(); m_childrenRequested.clear(); + m_inspectedNodes.clear(); } Node* InspectorDOMAgent::nodeForId(long id) @@ -374,35 +390,6 @@ Node* InspectorDOMAgent::nodeForId(long id) return 0; } -Node* InspectorDOMAgent::nodeForPath(const String& path) -{ - // The path is of form "1,HTML,2,BODY,1,DIV" - Node* node = mainFrameDocument(); - if (!node) - return 0; - - Vector<String> pathTokens; - path.split(",", false, pathTokens); - for (size_t i = 0; i < pathTokens.size() - 1; i += 2) { - bool success = true; - unsigned childNumber = pathTokens[i].toUInt(&success); - if (!success) - return 0; - if (childNumber >= innerChildNodeCount(node)) - return 0; - - Node* child = innerFirstChild(node); - String childName = pathTokens[i + 1]; - for (size_t j = 0; child && j < childNumber; ++j) - child = innerNextSibling(child); - - if (!child || child->nodeName() != childName) - return 0; - node = child; - } - return node; -} - void InspectorDOMAgent::getChildNodes(long callId, long nodeId) { pushChildNodesToFrontend(nodeId); @@ -481,40 +468,40 @@ void InspectorDOMAgent::removeNode(long callId, long nodeId) { Node* node = nodeForId(nodeId); if (!node) { - // Use -1 to denote an error condition. - m_frontend->didRemoveNode(callId, -1); + m_frontend->didRemoveNode(callId, 0); return; } Node* parentNode = node->parentNode(); if (!parentNode) { - m_frontend->didRemoveNode(callId, -1); + m_frontend->didRemoveNode(callId, 0); return; } - ExceptionCode code; - parentNode->removeChild(node, code); - if (code) { - m_frontend->didRemoveNode(callId, -1); + ExceptionCode ec = 0; + parentNode->removeChild(node, ec); + if (ec) { + m_frontend->didRemoveNode(callId, 0); return; } m_frontend->didRemoveNode(callId, nodeId); } -void InspectorDOMAgent::changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded) +void InspectorDOMAgent::changeTagName(long callId, long nodeId, const String& tagName) { Node* oldNode = nodeForId(nodeId); if (!oldNode || !oldNode->isElementNode()) { - // Use -1 to denote an error condition. - m_frontend->didChangeTagName(callId, -1); + m_frontend->didChangeTagName(callId, 0); return; } - ExceptionCode code = 0; - RefPtr<Element> newElem = oldNode->document()->createElement(tagName, code); - if (code) { - m_frontend->didChangeTagName(callId, -1); + bool childrenRequested = m_childrenRequested.contains(nodeId); + + ExceptionCode ec = 0; + RefPtr<Element> newElem = oldNode->document()->createElement(tagName, ec); + if (ec) { + m_frontend->didChangeTagName(callId, 0); return; } @@ -527,24 +514,63 @@ void InspectorDOMAgent::changeTagName(long callId, long nodeId, const AtomicStri // Copy over the original node's children. Node* child; while ((child = oldNode->firstChild())) - newElem->appendChild(child, code); + newElem->appendChild(child, ec); // Replace the old node with the new node Node* parent = oldNode->parentNode(); - parent->insertBefore(newElem, oldNode->nextSibling(), code); - parent->removeChild(oldNode, code); + parent->insertBefore(newElem, oldNode->nextSibling(), ec); + parent->removeChild(oldNode, ec); - if (code) { - m_frontend->didChangeTagName(callId, -1); + if (ec) { + m_frontend->didChangeTagName(callId, 0); return; } long newId = pushNodePathToFrontend(newElem.get()); - if (expanded) + if (childrenRequested) pushChildNodesToFrontend(newId); m_frontend->didChangeTagName(callId, newId); } +void InspectorDOMAgent::getOuterHTML(long callId, long nodeId) +{ + Node* node = nodeForId(nodeId); + if (!node || !node->isHTMLElement()) { + m_frontend->didGetOuterHTML(callId, ""); + return; + } + + HTMLElement* htmlElement = static_cast<HTMLElement*>(node); + m_frontend->didGetOuterHTML(callId, htmlElement->outerHTML()); +} + +void InspectorDOMAgent::setOuterHTML(long callId, long nodeId, const String& outerHTML) +{ + Node* node = nodeForId(nodeId); + if (!node || !node->isHTMLElement()) { + m_frontend->didSetOuterHTML(callId, 0); + return; + } + + bool childrenRequested = m_childrenRequested.contains(nodeId); + Node* previousSibling = node->previousSibling(); + Node* parentNode = node->parentNode(); + + HTMLElement* htmlElement = static_cast<HTMLElement*>(node); + ExceptionCode ec = 0; + htmlElement->setOuterHTML(outerHTML, ec); + if (ec) + m_frontend->didSetOuterHTML(callId, 0); + + Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); + + long newId = pushNodePathToFrontend(newNode); + if (childrenRequested) + pushChildNodesToFrontend(newId); + + m_frontend->didSetOuterHTML(callId, newId); +} + void InspectorDOMAgent::setTextNodeValue(long callId, long nodeId, const String& value) { Node* node = nodeForId(nodeId); @@ -632,6 +658,13 @@ void InspectorDOMAgent::getEventListenersForNode(long callId, long nodeId) m_frontend->didGetEventListenersForNode(callId, nodeId, listenersArray); } +void InspectorDOMAgent::addInspectedNode(long nodeId) +{ + m_inspectedNodes.prepend(nodeId); + while (m_inspectedNodes.size() > 5) + m_inspectedNodes.removeLast(); +} + void InspectorDOMAgent::performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously) { // FIXME: Few things are missing here: @@ -1531,6 +1564,35 @@ bool InspectorDOMAgent::ruleAffectsNode(CSSStyleRule* rule, Node* node) return false; } +Node* InspectorDOMAgent::nodeForPath(const String& path) +{ + // The path is of form "1,HTML,2,BODY,1,DIV" + Node* node = mainFrameDocument(); + if (!node) + return 0; + + Vector<String> pathTokens; + path.split(",", false, pathTokens); + for (size_t i = 0; i < pathTokens.size() - 1; i += 2) { + bool success = true; + unsigned childNumber = pathTokens[i].toUInt(&success); + if (!success) + return 0; + if (childNumber >= innerChildNodeCount(node)) + return 0; + + Node* child = innerFirstChild(node); + String childName = pathTokens[i + 1]; + for (size_t j = 0; child && j < childNumber; ++j) + child = innerNextSibling(child); + + if (!child || child->nodeName() != childName) + return 0; + node = child; + } + return node; +} + ScriptArray InspectorDOMAgent::toArray(const Vector<String>& data) { ScriptArray result = m_frontend->newScriptArray(); diff --git a/WebCore/inspector/InspectorDOMAgent.h b/WebCore/inspector/InspectorDOMAgent.h index a962569..70d5b94 100644 --- a/WebCore/inspector/InspectorDOMAgent.h +++ b/WebCore/inspector/InspectorDOMAgent.h @@ -102,9 +102,12 @@ namespace WebCore { void setAttribute(long callId, long elementId, const String& name, const String& value); void removeAttribute(long callId, long elementId, const String& name); void removeNode(long callId, long nodeId); - void changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded); + void changeTagName(long callId, long nodeId, const String& tagName); + void getOuterHTML(long callId, long nodeId); + void setOuterHTML(long callId, long nodeId, const String& outerHTML); void setTextNodeValue(long callId, long nodeId, const String& value); void getEventListenersForNode(long callId, long nodeId); + void addInspectedNode(long nodeId); void performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously); void searchCanceled(); @@ -131,9 +134,10 @@ namespace WebCore { void didModifyDOMAttr(Element*); Node* nodeForId(long nodeId); - Node* nodeForPath(const String& path); long pushNodePathToFrontend(Node* node); void pushChildNodesToFrontend(long nodeId); + long pushNodeByPathToFrontend(const String& path); + long inspectedNode(unsigned long num); private: static CSSStyleSheet* getParentStyleSheet(CSSStyleDeclaration*); @@ -183,6 +187,7 @@ namespace WebCore { String shorthandValue(CSSStyleDeclaration*, const String& shorthandProperty); String shorthandPriority(CSSStyleDeclaration*, const String& shorthandProperty); bool ruleAffectsNode(CSSStyleRule*, Node*); + Node* nodeForPath(const String& path); ScriptArray toArray(const Vector<String>& data); void discardBindings(); @@ -200,6 +205,7 @@ namespace WebCore { Deque<MatchJob*> m_pendingMatchJobs; Timer<InspectorDOMAgent> m_matchJobsTimer; HashSet<RefPtr<Node> > m_searchResults; + Vector<long> m_inspectedNodes; }; } // namespace WebCore diff --git a/WebCore/inspector/InspectorFrontend.cpp b/WebCore/inspector/InspectorFrontend.cpp index c9aa730..cde5a70 100644 --- a/WebCore/inspector/InspectorFrontend.cpp +++ b/WebCore/inspector/InspectorFrontend.cpp @@ -184,14 +184,6 @@ void InspectorFrontend::updateFocusedNode(long nodeId) function.call(); } -void InspectorFrontend::setAttachedWindow(bool attached) -{ - ScriptFunctionCall function(m_webInspector, "dispatch"); - function.appendArgument("setAttachedWindow"); - function.appendArgument(attached); - function.call(); -} - void InspectorFrontend::showPanel(int panel) { const char* showFunctionName; @@ -239,6 +231,11 @@ void InspectorFrontend::reset() callSimpleFunction("reset"); } +void InspectorFrontend::resetProfilesPanel() +{ + callSimpleFunction("resetProfilesPanel"); +} + void InspectorFrontend::bringToFront() { callSimpleFunction("bringToFront"); @@ -262,7 +259,6 @@ void InspectorFrontend::resourceTrackingWasDisabled() callSimpleFunction("resourceTrackingWasDisabled"); } - void InspectorFrontend::searchingForNodeWasEnabled() { callSimpleFunction("searchingForNodeWasEnabled"); @@ -273,6 +269,16 @@ void InspectorFrontend::searchingForNodeWasDisabled() callSimpleFunction("searchingForNodeWasDisabled"); } +void InspectorFrontend::monitoringXHRWasEnabled() +{ + callSimpleFunction("monitoringXHRWasEnabled"); +} + +void InspectorFrontend::monitoringXHRWasDisabled() +{ + callSimpleFunction("monitoringXHRWasDisabled"); +} + void InspectorFrontend::updatePauseOnExceptionsState(long state) { ScriptFunctionCall function(m_webInspector, "dispatch"); @@ -514,6 +520,33 @@ void InspectorFrontend::didChangeTagName(long callId, long nodeId) function.call(); } +void InspectorFrontend::didGetOuterHTML(long callId, const String& outerHTML) +{ + ScriptFunctionCall function(m_webInspector, "dispatch"); + function.appendArgument("didGetOuterHTML"); + function.appendArgument(callId); + function.appendArgument(outerHTML); + function.call(); +} + +void InspectorFrontend::didSetOuterHTML(long callId, long nodeId) +{ + ScriptFunctionCall function(m_webInspector, "dispatch"); + function.appendArgument("didSetOuterHTML"); + function.appendArgument(callId); + function.appendArgument(nodeId); + function.call(); +} + +void InspectorFrontend::didPushNodeByPathToFrontend(long callId, long nodeId) +{ + ScriptFunctionCall function(m_webInspector, "dispatch"); + function.appendArgument("didPushNodeByPathToFrontend"); + function.appendArgument(callId); + function.appendArgument(nodeId); + function.call(); +} + void InspectorFrontend::didGetChildNodes(long callId) { ScriptFunctionCall function(m_webInspector, "dispatch"); diff --git a/WebCore/inspector/InspectorFrontend.h b/WebCore/inspector/InspectorFrontend.h index 1762014..0b19983 100644 --- a/WebCore/inspector/InspectorFrontend.h +++ b/WebCore/inspector/InspectorFrontend.h @@ -77,10 +77,10 @@ namespace WebCore { void didGetResourceContent(long callId, const String& content); void updateFocusedNode(long nodeId); - void setAttachedWindow(bool attached); void showPanel(int panel); void populateInterface(); void reset(); + void resetProfilesPanel(); void bringToFront(); void inspectedURLChanged(const String&); @@ -91,6 +91,9 @@ namespace WebCore { void searchingForNodeWasEnabled(); void searchingForNodeWasDisabled(); + void monitoringXHRWasEnabled(); + void monitoringXHRWasDisabled(); + void updatePauseOnExceptionsState(long state); #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -142,6 +145,9 @@ namespace WebCore { void didGetEventListenersForNode(long callId, long nodeId, const ScriptArray& listenersArray); void didRemoveNode(long callId, long nodeId); void didChangeTagName(long callId, long nodeId); + void didGetOuterHTML(long callId, const String& outerHTML); + void didSetOuterHTML(long callId, long nodeId); + void didPushNodeByPathToFrontend(long callId, long nodeId); void didGetStyles(long callId, const ScriptValue& styles); void didGetAllStyles(long callId, const ScriptArray& styles); diff --git a/WebCore/inspector/InspectorFrontendClientLocal.cpp b/WebCore/inspector/InspectorFrontendClientLocal.cpp index 188566f..16a6a8b 100644 --- a/WebCore/inspector/InspectorFrontendClientLocal.cpp +++ b/WebCore/inspector/InspectorFrontendClientLocal.cpp @@ -148,7 +148,7 @@ void InspectorFrontendClientLocal::restoreAttachedWindowHeight() String attachedHeight = m_inspectorController->setting(inspectorAttachedHeightName); bool success = true; int height = attachedHeight.toInt(&success); - unsigned preferredHeight = success ? height : defaultAttachedHeight; + unsigned preferredHeight = success ? static_cast<unsigned>(height) : defaultAttachedHeight; // This call might not go through (if the window starts out detached), but if the window is initially created attached, // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight. diff --git a/WebCore/inspector/InspectorValues.cpp b/WebCore/inspector/InspectorValues.cpp index 5c7d0c8..f95116c 100644 --- a/WebCore/inspector/InspectorValues.cpp +++ b/WebCore/inspector/InspectorValues.cpp @@ -499,7 +499,7 @@ PassRefPtr<InspectorArray> InspectorValue::asArray() return 0; } -PassRefPtr<InspectorValue> InspectorValue::readJSON(const String& json) +PassRefPtr<InspectorValue> InspectorValue::parseJSON(const String& json) { const UChar* start = json.characters(); const UChar* end = json.characters() + json.length(); @@ -599,7 +599,7 @@ PassRefPtr<InspectorObject> InspectorObject::getObject(const String& name) const { PassRefPtr<InspectorValue> value = get(name); if (!value) - return false; + return 0; return value->asObject(); } @@ -607,7 +607,7 @@ PassRefPtr<InspectorArray> InspectorObject::getArray(const String& name) const { PassRefPtr<InspectorValue> value = get(name); if (!value) - return false; + return 0; return value->asArray(); } diff --git a/WebCore/inspector/InspectorValues.h b/WebCore/inspector/InspectorValues.h index b9920c4..30ba95a 100644 --- a/WebCore/inspector/InspectorValues.h +++ b/WebCore/inspector/InspectorValues.h @@ -73,7 +73,7 @@ public: virtual PassRefPtr<InspectorObject> asObject(); virtual PassRefPtr<InspectorArray> asArray(); - static PassRefPtr<InspectorValue> readJSON(const String& json); + static PassRefPtr<InspectorValue> parseJSON(const String& json); String toJSONString() const; virtual void writeJSON(Vector<UChar>* output) const; diff --git a/WebCore/inspector/ScriptBreakpoint.cpp b/WebCore/inspector/ScriptBreakpoint.cpp new file mode 100644 index 0000000..ce0d18a --- /dev/null +++ b/WebCore/inspector/ScriptBreakpoint.cpp @@ -0,0 +1,74 @@ +/* + * 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: + * + * 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. + */ + +#include "config.h" +#include "ScriptBreakpoint.h" + +#if ENABLE(INSPECTOR) + +#include "InspectorValues.h" + +namespace WebCore { + +void ScriptBreakpoint::sourceBreakpointsFromInspectorObject(PassRefPtr<InspectorObject> breakpoints, SourceBreakpoints* sourceBreakpoints) +{ + for (InspectorObject::iterator it = breakpoints->begin(); it != breakpoints->end(); ++it) { + bool ok; + int lineNumber = it->first.toInt(&ok); + if (!ok) + continue; + RefPtr<InspectorObject> breakpoint = it->second->asObject(); + if (!breakpoint) + continue; + bool enabled; + RefPtr<InspectorValue> enabledValue = breakpoint->get("enabled"); + if (!enabledValue || !enabledValue->asBool(&enabled)) + continue; + String condition; + RefPtr<InspectorValue> conditionValue = breakpoint->get("condition"); + if (!conditionValue || !conditionValue->asString(&condition)) + continue; + sourceBreakpoints->set(lineNumber, ScriptBreakpoint(enabled, condition)); + } +} + +PassRefPtr<InspectorObject> ScriptBreakpoint::inspectorObjectFromSourceBreakpoints(const SourceBreakpoints& sourceBreakpoints) +{ + RefPtr<InspectorObject> breakpoints = InspectorObject::create(); + for (SourceBreakpoints::const_iterator it = sourceBreakpoints.begin(); it != sourceBreakpoints.end(); ++it) { + RefPtr<InspectorObject> breakpoint = InspectorObject::create(); + breakpoint->setBool("enabled", it->second.enabled); + breakpoint->setString("condition", it->second.condition); + breakpoints->set(String::number(it->first), breakpoint); + } + return breakpoints.release(); +} + +} // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/WebCore/inspector/ScriptBreakpoint.h b/WebCore/inspector/ScriptBreakpoint.h index 8775901..b7c7a37 100644 --- a/WebCore/inspector/ScriptBreakpoint.h +++ b/WebCore/inspector/ScriptBreakpoint.h @@ -35,6 +35,11 @@ namespace WebCore { +class InspectorObject; +struct ScriptBreakpoint; + +typedef HashMap<int, ScriptBreakpoint> SourceBreakpoints; + struct ScriptBreakpoint { ScriptBreakpoint(bool enabled, const String& condition) : enabled(enabled) @@ -48,9 +53,10 @@ struct ScriptBreakpoint { bool enabled; String condition; -}; -typedef HashMap<int, ScriptBreakpoint> SourceBreakpoints; + static void sourceBreakpointsFromInspectorObject(PassRefPtr<InspectorObject>, SourceBreakpoints*); + static PassRefPtr<InspectorObject> inspectorObjectFromSourceBreakpoints(const SourceBreakpoints&); +}; } // namespace WebCore diff --git a/WebCore/inspector/front-end/BreakpointManager.js b/WebCore/inspector/front-end/BreakpointManager.js index 3ccccac..4f6965a 100644 --- a/WebCore/inspector/front-end/BreakpointManager.js +++ b/WebCore/inspector/front-end/BreakpointManager.js @@ -38,6 +38,7 @@ WebInspector.BreakpointManager.prototype = { if (this._oneTimeBreakpoint) this._removeBreakpointFromBackend(this._oneTimeBreakpoint); this._oneTimeBreakpoint = breakpoint; + // FIXME(40669): one time breakpoint will be persisted in inspector settings if not hit. this._saveBreakpointOnBackend(breakpoint); }, @@ -51,15 +52,15 @@ WebInspector.BreakpointManager.prototype = { addBreakpoint: function(sourceID, sourceURL, line, enabled, condition) { - var breakpoint = new WebInspector.Breakpoint(this, sourceID, sourceURL, line, enabled, condition); - if (this._breakpoints[breakpoint.id]) - return; - if (this._oneTimeBreakpoint && (this._oneTimeBreakpoint.id == breakpoint.id)) - delete this._oneTimeBreakpoint; - this._breakpoints[breakpoint.id] = breakpoint; - this._saveBreakpointOnBackend(breakpoint); - this.dispatchEventToListeners("breakpoint-added", breakpoint); - }, + var breakpoint = this._addBreakpoint(sourceID, sourceURL, line, enabled, condition); + if (breakpoint) + this._saveBreakpointOnBackend(breakpoint); + }, + + restoredBreakpoint: function(sourceID, sourceURL, line, enabled, condition) + { + this._addBreakpoint(sourceID, sourceURL, line, enabled, condition); + }, removeBreakpoint: function(breakpoint) { @@ -78,7 +79,7 @@ WebInspector.BreakpointManager.prototype = { breakpoints.push(this._breakpoints[id]); } return breakpoints; - }, + }, breakpointsForURL: function(url) { @@ -87,7 +88,7 @@ WebInspector.BreakpointManager.prototype = { if (this._breakpoints[id].url === url) breakpoints.push(this._breakpoints[id]); } - return breakpoints; + return breakpoints; }, reset: function() @@ -96,6 +97,18 @@ WebInspector.BreakpointManager.prototype = { delete this._oneTimeBreakpoint; }, + _addBreakpoint: function(sourceID, sourceURL, line, enabled, condition) + { + var breakpoint = new WebInspector.Breakpoint(this, sourceID, sourceURL, line, enabled, condition); + if (this._breakpoints[breakpoint.id]) + return; + if (this._oneTimeBreakpoint && (this._oneTimeBreakpoint.id == breakpoint.id)) + delete this._oneTimeBreakpoint; + this._breakpoints[breakpoint.id] = breakpoint; + this.dispatchEventToListeners("breakpoint-added", breakpoint); + return breakpoint; + }, + _saveBreakpointOnBackend: function(breakpoint) { InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition); diff --git a/WebCore/inspector/front-end/CSSCompletions.js b/WebCore/inspector/front-end/CSSCompletions.js new file mode 100644 index 0000000..5485464 --- /dev/null +++ b/WebCore/inspector/front-end/CSSCompletions.js @@ -0,0 +1,102 @@ +WebInspector.CSSCompletions = (function() { + var used = {}; + var properties = []; + var style = document.documentElement.style; + var list = document.defaultView.getComputedStyle(document.documentElement, ""); + var length = list.length; + for (var i = 0; i < length; ++i) + used[properties[i] = list[i]] = true; + + for (var i = 0, end = length; i < length; ++i) { + var propertyWords = properties[i].split("-"); + var j = propertyWords.length; + while (--j) { + propertyWords.pop(); + var shorthand = propertyWords.join("-"); + if (!(shorthand in used) && style[shorthand] !== undefined) { + used[shorthand] = true; + properties[end++] = shorthand; + } + } + } + + return properties.sort(); +})(); + +WebInspector.CSSCompletions.startsWith = function(prefix) +{ + var firstIndex = this._firstIndexOfPrefix(prefix); + if (firstIndex === -1) + return []; + + var results = []; + while (this[firstIndex].indexOf(prefix) === 0) + results.push(this[firstIndex++]); + return results; +} + +WebInspector.CSSCompletions.firstStartsWith = function(prefix) +{ + var foundIndex = this._firstIndexOfPrefix(prefix); + return (foundIndex === -1 ? "" : this[foundIndex]); +} + +WebInspector.CSSCompletions._firstIndexOfPrefix = function(prefix) +{ + if (!prefix) + return -1; + + var maxIndex = this.length - 1; + var minIndex = 0; + var foundIndex; + + do { + var middleIndex = (maxIndex + minIndex) >> 1; + if (this[middleIndex].indexOf(prefix) === 0) { + foundIndex = middleIndex; + break; + } + if (this[middleIndex] < prefix) + minIndex = middleIndex + 1; + else + maxIndex = middleIndex - 1; + } while (minIndex <= maxIndex); + + if (!foundIndex) + return -1; + + while (foundIndex && this[foundIndex - 1].indexOf(prefix) === 0) + foundIndex--; + + return foundIndex; +} + +WebInspector.CSSCompletions.next = function(str, prefix) +{ + return WebInspector.CSSCompletions._closest(str, prefix, 1); +} + +WebInspector.CSSCompletions.previous = function(str, prefix) +{ + return WebInspector.CSSCompletions._closest(str, prefix, -1); +} + +WebInspector.CSSCompletions._closest = function(str, prefix, shift) +{ + if (!str) + return ""; + + var index = this.indexOf(str); + if (index === -1) + return ""; + + if (!prefix) { + index = (index + this.length + shift) % this.length; + return this[index]; + } + + var propertiesWithPrefix = this.startsWith(prefix); + var j = propertiesWithPrefix.indexOf(str); + j = (j + propertiesWithPrefix.length + shift) % propertiesWithPrefix.length; + return propertiesWithPrefix[j]; +} diff --git a/WebCore/inspector/front-end/ConsoleView.js b/WebCore/inspector/front-end/ConsoleView.js index d1f347b..8bb71e6 100644 --- a/WebCore/inspector/front-end/ConsoleView.js +++ b/WebCore/inspector/front-end/ConsoleView.js @@ -296,7 +296,7 @@ WebInspector.ConsoleView.prototype = { requestClearMessages: function() { - InjectedScriptAccess.getDefault().clearConsoleMessages(function() {}); + InspectorBackend.clearConsoleMessages(); }, clearMessages: function() @@ -399,7 +399,13 @@ WebInspector.ConsoleView.prototype = { return; } - this._contextMenu.show(event); + var contextMenu = new WebInspector.ContextMenu(); + if (!WebInspector.monitoringXHREnabled) + contextMenu.appendItem(WebInspector.UIString("Enable XMLHttpRequest logging"), InspectorBackend.enableMonitoringXHR.bind(InspectorBackend)); + else + contextMenu.appendItem(WebInspector.UIString("Disable XMLHttpRequest logging"), InspectorBackend.disableMonitoringXHR.bind(InspectorBackend)); + contextMenu.appendItem(WebInspector.UIString("Clear Console"), this.requestClearMessages.bind(this)); + contextMenu.show(event); }, _messagesSelectStart: function(event) @@ -444,8 +450,6 @@ WebInspector.ConsoleView.prototype = { var clearConsoleHandler = this.requestClearMessages.bind(this); var shortcutL = shortcut.makeDescriptor("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl); this._shortcuts[shortcutL.key] = clearConsoleHandler; - this._contextMenu = new WebInspector.ContextMenu(); - this._contextMenu.appendItem(WebInspector.UIString("Clear Console"), clearConsoleHandler); var section = WebInspector.shortcutsHelp.section(WebInspector.UIString("Console")); var keys = WebInspector.isMac() ? [ shortcutK.name, shortcutL.name ] : [ shortcutL.name ]; diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js index 5bde12f..ee85d1c 100644 --- a/WebCore/inspector/front-end/DOMAgent.js +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -669,6 +669,9 @@ WebInspector.didRemoveAttribute = WebInspector.Callback.processCallback; WebInspector.didSetTextNodeValue = WebInspector.Callback.processCallback; WebInspector.didRemoveNode = WebInspector.Callback.processCallback; WebInspector.didChangeTagName = WebInspector.Callback.processCallback; +WebInspector.didGetOuterHTML = WebInspector.Callback.processCallback; +WebInspector.didSetOuterHTML = WebInspector.Callback.processCallback; +WebInspector.didPushNodeByPathToFrontend = WebInspector.Callback.processCallback; WebInspector.didGetEventListenersForNode = WebInspector.Callback.processCallback; WebInspector.didGetStyles = WebInspector.Callback.processCallback; diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index 55ba82d..c8eb3dd 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -59,7 +59,7 @@ WebInspector.ElementsPanel = function() this.panel.updateEventListeners(); if (this._focusedDOMNode) - InjectedScriptAccess.get(this._focusedDOMNode.injectedScriptId).addInspectedNode(this._focusedDOMNode.id, function() {}); + InspectorBackend.addInspectedNode(this._focusedDOMNode.id); }; this.contentElement.appendChild(this.treeOutline.element); @@ -224,9 +224,10 @@ WebInspector.ElementsPanel.prototype = { selectNode.call(this, node); } - if (this._selectedPathOnReset) - InjectedScriptAccess.getDefault().nodeByPath(this._selectedPathOnReset, selectLastSelectedNode.bind(this)); - else + if (this._selectedPathOnReset) { + var callId = WebInspector.Callback.wrap(selectLastSelectedNode.bind(this)); + InspectorBackend.pushNodeByPathToFrontend(callId, this._selectedPathOnReset); + } else selectNode.call(this); delete this._selectedPathOnReset; }, diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index e8fecb0..1b84b83 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -1094,7 +1094,7 @@ WebInspector.ElementsTreeElement.prototype = { function changeTagNameCallback(nodeId) { - if (nodeId === -1) { + if (!nodeId) { cancel(); return; } @@ -1111,7 +1111,7 @@ WebInspector.ElementsTreeElement.prototype = { } var callId = WebInspector.Callback.wrap(changeTagNameCallback); - InspectorBackend.changeTagName(callId, this.representedObject.id, newText, wasExpanded); + InspectorBackend.changeTagName(callId, this.representedObject.id, newText); }, _textNodeEditingCommitted: function(element, newText) @@ -1382,10 +1382,12 @@ WebInspector.ElementsTreeElement.prototype = { function commitChange(value) { - InjectedScriptAccess.get(node.injectedScriptId).setOuterHTML(node.id, value, wasExpanded, selectNode.bind(this)); + var setCallId = WebInspector.Callback.wrap(selectNode); + InspectorBackend.setOuterHTML(setCallId, node.id, value); } - InjectedScriptAccess.get(node.injectedScriptId).getNodePropertyValue(node.id, "outerHTML", this._startEditingAsHTML.bind(this, commitChange)); + var getCallId = WebInspector.Callback.wrap(this._startEditingAsHTML.bind(this, commitChange)); + InspectorBackend.getOuterHTML(getCallId, node.id); }, _copyHTML: function() diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js index e62a916..26495e8 100644 --- a/WebCore/inspector/front-end/InjectedScript.js +++ b/WebCore/inspector/front-end/InjectedScript.js @@ -80,13 +80,6 @@ InjectedScript.releaseWrapperObjectGroup = function(objectGroupName) { delete InjectedScript.objectGroups[objectGroupName]; }; -// Called from within InspectorController on the 'inspected page' side. -InjectedScript.reset = function() -{ -} - -InjectedScript.reset(); - InjectedScript.dispatch = function(methodName, args, callId) { var argsArray = eval("(" + args + ")"); @@ -218,29 +211,6 @@ InjectedScript.setPropertyValue = function(objectProxy, propertyName, expression } } -InjectedScript.getNodePropertyValue = function(nodeId, propertyName) -{ - var node = InjectedScript._nodeForId(nodeId); - if (!node) - return false; - var result = node[propertyName]; - return result !== undefined ? result : false; -} - -InjectedScript.setOuterHTML = function(nodeId, value, expanded) -{ - var node = InjectedScript._nodeForId(nodeId); - if (!node) - return false; - - var parent = node.parentNode; - var prevSibling = node.previousSibling; - node.outerHTML = value; - var newNode = prevSibling ? prevSibling.nextSibling : parent.firstChild; - - return InjectedScriptHost.pushNodePathToFrontend(newNode, expanded, false); -} - InjectedScript._populatePropertyNames = function(object, resultSet) { for (var o = object; o; o = o.__proto__) { @@ -281,14 +251,15 @@ InjectedScript.getCompletions = function(expression, includeInspectorCommandLine } else { if (!expression) expression = "this"; - expressionResult = InjectedScript._evaluateOn(inspectedWindow.eval, inspectedWindow, expression); + expressionResult = InjectedScript._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); } - if (typeof expressionResult == "object") + if (typeof expressionResult === "object") InjectedScript._populatePropertyNames(expressionResult, props); - if (includeInspectorCommandLineAPI) - for (var prop in inspectedWindow.console._inspectorCommandLineAPI) - if (prop.charAt(0) !== '_') - props[prop] = true; + + if (includeInspectorCommandLineAPI) { + for (var prop in InjectedScript._commandLineAPI) + props[prop] = true; + } } catch(e) { } return props; @@ -319,14 +290,21 @@ InjectedScript._evaluateAndWrap = function(evalFunction, object, expression, obj InjectedScript._evaluateOn = function(evalFunction, object, expression, dontUseCommandLineAPI) { - InjectedScript._ensureCommandLineAPIInstalled(evalFunction, object); - // Surround the expression in with statements to inject our command line API so that - // the window object properties still take more precedent than our API functions. - if (!dontUseCommandLineAPI) - expression = "with (window.console._inspectorCommandLineAPI) { with (window) {\n" + expression + "\n} }"; + if (!dontUseCommandLineAPI) { + // Only install command line api object for the time of evaluation. + + // Surround the expression in with statements to inject our command line API so that + // the window object properties still take more precedent than our API functions. + inspectedWindow.console._commandLineAPI = InjectedScript._commandLineAPI; + + expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }"; + } var value = evalFunction.call(object, expression); + if (!dontUseCommandLineAPI) + delete inspectedWindow.console._commandLineAPI; + // When evaluating on call frame error is not thrown, but returned as a value. if (InjectedScript._type(value) === "error") throw value.toString(); @@ -334,20 +312,6 @@ InjectedScript._evaluateOn = function(evalFunction, object, expression, dontUseC return value; } -InjectedScript.addInspectedNode = function(nodeId) -{ - var node = InjectedScript._nodeForId(nodeId); - if (!node) - return false; - - InjectedScript._ensureCommandLineAPIInstalled(inspectedWindow.eval, inspectedWindow); - var inspectedNodes = inspectedWindow.console._inspectorCommandLineAPI._inspectedNodes; - inspectedNodes.unshift(node); - if (inspectedNodes.length >= 5) - inspectedNodes.pop(); - return true; -} - InjectedScript.getNodeId = function(node) { return InjectedScriptHost.pushNodePathToFrontend(node, false, false); @@ -392,125 +356,10 @@ InjectedScript._callFrameForId = function(id) return callFrame; } -InjectedScript.clearConsoleMessages = function() -{ - InjectedScriptHost.clearConsoleMessages(); - return true; -} - -InjectedScript._inspectObject = function(o) -{ - if (arguments.length === 0) - return; - - inspectedWindow.console.log(o); - if (InjectedScript._type(o) === "node") { - InjectedScriptHost.pushNodePathToFrontend(o, false, true); - } else { - switch (InjectedScript._describe(o)) { - case "Database": - InjectedScriptHost.selectDatabase(o); - break; - case "Storage": - InjectedScriptHost.selectDOMStorage(o); - break; - } - } -} - -InjectedScript._copy = function(o) -{ - if (InjectedScript._type(o) === "node") { - var nodeId = InjectedScriptHost.pushNodePathToFrontend(o, false, false); - InjectedScriptHost.copyNode(nodeId); - } else { - InjectedScriptHost.copyText(o); - } -} - -InjectedScript._ensureCommandLineAPIInstalled = function(evalFunction, evalObject) -{ - if (evalFunction.call(evalObject, "window.console._inspectorCommandLineAPI")) - return; - var inspectorCommandLineAPI = evalFunction.call(evalObject, "window.console._inspectorCommandLineAPI = { \n\ - $: function() { return document.getElementById.apply(document, arguments) }, \n\ - $$: function() { return document.querySelectorAll.apply(document, arguments) }, \n\ - $x: function(xpath, context) \n\ - { \n\ - var nodes = []; \n\ - try { \n\ - var doc = context || document; \n\ - var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); \n\ - var node; \n\ - while (node = results.iterateNext()) nodes.push(node); \n\ - } catch (e) {} \n\ - return nodes; \n\ - }, \n\ - dir: function() { return console.dir.apply(console, arguments) }, \n\ - dirxml: function() { return console.dirxml.apply(console, arguments) }, \n\ - keys: function(o) { var a = []; for (var k in o) a.push(k); return a; }, \n\ - values: function(o) { var a = []; for (var k in o) a.push(o[k]); return a; }, \n\ - profile: function() { return console.profile.apply(console, arguments) }, \n\ - profileEnd: function() { return console.profileEnd.apply(console, arguments) }, \n\ - _logEvent: function _inspectorCommandLineAPI_logEvent(e) { console.log(e.type, e); }, \n\ - _allEventTypes: [\"mouse\", \"key\", \"load\", \"unload\", \"abort\", \"error\", \n\ - \"select\", \"change\", \"submit\", \"reset\", \"focus\", \"blur\", \n\ - \"resize\", \"scroll\"], \n\ - _normalizeEventTypes: function(t) \n\ - { \n\ - if (typeof t === \"undefined\") \n\ - t = console._inspectorCommandLineAPI._allEventTypes; \n\ - else if (typeof t === \"string\") \n\ - t = [t]; \n\ - var i, te = []; \n\ - for (i = 0; i < t.length; i++) { \n\ - if (t[i] === \"mouse\") \n\ - te.splice(0, 0, \"mousedown\", \"mouseup\", \"click\", \"dblclick\", \n\ - \"mousemove\", \"mouseover\", \"mouseout\"); \n\ - else if (t[i] === \"key\") \n\ - te.splice(0, 0, \"keydown\", \"keyup\", \"keypress\"); \n\ - else \n\ - te.push(t[i]); \n\ - } \n\ - return te; \n\ - }, \n\ - monitorEvents: function(o, t) \n\ - { \n\ - if (!o || !o.addEventListener || !o.removeEventListener) \n\ - return; \n\ - t = console._inspectorCommandLineAPI._normalizeEventTypes(t); \n\ - for (i = 0; i < t.length; i++) { \n\ - o.removeEventListener(t[i], console._inspectorCommandLineAPI._logEvent, false); \n\ - o.addEventListener(t[i], console._inspectorCommandLineAPI._logEvent, false); \n\ - } \n\ - }, \n\ - unmonitorEvents: function(o, t) \n\ - { \n\ - if (!o || !o.removeEventListener) \n\ - return; \n\ - t = console._inspectorCommandLineAPI._normalizeEventTypes(t); \n\ - for (i = 0; i < t.length; i++) { \n\ - o.removeEventListener(t[i], console._inspectorCommandLineAPI._logEvent, false); \n\ - } \n\ - }, \n\ - _inspectedNodes: [], \n\ - get $0() { return console._inspectorCommandLineAPI._inspectedNodes[0] }, \n\ - get $1() { return console._inspectorCommandLineAPI._inspectedNodes[1] }, \n\ - get $2() { return console._inspectorCommandLineAPI._inspectedNodes[2] }, \n\ - get $3() { return console._inspectorCommandLineAPI._inspectedNodes[3] }, \n\ - get $4() { return console._inspectorCommandLineAPI._inspectedNodes[4] }, \n\ - };"); - - inspectorCommandLineAPI.clear = InjectedScript.clearConsoleMessages; - inspectorCommandLineAPI.inspect = InjectedScript._inspectObject; - inspectorCommandLineAPI.copy = InjectedScript._copy; -} - InjectedScript._resolveObject = function(objectProxy) { var object = InjectedScript._objectForId(objectProxy.objectId); var path = objectProxy.path; - var protoDepth = objectProxy.protoDepth; // Follow the property path. for (var i = 0; InjectedScript._isDefined(object) && path && i < path.length; ++i) @@ -532,11 +381,11 @@ InjectedScript._objectForId = function(objectId) // - numbers point to DOM Node via the InspectorDOMAgent mapping // - strings point to console objects cached in InspectorController for lazy evaluation upon them // - objects contain complex ids and are currently used for scoped objects - if (typeof objectId === "number") { + if (typeof objectId === "number") return InjectedScript._nodeForId(objectId); - } else if (typeof objectId === "string") { + else if (typeof objectId === "string") return InjectedScript.unwrapObject(objectId); - } else if (typeof objectId === "object") { + else if (typeof objectId === "object") { var callFrame = InjectedScript._callFrameForId(objectId.callFrame); if (objectId.thisObject) return callFrame.thisObject; @@ -554,13 +403,6 @@ InjectedScript.pushNodeToFrontend = function(objectProxy) return InjectedScriptHost.pushNodePathToFrontend(object, false, false); } -InjectedScript.nodeByPath = function(path) -{ - // We make this call through the injected script only to get a nice - // callback for it. - return InjectedScriptHost.pushNodeByPathToFrontend(path.join(",")); -} - // Called from within InspectorController on the 'inspected page' side. InjectedScript.createProxyObject = function(object, objectId, abbreviate) { @@ -736,14 +578,13 @@ InjectedScript._type = function(obj) InjectedScript._describe = function(obj, abbreviated) { - var type1 = InjectedScript._type(obj); - var type2 = InjectedScript._className(obj); + var type = InjectedScript._type(obj); - switch (type1) { + switch (type) { case "object": case "node": case "array": - return type2; + return InjectedScript._className(obj); case "string": if (!abbreviated) return obj; @@ -752,10 +593,8 @@ InjectedScript._describe = function(obj, abbreviated) return "\"" + obj + "\""; case "function": var objectText = InjectedScript._toString(obj); - if (!/^function /.test(objectText)) - objectText = (type2 == "object") ? type1 : type2; - else if (abbreviated) - objectText = /.*/.exec(obj)[0].replace(/ +$/g, ""); + if (abbreviated) + objectText = /.*/.exec(objectText)[0].replace(/ +$/g, ""); return objectText; default: return InjectedScript._toString(obj); @@ -779,11 +618,185 @@ InjectedScript._className = function(obj) return str.replace(/^\[object (.*)\]$/i, "$1"); } else { // V8 - if (typeof obj !== "object") - return "null"; - return obj.constructor.name || "Object"; + return obj.constructor && obj.constructor.name || "Object"; + } +} + +InjectedScript._logEvent = function(event) +{ + console.log(event.type, event); +} + +InjectedScript._normalizeEventTypes = function(types) +{ + if (typeof types === "undefined") + types = [ "mouse", "key", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ]; + else if (typeof types === "string") + types = [ types ]; + + var result = []; + for (var i = 0; i < types.length; i++) { + if (types[i] === "mouse") + result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout"); + else if (types[i] === "key") + result.splice(0, 0, "keydown", "keyup", "keypress"); + else + result.push(types[i]); + } + return result; +} + +InjectedScript._inspectedNode = function(num) +{ + var nodeId = InjectedScriptHost.inspectedNode(num); + return InjectedScript._nodeForId(nodeId); +} + +function CommandLineAPI() +{ +} + +CommandLineAPI.prototype = { + // Only add API functions here, private stuff should go to + // InjectedScript so that it is not suggested by the completion. + $: function() + { + return document.getElementById.apply(document, arguments) + }, + + $$: function() + { + return document.querySelectorAll.apply(document, arguments) + }, + + $x: function(xpath, context) + { + var nodes = []; + try { + var doc = context || document; + var results = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null); + var node; + while (node = results.iterateNext()) + nodes.push(node); + } catch (e) { + } + return nodes; + }, + + dir: function() + { + return console.dir.apply(console, arguments) + }, + + dirxml: function() + { + return console.dirxml.apply(console, arguments) + }, + + keys: function(object) + { + return Object.keys(object); + }, + + values: function(object) + { + var result = []; + for (var key in object) + result.push(object[key]); + return result; + }, + + profile: function() + { + return console.profile.apply(console, arguments) + }, + + profileEnd: function() + { + return console.profileEnd.apply(console, arguments) + }, + + monitorEvents: function(object, types) + { + if (!object || !object.addEventListener || !object.removeEventListener) + return; + types = InjectedScript._normalizeEventTypes(types); + for (var i = 0; i < types.length; ++i) { + object.removeEventListener(types[i], InjectedScript._logEvent, false); + object.addEventListener(types[i], InjectedScript._logEvent, false); + } + }, + + unmonitorEvents: function(object, types) + { + if (!object || !object.addEventListener || !object.removeEventListener) + return; + types = InjectedScript._normalizeEventTypes(types); + for (var i = 0; i < types.length; ++i) + object.removeEventListener(types[i], InjectedScript._logEvent, false); + }, + + inspect: function(object) + { + if (arguments.length === 0) + return; + + inspectedWindow.console.log(object); + if (InjectedScript._type(object) === "node") + InjectedScriptHost.pushNodePathToFrontend(object, false, true); + else { + switch (InjectedScript._describe(object)) { + case "Database": + InjectedScriptHost.selectDatabase(object); + break; + case "Storage": + InjectedScriptHost.selectDOMStorage(object); + break; + } + } + }, + + copy: function(object) + { + if (InjectedScript._type(object) === "node") { + var nodeId = InjectedScriptHost.pushNodePathToFrontend(object, false, false); + InjectedScriptHost.copyNode(nodeId); + } else + InjectedScriptHost.copyText(object); + }, + + clear: function() + { + InjectedScriptHost.clearConsoleMessages(); + }, + + get $0() + { + return InjectedScript._inspectedNode(0); + }, + + get $1() + { + return InjectedScript._inspectedNode(1); + }, + + get $2() + { + return InjectedScript._inspectedNode(2); + }, + + get $3() + { + return InjectedScript._inspectedNode(3); + }, + + get $4() + { + return InjectedScript._inspectedNode(4); } } +InjectedScript._commandLineAPI = new CommandLineAPI(); + return InjectedScript; }); diff --git a/WebCore/inspector/front-end/InjectedScriptAccess.js b/WebCore/inspector/front-end/InjectedScriptAccess.js index c388213..90daab7 100644 --- a/WebCore/inspector/front-end/InjectedScriptAccess.js +++ b/WebCore/inspector/front-end/InjectedScriptAccess.js @@ -70,18 +70,13 @@ InjectedScriptAccess._installHandler = function(methodName, async) // - Make sure corresponding methods in InjectedScript return non-null and non-undefined values, // - Make sure last parameter of all the InjectedSriptAccess.* calls is a callback function. // We keep these sorted. -InjectedScriptAccess._installHandler("addInspectedNode"); -InjectedScriptAccess._installHandler("clearConsoleMessages"); InjectedScriptAccess._installHandler("evaluate"); InjectedScriptAccess._installHandler("evaluateInCallFrame"); InjectedScriptAccess._installHandler("getCompletions"); -InjectedScriptAccess._installHandler("getNodePropertyValue"); InjectedScriptAccess._installHandler("getProperties"); InjectedScriptAccess._installHandler("getPrototypes"); InjectedScriptAccess._installHandler("openInInspectedWindow"); InjectedScriptAccess._installHandler("pushNodeToFrontend"); -InjectedScriptAccess._installHandler("nodeByPath"); -InjectedScriptAccess._installHandler("setOuterHTML"); InjectedScriptAccess._installHandler("setPropertyValue"); InjectedScriptAccess._installHandler("evaluateOnSelf"); diff --git a/WebCore/inspector/front-end/InspectorBackendStub.js b/WebCore/inspector/front-end/InspectorBackendStub.js index 492bf87..1ae32b5 100644 --- a/WebCore/inspector/front-end/InspectorBackendStub.js +++ b/WebCore/inspector/front-end/InspectorBackendStub.js @@ -32,7 +32,6 @@ if (!window.InspectorBackend) { WebInspector.InspectorBackendStub = function() { - this._searchingForNode = false; this._attachedWindowHeight = 0; this._timelineEnabled = false; } @@ -60,25 +59,23 @@ WebInspector.InspectorBackendStub.prototype = { { }, - clearMessages: function() + clearConsoleMessages: function() { }, - searchingForNode: function() + getOuterHTML: function() { - return this._searchingForNode; }, - search: function(sourceRow, query) + setOuterHTML: function() { }, - toggleNodeSearch: function() + addInspectedNode: function() { - this._searchingForNode = !this._searchingForNode; }, - setAttachedWindowHeight: function(height) + search: function(sourceRow, query) { }, @@ -144,6 +141,16 @@ WebInspector.InspectorBackendStub.prototype = { WebInspector.searchingForNodeWasDisabled(); }, + enableMonitoringXHR: function() + { + WebInspector.monitoringXHRWasEnabled(); + }, + + disableMonitoringXHR: function() + { + WebInspector.monitoringXHRWasDisabled(); + }, + reloadPage: function() { }, diff --git a/WebCore/inspector/front-end/InspectorFrontendHostStub.js b/WebCore/inspector/front-end/InspectorFrontendHostStub.js index 5456069..39bbe02 100644 --- a/WebCore/inspector/front-end/InspectorFrontendHostStub.js +++ b/WebCore/inspector/front-end/InspectorFrontendHostStub.js @@ -40,7 +40,13 @@ WebInspector._platformFlavor = WebInspector.PlatformFlavor.MacLeopard; WebInspector.InspectorFrontendHostStub.prototype = { platform: function() { - return "mac"; + var match = navigator.userAgent.match(/Windows NT/); + if (match) + return "windows"; + match = navigator.userAgent.match(/Mac OS X/); + if (match) + return "mac"; + return "linux"; }, port: function() diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index 1980fa5..b5122af 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -124,7 +124,7 @@ WebInspector.ProfilesPanel = function() this._profiles = []; this._profilerEnabled = Preferences.profilerAlwaysEnabled; - this.reset(); + this._reset(); } WebInspector.ProfilesPanel.prototype = { @@ -167,7 +167,7 @@ WebInspector.ProfilesPanel.prototype = { populateInterface: function() { - this.reset(); + this._reset(); if (this.visible) this._populateProfiles(); else @@ -189,10 +189,15 @@ WebInspector.ProfilesPanel.prototype = { return; this._profilerEnabled = false; - this.reset(); + this._reset(); }, - reset: function() + resetProfiles: function() + { + this._reset(); + }, + + _reset: function() { for (var i = 0; i < this._profiles.length; ++i) delete this._profiles[i]._profileView; @@ -222,7 +227,7 @@ WebInspector.ProfilesPanel.prototype = { _clearProfiles: function() { InspectorBackend.clearProfiles(); - this.reset(); + this._reset(); }, registerProfileType: function(profileType) @@ -618,7 +623,8 @@ WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle) WebInspector.ProfileGroupSidebarTreeElement.prototype = { onselect: function() { - WebInspector.panels.profiles.showProfile(this.children[this.children.length - 1].profile); + if (this.children.length > 0) + WebInspector.panels.profiles.showProfile(this.children[this.children.length - 1].profile); } } diff --git a/WebCore/inspector/front-end/ScriptView.js b/WebCore/inspector/front-end/ScriptView.js index fb0bb4b..1883fb3 100644 --- a/WebCore/inspector/front-end/ScriptView.js +++ b/WebCore/inspector/front-end/ScriptView.js @@ -105,7 +105,12 @@ WebInspector.ScriptView.prototype = { this.sourceFrame.updateContent(this._prependWhitespace(newBody)); }, - // The follow methods are pulled from SourceView, since they are + _sourceIDForLine: function(line) + { + return this.script.sourceID; + }, + + // The following methods are pulled from SourceView, since they are // generic and work with ScriptView just fine. hide: WebInspector.SourceView.prototype.hide, diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 4504d57..c23db14 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -169,8 +169,6 @@ WebInspector.ScriptsPanel = function() this._registerShortcuts(); this._debuggerEnabled = Preferences.debuggerAlwaysEnabled; - if (Preferences.debuggerAlwaysEnabled) - this._attachDebuggerWhenShown = true; WebInspector.breakpointManager.addEventListener("breakpoint-added", this._breakpointAdded, this); WebInspector.breakpointManager.addEventListener("breakpoint-removed", this._breakpointRemoved, this); diff --git a/WebCore/inspector/front-end/Section.js b/WebCore/inspector/front-end/Section.js index 7710192..913d495 100644 --- a/WebCore/inspector/front-end/Section.js +++ b/WebCore/inspector/front-end/Section.js @@ -82,7 +82,22 @@ WebInspector.Section.prototype = { if (this._subtitle === x) return; this._subtitle = x; - this.subtitleElement.innerHTML = x; + this.subtitleElement.setAttribute("data-uncopyable", x); + }, + + get subtitleAsText() + { + var result = ""; + var data = this.subtitleElement.getAttribute("data-uncopyable"); + if (data) + result += data; + var child = this.subtitleElement.querySelector("[data-uncopyable]"); + if (child) { + var linkData = child.getAttribute("data-uncopyable"); + if (linkData) + result += linkData; + } + return result; }, get expanded() diff --git a/WebCore/inspector/front-end/StoragePanel.js b/WebCore/inspector/front-end/StoragePanel.js index ca1b276..fef7802 100644 --- a/WebCore/inspector/front-end/StoragePanel.js +++ b/WebCore/inspector/front-end/StoragePanel.js @@ -289,6 +289,7 @@ WebInspector.StoragePanel.prototype = { var column = {}; column.width = columnIdentifier.length; column.title = columnIdentifier; + column.sortable = true; columns[columnIdentifier] = column; ++numColumns; @@ -313,9 +314,45 @@ WebInspector.StoragePanel.prototype = { for (var i = 0; i < length; ++i) dataGrid.appendChild(nodes[i]); + dataGrid.addEventListener("sorting changed", this._sortDataGrid.bind(this, dataGrid), this); return dataGrid; }, + _sortDataGrid: function(dataGrid) + { + var nodes = dataGrid.children.slice(); + var sortColumnIdentifier = dataGrid.sortColumnIdentifier; + var sortDirection = dataGrid.sortOrder === "ascending" ? 1 : -1; + var columnIsNumeric = true; + + for (var i = 0; i < nodes.length; i++) { + if (isNaN(Number(nodes[i].data[sortColumnIdentifier]))) + columnIsNumeric = false; + } + + function comparator(dataGridNode1, dataGridNode2) + { + var item1 = dataGridNode1.data[sortColumnIdentifier]; + var item2 = dataGridNode2.data[sortColumnIdentifier]; + + var comparison; + if (columnIsNumeric) { + // Sort numbers based on comparing their values rather than a lexicographical comparison. + var number1 = parseFloat(item1); + var number2 = parseFloat(item2); + comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0); + } else + comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0); + + return sortDirection * comparison; + } + + nodes.sort(comparator); + dataGrid.removeChildren(); + for (var i = 0; i < nodes.length; i++) + dataGrid.appendChild(nodes[i]); + }, + updateDOMStorage: function(storageId) { var domStorage = this._domStorageForId(storageId); diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js index 18b7f0f..649b9d0 100644 --- a/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/WebCore/inspector/front-end/StylesSidebarPane.js @@ -651,7 +651,10 @@ WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyl if (!subtitle) { if (this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.href) { var url = this.styleRule.parentStyleSheet.href; - this.subtitleElement.appendChild(WebInspector.linkifyResourceAsNode(url, "resources", this.rule.sourceLine + 1)); + var link = WebInspector.linkifyResourceAsNode(url, "resources", this.rule.sourceLine + 1); + link.setAttribute("data-uncopyable", link.textContent); + link.textContent = ""; + this.subtitleElement.appendChild(link); } else if (isUserAgent) subtitle = WebInspector.UIString("user agent stylesheet"); else if (isUser) @@ -669,7 +672,7 @@ WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyl this.identifier = styleRule.selectorText; if (this.subtitle) - this.identifier += ":" + this.subtitleElement.textContent; + this.identifier += ":" + this.subtitle; } WebInspector.StylePropertiesSection.prototype = { @@ -1315,6 +1318,18 @@ WebInspector.StylePropertyTreeElement.prototype = { event.stopPropagation(); }, + restoreNameElement: function() + { + // Restore <span class="webkit-css-property"> if it doesn't yet exist or was accidentally deleted. + if (this.nameElement === this.listItemElement.querySelector(".webkit-css-property")) + return; + + this.nameElement = document.createElement("span"); + this.nameElement.className = "webkit-css-property"; + this.nameElement.textContent = ""; + this.listItemElement.insertBefore(this.nameElement, this.listItemElement.firstChild); + }, + startEditing: function(selectElement) { // FIXME: we don't allow editing of longhand properties under a shorthand right now. @@ -1324,7 +1339,12 @@ WebInspector.StylePropertyTreeElement.prototype = { if (WebInspector.isBeingEdited(this.listItemElement) || (this.treeOutline.section && !this.treeOutline.section.editable)) return; - var context = { expanded: this.expanded, hasChildren: this.hasChildren, keyDownListener: this.editingKeyDown.bind(this) }; + var context = { + expanded: this.expanded, + hasChildren: this.hasChildren, + keyDownListener: this.editingKeyDown.bind(this), + keyPressListener: this.editingKeyPress.bind(this) + }; // Lie about our children to prevent expanding on double click and to collapse shorthands. this.hasChildren = false; @@ -1333,11 +1353,42 @@ WebInspector.StylePropertyTreeElement.prototype = { selectElement = this.listItemElement; this.listItemElement.addEventListener("keydown", context.keyDownListener, false); + this.listItemElement.addEventListener("keypress", context.keyPressListener, false); WebInspector.startEditing(this.listItemElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context); window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); }, + editingKeyPress: function(event) + { + var selection = window.getSelection(); + var colonIndex = this.listItemElement.textContent.indexOf(":"); + var selectionLeftOffset = event.target.selectionLeftOffset; + + if (colonIndex < 0 || selectionLeftOffset <= colonIndex) { + // Complete property names. + var character = event.data.toLowerCase(); + if (character && /[a-z-]/.test(character)) { + var prefix = selection.anchorNode.textContent.substring(0, selection.anchorOffset); + var property = WebInspector.CSSCompletions.firstStartsWith(prefix + character); + + if (!selection.isCollapsed) + selection.deleteFromDocument(); + + this.restoreNameElement(); + + if (property) { + if (property !== this.nameElement.textContent) + this.nameElement.textContent = property; + this.nameElement.firstChild.select(prefix.length + 1); + event.preventDefault(); + } + } + } else { + // FIXME: This should complete property values. + } + }, + editingKeyDown: function(event) { var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down"); @@ -1396,9 +1447,24 @@ WebInspector.StylePropertyTreeElement.prototype = { } replacementString = prefix + number + suffix; - } else { - // FIXME: this should cycle through known keywords for the current property name. + } else if (selection.containsNode(this.nameElement, true)) { + var prefix = selectionRange.startContainer.textContent.substring(0, selectionRange.startOffset); + var property; + + if (event.keyIdentifier === "Up") + property = WebInspector.CSSCompletions.previous(wordString, prefix); + else if (event.keyIdentifier === "Down") + property = WebInspector.CSSCompletions.next(wordString, prefix); + + var startOffset = selectionRange.startOffset; + if (property) { + this.nameElement.textContent = property; + this.nameElement.firstChild.select(startOffset); + } + event.preventDefault(); return; + } else { + // FIXME: this should cycle through known keywords for the current property value. } var replacementTextNode = document.createTextNode(replacementString); @@ -1434,6 +1500,7 @@ WebInspector.StylePropertyTreeElement.prototype = { if (context.expanded) this.expand(); this.listItemElement.removeEventListener("keydown", context.keyDownListener, false); + this.listItemElement.removeEventListener("keypress", context.keyPressListener, false); delete this.originalCSSText; }, diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index fd84586..add50e1 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -19,6 +19,7 @@ <file>ConsoleView.js</file> <file>ContextMenu.js</file> <file>CookieItemsView.js</file> + <file>CSSCompletions.js</file> <file>CSSStyleModel.js</file> <file>Database.js</file> <file>DatabaseQueryView.js</file> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 52b85bc..b92672a 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -27,6 +27,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +html { + height: 100%; +} + body { cursor: default; position: absolute; @@ -4038,6 +4042,10 @@ a.worker-item { color: inherit; } +.styles-section .subtitle::before, .styles-section .subtitle a::before { + content: attr(data-uncopyable); +} + .styles-section .properties { display: none; margin: 0; diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 4c51634..8a8b7d5 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -82,6 +82,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="PropertiesSidebarPane.js"></script> <script type="text/javascript" src="EventListenersSidebarPane.js"></script> <script type="text/javascript" src="Color.js"></script> + <script type="text/javascript" src="CSSCompletions.js"></script> <script type="text/javascript" src="StylesSidebarPane.js"></script> <script type="text/javascript" src="PanelEnablerView.js"></script> <script type="text/javascript" src="WelcomeView.js"></script> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index e8108af..3bb4180 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -1297,6 +1297,16 @@ WebInspector.searchingForNodeWasDisabled = function() this.panels.elements.searchingForNodeWasDisabled(); } +WebInspector.monitoringXHRWasEnabled = function() +{ + this.monitoringXHREnabled = true; +} + +WebInspector.monitoringXHRWasDisabled = function() +{ + this.monitoringXHREnabled = false; +} + WebInspector.attachDebuggerWhenShown = function() { this.panels.scripts.attachDebuggerWhenShown(); @@ -1334,7 +1344,7 @@ WebInspector.parsedScriptSource = function(sourceID, sourceURL, source, starting WebInspector.restoredBreakpoint = function(sourceID, sourceURL, line, enabled, condition) { - this.breakpointManager.addBreakpoint(sourceID, sourceURL, line, enabled, condition); + this.breakpointManager.restoredBreakpoint(sourceID, sourceURL, line, enabled, condition); } WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLine, errorLine, errorMessage) @@ -1385,6 +1395,12 @@ WebInspector.reset = function() this.console.clearMessages(); } +WebInspector.resetProfilesPanel = function() +{ + if (WebInspector.panels.profiles) + WebInspector.panels.profiles.resetProfiles(); +} + WebInspector.bringToFront = function() { InspectorFrontendHost.bringToFront(); diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index bb19dbd..1312e5b 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -328,6 +328,63 @@ Element.prototype.offsetRelativeToWindow = function(targetWindow) return elementOffset; } +KeyboardEvent.prototype.__defineGetter__("data", function() +{ + // Emulate "data" attribute from DOM 3 TextInput event. + // See http://www.w3.org/TR/DOM-Level-3-Events/#events-Events-TextEvent-data + switch (this.type) { + case "keypress": + if (!this.ctrlKey && !this.metaKey) + return String.fromCharCode(this.charCode); + else + return ""; + case "keydown": + case "keyup": + if (!this.ctrlKey && !this.metaKey && !this.altKey) + return String.fromCharCode(this.which); + else + return ""; + } +}); + +Text.prototype.select = function(start, end) +{ + start = start || 0; + end = end || this.textContent.length; + + if (start < 0) + start = end + start; + + var selection = window.getSelection(); + selection.removeAllRanges(); + var range = document.createRange(); + range.setStart(this, start); + range.setEnd(this, end); + selection.addRange(range); + return this; +} + +Element.prototype.__defineGetter__("selectionLeftOffset", function() { + // Calculate selection offset relative to the current element. + + var selection = window.getSelection(); + if (!selection.containsNode(this, true)) + return null; + + var leftOffset = selection.anchorOffset; + var node = selection.anchorNode; + + while (node !== this) { + while (node.previousSibling) { + node = node.previousSibling; + leftOffset += node.textContent.length; + } + node = node.parentNode; + } + + return leftOffset; +}); + Node.prototype.isWhitespace = isNodeWhitespace; Node.prototype.displayName = nodeDisplayName; Node.prototype.isAncestor = function(node) @@ -672,6 +729,12 @@ Array.prototype.keySet = function() return keys; } +Array.convert = function(list) +{ + // Cast array-like object to an array. + return Array.prototype.slice.call(list); +} + function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction) { // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound. |