Move render_view_context_menu.* and related files out of tab_contents.
[chromium-blink-merge.git] / chrome / test / pyautolib / dom_mutation_observer.js
blobced5ec3f026615374fbb280541b2e8e9b3b3d902
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
5 * Helper javascript injected whenever a DomMutationEventObserver is created.
7 * This script uses MutationObservers to watch for changes to the DOM, then
8 * reports the event to the observer using the DomAutomationController. An
9 * anonymous namespace is used to prevent conflict with other Javascript.
11 * Args:
12 * automation_id: Automation id used to route DomAutomationController messages.
13 * observer_id: Id of the observer who will be receiving the messages.
14 * observer_type: One of 'add', 'remove', 'change', or 'exists'.
15 * xpath: XPath used to specify the DOM node of interest.
16 * attribute: If |expected_value| is provided, check if this attribute of the
17 * DOM node matches |expected value|.
18 * expected_value: If not null, regular expression to match with the value of
19 * |attribute| after the mutation.
21 function(automation_id, observer_id, observer_type, xpath, attribute,
22 expected_value) {
24 /* Raise an event for the DomMutationEventObserver. */
25 function raiseEvent() {
26 if (window.domAutomationController) {
27 console.log("Event sent to DomEventObserver with id=" +
28 observer_id + ".");
29 window.domAutomationController.sendWithId(
30 automation_id, "__dom_mutation_observer__:" + observer_id);
34 /* Calls raiseEvent if the expected node has been added to the DOM.
36 * Args:
37 * mutations: A list of mutation objects.
38 * observer: The mutation observer object associated with this callback.
40 function addNodeCallback(mutations, observer) {
41 for (var j=0; j<mutations.length; j++) {
42 for (var i=0; i<mutations[j].addedNodes.length; i++) {
43 var node = mutations[j].addedNodes[i];
44 if (xpathMatchesNode(node, xpath) &&
45 nodeAttributeValueEquals(node, attribute, expected_value)) {
46 raiseEvent();
47 observer.disconnect();
48 delete observer;
49 return;
55 /* Calls raiseEvent if the expected node has been removed from the DOM.
57 * Args:
58 * mutations: A list of mutation objects.
59 * observer: The mutation observer object associated with this callback.
61 function removeNodeCallback(mutations, observer) {
62 var node = firstXPathNode(xpath);
63 if (!node) {
64 raiseEvent();
65 observer.disconnect();
66 delete observer;
70 /* Calls raiseEvent if the given node has been changed to expected_value.
72 * Args:
73 * mutations: A list of mutation objects.
74 * observer: The mutation observer object associated with this callback.
76 function changeNodeCallback(mutations, observer) {
77 for (var j=0; j<mutations.length; j++) {
78 if (nodeAttributeValueEquals(mutations[j].target, attribute,
79 expected_value)) {
80 raiseEvent();
81 observer.disconnect();
82 delete observer;
83 return;
88 /* Calls raiseEvent if the expected node exists in the DOM.
90 * Args:
91 * mutations: A list of mutation objects.
92 * observer: The mutation observer object associated with this callback.
94 function existsNodeCallback(mutations, observer) {
95 if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
96 raiseEvent();
97 observer.disconnect();
98 delete observer;
99 return;
103 /* Return true if the xpath matches the given node.
105 * Args:
106 * node: A node object from the DOM.
107 * xpath: An XPath used to compare with the DOM node.
109 function xpathMatchesNode(node, xpath) {
110 var con = document.evaluate(xpath, document, null,
111 XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
112 var thisNode = con.iterateNext();
113 while (thisNode) {
114 if (node == thisNode) {
115 return true;
117 thisNode = con.iterateNext();
119 return false;
122 /* Returns the first node in the DOM that matches the xpath.
124 * Args:
125 * xpath: XPath used to specify the DOM node of interest.
127 function firstXPathNode(xpath) {
128 return document.evaluate(xpath, document, null,
129 XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
132 /* Returns the first node in the DOM that matches the xpath.
134 * Args:
135 * xpath: XPath used to specify the DOM node of interest.
136 * attribute: The attribute to match |expected_value| against.
137 * expected_value: A regular expression to match with the node's
138 * |attribute|. If null the match always succeeds.
140 function findNodeMatchingXPathAndValue(xpath, attribute, expected_value) {
141 var nodes = document.evaluate(xpath, document, null,
142 XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
143 var node;
144 while ( (node = nodes.iterateNext()) ) {
145 if (nodeAttributeValueEquals(node, attribute, expected_value))
146 return node;
148 return null;
151 /* Returns true if the node's |attribute| value is matched by the regular
152 * expression |expected_value|, false otherwise.
154 * Args:
155 * node: A node object from the DOM.
156 * attribute: The attribute to match |expected_value| against.
157 * expected_value: A regular expression to match with the node's
158 * |attribute|. If null the test always passes.
160 function nodeAttributeValueEquals(node, attribute, expected_value) {
161 return expected_value == null ||
162 (node[attribute] && RegExp(expected_value, "").test(node[attribute]));
165 /* Watch for a node matching xpath to be added to the DOM.
167 * Args:
168 * xpath: XPath used to specify the DOM node of interest.
170 function observeAdd(xpath) {
171 window.domAutomationController.send("success");
172 if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
173 raiseEvent();
174 console.log("Matching node in DOM, assuming it was previously added.");
175 return;
178 var obs = new MutationObserver(addNodeCallback);
179 obs.observe(document,
180 { childList: true,
181 attributes: true,
182 characterData: true,
183 subtree: true});
186 /* Watch for a node matching xpath to be removed from the DOM.
188 * Args:
189 * xpath: XPath used to specify the DOM node of interest.
191 function observeRemove(xpath) {
192 window.domAutomationController.send("success");
193 if (!firstXPathNode(xpath)) {
194 raiseEvent();
195 console.log("No matching node in DOM, assuming it was already removed.");
196 return;
199 var obs = new MutationObserver(removeNodeCallback);
200 obs.observe(document,
201 { childList: true,
202 attributes: true,
203 subtree: true});
206 /* Watch for the textContent of a node matching xpath to change to
207 * expected_value.
209 * Args:
210 * xpath: XPath used to specify the DOM node of interest.
212 function observeChange(xpath) {
213 var node = firstXPathNode(xpath);
214 if (!node) {
215 console.log("No matching node in DOM.");
216 window.domAutomationController.send(
217 "No DOM node matching xpath exists.");
218 return;
220 window.domAutomationController.send("success");
222 var obs = new MutationObserver(changeNodeCallback);
223 obs.observe(node,
224 { childList: true,
225 attributes: true,
226 characterData: true,
227 subtree: true});
230 /* Watch for a node matching xpath to exist in the DOM.
232 * Args:
233 * xpath: XPath used to specify the DOM node of interest.
235 function observeExists(xpath) {
236 window.domAutomationController.send("success");
237 if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
238 raiseEvent();
239 console.log("Node already exists in DOM.");
240 return;
243 var obs = new MutationObserver(existsNodeCallback);
244 obs.observe(document,
245 { childList: true,
246 attributes: true,
247 characterData: true,
248 subtree: true});
251 /* Interpret arguments and launch the requested observer function. */
252 function installMutationObserver() {
253 switch (observer_type) {
254 case "add":
255 observeAdd(xpath);
256 break;
257 case "remove":
258 observeRemove(xpath);
259 break;
260 case "change":
261 observeChange(xpath);
262 break;
263 case "exists":
264 observeExists(xpath);
265 break;
267 console.log("MutationObserver javscript injection completed.");
270 /* Ensure the DOM is loaded before attempting to create MutationObservers. */
271 if (document.body) {
272 installMutationObserver();
273 } else {
274 window.addEventListener("DOMContentLoaded", installMutationObserver, true);