| Index: chrome/test/chromedriver/js/call_function.js
|
| diff --git a/chrome/test/chromedriver/js/call_function.js b/chrome/test/chromedriver/js/call_function.js
|
| index a5c9b1f985ac39c7b82ac16f57305c2ec75cabc7..6dee10578534cd64d5db4425d75241e6605d61ec 100644
|
| --- a/chrome/test/chromedriver/js/call_function.js
|
| +++ b/chrome/test/chromedriver/js/call_function.js
|
| @@ -28,6 +28,13 @@ var NodeType = {
|
| var ELEMENT_KEY = 'ELEMENT';
|
|
|
| /**
|
| + * True if using W3C Element references.
|
| + * @const
|
| + * @type {boolean}
|
| + */
|
| +var w3cEnabled = false;
|
| +
|
| +/**
|
| * True if shadow dom is enabled.
|
| * @const
|
| * @type {boolean}
|
| @@ -35,6 +42,95 @@ var ELEMENT_KEY = 'ELEMENT';
|
| var SHADOW_DOM_ENABLED = typeof ShadowRoot === 'function';
|
|
|
| /**
|
| + * Generates a unique ID to identify an element.
|
| + * @void
|
| + * @return {string} Randomly generated ID.
|
| + */
|
| +function generateUUID() {
|
| + var array = new Uint8Array(16);
|
| + window.crypto.getRandomValues(array);
|
| + array[6] = 0x40 | (array[6] & 0x0f);
|
| + array[8] = 0x80 | (array[8] & 0x3f);
|
| +
|
| + var UUID = "";
|
| + for (var i = 0; i < 16; i++) {
|
| + var temp = array[i].toString(16);
|
| + if (temp.length < 2)
|
| + temp = "0" + temp;
|
| + UUID += temp;
|
| + if (i == 3 || i == 5 || i == 7 || i == 9)
|
| + UUID += "-";
|
| + }
|
| + return UUID;
|
| +};
|
| +
|
| +/**
|
| + * A cache which maps IDs <-> cached objects for the purpose of identifying
|
| + * a script object remotely. Uses UUIDs for identification.
|
| + * @constructor
|
| + */
|
| +function CacheWithUUID() {
|
| + this.cache_ = {};
|
| +}
|
| +
|
| +CacheWithUUID.prototype = {
|
| + /**
|
| + * Stores a given item in the cache and returns a unique UUID.
|
| + *
|
| + * @param {!Object} item The item to store in the cache.
|
| + * @return {number} The UUID for the cached item.
|
| + */
|
| + storeItem: function(item) {
|
| + for (var i in this.cache_) {
|
| + if (item == this.cache_[i])
|
| + return i;
|
| + }
|
| + var id = generateUUID();
|
| + this.cache_[id] = item;
|
| + return id;
|
| + },
|
| +
|
| + /**
|
| + * Retrieves the cached object for the given ID.
|
| + *
|
| + * @param {number} id The ID for the cached item to retrieve.
|
| + * @return {!Object} The retrieved item.
|
| + */
|
| + retrieveItem: function(id) {
|
| + var item = this.cache_[id];
|
| + if (item)
|
| + return item;
|
| + var error = new Error('not in cache');
|
| + error.code = StatusCode.STALE_ELEMENT_REFERENCE;
|
| + error.message = 'element is not attached to the page document';
|
| + throw error;
|
| + },
|
| +
|
| + /**
|
| + * Clears stale items from the cache.
|
| + */
|
| + clearStale: function() {
|
| + for (var id in this.cache_) {
|
| + var node = this.cache_[id];
|
| + if (!this.isNodeReachable_(node))
|
| + delete this.cache_[id];
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * @private
|
| + * @param {!Node} node The node to check.
|
| + * @return {boolean} If the nodes is reachable.
|
| + */
|
| + isNodeReachable_: function(node) {
|
| + var nodeRoot = getNodeRootThroughAnyShadows(node);
|
| + return (nodeRoot == document);
|
| + }
|
| +
|
| +
|
| +};
|
| +
|
| +/**
|
| * A cache which maps IDs <-> cached objects for the purpose of identifying
|
| * a script object remotely.
|
| * @constructor
|
| @@ -133,12 +229,19 @@ function getNodeRootThroughAnyShadows(node) {
|
| * the current document.
|
| * @return {!Cache} The page's object cache.
|
| */
|
| -function getPageCache(opt_doc) {
|
| +function getPageCache(opt_doc, opt_w3c) {
|
| var doc = opt_doc || document;
|
| + var w3c = opt_w3c || false;
|
| var key = '$cdc_asdjflasutopfhvcZLmcfl_';
|
| - if (!(key in doc))
|
| - doc[key] = new Cache();
|
| - return doc[key];
|
| + if (w3c) {
|
| + if (!(key in doc))
|
| + doc[key] = new CacheWithUUID();
|
| + return doc[key];
|
| + } else {
|
| + if (!(key in doc))
|
| + doc[key] = new Cache();
|
| + return doc[key];
|
| + }
|
| }
|
|
|
| /**
|
| @@ -163,7 +266,7 @@ function wrap(value) {
|
| || (SHADOW_DOM_ENABLED && value instanceof ShadowRoot)) {
|
| var wrapped = {};
|
| var root = getNodeRootThroughAnyShadows(value);
|
| - wrapped[ELEMENT_KEY] = getPageCache(root).storeItem(value);
|
| + wrapped[ELEMENT_KEY] = getPageCache(root, w3cEnabled).storeItem(value);
|
| return wrapped;
|
| }
|
|
|
| @@ -209,6 +312,7 @@ function unwrap(value, cache) {
|
| * @param {function(...[*]) : *} func The function to invoke.
|
| * @param {!Array<*>} args The array of arguments to supply to the function,
|
| * which will be unwrapped before invoking the function.
|
| + * @param {boolean} w3c Whether to return a W3C compliant element reference.
|
| * @param {boolean=} opt_unwrappedReturn Whether the function's return value
|
| * should be left unwrapped.
|
| * @return {*} An object containing a status and value property, where status
|
| @@ -216,15 +320,20 @@ function unwrap(value, cache) {
|
| * unwrapped return was specified, this will be the function's pure return
|
| * value.
|
| */
|
| -function callFunction(shadowHostIds, func, args, opt_unwrappedReturn) {
|
| - var cache = getPageCache();
|
| +function callFunction(shadowHostIds, func, args, w3c, opt_unwrappedReturn) {
|
| + if (w3c) {
|
| + w3cEnabled = true;
|
| + ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf';
|
| +
|
| + }
|
| + var cache = getPageCache(null, w3cEnabled);
|
| cache.clearStale();
|
| if (shadowHostIds && SHADOW_DOM_ENABLED) {
|
| for (var i = 0; i < shadowHostIds.length; i++) {
|
| var host = cache.retrieveItem(shadowHostIds[i]);
|
| // TODO(zachconrad): Use the olderShadowRoot API when available to check
|
| // all of the shadow roots.
|
| - cache = getPageCache(host.webkitShadowRoot);
|
| + cache = getPageCache(host.webkitShadowRoot, w3cEnabled);
|
| cache.clearStale();
|
| }
|
| }
|
|
|