Update wmts-hidpi, add nicer-api-docs
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
// Copyright 2009 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 Trogedit unit tests for goog.editor.SeamlessField.
|
||||
*
|
||||
* @author nicksantos@google.com (Nick Santos)
|
||||
* @suppress {missingProperties} There are many mocks in this unit test,
|
||||
* and the mocks don't fit well in the type system.
|
||||
*/
|
||||
|
||||
/** @suppress {extraProvide} */
|
||||
goog.provide('goog.editor.seamlessfield_test');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.DomHelper');
|
||||
goog.require('goog.dom.Range');
|
||||
goog.require('goog.editor.BrowserFeature');
|
||||
goog.require('goog.editor.Field');
|
||||
goog.require('goog.editor.SeamlessField');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.testing.MockClock');
|
||||
goog.require('goog.testing.MockRange');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
goog.setTestOnly('seamlessfield_test');
|
||||
|
||||
var fieldElem;
|
||||
var fieldElemClone;
|
||||
|
||||
function setUp() {
|
||||
fieldElem = goog.dom.getElement('field');
|
||||
fieldElemClone = fieldElem.cloneNode(true);
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
goog.events.removeAllNativeListeners();
|
||||
fieldElem.parentNode.replaceChild(fieldElemClone, fieldElem);
|
||||
}
|
||||
|
||||
// the following tests check for blended iframe positioning. They really
|
||||
// only make sense on browsers without contentEditable.
|
||||
function testBlankField() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField(' ', {}), createSeamlessIframe());
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithContent() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField('Hi!', {}), createSeamlessIframe());
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithPadding() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField('Hi!', {'padding': '2px 5px'}),
|
||||
createSeamlessIframe());
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithMargin() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField('Hi!', {'margin': '2px 5px'}),
|
||||
createSeamlessIframe());
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithBorder() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField('Hi!', {'border': '2px 5px'}),
|
||||
createSeamlessIframe());
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithOverflow() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
assertAttachSeamlessIframeSizesCorrectly(
|
||||
initSeamlessField(['1', '2', '3', '4', '5', '6', '7'].join('<p/>'),
|
||||
{'overflow': 'auto', 'position': 'relative', 'height': '20px'}),
|
||||
createSeamlessIframe());
|
||||
assertEquals(20, fieldElem.offsetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function testFieldWithOverflowAndPadding() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
var blendedField = initSeamlessField(
|
||||
['1', '2', '3', '4', '5', '6', '7'].join('<p/>'),
|
||||
{
|
||||
'overflow': 'auto',
|
||||
'position': 'relative',
|
||||
'height': '20px',
|
||||
'padding': '2px 3px'
|
||||
});
|
||||
var blendedIframe = createSeamlessIframe();
|
||||
assertAttachSeamlessIframeSizesCorrectly(blendedField, blendedIframe);
|
||||
assertEquals(24, fieldElem.offsetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function testIframeHeightGrowsOnWrap() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
var blendedField;
|
||||
try {
|
||||
blendedField = initSeamlessField('',
|
||||
{'border': '1px solid black', 'height': '20px'});
|
||||
blendedField.makeEditable();
|
||||
blendedField.setHtml(false, 'Content that should wrap after resize.');
|
||||
|
||||
// Ensure that the field was fully loaded and sized before measuring.
|
||||
clock.tick(1);
|
||||
|
||||
// Capture starting heights.
|
||||
var unwrappedIframeHeight = blendedField.getEditableIframe().offsetHeight;
|
||||
|
||||
// Resize the field such that the text should wrap.
|
||||
fieldElem.style.width = '200px';
|
||||
blendedField.doFieldSizingGecko();
|
||||
|
||||
// Iframe should grow as a result.
|
||||
var wrappedIframeHeight = blendedField.getEditableIframe().offsetHeight;
|
||||
assertTrue('Wrapped text should cause iframe to grow - initial height: ' +
|
||||
unwrappedIframeHeight + ', wrapped height: ' + wrappedIframeHeight,
|
||||
wrappedIframeHeight > unwrappedIframeHeight);
|
||||
} finally {
|
||||
blendedField.dispose();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testDispatchIframeResizedForWrapperHeight() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
var blendedField = initSeamlessField('Hi!', {'border': '2px 5px'});
|
||||
var iframe = createSeamlessIframe();
|
||||
blendedField.attachIframe(iframe);
|
||||
|
||||
var resizeCalled = false;
|
||||
goog.events.listenOnce(
|
||||
blendedField,
|
||||
goog.editor.Field.EventType.IFRAME_RESIZED,
|
||||
function() {
|
||||
resizeCalled = true;
|
||||
});
|
||||
|
||||
try {
|
||||
blendedField.makeEditable();
|
||||
blendedField.setHtml(false, 'Content that should wrap after resize.');
|
||||
|
||||
// Ensure that the field was fully loaded and sized before measuring.
|
||||
clock.tick(1);
|
||||
|
||||
assertFalse('Iframe resize must not be dispatched yet', resizeCalled);
|
||||
|
||||
// Resize the field such that the text should wrap.
|
||||
fieldElem.style.width = '200px';
|
||||
blendedField.sizeIframeToWrapperGecko_();
|
||||
assertTrue('Iframe resize must be dispatched for Wrapper', resizeCalled);
|
||||
} finally {
|
||||
blendedField.dispose();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testDispatchIframeResizedForBodyHeight() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
var blendedField = initSeamlessField('Hi!', {'border': '2px 5px'});
|
||||
var iframe = createSeamlessIframe();
|
||||
blendedField.attachIframe(iframe);
|
||||
|
||||
var resizeCalled = false;
|
||||
goog.events.listenOnce(
|
||||
blendedField,
|
||||
goog.editor.Field.EventType.IFRAME_RESIZED,
|
||||
function() {
|
||||
resizeCalled = true;
|
||||
});
|
||||
|
||||
try {
|
||||
blendedField.makeEditable();
|
||||
blendedField.setHtml(false, 'Content that should wrap after resize.');
|
||||
|
||||
// Ensure that the field was fully loaded and sized before measuring.
|
||||
clock.tick(1);
|
||||
|
||||
assertFalse('Iframe resize must not be dispatched yet', resizeCalled);
|
||||
|
||||
// Resize the field to a different body height.
|
||||
var bodyHeight = blendedField.getIframeBodyHeightGecko_();
|
||||
blendedField.getIframeBodyHeightGecko_ = function() {
|
||||
return bodyHeight + 1;
|
||||
};
|
||||
blendedField.sizeIframeToBodyHeightGecko_();
|
||||
assertTrue('Iframe resize must be dispatched for Body', resizeCalled);
|
||||
} finally {
|
||||
blendedField.dispose();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testDispatchBlur() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE &&
|
||||
!goog.editor.BrowserFeature.CLEARS_SELECTION_WHEN_FOCUS_LEAVES) {
|
||||
var blendedField = initSeamlessField('Hi!', {'border': '2px 5px'});
|
||||
var iframe = createSeamlessIframe();
|
||||
blendedField.attachIframe(iframe);
|
||||
|
||||
var blurCalled = false;
|
||||
goog.events.listenOnce(blendedField, goog.editor.Field.EventType.BLUR,
|
||||
function() {
|
||||
blurCalled = true;
|
||||
});
|
||||
|
||||
var clearSelection = goog.dom.Range.clearSelection;
|
||||
var cleared = false;
|
||||
var clearedWindow;
|
||||
blendedField.editableDomHelper = new goog.dom.DomHelper();
|
||||
blendedField.editableDomHelper.getWindow =
|
||||
goog.functions.constant(iframe.contentWindow);
|
||||
var mockRange = new goog.testing.MockRange();
|
||||
blendedField.getRange = function() {
|
||||
return mockRange;
|
||||
};
|
||||
goog.dom.Range.clearSelection = function(opt_window) {
|
||||
clearSelection(opt_window);
|
||||
cleared = true;
|
||||
clearedWindow = opt_window;
|
||||
};
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
|
||||
mockRange.collapse(true);
|
||||
mockRange.select();
|
||||
mockRange.$replay();
|
||||
blendedField.dispatchBlur();
|
||||
clock.tick(1);
|
||||
|
||||
assertTrue('Blur must be dispatched.', blurCalled);
|
||||
assertTrue('Selection must be cleared.', cleared);
|
||||
assertEquals('Selection must be cleared in iframe',
|
||||
iframe.contentWindow, clearedWindow);
|
||||
mockRange.$verify();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function testSetMinHeight() {
|
||||
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
try {
|
||||
var field = initSeamlessField(
|
||||
['1', '2', '3', '4', '5', '6', '7'].join('<p/>'),
|
||||
{'position': 'relative', 'height': '60px'});
|
||||
|
||||
// Initially create and size iframe.
|
||||
var iframe = createSeamlessIframe();
|
||||
field.attachIframe(iframe);
|
||||
field.iframeFieldLoadHandler(iframe, '', {});
|
||||
// Need to process timeouts set by load handlers.
|
||||
clock.tick(1000);
|
||||
|
||||
var normalHeight = goog.style.getSize(iframe).height;
|
||||
|
||||
var delayedChangeCalled = false;
|
||||
goog.events.listen(field, goog.editor.Field.EventType.DELAYEDCHANGE,
|
||||
function() {
|
||||
delayedChangeCalled = true;
|
||||
});
|
||||
|
||||
// Test that min height is obeyed.
|
||||
field.setMinHeight(30);
|
||||
clock.tick(1000);
|
||||
assertEquals('Iframe height must match min height.',
|
||||
30, goog.style.getSize(iframe).height);
|
||||
assertFalse('Setting min height must not cause delayed change event.',
|
||||
delayedChangeCalled);
|
||||
|
||||
// Test that min height doesn't shrink field.
|
||||
field.setMinHeight(0);
|
||||
clock.tick(1000);
|
||||
assertEquals(normalHeight, goog.style.getSize(iframe).height);
|
||||
assertFalse('Setting min height must not cause delayed change event.',
|
||||
delayedChangeCalled);
|
||||
} finally {
|
||||
goog.events.removeAllNativeListeners();
|
||||
field.dispose();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @bug 1649967 This code used to throw a Javascript error.
|
||||
*/
|
||||
function testSetMinHeightWithNoIframe() {
|
||||
if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
|
||||
try {
|
||||
var field = initSeamlessField(' ', {});
|
||||
field.makeEditable();
|
||||
field.setMinHeight(30);
|
||||
} finally {
|
||||
field.dispose();
|
||||
goog.events.removeAllNativeListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testStartChangeEvents() {
|
||||
if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
|
||||
try {
|
||||
var field = initSeamlessField(' ', {});
|
||||
field.makeEditable();
|
||||
|
||||
var changeCalled = false;
|
||||
goog.events.listenOnce(field, goog.editor.Field.EventType.CHANGE,
|
||||
function() {
|
||||
changeCalled = true;
|
||||
});
|
||||
|
||||
var delayedChangeCalled = false;
|
||||
goog.events.listenOnce(field, goog.editor.Field.EventType.CHANGE,
|
||||
function() {
|
||||
delayedChangeCalled = true;
|
||||
});
|
||||
|
||||
field.stopChangeEvents(true, true);
|
||||
if (field.changeTimerGecko_) {
|
||||
field.changeTimerGecko_.start();
|
||||
}
|
||||
|
||||
field.startChangeEvents();
|
||||
clock.tick(1000);
|
||||
|
||||
assertFalse(changeCalled);
|
||||
assertFalse(delayedChangeCalled);
|
||||
} finally {
|
||||
clock.dispose();
|
||||
field.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testManipulateDom() {
|
||||
// Test in blended field since that is what fires change events.
|
||||
var editableField = initSeamlessField(' ', {});
|
||||
var clock = new goog.testing.MockClock(true);
|
||||
|
||||
var delayedChangeCalled = 0;
|
||||
goog.events.listen(editableField, goog.editor.Field.EventType.DELAYEDCHANGE,
|
||||
function() {
|
||||
delayedChangeCalled++;
|
||||
});
|
||||
|
||||
assertFalse(editableField.isLoaded());
|
||||
editableField.manipulateDom(goog.nullFunction);
|
||||
clock.tick(1000);
|
||||
assertEquals('Must not fire delayed change events if field is not loaded.',
|
||||
0, delayedChangeCalled);
|
||||
|
||||
editableField.makeEditable();
|
||||
var usesIframe = editableField.usesIframe();
|
||||
|
||||
try {
|
||||
editableField.manipulateDom(goog.nullFunction);
|
||||
clock.tick(1000); // Wait for delayed change to fire.
|
||||
assertEquals('By default must fire a single delayed change event.',
|
||||
1, delayedChangeCalled);
|
||||
|
||||
editableField.manipulateDom(goog.nullFunction, true);
|
||||
clock.tick(1000); // Wait for delayed change to fire.
|
||||
assertEquals('Must prevent all delayed change events.',
|
||||
1, delayedChangeCalled);
|
||||
|
||||
editableField.manipulateDom(function() {
|
||||
this.handleChange();
|
||||
this.handleChange();
|
||||
if (this.changeTimerGecko_) {
|
||||
this.changeTimerGecko_.fire();
|
||||
}
|
||||
|
||||
this.dispatchDelayedChange_();
|
||||
this.delayedChangeTimer_.fire();
|
||||
}, false, editableField);
|
||||
clock.tick(1000); // Wait for delayed change to fire.
|
||||
assertEquals('Must ignore dispatch delayed change called within func.',
|
||||
2, delayedChangeCalled);
|
||||
} finally {
|
||||
// Ensure we always uninstall the mock clock and dispose of everything.
|
||||
editableField.dispose();
|
||||
clock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function testAttachIframe() {
|
||||
var blendedField = initSeamlessField('Hi!', {});
|
||||
var iframe = createSeamlessIframe();
|
||||
try {
|
||||
blendedField.attachIframe(iframe);
|
||||
} catch (err) {
|
||||
fail('Error occurred while attaching iframe.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createSeamlessIframe() {
|
||||
// NOTE(nicksantos): This is a reimplementation of
|
||||
// TR_EditableUtil.getIframeAttributes, but untangled for tests, and
|
||||
// specifically with what we need for blended mode.
|
||||
return goog.dom.createDom('IFRAME',
|
||||
{ 'frameBorder': '0', 'style': 'padding:0;' });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a new editable field for the field id 'field', with the given
|
||||
* innerHTML and styles.
|
||||
*
|
||||
* @param {string} innerHTML html for the field contents.
|
||||
* @param {Object} styles Key-value pairs for styles on the field.
|
||||
* @return {goog.editor.SeamlessField} The field.
|
||||
*/
|
||||
function initSeamlessField(innerHTML, styles) {
|
||||
var field = new goog.editor.SeamlessField('field');
|
||||
fieldElem.innerHTML = innerHTML;
|
||||
goog.style.setStyle(fieldElem, styles);
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure that the original field element for the given goog.editor.Field has
|
||||
* the same size before and after attaching the given iframe. If this is not
|
||||
* true, then the field will fidget while we're initializing the field,
|
||||
* and that's not what we want.
|
||||
*
|
||||
* @param {goog.editor.Field} fieldObj The field.
|
||||
* @param {HTMLIFrameElement} iframe The iframe.
|
||||
*/
|
||||
function assertAttachSeamlessIframeSizesCorrectly(fieldObj, iframe) {
|
||||
var size = goog.style.getSize(fieldObj.getOriginalElement());
|
||||
fieldObj.attachIframe(iframe);
|
||||
var newSize = goog.style.getSize(fieldObj.getOriginalElement());
|
||||
|
||||
assertEquals(size.width, newSize.width);
|
||||
assertEquals(size.height, newSize.height);
|
||||
}
|
||||
Reference in New Issue
Block a user