Path: blob/trunk/javascript/webdriver/atoms/attribute.js
3990 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');23var utils = goog.require('goog.utils');242526/**27* Common aliases for properties. This maps names that users use to the correct28* property name.29*30* @const {!Object<string, string>}31*/32var PROPERTY_ALIASES = {33'class': 'className',34'readonly': 'readOnly'35};363738/**39* Used to determine whether we should return a boolean value from getAttribute.40* These are all extracted from the WHATWG spec:41*42* http://www.whatwg.org/specs/web-apps/current-work/43*44* These must all be lower-case.45*46* @const {!Array<string>}47*/48var BOOLEAN_PROPERTIES = [49'allowfullscreen',50'allowpaymentrequest',51'allowusermedia',52'async',53'autofocus',54'autoplay',55'checked',56'compact',57'complete',58'controls',59'declare',60'default',61'defaultchecked',62'defaultselected',63'defer',64'disabled',65'ended',66'formnovalidate',67'hidden',68'indeterminate',69'iscontenteditable',70'ismap',71'itemscope',72'loop',73'multiple',74'muted',75'nohref',76'nomodule',77'noresize',78'noshade',79'novalidate',80'nowrap',81'open',82'paused',83'playsinline',84'pubdate',85'readonly',86'required',87'reversed',88'scoped',89'seamless',90'seeking',91'selected',92'truespeed',93'typemustmatch',94'willvalidate'95];969798/**99* Get the value of the given property or attribute. If the "attribute" is for100* a boolean property, we return null in the case where the value is false. If101* the attribute name is "style" an attempt to convert that style into a string102* is done.103*104* @param {!Element} element The element to use.105* @param {string} attribute The name of the attribute to look up.106* @return {?string} The string value of the attribute or property, or null.107* @suppress {reportUnknownTypes}108*/109exports.get = function(element, attribute) {110var value = null;111var name = attribute.toLowerCase();112113if ('style' == name) {114value = element.style;115116if (value && typeof value !== 'string') {117value = value.cssText;118}119120return /** @type {?string} */ (value);121}122123if (('selected' == name || 'checked' == name) &&124domCore.isSelectable(element)) {125return domCore.isSelected(element) ? 'true' : null;126}127128// Our tests suggest that returning the attribute is desirable for129// the href attribute of <a> tags and the src attribute of <img> tags,130// but we normally attempt to get the property value before the attribute.131var isLink = domCore.isElement(element, TagName.A);132var isImg = domCore.isElement(element, TagName.IMG);133134// Although the attribute matters, the property is consistent. Return that in135// preference to the attribute for links and images.136if ((isImg && name == 'src') || (isLink && name == 'href')) {137value = domCore.getAttribute(element, name);138if (value) {139// We want the full URL if present140value = domCore.getProperty(element, name);141}142return /** @type {?string} */ (value);143}144145if ('spellcheck' == name) {146value = domCore.getAttribute(element, name);147if (value !== null) {148if (value.toLowerCase() == 'false') {149return 'false';150} else if (value.toLowerCase() == 'true') {151return 'true';152}153}154// coerce the property value to a string155return domCore.getProperty(element, name) + '';156}157158var propName = PROPERTY_ALIASES[attribute] || attribute;159if (array.contains(BOOLEAN_PROPERTIES, name)) {160value = domCore.getAttribute(element, attribute) !== null ||161domCore.getProperty(element, propName);162return value ? 'true' : null;163}164165var property;166try {167property = domCore.getProperty(element, propName);168} catch (e) {169// Leaves property undefined or null170}171172// 1- Call getAttribute if getProperty fails,173// i.e. property is null or undefined.174// This happens for event handlers in Firefox.175// For example, calling getProperty for 'onclick' would176// fail while getAttribute for 'onclick' will succeed and177// return the JS code of the handler.178//179// 2- When property is an object we fall back to the180// actual attribute instead.181// See issue http://code.google.com/p/selenium/issues/detail?id=966182if (property == null || utils.isObject(property)) {183value = domCore.getAttribute(element, attribute);184} else {185value = property;186}187188// The empty string is a valid return value.189return value != null ? value.toString() : null;190};191192193194