browserrange.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. // Copyright 2007 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 Definition of the browser range namespace and interface, as
  16. * well as several useful utility functions.
  17. *
  18. * DO NOT USE THIS FILE DIRECTLY. Use goog.dom.Range instead.
  19. *
  20. * @author robbyw@google.com (Robby Walker)
  21. */
  22. goog.provide('goog.dom.browserrange');
  23. goog.provide('goog.dom.browserrange.Error');
  24. goog.require('goog.dom');
  25. goog.require('goog.dom.BrowserFeature');
  26. goog.require('goog.dom.NodeType');
  27. goog.require('goog.dom.browserrange.GeckoRange');
  28. goog.require('goog.dom.browserrange.IeRange');
  29. goog.require('goog.dom.browserrange.OperaRange');
  30. goog.require('goog.dom.browserrange.W3cRange');
  31. goog.require('goog.dom.browserrange.WebKitRange');
  32. goog.require('goog.userAgent');
  33. /**
  34. * Common error constants.
  35. * @enum {string}
  36. */
  37. goog.dom.browserrange.Error = {
  38. NOT_IMPLEMENTED: 'Not Implemented'
  39. };
  40. // NOTE(robbyw): While it would be nice to eliminate the duplicate switches
  41. // below, doing so uncovers bugs in the JsCompiler in which
  42. // necessary code is stripped out.
  43. /**
  44. * Static method that returns the proper type of browser range.
  45. * @param {Range|TextRange} range A browser range object.
  46. * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
  47. */
  48. goog.dom.browserrange.createRange = function(range) {
  49. if (goog.dom.BrowserFeature.LEGACY_IE_RANGES) {
  50. return new goog.dom.browserrange.IeRange(
  51. /** @type {TextRange} */ (range),
  52. goog.dom.getOwnerDocument(range.parentElement()));
  53. } else if (goog.userAgent.WEBKIT) {
  54. return new goog.dom.browserrange.WebKitRange(
  55. /** @type {Range} */ (range));
  56. } else if (goog.userAgent.GECKO) {
  57. return new goog.dom.browserrange.GeckoRange(
  58. /** @type {Range} */ (range));
  59. } else if (goog.userAgent.OPERA) {
  60. return new goog.dom.browserrange.OperaRange(
  61. /** @type {Range} */ (range));
  62. } else {
  63. // Default other browsers, including Opera, to W3c ranges.
  64. return new goog.dom.browserrange.W3cRange(
  65. /** @type {Range} */ (range));
  66. }
  67. };
  68. /**
  69. * Static method that returns the proper type of browser range.
  70. * @param {Node} node The node to select.
  71. * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
  72. */
  73. goog.dom.browserrange.createRangeFromNodeContents = function(node) {
  74. if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
  75. return goog.dom.browserrange.IeRange.createFromNodeContents(node);
  76. } else if (goog.userAgent.WEBKIT) {
  77. return goog.dom.browserrange.WebKitRange.createFromNodeContents(node);
  78. } else if (goog.userAgent.GECKO) {
  79. return goog.dom.browserrange.GeckoRange.createFromNodeContents(node);
  80. } else if (goog.userAgent.OPERA) {
  81. return goog.dom.browserrange.OperaRange.createFromNodeContents(node);
  82. } else {
  83. // Default other browsers to W3c ranges.
  84. return goog.dom.browserrange.W3cRange.createFromNodeContents(node);
  85. }
  86. };
  87. /**
  88. * Static method that returns the proper type of browser range.
  89. * @param {Node} startNode The node to start with.
  90. * @param {number} startOffset The offset within the node to start. This is
  91. * either the index into the childNodes array for element startNodes or
  92. * the index into the character array for text startNodes.
  93. * @param {Node} endNode The node to end with.
  94. * @param {number} endOffset The offset within the node to end. This is
  95. * either the index into the childNodes array for element endNodes or
  96. * the index into the character array for text endNodes.
  97. * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
  98. */
  99. goog.dom.browserrange.createRangeFromNodes = function(
  100. startNode, startOffset, endNode, endOffset) {
  101. if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
  102. return goog.dom.browserrange.IeRange.createFromNodes(
  103. startNode, startOffset, endNode, endOffset);
  104. } else if (goog.userAgent.WEBKIT) {
  105. return goog.dom.browserrange.WebKitRange.createFromNodes(
  106. startNode, startOffset, endNode, endOffset);
  107. } else if (goog.userAgent.GECKO) {
  108. return goog.dom.browserrange.GeckoRange.createFromNodes(
  109. startNode, startOffset, endNode, endOffset);
  110. } else if (goog.userAgent.OPERA) {
  111. return goog.dom.browserrange.OperaRange.createFromNodes(
  112. startNode, startOffset, endNode, endOffset);
  113. } else {
  114. // Default other browsers to W3c ranges.
  115. return goog.dom.browserrange.W3cRange.createFromNodes(
  116. startNode, startOffset, endNode, endOffset);
  117. }
  118. };
  119. /**
  120. * Tests whether the given node can contain a range end point.
  121. * @param {Node} node The node to check.
  122. * @return {boolean} Whether the given node can contain a range end point.
  123. */
  124. goog.dom.browserrange.canContainRangeEndpoint = function(node) {
  125. // NOTE(user, bloom): This is not complete, as divs with style -
  126. // 'display:inline-block' or 'position:absolute' can also not contain range
  127. // endpoints. A more complete check is to see if that element can be partially
  128. // selected (can be container) or not.
  129. return goog.dom.canHaveChildren(node) ||
  130. node.nodeType == goog.dom.NodeType.TEXT;
  131. };