Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/webdriver/atoms/attribute.js
4502 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
goog.module('webdriver.atoms.element.attribute');
19
goog.module.declareLegacyNamespace();
20
21
var TagName = goog.require('goog.dom.TagName');
22
var array = goog.require('goog.array');
23
var domCore = goog.require('bot.dom.core');
24
var utils = goog.require('goog.utils');
25
26
27
/**
28
* Common aliases for properties. This maps names that users use to the correct
29
* property name.
30
*
31
* @const {!Object<string, string>}
32
*/
33
var PROPERTY_ALIASES = {
34
'class': 'className',
35
'readonly': 'readOnly'
36
};
37
38
39
/**
40
* Used to determine whether we should return a boolean value from getAttribute.
41
* These are all extracted from the WHATWG spec:
42
*
43
* http://www.whatwg.org/specs/web-apps/current-work/
44
*
45
* These must all be lower-case.
46
*
47
* @const {!Array<string>}
48
*/
49
var BOOLEAN_PROPERTIES = [
50
'allowfullscreen',
51
'allowpaymentrequest',
52
'allowusermedia',
53
'async',
54
'autofocus',
55
'autoplay',
56
'checked',
57
'compact',
58
'complete',
59
'controls',
60
'declare',
61
'default',
62
'defaultchecked',
63
'defaultselected',
64
'defer',
65
'disabled',
66
'ended',
67
'formnovalidate',
68
'hidden',
69
'indeterminate',
70
'iscontenteditable',
71
'ismap',
72
'itemscope',
73
'loop',
74
'multiple',
75
'muted',
76
'nohref',
77
'nomodule',
78
'noresize',
79
'noshade',
80
'novalidate',
81
'nowrap',
82
'open',
83
'paused',
84
'playsinline',
85
'pubdate',
86
'readonly',
87
'required',
88
'reversed',
89
'scoped',
90
'seamless',
91
'seeking',
92
'selected',
93
'truespeed',
94
'typemustmatch',
95
'willvalidate'
96
];
97
98
99
/**
100
* Get the value of the given property or attribute. If the "attribute" is for
101
* a boolean property, we return null in the case where the value is false. If
102
* the attribute name is "style" an attempt to convert that style into a string
103
* is done.
104
*
105
* @param {!Element} element The element to use.
106
* @param {string} attribute The name of the attribute to look up.
107
* @return {?string} The string value of the attribute or property, or null.
108
* @suppress {reportUnknownTypes}
109
*/
110
exports.get = function(element, attribute) {
111
var value = null;
112
var name = attribute.toLowerCase();
113
114
if ('style' == name) {
115
value = element.style;
116
117
if (value && typeof value !== 'string') {
118
value = value.cssText;
119
}
120
121
return /** @type {?string} */ (value);
122
}
123
124
if (('selected' == name || 'checked' == name) &&
125
domCore.isSelectable(element)) {
126
return domCore.isSelected(element) ? 'true' : null;
127
}
128
129
// Our tests suggest that returning the attribute is desirable for
130
// the href attribute of <a> tags and the src attribute of <img> tags,
131
// but we normally attempt to get the property value before the attribute.
132
var isLink = domCore.isElement(element, TagName.A);
133
var isImg = domCore.isElement(element, TagName.IMG);
134
135
// Although the attribute matters, the property is consistent. Return that in
136
// preference to the attribute for links and images.
137
if ((isImg && name == 'src') || (isLink && name == 'href')) {
138
value = domCore.getAttribute(element, name);
139
if (value) {
140
// We want the full URL if present
141
value = domCore.getProperty(element, name);
142
}
143
return /** @type {?string} */ (value);
144
}
145
146
if ('spellcheck' == name) {
147
value = domCore.getAttribute(element, name);
148
if (value !== null) {
149
if (value.toLowerCase() == 'false') {
150
return 'false';
151
} else if (value.toLowerCase() == 'true') {
152
return 'true';
153
}
154
}
155
// coerce the property value to a string
156
return domCore.getProperty(element, name) + '';
157
}
158
159
var propName = PROPERTY_ALIASES[attribute] || attribute;
160
if (array.contains(BOOLEAN_PROPERTIES, name)) {
161
value = domCore.getAttribute(element, attribute) !== null ||
162
domCore.getProperty(element, propName);
163
return value ? 'true' : null;
164
}
165
166
var property;
167
try {
168
property = domCore.getProperty(element, propName);
169
} catch (e) {
170
// Leaves property undefined or null
171
}
172
173
// 1- Call getAttribute if getProperty fails,
174
// i.e. property is null or undefined.
175
// This happens for event handlers in Firefox.
176
// For example, calling getProperty for 'onclick' would
177
// fail while getAttribute for 'onclick' will succeed and
178
// return the JS code of the handler.
179
//
180
// 2- When property is an object we fall back to the
181
// actual attribute instead.
182
// See issue http://code.google.com/p/selenium/issues/detail?id=966
183
if (property == null || utils.isObject(property)) {
184
value = domCore.getAttribute(element, attribute);
185
} else {
186
value = property;
187
}
188
189
// The empty string is a valid return value.
190
return value != null ? value.toString() : null;
191
};
192
193
194