Merge remote-tracking branch 'origin/master' into 449_keep_span_pool

This commit is contained in:
Daniel Imms
2017-05-07 15:49:40 -07:00
50 changed files with 9233 additions and 9251 deletions
+77
View File
@@ -0,0 +1,77 @@
/**
* @license MIT
*/
import jsdom = require('jsdom');
import { assert } from 'chai';
import { ICharMeasure, ITerminal } from '../Interfaces';
import { CharMeasure } from './CharMeasure';
describe('CharMeasure', () => {
let window: Window;
let document: Document;
let container: HTMLElement;
let charMeasure: ICharMeasure;
beforeEach(done => {
jsdom.env('', (err, w) => {
window = w;
document = window.document;
container = document.createElement('div');
document.body.appendChild(container);
charMeasure = new CharMeasure(document, container);
done();
});
});
describe('measure', () => {
it('should set _measureElement on first call', () => {
charMeasure.measure();
assert.isDefined((<any>charMeasure)._measureElement, 'CharMeasure.measure should have created _measureElement');
});
it('should be performed async on first call', done => {
assert.equal(charMeasure.width, null);
charMeasure.measure();
// Mock getBoundingClientRect since jsdom doesn't have a layout engine
(<any>charMeasure)._measureElement.getBoundingClientRect = () => {
return { width: 1, height: 1 };
};
assert.equal(charMeasure.width, null);
setTimeout(() => {
assert.equal(charMeasure.width, 1);
done();
}, 0);
});
it('should be performed sync on successive calls', done => {
charMeasure.measure();
// Mock getBoundingClientRect since jsdom doesn't have a layout engine
(<any>charMeasure)._measureElement.getBoundingClientRect = () => {
return { width: 1, height: 1 };
};
setTimeout(() => {
const firstWidth = charMeasure.width;
// Mock getBoundingClientRect since jsdom doesn't have a layout engine
(<any>charMeasure)._measureElement.getBoundingClientRect = () => {
return { width: 2, height: 2 };
};
charMeasure.measure();
assert.equal(charMeasure.width, firstWidth * 2);
done();
}, 0);
});
it('should NOT do a measure when the parent is hidden', done => {
charMeasure.measure();
setTimeout(() => {
const firstWidth = charMeasure.width;
container.style.display = 'none';
container.style.fontSize = '2em';
charMeasure.measure();
assert.equal(charMeasure.width, firstWidth);
done();
}, 0);
});
});
});
+21 -11
View File
@@ -9,13 +9,15 @@ import { EventEmitter } from '../EventEmitter.js';
* Utility class that measures the size of a character.
*/
export class CharMeasure extends EventEmitter {
private _document: Document;
private _parentElement: HTMLElement;
private _measureElement: HTMLElement;
private _width: number;
private _height: number;
constructor(parentElement: HTMLElement) {
constructor(document: Document, parentElement: HTMLElement) {
super();
this._document = document;
this._parentElement = parentElement;
}
@@ -28,24 +30,32 @@ export class CharMeasure extends EventEmitter {
}
public measure(): void {
const oldWidth = this._width;
const oldHeight = this._height;
if (!this._measureElement) {
this._measureElement = document.createElement('span');
this._measureElement = this._document.createElement('span');
this._measureElement.style.position = 'absolute';
this._measureElement.style.top = '0';
this._measureElement.style.left = '-9999em';
this._measureElement.textContent = 'W';
this._measureElement.setAttribute('aria-hidden', 'true');
this._parentElement.appendChild(this._measureElement);
// Perform _doMeasure async if the element was just attached as sometimes
// getBoundingClientRect does not return accurate values without this.
setTimeout(() => this._doMeasure(), 0);
} else {
this._doMeasure();
}
}
this._parentElement.appendChild(this._measureElement);
private _doMeasure(): void {
const geometry = this._measureElement.getBoundingClientRect();
this._width = geometry.width;
this._height = geometry.height;
this._parentElement.removeChild(this._measureElement);
if (this._width !== oldWidth || this._height !== oldHeight) {
// The element is likely currently display:none, we should retain the
// previous value.
if (geometry.width === 0 || geometry.height === 0) {
return;
}
if (this._width !== geometry.width || this._height !== geometry.height) {
this._width = geometry.width;
this._height = geometry.height;
this.emit('charsizechanged');
}
}