Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/webdriver/atoms/element.js
2868 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
19
/**
20
* @fileoverview Atoms-based implementation of the webelement interface.
21
*/
22
23
goog.provide('webdriver.atoms.element');
24
25
goog.require('bot.Keyboard.Keys');
26
goog.require('bot.action');
27
goog.require('bot.dom');
28
goog.require('goog.array');
29
goog.require('goog.math.Coordinate');
30
goog.require('goog.style');
31
goog.require('webdriver.Key');
32
goog.require('webdriver.atoms.element.attribute');
33
34
35
/**
36
* @param {!Element} element The element to use.
37
* @return {boolean} Whether the element is checked or selected.
38
*/
39
webdriver.atoms.element.isSelected = function(element) {
40
// Although this method looks unloved, its compiled form is used by
41
// Chrome.
42
if (!bot.dom.isSelectable(element)) {
43
return false;
44
}
45
46
return bot.dom.isSelected(element);
47
};
48
49
50
51
/**
52
* @const
53
* @deprecated Use webdriver.atoms.element.attribute.get() instead.
54
*/
55
webdriver.atoms.element.getAttribute = webdriver.atoms.element.attribute.get;
56
57
58
/**
59
* Get the location of the element in page space, if it's displayed.
60
*
61
* @param {!Element} element The element to get the location for.
62
* @return {?goog.math.Rect} The bounding rectangle of the element.
63
*/
64
webdriver.atoms.element.getLocation = function(element) {
65
if (!bot.dom.isShown(element)) {
66
return null;
67
}
68
return goog.style.getBounds(element);
69
};
70
71
72
/**
73
* Scrolls the element into the client's view and returns its position
74
* relative to the client viewport. If the element or region is too
75
* large to fit in the view, it will be aligned to the top-left of the
76
* container.
77
*
78
* The element should be attached to the current document.
79
*
80
* @param {!Element} elem The element to use.
81
* @param {!goog.math.Rect=} opt_elemRegion The region relative to the element
82
* to be scrolled into view.
83
* @return {!goog.math.Coordinate} The coordinate of the element in client
84
* space.
85
*/
86
webdriver.atoms.element.getLocationInView = function(elem, opt_elemRegion) {
87
bot.action.scrollIntoView(elem, opt_elemRegion);
88
var region = bot.dom.getClientRegion(elem, opt_elemRegion);
89
return new goog.math.Coordinate(region.left, region.top);
90
};
91
92
93
/**
94
* @param {?Node} element The element to use.
95
* @return {boolean} Whether the element is in the HEAD tag.
96
* @private
97
* @suppress {reportUnknownTypes}
98
*/
99
webdriver.atoms.element.isInHead_ = function(element) {
100
while (element) {
101
if (element.tagName && element.tagName.toLowerCase() == 'head') {
102
return true;
103
}
104
try {
105
element = element.parentNode;
106
} catch (e) {
107
// Fine. the DOM has dispeared from underneath us
108
return false;
109
}
110
}
111
112
return false;
113
};
114
115
116
/**
117
* @param {!Element} element The element to get the text from.
118
* @return {string} The visible text or an empty string.
119
*/
120
webdriver.atoms.element.getText = function(element) {
121
return bot.dom.getVisibleText(element);
122
};
123
124
125
/**
126
* Types keys on the given `element` with a virtual keyboard. Converts
127
* special characters from the WebDriver JSON wire protocol to the appropriate
128
* {@link bot.Keyboard.Key} value.
129
*
130
* @param {!Element} element The element to type upon.
131
* @param {!Array.<string>} keys The keys to type on the element.
132
* @param {?bot.Keyboard=} opt_keyboard Keyboard to use; if not provided,
133
* constructs one.
134
* @param {boolean=} opt_persistModifiers Whether modifier keys should remain
135
* pressed when this function ends.
136
* @see bot.action.type
137
* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
138
* @suppress {reportUnknownTypes}
139
*/
140
webdriver.atoms.element.type = function(
141
element, keys, opt_keyboard, opt_persistModifiers) {
142
var persistModifierKeys = !!opt_persistModifiers;
143
function createSequenceRecord() {
144
return {persist: persistModifierKeys, keys: []};
145
}
146
147
/**
148
* @type {!Array.<{persist: boolean,
149
* keys: !Array.<(string|!bot.Keyboard.Key)>}>}
150
*/
151
var convertedSequences = [];
152
153
/**
154
* @type {{persist: boolean,
155
* keys: !Array.<(string|!bot.Keyboard.Key)>}}
156
*/
157
var current = createSequenceRecord();
158
convertedSequences.push(current);
159
160
goog.array.forEach(keys, function(sequence) {
161
goog.array.forEach(sequence.split(''), function(key) {
162
if (isWebDriverKey(key)) {
163
var webdriverKey = webdriver.atoms.element.type.JSON_TO_KEY_MAP_[key];
164
// goog.isNull uses ==, which accepts undefined.
165
if (webdriverKey === null) {
166
// bot.action.type does not support a "null" key, so we have to
167
// terminate the entire sequence to release modifier keys. If
168
// we currently allow modifier key state to persist across key
169
// sequences, we need to inject a dummy sequence that does not
170
// persist state so every modifier key gets released.
171
convertedSequences.push(current = createSequenceRecord());
172
if (persistModifierKeys) {
173
current.persist = false;
174
convertedSequences.push(current = createSequenceRecord());
175
}
176
} else if (goog.isDef(webdriverKey)) {
177
current.keys.push(webdriverKey);
178
} else {
179
throw Error('Unsupported WebDriver key: \\u' +
180
key.charCodeAt(0).toString(16));
181
}
182
} else {
183
// Handle common aliases.
184
switch (key) {
185
case '\n':
186
current.keys.push(bot.Keyboard.Keys.ENTER);
187
break;
188
case '\t':
189
current.keys.push(bot.Keyboard.Keys.TAB);
190
break;
191
case '\b':
192
current.keys.push(bot.Keyboard.Keys.BACKSPACE);
193
break;
194
default:
195
current.keys.push(key);
196
break;
197
}
198
}
199
});
200
});
201
202
goog.array.forEach(convertedSequences, function(sequence) {
203
bot.action.type(element, sequence.keys, opt_keyboard,
204
sequence.persist);
205
});
206
207
/**
208
* @param {!string|!bot.Keyboard.Key} c
209
* @returns {!boolean}
210
*/
211
function isWebDriverKey(c) {
212
return '\uE000' <= c && c <= '\uE03D';
213
}
214
};
215
216
217
/**
218
* Maps JSON wire protocol values to their {@link bot.Keyboard.Key} counterpart.
219
* @private {!Object.<?bot.Keyboard.Key>}
220
* @const
221
*/
222
webdriver.atoms.element.type.JSON_TO_KEY_MAP_ = {};
223
goog.scope(function() {
224
var map = webdriver.atoms.element.type.JSON_TO_KEY_MAP_;
225
var key = webdriver.Key;
226
var botKey = bot.Keyboard.Keys;
227
228
map[key.NULL] = null;
229
map[key.BACK_SPACE] = botKey.BACKSPACE;
230
map[key.TAB] = botKey.TAB;
231
map[key.RETURN] = botKey.ENTER;
232
// This not correct, but most browsers will do the right thing.
233
map[key.ENTER] = botKey.ENTER;
234
map[key.SHIFT] = botKey.SHIFT;
235
map[key.CONTROL] = botKey.CONTROL;
236
map[key.ALT] = botKey.ALT;
237
map[key.PAUSE] = botKey.PAUSE;
238
map[key.ESCAPE] = botKey.ESC;
239
map[key.SPACE] = botKey.SPACE;
240
map[key.PAGE_UP] = botKey.PAGE_UP;
241
map[key.PAGE_DOWN] = botKey.PAGE_DOWN;
242
map[key.END] = botKey.END;
243
map[key.HOME] = botKey.HOME;
244
map[key.LEFT] = botKey.LEFT;
245
map[key.UP] = botKey.UP;
246
map[key.RIGHT] = botKey.RIGHT;
247
map[key.DOWN] = botKey.DOWN;
248
map[key.INSERT] = botKey.INSERT;
249
map[key.DELETE] = botKey.DELETE;
250
map[key.SEMICOLON] = botKey.SEMICOLON;
251
map[key.EQUALS] = botKey.EQUALS;
252
map[key.NUMPAD0] = botKey.NUM_ZERO;
253
map[key.NUMPAD1] = botKey.NUM_ONE;
254
map[key.NUMPAD2] = botKey.NUM_TWO;
255
map[key.NUMPAD3] = botKey.NUM_THREE;
256
map[key.NUMPAD4] = botKey.NUM_FOUR;
257
map[key.NUMPAD5] = botKey.NUM_FIVE;
258
map[key.NUMPAD6] = botKey.NUM_SIX;
259
map[key.NUMPAD7] = botKey.NUM_SEVEN;
260
map[key.NUMPAD8] = botKey.NUM_EIGHT;
261
map[key.NUMPAD9] = botKey.NUM_NINE;
262
map[key.MULTIPLY] = botKey.NUM_MULTIPLY;
263
map[key.ADD] = botKey.NUM_PLUS;
264
map[key.SUBTRACT] = botKey.NUM_MINUS;
265
map[key.DECIMAL] = botKey.NUM_PERIOD;
266
map[key.DIVIDE] = botKey.NUM_DIVISION;
267
map[key.SEPARATOR] = botKey.SEPARATOR;
268
map[key.F1] = botKey.F1;
269
map[key.F2] = botKey.F2;
270
map[key.F3] = botKey.F3;
271
map[key.F4] = botKey.F4;
272
map[key.F5] = botKey.F5;
273
map[key.F6] = botKey.F6;
274
map[key.F7] = botKey.F7;
275
map[key.F8] = botKey.F8;
276
map[key.F9] = botKey.F9;
277
map[key.F10] = botKey.F10;
278
map[key.F11] = botKey.F11;
279
map[key.F12] = botKey.F12;
280
map[key.META] = botKey.META;
281
}); // goog.scope
282
283