rainux-selenium-webdriver 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/COPYING +204 -0
  2. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  3. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  4. data/chrome/src/extension/background.html +9 -0
  5. data/chrome/src/extension/background.js +995 -0
  6. data/chrome/src/extension/content_script.js +1321 -0
  7. data/chrome/src/extension/icons/busy.png +0 -0
  8. data/chrome/src/extension/icons/free.png +0 -0
  9. data/chrome/src/extension/manifest-nonwin.json +19 -0
  10. data/chrome/src/extension/manifest-win.json +20 -0
  11. data/chrome/src/extension/utils.js +231 -0
  12. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
  13. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +358 -0
  14. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +124 -0
  15. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +135 -0
  16. data/common/src/js/abstractcommandprocessor.js +134 -0
  17. data/common/src/js/asserts.js +296 -0
  18. data/common/src/js/by.js +149 -0
  19. data/common/src/js/command.js +304 -0
  20. data/common/src/js/context.js +58 -0
  21. data/common/src/js/core/Blank.html +7 -0
  22. data/common/src/js/core/InjectedRemoteRunner.html +8 -0
  23. data/common/src/js/core/RemoteRunner.html +101 -0
  24. data/common/src/js/core/SeleniumLog.html +109 -0
  25. data/common/src/js/core/TestPrompt.html +145 -0
  26. data/common/src/js/core/TestRunner-splash.html +55 -0
  27. data/common/src/js/core/TestRunner.html +165 -0
  28. data/common/src/js/core/icons/all.png +0 -0
  29. data/common/src/js/core/icons/continue.png +0 -0
  30. data/common/src/js/core/icons/continue_disabled.png +0 -0
  31. data/common/src/js/core/icons/pause.png +0 -0
  32. data/common/src/js/core/icons/pause_disabled.png +0 -0
  33. data/common/src/js/core/icons/selected.png +0 -0
  34. data/common/src/js/core/icons/step.png +0 -0
  35. data/common/src/js/core/icons/step_disabled.png +0 -0
  36. data/common/src/js/core/lib/cssQuery/cssQuery-p.js +6 -0
  37. data/common/src/js/core/lib/cssQuery/src/cssQuery-level2.js +142 -0
  38. data/common/src/js/core/lib/cssQuery/src/cssQuery-level3.js +150 -0
  39. data/common/src/js/core/lib/cssQuery/src/cssQuery-standard.js +53 -0
  40. data/common/src/js/core/lib/cssQuery/src/cssQuery.js +356 -0
  41. data/common/src/js/core/lib/prototype.js +2006 -0
  42. data/common/src/js/core/lib/scriptaculous/builder.js +101 -0
  43. data/common/src/js/core/lib/scriptaculous/controls.js +815 -0
  44. data/common/src/js/core/lib/scriptaculous/dragdrop.js +915 -0
  45. data/common/src/js/core/lib/scriptaculous/effects.js +958 -0
  46. data/common/src/js/core/lib/scriptaculous/scriptaculous.js +47 -0
  47. data/common/src/js/core/lib/scriptaculous/slider.js +283 -0
  48. data/common/src/js/core/lib/scriptaculous/unittest.js +383 -0
  49. data/common/src/js/core/lib/snapsie.js +91 -0
  50. data/common/src/js/core/scripts/find_matching_child.js +69 -0
  51. data/common/src/js/core/scripts/htmlutils.js +8716 -0
  52. data/common/src/js/core/scripts/injection.html +72 -0
  53. data/common/src/js/core/scripts/selenium-api.js +3291 -0
  54. data/common/src/js/core/scripts/selenium-browserbot.js +2457 -0
  55. data/common/src/js/core/scripts/selenium-browserdetect.js +153 -0
  56. data/common/src/js/core/scripts/selenium-commandhandlers.js +379 -0
  57. data/common/src/js/core/scripts/selenium-executionloop.js +175 -0
  58. data/common/src/js/core/scripts/selenium-logging.js +148 -0
  59. data/common/src/js/core/scripts/selenium-remoterunner.js +695 -0
  60. data/common/src/js/core/scripts/selenium-testrunner.js +1362 -0
  61. data/common/src/js/core/scripts/selenium-version.js +5 -0
  62. data/common/src/js/core/scripts/ui-doc.html +808 -0
  63. data/common/src/js/core/scripts/ui-element.js +1644 -0
  64. data/common/src/js/core/scripts/ui-map-sample.js +979 -0
  65. data/common/src/js/core/scripts/user-extensions.js +3 -0
  66. data/common/src/js/core/scripts/user-extensions.js.sample +75 -0
  67. data/common/src/js/core/scripts/xmlextras.js +153 -0
  68. data/common/src/js/core/selenium-logo.png +0 -0
  69. data/common/src/js/core/selenium-test.css +43 -0
  70. data/common/src/js/core/selenium.css +316 -0
  71. data/common/src/js/core/xpath/dom.js +566 -0
  72. data/common/src/js/core/xpath/javascript-xpath-0.1.11.js +2816 -0
  73. data/common/src/js/core/xpath/util.js +549 -0
  74. data/common/src/js/core/xpath/xmltoken.js +149 -0
  75. data/common/src/js/core/xpath/xpath.js +2481 -0
  76. data/common/src/js/extension/README +2 -0
  77. data/common/src/js/extension/dommessenger.js +152 -0
  78. data/common/src/js/factory.js +55 -0
  79. data/common/src/js/future.js +141 -0
  80. data/common/src/js/jsunit.js +40 -0
  81. data/common/src/js/jsunit/app/css/jsUnitStyle.css +50 -0
  82. data/common/src/js/jsunit/app/css/readme +10 -0
  83. data/common/src/js/jsunit/app/emptyPage.html +11 -0
  84. data/common/src/js/jsunit/app/jsUnitCore.js +534 -0
  85. data/common/src/js/jsunit/app/jsUnitMockTimeout.js +81 -0
  86. data/common/src/js/jsunit/app/jsUnitTestManager.js +705 -0
  87. data/common/src/js/jsunit/app/jsUnitTestSuite.js +44 -0
  88. data/common/src/js/jsunit/app/jsUnitTracer.js +102 -0
  89. data/common/src/js/jsunit/app/jsUnitVersionCheck.js +59 -0
  90. data/common/src/js/jsunit/app/main-counts-errors.html +12 -0
  91. data/common/src/js/jsunit/app/main-counts-failures.html +13 -0
  92. data/common/src/js/jsunit/app/main-counts-runs.html +13 -0
  93. data/common/src/js/jsunit/app/main-counts.html +21 -0
  94. data/common/src/js/jsunit/app/main-data.html +178 -0
  95. data/common/src/js/jsunit/app/main-errors.html +23 -0
  96. data/common/src/js/jsunit/app/main-frame.html +19 -0
  97. data/common/src/js/jsunit/app/main-loader.html +45 -0
  98. data/common/src/js/jsunit/app/main-progress.html +25 -0
  99. data/common/src/js/jsunit/app/main-results.html +67 -0
  100. data/common/src/js/jsunit/app/main-status.html +13 -0
  101. data/common/src/js/jsunit/app/testContainer.html +16 -0
  102. data/common/src/js/jsunit/app/testContainerController.html +77 -0
  103. data/common/src/js/jsunit/app/xbDebug.js +306 -0
  104. data/common/src/js/jsunit/changelog.txt +60 -0
  105. data/common/src/js/jsunit/css/jsUnitStyle.css +83 -0
  106. data/common/src/js/jsunit/images/green.gif +0 -0
  107. data/common/src/js/jsunit/images/logo_jsunit.gif +0 -0
  108. data/common/src/js/jsunit/images/powerby-transparent.gif +0 -0
  109. data/common/src/js/jsunit/images/red.gif +0 -0
  110. data/common/src/js/jsunit/licenses/JDOM_license.txt +56 -0
  111. data/common/src/js/jsunit/licenses/Jetty_license.html +213 -0
  112. data/common/src/js/jsunit/licenses/MPL-1.1.txt +470 -0
  113. data/common/src/js/jsunit/licenses/gpl-2.txt +340 -0
  114. data/common/src/js/jsunit/licenses/index.html +141 -0
  115. data/common/src/js/jsunit/licenses/lgpl-2.1.txt +504 -0
  116. data/common/src/js/jsunit/licenses/mpl-tri-license-c.txt +35 -0
  117. data/common/src/js/jsunit/licenses/mpl-tri-license-html.txt +35 -0
  118. data/common/src/js/jsunit/readme.txt +19 -0
  119. data/common/src/js/jsunit/testRunner.html +167 -0
  120. data/common/src/js/jsunit/version.txt +1 -0
  121. data/common/src/js/key.js +117 -0
  122. data/common/src/js/localcommandprocessor.js +185 -0
  123. data/common/src/js/testcase.js +217 -0
  124. data/common/src/js/timing.js +89 -0
  125. data/common/src/js/webdriver.js +890 -0
  126. data/common/src/js/webelement.js +485 -0
  127. data/common/src/rb/README +30 -0
  128. data/common/src/rb/lib/selenium-webdriver.rb +1 -0
  129. data/common/src/rb/lib/selenium/webdriver.rb +67 -0
  130. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +91 -0
  131. data/common/src/rb/lib/selenium/webdriver/child_process.rb +180 -0
  132. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
  133. data/common/src/rb/lib/selenium/webdriver/driver.rb +252 -0
  134. data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +24 -0
  135. data/common/src/rb/lib/selenium/webdriver/element.rb +262 -0
  136. data/common/src/rb/lib/selenium/webdriver/error.rb +67 -0
  137. data/common/src/rb/lib/selenium/webdriver/find.rb +89 -0
  138. data/common/src/rb/lib/selenium/webdriver/keys.rb +84 -0
  139. data/common/src/rb/lib/selenium/webdriver/navigation.rb +27 -0
  140. data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
  141. data/common/src/rb/lib/selenium/webdriver/platform.rb +86 -0
  142. data/common/src/rb/lib/selenium/webdriver/target_locator.rb +70 -0
  143. data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
  144. data/firefox/prebuilt/linux/Release/libwebdriver-firefox.so +0 -0
  145. data/firefox/prebuilt/linux/Release/x_ignore_nofocus.so +0 -0
  146. data/firefox/prebuilt/linux64/Release/libwebdriver-firefox.so +0 -0
  147. data/firefox/prebuilt/linux64/Release/x_ignore_nofocus.so +0 -0
  148. data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
  149. data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
  150. data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
  151. data/firefox/src/extension/chrome.manifest +3 -0
  152. data/firefox/src/extension/components/badCertListener.js +294 -0
  153. data/firefox/src/extension/components/context.js +37 -0
  154. data/firefox/src/extension/components/driver-component.js +127 -0
  155. data/firefox/src/extension/components/firefoxDriver.js +810 -0
  156. data/firefox/src/extension/components/json2.js +273 -0
  157. data/firefox/src/extension/components/keytest.html +554 -0
  158. data/firefox/src/extension/components/nsCommandProcessor.js +643 -0
  159. data/firefox/src/extension/components/promptService.js +208 -0
  160. data/firefox/src/extension/components/screenshooter.js +81 -0
  161. data/firefox/src/extension/components/socketListener.js +185 -0
  162. data/firefox/src/extension/components/utils.js +1263 -0
  163. data/firefox/src/extension/components/webLoadingListener.js +57 -0
  164. data/firefox/src/extension/components/webdriverserver.js +106 -0
  165. data/firefox/src/extension/components/wrappedElement.js +683 -0
  166. data/firefox/src/extension/content/fxdriver.xul +30 -0
  167. data/firefox/src/extension/content/server.js +95 -0
  168. data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
  169. data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
  170. data/firefox/src/extension/install.rdf +29 -0
  171. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +31 -0
  172. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +107 -0
  173. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +484 -0
  174. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +90 -0
  175. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +155 -0
  176. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +233 -0
  177. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +59 -0
  178. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
  179. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  180. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  181. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
  182. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +565 -0
  183. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +99 -0
  184. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
  185. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
  186. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +408 -0
  187. data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
  188. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
  189. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
  190. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +49 -0
  191. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
  192. metadata +303 -0
@@ -0,0 +1,1263 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ function StaleElementError() {
20
+ this.isStaleElementError = true;
21
+ }
22
+
23
+ function createSwitchFile(file_content) {
24
+ var filename = "/tmp/switch_window_started";
25
+ var cc = Components.classes;
26
+ var ci = Components.interfaces;
27
+
28
+ try {
29
+ // TODO(eran): Look at the OS and only do this where it makes sense.
30
+ var tmpdir = cc['@mozilla.org/file/local;1'].createInstance(ci.nsILocalFile);
31
+ tmpdir.initWithPath("/tmp");
32
+
33
+ // Do not create a switch file on systems that do not have a /tmp directory
34
+ // - this serves to prevent creation of a switch file on Windows systems.
35
+ if (!tmpdir.exists()) {
36
+ return;
37
+ }
38
+
39
+ var file = cc['@mozilla.org/file/local;1'].createInstance(ci.nsILocalFile);
40
+ file.initWithPath(filename);
41
+ var fileOutputStream = cc['@mozilla.org/network/safe-file-output-stream;1'].createInstance(ci.nsIFileOutputStream);
42
+ fileOutputStream.init(file, -1, -1, null);
43
+
44
+ fileOutputStream.write(file_content, file_content.length);
45
+ if (fileOutputStream instanceof ci.nsISafeOutputStream) {
46
+ fileOutputStream.finish();
47
+ } else {
48
+ fileOutputStream.close();
49
+ }
50
+ } catch (e) {
51
+ // Fine. Log it and continue
52
+ Utils.dumpn(e);
53
+ }
54
+ }
55
+
56
+ function Utils() {
57
+ }
58
+
59
+
60
+ Utils.getUniqueId = function() {
61
+ if (!Utils._generator) {
62
+ Utils._generator =
63
+ Utils.getService("@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
64
+ }
65
+ return Utils._generator.generateUUID().toString();
66
+ };
67
+
68
+
69
+ Utils.newInstance = function(className, interfaceName) {
70
+ var clazz = Components.classes[className];
71
+
72
+ if (!clazz)
73
+ return undefined;
74
+
75
+ var iface = Components.interfaces[interfaceName];
76
+ return clazz.createInstance(iface);
77
+ };
78
+
79
+
80
+ Utils.getService = function(className, serviceName) {
81
+ var clazz = Components.classes[className];
82
+ if (clazz == undefined) {
83
+ throw new Exception();
84
+ }
85
+
86
+ return clazz.getService(Components.interfaces[serviceName]);
87
+ };
88
+
89
+
90
+ Utils.getServer = function() {
91
+ var handle =
92
+ Utils.newInstance("@googlecode.com/webdriver/fxdriver;1", "nsISupports");
93
+ return handle.wrappedJSObject;
94
+ };
95
+
96
+
97
+ Utils.getBrowser = function(context) {
98
+ return context.fxbrowser;
99
+ };
100
+
101
+
102
+ Utils.getDocument = function(context) {
103
+ if (context.frame) {
104
+ return context.frame.document;
105
+ }
106
+ return context.fxbrowser.contentDocument;
107
+ };
108
+
109
+
110
+ Utils.getActiveElement = function(context) {
111
+ var doc = Utils.getDocument(context);
112
+
113
+ var element;
114
+ if (doc["activeElement"]) {
115
+ element = doc.activeElement;
116
+ } else {
117
+ var commandDispatcher = Utils.getBrowser(context).ownerDocument.
118
+ commandDispatcher;
119
+
120
+ doc = Utils.getDocument(context);
121
+ element = commandDispatcher.focusedElement;
122
+
123
+ if (element && Utils.getDocument(context) != element.ownerDocument)
124
+ element = null;
125
+ }
126
+
127
+ // Default to the body
128
+ if (!element) {
129
+ element = Utils.getDocument(context).body;
130
+ }
131
+
132
+ return element;
133
+ };
134
+
135
+
136
+ function getTextFromNode(node, toReturn, textSoFar) {
137
+ if (node['tagName'] && node.tagName == "SCRIPT") {
138
+ return [toReturn, textSoFar];
139
+ }
140
+ var children = node.childNodes;
141
+
142
+ var bits;
143
+ for (var i = 0; i < children.length; i++) {
144
+ var child = children[i];
145
+
146
+ // Do we need to collapse the text so far?
147
+ if (child["tagName"] && child.tagName == "PRE") {
148
+ toReturn += collapseWhitespace(textSoFar);
149
+ textSoFar = "";
150
+ bits = getTextFromNode(child, toReturn, "", true);
151
+ toReturn += bits[1];
152
+ continue;
153
+ }
154
+
155
+ // Or is this just plain text?
156
+ if (child.nodeName == "#text") {
157
+ if (Utils.isDisplayed(child, false)) {
158
+ var textToAdd = child.nodeValue;
159
+ textToAdd =
160
+ textToAdd.replace(new RegExp(String.fromCharCode(160), "gm"), " ");
161
+ textSoFar += textToAdd;
162
+ }
163
+ continue;
164
+ }
165
+
166
+ // Treat as another child node.
167
+ bits = getTextFromNode(child, toReturn, textSoFar, false);
168
+ toReturn = bits[0];
169
+ textSoFar = bits[1];
170
+ }
171
+
172
+ if (isBlockLevel(node)) {
173
+ if (node["tagName"] && node.tagName != "PRE") {
174
+ toReturn += collapseWhitespace(textSoFar) + "\n";
175
+ textSoFar = "";
176
+ } else {
177
+ toReturn += "\n";
178
+ }
179
+ }
180
+ return [toReturn, textSoFar];
181
+ }
182
+
183
+
184
+ function isBlockLevel(node) {
185
+ if (node["tagName"] && node.tagName == "BR")
186
+ return true;
187
+
188
+ try {
189
+ // Should we think about getting hold of the current document?
190
+ return "block" == Utils.getStyleProperty(node, "display");
191
+ } catch (e) {
192
+ return false;
193
+ }
194
+ }
195
+
196
+
197
+ Utils.isInHead = function(element) {
198
+ while (element) {
199
+ if (element.tagName && element.tagName.toLowerCase() == "head") {
200
+ return true;
201
+ }
202
+ try {
203
+ element = element.parentNode;
204
+ } catch (e) {
205
+ // Fine. the DOM has dispeared from underneath us
206
+ return false;
207
+ }
208
+ }
209
+
210
+ return false;
211
+ };
212
+
213
+
214
+ /**
215
+ * Checks that the element is not hidden by dimensions or CSS
216
+ */
217
+ Utils.isDisplayed = function(element, scrollIfNecessary) {
218
+ // Ensure that we're dealing with an element.
219
+ var el = element;
220
+ while (el.nodeType != 1 && !(el.nodeType >= 9 && el.nodeType <= 11)) {
221
+ el = el.parentNode;
222
+ }
223
+
224
+ if (!el) {
225
+ return false;
226
+ }
227
+
228
+ // Hidden input elements are, by definition, never displayed
229
+ if (el.tagName == "input" && el.type == "hidden") {
230
+ return false;
231
+ }
232
+
233
+ var box = scrollIfNecessary ? Utils.getLocationOnceScrolledIntoView(el) : Utils.getLocation(el);
234
+ // Elements with zero width or height are never displayed
235
+ if (box.width == 0 || box.height == 0) {
236
+ return false;
237
+ }
238
+
239
+ var visibility = Utils.getStyleProperty(el, "visibility");
240
+
241
+ var _isDisplayed = function(e) {
242
+ var display = e.ownerDocument.defaultView.getComputedStyle(e, null).
243
+ getPropertyValue("display");
244
+ if (display == "none") return display;
245
+ if (e && e.parentNode && e.parentNode.style) {
246
+ return _isDisplayed(e.parentNode);
247
+ }
248
+ return undefined;
249
+ };
250
+
251
+ var displayed = _isDisplayed(el);
252
+
253
+ return displayed != "none" && visibility != "hidden";
254
+ };
255
+
256
+
257
+ /**
258
+ * Gets the computed style of a DOM {@code element}. If the computed style is
259
+ * inherited from the element's parent, the parent will be queried for its
260
+ * style value. If the style value is an RGB color string, it will be converted
261
+ * to hex ("#rrggbb").
262
+ * @param {Element} element The DOM element whose computed style to retrieve.
263
+ * @param {string} propertyName The name of the CSS style proeprty to get.
264
+ * @return {string} The computed style as a string.
265
+ */
266
+ Utils.getStyleProperty = function(element, propertyName) {
267
+ if (!element) {
268
+ return undefined;
269
+ }
270
+
271
+ var value = element.ownerDocument.defaultView.getComputedStyle(element, null).
272
+ getPropertyValue(propertyName);
273
+
274
+ if ('inherit' == value && element.parentNode.style) {
275
+ value = Utils.getStyleProperty(element.parentNode, propertyName);
276
+ }
277
+
278
+ // Convert colours to hex if possible
279
+ var raw = /rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)/.exec(value);
280
+ if (raw) {
281
+ var hex = (Number(raw[1]) << 16) +
282
+ (Number(raw[2]) << 8) +
283
+ (Number(raw[3]));
284
+ hex = (hex & 0x00ffffff) | 0x1000000;
285
+ value = '#' + hex.toString(16).substring(1);
286
+ }
287
+
288
+ return value;
289
+ };
290
+
291
+
292
+ function collapseWhitespace(textSoFar) {
293
+ return textSoFar.replace(/\s+/g, " ");
294
+ }
295
+
296
+
297
+ function getPreformattedText(node) {
298
+ var textToAdd = "";
299
+ return getTextFromNode(node, "", textToAdd, true)[1];
300
+ }
301
+
302
+
303
+ function isWhiteSpace(character) {
304
+ return character == '\n' || character == ' ' || character == '\t' || character
305
+ == '\r';
306
+ }
307
+
308
+
309
+ Utils.getText = function(element) {
310
+ var bits = getTextFromNode(element, "", "", element.tagName == "PRE");
311
+ var text = bits[0] + collapseWhitespace(bits[1]);
312
+ var start = 0;
313
+ while (start < text.length && isWhiteSpace(text[start])) {
314
+ ++start;
315
+ }
316
+ var end = text.length;
317
+ while (end > start && isWhiteSpace(text[end - 1])) {
318
+ --end;
319
+ }
320
+ return text.slice(start, end);
321
+ };
322
+
323
+
324
+ Utils.addToKnownElements = function(element, context) {
325
+ var doc = Utils.getDocument(context);
326
+ if (!doc.fxdriver_elements) {
327
+ doc.fxdriver_elements = {};
328
+ }
329
+
330
+ for (var e in doc.fxdriver_elements) {
331
+ if (doc.fxdriver_elements[e] == element) {
332
+ return e;
333
+ }
334
+ }
335
+
336
+ var id = Utils.getUniqueId();
337
+ doc.fxdriver_elements[id] = element;
338
+
339
+ return id;
340
+ };
341
+
342
+
343
+ Utils.getElementAt = function(index, context) {
344
+ var doc = Utils.getDocument(context);
345
+ var e = doc.fxdriver_elements ? doc.fxdriver_elements[index] : undefined;
346
+ if (e) {
347
+ // Is this a stale reference?
348
+ var parent = e;
349
+ while (parent && parent != e.ownerDocument.documentElement) {
350
+ parent = parent.parentNode;
351
+ }
352
+
353
+ if (parent !== e.ownerDocument.documentElement) {
354
+ // Remove from the cache
355
+ delete doc.fxdriver_elements[index];
356
+
357
+ throw new StaleElementError();
358
+ }
359
+ } else {
360
+ throw new StaleElementError();
361
+ }
362
+
363
+ return e;
364
+ };
365
+
366
+
367
+ Utils.currentDocument = function(context) {
368
+ if (context) {
369
+ return Utils.getDocument(context);
370
+ } else {
371
+ return document;
372
+ }
373
+ };
374
+
375
+
376
+ Utils.platform = function(context) {
377
+ if (!this.userAgentPlatformLowercase) {
378
+ var currentWindow = Utils.currentDocument(context).defaultView;
379
+ this.userAgentPlatformLowercase =
380
+ currentWindow.navigator.platform.toLowerCase();
381
+ }
382
+
383
+ return this.userAgentPlatformLowercase;
384
+ };
385
+
386
+
387
+ Utils.shiftCount = 0;
388
+
389
+
390
+ Utils.getNativeEvents = function() {
391
+ try {
392
+ const cid = "@openqa.org/nativeevents;1";
393
+ var obj = Components.classes[cid].createInstance();
394
+ return obj.QueryInterface(Components.interfaces.nsINativeEvents);
395
+ } catch(e) {
396
+ // Unable to retrieve native events. No biggie, because we fall back to
397
+ // synthesis later
398
+ return undefined;
399
+ }
400
+ };
401
+
402
+
403
+ Utils.getNodeForNativeEvents = function(element) {
404
+ try {
405
+ // This stuff changes between releases.
406
+ // Do as much up-front work in JS as possible
407
+ var retrieval = Utils.newInstance(
408
+ "@mozilla.org/accessibleRetrieval;1", "nsIAccessibleRetrieval");
409
+ var accessible = retrieval.getAccessibleFor(element.ownerDocument);
410
+ var accessibleDoc =
411
+ accessible.QueryInterface(Components.interfaces.nsIAccessibleDocument);
412
+ return accessibleDoc.QueryInterface(Components.interfaces.nsISupports);
413
+ } catch(e) {
414
+ // Unable to retrieve the accessible doc
415
+ return undefined;
416
+ }
417
+ };
418
+
419
+
420
+ Utils.type = function(context, element, text, opt_useNativeEvents) {
421
+
422
+ // For consistency between native and synthesized events, convert common
423
+ // escape sequences to their Key enum aliases.
424
+ text = text.replace(new RegExp('\b', 'g'), '\uE003'). // DOM_VK_BACK_SPACE
425
+ replace(/\t/g, '\uE004'). // DOM_VK_TAB
426
+ replace(/(\r\n|\n|\r)/g, '\uE006'); // DOM_VK_RETURN
427
+
428
+ // Special-case file input elements. This is ugly, but should be okay
429
+ if (element.tagName == "INPUT") {
430
+ var inputtype = element.getAttribute("type");
431
+ if (inputtype && inputtype.toLowerCase() == "file") {
432
+ element.value = text;
433
+ Utils.fireHtmlEvent(context, element, "change");
434
+ return;
435
+ }
436
+ }
437
+
438
+ var obj = Utils.getNativeEvents();
439
+ var node = Utils.getNodeForNativeEvents(element);
440
+ const thmgr_cls = Components.classes["@mozilla.org/thread-manager;1"];
441
+
442
+ if (opt_useNativeEvents && obj && node && thmgr_cls) {
443
+
444
+ // This indicates that a the page has been unloaded
445
+ var pageHasBeenUnloaded = false;
446
+
447
+ // This is the standard indicator that a page has been unloaded, but
448
+ // due to Firefox's caching policy, will occur only when Firefox works
449
+ // *without* caching at all.
450
+ var unloadFunction = function() { pageHasBeenUnloaded = true; };
451
+
452
+ element.ownerDocument.body.addEventListener("unload",
453
+ unloadFunction, false);
454
+
455
+ // This is a Firefox specific event - See:
456
+ // https://developer.mozilla.org/En/Using_Firefox_1.5_caching
457
+ element.ownerDocument.defaultView.addEventListener("pagehide",
458
+ unloadFunction, false);
459
+
460
+ // Now do the native thing.
461
+ obj.sendKeys(node, text);
462
+
463
+ var hasEvents = {};
464
+ var threadmgr =
465
+ thmgr_cls.getService(Components.interfaces.nsIThreadManager);
466
+ var thread = threadmgr.currentThread;
467
+
468
+ do {
469
+
470
+ // This sleep is needed so that Firefox on Linux will manage to process
471
+ // all of the keyboard events before returning control to the caller
472
+ // code (otherwise the caller may not find all of the keystrokes it
473
+ // has entered).
474
+ var the_window = element.ownerDocument.defaultView;
475
+
476
+ var doneNativeEventWait = false;
477
+
478
+ if (the_window) {
479
+ the_window.setTimeout(function() {
480
+ doneNativeEventWait = true; }, 100);
481
+ }
482
+
483
+ // Do it as long as the timeout function has not been called and the
484
+ // page has not been unloaded. If the page has been unloaded, there is no
485
+ // point in waiting for other native events to be processed in this page
486
+ // as they "belong" to the next page.
487
+ while ((!doneNativeEventWait) && (!pageHasBeenUnloaded)) {
488
+ thread.processNextEvent(true);
489
+ }
490
+
491
+ obj.hasUnhandledEvents(node, hasEvents);
492
+
493
+ } while ((hasEvents.value == true) && (!pageHasBeenUnloaded));
494
+
495
+ if (pageHasBeenUnloaded) {
496
+ Utils.dumpn("Page has been reloaded while waiting for native events to "
497
+ + "be processed. Remaining events? " + hasEvents.value);
498
+ } else {
499
+ // Remove event listeners...
500
+ element.ownerDocument.body.removeEventListener("unload",
501
+ unloadFunction, false);
502
+ element.ownerDocument.defaultView.removeEventListener("pagehide",
503
+ unloadFunction, false);
504
+ }
505
+
506
+ // It is possible that, even though the native code reports all of the
507
+ // keyboard events are out of the GDK event queue, the process is not done.
508
+ // These keyboard events are converted into Javascript events - and not all
509
+ // of them may have been processed. In fact, this is the common case when
510
+ // the sleep timeout above is less than 500 msec.
511
+ // The appropriate thing to do is process all the remaining JS events.
512
+ // Only existing events in the queue should be processed - hence the call
513
+ // to processNextEvent with false.
514
+
515
+ var numExtraEventsProcessed = 0;
516
+ var hasMoreEvents = thread.processNextEvent(false);
517
+ // A safety net to prevent the code from endlessly staying in this loop,
518
+ // in case there is some source of events that's constantly generating them.
519
+ var MAX_EXTRA_EVENTS_TO_PROCESS = 150;
520
+
521
+ while ((hasMoreEvents) &&
522
+ (numExtraEventsProcessed < MAX_EXTRA_EVENTS_TO_PROCESS)) {
523
+ hasMoreEvents = thread.processNextEvent(false);
524
+ numExtraEventsProcessed += 1;
525
+ }
526
+
527
+ return;
528
+ }
529
+
530
+ Utils.dumpn("Doing sendKeys in a non-native way...")
531
+ var controlKey = false;
532
+ var shiftKey = false;
533
+ var altKey = false;
534
+ var metaKey = false;
535
+
536
+ Utils.shiftCount = 0;
537
+
538
+ var upper = text.toUpperCase();
539
+
540
+ for (var i = 0; i < text.length; i++) {
541
+ var c = text.charAt(i);
542
+
543
+ // NULL key: reset modifier key states, and continue
544
+
545
+ if (c == '\uE000') {
546
+ if (controlKey) {
547
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
548
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
549
+ controlKey = false, shiftKey, altKey, metaKey);
550
+ }
551
+
552
+ if (shiftKey) {
553
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
554
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
555
+ controlKey, shiftKey = false, altKey, metaKey);
556
+ }
557
+
558
+ if (altKey) {
559
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
560
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
561
+ controlKey, shiftKey, altKey = false, metaKey);
562
+ }
563
+
564
+ if (metaKey) {
565
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
566
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
567
+ controlKey, shiftKey, altKey, metaKey = false);
568
+ }
569
+
570
+ continue;
571
+ }
572
+
573
+ // otherwise decode keyCode, charCode, modifiers ...
574
+
575
+ var modifierEvent = "";
576
+ var charCode = 0;
577
+ var keyCode = 0;
578
+
579
+ if (c == '\uE001') {
580
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CANCEL;
581
+ } else if (c == '\uE002') {
582
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_HELP;
583
+ } else if (c == '\uE003') {
584
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_SPACE;
585
+ } else if (c == '\uE004') {
586
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_TAB;
587
+ } else if (c == '\uE005') {
588
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CLEAR;
589
+ } else if (c == '\uE006') {
590
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_RETURN;
591
+ } else if (c == '\uE007') {
592
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ENTER;
593
+ } else if (c == '\uE008') {
594
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
595
+ shiftKey = !shiftKey;
596
+ modifierEvent = shiftKey ? "keydown" : "keyup";
597
+ } else if (c == '\uE009') {
598
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
599
+ controlKey = !controlKey;
600
+ modifierEvent = controlKey ? "keydown" : "keyup";
601
+ } else if (c == '\uE00A') {
602
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
603
+ altKey = !altKey;
604
+ modifierEvent = altKey ? "keydown" : "keyup";
605
+ } else if (c == '\uE03D') {
606
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
607
+ metaKey = !metaKey;
608
+ modifierEvent = metaKey ? "keydown" : "keyup";
609
+ } else if (c == '\uE00B') {
610
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAUSE;
611
+ } else if (c == '\uE00C') {
612
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ESCAPE;
613
+ } else if (c == '\uE00D') {
614
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SPACE;
615
+ keyCode = charCode = ' '.charCodeAt(0); // printable
616
+ } else if (c == '\uE00E') {
617
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAGE_UP;
618
+ } else if (c == '\uE00F') {
619
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN;
620
+ } else if (c == '\uE010') {
621
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_END;
622
+ } else if (c == '\uE011') {
623
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_HOME;
624
+ } else if (c == '\uE012') {
625
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_LEFT;
626
+ } else if (c == '\uE013') {
627
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_UP;
628
+ } else if (c == '\uE014') {
629
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_RIGHT;
630
+ } else if (c == '\uE015') {
631
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DOWN;
632
+ } else if (c == '\uE016') {
633
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_INSERT;
634
+ } else if (c == '\uE017') {
635
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DELETE;
636
+ } else if (c == '\uE018') {
637
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SEMICOLON;
638
+ charCode = ';'.charCodeAt(0);
639
+ } else if (c == '\uE019') {
640
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_EQUALS;
641
+ charCode = '='.charCodeAt(0);
642
+ } else if (c == '\uE01A') {
643
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD0;
644
+ charCode = '0'.charCodeAt(0);
645
+ } else if (c == '\uE01B') {
646
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD1;
647
+ charCode = '1'.charCodeAt(0);
648
+ } else if (c == '\uE01C') {
649
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD2;
650
+ charCode = '2'.charCodeAt(0);
651
+ } else if (c == '\uE01D') {
652
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD3;
653
+ charCode = '3'.charCodeAt(0);
654
+ } else if (c == '\uE01E') {
655
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD4;
656
+ charCode = '4'.charCodeAt(0);
657
+ } else if (c == '\uE01F') {
658
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD5;
659
+ charCode = '5'.charCodeAt(0);
660
+ } else if (c == '\uE020') {
661
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD6;
662
+ charCode = '6'.charCodeAt(0);
663
+ } else if (c == '\uE021') {
664
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD7;
665
+ charCode = '7'.charCodeAt(0);
666
+ } else if (c == '\uE022') {
667
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD8;
668
+ charCode = '8'.charCodeAt(0);
669
+ } else if (c == '\uE023') {
670
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD9;
671
+ charCode = '9'.charCodeAt(0);
672
+ } else if (c == '\uE024') {
673
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_MULTIPLY;
674
+ charCode = '*'.charCodeAt(0);
675
+ } else if (c == '\uE025') {
676
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ADD;
677
+ charCode = '+'.charCodeAt(0);
678
+ } else if (c == '\uE026') {
679
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SEPARATOR;
680
+ charCode = ','.charCodeAt(0);
681
+ } else if (c == '\uE027') {
682
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SUBTRACT;
683
+ charCode = '-'.charCodeAt(0);
684
+ } else if (c == '\uE028') {
685
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DECIMAL;
686
+ charCode = '.'.charCodeAt(0);
687
+ } else if (c == '\uE029') {
688
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DIVIDE;
689
+ charCode = '/'.charCodeAt(0);
690
+ } else if (c == '\uE031') {
691
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F1;
692
+ } else if (c == '\uE032') {
693
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F2;
694
+ } else if (c == '\uE033') {
695
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F3;
696
+ } else if (c == '\uE034') {
697
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F4;
698
+ } else if (c == '\uE035') {
699
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F5;
700
+ } else if (c == '\uE036') {
701
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F6;
702
+ } else if (c == '\uE037') {
703
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F7;
704
+ } else if (c == '\uE038') {
705
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F8;
706
+ } else if (c == '\uE039') {
707
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F9;
708
+ } else if (c == '\uE03A') {
709
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F10;
710
+ } else if (c == '\uE03B') {
711
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F11;
712
+ } else if (c == '\uE03C') {
713
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F12;
714
+ } else if (c == ',' || c == '<') {
715
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_COMMA;
716
+ charCode = c.charCodeAt(0);
717
+ } else if (c == '.' || c == '>') {
718
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PERIOD;
719
+ charCode = c.charCodeAt(0);
720
+ } else if (c == '/' || c == '?') {
721
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SLASH;
722
+ charCode = text.charCodeAt(i);
723
+ } else if (c == '`' || c == '~') {
724
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
725
+ charCode = c.charCodeAt(0);
726
+ } else if (c == '{' || c == '[') {
727
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
728
+ charCode = c.charCodeAt(0);
729
+ } else if (c == '\\' || c == '|') {
730
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
731
+ charCode = c.charCodeAt(0);
732
+ } else if (c == '}' || c == ']') {
733
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
734
+ charCode = c.charCodeAt(0);
735
+ } else if (c == '\'' || c == '"') {
736
+ keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_QUOTE;
737
+ charCode = c.charCodeAt(0);
738
+ } else {
739
+ keyCode = upper.charCodeAt(i);
740
+ charCode = text.charCodeAt(i);
741
+ }
742
+
743
+ // generate modifier key event if needed, and continue
744
+
745
+ if (modifierEvent) {
746
+ Utils.keyEvent(context, element, modifierEvent, keyCode, 0,
747
+ controlKey, shiftKey, altKey, metaKey);
748
+ continue;
749
+ }
750
+
751
+ // otherwise, shift down if needed
752
+
753
+ var needsShift = false;
754
+ if (charCode) {
755
+ needsShift = /[A-Z\!\$\^\*\(\)\+\{\}\:\?\|~@#%&_"<>]/.test(c);
756
+ }
757
+
758
+ if (needsShift && !shiftKey) {
759
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
760
+ Utils.keyEvent(context, element, "keydown", kCode, 0,
761
+ controlKey, true, altKey, metaKey);
762
+ Utils.shiftCount += 1;
763
+ }
764
+
765
+ // generate key[down/press/up] for key
766
+
767
+ var pressCode = keyCode;
768
+ if (charCode >= 32 && charCode < 127) {
769
+ pressCode = 0;
770
+ if (!needsShift && shiftKey && charCode > 32) {
771
+ // If typing a lowercase character key and the shiftKey is down, the
772
+ // charCode should be mapped to the shifted key value. This assumes
773
+ // a default 104 international keyboard layout.
774
+ if (charCode >= 97 && charCode <= 122) {
775
+ charCode = charCode + 65 - 97; // [a-z] -> [A-Z]
776
+ } else {
777
+ var mapFrom = '`1234567890-=[]\\;\',./';
778
+ var mapTo = '~!@#$%^&*()_+{}|:"<>?';
779
+
780
+ var value = String.fromCharCode(charCode).
781
+ replace(/([\[\\\.])/g, '\\$1');
782
+ var index = mapFrom.search(value);
783
+ if (index >= 0) {
784
+ charCode = mapTo.charCodeAt(index);
785
+ }
786
+ }
787
+ }
788
+ }
789
+
790
+ var accepted =
791
+ Utils.keyEvent(context, element, "keydown", keyCode, 0,
792
+ controlKey, needsShift || shiftKey, altKey, metaKey);
793
+
794
+ Utils.keyEvent(context, element, "keypress", pressCode, charCode,
795
+ controlKey, needsShift || shiftKey, altKey, metaKey, !accepted);
796
+
797
+ Utils.keyEvent(context, element, "keyup", keyCode, 0,
798
+ controlKey, needsShift || shiftKey, altKey, metaKey);
799
+
800
+ // shift up if needed
801
+
802
+ if (needsShift && !shiftKey) {
803
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
804
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
805
+ controlKey, false, altKey, metaKey);
806
+ }
807
+ }
808
+
809
+ // exit cleanup: keyup active modifier keys
810
+
811
+ if (controlKey) {
812
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
813
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
814
+ controlKey = false, shiftKey, altKey, metaKey);
815
+ }
816
+
817
+ if (shiftKey) {
818
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
819
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
820
+ controlKey, shiftKey = false, altKey, metaKey);
821
+ }
822
+
823
+ if (altKey) {
824
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
825
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
826
+ controlKey, shiftKey, altKey = false, metaKey);
827
+ }
828
+
829
+ if (metaKey) {
830
+ var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
831
+ Utils.keyEvent(context, element, "keyup", kCode, 0,
832
+ controlKey, shiftKey, altKey, metaKey = false);
833
+ }
834
+ };
835
+
836
+
837
+ Utils.keyEvent = function(context, element, type, keyCode, charCode,
838
+ controlState, shiftState, altState, metaState,
839
+ shouldPreventDefault) {
840
+ var preventDefault = shouldPreventDefault == undefined ? false
841
+ : shouldPreventDefault;
842
+
843
+ var keyboardEvent =
844
+ Utils.currentDocument(context).createEvent("KeyEvents");
845
+ var currentView =
846
+ Utils.currentDocument(context).defaultView;
847
+
848
+ keyboardEvent.initKeyEvent(
849
+ type, // in DOMString typeArg,
850
+ true, // in boolean canBubbleArg
851
+ true, // in boolean cancelableArg
852
+ currentView, // in nsIDOMAbstractView viewArg
853
+ controlState, // in boolean ctrlKeyArg
854
+ altState, // in boolean altKeyArg
855
+ shiftState, // in boolean shiftKeyArg
856
+ metaState, // in boolean metaKeyArg
857
+ keyCode, // in unsigned long keyCodeArg
858
+ charCode); // in unsigned long charCodeArg
859
+
860
+ if (preventDefault) {
861
+ keyboardEvent.preventDefault();
862
+ }
863
+
864
+ return element.dispatchEvent(keyboardEvent);
865
+ };
866
+
867
+
868
+ Utils.fireHtmlEvent = function(context, element, eventName) {
869
+ var doc = element.ownerDocument;
870
+ var e = doc.createEvent("HTMLEvents");
871
+ e.initEvent(eventName, true, true);
872
+ return element.dispatchEvent(e);
873
+ };
874
+
875
+
876
+ Utils.findForm = function(element) {
877
+ // Are we already on an element that can be used to submit the form?
878
+ try {
879
+ element.QueryInterface(Components.interfaces.nsIDOMHTMLButtonElement);
880
+ return element;
881
+ } catch(e) {
882
+ }
883
+
884
+ try {
885
+ var input =
886
+ element.QueryInterface(Components.interfaces.nsIDOMHTMLInputElement);
887
+ if (input.type == "image" || input.type == "submit")
888
+ return input;
889
+ } catch(e) {
890
+ }
891
+
892
+ var form = element;
893
+ while (form) {
894
+ if (form["submit"])
895
+ return form;
896
+ form = form.parentNode;
897
+ }
898
+ return undefined;
899
+ };
900
+
901
+
902
+ Utils.fireMouseEventOn = function(context, element, eventName) {
903
+ Utils.triggerMouseEvent(element, eventName, 0, 0);
904
+ };
905
+
906
+
907
+ Utils.triggerMouseEvent = function(element, eventType, clientX, clientY) {
908
+ var event = element.ownerDocument.createEvent("MouseEvents");
909
+ var view = element.ownerDocument.defaultView;
910
+
911
+ event.initMouseEvent(eventType, true, true, view, 1, 0, 0, clientX, clientY,
912
+ false, false, false, false, 0, element);
913
+ element.dispatchEvent(event);
914
+ };
915
+
916
+
917
+ Utils.findDocumentInFrame = function(browser, frameId) {
918
+ var frame = Utils.findFrame(browser, frameId);
919
+ return frame ? frame.document : null;
920
+ };
921
+
922
+
923
+ Utils.findFrame = function(browser, frameId) {
924
+ var stringId = "" + frameId;
925
+ var names = stringId.split(".");
926
+ var frame = browser.contentWindow;
927
+ for (var i = 0; i < names.length; i++) {
928
+ // Try a numerical index first
929
+ var index = names[i] - 0;
930
+ if (!isNaN(index)) {
931
+ frame = frame.frames[index];
932
+ if (frame) {
933
+ return frame;
934
+ }
935
+ } else {
936
+ // Fine. Use the name and loop
937
+ var found = false;
938
+ for (var j = 0; j < frame.frames.length; j++) {
939
+ var f = frame.frames[j];
940
+ if (f.name == names[i] || f.frameElement.id == names[i]) {
941
+ frame = f;
942
+ found = true;
943
+ break;
944
+ }
945
+ }
946
+
947
+ if (!found) {
948
+ return null;
949
+ }
950
+ }
951
+ }
952
+
953
+ return frame;
954
+ };
955
+
956
+
957
+ Utils.dumpText = function(text) {
958
+ var consoleService = Utils.getService(
959
+ "@mozilla.org/consoleservice;1", "nsIConsoleService");
960
+ if (consoleService)
961
+ consoleService.logStringMessage(text);
962
+ else
963
+ dump(text);
964
+ };
965
+
966
+
967
+ Utils.dumpn = function(text) {
968
+ Utils.dumpText(text + "\n");
969
+ };
970
+
971
+
972
+ Utils.dump = function(element) {
973
+ var dump = "=============\n";
974
+
975
+ var rows = [];
976
+
977
+ dump += "Supported interfaces: ";
978
+ for (var i in Components.interfaces) {
979
+ try {
980
+ var view = element.QueryInterface(Components.interfaces[i]);
981
+ dump += i + ", ";
982
+ } catch (e) {
983
+ // Doesn't support the interface
984
+ }
985
+ }
986
+ dump += "\n------------\n";
987
+
988
+ try {
989
+ Utils.dumpProperties(element, rows);
990
+ } catch (e) {
991
+ Utils.dumpText("caught an exception: " + e);
992
+ }
993
+
994
+ rows.sort();
995
+ for (var i in rows) {
996
+ dump += rows[i] + "\n";
997
+ }
998
+
999
+ dump += "=============\n\n\n";
1000
+ Utils.dumpText(dump);
1001
+ };
1002
+
1003
+
1004
+ Utils.dumpProperties = function(view, rows) {
1005
+ for (var i in view) {
1006
+ var value = "\t" + i + ": ";
1007
+ try {
1008
+ if (typeof(view[i]) == typeof(Function)) {
1009
+ value += " function()";
1010
+ } else {
1011
+ value += String(view[i]);
1012
+ }
1013
+ } catch (e) {
1014
+ value += " Cannot obtain value";
1015
+ }
1016
+
1017
+ rows.push(value);
1018
+ }
1019
+ };
1020
+
1021
+
1022
+ Utils.stackTrace = function() {
1023
+ var stack = Components.stack;
1024
+ var i = 5;
1025
+ var dump = "";
1026
+ while (i && stack.caller) {
1027
+ stack = stack.caller;
1028
+ dump += stack + "\n";
1029
+ }
1030
+
1031
+ Utils.dumpText(dump);
1032
+ };
1033
+
1034
+
1035
+ Utils.getElementLocation = function(element, context) {
1036
+ var x = element.offsetLeft;
1037
+ var y = element.offsetTop;
1038
+ var elementParent = element.offsetParent;
1039
+ while (elementParent != null) {
1040
+ if (elementParent.tagName == "TABLE") {
1041
+ var parentBorder = parseInt(elementParent.border);
1042
+ if (isNaN(parentBorder)) {
1043
+ var parentFrame = elementParent.getAttribute('frame');
1044
+ if (parentFrame != null) {
1045
+ x += 1;
1046
+ y += 1;
1047
+ }
1048
+ } else if (parentBorder > 0) {
1049
+ x += parentBorder;
1050
+ y += parentBorder;
1051
+ }
1052
+ }
1053
+ x += elementParent.offsetLeft;
1054
+ y += elementParent.offsetTop;
1055
+ elementParent = elementParent.offsetParent;
1056
+ }
1057
+
1058
+ // Netscape can get confused in some cases, such that the height of the parent
1059
+ // is smaller than that of the element (which it shouldn't really be). If this
1060
+ // is the case, we need to exclude this element, since it will result in too
1061
+ // large a 'top' return value.
1062
+ if (element.offsetParent && element.offsetParent.offsetHeight
1063
+ && element.offsetParent.offsetHeight < element.offsetHeight) {
1064
+ // skip the parent that's too small
1065
+ element = element.offsetParent.offsetParent;
1066
+ } else {
1067
+ // Next up...
1068
+ element = element.offsetParent;
1069
+ }
1070
+ var location = new Object();
1071
+ location.x = x;
1072
+ location.y = y;
1073
+ return location;
1074
+ };
1075
+
1076
+
1077
+ Utils.findElementsByXPath = function (xpath, contextNode, context) {
1078
+ var doc = Utils.getDocument(context);
1079
+ var result = doc.evaluate(xpath, contextNode, null,
1080
+ Components.interfaces.nsIDOMXPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
1081
+ var indices = [];
1082
+ var element = result.iterateNext();
1083
+ while (element) {
1084
+ var index = Utils.addToKnownElements(element, context);
1085
+ indices.push(index);
1086
+ element = result.iterateNext();
1087
+ }
1088
+ return indices;
1089
+ };
1090
+
1091
+
1092
+ Utils.getLocation = function(element) {
1093
+ var retrieval = Utils.newInstance(
1094
+ "@mozilla.org/accessibleRetrieval;1", "nsIAccessibleRetrieval");
1095
+
1096
+ try {
1097
+ element = element.wrappedJSObject ? element.wrappedJSObject : element;
1098
+
1099
+ var clientRect = element.getBoundingClientRect();
1100
+
1101
+ // Firefox 3.5
1102
+ if (clientRect['width']) {
1103
+ return {
1104
+ x : clientRect.left + 3,
1105
+ y : clientRect.top,
1106
+ width: clientRect.width,
1107
+ height: clientRect.height
1108
+ };
1109
+ }
1110
+
1111
+ // Firefox 3.0.14 seems to have top, bottom attributes.
1112
+ if (clientRect['top'] !== undefined) {
1113
+ var retWidth = clientRect.right - clientRect.left;
1114
+ var retHeight = clientRect.bottom - clientRect.top;
1115
+ return {
1116
+ x : clientRect.left,
1117
+ y : clientRect.top,
1118
+ width: retWidth,
1119
+ height: retHeight
1120
+ }
1121
+ }
1122
+
1123
+ // Firefox 3.0, but lacking client rect
1124
+ Utils.dumpn("Falling back to firefox3 mechanism");
1125
+ var accessible = retrieval.getAccessibleFor(element);
1126
+
1127
+ var x = {}, y = {}, width = {}, height = {};
1128
+ accessible.getBounds(x, y, width, height);
1129
+
1130
+ return {
1131
+ x : clientRect.left + 3,
1132
+ y : clientRect.top,
1133
+ width: width.value,
1134
+ height: height.value
1135
+ };
1136
+ } catch(e) {
1137
+ Utils.dumpn(e);
1138
+ // Element doesn't have an accessibility node
1139
+ }
1140
+
1141
+ // Firefox 2.0
1142
+
1143
+ Utils.dumpn("Falling back to firefox2 mechanism");
1144
+ // Fallback. Use the (deprecated) method to find out where the element is in
1145
+ // the viewport. This should be fine to use because we only fall down this
1146
+ // code path on older versions of Firefox (I think!)
1147
+ var theDoc = element.ownerDocument;
1148
+ var box = theDoc.getBoxObjectFor(element);
1149
+
1150
+ // We've seen cases where width is 0, despite the element actually having
1151
+ // children with width.
1152
+ // This happens particularly with GWT.
1153
+ if (box.width == 0 || box.height == 0) {
1154
+ // Check the child, and hope the user doesn't nest this stuff. Walk the
1155
+ // children til we find an element. At this point, we know that width and
1156
+ // height are a polite fiction
1157
+ for (var i = 0; i < element.childNodes.length; i++) {
1158
+ var c = element.childNodes[i];
1159
+ if (c.nodeType == 1) {
1160
+ Utils.dumpn(
1161
+ "Width and height are ficticious values, based on child node");
1162
+ box = theDoc.getBoxObjectFor(c);
1163
+ break;
1164
+ }
1165
+ }
1166
+ }
1167
+
1168
+ return {
1169
+ x : box.x + 3,
1170
+ y : box.y,
1171
+ width: box.width,
1172
+ height: box.height
1173
+ };
1174
+ };
1175
+
1176
+
1177
+ Utils.getLocationOnceScrolledIntoView = function(element) {
1178
+ // Some elements may not a scrollIntoView function - for example,
1179
+ // elements under an SVG element. Call those only if they exist.
1180
+ if (typeof element.scrollIntoView == 'function') {
1181
+ element.scrollIntoView(true);
1182
+ }
1183
+
1184
+ return Utils.getLocation(element);
1185
+ };
1186
+
1187
+
1188
+ Utils.unwrapParameters = function(wrappedParameters, resultArray, context) {
1189
+ while (wrappedParameters && wrappedParameters.length > 0) {
1190
+ var t = wrappedParameters.shift();
1191
+
1192
+ if (t != null && t.length !== undefined && t.length != null && (t['type']
1193
+ === undefined || t['type'] == null)) {
1194
+ var innerArray = [];
1195
+ Utils.unwrapParameters(t, innerArray);
1196
+ resultArray.push(innerArray);
1197
+ return;
1198
+ }
1199
+
1200
+ if (t['type'] == "ELEMENT") {
1201
+ var element = Utils.getElementAt(t['value'], context);
1202
+ t['value'] = element.wrappedJSObject ? element.wrappedJSObject : element;
1203
+ }
1204
+
1205
+ resultArray.push(t['value']);
1206
+ }
1207
+ };
1208
+
1209
+
1210
+ Utils.isArray_ = function(obj) {
1211
+ return (obj !== undefined &&
1212
+ obj.constructor.toString().indexOf("Array") != -1);
1213
+ }
1214
+
1215
+
1216
+ Utils.isHtmlCollection_ = function(obj) {
1217
+ return (obj !== undefined && obj['length'] &&
1218
+ obj['item'] && obj['namedItem']);
1219
+ }
1220
+
1221
+
1222
+ Utils.wrapResult = function(result, context) {
1223
+ // Sophisticated.
1224
+ if (null === result || undefined === result) {
1225
+ return {type: "NULL", value: null};
1226
+ } else if (result['tagName']) {
1227
+ return {type: "ELEMENT",
1228
+ value: Utils.addToKnownElements(result, context)};
1229
+ } else if (Utils.isArray_(result) || Utils.isHtmlCollection_(result)) {
1230
+ var array = [];
1231
+ for (var i = 0; i < result.length; i++) {
1232
+ array.push(Utils.wrapResult(result[i], context));
1233
+ }
1234
+ return {type: "ARRAY", value: array};
1235
+ } else {
1236
+ return {type: "OTHER", value: result};
1237
+ }
1238
+ }
1239
+
1240
+ /**
1241
+ * Gets canonical xpath of the passed element, e.g. /HTML[1]/BODY[1]/P[1]
1242
+ */
1243
+ Utils.getXPathOfElement = function(element) {
1244
+ var path = "";
1245
+ for (; element && element.nodeType == 1; element = element.parentNode) {
1246
+ index = Utils.getElementIndexForXPath_(element);
1247
+ path = "/" + element.tagName + "[" + index + "]" + path;
1248
+ }
1249
+ return path;
1250
+ }
1251
+
1252
+ /**
1253
+ * Returns n for the nth child of the parent of that element, of type element.tagName, starting at 1
1254
+ */
1255
+ Utils.getElementIndexForXPath_ = function (element) {
1256
+ var index = 1;
1257
+ for (var sibling = element.previousSibling; sibling ; sibling = sibling.previousSibling) {
1258
+ if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
1259
+ index++;
1260
+ }
1261
+ }
1262
+ return index;
1263
+ }