Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

t/153: Rect utility should work for collapsed DOM Ranges. Closes #153. #154

Merged
merged 2 commits into from
May 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions src/dom/rect.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import global from './global';
import isRange from './isrange';
import isElement from '../lib/lodash/isElement';

const rectProperties = [ 'top', 'right', 'bottom', 'left', 'width', 'height' ];

/**
* A helper class representing a `ClientRect` object, e.g. value returned by
* the native `object.getBoundingClientRect()` method. Provides a set of methods
Expand Down Expand Up @@ -54,11 +52,31 @@ export default class Rect {
enumerable: false
} );

if ( isElement( source ) || isRange( source ) ) {
source = source.getBoundingClientRect();
}
if ( isElement( source ) ) {
copyRectProperties( this, source.getBoundingClientRect() );
} else if ( isRange( source ) ) {
// Use getClientRects() when the range is collapsed.
// https://github.com/ckeditor/ckeditor5-utils/issues/153
if ( source.collapsed ) {
const rects = source.getClientRects();

rectProperties.forEach( p => this[ p ] = source[ p ] );
if ( rects.length ) {
copyRectProperties( this, rects[ 0 ] );
}
// If there's no client rects for the Range, use parent container's bounding
// rect instead and adjust rect's width to simulate the actual geometry of such
// range.
// https://github.com/ckeditor/ckeditor5-utils/issues/153
else {
copyRectProperties( this, source.startContainer.getBoundingClientRect() );
this.width = 0;
}
} else {
copyRectProperties( this, source.getBoundingClientRect() );
}
} else {
copyRectProperties( this, source );
}

/**
* The "top" value of the rect.
Expand Down Expand Up @@ -251,3 +269,16 @@ export default class Rect {
} );
}
}

const rectProperties = [ 'top', 'right', 'bottom', 'left', 'width', 'height' ];

// Acquires all the rect properties from the passed source.
//
// @private
// @param {module:utils/dom/rect~Rect} rect
// @param {ClientRect|module:utils/dom/rect~Rect|Object} source
function copyRectProperties( rect, source ) {
for ( const p of rectProperties ) {
rect[ p ] = source[ p ];
}
}
30 changes: 29 additions & 1 deletion tests/dom/rect.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,41 @@ describe( 'Rect', () => {
assertRect( new Rect( element ), geometry );
} );

it( 'should accept Range', () => {
it( 'should accept Range (non–collapsed)', () => {
const range = document.createRange();

range.selectNode( document.body );
testUtils.sinon.stub( range, 'getBoundingClientRect' ).returns( geometry );

assertRect( new Rect( range ), geometry );
} );

// https://github.com/ckeditor/ckeditor5-utils/issues/153
it( 'should accept Range (collapsed)', () => {
const range = document.createRange();

range.collapse();
testUtils.sinon.stub( range, 'getClientRects' ).returns( [ geometry ] );

assertRect( new Rect( range ), geometry );
} );

// https://github.com/ckeditor/ckeditor5-utils/issues/153
it( 'should accept Range (collapsed, no Range rects available)', () => {
const range = document.createRange();
const element = document.createElement( 'div' );

range.setStart( element, 0 );
range.collapse();
testUtils.sinon.stub( range, 'getClientRects' ).returns( [] );
testUtils.sinon.stub( element, 'getBoundingClientRect' ).returns( geometry );

const expectedGeometry = Object.assign( {}, geometry );
expectedGeometry.width = 0;

assertRect( new Rect( range ), expectedGeometry );
} );

it( 'should accept Rect', () => {
const sourceRect = new Rect( geometry );
const rect = new Rect( sourceRect );
Expand Down Expand Up @@ -481,6 +508,7 @@ describe( 'Rect', () => {

it( 'should return the visible rect (Range), partially cropped', () => {
range.setStart( ancestorA, 0 );
range.setEnd( ancestorA, 1 );

testUtils.sinon.stub( range, 'getBoundingClientRect' ).returns( {
top: 0,
Expand Down