Changeset 187496 in webkit
- Timestamp:
- Jul 28, 2015 11:47:14 AM (9 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r187489 r187496 1 2015-07-28 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Show Pseudo Elements in DOM Tree 4 https://bugs.webkit.org/show_bug.cgi?id=139612 5 6 Reviewed by Timothy Hatcher. 7 8 * inspector/css/pseudo-element-matches-for-pseudo-element-node-expected.txt: Added. 9 * inspector/css/pseudo-element-matches-for-pseudo-element-node.html: Added. 10 * inspector/dom/pseudo-element-dynamic-expected.txt: Added. 11 * inspector/dom/pseudo-element-dynamic.html: Added. 12 * inspector/dom/pseudo-element-static-expected.txt: Added. 13 * inspector/dom/pseudo-element-static.html: Added. 14 1 15 2015-07-28 Chris Dumez <cdumez@apple.com> 2 16 -
trunk/Source/JavaScriptCore/ChangeLog
r187488 r187496 1 2015-07-28 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Show Pseudo Elements in DOM Tree 4 https://bugs.webkit.org/show_bug.cgi?id=139612 5 6 Reviewed by Timothy Hatcher. 7 8 * inspector/protocol/DOM.json: 9 Add new properties to DOMNode if it is a pseudo element or if it has 10 pseudo element children. Add new events for if a pseudo element is 11 added or removed dynamically to an existing DOMNode. 12 1 13 2015-07-27 Filip Pizlo <fpizlo@apple.com> 2 14 -
trunk/Source/JavaScriptCore/inspector/protocol/DOM.json
r185784 r187496 13 13 "type": "integer", 14 14 "description": "Unique DOM node identifier used to reference a node that may not have been pushed to the front-end." 15 }, 16 { 17 "id": "PseudoType", 18 "type": "string", 19 "enum": ["before", "after"], 20 "description": "Pseudo element type." 15 21 }, 16 22 { … … 40 46 { "name": "name", "type": "string", "optional": true, "description": "<code>Attr</code>'s name." }, 41 47 { "name": "value", "type": "string", "optional": true, "description": "<code>Attr</code>'s value." }, 48 { "name": "pseudoType", "$ref": "PseudoType", "optional": true, "description": "Pseudo element type for this node." }, 42 49 { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Frame ID for frame owner elements." }, 43 50 { "name": "contentDocument", "$ref": "Node", "optional": true, "description": "Content document for frame owner elements." }, 44 51 { "name": "shadowRoots", "type": "array", "optional": true, "items": { "$ref": "Node" }, "description": "Shadow root list for given element host." }, 45 52 { "name": "templateContent", "$ref": "Node", "optional": true, "description": "Content document fragment for template elements" }, 53 { "name": "pseudoElements", "type": "array", "items": { "$ref": "Node" }, "optional": true, "description": "Pseudo elements associated with this node." }, 46 54 { "name": "role", "type": "string", "optional": true, "description": "Computed value for first recognized role token, default role per element, or overridden role." } 47 55 ], … … 527 535 ], 528 536 "description": "Called when shadow root is popped from the element." 537 }, 538 { 539 "name": "pseudoElementAdded", 540 "parameters": [ 541 { "name": "parentId", "$ref": "NodeId", "description": "Pseudo element's parent element id." }, 542 { "name": "pseudoElement", "$ref": "Node", "description": "The added pseudo element." } 543 ], 544 "description": "Called when a pseudo element is added to an element." 545 }, 546 { 547 "name": "pseudoElementRemoved", 548 "parameters": [ 549 { "name": "parentId", "$ref": "NodeId", "description": "Pseudo element's parent element id." }, 550 { "name": "pseudoElementId", "$ref": "NodeId", "description": "The removed pseudo element id." } 551 ], 552 "description": "Called when a pseudo element is removed from an element." 529 553 } 530 554 ] -
trunk/Source/WebCore/ChangeLog
r187494 r187496 1 2015-07-28 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Show Pseudo Elements in DOM Tree 4 https://bugs.webkit.org/show_bug.cgi?id=139612 5 6 Reviewed by Timothy Hatcher. 7 8 Tests: inspector/css/pseudo-element-matches-for-pseudo-element-node.html 9 inspector/dom/pseudo-element-dynamic.html 10 inspector/dom/pseudo-element-static.html 11 12 Much of this patch was modelled after the Blink implementation of 13 pseudo element inspection. 14 15 * dom/PseudoElement.h: 16 * dom/PseudoElement.cpp: 17 (WebCore::PseudoElement::~PseudoElement): 18 (WebCore::PseudoElement::clearHostElement): 19 Since InspectorDOMAgent may hold a reference to this PseudoElement we 20 can't report it as destroyed in the destructor, as that wouldn't be 21 reached if the inspector holds a reference. Move this to when the 22 psuedo element is disconnected, which is immediately before destruction. 23 24 * inspector/InspectorCSSAgent.h: 25 * inspector/InspectorCSSAgent.cpp: 26 (WebCore::InspectorCSSAgent::getMatchedStylesForNode): 27 When computing styles for a pseudo element, compute styles from the 28 host element for just the pseudo element's pseudo type. Likewise 29 only include matched results, not inherited or others. 30 31 (WebCore::InspectorCSSAgent::buildArrayForMatchedRuleList): 32 Add the pseudo type to the checker context to try and detect exactly 33 which selector in a list of selectors matched the pseudo element. 34 35 * inspector/InspectorDOMAgent.h: 36 * inspector/InspectorDOMAgent.cpp: 37 (WebCore::InspectorDOMAgent::unbind): 38 When unbinding an element, also unbind any pseudo element children 39 it may have had and bound. 40 41 (WebCore::InspectorDOMAgent::assertEditableNode): 42 (WebCore::InspectorDOMAgent::assertEditableElement): 43 (WebCore::InspectorDOMAgent::removeNode): 44 Improve grammar in error message. Don't allow editing pseudo elements. 45 46 (WebCore::pseudoElementType): 47 (WebCore::InspectorDOMAgent::buildObjectForNode): 48 (WebCore::InspectorDOMAgent::buildArrayForPseudoElements): 49 If a node is a pseudo element include its pseudoType. 50 If a node has pseudo element children include them. 51 52 (WebCore::InspectorDOMAgent::pseudoElementCreated): 53 (WebCore::InspectorDOMAgent::pseudoElementDestroyed): 54 When pseudo elements are dynamically created or destroyed 55 push pseudo element nodes to the frontend if needed. 56 57 * inspector/InspectorInstrumentation.cpp: 58 (WebCore::InspectorInstrumentation::pseudoElementCreatedImpl): 59 (WebCore::InspectorInstrumentation::pseudoElementDestroyedImpl): 60 * inspector/InspectorInstrumentation.h: 61 (WebCore::InspectorInstrumentation::pseudoElementCreated): 62 (WebCore::InspectorInstrumentation::pseudoElementDestroyed): 63 (WebCore::InspectorInstrumentation::layerTreeDidChange): 64 (WebCore::InspectorInstrumentation::renderLayerDestroyed): 65 Plumbing for pseudo element created/destroyed events. 66 67 * style/StyleResolveTree.cpp: 68 (WebCore::Style::attachBeforeOrAfterPseudoElementIfNeeded): 69 This is the only place a pseudo element is created, inform the inspector. 70 71 * inspector/InspectorOverlay.cpp: 72 (WebCore::buildObjectForElementData): 73 Update the element data for the node highlight label to include the 74 host element's selector and the pseudo element selector. 75 1 76 2015-07-28 Tim Horton <timothy_horton@apple.com> 2 77 -
trunk/Source/WebCore/dom/PseudoElement.cpp
r177925 r187496 68 68 { 69 69 ASSERT(!m_hostElement); 70 } 71 72 void PseudoElement::clearHostElement() 73 { 70 74 InspectorInstrumentation::pseudoElementDestroyed(document().page(), *this); 75 76 m_hostElement = nullptr; 71 77 } 72 78 -
trunk/Source/WebCore/dom/PseudoElement.h
r177751 r187496 44 44 45 45 Element* hostElement() const { return m_hostElement; } 46 void clearHostElement() { m_hostElement = nullptr; }46 void clearHostElement(); 47 47 48 48 virtual RefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override; -
trunk/Source/WebCore/inspector/InspectorCSSAgent.cpp
r187249 r187496 46 46 #include "Node.h" 47 47 #include "NodeList.h" 48 #include "PseudoElement.h" 48 49 #include "RenderNamedFlowFragment.h" 49 50 #include "SVGStyleElement.h" … … 511 512 return; 512 513 514 Element* originalElement = element; 515 PseudoId elementPseudoId = element->pseudoId(); 516 if (elementPseudoId) { 517 element = downcast<PseudoElement>(*element).hostElement(); 518 if (!element) { 519 errorString = ASCIILiteral("Pseudo element has no parent"); 520 return; 521 } 522 } 523 513 524 // Matched rules. 514 525 StyleResolver& styleResolver = element->document().ensureStyleResolver(); 515 auto matchedRules = styleResolver.styleRulesForElement(element, StyleResolver::AllCSSRules); 516 matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element); 517 518 // Pseudo elements. 519 if (!includePseudo || *includePseudo) { 520 auto pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>::create(); 521 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) { 522 auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules); 523 if (!matchedRules.isEmpty()) { 524 auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create() 525 .setPseudoId(static_cast<int>(pseudoId)) 526 .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element)) 526 auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules); 527 matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element, elementPseudoId); 528 529 if (!originalElement->isPseudoElement()) { 530 // Pseudo elements. 531 if (!includePseudo || *includePseudo) { 532 auto pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>::create(); 533 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) { 534 auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules); 535 if (!matchedRules.isEmpty()) { 536 auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create() 537 .setPseudoId(static_cast<int>(pseudoId)) 538 .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element, pseudoId)) 539 .release(); 540 pseudoElements->addItem(WTF::move(matches)); 541 } 542 } 543 544 pseudoIdMatches = WTF::move(pseudoElements); 545 } 546 547 // Inherited styles. 548 if (!includeInherited || *includeInherited) { 549 auto entries = Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>::create(); 550 Element* parentElement = element->parentElement(); 551 while (parentElement) { 552 StyleResolver& parentStyleResolver = parentElement->document().ensureStyleResolver(); 553 auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules); 554 auto entry = Inspector::Protocol::CSS::InheritedStyleEntry::create() 555 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement, NOPSEUDO)) 527 556 .release(); 528 pseudoElements->addItem(WTF::move(matches)); 557 if (parentElement->style() && parentElement->style()->length()) { 558 if (InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement)) 559 entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0)))); 560 } 561 562 entries->addItem(WTF::move(entry)); 563 parentElement = parentElement->parentElement(); 529 564 } 565 566 inheritedEntries = WTF::move(entries); 530 567 } 531 532 pseudoIdMatches = WTF::move(pseudoElements);533 }534 535 // Inherited styles.536 if (!includeInherited || *includeInherited) {537 auto entries = Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>::create();538 Element* parentElement = element->parentElement();539 while (parentElement) {540 StyleResolver& parentStyleResolver = parentElement->document().ensureStyleResolver();541 auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);542 auto entry = Inspector::Protocol::CSS::InheritedStyleEntry::create()543 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement))544 .release();545 if (parentElement->style() && parentElement->style()->length()) {546 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);547 if (styleSheet)548 entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));549 }550 551 entries->addItem(WTF::move(entry));552 parentElement = parentElement->parentElement();553 }554 555 inheritedEntries = WTF::move(entries);556 568 } 557 569 } … … 925 937 } 926 938 927 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element* element )939 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element* element, PseudoId psuedoId) 928 940 { 929 941 auto result = Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>::create(); 930 942 931 943 SelectorChecker::CheckingContext context(SelectorChecker::Mode::CollectingRules); 944 context.pseudoId = psuedoId ? psuedoId : element->pseudoId(); 932 945 SelectorChecker selectorChecker(element->document()); 933 946 -
trunk/Source/WebCore/inspector/InspectorCSSAgent.h
r187249 r187496 150 150 RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(StyleRule*, StyleResolver&, Element*); 151 151 RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(CSSStyleRule*); 152 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>&, StyleResolver&, Element* );152 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>&, StyleResolver&, Element*, PseudoId); 153 153 RefPtr<Inspector::Protocol::CSS::CSSStyle> buildObjectForAttributesStyle(Element*); 154 154 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> buildArrayForRegions(ErrorString&, RefPtr<NodeList>&&, int documentNodeId); -
trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp
r186279 r187496 76 76 #include "Page.h" 77 77 #include "Pasteboard.h" 78 #include "PseudoElement.h" 78 79 #include "RenderStyle.h" 79 80 #include "RenderStyleConstants.h" … … 333 334 334 335 if (is<Element>(*node)) { 335 if (ShadowRoot* root = downcast<Element>(*node).shadowRoot()) 336 Element& element = downcast<Element>(*node); 337 if (ShadowRoot* root = element.shadowRoot()) 336 338 unbind(root, nodesMap); 339 if (PseudoElement* beforeElement = element.beforePseudoElement()) 340 unbind(beforeElement, nodesMap); 341 if (PseudoElement* afterElement = element.afterPseudoElement()) 342 unbind(afterElement, nodesMap); 337 343 } 338 344 … … 393 399 return nullptr; 394 400 if (node->isInShadowTree()) { 395 errorString = ASCIILiteral("Can not edit nodes from shadow trees"); 401 errorString = ASCIILiteral("Cannot edit nodes from shadow trees"); 402 return nullptr; 403 } 404 if (node->isPseudoElement()) { 405 errorString = ASCIILiteral("Cannot edit pseudo elements"); 396 406 return nullptr; 397 407 } … … 405 415 return nullptr; 406 416 if (element->isInShadowTree()) { 407 errorString = ASCIILiteral("Can not edit elements from shadow trees"); 417 errorString = ASCIILiteral("Cannot edit elements from shadow trees"); 418 return nullptr; 419 } 420 if (element->isPseudoElement()) { 421 errorString = ASCIILiteral("Cannot edit pseudo elements"); 408 422 return nullptr; 409 423 } … … 699 713 ContainerNode* parentNode = node->parentNode(); 700 714 if (!parentNode) { 701 errorString = ASCIILiteral("Can 715 errorString = ASCIILiteral("Cannot remove detached node"); 702 716 return; 703 717 } … … 1255 1269 } 1256 1270 1271 static bool pseudoElementType(PseudoId pseudoId, Inspector::Protocol::DOM::PseudoType* type) 1272 { 1273 switch (pseudoId) { 1274 case BEFORE: 1275 *type = Inspector::Protocol::DOM::PseudoType::Before; 1276 return true; 1277 case AFTER: 1278 *type = Inspector::Protocol::DOM::PseudoType::After; 1279 return true; 1280 default: 1281 return false; 1282 } 1283 } 1284 1257 1285 Ref<Inspector::Protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap) 1258 1286 { … … 1328 1356 #endif 1329 1357 1358 if (element.pseudoId()) { 1359 Inspector::Protocol::DOM::PseudoType pseudoType; 1360 if (pseudoElementType(element.pseudoId(), &pseudoType)) 1361 value->setPseudoType(pseudoType); 1362 } else { 1363 if (auto pseudoElements = buildArrayForPseudoElements(element, nodesMap)) 1364 value->setPseudoElements(WTF::move(pseudoElements)); 1365 } 1366 1330 1367 } else if (is<Document>(*node)) { 1331 1368 Document& document = downcast<Document>(*node); … … 1393 1430 } 1394 1431 return WTF::move(children); 1432 } 1433 1434 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> InspectorDOMAgent::buildArrayForPseudoElements(const Element& element, NodeToIdMap* nodesMap) 1435 { 1436 PseudoElement* beforeElement = element.beforePseudoElement(); 1437 PseudoElement* afterElement = element.afterPseudoElement(); 1438 if (!beforeElement && !afterElement) 1439 return nullptr; 1440 1441 auto pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>::create(); 1442 if (beforeElement) 1443 pseudoElements->addItem(buildObjectForNode(beforeElement, 0, nodesMap)); 1444 if (afterElement) 1445 pseudoElements->addItem(buildObjectForNode(afterElement, 0, nodesMap)); 1446 return WTF::move(pseudoElements); 1395 1447 } 1396 1448 … … 1958 2010 } 1959 2011 2012 void InspectorDOMAgent::pseudoElementCreated(PseudoElement& pseudoElement) 2013 { 2014 Element* parent = pseudoElement.hostElement(); 2015 if (!parent) 2016 return; 2017 2018 int parentId = m_documentNodeToIdMap.get(parent); 2019 if (!parentId) 2020 return; 2021 2022 pushChildNodesToFrontend(parentId, 1); 2023 m_frontendDispatcher->pseudoElementAdded(parentId, buildObjectForNode(&pseudoElement, 0, &m_documentNodeToIdMap)); 2024 } 2025 2026 void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement& pseudoElement) 2027 { 2028 int pseudoElementId = m_documentNodeToIdMap.get(&pseudoElement); 2029 if (!pseudoElementId) 2030 return; 2031 2032 // If a PseudoElement is bound, its parent element must have been bound. 2033 Element* parent = pseudoElement.hostElement(); 2034 ASSERT(parent); 2035 int parentId = m_documentNodeToIdMap.get(parent); 2036 ASSERT(parentId); 2037 2038 unbind(&pseudoElement, &m_documentNodeToIdMap); 2039 m_frontendDispatcher->pseudoElementRemoved(parentId, pseudoElementId); 2040 } 2041 1960 2042 Node* InspectorDOMAgent::nodeForPath(const String& path) 1961 2043 { -
trunk/Source/WebCore/inspector/InspectorDOMAgent.h
r185784 r187496 170 170 void didCommitLoad(Document*); 171 171 void frameDocumentUpdated(Frame*); 172 void pseudoElementCreated(PseudoElement&); 173 void pseudoElementDestroyed(PseudoElement&); 172 174 173 175 // Callbacks that don't directly correspond to an instrumentation entry point. … … 234 236 Ref<Inspector::Protocol::Array<String>> buildArrayForElementAttributes(Element*); 235 237 Ref<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap); 238 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&, NodeToIdMap* nodesMap); 236 239 Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*, const String* objectGroupId); 237 240 RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node*); -
trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp
r186133 r187496 209 209 } 210 210 211 void InspectorInstrumentation::pseudoElementCreatedImpl(InstrumentingAgents& instrumentingAgents, PseudoElement& pseudoElement) 212 { 213 if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent()) 214 domAgent->pseudoElementCreated(pseudoElement); 215 } 216 217 void InspectorInstrumentation::pseudoElementDestroyedImpl(InstrumentingAgents& instrumentingAgents, PseudoElement& pseudoElement) 218 { 219 if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent()) 220 domAgent->pseudoElementDestroyed(pseudoElement); 221 if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents.inspectorLayerTreeAgent()) 222 layerTreeAgent->pseudoElementDestroyed(pseudoElement); 223 } 224 211 225 void InspectorInstrumentation::didCreateNamedFlowImpl(InstrumentingAgents& instrumentingAgents, Document* document, WebKitNamedFlow& namedFlow) 212 226 { … … 1275 1289 } 1276 1290 1277 void InspectorInstrumentation::pseudoElementDestroyedImpl(InstrumentingAgents& instrumentingAgents, PseudoElement& pseudoElement)1278 {1279 if (InspectorLayerTreeAgent* layerTreeAgent = instrumentingAgents.inspectorLayerTreeAgent())1280 layerTreeAgent->pseudoElementDestroyed(pseudoElement);1281 }1282 1283 1291 } // namespace WebCore -
trunk/Source/WebCore/inspector/InspectorInstrumentation.h
r186133 r187496 76 76 class Database; 77 77 class Document; 78 class Element;79 78 class DocumentLoader; 80 79 class DocumentStyleSheetCollection; 80 class Element; 81 81 class GraphicsContext; 82 82 class HTTPHeaderMap; … … 86 86 class InspectorTimelineAgent; 87 87 class InstrumentingAgents; 88 class URL;89 88 class Node; 90 89 class PseudoElement; … … 101 100 class StyleRule; 102 101 class ThreadableLoaderClient; 102 class URL; 103 103 class WorkerGlobalScope; 104 104 class WorkerGlobalScopeProxy; … … 127 127 static void didPushShadowRoot(Element& host, ShadowRoot&); 128 128 static void willPopShadowRoot(Element& host, ShadowRoot&); 129 static void pseudoElementCreated(Page*, PseudoElement&); 130 static void pseudoElementDestroyed(Page*, PseudoElement&); 129 131 static void didCreateNamedFlow(Document*, WebKitNamedFlow&); 130 132 static void willRemoveNamedFlow(Document*, WebKitNamedFlow&); … … 276 278 static void layerTreeDidChange(Page*); 277 279 static void renderLayerDestroyed(Page*, const RenderLayer&); 278 static void pseudoElementDestroyed(Page*, PseudoElement&);279 280 280 281 static void frontendCreated() { s_frontendCounter += 1; } … … 307 308 static void didPushShadowRootImpl(InstrumentingAgents&, Element& host, ShadowRoot&); 308 309 static void willPopShadowRootImpl(InstrumentingAgents&, Element& host, ShadowRoot&); 310 static void pseudoElementCreatedImpl(InstrumentingAgents&, PseudoElement&); 311 static void pseudoElementDestroyedImpl(InstrumentingAgents&, PseudoElement&); 309 312 static void didCreateNamedFlowImpl(InstrumentingAgents&, Document*, WebKitNamedFlow&); 310 313 static void willRemoveNamedFlowImpl(InstrumentingAgents&, Document*, WebKitNamedFlow&); … … 450 453 static void layerTreeDidChangeImpl(InstrumentingAgents&); 451 454 static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&); 452 static void pseudoElementDestroyedImpl(InstrumentingAgents&, PseudoElement&);453 455 454 456 static InstrumentingAgents* instrumentingAgentsForPage(Page&); … … 568 570 } 569 571 572 inline void InspectorInstrumentation::pseudoElementCreated(Page* page, PseudoElement& pseudoElement) 573 { 574 FAST_RETURN_IF_NO_FRONTENDS(void()); 575 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page)) 576 pseudoElementCreatedImpl(*instrumentingAgents, pseudoElement); 577 } 578 579 inline void InspectorInstrumentation::pseudoElementDestroyed(Page* page, PseudoElement& pseudoElement) 580 { 581 FAST_RETURN_IF_NO_FRONTENDS(void()); 582 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page)) 583 pseudoElementDestroyedImpl(*instrumentingAgents, pseudoElement); 584 } 585 570 586 inline void InspectorInstrumentation::didCreateNamedFlow(Document* document, WebKitNamedFlow& namedFlow) 571 587 { … … 1309 1325 inline void InspectorInstrumentation::layerTreeDidChange(Page* page) 1310 1326 { 1327 FAST_RETURN_IF_NO_FRONTENDS(void()); 1311 1328 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page)) 1312 1329 layerTreeDidChangeImpl(*instrumentingAgents); … … 1315 1332 inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const RenderLayer& renderLayer) 1316 1333 { 1334 FAST_RETURN_IF_NO_FRONTENDS(void()); 1317 1335 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page)) 1318 1336 renderLayerDestroyedImpl(*instrumentingAgents, renderLayer); 1319 }1320 1321 inline void InspectorInstrumentation::pseudoElementDestroyed(Page* page, PseudoElement& pseudoElement)1322 {1323 if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForPage(page))1324 pseudoElementDestroyedImpl(*instrumentingAgents, pseudoElement);1325 1337 } 1326 1338 -
trunk/Source/WebCore/inspector/InspectorOverlay.cpp
r187492 r187496 42 42 #include "PageConfiguration.h" 43 43 #include "PolygonShape.h" 44 #include "PseudoElement.h" 44 45 #include "RectangleShape.h" 45 46 #include "RenderBoxModelObject.h" … … 687 688 return nullptr; 688 689 689 Element& element = downcast<Element>(*node); 690 Element* effectiveElement = downcast<Element>(node); 691 if (node->isPseudoElement()) { 692 Element* hostElement = downcast<PseudoElement>(*node).hostElement(); 693 if (!hostElement) 694 return nullptr; 695 effectiveElement = hostElement; 696 } 697 698 Element& element = *effectiveElement; 690 699 bool isXHTML = element.document().isXHTMLDocument(); 691 692 700 auto elementData = Inspector::Protocol::OverlayTypes::ElementData::create() 693 701 .setTagName(isXHTML ? element.nodeName() : element.nodeName().lower()) … … 695 703 .release(); 696 704 697 HashSet<AtomicString> usedClassNames;705 StringBuilder classNames; 698 706 if (element.hasClass() && is<StyledElement>(element)) { 699 StringBuilder classNames;707 HashSet<AtomicString> usedClassNames; 700 708 const SpaceSplitString& classNamesString = downcast<StyledElement>(element).classNames(); 701 709 size_t classNameCount = classNamesString.size(); … … 708 716 classNames.append(className); 709 717 } 718 } 719 if (node->isPseudoElement()) { 720 if (node->pseudoId() == BEFORE) 721 classNames.appendLiteral("::before"); 722 else if (node->pseudoId() == AFTER) 723 classNames.appendLiteral("::after"); 724 } 725 if (!classNames.isEmpty()) 710 726 elementData->setClassName(classNames.toString()); 711 }712 727 713 728 RenderElement* renderer = element.renderer(); -
trunk/Source/WebCore/style/StyleResolveTree.cpp
r184990 r187496 34 34 #include "FlowThreadController.h" 35 35 #include "InsertionPoint.h" 36 #include "InspectorInstrumentation.h" 36 37 #include "LoaderStrategy.h" 37 38 #include "MainFrame.h" … … 465 466 return; 466 467 Ref<PseudoElement> pseudoElement = PseudoElement::create(current, pseudoId); 468 InspectorInstrumentation::pseudoElementCreated(pseudoElement->document().page(), pseudoElement.get()); 467 469 setBeforeOrAfterPseudoElement(current, pseudoElement.copyRef(), pseudoId); 468 470 attachRenderTree(pseudoElement.get(), *current.renderStyle(), renderTreePosition, nullptr); -
trunk/Source/WebInspectorUI/ChangeLog
r187480 r187496 1 2015-07-28 Joseph Pecoraro <pecoraro@apple.com> 2 3 Web Inspector: Show Pseudo Elements in DOM Tree 4 https://bugs.webkit.org/show_bug.cgi?id=139612 5 6 Reviewed by Timothy Hatcher. 7 8 * UserInterface/Controllers/DOMTreeManager.js: 9 (WebInspector.DOMTreeManager.prototype._pseudoElementAdded): 10 Hook up the new pseudo element DOMNode to the parent. 11 12 (WebInspector.DOMTreeManager.prototype._pseudoElementRemoved): 13 Unhook the pseudo element from its parent. 14 15 (WebInspector.DOMTreeManager.prototype._unbind): 16 When unbinding, unbind any pseudo element children we may have had. 17 18 * UserInterface/Models/DOMNode.js: 19 (WebInspector.DOMNode.prototype.isPseudoElement): 20 (WebInspector.DOMNode.prototype.pseudoType): 21 (WebInspector.DOMNode.prototype.hasPseudoElements): 22 (WebInspector.DOMNode.prototype.pseudoElements): 23 New state of a DOMNode may include pseudo elements. 24 25 (WebInspector.DOMNode.prototype.appropriateSelectorFor): 26 A selector for this node includes the selector for the node above it. 27 28 * UserInterface/Protocol/DOMObserver.js: 29 (WebInspector.DOMObserver.prototype.pseudoElementAdded): 30 (WebInspector.DOMObserver.prototype.pseudoElementRemoved): 31 Pass the message on to DOMTreeManager. 32 33 * UserInterface/Views/DOMTreeElement.js: 34 (WebInspector.DOMTreeElement.prototype.get editable): 35 Pseudo element nodes are not editable. 36 37 (WebInspector.DOMTreeElement.prototype.showChildNode): 38 (WebInspector.DOMTreeElement.prototype.onpopulate): 39 (WebInspector.DOMTreeElement.prototype.updateChildren): 40 (WebInspector.DOMTreeElement.prototype._nodeTitleInfo): 41 (WebInspector.DOMTreeElement.prototype._singleTextChild): 42 (WebInspector.DOMTreeElement.prototype._hasVisibleChildren): 43 (WebInspector.DOMTreeElement.prototype._visibleChildren): 44 (WebInspector.DOMTreeElement.prototype._updateChildren): 45 (WebInspector.DOMTreeElement.prototype.adjustCollapsedRange): 46 (WebInspector.DOMTreeElement.prototype.handleLoadAllChildren): 47 A DOMTreeElement's children are no longer 1-to-1 to DOMNode's children. 48 Instead a DOMNode may have a before/after pseudo element child that 49 are not included in the children list. Update parts of DOMTreeElement 50 to respect this list of visible children. 51 52 * UserInterface/Views/DOMTreeElementPathComponent.js: 53 (WebInspector.DOMTreeElementPathComponent): 54 * UserInterface/Views/PathComponentIcons.css: 55 (.dom-pseudo-element-icon .icon): 56 Styling for the path component when a pseudo element is selected. 57 58 * UserInterface/Views/DOMTreeOutline.css: 59 (.dom-tree-outline .html-pseudo-element): 60 (.dom-tree-outline .html-fragment.shadow): 61 (.webkit-html-fragment.shadow): Deleted. 62 Styles for pseudo elements in the DOM tree. 63 64 * UserInterface/Views/DOMTreeOutline.js: 65 (WebInspector.DOMTreeOutline.prototype._hideElement): 66 Make the hide element selector hide the host element. 67 68 * UserInterface/Views/CSSStyleDetailsSidebarPanel.js: 69 (WebInspector.CSSStyleDetailsSidebarPanel.prototype.addEventListeners): 70 (WebInspector.CSSStyleDetailsSidebarPanel.prototype.removeEventListeners): 71 (WebInspector.CSSStyleDetailsSidebarPanel.prototype._forcedPseudoClassCheckboxChanged): 72 (WebInspector.CSSStyleDetailsSidebarPanel.prototype._updatePseudoClassCheckboxes): 73 Pseudo class changes won't happen on pseudo elements, but will 74 happen on their host element, so listen to and make pseudo class 75 changes to the host element. 76 77 * UserInterface/Views/RulesStyleDetailsPanel.css: 78 (.sidebar > .panel.details.css-style .rules > *:first-child:matches(.new-rule)): 79 Since a pseudo element does not have a style attribute, 80 give some margin in the style sidebar above the "New Rule" 81 button so it looks better. 82 1 83 2015-07-27 Matt Baker <mattbaker@apple.com> 2 84 -
trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js
r187450 r187496 247 247 parent._removeChild(node); 248 248 this._unbind(node); 249 this.dispatchEventToListeners(WebInspector.DOMTreeManager.Event.NodeRemoved, {node:node, parent}); 249 this.dispatchEventToListeners(WebInspector.DOMTreeManager.Event.NodeRemoved, {node, parent}); 250 } 251 252 _pseudoElementAdded(parentId, pseudoElement) 253 { 254 var parent = this._idToDOMNode[parentId]; 255 if (!parent) 256 return; 257 258 var node = new WebInspector.DOMNode(this, parent.ownerDocument, false, pseudoElement); 259 node.parentNode = parent; 260 this._idToDOMNode[node.id] = node; 261 console.assert(!parent.pseudoElements().get(node.pseudoType())); 262 parent.pseudoElements().set(node.pseudoType(), node); 263 this.dispatchEventToListeners(WebInspector.DOMTreeManager.Event.NodeInserted, {node, parent}); 264 } 265 266 _pseudoElementRemoved(parentId, pseudoElementId) 267 { 268 var pseudoElement = this._idToDOMNode[pseudoElementId]; 269 if (!pseudoElement) 270 return; 271 272 var parent = pseudoElement.parentNode; 273 console.assert(parent); 274 console.assert(parent.id === parentId); 275 if (!parent) 276 return; 277 278 parent._removeChild(pseudoElement); 279 this._unbind(pseudoElement); 280 this.dispatchEventToListeners(WebInspector.DOMTreeManager.Event.NodeRemoved, {node: pseudoElement, parent}); 250 281 } 251 282 … … 255 286 256 287 delete this._idToDOMNode[node.id]; 288 257 289 for (var i = 0; node.children && i < node.children.length; ++i) 258 290 this._unbind(node.children[i]); 291 292 var pseudoElements = node.pseudoElements(); 293 for (var pseudoElement of pseudoElements) 294 this._unbind(pseudoElement); 295 296 // FIXME: Handle shadow roots. 297 // FIXME: Handle template content. 259 298 } 260 299 -
trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js
r185784 r187496 47 47 this._localName = payload.localName; 48 48 this._nodeValue = payload.nodeValue; 49 this._pseudoType = payload.pseudoType; 49 50 this._computedRole = payload.role; 50 51 … … 79 80 } 80 81 82 // FIXME: Handle templateContent. 83 81 84 if (payload.children) 82 85 this._setChildrenPayload(payload.children); 86 87 this._pseudoElements = new Map; 88 if (payload.pseudoElements) { 89 for (var i = 0; i < payload.pseudoElements.length; ++i) { 90 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload.pseudoElements[i]); 91 node.parentNode = this; 92 this._pseudoElements.set(node.pseudoType(), node); 93 } 94 } 83 95 84 96 if (payload.contentDocument) { … … 222 234 } 223 235 236 isPseudoElement() 237 { 238 return this._pseudoType !== undefined; 239 } 240 224 241 nodeType() 225 242 { … … 245 262 { 246 263 return this._localName; 264 } 265 266 pseudoType() 267 { 268 return this._pseudoType; 269 } 270 271 hasPseudoElements() 272 { 273 return this._pseudoElements.size > 0; 274 } 275 276 pseudoElements() 277 { 278 return this._pseudoElements; 279 } 280 281 beforePseudoElement() 282 { 283 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementType.Before) || null; 284 } 285 286 afterPseudoElement() 287 { 288 return this._pseudoElements.get(WebInspector.DOMNode.PseudoElementType.After) || null; 247 289 } 248 290 … … 408 450 appropriateSelectorFor(justSelector) 409 451 { 452 if (this.isPseudoElement()) 453 return this.parentNode.appropriateSelectorFor() + "::" + this._pseudoType; 454 410 455 var lowerCaseName = this.localName() || this.nodeName().toLowerCase(); 411 456 … … 476 521 _removeChild(node) 477 522 { 478 this._children.splice(this._children.indexOf(node), 1); 523 // FIXME: Handle removal if this is a shadow root. 524 if (node.isPseudoElement()) 525 this._pseudoElements.delete(node.pseudoType()); 526 else 527 this._children.splice(this._children.indexOf(node), 1); 528 479 529 node.parentNode = null; 480 530 this._renumber(); … … 489 539 this._children = this._shadowRoots.slice(); 490 540 for (var i = 0; i < payloads.length; ++i) { 491 var payload = payloads[i]; 492 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload); 541 var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payloads[i]); 493 542 this._children.push(node); 494 543 } … … 598 647 AttributeRemoved: "dom-node-attribute-removed" 599 648 }; 649 650 WebInspector.DOMNode.PseudoElementType = { 651 Before: "before", 652 After: "after", 653 }; -
trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js
r182039 r187496 82 82 WebInspector.domTreeManager._childNodeRemoved(parentNodeId, nodeId); 83 83 } 84 85 pseudoElementAdded(parentNodeId, pseudoElement) 86 { 87 WebInspector.domTreeManager._pseudoElementAdded(parentNodeId, pseudoElement); 88 } 89 90 pseudoElementRemoved(parentNodeId, pseudoElementId) 91 { 92 WebInspector.domTreeManager._pseudoElementRemoved(parentNodeId, pseudoElementId); 93 } 84 94 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDetailsSidebarPanel.js
r187402 r187496 158 158 addEventListeners() 159 159 { 160 this.domNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this); 160 var effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode; 161 if (!effectiveDOMNode) 162 return; 163 164 effectiveDOMNode.addEventListener(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged, this._updatePseudoClassCheckboxes, this); 161 165 } 162 166 163 167 removeEventListeners() 164 168 { 165 this.domNode.removeEventListener(null, null, this); 169 var effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode; 170 if (!effectiveDOMNode) 171 return; 172 173 effectiveDOMNode.removeEventListener(null, null, this); 166 174 } 167 175 … … 236 244 return; 237 245 238 this.domNode.setPseudoClassEnabled(pseudoClass, event.target.checked); 246 var effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode; 247 248 effectiveDOMNode.setPseudoClassEnabled(pseudoClass, event.target.checked); 239 249 } 240 250 … … 244 254 return; 245 255 246 var enabledPseudoClasses = this.domNode.enabledPseudoClasses; 256 var effectiveDOMNode = this.domNode.isPseudoElement() ? this.domNode.parentNode : this.domNode; 257 258 var enabledPseudoClasses = effectiveDOMNode.enabledPseudoClasses; 247 259 248 260 for (var pseudoClass in this._forcedPseudoClassCheckboxes) { -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeElement.js
r187465 r187496 36 36 37 37 this._elementCloseTag = elementCloseTag; 38 this.hasChildren = !elementCloseTag && node.hasChildNodes() && !this._showInlineText(node);38 this.hasChildren = !elementCloseTag && this._hasVisibleChildren(); 39 39 40 40 if (this.representedObject.nodeType() === Node.ELEMENT_NODE && !elementCloseTag) … … 159 159 get editable() 160 160 { 161 if (this.representedObject.isInShadowTree()) 161 var node = this.representedObject; 162 if (node.isInShadowTree()) 163 return false; 164 if (node.isPseudoElement()) 162 165 return false; 163 166 … … 190 193 } 191 194 192 showChild (index)195 showChildNode(node) 193 196 { 194 197 console.assert(!this._elementCloseTag); 195 198 if (this._elementCloseTag) 196 return false; 199 return null; 200 201 var index = this._visibleChildren().indexOf(node); 202 if (index === -1) 203 return null; 197 204 198 205 if (index >= this.expandedChildrenLimit) { … … 201 208 } 202 209 203 // Whether index-th child is visible in the children tree 204 return this.expandedChildCount > index; 210 return this.children[index]; 205 211 } 206 212 … … 285 291 onpopulate() 286 292 { 287 if (this.children.length || this._showInlineText(this.representedObject) || this._elementCloseTag)293 if (this.children.length || !this._hasVisibleChildren() || this._elementCloseTag) 288 294 return; 289 295 … … 300 306 if (this._elementCloseTag) 301 307 return; 308 302 309 this.representedObject.getChildNodes(this._updateChildren.bind(this, fullRefresh)); 303 310 } … … 326 333 327 334 this._updateChildrenInProgress = true; 335 336 var node = this.representedObject; 328 337 var selectedNode = this.treeOutline.selectedDOMNode(); 329 338 var originalScrollTop = 0; 330 if (fullRefresh) { 339 340 var hasVisibleChildren = this._hasVisibleChildren(); 341 342 if (fullRefresh || !hasVisibleChildren) { 331 343 var treeOutlineContainerElement = this.treeOutline.element.parentNode; 332 344 originalScrollTop = treeOutlineContainerElement.scrollTop; … … 335 347 this.select(); 336 348 this.removeChildren(); 337 } 338 339 var treeElement = this; 340 var treeChildIndex = 0; 341 var elementToSelect; 342 343 function updateChildrenOfNode(node) 344 { 345 var treeOutline = treeElement.treeOutline; 346 var child = node.firstChild; 347 while (child) { 348 var currentTreeElement = treeElement.children[treeChildIndex]; 349 if (!currentTreeElement || currentTreeElement.representedObject !== child) { 350 // Find any existing element that is later in the children list. 351 var existingTreeElement = null; 352 for (var i = (treeChildIndex + 1), size = treeElement.expandedChildCount; i < size; ++i) { 353 if (treeElement.children[i].representedObject === child) { 354 existingTreeElement = treeElement.children[i]; 355 break; 356 } 357 } 358 359 if (existingTreeElement && existingTreeElement.parent === treeElement) { 360 // If an existing element was found and it has the same parent, just move it. 361 treeElement.moveChild(existingTreeElement, treeChildIndex); 362 } else { 363 // No existing element found, insert a new element. 364 if (treeChildIndex < treeElement.expandedChildrenLimit) { 365 var newElement = treeElement.insertChildElement(child, treeChildIndex); 366 if (child === selectedNode) 367 elementToSelect = newElement; 368 if (treeElement.expandedChildCount > treeElement.expandedChildrenLimit) 369 treeElement.expandedChildrenLimit++; 370 } 371 } 372 } 373 374 child = child.nextSibling; 375 ++treeChildIndex; 376 } 349 350 // No longer have children. 351 if (!hasVisibleChildren) { 352 this.hasChildren = false; 353 this.updateTitle(); 354 this._updateChildrenInProgress = false; 355 return; 356 } 357 } 358 359 // We now have children. 360 if (!this.hasChildren) { 361 this.hasChildren = true; 362 this.updateTitle(); 377 363 } 378 364 379 365 // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. 366 // Keep a list of existing tree elements for nodes that we can use later. 367 var existingChildTreeElements = new Map; 380 368 for (var i = (this.children.length - 1); i >= 0; --i) { 381 var currentChild = this.children[i];382 var currentNode = currentChild .representedObject;369 var currentChildTreeElement = this.children[i]; 370 var currentNode = currentChildTreeElement.representedObject; 383 371 var currentParentNode = currentNode.parentNode; 384 385 if (currentParentNode === this.representedObject)372 if (currentParentNode === node) { 373 existingChildTreeElements.set(currentNode, currentChildTreeElement); 386 374 continue; 375 } 387 376 388 377 var selectedTreeElement = this.treeOutline.selectedTreeElement; 389 if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild)))378 if (selectedTreeElement && (selectedTreeElement === currentChildTreeElement || selectedTreeElement.hasAncestor(currentChildTreeElement))) 390 379 this.select(); 391 380 … … 393 382 } 394 383 395 updateChildrenOfNode(this.representedObject); 384 // Move / create TreeElements for our visible children. 385 var childIndex = 0; 386 var elementToSelect = null; 387 var visibleChildren = this._visibleChildren(); 388 for (var i = 0; i < visibleChildren.length && i < this.expandedChildrenLimit; ++i) { 389 var childNode = visibleChildren[i]; 390 391 // Already have a tree element for this child, just move it. 392 var existingChildTreeElement = existingChildTreeElements.get(childNode); 393 if (existingChildTreeElement) { 394 this.moveChild(existingChildTreeElement, i); 395 continue; 396 } 397 398 // No existing tree element for this child. Insert a new element. 399 var newChildTreeElement = this.insertChildElement(childNode, i); 400 401 // Update state. 402 if (childNode === selectedNode) 403 elementToSelect = newChildTreeElement; 404 if (this.expandedChildCount > this.expandedChildrenLimit) 405 this.expandedChildrenLimit++; 406 } 407 408 // Update expand all children button. 396 409 this.adjustCollapsedRange(); 397 410 411 // Insert closing tag tree element. 398 412 var lastChild = this.children.lastValue; 399 if ( this.representedObject.nodeType() === Node.ELEMENT_NODE && (!lastChild || !lastChild._elementCloseTag))413 if (node.nodeType() === Node.ELEMENT_NODE && (!lastChild || !lastChild._elementCloseTag)) 400 414 this.insertChildElement(this.representedObject, this.children.length, true); 401 415 … … 418 432 419 433 var node = this.representedObject; 420 if (!node.children) 421 return; 422 var childNodeCount = node.children.length; 434 if (!this._hasVisibleChildren()) 435 return; 436 437 var visibleChildren = this._visibleChildren(); 438 var totalChildrenCount = visibleChildren.length; 423 439 424 440 // In case some nodes from the expanded range were removed, pull some nodes from the collapsed range into the expanded range at the bottom. 425 for (var i = this.expandedChildCount, limit = Math.min(this.expandedChildrenLimit, childNodeCount); i < limit; ++i)426 this.insertChildElement( node.children[i], i);441 for (var i = this.expandedChildCount, limit = Math.min(this.expandedChildrenLimit, totalChildrenCount); i < limit; ++i) 442 this.insertChildElement(totalChildrenCount[i], i); 427 443 428 444 var expandedChildCount = this.expandedChildCount; 429 if ( childNodeCount > this.expandedChildCount) {445 if (totalChildrenCount > this.expandedChildCount) { 430 446 var targetButtonIndex = expandedChildCount; 431 447 if (!this.expandAllButtonElement) { … … 445 461 this.insertChild(this.expandAllButtonElement.__treeElement, targetButtonIndex); 446 462 447 this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)").format( childNodeCount - expandedChildCount);463 this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)").format(totalChildrenCount - expandedChildCount); 448 464 } else if (this.expandAllButtonElement) 449 465 this.expandAllButtonElement = null; … … 452 468 handleLoadAllChildren() 453 469 { 454 this.expandedChildrenLimit = Math.max(this.representedObject.childNodeCount, this.expandedChildrenLimit + WebInspector.DOMTreeElement.InitialChildrenLimit); 470 var visibleChildren = this._visibleChildren(); 471 var totalChildrenCount = visibleChildren.length; 472 this.expandedChildrenLimit = Math.max(visibleChildren.length, this.expandedChildrenLimit + WebInspector.DOMTreeElement.InitialChildrenLimit); 455 473 } 456 474 … … 573 591 return false; 574 592 575 if (this.representedObject.isInShadowTree() )593 if (this.representedObject.isInShadowTree() || this.representedObject.isPseudoElement()) 576 594 return false; 577 595 … … 1112 1130 switch (node.nodeType()) { 1113 1131 case Node.DOCUMENT_FRAGMENT_NODE: 1114 var fragmentElement = info.titleDOM.createChild("span", " webkit-html-fragment");1132 var fragmentElement = info.titleDOM.createChild("span", "html-fragment"); 1115 1133 if (node.isInShadowTree()) { 1116 1134 fragmentElement.textContent = WebInspector.UIString("Shadow Content"); … … 1126 1144 1127 1145 case Node.ELEMENT_NODE: 1146 if (node.isPseudoElement()) { 1147 var pseudoElement = info.titleDOM.createChild("span", "html-pseudo-element"); 1148 pseudoElement.textContent = "::" + node.pseudoType(); 1149 info.titleDOM.appendChild(document.createTextNode("\u200B")); 1150 info.hasChildren = false; 1151 break; 1152 } 1153 1128 1154 var tagName = node.nodeNameInCorrectCase(); 1129 1155 if (this._elementCloseTag) { … … 1235 1261 if (node.hasShadowRoots()) 1236 1262 return null; 1263 if (node.hasPseudoElements()) 1264 return null; 1237 1265 1238 1266 var sibling = firstChild.nextSibling; … … 1248 1276 } 1249 1277 return false; 1278 } 1279 1280 _hasVisibleChildren() 1281 { 1282 var node = this.representedObject; 1283 1284 if (this._showInlineText(node)) 1285 return false; 1286 1287 if (node.hasChildNodes()) 1288 return true; 1289 if (node.hasPseudoElements()) 1290 return true; 1291 1292 return false; 1293 } 1294 1295 _visibleChildren() 1296 { 1297 var node = this.representedObject; 1298 1299 var visibleChildren = []; 1300 1301 var beforePseudoElement = node.beforePseudoElement(); 1302 if (beforePseudoElement) 1303 visibleChildren.push(beforePseudoElement); 1304 1305 if (node.childNodeCount) 1306 visibleChildren = visibleChildren.concat(node.children); 1307 1308 var afterPseudoElement = node.afterPseudoElement(); 1309 if (afterPseudoElement) 1310 visibleChildren.push(afterPseudoElement); 1311 1312 return visibleChildren; 1250 1313 } 1251 1314 -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeElementPathComponent.js
r182040 r187496 35 35 switch (node.nodeType()) { 36 36 case Node.ELEMENT_NODE: 37 className = WebInspector.DOMTreeElementPathComponent.DOMElementIconStyleClassName; 38 title = WebInspector.displayNameForNode(node); 37 if (node.isPseudoElement()) { 38 className = WebInspector.DOMTreeElementPathComponent.DOMPseudoElementIconStyleClassName; 39 title = "::" + node.pseudoType(); 40 } else { 41 className = WebInspector.DOMTreeElementPathComponent.DOMElementIconStyleClassName; 42 title = WebInspector.displayNameForNode(node); 43 } 39 44 break; 40 45 … … 130 135 131 136 WebInspector.DOMTreeElementPathComponent.DOMElementIconStyleClassName = "dom-element-icon"; 137 WebInspector.DOMTreeElementPathComponent.DOMPseudoElementIconStyleClassName = "dom-pseudo-element-icon"; 132 138 WebInspector.DOMTreeElementPathComponent.DOMTextNodeIconStyleClassName = "dom-text-node-icon"; 133 139 WebInspector.DOMTreeElementPathComponent.DOMCommentIconStyleClassName = "dom-comment-icon"; -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.css
r187434 r187496 157 157 } 158 158 159 .dom-tree-outline .html-pseudo-element { 160 color: hsl(0, 59%, 41%); 161 } 162 163 .dom-tree-outline .html-fragment.shadow { 164 opacity: 0.6; 165 } 166 159 167 .showing-find-banner .dom-tree-outline .search-highlight { 160 168 color: black; … … 162 170 border-bottom: 1px solid hsl(47, 82%, 60%); 163 171 } 164 165 .webkit-html-fragment.shadow {166 opacity: 0.6;167 } -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeOutline.js
r186634 r187496 229 229 if (treeElement) 230 230 return treeElement; 231 231 232 if (!node.parentNode) 232 233 return null; 233 234 234 235 treeElement = this.createTreeElementFor(node.parentNode); 235 if ( treeElement && treeElement.showChild(node.index))236 return treeElement.children[node.index];237 238 return null;236 if (!treeElement) 237 return null; 238 239 return treeElement.showChildNode(node); 239 240 } 240 241 … … 549 550 event.preventDefault(); 550 551 551 var selectedNode = this.selectedTreeElement.representedObject; 552 console.assert(selectedNode); 553 if (!selectedNode) 554 return; 555 556 if (selectedNode.nodeType() !== Node.ELEMENT_NODE) 552 var effectiveNode = this.selectedTreeElement.representedObject; 553 console.assert(effectiveNode); 554 if (!effectiveNode) 555 return; 556 557 if (effectiveNode.isPseudoElement()) { 558 effectiveNode = effectiveNode.parentNode; 559 console.assert(effectiveNode); 560 if (!effectiveNode) 561 return; 562 } 563 564 if (effectiveNode.nodeType() !== Node.ELEMENT_NODE) 557 565 return; 558 566 … … 580 588 } 581 589 582 WebInspector.RemoteObject.resolveNode( selectedNode, "", resolvedNode);590 WebInspector.RemoteObject.resolveNode(effectiveNode, "", resolvedNode); 583 591 } 584 592 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/PathComponentIcons.css
r183671 r187496 36 36 } 37 37 38 .dom-pseudo-element-icon .icon { 39 content: url(../Images/PseudoElement.svg); 40 } 41 38 42 .dom-text-node-icon .icon { 39 43 content: url(../Images/DOMTextNode.svg); -
trunk/Source/WebInspectorUI/UserInterface/Views/RulesStyleDetailsPanel.css
r187105 r187496 51 51 52 52 opacity: 0.5; 53 } 54 55 .sidebar > .panel.details.css-style .rules > *:first-child:matches(.new-rule) { 56 margin-top: 8px; 53 57 } 54 58
Note: See TracChangeset
for help on using the changeset viewer.