Path: blob/trunk/javascript/webdriver/atoms/element.js
2868 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.161718/**19* @fileoverview Atoms-based implementation of the webelement interface.20*/2122goog.provide('webdriver.atoms.element');2324goog.require('bot.Keyboard.Keys');25goog.require('bot.action');26goog.require('bot.dom');27goog.require('goog.array');28goog.require('goog.math.Coordinate');29goog.require('goog.style');30goog.require('webdriver.Key');31goog.require('webdriver.atoms.element.attribute');323334/**35* @param {!Element} element The element to use.36* @return {boolean} Whether the element is checked or selected.37*/38webdriver.atoms.element.isSelected = function(element) {39// Although this method looks unloved, its compiled form is used by40// Chrome.41if (!bot.dom.isSelectable(element)) {42return false;43}4445return bot.dom.isSelected(element);46};47484950/**51* @const52* @deprecated Use webdriver.atoms.element.attribute.get() instead.53*/54webdriver.atoms.element.getAttribute = webdriver.atoms.element.attribute.get;555657/**58* Get the location of the element in page space, if it's displayed.59*60* @param {!Element} element The element to get the location for.61* @return {?goog.math.Rect} The bounding rectangle of the element.62*/63webdriver.atoms.element.getLocation = function(element) {64if (!bot.dom.isShown(element)) {65return null;66}67return goog.style.getBounds(element);68};697071/**72* Scrolls the element into the client's view and returns its position73* relative to the client viewport. If the element or region is too74* large to fit in the view, it will be aligned to the top-left of the75* container.76*77* The element should be attached to the current document.78*79* @param {!Element} elem The element to use.80* @param {!goog.math.Rect=} opt_elemRegion The region relative to the element81* to be scrolled into view.82* @return {!goog.math.Coordinate} The coordinate of the element in client83* space.84*/85webdriver.atoms.element.getLocationInView = function(elem, opt_elemRegion) {86bot.action.scrollIntoView(elem, opt_elemRegion);87var region = bot.dom.getClientRegion(elem, opt_elemRegion);88return new goog.math.Coordinate(region.left, region.top);89};909192/**93* @param {?Node} element The element to use.94* @return {boolean} Whether the element is in the HEAD tag.95* @private96* @suppress {reportUnknownTypes}97*/98webdriver.atoms.element.isInHead_ = function(element) {99while (element) {100if (element.tagName && element.tagName.toLowerCase() == 'head') {101return true;102}103try {104element = element.parentNode;105} catch (e) {106// Fine. the DOM has dispeared from underneath us107return false;108}109}110111return false;112};113114115/**116* @param {!Element} element The element to get the text from.117* @return {string} The visible text or an empty string.118*/119webdriver.atoms.element.getText = function(element) {120return bot.dom.getVisibleText(element);121};122123124/**125* Types keys on the given `element` with a virtual keyboard. Converts126* special characters from the WebDriver JSON wire protocol to the appropriate127* {@link bot.Keyboard.Key} value.128*129* @param {!Element} element The element to type upon.130* @param {!Array.<string>} keys The keys to type on the element.131* @param {?bot.Keyboard=} opt_keyboard Keyboard to use; if not provided,132* constructs one.133* @param {boolean=} opt_persistModifiers Whether modifier keys should remain134* pressed when this function ends.135* @see bot.action.type136* @see https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol137* @suppress {reportUnknownTypes}138*/139webdriver.atoms.element.type = function(140element, keys, opt_keyboard, opt_persistModifiers) {141var persistModifierKeys = !!opt_persistModifiers;142function createSequenceRecord() {143return {persist: persistModifierKeys, keys: []};144}145146/**147* @type {!Array.<{persist: boolean,148* keys: !Array.<(string|!bot.Keyboard.Key)>}>}149*/150var convertedSequences = [];151152/**153* @type {{persist: boolean,154* keys: !Array.<(string|!bot.Keyboard.Key)>}}155*/156var current = createSequenceRecord();157convertedSequences.push(current);158159goog.array.forEach(keys, function(sequence) {160goog.array.forEach(sequence.split(''), function(key) {161if (isWebDriverKey(key)) {162var webdriverKey = webdriver.atoms.element.type.JSON_TO_KEY_MAP_[key];163// goog.isNull uses ==, which accepts undefined.164if (webdriverKey === null) {165// bot.action.type does not support a "null" key, so we have to166// terminate the entire sequence to release modifier keys. If167// we currently allow modifier key state to persist across key168// sequences, we need to inject a dummy sequence that does not169// persist state so every modifier key gets released.170convertedSequences.push(current = createSequenceRecord());171if (persistModifierKeys) {172current.persist = false;173convertedSequences.push(current = createSequenceRecord());174}175} else if (goog.isDef(webdriverKey)) {176current.keys.push(webdriverKey);177} else {178throw Error('Unsupported WebDriver key: \\u' +179key.charCodeAt(0).toString(16));180}181} else {182// Handle common aliases.183switch (key) {184case '\n':185current.keys.push(bot.Keyboard.Keys.ENTER);186break;187case '\t':188current.keys.push(bot.Keyboard.Keys.TAB);189break;190case '\b':191current.keys.push(bot.Keyboard.Keys.BACKSPACE);192break;193default:194current.keys.push(key);195break;196}197}198});199});200201goog.array.forEach(convertedSequences, function(sequence) {202bot.action.type(element, sequence.keys, opt_keyboard,203sequence.persist);204});205206/**207* @param {!string|!bot.Keyboard.Key} c208* @returns {!boolean}209*/210function isWebDriverKey(c) {211return '\uE000' <= c && c <= '\uE03D';212}213};214215216/**217* Maps JSON wire protocol values to their {@link bot.Keyboard.Key} counterpart.218* @private {!Object.<?bot.Keyboard.Key>}219* @const220*/221webdriver.atoms.element.type.JSON_TO_KEY_MAP_ = {};222goog.scope(function() {223var map = webdriver.atoms.element.type.JSON_TO_KEY_MAP_;224var key = webdriver.Key;225var botKey = bot.Keyboard.Keys;226227map[key.NULL] = null;228map[key.BACK_SPACE] = botKey.BACKSPACE;229map[key.TAB] = botKey.TAB;230map[key.RETURN] = botKey.ENTER;231// This not correct, but most browsers will do the right thing.232map[key.ENTER] = botKey.ENTER;233map[key.SHIFT] = botKey.SHIFT;234map[key.CONTROL] = botKey.CONTROL;235map[key.ALT] = botKey.ALT;236map[key.PAUSE] = botKey.PAUSE;237map[key.ESCAPE] = botKey.ESC;238map[key.SPACE] = botKey.SPACE;239map[key.PAGE_UP] = botKey.PAGE_UP;240map[key.PAGE_DOWN] = botKey.PAGE_DOWN;241map[key.END] = botKey.END;242map[key.HOME] = botKey.HOME;243map[key.LEFT] = botKey.LEFT;244map[key.UP] = botKey.UP;245map[key.RIGHT] = botKey.RIGHT;246map[key.DOWN] = botKey.DOWN;247map[key.INSERT] = botKey.INSERT;248map[key.DELETE] = botKey.DELETE;249map[key.SEMICOLON] = botKey.SEMICOLON;250map[key.EQUALS] = botKey.EQUALS;251map[key.NUMPAD0] = botKey.NUM_ZERO;252map[key.NUMPAD1] = botKey.NUM_ONE;253map[key.NUMPAD2] = botKey.NUM_TWO;254map[key.NUMPAD3] = botKey.NUM_THREE;255map[key.NUMPAD4] = botKey.NUM_FOUR;256map[key.NUMPAD5] = botKey.NUM_FIVE;257map[key.NUMPAD6] = botKey.NUM_SIX;258map[key.NUMPAD7] = botKey.NUM_SEVEN;259map[key.NUMPAD8] = botKey.NUM_EIGHT;260map[key.NUMPAD9] = botKey.NUM_NINE;261map[key.MULTIPLY] = botKey.NUM_MULTIPLY;262map[key.ADD] = botKey.NUM_PLUS;263map[key.SUBTRACT] = botKey.NUM_MINUS;264map[key.DECIMAL] = botKey.NUM_PERIOD;265map[key.DIVIDE] = botKey.NUM_DIVISION;266map[key.SEPARATOR] = botKey.SEPARATOR;267map[key.F1] = botKey.F1;268map[key.F2] = botKey.F2;269map[key.F3] = botKey.F3;270map[key.F4] = botKey.F4;271map[key.F5] = botKey.F5;272map[key.F6] = botKey.F6;273map[key.F7] = botKey.F7;274map[key.F8] = botKey.F8;275map[key.F9] = botKey.F9;276map[key.F10] = botKey.F10;277map[key.F11] = botKey.F11;278map[key.F12] = botKey.F12;279map[key.META] = botKey.META;280}); // goog.scope281282283