api_util.js revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @fileoverview Shared util methods between api.js and api_implementation.js
7 * for doing common tasks such as passing node references between page script
8 * and ChromeVox.
9 */
10
11if (typeof(goog) != 'undefined' && goog.provide){
12  goog.provide('cvox.ApiUtil');
13}
14
15
16if (!window['cvox']) {
17   window['cvox'] = {};
18}
19
20/**
21 * @constructor
22 */
23cvox.ApiUtils = function() {
24};
25
26/**
27 * The next id to use for the cvoxid attribute that we add to elements
28 * in order to be able to find them from the content script.
29 * @type {number}
30 */
31cvox.ApiUtils.nextCvoxId_ = 1;
32
33/**
34 * Makes a serializable reference to a node.
35 * If the node or its parent has an ID, reference it directly. Otherwise,
36 * add a temporary cvoxid attribute. This has a corresponding method in
37 * api_implementation.js to decode this and return a node.
38 * @param {Node} targetNode The node to reference.
39 * @return {Object} A serializable node reference.
40 */
41cvox.ApiUtils.makeNodeReference = function(targetNode) {
42  if (targetNode.id && document.getElementById(targetNode.id) == targetNode) {
43    return {'id': targetNode.id};
44  } else if (targetNode instanceof HTMLElement) {
45    var cvoxid = cvox.ApiUtils.nextCvoxId_;
46    targetNode.setAttribute('cvoxid', cvoxid);
47    cvox.ApiUtils.nextCvoxId_ = (cvox.ApiUtils.nextCvoxId_ + 1) % 100;
48    return {'cvoxid': cvoxid};
49  } else if (targetNode.parentElement) {
50    var parent = targetNode.parentElement;
51    var childIndex = -1;
52    for (var i = 0; i < parent.childNodes.length; i++) {
53      if (parent.childNodes[i] == targetNode) {
54        childIndex = i;
55        break;
56      }
57    }
58    if (childIndex >= 0) {
59      var cvoxid = cvox.ApiUtils.nextCvoxId_;
60      parent.setAttribute('cvoxid', cvoxid);
61      cvox.ApiUtils.nextCvoxId_ = (cvox.ApiUtils.nextCvoxId_ + 1) % 100;
62      return {'cvoxid': cvoxid, 'childIndex': childIndex};
63    }
64  }
65  throw 'Cannot reference node: ' + targetNode;
66};
67
68/**
69 * Retrieves a node from its serializable node reference.
70 *
71 * @param {Object} nodeRef A serializable reference to a node.
72 * @return {Node} The node on the page that this object refers to.
73 */
74cvox.ApiUtils.getNodeFromRef = function(nodeRef) {
75  if (nodeRef['id']) {
76    return document.getElementById(nodeRef['id']);
77  } else if (nodeRef['cvoxid']) {
78    var selector = '*[cvoxid="' + nodeRef['cvoxid'] + '"]';
79    var element = document.querySelector(selector);
80    if (element && element.removeAttribute) {
81      element.removeAttribute('cvoxid');
82    }
83    if (nodeRef['childIndex'] != null) {
84      return element.childNodes[nodeRef['childIndex']];
85    } else {
86      return element;
87    }
88  }
89  throw 'Bad node reference: ' + cvox.ChromeVoxJSON.stringify(nodeRef);
90};
91