diff options
Diffstat (limited to 'contexts/data/lib/closure-library/closure/goog/editor/field_test.js')
-rw-r--r-- | contexts/data/lib/closure-library/closure/goog/editor/field_test.js | 1160 |
1 files changed, 0 insertions, 1160 deletions
diff --git a/contexts/data/lib/closure-library/closure/goog/editor/field_test.js b/contexts/data/lib/closure-library/closure/goog/editor/field_test.js deleted file mode 100644 index c2c782c..0000000 --- a/contexts/data/lib/closure-library/closure/goog/editor/field_test.js +++ /dev/null @@ -1,1160 +0,0 @@ -// 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 jparent@google.com (Julie Parent) - * @author gboyer@google.com (Garrett Boyer) - */ - -goog.provide('goog.editor.field_test'); - -goog.require('goog.dom.Range'); -goog.require('goog.editor.Field'); -goog.require('goog.editor.Plugin'); -goog.require('goog.editor.Command'); -goog.require('goog.events'); -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.recordFunction'); -goog.require('goog.userAgent'); -goog.require('goog.userAgent.product'); -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 { - goog.events.removeAll(); - } catch (e) {} -} - -// Tests for the plugin interface. - - - -/** - * Dummy plugin for test usage. - * @constructor - * @extends {goog.editor.Plugin} - */ -function TestPlugin() { - 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; -} - - -/** - * 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 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 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 SELECTIONCHANGE - // event after a short timeout. - editableField.handleKeyUp_({keyCode: goog.events.KeyCodes.LEFT}); - 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 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 an immediate - // SELECTIONCHANGE, plus a second one in IE after a short timeout. - editableField.handleMouseUp_(fakeEvent); - 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')); - - editableField.getElement().focus(); - editableField.dispatchSelectionChangeEvent(); - assertNull(editableField.queryCommandValue('boo')); - assertObjectEquals({'boo': null, 'aieee': null}, - editableField.queryCommandValue(['boo', 'aieee'])); - editableField.dispose(); -} - - -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.isVersion('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()); -} - - -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=} 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. - 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 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; - 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()); -} |