123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434 |
- // Copyright 2012 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 Shared tests for goog.editor.Field and ContentEditableField.
- * Since ContentEditableField switches many of the internal code paths in Field
- * (such as via usesIframe()) it's important to re-run a lot of the same tests.
- *
- * @author nicksantos@google.com (Nick Santos)
- * @author gboyer@google.com (Garrett Boyer)
- */
- /** @suppress {extraProvide} */
- goog.provide('goog.editor.field_test');
- goog.require('goog.array');
- goog.require('goog.dom');
- goog.require('goog.dom.Range');
- goog.require('goog.dom.TagName');
- goog.require('goog.dom.classlist');
- goog.require('goog.editor.BrowserFeature');
- goog.require('goog.editor.Field');
- goog.require('goog.editor.Plugin');
- goog.require('goog.editor.range');
- goog.require('goog.events');
- goog.require('goog.events.BrowserEvent');
- goog.require('goog.events.EventType');
- goog.require('goog.events.KeyCodes');
- goog.require('goog.functions');
- goog.require('goog.testing.LooseMock');
- goog.require('goog.testing.MockClock');
- goog.require('goog.testing.dom');
- goog.require('goog.testing.events');
- goog.require('goog.testing.events.Event');
- goog.require('goog.testing.recordFunction');
- goog.require('goog.userAgent');
- goog.setTestOnly('Tests for goog.editor.*Field');
- /** Constructor to use for creating the field. Set by the test HTML file. */
- var FieldConstructor;
- /** Hard-coded HTML for the tests. */
- var HTML = '<div id="testField">I am text.</div>';
- function setUp() {
- goog.dom.getElement('parent').innerHTML = HTML;
- assertTrue(
- 'FieldConstructor should be set by the test HTML file',
- goog.isFunction(FieldConstructor));
- }
- function tearDown() {
- // NOTE(nicksantos): I think IE is blowing up on this call because
- // it is lame. It manifests its lameness by throwing an exception.
- // Kudos to XT for helping me to figure this out.
- try {
- } catch (e) {
- }
- }
- // Tests for the plugin interface.
- /**
- * Dummy plugin for test usage.
- * @constructor
- * @extends {goog.editor.Plugin}
- * @final
- */
- function TestPlugin() {
- TestPlugin.base(this, 'constructor');
- this.getTrogClassId = function() { return 'TestPlugin'; };
- this.handleKeyDown = goog.nullFunction;
- this.handleKeyPress = goog.nullFunction;
- this.handleKeyUp = goog.nullFunction;
- this.handleKeyboardShortcut = goog.nullFunction;
- this.isSupportedCommand = goog.nullFunction;
- this.execCommandInternal = goog.nullFunction;
- this.queryCommandValue = goog.nullFunction;
- this.activeOnUneditableFields = goog.nullFunction;
- this.handleSelectionChange = goog.nullFunction;
- }
- goog.inherits(TestPlugin, goog.editor.Plugin);
- /**
- * Tests that calling registerPlugin will add the plugin to the
- * plugin map.
- */
- function testRegisterPlugin() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- editableField.registerPlugin(plugin);
- assertEquals(
- 'Registered plugin must be in protected plugin map.', plugin,
- editableField.plugins_[plugin.getTrogClassId()]);
- assertEquals(
- 'Plugin has a keydown handler, should be in keydown map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.KEYDOWN][0]);
- assertEquals(
- 'Plugin has a keypress handler, should be in keypress map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.KEYPRESS][0]);
- assertEquals(
- 'Plugin has a keyup handler, should be in keuup map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.KEYUP][0]);
- assertEquals(
- 'Plugin has a selectionchange handler, should be in selectionchange map',
- plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.SELECTION][0]);
- assertEquals(
- 'Plugin has a shortcut handler, should be in shortcut map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.SHORTCUT][0]);
- assertEquals(
- 'Plugin has a execCommand, should be in execCommand map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.EXEC_COMMAND][0]);
- assertEquals(
- 'Plugin has a queryCommand, should be in queryCommand map', plugin,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.QUERY_COMMAND][0]);
- assertEquals(
- 'Plugin does not have a prepareContentsHtml,' +
- 'should not be in prepareContentsHtml map',
- undefined,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.PREPARE_CONTENTS_HTML]
- [0]);
- assertEquals(
- 'Plugin does not have a cleanContentsDom,' +
- 'should not be in cleanContentsDom map',
- undefined,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.CLEAN_CONTENTS_DOM]
- [0]);
- assertEquals(
- 'Plugin does not have a cleanContentsHtml,' +
- 'should not be in cleanContentsHtml map',
- undefined,
- editableField.indexedPlugins_[goog.editor.Plugin.Op.CLEAN_CONTENTS_HTML]
- [0]);
- editableField.dispose();
- }
- /**
- * Tests that calling unregisterPlugin will remove the plugin from
- * the map.
- */
- function testUnregisterPlugin() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- editableField.registerPlugin(plugin);
- editableField.unregisterPlugin(plugin);
- assertUndefined(
- 'Unregistered plugin must not be in protected plugin map.',
- editableField.plugins_[plugin.getTrogClassId()]);
- editableField.dispose();
- }
- /**
- * Tests that registered plugins can be fetched by their id.
- */
- function testGetPluginByClassId() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- assertUndefined(
- 'Must not be able to get unregistered plugins by class id.',
- editableField.getPluginByClassId(plugin.getTrogClassId()));
- editableField.registerPlugin(plugin);
- assertEquals(
- 'Must be able to get registered plugins by class id.', plugin,
- editableField.getPluginByClassId(plugin.getTrogClassId()));
- editableField.dispose();
- }
- /**
- * Tests that plugins get auto disposed by default when the field is disposed.
- * Tests that plugins with setAutoDispose(false) do not get disposed when the
- * field is disposed.
- */
- function testDisposed_PluginAutoDispose() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var noDisposePlugin = new goog.editor.Plugin();
- noDisposePlugin.getTrogClassId = function() { return 'noDisposeId'; };
- noDisposePlugin.setAutoDispose(false);
- editableField.registerPlugin(plugin);
- editableField.registerPlugin(noDisposePlugin);
- editableField.dispose();
- assert(editableField.isDisposed());
- assertTrue(plugin.isDisposed());
- assertFalse(noDisposePlugin.isDisposed());
- }
- var STRING_KEY = String.fromCharCode(goog.events.KeyCodes.A).toLowerCase();
- /**
- * @return {goog.events.Event} Returns an event for a keyboard shortcut
- * for the letter 'a'.
- */
- function getBrowserEvent() {
- var e = new goog.events.BrowserEvent();
- e.ctrlKey = true;
- e.metaKey = true;
- e.charCode = goog.events.KeyCodes.A;
- return e;
- }
- /**
- * @param {boolean} followLinkInNewWindow Whether activating a hyperlink
- * in the editable field will open a new window or not.
- * @return {!goog.editor.Field} Returns an editable field after its load phase.
- */
- function createEditableFieldWithListeners(followLinkInNewWindow) {
- var editableField = new FieldConstructor('testField');
- editableField.setFollowLinkInNewWindow(followLinkInNewWindow);
- var originalElement = editableField.getOriginalElement();
- editableField.setupFieldObject(originalElement);
- editableField.handleFieldLoad();
- return editableField;
- }
- function getListenerTarget(editableField) {
- var elt = editableField.getElement();
- var listenerTarget = goog.editor.BrowserFeature.USE_DOCUMENT_FOR_KEY_EVENTS &&
- editableField.usesIframe() ?
- elt.ownerDocument :
- elt;
- return listenerTarget;
- }
- function assertClickDefaultActionIsCanceled(editableField) {
- var cancelClickDefaultActionListener = goog.events.getListener(
- getListenerTarget(editableField), goog.events.EventType.CLICK,
- goog.editor.Field.cancelLinkClick_, undefined, editableField);
- assertNotNull(cancelClickDefaultActionListener);
- }
- function assertClickDefaultActionIsNotCanceled(editableField) {
- var cancelClickDefaultActionListener = goog.events.getListener(
- getListenerTarget(editableField), goog.events.EventType.CLICK,
- goog.editor.Field.cancelLinkClick_, undefined, editableField);
- assertNull(cancelClickDefaultActionListener);
- }
- /**
- * Tests that plugins are disabled when the field is made uneditable.
- */
- function testMakeUneditableDisablesPlugins() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var calls = 0;
- plugin.disable = function(field) {
- assertEquals(editableField, field);
- assertTrue(field.isUneditable());
- calls++;
- };
- editableField.registerPlugin(plugin);
- editableField.makeEditable();
- assertEquals(0, calls);
- editableField.makeUneditable();
- assertEquals(1, calls);
- editableField.dispose();
- }
- /**
- * Test that if a browser open a new page when clicking a link in a content
- * editable element, a click listener is set to cancel this default action.
- */
- function testClickDefaultActionIsCanceledWhenBrowserFollowsClick() {
- // Simulate a browser that will open a new page when activating a link in a
- // content editable element.
- var editableField =
- createEditableFieldWithListeners(true /* followLinkInNewWindow */);
- assertClickDefaultActionIsCanceled(editableField);
- editableField.dispose();
- }
- /**
- * Test that if a browser does not open a new page when clicking a link in a
- * content editable element, the click default action is not canceled.
- */
- function testClickDefaultActionIsNotCanceledWhenBrowserDontFollowsClick() {
- // Simulate a browser that will NOT open a new page when activating a link in
- // a content editable element.
- var editableField =
- createEditableFieldWithListeners(false /* followLinkInNewWindow */);
- assertClickDefaultActionIsNotCanceled(editableField);
- editableField.dispose();
- }
- /**
- * Test that if a plugin registers keyup, it gets called.
- */
- function testPluginKeyUp() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin.handleKeyUp(e);
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- editableField.handleKeyUp_(e);
- mockPlugin.$verify();
- }
- /**
- * Test that if a plugin registers keydown, it gets called.
- */
- function testPluginKeyDown() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin.handleKeyDown(e).$returns(true);
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- editableField.handleKeyDown_(e);
- mockPlugin.$verify();
- }
- /**
- * Test that if a plugin registers keypress, it gets called.
- */
- function testPluginKeyPress() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin.handleKeyPress(e).$returns(true);
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- editableField.handleKeyPress_(e);
- mockPlugin.$verify();
- }
- /**
- * If one plugin handles a key event, the rest of the plugins do not get their
- * key handlers invoked.
- */
- function testHandledKeyEvent() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin1.handleKeyDown(e).$returns(true);
- } else {
- mockPlugin1.handleKeyPress(e).$returns(true);
- }
- mockPlugin1.handleKeyUp(e).$returns(true);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.handleKeyUp_(e);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- editableField.handleKeyDown_(e);
- } else {
- editableField.handleKeyPress_(e);
- }
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Tests to make sure the cut and paste events are not dispatched immediately.
- */
- function testHandleCutAndPasteEvents() {
- if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
- // Cut and paste events do not raise events at all in Mozilla.
- return;
- }
- var editableField = new FieldConstructor('testField');
- var clock = new goog.testing.MockClock(true);
- var delayedChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.DELAYEDCHANGE, delayedChanges);
- editableField.makeEditable();
- goog.testing.events.fireBrowserEvent(
- new goog.testing.events.Event('cut', editableField.getElement()));
- assertEquals(
- 'Cut event should be on a timer', 0, delayedChanges.getCallCount());
- clock.tick(1000);
- assertEquals(
- 'delayed change event should fire within 1s after cut', 1,
- delayedChanges.getCallCount());
- goog.testing.events.fireBrowserEvent(
- new goog.testing.events.Event('paste', editableField.getElement()));
- assertEquals(
- 'Paste event should be on a timer', 1, delayedChanges.getCallCount());
- clock.tick(1000);
- assertEquals(
- 'delayed change event should fire within 1s after paste', 2,
- delayedChanges.getCallCount());
- clock.dispose();
- editableField.dispose();
- }
- /**
- * If the first plugin does not handle the key event, the next plugin gets
- * a chance to handle it.
- */
- function testNotHandledKeyEvent() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin1.handleKeyDown(e).$returns(false);
- } else {
- mockPlugin1.handleKeyPress(e).$returns(false);
- }
- mockPlugin1.handleKeyUp(e).$returns(false);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin2.handleKeyDown(e).$returns(true);
- } else {
- mockPlugin2.handleKeyPress(e).$returns(true);
- }
- mockPlugin2.handleKeyUp(e).$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.handleKeyUp_(e);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- editableField.handleKeyDown_(e);
- } else {
- editableField.handleKeyPress_(e);
- }
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Make sure that handleKeyboardShortcut is called if other key handlers
- * return false.
- */
- function testKeyboardShortcutCalled() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin.handleKeyDown(e).$returns(false);
- } else {
- mockPlugin.handleKeyPress(e).$returns(false);
- }
- mockPlugin.handleKeyboardShortcut(e, STRING_KEY, true).$returns(false);
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- editableField.handleKeyDown_(e);
- } else {
- editableField.handleKeyPress_(e);
- }
- mockPlugin.$verify();
- }
- /**
- * Make sure that handleKeyboardShortcut is not called if other key handlers
- * return true.
- */
- function testKeyboardShortcutNotCalled() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin.handleKeyDown(e).$returns(true);
- } else {
- mockPlugin.handleKeyPress(e).$returns(true);
- }
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- editableField.handleKeyDown_(e);
- } else {
- editableField.handleKeyPress_(e);
- }
- mockPlugin.$verify();
- }
- /**
- * Make sure that handleKeyboardShortcut is not called if alt is pressed.
- * @bug 1363959
- */
- function testKeyHandlingAlt() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- e.altKey = true;
- var mockPlugin = new goog.testing.LooseMock(plugin);
- mockPlugin.getTrogClassId().$returns('mockPlugin');
- mockPlugin.registerFieldObject(editableField);
- mockPlugin.isEnabled(editableField).$anyTimes().$returns(true);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- mockPlugin.handleKeyDown(e).$returns(false);
- } else {
- mockPlugin.handleKeyPress(e).$returns(false);
- }
- mockPlugin.$replay();
- editableField.registerPlugin(mockPlugin);
- if (goog.editor.BrowserFeature.USES_KEYDOWN) {
- editableField.handleKeyDown_(e);
- } else {
- editableField.handleKeyPress_(e);
- }
- mockPlugin.$verify();
- }
- /**
- * Test that if a plugin has an execCommand function, it gets called
- * but only for supported commands.
- */
- function testPluginExecCommand() {
- var plugin = new TestPlugin();
- var passedCommand, passedArg;
- plugin.execCommand = function(command, arg) {
- passedCommand = command;
- passedArg = arg;
- };
- var editableField = new FieldConstructor('testField');
- editableField.registerPlugin(plugin);
- plugin.enable(editableField);
- plugin.isSupportedCommand = goog.functions.constant(true);
- editableField.execCommand('+indent', true);
- // Verify that the plugin's execCommand was called with the correct
- // args.
- assertEquals('+indent', passedCommand);
- assertTrue(passedArg);
- passedCommand = null;
- passedArg = null;
- plugin.isSupportedCommand = goog.functions.constant(false);
- editableField.execCommand('+outdent', false);
- // Verify that a plugin's execCommand is not called if it isn't a supported
- // command.
- assertNull(passedCommand);
- assertNull(passedArg);
- editableField.dispose();
- plugin.dispose();
- }
- /**
- * Test that if one plugin supports execCommand, no other plugins
- * get a chance to handle the execComand.
- */
- function testSupportedExecCommand() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.isSupportedCommand('+indent').$returns(true);
- mockPlugin1.execCommandInternal('+indent').$returns(true);
- mockPlugin1.execCommand('+indent').$does(function() {
- mockPlugin1.execCommandInternal('+indent');
- });
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.execCommand('+indent');
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Test that if the first plugin does not support execCommand, the other
- * plugins get a chance to handle the execCommand.
- */
- function testNotSupportedExecCommand() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.isSupportedCommand('+indent').$returns(false);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.isSupportedCommand('+indent').$returns(true);
- mockPlugin2.execCommandInternal('+indent').$returns(true);
- mockPlugin2.execCommand('+indent').$does(function() {
- mockPlugin2.execCommandInternal('+indent');
- });
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.execCommand('+indent');
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Tests that if a plugin supports a command that its queryCommandValue
- * gets called and no further plugins can handle the queryCommandValue.
- */
- function testSupportedQueryCommand() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.isSupportedCommand('+indent').$returns(true);
- mockPlugin1.queryCommandValue('+indent').$returns(true);
- mockPlugin1.activeOnUneditableFields().$returns(true);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.queryCommandValue('+indent');
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Tests that if the first plugin does not support a command that its
- * queryCommandValue do not get called and the next plugin can handle the
- * queryCommandValue.
- */
- function testNotSupportedQueryCommand() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.isSupportedCommand('+indent').$returns(false);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.isSupportedCommand('+indent').$returns(true);
- mockPlugin2.queryCommandValue('+indent').$returns(true);
- mockPlugin2.activeOnUneditableFields().$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.queryCommandValue('+indent');
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Tests that if a plugin handles selectionChange that it gets called and
- * no further plugins can handle the selectionChange.
- */
- function testHandledSelectionChange() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.handleSelectionChange(e, undefined).$returns(true);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.dispatchSelectionChangeEvent(e);
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- /**
- * Tests that if the first plugin does not handle selectionChange that
- * the next plugin gets a chance to handle it.
- */
- function testNotHandledSelectionChange() {
- var editableField = new FieldConstructor('testField');
- var plugin = new TestPlugin();
- var e = getBrowserEvent();
- var mockPlugin1 = new goog.testing.LooseMock(plugin);
- mockPlugin1.getTrogClassId().$returns('mockPlugin1');
- mockPlugin1.registerFieldObject(editableField);
- mockPlugin1.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin1.handleSelectionChange(e, undefined).$returns(false);
- mockPlugin1.$replay();
- var mockPlugin2 = new goog.testing.LooseMock(plugin);
- mockPlugin2.getTrogClassId().$returns('mockPlugin2');
- mockPlugin2.registerFieldObject(editableField);
- mockPlugin2.isEnabled(editableField).$anyTimes().$returns(true);
- mockPlugin2.handleSelectionChange(e, undefined).$returns(true);
- mockPlugin2.$replay();
- editableField.registerPlugin(mockPlugin1);
- editableField.registerPlugin(mockPlugin2);
- editableField.dispatchSelectionChangeEvent(e);
- mockPlugin1.$verify();
- mockPlugin2.$verify();
- }
- // Tests for goog.editor.Field internals.
- function testSelectionChange() {
- var editableField = new FieldConstructor('testField', document);
- var clock = new goog.testing.MockClock(true);
- var beforeSelectionChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.BEFORESELECTIONCHANGE,
- beforeSelectionChanges);
- var selectionChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.SELECTIONCHANGE,
- selectionChanges);
- editableField.makeEditable();
- // Emulate pressing left arrow key, this should result in a
- // BEFORESELECTIONCHANGE event immediately, and a SELECTIONCHANGE event after
- // a short timeout.
- editableField.handleKeyUp_({keyCode: goog.events.KeyCodes.LEFT});
- assertEquals(
- 'Before selection change should fire immediately', 1,
- beforeSelectionChanges.getCallCount());
- assertEquals(
- 'Selection change should be on a timer', 0,
- selectionChanges.getCallCount());
- clock.tick(1000);
- assertEquals(
- 'Selection change should fire within 1s', 1,
- selectionChanges.getCallCount());
- // Programically place cursor at start. SELECTIONCHANGE event should be fired.
- editableField.placeCursorAtStart();
- assertEquals(
- 'Selection change should fire', 2, selectionChanges.getCallCount());
- clock.dispose();
- editableField.dispose();
- }
- function testSelectionChangeOnMouseUp() {
- var fakeEvent =
- new goog.events.BrowserEvent({type: 'mouseup', target: 'fakeTarget'});
- var editableField = new FieldConstructor('testField', document);
- var clock = new goog.testing.MockClock(true);
- var beforeSelectionChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.BEFORESELECTIONCHANGE,
- beforeSelectionChanges);
- var selectionChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.SELECTIONCHANGE,
- selectionChanges);
- var plugin = new TestPlugin();
- plugin.handleSelectionChange = goog.testing.recordFunction();
- editableField.registerPlugin(plugin);
- editableField.makeEditable();
- // Emulate a mouseup event, this should result in immediate
- // BEFORESELECTIONCHANGE and SELECTIONCHANGE, plus a second SELECTIONCHANGE in
- // IE after a short timeout.
- editableField.handleMouseUp_(fakeEvent);
- assertEquals(
- 'Before selection change should fire immediately', 1,
- beforeSelectionChanges.getCallCount());
- assertEquals(
- 'Selection change should fire immediately', 1,
- selectionChanges.getCallCount());
- assertEquals(
- 'Plugin should have handled selection change immediately', 1,
- plugin.handleSelectionChange.getCallCount());
- assertEquals(
- 'Plugin should have received original browser event to handle', fakeEvent,
- plugin.handleSelectionChange.getLastCall().getArguments()[0]);
- // Pretend another plugin fired a SELECTIONCHANGE in the meantime.
- editableField.dispatchSelectionChangeEvent();
- assertEquals(
- 'Second selection change should fire immediately', 2,
- selectionChanges.getCallCount());
- assertEquals(
- 'Plugin should have handled second selection change immediately', 2,
- plugin.handleSelectionChange.getCallCount());
- var args = plugin.handleSelectionChange.getLastCall().getArguments();
- assertTrue(
- 'Plugin should not have received data from extra firing',
- args.length == 0 || !args[0] && (args.length == 1 || !args[1]));
- // Now check for the extra call in IE.
- clock.tick(1000);
- if (goog.userAgent.IE) {
- assertEquals(
- 'Additional selection change should fire within 1s', 3,
- selectionChanges.getCallCount());
- assertEquals(
- 'Plugin should have handled selection change within 1s', 3,
- plugin.handleSelectionChange.getCallCount());
- assertEquals(
- 'Plugin should have received target of original browser event',
- fakeEvent.target,
- plugin.handleSelectionChange.getLastCall().getArguments().pop());
- } else {
- assertEquals(
- 'No additional selection change should fire', 2,
- selectionChanges.getCallCount());
- assertEquals(
- 'Plugin should not have handled selection change again', 2,
- plugin.handleSelectionChange.getCallCount());
- }
- clock.dispose();
- editableField.dispose();
- }
- function testSelectionChangeBeforeUneditable() {
- var editableField = new FieldConstructor('testField', document);
- var clock = new goog.testing.MockClock(true);
- var selectionChanges = goog.testing.recordFunction();
- goog.events.listen(
- editableField, goog.editor.Field.EventType.SELECTIONCHANGE,
- selectionChanges);
- editableField.makeEditable();
- editableField.handleKeyUp_({keyCode: goog.events.KeyCodes.LEFT});
- assertEquals(
- 'Selection change should be on a timer', 0,
- selectionChanges.getCallCount());
- editableField.makeUneditable();
- assertEquals(
- 'Selection change should fire during make uneditable', 1,
- selectionChanges.getCallCount());
- clock.tick(1000);
- assertEquals(
- 'No additional selection change should fire', 1,
- selectionChanges.getCallCount());
- clock.dispose();
- editableField.dispose();
- }
- function testGetEditableDomHelper() {
- var editableField = new FieldConstructor('testField', document);
- assertNull(
- 'Before being made editable, we do not know the dom helper',
- editableField.getEditableDomHelper());
- editableField.makeEditable();
- assertNotNull(
- 'After being made editable, we know the dom helper',
- editableField.getEditableDomHelper());
- assertEquals(
- 'Document from domHelper should be the editable elements doc',
- goog.dom.getOwnerDocument(editableField.getElement()),
- editableField.getEditableDomHelper().getDocument());
- editableField.dispose();
- }
- function testQueryCommandValue() {
- var editableField = new FieldConstructor('testField', document);
- assertFalse(editableField.queryCommandValue('boo'));
- assertObjectEquals(
- {'boo': false, 'aieee': false},
- editableField.queryCommandValue(['boo', 'aieee']));
- editableField.makeEditable();
- assertFalse(editableField.queryCommandValue('boo'));
- focusFieldSync(editableField);
- assertNull(editableField.queryCommandValue('boo'));
- assertObjectEquals(
- {'boo': null, 'aieee': null},
- editableField.queryCommandValue(['boo', 'aieee']));
- editableField.dispose();
- }
- function focusFieldSync(field) {
- field.focus();
- // IE fires focus events async, so create a fake focus event
- // synchronously.
- goog.testing.events.fireFocusEvent(field.getElement());
- }
- function testSetHtml() {
- var editableField = new FieldConstructor('testField', document);
- var clock = new goog.testing.MockClock(true);
- try {
- var delayedChangeCalled = false;
- goog.events.listen(
- editableField, goog.editor.Field.EventType.DELAYEDCHANGE,
- function() { delayedChangeCalled = true; });
- editableField.makeEditable();
- clock.tick(1000);
- assertFalse(
- 'Make editable must not fire delayed change.', delayedChangeCalled);
- editableField.setHtml(false, 'bar', true /* Don't fire delayed change */);
- goog.testing.dom.assertHtmlContentsMatch('bar', editableField.getElement());
- clock.tick(1000);
- assertFalse(
- 'setHtml must not fire delayed change if so configured.',
- delayedChangeCalled);
- editableField.setHtml(false, 'foo', false /* Fire delayed change */);
- goog.testing.dom.assertHtmlContentsMatch('foo', editableField.getElement());
- clock.tick(1000);
- assertTrue(
- 'setHtml must fire delayed change by default', delayedChangeCalled);
- } finally {
- clock.dispose();
- editableField.dispose();
- }
- }
- /**
- * Helper to test that the cursor is placed at the beginning of the editable
- * field's contents.
- * @param {string=} opt_html Html to replace the test file default field
- * contents with.
- * @param {string=} opt_parentId Id of the parent of the node where the cursor
- * is expected to be placed. If omitted, will expect cursor to be placed in
- * the first child of the field element (or, if the field has no content, in
- * the field element itself).
- */
- function doTestPlaceCursorAtStart(opt_html, opt_parentId) {
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- // Initially place selection not at the start of the editable field.
- var textNode = editableField.getElement().firstChild;
- goog.dom.Range.createFromNodes(textNode, 1, textNode, 2).select();
- if (opt_html != null) {
- editableField.getElement().innerHTML = opt_html;
- }
- editableField.placeCursorAtStart();
- var range = editableField.getRange();
- assertNotNull(
- 'Placing the cursor should result in a range object being available',
- range);
- assertTrue('The range should be collapsed', range.isCollapsed());
- textNode = editableField.getElement().firstChild;
- // We check whether getAttribute exist because textNode may be an actual
- // TextNode, which does not have getAttribute.
- if (textNode && textNode.getAttribute &&
- textNode.getAttribute('_moz_editor_bogus_node')) {
- // At least in FF >= 6, assigning '' to innerHTML of a contentEditable
- // element will results in textNode being modified into:
- // <br _moz_editor_bogus_node="TRUE" _moz_dirty=""> instead of nulling
- // it. So we should null it ourself.
- textNode = null;
- }
- var startNode = opt_parentId ?
- editableField.getEditableDomHelper().getElement(opt_parentId).firstChild :
- textNode ? textNode : editableField.getElement();
- if (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('528')) {
- // Safari 3 seems to normalize the selection to the shallowest endpoint (in
- // this case the editable element) in all cases tested below. This is OK
- // because when you start typing it magically inserts the text at the
- // deepest endpoint, and even behaves as desired in the case tested by
- // testPlaceCursorAtStartNonImportantTextNode.
- startNode = editableField.getElement();
- }
- assertEquals(
- 'The range should start at the specified expected node', startNode,
- range.getStartNode());
- assertEquals(
- 'The range should start at the beginning of the node', 0,
- range.getStartOffset());
- }
- /**
- * Verify that restoreSavedRange() restores the range and sets the focus.
- */
- function testRestoreSavedRange() {
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- // Create another node to take the focus later.
- var doc = goog.dom.getOwnerDocument(editableField.getElement());
- var dom = goog.dom.getDomHelper(editableField.getElement());
- var otherElem = dom.createElement(goog.dom.TagName.DIV);
- otherElem.tabIndex = 1; // Make it focusable.
- editableField.getElement().parentNode.appendChild(otherElem);
- // Initially place selection not at the start of the editable field.
- var textNode = editableField.getElement().firstChild;
- var range = goog.dom.Range.createFromNodes(textNode, 1, textNode, 2);
- range.select();
- var savedRange = goog.editor.range.saveUsingNormalizedCarets(range);
- // Change range to be a simple cursor at start, and move focus away.
- editableField.placeCursorAtStart();
- otherElem.focus();
- editableField.restoreSavedRange(savedRange);
- // Verify that we have focus and the range is restored.
- assertEquals(
- 'Field should be focused', editableField.getElement(),
- goog.dom.getActiveElement(doc));
- var newRange = editableField.getRange();
- assertEquals('Range startNode', textNode, newRange.getStartNode());
- assertEquals('Range startOffset', 1, newRange.getStartOffset());
- assertEquals('Range endNode', textNode, newRange.getEndNode());
- assertEquals('Range endOffset', 2, newRange.getEndOffset());
- }
- function testPlaceCursorAtStart() {
- doTestPlaceCursorAtStart();
- }
- function testPlaceCursorAtStartEmptyField() {
- doTestPlaceCursorAtStart('');
- }
- function testPlaceCursorAtStartNonImportantTextNode() {
- doTestPlaceCursorAtStart(
- '\n<span id="important">important text</span>', 'important');
- }
- /**
- * Helper to test that the cursor is placed at the beginning of the editable
- * field's contents.
- * @param {string=} opt_html Html to replace the test file default field
- * contents with.
- * @param {string=} opt_parentId Id of the parent of the node where the cursor
- * is expected to be placed. If omitted, will expect cursor to be placed in
- * the first child of the field element (or, if the field has no content, in
- * the field element itself).
- * @param {number=} opt_offset The offset to expect for the end position.
- */
- function doTestPlaceCursorAtEnd(opt_html, opt_parentId, opt_offset) {
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- // Initially place selection not at the end of the editable field.
- var textNode = editableField.getElement().firstChild;
- goog.dom.Range.createFromNodes(textNode, 0, textNode, 1).select();
- if (opt_html != null) {
- editableField.getElement().innerHTML = opt_html;
- }
- editableField.placeCursorAtEnd();
- var range = editableField.getRange();
- assertNotNull(
- 'Placing the cursor should result in a range object being available',
- range);
- assertTrue('The range should be collapsed', range.isCollapsed());
- textNode = editableField.getElement().firstChild;
- // We check whether getAttribute exist because textNode may be an actual
- // TextNode, which does not have getAttribute.
- var hasBogusNode = textNode && textNode.getAttribute &&
- textNode.getAttribute('_moz_editor_bogus_node');
- if (hasBogusNode) {
- // At least in FF >= 6, assigning '' to innerHTML of a contentEditable
- // element will results in textNode being modified into:
- // <br _moz_editor_bogus_node="TRUE" _moz_dirty=""> instead of nulling
- // it. So we should null it ourself.
- textNode = null;
- }
- var endNode = opt_parentId ?
- editableField.getEditableDomHelper().getElement(opt_parentId).lastChild :
- textNode ? textNode : editableField.getElement();
- assertEquals(
- 'The range should end at the specified expected node', endNode,
- range.getEndNode());
- var offset = goog.isDefAndNotNull(opt_offset) ? opt_offset : textNode ?
- endNode.nodeValue.length :
- endNode.childNodes.length - 1;
- if (hasBogusNode) {
- assertEquals(
- 'The range should end at the ending of the bogus node ' +
- 'added by FF',
- offset + 1, range.getEndOffset());
- } else {
- assertEquals(
- 'The range should end at the ending of the node', offset,
- range.getEndOffset());
- }
- }
- function testPlaceCursorAtEnd() {
- doTestPlaceCursorAtEnd();
- }
- function testPlaceCursorAtEndEmptyField() {
- doTestPlaceCursorAtEnd('', null, 0);
- }
- function testPlaceCursorAtEndNonImportantTextNode() {
- doTestPlaceCursorAtStart(
- '\n<span id="important">important text</span>', 'important');
- }
- // Tests related to change/delayed change events.
- function testClearDelayedChange() {
- var clock = new goog.testing.MockClock(true);
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- var delayedChangeCalled = false;
- goog.events.listen(
- editableField, goog.editor.Field.EventType.DELAYEDCHANGE,
- function() { delayedChangeCalled = true; });
- // Clears delayed change timer.
- editableField.delayedChangeTimer_.start();
- editableField.clearDelayedChange();
- assertTrue(delayedChangeCalled);
- if (editableField.changeTimerGecko_) {
- assertFalse(editableField.changeTimerGecko_.isActive());
- }
- assertFalse(editableField.delayedChangeTimer_.isActive());
- // Clears delayed changes caused by changeTimerGecko_
- if (editableField.changeTimerGecko_) {
- delayedChangeCalled = false;
- editableField.changeTimerGecko_.start();
- editableField.clearDelayedChange();
- assertTrue(delayedChangeCalled);
- if (editableField.changeTimerGecko_) {
- assertFalse(editableField.changeTimerGecko_.isActive());
- }
- assertFalse(editableField.delayedChangeTimer_.isActive());
- }
- clock.dispose();
- }
- function testHandleChange() {
- if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- editableField.changeTimerGecko_.start();
- editableField.handleChange();
- assertFalse(editableField.changeTimerGecko_.isActive());
- }
- }
- function testDispatchDelayedChange() {
- var editableField = new FieldConstructor('testField', document);
- editableField.makeEditable();
- editableField.delayedChangeTimer_.start();
- editableField.dispatchDelayedChange_();
- assertFalse(editableField.delayedChangeTimer_.isActive());
- }
- function testHandleWindowLevelMouseUp() {
- var editableField = new FieldConstructor('testField', document);
- if (editableField.usesIframe()) {
- // Only run this test if the editor does not use an iframe.
- return;
- }
- editableField.setUseWindowMouseUp(true);
- editableField.makeEditable();
- var selectionHasFired = false;
- goog.events.listenOnce(
- editableField, goog.editor.Field.EventType.SELECTIONCHANGE,
- function(e) { selectionHasFired = true; });
- var editableElement = editableField.getElement();
- var otherElement = goog.dom.createDom(goog.dom.TagName.DIV);
- goog.dom.insertSiblingAfter(otherElement, document.body.lastChild);
- goog.testing.events.fireMouseDownEvent(editableElement);
- assertFalse(selectionHasFired);
- goog.testing.events.fireMouseUpEvent(otherElement);
- assertTrue(selectionHasFired);
- }
- function testNoHandleWindowLevelMouseUp() {
- var editableField = new FieldConstructor('testField', document);
- editableField.setUseWindowMouseUp(false);
- editableField.makeEditable();
- var selectionHasFired = false;
- goog.events.listenOnce(
- editableField, goog.editor.Field.EventType.SELECTIONCHANGE,
- function(e) { selectionHasFired = true; });
- var editableElement = editableField.getElement();
- var otherElement = goog.dom.createDom(goog.dom.TagName.DIV);
- goog.dom.insertSiblingAfter(otherElement, document.body.lastChild);
- goog.testing.events.fireMouseDownEvent(editableElement);
- assertFalse(selectionHasFired);
- goog.testing.events.fireMouseUpEvent(otherElement);
- assertFalse(selectionHasFired);
- }
- function testIsGeneratingKey() {
- var regularKeyEvent = new goog.events.BrowserEvent();
- regularKeyEvent.charCode = goog.events.KeyCodes.A;
- var ctrlKeyEvent = new goog.events.BrowserEvent();
- ctrlKeyEvent.ctrlKey = true;
- ctrlKeyEvent.metaKey = true;
- ctrlKeyEvent.charCode = goog.events.KeyCodes.A;
- var imeKeyEvent = new goog.events.BrowserEvent();
- imeKeyEvent.keyCode =
- 229; // indicates from an IME - see KEYS_CAUSING_CHANGES
- assertTrue(goog.editor.Field.isGeneratingKey_(regularKeyEvent, true));
- assertFalse(goog.editor.Field.isGeneratingKey_(ctrlKeyEvent, true));
- if (goog.userAgent.WINDOWS && !goog.userAgent.GECKO) {
- assertTrue(goog.editor.Field.isGeneratingKey_(imeKeyEvent, false));
- } else {
- assertFalse(goog.editor.Field.isGeneratingKey_(imeKeyEvent, false));
- }
- }
- function testSetEditableClassName() {
- var element = goog.dom.getElement('testField');
- var editableField = new FieldConstructor('testField');
- assertFalse(goog.dom.classlist.contains(element, 'editable'));
- editableField.makeEditable();
- assertTrue(goog.dom.classlist.contains(element, 'editable'));
- assertEquals(
- 1,
- goog.array.count(
- goog.dom.classlist.get(element), goog.functions.equalTo('editable')));
- // Skip restore won't reset the original element's CSS classes.
- editableField.makeUneditable(true /* opt_skipRestore */);
- editableField.makeEditable();
- assertTrue(goog.dom.classlist.contains(element, 'editable'));
- assertEquals(
- 1,
- goog.array.count(
- goog.dom.classlist.get(element), goog.functions.equalTo('editable')));
- }
|