Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/javascript/webdriver/atoms/attribute.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
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
25
26
/**
27
* Common aliases for properties. This maps names that users use to the correct
28
* property name.
29
*
30
* @const {!Object<string, string>}
31
*/
32
var PROPERTY_ALIASES = {
33
'class': 'className',
34
'readonly': 'readOnly'
35
};
36
37
38
/**
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
*/
48
var 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
];
96
97
98
/**
99
* Get the value of the given property or attribute. If the "attribute" is for
100
* a boolean property, we return null in the case where the value is false. If
101
* the attribute name is "style" an attempt to convert that style into a string
102
* 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
*/
109
exports.get = function(element, attribute) {
110
var value = null;
111
var name = attribute.toLowerCase();
112
113
if ('style' == name) {
114
value = element.style;
115
116
if (value && !goog.isString(value)) {
117
value = value.cssText;
118
}
119
120
return /** @type {?string} */ (value);
121
}
122
123
if (('selected' == name || 'checked' == name) &&
124
domCore.isSelectable(element)) {
125
return domCore.isSelected(element) ? 'true' : null;
126
}
127
128
// Our tests suggest that returning the attribute is desirable for
129
// 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.
131
var isLink = domCore.isElement(element, TagName.A);
132
var isImg = domCore.isElement(element, TagName.IMG);
133
134
// Although the attribute matters, the property is consistent. Return that in
135
// preference to the attribute for links and images.
136
if ((isImg && name == 'src') || (isLink && name == 'href')) {
137
value = domCore.getAttribute(element, name);
138
if (value) {
139
// We want the full URL if present
140
value = domCore.getProperty(element, name);
141
}
142
return /** @type {?string} */ (value);
143
}
144
145
if ('spellcheck' == name) {
146
value = domCore.getAttribute(element, name);
147
if (!goog.isNull(value)) {
148
if (value.toLowerCase() == 'false') {
149
return 'false';
150
} else if (value.toLowerCase() == 'true') {
151
return 'true';
152
}
153
}
154
// coerce the property value to a string
155
return domCore.getProperty(element, name) + '';
156
}
157
158
var propName = PROPERTY_ALIASES[attribute] || attribute;
159
if (array.contains(BOOLEAN_PROPERTIES, name)) {
160
value = !goog.isNull(domCore.getAttribute(element, attribute)) ||
161
domCore.getProperty(element, propName);
162
return value ? 'true' : null;
163
}
164
165
var property;
166
try {
167
property = domCore.getProperty(element, propName);
168
} catch (e) {
169
// Leaves property undefined or null
170
}
171
172
// 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' would
176
// fail while getAttribute for 'onclick' will succeed and
177
// return the JS code of the handler.
178
//
179
// 2- When property is an object we fall back to the
180
// actual attribute instead.
181
// See issue http://code.google.com/p/selenium/issues/detail?id=966
182
if (!goog.isDefAndNotNull(property) || goog.isObject(property)) {
183
value = domCore.getAttribute(element, attribute);
184
} else {
185
value = property;
186
}
187
188
// The empty string is a valid return value.
189
return goog.isDefAndNotNull(value) ? value.toString() : null;
190
};
191
192
193