334 lines
11 KiB
JavaScript
334 lines
11 KiB
JavaScript
// Copyright 2008 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.
|
|
|
|
goog.provide('goog.dom.TextRangeTest');
|
|
goog.setTestOnly('goog.dom.TextRangeTest');
|
|
|
|
goog.require('goog.dom');
|
|
goog.require('goog.dom.ControlRange');
|
|
goog.require('goog.dom.Range');
|
|
goog.require('goog.dom.TextRange');
|
|
goog.require('goog.math.Coordinate');
|
|
goog.require('goog.style');
|
|
goog.require('goog.testing.ExpectedFailures');
|
|
goog.require('goog.testing.jsunit');
|
|
goog.require('goog.userAgent');
|
|
|
|
var logo;
|
|
var logo2;
|
|
var logo3;
|
|
var logo3Rtl;
|
|
var table;
|
|
var table2;
|
|
var table2div;
|
|
var test3;
|
|
var test3Rtl;
|
|
var expectedFailures;
|
|
|
|
function setUpPage() {
|
|
logo = goog.dom.getElement('logo');
|
|
logo2 = goog.dom.getElement('logo2');
|
|
logo3 = goog.dom.getElement('logo3');
|
|
logo3Rtl = goog.dom.getElement('logo3Rtl');
|
|
table = goog.dom.getElement('table');
|
|
table2 = goog.dom.getElement('table2');
|
|
table2div = goog.dom.getElement('table2div');
|
|
test3 = goog.dom.getElement('test3');
|
|
test3Rtl = goog.dom.getElement('test3Rtl');
|
|
expectedFailures = new goog.testing.ExpectedFailures();
|
|
}
|
|
|
|
function tearDown() {
|
|
expectedFailures.handleTearDown();
|
|
}
|
|
|
|
function testCreateFromNodeContents() {
|
|
assertNotNull('Text range object can be created for element node',
|
|
goog.dom.TextRange.createFromNodeContents(logo));
|
|
assertNotNull('Text range object can be created for text node',
|
|
goog.dom.TextRange.createFromNodeContents(logo2.previousSibling));
|
|
}
|
|
|
|
function testMoveToNodes() {
|
|
var range = goog.dom.TextRange.createFromNodeContents(table2);
|
|
range.moveToNodes(table2div, 0, table2div, 1, false);
|
|
assertEquals('Range should start in table2div',
|
|
table2div,
|
|
range.getStartNode());
|
|
assertEquals('Range should end in table2div',
|
|
table2div,
|
|
range.getEndNode());
|
|
assertEquals('Range start offset should be 0',
|
|
0,
|
|
range.getStartOffset());
|
|
assertEquals('Range end offset should be 0',
|
|
1,
|
|
range.getEndOffset());
|
|
assertFalse('Range should not be reversed',
|
|
range.isReversed());
|
|
range.moveToNodes(table2div, 0, table2div, 1, true);
|
|
assertTrue('Range should be reversed',
|
|
range.isReversed());
|
|
assertEquals('Range text should be "foo"',
|
|
'foo',
|
|
range.getText());
|
|
}
|
|
|
|
function testContainsTextRange() {
|
|
var range = goog.dom.TextRange.createFromNodeContents(table2);
|
|
var range2 = goog.dom.TextRange.createFromNodeContents(table2div);
|
|
assertTrue('TextRange contains other TextRange',
|
|
range.containsRange(range2));
|
|
assertFalse('TextRange does not contain other TextRange',
|
|
range2.containsRange(range));
|
|
|
|
range = goog.dom.Range.createFromNodes(
|
|
table2div.firstChild, 1, table2div.lastChild, 1);
|
|
range2 = goog.dom.TextRange.createFromNodes(
|
|
table2div.firstChild, 0, table2div.lastChild, 0);
|
|
assertTrue('TextRange partially contains other TextRange',
|
|
range2.containsRange(range, true));
|
|
assertFalse('TextRange does not fully contain other TextRange',
|
|
range2.containsRange(range, false));
|
|
}
|
|
|
|
function testContainsControlRange() {
|
|
if (goog.userAgent.IE) {
|
|
var range = goog.dom.ControlRange.createFromElements(table2);
|
|
var range2 = goog.dom.TextRange.createFromNodeContents(table2div);
|
|
assertFalse('TextRange does not contain ControlRange',
|
|
range2.containsRange(range));
|
|
range = goog.dom.ControlRange.createFromElements(logo2);
|
|
assertTrue('TextRange contains ControlRange',
|
|
range2.containsRange(range));
|
|
range = goog.dom.TextRange.createFromNodeContents(table2);
|
|
range2 = goog.dom.ControlRange.createFromElements(logo, logo2);
|
|
assertTrue('TextRange partially contains ControlRange',
|
|
range2.containsRange(range, true));
|
|
assertFalse('TextRange does not fully contain ControlRange',
|
|
range2.containsRange(range, false));
|
|
}
|
|
}
|
|
|
|
function testGetStartPosition() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
|
|
// The start node is in the top left.
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3);
|
|
var topLeft = goog.style.getPageOffset(test3.firstChild);
|
|
|
|
if (goog.userAgent.IE) {
|
|
// On IE the selection is as tall as its tallest element.
|
|
var logoPosition = goog.style.getPageOffset(logo3);
|
|
topLeft.y = logoPosition.y;
|
|
|
|
if (!goog.userAgent.isVersionOrHigher('8')) {
|
|
topLeft.x += 2;
|
|
topLeft.y += 2;
|
|
}
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getStartPosition, range));
|
|
assertObjectEquals(topLeft, result);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testGetStartPositionNotInDocument() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
expectedFailures.expectFailureFor(goog.userAgent.IE &&
|
|
!goog.userAgent.isVersionOrHigher('8'));
|
|
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3);
|
|
|
|
goog.dom.removeNode(test3);
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getStartPosition, range));
|
|
assertNull(result);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
} finally {
|
|
goog.dom.appendChild(document.body, test3);
|
|
}
|
|
}
|
|
|
|
function testGetStartPositionReversed() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
|
|
// Simulate the user selecting backwards from right-to-left.
|
|
// The start node is now in the bottom right.
|
|
var firstNode = test3.firstChild.firstChild;
|
|
var lastNode = test3.lastChild.lastChild;
|
|
var range = goog.dom.TextRange.createFromNodes(
|
|
lastNode, lastNode.nodeValue.length, firstNode, 0);
|
|
var pageOffset = goog.style.getPageOffset(test3.lastChild);
|
|
var bottomRight = new goog.math.Coordinate(
|
|
pageOffset.x + test3.lastChild.offsetWidth,
|
|
pageOffset.y + test3.lastChild.offsetHeight);
|
|
|
|
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
|
|
bottomRight.x += 2;
|
|
bottomRight.y += 2;
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getStartPosition, range));
|
|
assertObjectRoughlyEquals(bottomRight, result, 1);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testGetStartPositionRightToLeft() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
|
|
// Even in RTL content the start node is still in the top left.
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3Rtl);
|
|
var topLeft = goog.style.getPageOffset(test3Rtl.firstChild);
|
|
|
|
if (goog.userAgent.IE) {
|
|
// On IE the selection is as tall as its tallest element.
|
|
var logoPosition = goog.style.getPageOffset(logo3Rtl);
|
|
topLeft.y = logoPosition.y;
|
|
|
|
if (!goog.userAgent.isVersionOrHigher('8')) {
|
|
topLeft.x += 2;
|
|
topLeft.y += 2;
|
|
}
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getStartPosition, range));
|
|
assertObjectRoughlyEquals(topLeft, result, 0.1);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testGetEndPosition() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
|
|
// The end node is in the bottom right.
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3);
|
|
var pageOffset = goog.style.getPageOffset(test3.lastChild);
|
|
var bottomRight = new goog.math.Coordinate(
|
|
pageOffset.x + test3.lastChild.offsetWidth,
|
|
pageOffset.y + test3.lastChild.offsetHeight);
|
|
|
|
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
|
|
bottomRight.x += 6;
|
|
bottomRight.y += 2;
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getEndPosition, range));
|
|
assertObjectRoughlyEquals(bottomRight, result, 1);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testGetEndPositionNotInDocument() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
expectedFailures.expectFailureFor(goog.userAgent.IE &&
|
|
!goog.userAgent.isVersionOrHigher('8'));
|
|
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3);
|
|
|
|
goog.dom.removeNode(test3);
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getEndPosition, range));
|
|
assertNull(result);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
} finally {
|
|
goog.dom.appendChild(document.body, test3);
|
|
}
|
|
}
|
|
|
|
function testGetEndPositionReversed() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
|
|
// Simulate the user selecting backwards from right-to-left.
|
|
// The end node is now in the top left.
|
|
var firstNode = test3.firstChild.firstChild;
|
|
var lastNode = test3.lastChild.lastChild;
|
|
var range = goog.dom.TextRange.createFromNodes(
|
|
lastNode, lastNode.nodeValue.length, firstNode, 0);
|
|
var topLeft = goog.style.getPageOffset(test3.firstChild);
|
|
|
|
if (goog.userAgent.IE) {
|
|
// On IE the selection is as tall as its tallest element.
|
|
var logoPosition = goog.style.getPageOffset(logo3);
|
|
topLeft.y = logoPosition.y;
|
|
|
|
if (!goog.userAgent.isVersionOrHigher('8')) {
|
|
topLeft.x += 2;
|
|
topLeft.y += 2;
|
|
}
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getEndPosition, range));
|
|
assertObjectEquals(topLeft, result);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testGetEndPositionRightToLeft() {
|
|
expectedFailures.expectFailureFor(goog.userAgent.GECKO &&
|
|
!goog.userAgent.isVersionOrHigher('2'));
|
|
expectedFailures.expectFailureFor(goog.userAgent.IE &&
|
|
!goog.userAgent.isVersionOrHigher('8'));
|
|
|
|
// Even in RTL content the end node is still in the bottom right.
|
|
var range = goog.dom.TextRange.createFromNodeContents(test3Rtl);
|
|
var pageOffset = goog.style.getPageOffset(test3Rtl.lastChild);
|
|
var bottomRight = new goog.math.Coordinate(
|
|
pageOffset.x + test3Rtl.lastChild.offsetWidth,
|
|
pageOffset.y + test3Rtl.lastChild.offsetHeight);
|
|
|
|
if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('8')) {
|
|
bottomRight.x += 2;
|
|
bottomRight.y += 2;
|
|
}
|
|
|
|
try {
|
|
var result = assertNotThrows(goog.bind(range.getEndPosition, range));
|
|
assertObjectRoughlyEquals(bottomRight, result, 1);
|
|
} catch (e) {
|
|
expectedFailures.handleException(e);
|
|
}
|
|
}
|
|
|
|
function testCloneRangeDeep() {
|
|
var range = goog.dom.TextRange.createFromNodeContents(logo);
|
|
assertFalse(range.isCollapsed());
|
|
|
|
var cloned = range.clone();
|
|
cloned.collapse();
|
|
assertTrue(cloned.isCollapsed());
|
|
assertFalse(range.isCollapsed());
|
|
}
|