Path: blob/trunk/javascript/webdriver/atoms/attribute.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.1617goog.module('webdriver.atoms.element.attribute');18goog.module.declareLegacyNamespace();1920var TagName = goog.require('goog.dom.TagName');21var array = goog.require('goog.array');22var domCore = goog.require('bot.dom.core');232425/**26* Common aliases for properties. This maps names that users use to the correct27* property name.28*29* @const {!Object<string, string>}30*/31var PROPERTY_ALIASES = {32'class': 'className',33'readonly': 'readOnly'34};353637/**38* Used to determine whether we should return a boolean value from getAttribute.39* These are all extracted from the WHATWG spec:40*41* http://www.whatwg.org/specs/web-apps/current-work/42*43* These must all be lower-case.44*45* @const {!Array<string>}46*/47var BOOLEAN_PROPERTIES = [48'allowfullscreen',49'allowpaymentrequest',50'allowusermedia',51'async',52'autofocus',53'autoplay',54'checked',55'compact',56'complete',57'controls',58'declare',59'default',60'defaultchecked',61'defaultselected',62'defer',63'disabled',64'ended',65'formnovalidate',66'hidden',67'indeterminate',68'iscontenteditable',69'ismap',70'itemscope',71'loop',72'multiple',73'muted',74'nohref',75'nomodule',76'noresize',77'noshade',78'novalidate',79'nowrap',80'open',81'paused',82'playsinline',83'pubdate',84'readonly',85'required',86'reversed',87'scoped',88'seamless',89'seeking',90'selected',91'truespeed',92'typemustmatch',93'willvalidate'94];959697/**98* Get the value of the given property or attribute. If the "attribute" is for99* a boolean property, we return null in the case where the value is false. If100* the attribute name is "style" an attempt to convert that style into a string101* is done.102*103* @param {!Element} element The element to use.104* @param {string} attribute The name of the attribute to look up.105* @return {?string} The string value of the attribute or property, or null.106* @suppress {reportUnknownTypes}107*/108exports.get = function(element, attribute) {109var value = null;110var name = attribute.toLowerCase();111112if ('style' == name) {113value = element.style;114115if (value && !goog.isString(value)) {116value = value.cssText;117}118119return /** @type {?string} */ (value);120}121122if (('selected' == name || 'checked' == name) &&123domCore.isSelectable(element)) {124return domCore.isSelected(element) ? 'true' : null;125}126127// Our tests suggest that returning the attribute is desirable for128// the href attribute of <a> tags and the src attribute of <img> tags,129// but we normally attempt to get the property value before the attribute.130var isLink = domCore.isElement(element, TagName.A);131var isImg = domCore.isElement(element, TagName.IMG);132133// Although the attribute matters, the property is consistent. Return that in134// preference to the attribute for links and images.135if ((isImg && name == 'src') || (isLink && name == 'href')) {136value = domCore.getAttribute(element, name);137if (value) {138// We want the full URL if present139value = domCore.getProperty(element, name);140}141return /** @type {?string} */ (value);142}143144if ('spellcheck' == name) {145value = domCore.getAttribute(element, name);146if (!goog.isNull(value)) {147if (value.toLowerCase() == 'false') {148return 'false';149} else if (value.toLowerCase() == 'true') {150return 'true';151}152}153// coerce the property value to a string154return domCore.getProperty(element, name) + '';155}156157var propName = PROPERTY_ALIASES[attribute] || attribute;158if (array.contains(BOOLEAN_PROPERTIES, name)) {159value = !goog.isNull(domCore.getAttribute(element, attribute)) ||160domCore.getProperty(element, propName);161return value ? 'true' : null;162}163164var property;165try {166property = domCore.getProperty(element, propName);167} catch (e) {168// Leaves property undefined or null169}170171// 1- Call getAttribute if getProperty fails,172// i.e. property is null or undefined.173// This happens for event handlers in Firefox.174// For example, calling getProperty for 'onclick' would175// fail while getAttribute for 'onclick' will succeed and176// return the JS code of the handler.177//178// 2- When property is an object we fall back to the179// actual attribute instead.180// See issue http://code.google.com/p/selenium/issues/detail?id=966181if (!goog.isDefAndNotNull(property) || goog.isObject(property)) {182value = domCore.getAttribute(element, attribute);183} else {184value = property;185}186187// The empty string is a valid return value.188return goog.isDefAndNotNull(value) ? value.toString() : null;189};190191192193