Skip to content

Commit 703cffb

Browse files
committed
[atoms] Cleaning up getAttribute dependencies, reducing size from 36K to 7K
The getAttribute atom had a transitive dependency on wgxpath, which was never being flagged for dead-code removal by the Closure compiler. This unnecessarily bloats the atom. As a workaround, move the atom's definition from webdriver.atoms.element.getAttribute to a new module: webdriver.atoms.element.attribute (with a single exported "get" function). Also moving all of the new module's bot.dom dependencies to a new namespace, bot.dom.core. Having to rearrange the code like this is a bit unfortunate, but I cannot figure out why the compiler is not pruning wgxpath from the atom.
1 parent 3d82e9e commit 703cffb

File tree

8 files changed

+452
-319
lines changed

8 files changed

+452
-319
lines changed

javascript/atoms/BUCK

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,28 @@ js_library(name = 'devices',
5656
)
5757

5858

59+
js_library(name = 'domcore',
60+
srcs = [
61+
"domcore.js",
62+
],
63+
deps = [
64+
':errors',
65+
':useragent',
66+
'//third_party/closure:closure',
67+
],
68+
visibility = [
69+
'//javascript/...',
70+
],
71+
)
72+
73+
5974
js_library(name = 'dom',
6075
srcs = [
6176
"dom.js",
6277
],
6378
deps = [
6479
':bot',
80+
':domcore',
6581
':color',
6682
':json',
6783
':xpath',
@@ -160,6 +176,19 @@ js_library(name = 'locators',
160176
)
161177

162178

179+
js_library(name = 'useragent',
180+
srcs = [
181+
'userAgent.js',
182+
],
183+
deps = [
184+
'//third_party/closure:closure',
185+
],
186+
visibility = [
187+
'//javascript/...',
188+
],
189+
)
190+
191+
163192
js_library(name = 'window',
164193
srcs = [
165194
'frame.js',

javascript/atoms/build.desc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ js_library(name = "all_js",
1717
js_library(name = "dom",
1818
srcs = [
1919
"dom.js",
20+
"domcore.js",
2021
])
2122

2223
js_library(name = "error_lib",

javascript/atoms/dom.js

Lines changed: 10 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ goog.provide('bot.dom');
2323

2424
goog.require('bot');
2525
goog.require('bot.color');
26+
goog.require('bot.dom.core');
2627
goog.require('bot.locators.xpath');
2728
goog.require('bot.userAgent');
2829
goog.require('goog.array');
@@ -66,18 +67,9 @@ bot.dom.getActiveElement = function(nodeOrWindow) {
6667

6768

6869
/**
69-
* Returns whether the given node is an element and, optionally, whether it has
70-
* the given tag name. If the tag name is not provided, returns true if the node
71-
* is an element, regardless of the tag name.h
72-
*
73-
* @param {Node} node The node to test.
74-
* @param {string=} opt_tagName Tag name to test the node for.
75-
* @return {boolean} Whether the node is an element with the given tag name.
70+
* @const
7671
*/
77-
bot.dom.isElement = function(node, opt_tagName) {
78-
return !!node && node.nodeType == goog.dom.NodeType.ELEMENT &&
79-
(!opt_tagName || node.tagName.toUpperCase() == opt_tagName);
80-
};
72+
bot.dom.isElement = bot.dom.core.isElement;
8173

8274

8375
/**
@@ -113,45 +105,15 @@ bot.dom.hasPointerEventsDisabled_ = function(element) {
113105

114106

115107
/**
116-
* Returns whether the element can be checked or selected.
117-
*
118-
* @param {!Element} element The element to check.
119-
* @return {boolean} Whether the element could be checked or selected.
108+
* @const
120109
*/
121-
bot.dom.isSelectable = function(element) {
122-
if (bot.dom.isElement(element, goog.dom.TagName.OPTION)) {
123-
return true;
124-
}
125-
126-
if (bot.dom.isElement(element, goog.dom.TagName.INPUT)) {
127-
var type = element.type.toLowerCase();
128-
return type == 'checkbox' || type == 'radio';
129-
}
130-
131-
return false;
132-
};
110+
bot.dom.isSelectable = bot.dom.core.isSelectable;
133111

134112

135113
/**
136-
* Returns whether the element is checked or selected.
137-
*
138-
* @param {!Element} element The element to check.
139-
* @return {boolean} Whether the element is checked or selected.
114+
* @const
140115
*/
141-
bot.dom.isSelected = function(element) {
142-
if (!bot.dom.isSelectable(element)) {
143-
throw new bot.Error(bot.ErrorCode.ELEMENT_NOT_SELECTABLE,
144-
'Element is not selectable');
145-
}
146-
147-
var propertyName = 'selected';
148-
var type = element.type && element.type.toLowerCase();
149-
if ('checkbox' == type || 'radio' == type) {
150-
propertyName = 'checked';
151-
}
152-
153-
return !!bot.dom.getProperty(element, propertyName);
154-
};
116+
bot.dom.isSelected = bot.dom.core.isSelected;
155117

156118

157119
/**
@@ -190,123 +152,15 @@ bot.dom.isFocusable = function(element) {
190152

191153

192154
/**
193-
* Looks up the given property (not to be confused with an attribute) on the
194-
* given element.
195-
*
196-
* @param {!Element} element The element to use.
197-
* @param {string} propertyName The name of the property.
198-
* @return {*} The value of the property.
199-
*/
200-
bot.dom.getProperty = function(element, propertyName) {
201-
// When an <option>'s value attribute is not set, its value property should be
202-
// its text content, but IE < 8 does not adhere to that behavior, so fix it.
203-
// http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-value-OPTION
204-
if (bot.userAgent.IE_DOC_PRE8 && propertyName == 'value' &&
205-
bot.dom.isElement(element, goog.dom.TagName.OPTION) &&
206-
goog.isNull(bot.dom.getAttribute(element, 'value'))) {
207-
return goog.dom.getRawTextContent(element);
208-
}
209-
return element[propertyName];
210-
};
211-
212-
213-
/**
214-
* Regex to split on semicolons, but not when enclosed in parens or quotes.
215-
* Helper for {@link bot.dom.standardizeStyleAttribute_}.
216-
* If the style attribute ends with a semicolon this will include an empty
217-
* string at the end of the array
218-
* @private {!RegExp}
219155
* @const
220156
*/
221-
bot.dom.SPLIT_STYLE_ATTRIBUTE_ON_SEMICOLONS_REGEXP_ =
222-
new RegExp('[;]+' +
223-
'(?=(?:(?:[^"]*"){2})*[^"]*$)' +
224-
'(?=(?:(?:[^\']*\'){2})*[^\']*$)' +
225-
'(?=(?:[^()]*\\([^()]*\\))*[^()]*$)');
157+
bot.dom.getProperty = bot.dom.core.getProperty;
226158

227159

228160
/**
229-
* Standardize a style attribute value, which includes:
230-
* (1) converting all property names lowercase
231-
* (2) ensuring it ends in a trailing semi-colon
232-
* @param {string} value The style attribute value.
233-
* @return {string} The identical value, with the formatting rules described
234-
* above applied.
235-
* @private
236-
*/
237-
bot.dom.standardizeStyleAttribute_ = function(value) {
238-
var styleArray = value.split(
239-
bot.dom.SPLIT_STYLE_ATTRIBUTE_ON_SEMICOLONS_REGEXP_);
240-
var css = [];
241-
goog.array.forEach(styleArray, function(pair) {
242-
var i = pair.indexOf(':');
243-
if (i > 0) {
244-
var keyValue = [pair.slice(0, i), pair.slice(i + 1)];
245-
if (keyValue.length == 2) {
246-
css.push(keyValue[0].toLowerCase(), ':', keyValue[1], ';');
247-
}
248-
}
249-
});
250-
css = css.join('');
251-
css = css.charAt(css.length - 1) == ';' ? css : css + ';';
252-
return css;
253-
};
254-
255-
256-
/**
257-
* Get the user-specified value of the given attribute of the element, or null
258-
* if the attribute is not present.
259-
*
260-
* <p>For boolean attributes such as "selected" or "checked", this method
261-
* returns the value of element.getAttribute(attributeName) cast to a String
262-
* when attribute is present. For modern browsers, this will be the string the
263-
* attribute is given in the HTML, but for IE8 it will be the name of the
264-
* attribute, and for IE7, it will be the string "true". To test whether a
265-
* boolean attribute is present, test whether the return value is non-null, the
266-
* same as one would for non-boolean attributes. Specifically, do *not* test
267-
* whether the boolean evaluation of the return value is true, because the value
268-
* of a boolean attribute that is present will often be the empty string.
269-
*
270-
* <p>For the style attribute, it standardizes the value by lower-casing the
271-
* property names and always including a trailing semi-colon.
272-
*
273-
* @param {!Element} element The element to use.
274-
* @param {string} attributeName The name of the attribute to return.
275-
* @return {?string} The value of the attribute or "null" if entirely missing.
161+
* @const
276162
*/
277-
bot.dom.getAttribute = function(element, attributeName) {
278-
attributeName = attributeName.toLowerCase();
279-
280-
// The style attribute should be a css text string that includes only what
281-
// the HTML element specifies itself (excluding what is inherited from parent
282-
// elements or style sheets). We standardize the format of this string via the
283-
// standardizeStyleAttribute method.
284-
if (attributeName == 'style') {
285-
return bot.dom.standardizeStyleAttribute_(element.style.cssText);
286-
}
287-
288-
// In IE doc mode < 8, the "value" attribute of an <input> is only accessible
289-
// as a property.
290-
if (bot.userAgent.IE_DOC_PRE8 && attributeName == 'value' &&
291-
bot.dom.isElement(element, goog.dom.TagName.INPUT)) {
292-
return element['value'];
293-
}
294-
295-
// In IE < 9, element.getAttributeNode will return null for some boolean
296-
// attributes that are present, such as the selected attribute on <option>
297-
// elements. This if-statement is sufficient if these cases are restricted
298-
// to boolean attributes whose reflected property names are all lowercase
299-
// (as attributeName is by this point), like "selected". We have not
300-
// found a boolean attribute for which this does not work.
301-
if (bot.userAgent.IE_DOC_PRE9 && element[attributeName] === true) {
302-
return String(element.getAttribute(attributeName));
303-
}
304-
305-
// When the attribute is not present, either attr will be null or
306-
// attr.specified will be false.
307-
var attr = element.getAttributeNode(attributeName);
308-
return (attr && attr.specified) ? attr.value : null;
309-
};
163+
bot.dom.getAttribute = bot.dom.core.getAttribute;
310164

311165

312166
/**

0 commit comments

Comments
 (0)