Changeset 102814 in webkit
- Timestamp:
- Dec 14, 2011, 1:14:15 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r102800 r102814 1 2011-12-14 Adam Klein <adamk@chromium.org> 2 3 Broaden support for mutation observation of attributes 4 https://bugs.webkit.org/show_bug.cgi?id=74448 5 6 Reviewed by Ryosuke Niwa. 7 8 Add tests covering attribute mutation via Attr nodes. 9 10 * fast/mutation/observe-attributes-expected.txt: 11 * fast/mutation/observe-attributes.html: 12 1 13 2011-12-14 Eric Carlson <eric.carlson@apple.com> 2 14 -
trunk/LayoutTests/fast/mutation/observe-attributes-expected.txt
r102264 r102814 91 91 92 92 Testing setting an attribute via reflected IDL attribute. 93 PASS mutations.length is 293 PASS mutations.length is 3 94 94 PASS mutations[0].type is "attributes" 95 95 PASS mutations[0].attributeName is "id" … … 98 98 PASS mutations[1].attributeName is "id" 99 99 PASS mutations[1].oldValue is "foo" 100 PASS mutations[2].type is "attributes" 101 PASS mutations[2].attributeName is "id" 102 PASS mutations[2].oldValue is "bar" 100 103 101 104 Testing that attributeFilter works as expected and ignores case with HTML elements. … … 190 193 PASS mutations is null 191 194 195 Test that mutating an attribute through an attr node delivers mutation records 196 PASS mutations.length is 1 197 PASS mutations[0].target is div 198 PASS mutations[0].type is "attributes" 199 PASS mutations[0].attributeName is "data-test" 200 PASS mutations[0].oldValue is "foo" 201 202 Test that mutating an attribute by attaching a child to an attr node delivers mutation records 203 PASS mutations.length is 1 204 PASS mutations[0].target is div 205 PASS mutations[0].type is "attributes" 206 PASS mutations[0].attributeName is "data-test" 207 PASS mutations[0].oldValue is "foo" 208 209 Test that mutating via setAttributeNode delivers mutation records 210 PASS mutations.length is 3 211 PASS mutations[0].target is div 212 PASS mutations[0].type is "attributes" 213 PASS mutations[0].attributeName is "data-test" 214 PASS mutations[0].oldValue is "foo" 215 PASS mutations[1].target is div 216 PASS mutations[1].type is "attributes" 217 PASS mutations[1].attributeName is "data-other" 218 PASS mutations[1].oldValue is null 219 PASS mutations[2].target is div 220 PASS mutations[2].type is "attributes" 221 PASS mutations[2].attributeName is "id" 222 PASS mutations[2].oldValue is "myId" 223 224 Test that setAttribute on an attribute with an existing Attr delivers mutation records 225 PASS mutations.length is 1 226 PASS mutations[0].target is div 227 PASS mutations[0].type is "attributes" 228 PASS mutations[0].attributeName is "data-test" 229 PASS mutations[0].oldValue is "foo" 230 231 Test that setNamedItem and removeNamedItem deliver mutation records 232 PASS mutations.length is 2 233 PASS mutations[0].target is div 234 PASS mutations[0].type is "attributes" 235 PASS mutations[0].attributeName is "data-test" 236 PASS mutations[0].oldValue is "foo" 237 PASS mutations[1].target is div 238 PASS mutations[1].type is "attributes" 239 PASS mutations[1].attributeName is "data-test" 240 PASS mutations[1].oldValue is "bar" 241 192 242 PASS successfullyParsed is true 193 243 -
trunk/LayoutTests/fast/mutation/observe-attributes.html
r102264 r102814 1 1 <!DOCTYPE html> 2 <html>3 <head>4 <meta charset="utf-8">5 2 <script src="../js/resources/js-test-pre.js"></script> 6 </head>7 <body>8 <p id=description></p>9 <div id="console"></div>10 3 <script> 11 4 … … 13 6 var mutations, mutations2, mutationsWithOldValue; 14 7 var calls; 8 var div; 15 9 16 10 function testBasic() { … … 430 424 div.id = 'foo'; 431 425 div.id = 'bar'; 432 setTimeout(finish, 0); 433 } 434 435 function finish() { 436 shouldBe('mutations.length', '2'); 426 div.id = null; 427 setTimeout(finish, 0); 428 } 429 430 function finish() { 431 shouldBe('mutations.length', '3'); 437 432 shouldBe('mutations[0].type', '"attributes"'); 438 433 shouldBe('mutations[0].attributeName', '"id"'); … … 441 436 shouldBe('mutations[1].attributeName', '"id"'); 442 437 shouldBe('mutations[1].oldValue', '"foo"'); 438 shouldBe('mutations[2].type', '"attributes"'); 439 shouldBe('mutations[2].attributeName', '"id"'); 440 shouldBe('mutations[2].oldValue', '"bar"'); 443 441 observer.disconnect(); 444 442 debug(''); … … 778 776 function finish() { 779 777 shouldBe('mutations', 'null'); 778 779 observer.disconnect(); 780 debug(''); 781 runNextTest(); 782 } 783 784 start(); 785 } 786 787 function testMutateThroughAttrNodeValue() { 788 var observer; 789 790 function start() { 791 debug('Test that mutating an attribute through an attr node delivers mutation records'); 792 793 mutations = null; 794 observer = new WebKitMutationObserver(function(mutations) { 795 window.mutations = mutations; 796 }); 797 798 div = document.createElement('div'); 799 div.setAttribute('data-test', 'foo'); 800 observer.observe(div, { attributes: true, attributeOldValue: true }); 801 div.attributes['data-test'].value = 'bar'; 802 803 setTimeout(finish, 0); 804 } 805 806 function finish() { 807 shouldBe('mutations.length', '1'); 808 shouldBe('mutations[0].target', 'div'); 809 shouldBe('mutations[0].type', '"attributes"'); 810 shouldBe('mutations[0].attributeName', '"data-test"'); 811 shouldBe('mutations[0].oldValue', '"foo"'); 812 813 observer.disconnect(); 814 debug(''); 815 runNextTest(); 816 } 817 818 start(); 819 } 820 821 function testMutateThroughAttrNodeChild() { 822 var observer; 823 824 function start() { 825 debug('Test that mutating an attribute by attaching a child to an attr node delivers mutation records'); 826 827 mutations = null; 828 observer = new WebKitMutationObserver(function(mutations) { 829 window.mutations = mutations; 830 }); 831 832 div = document.createElement('div'); 833 div.setAttribute('data-test', 'foo'); 834 observer.observe(div, { attributes: true, attributeOldValue: true }); 835 div.attributes['data-test'].appendChild(document.createTextNode('bar')); 836 837 setTimeout(finish, 0); 838 } 839 840 function finish() { 841 shouldBe('mutations.length', '1'); 842 shouldBe('mutations[0].target', 'div'); 843 shouldBe('mutations[0].type', '"attributes"'); 844 shouldBe('mutations[0].attributeName', '"data-test"'); 845 shouldBe('mutations[0].oldValue', '"foo"'); 846 847 observer.disconnect(); 848 debug(''); 849 runNextTest(); 850 } 851 852 start(); 853 } 854 855 function testSetAndRemoveAttributeNode() { 856 var observer; 857 858 function start() { 859 debug('Test that mutating via setAttributeNode delivers mutation records'); 860 861 mutations = null; 862 observer = new WebKitMutationObserver(function(mutations) { 863 window.mutations = mutations; 864 }); 865 866 div = document.createElement('div'); 867 div.id = 'myId'; 868 div.setAttribute('data-test', 'foo'); 869 observer.observe(div, { attributes: true, attributeOldValue: true }); 870 var attr = document.createAttribute('data-test'); 871 attr.value = 'bar'; 872 div.setAttributeNode(attr); 873 attr = document.createAttribute('data-other'); 874 attr.value = 'baz'; 875 div.setAttributeNode(attr); 876 div.removeAttributeNode(div.attributes['id']); 877 878 setTimeout(finish, 0); 879 } 880 881 function finish() { 882 shouldBe('mutations.length', '3'); 883 shouldBe('mutations[0].target', 'div'); 884 shouldBe('mutations[0].type', '"attributes"'); 885 shouldBe('mutations[0].attributeName', '"data-test"'); 886 shouldBe('mutations[0].oldValue', '"foo"'); 887 shouldBe('mutations[1].target', 'div'); 888 shouldBe('mutations[1].type', '"attributes"'); 889 shouldBe('mutations[1].attributeName', '"data-other"'); 890 shouldBe('mutations[1].oldValue', 'null'); 891 shouldBe('mutations[2].target', 'div'); 892 shouldBe('mutations[2].type', '"attributes"'); 893 shouldBe('mutations[2].attributeName', '"id"'); 894 shouldBe('mutations[2].oldValue', '"myId"'); 895 896 observer.disconnect(); 897 debug(''); 898 runNextTest(); 899 } 900 901 start(); 902 } 903 904 function testMixedNodeAndElementOperations() { 905 var observer; 906 907 function start() { 908 debug('Test that setAttribute on an attribute with an existing Attr delivers mutation records'); 909 910 mutations = null; 911 observer = new WebKitMutationObserver(function(mutations) { 912 window.mutations = mutations; 913 }); 914 915 div = document.createElement('div'); 916 var attr = document.createAttribute('data-test'); 917 attr.value = 'foo'; 918 div.setAttributeNode(attr); 919 observer.observe(div, { attributes: true, attributeOldValue: true }); 920 div.setAttribute('data-test', 'bar'); 921 922 setTimeout(finish, 0); 923 } 924 925 function finish() { 926 shouldBe('mutations.length', '1'); 927 shouldBe('mutations[0].target', 'div'); 928 shouldBe('mutations[0].type', '"attributes"'); 929 shouldBe('mutations[0].attributeName', '"data-test"'); 930 shouldBe('mutations[0].oldValue', '"foo"'); 931 932 observer.disconnect(); 933 debug(''); 934 runNextTest(); 935 } 936 937 start(); 938 } 939 940 function testNamedNodeMapOperations() { 941 var observer; 942 943 function start() { 944 debug('Test that setNamedItem and removeNamedItem deliver mutation records'); 945 946 mutations = null; 947 observer = new WebKitMutationObserver(function(mutations) { 948 window.mutations = mutations; 949 }); 950 951 div = document.createElement('div'); 952 div.setAttribute('data-test', 'foo'); 953 observer.observe(div, { attributes: true, attributeOldValue: true }); 954 var attr = document.createAttribute('data-test'); 955 attr.value = 'bar'; 956 div.attributes.setNamedItem(attr); 957 div.attributes.removeNamedItem('data-test'); 958 959 setTimeout(finish, 0); 960 } 961 962 function finish() { 963 shouldBe('mutations.length', '2'); 964 shouldBe('mutations[0].target', 'div'); 965 shouldBe('mutations[0].type', '"attributes"'); 966 shouldBe('mutations[0].attributeName', '"data-test"'); 967 shouldBe('mutations[0].oldValue', '"foo"'); 968 shouldBe('mutations[1].target', 'div'); 969 shouldBe('mutations[1].type', '"attributes"'); 970 shouldBe('mutations[1].attributeName', '"data-test"'); 971 shouldBe('mutations[1].oldValue', '"bar"'); 780 972 781 973 observer.disconnect(); … … 805 997 testStyleAttributePropertyAccess, 806 998 testStyleAttributePropertyAccessOldValue, 807 testStyleAttributePropertyAccessIgnoreNoop 999 testStyleAttributePropertyAccessIgnoreNoop, 1000 testMutateThroughAttrNodeValue, 1001 testMutateThroughAttrNodeChild, 1002 testSetAndRemoveAttributeNode, 1003 testMixedNodeAndElementOperations, 1004 testNamedNodeMapOperations 808 1005 ]; 809 1006 var testIndex = 0; … … 825 1022 </script> 826 1023 <script src="../js/resources/js-test-post.js"></script> 827 </body>828 </html> -
trunk/Source/WebCore/ChangeLog
r102810 r102814 1 2011-12-14 Adam Klein <adamk@chromium.org> 2 3 Broaden support for mutation observation of attributes 4 https://bugs.webkit.org/show_bug.cgi?id=74448 5 6 Reviewed by Ryosuke Niwa. 7 8 The previously-landed MutationObserver support for attributes was incomplete: 9 it didn't support mutations related to Attr nodes (methods on Attrs, 10 setAttributeNode/removeAttributeNode on Element, or methods on NamedNodeMap). 11 12 This patch adds full support of mutation observation for all these cases, 13 and adds test cases for all these situations. 14 15 * dom/Attr.cpp: 16 (WebCore::Attr::setValue): Enqueue a mutation record when Attr.value is set from JS. 17 (WebCore::Attr::childrenChanged): Enqueue a mutation record when an Attr's value 18 changes to due additions/removals of Text children. 19 * dom/Element.cpp: 20 (WebCore::Element::enqueueAttributesMutationRecordIfRequested): Previously a static, 21 expose as part of Element's interface to allow it to be re-used by NamedNodeMap and Attr. 22 (WebCore::Element::removeAttribute): Remove enqueue call now handled by NamedNodeMap. 23 (WebCore::Element::setAttributeInternal): Fixup call of enqueueAttributesMutationRecordIfRequested. 24 * dom/Element.h: 25 * dom/NamedNodeMap.cpp: 26 (WebCore::NamedNodeMap::setNamedItem): Enqueue a mutation record when an attribute 27 is changed via Element.attributes.setNamedItem from JS. 28 (WebCore::NamedNodeMap::removeNamedItem): Enqueue a mutation record when an 29 attribute is removed, either via Element.attributes.removeNamedItem or Element.removeAttribute. 30 1 31 2011-12-14 Raymond Toy <rtoy@google.com> 2 32 -
trunk/Source/WebCore/dom/Attr.cpp
r102431 r102814 131 131 void Attr::setValue(const AtomicString& value, ExceptionCode&) 132 132 { 133 #if ENABLE(MUTATION_OBSERVERS) 134 if (m_element) 135 m_element->enqueueAttributesMutationRecordIfRequested(m_attribute->name(), m_attribute->value()); 136 #endif 137 133 138 if (m_element && m_element->isIdAttributeName(m_attribute->name())) 134 139 m_element->updateId(m_element->getIdAttribute(), value); … … 168 173 if (m_ignoreChildrenChanged > 0) 169 174 return; 170 175 176 #if ENABLE(MUTATION_OBSERVERS) 177 if (m_element) 178 m_element->enqueueAttributesMutationRecordIfRequested(m_attribute->name(), m_attribute->value()); 179 #endif 180 171 181 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 172 182 -
trunk/Source/WebCore/dom/Element.cpp
r102721 r102814 182 182 183 183 #if ENABLE(MUTATION_OBSERVERS) 184 static void enqueueAttributesMutationRecord(Element* target, const QualifiedName& attributeName, const AtomicString& oldValue) 185 { 186 if (OwnPtr<MutationObserverInterestGroup> mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(target, attributeName)) 187 mutationRecipients->enqueueMutationRecord(MutationRecord::createAttributes(target, attributeName, oldValue)); 184 void Element::enqueueAttributesMutationRecordIfRequested(const QualifiedName& attributeName, const AtomicString& oldValue) 185 { 186 if (isSynchronizingStyleAttribute()) 187 return; 188 if (OwnPtr<MutationObserverInterestGroup> mutationRecipients = MutationObserverInterestGroup::createForAttributesMutation(this, attributeName)) 189 mutationRecipients->enqueueMutationRecord(MutationRecord::createAttributes(this, attributeName, oldValue)); 188 190 } 189 191 #endif … … 196 198 if (ec == NOT_FOUND_ERR) 197 199 ec = 0; 198 #if ENABLE(MUTATION_OBSERVERS)199 else200 enqueueAttributesMutationRecord(this, name, attrNode->nodeValue());201 #endif202 200 } 203 201 } … … 657 655 #endif 658 656 657 #if ENABLE(MUTATION_OBSERVERS) 658 enqueueAttributesMutationRecordIfRequested(name, old ? old->value() : nullAtom); 659 #endif 660 659 661 document()->incDOMTreeVersion(); 660 661 #if ENABLE(MUTATION_OBSERVERS)662 // The call to attributeChanged below may dispatch DOMSubtreeModified, so it's important to enqueue a MutationRecord now.663 if (!isSynchronizingStyleAttribute())664 enqueueAttributesMutationRecord(this, name, old ? old->value() : nullAtom);665 #endif666 662 667 663 if (isIdAttributeName(name)) … … 1524 1520 if (ec == NOT_FOUND_ERR) 1525 1521 ec = 0; 1526 #if ENABLE(MUTATION_OBSERVERS)1527 else1528 enqueueAttributesMutationRecord(this, QualifiedName(nullAtom, localName, nullAtom), attrNode->nodeValue());1529 #endif1530 1522 } 1531 1523 -
trunk/Source/WebCore/dom/Element.h
r102695 r102814 365 365 PassRefPtr<RenderStyle> styleForRenderer(); 366 366 367 #if ENABLE(MUTATION_OBSERVERS) 368 void enqueueAttributesMutationRecordIfRequested(const QualifiedName&, const AtomicString& oldValue); 369 #endif 370 367 371 protected: 368 372 Element(const QualifiedName& tagName, Document* document, ConstructionType type) -
trunk/Source/WebCore/dom/NamedNodeMap.cpp
r102705 r102814 120 120 } 121 121 122 #if ENABLE(MUTATION_OBSERVERS) 123 m_element->enqueueAttributesMutationRecordIfRequested(attribute->name(), oldAttribute ? oldAttribute->value() : nullAtom); 124 #endif 125 122 126 if (attr->isId()) 123 127 m_element->updateId(oldAttribute ? oldAttribute->value() : nullAtom, attribute->value()); … … 149 153 return 0; 150 154 } 155 156 #if ENABLE(MUTATION_OBSERVERS) 157 if (m_element) 158 m_element->enqueueAttributesMutationRecordIfRequested(attribute->name(), attribute->value()); 159 #endif 151 160 152 161 RefPtr<Attr> attr = attribute->createAttrIfNeeded(m_element);
Note:
See TracChangeset
for help on using the changeset viewer.