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