| // Copyright 2007 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| /** |
| * @fileoverview Definition of the browser range namespace and interface, as |
| * well as several useful utility functions. |
| * |
| * DO NOT USE THIS FILE DIRECTLY. Use goog.dom.Range instead. |
| * |
| * @author robbyw@google.com (Robby Walker) |
| * |
| * @supported IE6, IE7, FF1.5+, Safari. |
| */ |
| |
| |
| goog.provide('goog.dom.browserrange'); |
| goog.provide('goog.dom.browserrange.Error'); |
| |
| goog.require('goog.dom'); |
| goog.require('goog.dom.BrowserFeature'); |
| goog.require('goog.dom.NodeType'); |
| goog.require('goog.dom.browserrange.GeckoRange'); |
| goog.require('goog.dom.browserrange.IeRange'); |
| goog.require('goog.dom.browserrange.OperaRange'); |
| goog.require('goog.dom.browserrange.W3cRange'); |
| goog.require('goog.dom.browserrange.WebKitRange'); |
| goog.require('goog.userAgent'); |
| |
| |
| /** |
| * Common error constants. |
| * @enum {string} |
| */ |
| goog.dom.browserrange.Error = { |
| NOT_IMPLEMENTED: 'Not Implemented' |
| }; |
| |
| |
| // NOTE(robbyw): While it would be nice to eliminate the duplicate switches |
| // below, doing so uncovers bugs in the JsCompiler in which |
| // necessary code is stripped out. |
| |
| |
| /** |
| * Static method that returns the proper type of browser range. |
| * @param {Range|TextRange} range A browser range object. |
| * @return {!goog.dom.browserrange.AbstractRange} A wrapper object. |
| */ |
| goog.dom.browserrange.createRange = function(range) { |
| if (goog.dom.BrowserFeature.LEGACY_IE_RANGES) { |
| return new goog.dom.browserrange.IeRange( |
| /** @type {TextRange} */ (range), |
| goog.dom.getOwnerDocument(range.parentElement())); |
| } else if (goog.userAgent.WEBKIT) { |
| return new goog.dom.browserrange.WebKitRange( |
| /** @type {Range} */ (range)); |
| } else if (goog.userAgent.GECKO) { |
| return new goog.dom.browserrange.GeckoRange( |
| /** @type {Range} */ (range)); |
| } else if (goog.userAgent.OPERA) { |
| return new goog.dom.browserrange.OperaRange( |
| /** @type {Range} */ (range)); |
| } else { |
| // Default other browsers, including Opera, to W3c ranges. |
| return new goog.dom.browserrange.W3cRange( |
| /** @type {Range} */ (range)); |
| } |
| }; |
| |
| |
| /** |
| * Static method that returns the proper type of browser range. |
| * @param {Node} node The node to select. |
| * @return {!goog.dom.browserrange.AbstractRange} A wrapper object. |
| */ |
| goog.dom.browserrange.createRangeFromNodeContents = function(node) { |
| if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { |
| return goog.dom.browserrange.IeRange.createFromNodeContents(node); |
| } else if (goog.userAgent.WEBKIT) { |
| return goog.dom.browserrange.WebKitRange.createFromNodeContents(node); |
| } else if (goog.userAgent.GECKO) { |
| return goog.dom.browserrange.GeckoRange.createFromNodeContents(node); |
| } else if (goog.userAgent.OPERA) { |
| return goog.dom.browserrange.OperaRange.createFromNodeContents(node); |
| } else { |
| // Default other browsers to W3c ranges. |
| return goog.dom.browserrange.W3cRange.createFromNodeContents(node); |
| } |
| }; |
| |
| |
| /** |
| * Static method that returns the proper type of browser range. |
| * @param {Node} startNode The node to start with. |
| * @param {number} startOffset The offset within the node to start. This is |
| * either the index into the childNodes array for element startNodes or |
| * the index into the character array for text startNodes. |
| * @param {Node} endNode The node to end with. |
| * @param {number} endOffset The offset within the node to end. This is |
| * either the index into the childNodes array for element endNodes or |
| * the index into the character array for text endNodes. |
| * @return {!goog.dom.browserrange.AbstractRange} A wrapper object. |
| */ |
| goog.dom.browserrange.createRangeFromNodes = function(startNode, startOffset, |
| endNode, endOffset) { |
| if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) { |
| return goog.dom.browserrange.IeRange.createFromNodes(startNode, startOffset, |
| endNode, endOffset); |
| } else if (goog.userAgent.WEBKIT) { |
| return goog.dom.browserrange.WebKitRange.createFromNodes(startNode, |
| startOffset, endNode, endOffset); |
| } else if (goog.userAgent.GECKO) { |
| return goog.dom.browserrange.GeckoRange.createFromNodes(startNode, |
| startOffset, endNode, endOffset); |
| } else if (goog.userAgent.OPERA) { |
| return goog.dom.browserrange.OperaRange.createFromNodes(startNode, |
| startOffset, endNode, endOffset); |
| } else { |
| // Default other browsers to W3c ranges. |
| return goog.dom.browserrange.W3cRange.createFromNodes(startNode, |
| startOffset, endNode, endOffset); |
| } |
| }; |
| |
| |
| /** |
| * Tests whether the given node can contain a range end point. |
| * @param {Node} node The node to check. |
| * @return {boolean} Whether the given node can contain a range end point. |
| */ |
| goog.dom.browserrange.canContainRangeEndpoint = function(node) { |
| // NOTE(user, bloom): This is not complete, as divs with style - |
| // 'display:inline-block' or 'position:absolute' can also not contain range |
| // endpoints. A more complete check is to see if that element can be partially |
| // selected (can be container) or not. |
| return goog.dom.canHaveChildren(node) || |
| node.nodeType == goog.dom.NodeType.TEXT; |
| }; |