nodeoffset.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright 2005 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Object to store the offset from one node to another in a way
  16. * that works on any similar DOM structure regardless of whether it is the same
  17. * actual nodes.
  18. *
  19. * @author robbyw@google.com (Robby Walker)
  20. */
  21. goog.provide('goog.dom.NodeOffset');
  22. goog.require('goog.Disposable');
  23. goog.require('goog.dom.TagName');
  24. /**
  25. * Object to store the offset from one node to another in a way that works on
  26. * any similar DOM structure regardless of whether it is the same actual nodes.
  27. * @param {Node} node The node to get the offset for.
  28. * @param {Node} baseNode The node to calculate the offset from.
  29. * @extends {goog.Disposable}
  30. * @constructor
  31. * @final
  32. */
  33. goog.dom.NodeOffset = function(node, baseNode) {
  34. goog.Disposable.call(this);
  35. /**
  36. * A stack of childNode offsets.
  37. * @type {Array<number>}
  38. * @private
  39. */
  40. this.offsetStack_ = [];
  41. /**
  42. * A stack of childNode names.
  43. * @type {Array<string>}
  44. * @private
  45. */
  46. this.nameStack_ = [];
  47. while (node && node.nodeName != goog.dom.TagName.BODY && node != baseNode) {
  48. // Compute the sibling offset.
  49. var siblingOffset = 0;
  50. var sib = node.previousSibling;
  51. while (sib) {
  52. sib = sib.previousSibling;
  53. ++siblingOffset;
  54. }
  55. this.offsetStack_.unshift(siblingOffset);
  56. this.nameStack_.unshift(node.nodeName);
  57. node = node.parentNode;
  58. }
  59. };
  60. goog.inherits(goog.dom.NodeOffset, goog.Disposable);
  61. /**
  62. * @return {string} A string representation of this object.
  63. * @override
  64. */
  65. goog.dom.NodeOffset.prototype.toString = function() {
  66. var strs = [];
  67. var name;
  68. for (var i = 0; name = this.nameStack_[i]; i++) {
  69. strs.push(this.offsetStack_[i] + ',' + name);
  70. }
  71. return strs.join('\n');
  72. };
  73. /**
  74. * Walk the dom and find the node relative to baseNode. Returns null on
  75. * failure.
  76. * @param {Node} baseNode The node to start walking from. Should be equivalent
  77. * to the node passed in to the constructor, in that it should have the
  78. * same contents.
  79. * @return {Node} The node relative to baseNode, or null on failure.
  80. */
  81. goog.dom.NodeOffset.prototype.findTargetNode = function(baseNode) {
  82. var name;
  83. var curNode = baseNode;
  84. for (var i = 0; name = this.nameStack_[i]; ++i) {
  85. curNode = curNode.childNodes[this.offsetStack_[i]];
  86. // Sanity check and make sure the element names match.
  87. if (!curNode || curNode.nodeName != name) {
  88. return null;
  89. }
  90. }
  91. return curNode;
  92. };
  93. /** @override */
  94. goog.dom.NodeOffset.prototype.disposeInternal = function() {
  95. delete this.offsetStack_;
  96. delete this.nameStack_;
  97. };