зеркало из https://github.com/mozilla/pjs.git
Bug 488420 IME enabled state is not modified when a focused editor's readonly attribute is changed r=smaug
This commit is contained in:
Родитель
a8da5c275d
Коммит
dc7e7da106
|
@ -615,20 +615,7 @@ public:
|
|||
IME_STATUS_PASSWORD | IME_STATUS_PLUGIN,
|
||||
IME_STATUS_MASK_OPENED = IME_STATUS_OPEN | IME_STATUS_CLOSE
|
||||
};
|
||||
virtual PRUint32 GetDesiredIMEState()
|
||||
{
|
||||
if (!IsEditableInternal())
|
||||
return IME_STATUS_DISABLE;
|
||||
nsIContent *editableAncestor = nsnull;
|
||||
for (nsIContent* parent = GetParent();
|
||||
parent && parent->HasFlag(NODE_IS_EDITABLE);
|
||||
parent = parent->GetParent())
|
||||
editableAncestor = parent;
|
||||
// This is in another editable content, use the result of it.
|
||||
if (editableAncestor)
|
||||
return editableAncestor->GetDesiredIMEState();
|
||||
return IME_STATUS_ENABLE;
|
||||
}
|
||||
virtual PRUint32 GetDesiredIMEState();
|
||||
|
||||
/**
|
||||
* Gets content node with the binding (or native code, possibly on the
|
||||
|
|
|
@ -125,6 +125,7 @@
|
|||
#include "nsIDOMUserDataHandler.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIEditorIMESupport.h"
|
||||
#include "nsIEditorDocShell.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsContentCreatorFunctions.h"
|
||||
|
@ -636,6 +637,47 @@ nsIContent::GetFlattenedTreeParent() const
|
|||
return parent;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsIContent::GetDesiredIMEState()
|
||||
{
|
||||
if (!IsEditableInternal()) {
|
||||
return IME_STATUS_DISABLE;
|
||||
}
|
||||
nsIContent *editableAncestor = nsnull;
|
||||
for (nsIContent* parent = GetParent();
|
||||
parent && parent->HasFlag(NODE_IS_EDITABLE);
|
||||
parent = parent->GetParent()) {
|
||||
editableAncestor = parent;
|
||||
}
|
||||
// This is in another editable content, use the result of it.
|
||||
if (editableAncestor) {
|
||||
return editableAncestor->GetDesiredIMEState();
|
||||
}
|
||||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (!doc) {
|
||||
return IME_STATUS_DISABLE;
|
||||
}
|
||||
nsIPresShell* ps = doc->GetPrimaryShell();
|
||||
if (!ps) {
|
||||
return IME_STATUS_DISABLE;
|
||||
}
|
||||
nsPresContext* pc = ps->GetPresContext();
|
||||
if (!pc) {
|
||||
return IME_STATUS_DISABLE;
|
||||
}
|
||||
nsIEditor* editor = GetHTMLEditor(pc);
|
||||
nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
|
||||
if (!imeEditor) {
|
||||
return IME_STATUS_DISABLE;
|
||||
}
|
||||
// Use "enable" for the default value because IME is disabled unexpectedly,
|
||||
// it makes serious a11y problem.
|
||||
PRUint32 state = IME_STATUS_ENABLE;
|
||||
nsresult rv = imeEditor->GetPreferredIMEState(&state);
|
||||
NS_ENSURE_SUCCESS(rv, IME_STATUS_ENABLE);
|
||||
return state;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ADDREF(nsChildContentList)
|
||||
|
|
|
@ -83,7 +83,7 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
|||
nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
|
||||
if (widget) {
|
||||
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
||||
SetIMEState(sPresContext, newState, widget);
|
||||
SetIMEState(newState, widget);
|
||||
}
|
||||
sContent = nsnull;
|
||||
sPresContext = nsnull;
|
||||
|
@ -108,7 +108,7 @@ nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
|||
if (NS_FAILED(rv))
|
||||
widget->ResetInputState();
|
||||
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
||||
SetIMEState(sPresContext, newState, widget);
|
||||
SetIMEState(newState, widget);
|
||||
}
|
||||
|
||||
sContent = nsnull;
|
||||
|
@ -162,7 +162,7 @@ nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
|
|||
|
||||
if (newState != nsIContent::IME_STATUS_NONE) {
|
||||
// Update IME state for new focus widget
|
||||
SetIMEState(aPresContext, newState, widget);
|
||||
SetIMEState(newState, widget);
|
||||
}
|
||||
|
||||
sPresContext = aPresContext;
|
||||
|
@ -178,6 +178,26 @@ nsIMEStateManager::OnInstalledMenuKeyboardListener(PRBool aInstalling)
|
|||
OnChangeFocus(sPresContext, sContent);
|
||||
}
|
||||
|
||||
void
|
||||
nsIMEStateManager::ChangeIMEStateTo(PRUint32 aNewIMEState)
|
||||
{
|
||||
if (!sPresContext) {
|
||||
NS_WARNING("ISM doesn't know which editor has focus");
|
||||
return;
|
||||
}
|
||||
NS_PRECONDITION(aNewIMEState != 0, "aNewIMEState doesn't specify new state.");
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
|
||||
if (!widget) {
|
||||
NS_WARNING("focused widget is not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// commit current composition
|
||||
widget->ResetInputState();
|
||||
|
||||
SetIMEState(aNewIMEState, widget);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||
nsIContent* aContent)
|
||||
|
@ -204,18 +224,17 @@ nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
|||
}
|
||||
|
||||
void
|
||||
nsIMEStateManager::SetIMEState(nsPresContext* aPresContext,
|
||||
PRUint32 aState,
|
||||
nsIWidget* aKB)
|
||||
nsIMEStateManager::SetIMEState(PRUint32 aState,
|
||||
nsIWidget* aWidget)
|
||||
{
|
||||
if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
|
||||
PRUint32 state =
|
||||
nsContentUtils::GetWidgetStatusFromIMEStatus(aState);
|
||||
aKB->SetIMEEnabled(state);
|
||||
aWidget->SetIMEEnabled(state);
|
||||
}
|
||||
if (aState & nsIContent::IME_STATUS_MASK_OPENED) {
|
||||
PRBool open = !!(aState & nsIContent::IME_STATUS_OPEN);
|
||||
aKB->SetIMEOpenState(open);
|
||||
aWidget->SetIMEOpenState(open);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,10 +80,11 @@ public:
|
|||
// Get the focused editor's selection and root
|
||||
static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
|
||||
nsIContent** aRoot);
|
||||
// This method changes the current IME state forcedly.
|
||||
// So, the caller should check whether you're focused or not.
|
||||
static void ChangeIMEStateTo(PRUint32 aNewIMEState);
|
||||
protected:
|
||||
static void SetIMEState(nsPresContext* aPresContext,
|
||||
PRUint32 aState,
|
||||
nsIWidget* aKB);
|
||||
static void SetIMEState(PRUint32 aState, nsIWidget* aWidget);
|
||||
static PRUint32 GetNewIMEState(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
|
||||
|
|
|
@ -91,4 +91,5 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
INCLUDES += \
|
||||
-I$(topsrcdir)/content/base/src \
|
||||
-I$(topsrcdir)/content/events/src \
|
||||
$(NULL)
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "nsIDOMHTMLElement.h"
|
||||
#include "nsIDOMNSHTMLElement.h"
|
||||
#include "nsPIDOMEventTarget.h"
|
||||
#include "nsIMEStateManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
@ -219,13 +221,17 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
|||
if ((nsnull==aDoc) || (nsnull==aPresShell))
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// First only set flags, but other stuff shouldn't be initialized now.
|
||||
// Don't move this call after initializing mDocWeak and mPresShellWeak.
|
||||
// SetFlags() can check whether it's called during initialization or not by
|
||||
// them. Note that SetFlags() will be called by PostCreate().
|
||||
nsresult rv = SetFlags(aFlags);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
|
||||
|
||||
mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc
|
||||
mPresShellWeak = do_GetWeakReference(aPresShell); // weak reference to pres shell
|
||||
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller
|
||||
|
||||
nsresult rv = SetFlags(aFlags);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "SetFlags() failed");
|
||||
|
||||
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
|
@ -279,8 +285,8 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
|||
NS_IMETHODIMP
|
||||
nsEditor::PostCreate()
|
||||
{
|
||||
// Set up spellchecking
|
||||
nsresult rv = SyncRealTimeSpell();
|
||||
// Synchronize some stuff for the flags
|
||||
nsresult rv = SetFlags(mFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set up listeners
|
||||
|
@ -437,8 +443,29 @@ nsEditor::SetFlags(PRUint32 aFlags)
|
|||
{
|
||||
mFlags = aFlags;
|
||||
|
||||
if (!mDocWeak || !mPresShellWeak) {
|
||||
// If we're initializing, we shouldn't do anything now.
|
||||
// SetFlags() will be called by PostCreate(),
|
||||
// we should synchronize some stuff for the flags at that time.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Changing the flags can change whether spellchecking is on, so re-sync it
|
||||
SyncRealTimeSpell();
|
||||
nsresult rv = SyncRealTimeSpell();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Might be changing editable state, so, we need to reset current IME state
|
||||
// if we're focused.
|
||||
if (HasFocus()) {
|
||||
// Use "enable" for the default value because if IME is disabled
|
||||
// unexpectedly, it makes serious a11y problem.
|
||||
PRUint32 newState = nsIContent::IME_STATUS_ENABLE;
|
||||
rv = GetPreferredIMEState(&newState);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsIMEStateManager::ChangeIMEStateTo(newState);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5155,3 +5182,18 @@ nsEditor::IsModifiableNode(nsIDOMNode *aNode)
|
|||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEditor::HasFocus()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMEventTarget> piTarget = GetPIDOMEventTarget();
|
||||
if (!piTarget) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
NS_ENSURE_TRUE(fm, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIContent> content = fm->GetFocusedContent();
|
||||
return SameCOMIdentity(content, piTarget);
|
||||
}
|
||||
|
|
|
@ -647,6 +647,9 @@ public:
|
|||
return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
|
||||
}
|
||||
|
||||
// Whether the editor has focus or not.
|
||||
virtual PRBool HasFocus();
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mModCount; // number of modifications (for undo/redo stack)
|
||||
|
|
|
@ -917,6 +917,9 @@ FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
|
|||
return root;
|
||||
}
|
||||
|
||||
// XXX If the editor is HTML editor and has readonly flag, shouldn't return
|
||||
// the element which has contenteditable="true"? However, such case isn't
|
||||
// there without chrome permission script.
|
||||
if (aEditor->IsReadonly()) {
|
||||
// We still want to allow selection in a readonly editor.
|
||||
nsCOMPtr<nsIDOMElement> rootElement;
|
||||
|
@ -936,6 +939,11 @@ FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
|
|||
|
||||
// For non-readonly editors we want to find the root of the editable subtree
|
||||
// containing aContent.
|
||||
// XXX This is wrong in meaning of this method if the editor is form control.
|
||||
// The editable form controls are also have NODE_IS_EDITABLE flag but it can
|
||||
// be in contenteditable elements. So, at this time, this climbs up to the
|
||||
// root editable element. But fortunately, we don't have any problem by
|
||||
// another issue, see the XXX comment in focus event handler.
|
||||
nsIContent *parent, *content = aContent;
|
||||
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
|
||||
content = parent;
|
||||
|
@ -965,6 +973,12 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
|
|||
PRBool targetIsEditableDoc = PR_FALSE;
|
||||
nsCOMPtr<nsIContent> editableRoot;
|
||||
if (content) {
|
||||
// XXX If the focus event target is a form control in contenteditable
|
||||
// element, perhaps, the parent HTML editor should do nothing by this
|
||||
// handler. However, FindSelectionRoot() returns the root element of the
|
||||
// contenteditable editor. So, the editableRoot value is invalid for
|
||||
// the plain text editor, and it will be set to the wrong limiter of
|
||||
// the selection. However, fortunately, actual bugs are not found yet.
|
||||
editableRoot = FindSelectionRoot(mEditor, content);
|
||||
|
||||
// make sure that the element is really focused in case an earlier
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
#include "SetDocTitleTxn.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
// netwerk
|
||||
#include "nsIURI.h"
|
||||
|
@ -5632,3 +5634,78 @@ nsHTMLEditor::GetReturnInParagraphCreatesNewParagraph(PRBool *aCreatesNewParagra
|
|||
*aCreatesNewParagraph = mCRInParagraphCreatesParagraph;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditor::HasFocus()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDocWeak, PR_FALSE);
|
||||
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
NS_ENSURE_TRUE(fm, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
PRBool inDesignMode = doc->HasFlag(NODE_IS_EDITABLE);
|
||||
if (!focusedContent) {
|
||||
// in designMode, nobody gets focus in most cases.
|
||||
return inDesignMode ? OurWindowHasFocus() : PR_FALSE;
|
||||
}
|
||||
|
||||
if (inDesignMode) {
|
||||
return OurWindowHasFocus() ?
|
||||
nsContentUtils::ContentIsDescendantOf(focusedContent, doc) : PR_FALSE;
|
||||
}
|
||||
|
||||
// We're HTML editor for contenteditable
|
||||
|
||||
// If the focused content isn't editable, or it has independent selection,
|
||||
// we don't have focus.
|
||||
if (!focusedContent->HasFlag(NODE_IS_EDITABLE) ||
|
||||
IsIndependentSelectionContent(focusedContent)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsCOMPtr<nsIContent> rootContent = do_QueryInterface(GetRoot());
|
||||
if (!rootContent) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
// If the focused content is a descendant of our editor root, we're focused.
|
||||
return nsContentUtils::ContentIsDescendantOf(focusedContent, rootContent);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditor::OurWindowHasFocus()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDocWeak, PR_FALSE);
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
NS_ENSURE_TRUE(fm, PR_FALSE);
|
||||
nsCOMPtr<nsIDOMWindow> focusedWindow;
|
||||
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
||||
if (!focusedWindow) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
|
||||
nsCOMPtr<nsIDOMWindow> ourWindow = do_QueryInterface(doc->GetWindow());
|
||||
return ourWindow == focusedWindow;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLEditor::IsIndependentSelectionContent(nsIContent* aContent)
|
||||
{
|
||||
NS_PRECONDITION(aContent, "aContent must not be null");
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
return (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetPreferredIMEState(PRUint32 *aState)
|
||||
{
|
||||
if (IsReadonly() || IsDisabled()) {
|
||||
*aState = nsIContent::IME_STATUS_DISABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// HTML editor don't prefer the CSS ime-mode because IE didn't do so too.
|
||||
*aState = nsIContent::IME_STATUS_ENABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -146,6 +146,10 @@ public:
|
|||
NS_IMETHODIMP HandleKeyPress(nsIDOMKeyEvent* aKeyEvent);
|
||||
NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable);
|
||||
NS_IMETHODIMP BeginningOfDocument();
|
||||
virtual PRBool HasFocus();
|
||||
|
||||
/* ------------ nsIEditorIMESupport overrides ------------ */
|
||||
NS_IMETHOD GetPreferredIMEState(PRUint32 *aState);
|
||||
|
||||
/* ------------ nsIHTMLEditor methods -------------- */
|
||||
|
||||
|
@ -725,6 +729,12 @@ protected:
|
|||
nsresult HasStyleOrIdOrClass(nsIDOMElement * aElement, PRBool *aHasStyleOrIdOrClass);
|
||||
nsresult RemoveElementIfNoStyleOrIdOrClass(nsIDOMElement * aElement, nsIAtom * aTag);
|
||||
|
||||
// Whether the outer window of the DOM event target has focus or not.
|
||||
PRBool OurWindowHasFocus();
|
||||
// Whether the content has independent selection or not. E.g., input field,
|
||||
// password field and textarea element. At that time, this returns TRUE.
|
||||
PRBool IsIndependentSelectionContent(nsIContent* aContent);
|
||||
|
||||
// Data members
|
||||
protected:
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ _TEST_FILES = \
|
|||
test_bug487524.html \
|
||||
test_bug525389.html \
|
||||
test_bug537046.html \
|
||||
test_contenteditable_focus.html \
|
||||
test_select_all_without_body.html \
|
||||
file_select_all_without_body.html \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Test for contenteditable focus</title>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
First text in this document.<br>
|
||||
<input id="inputText" type="text"><br>
|
||||
<input id="inputTextReadonly" type="text" readonly><br>
|
||||
<input id="inputButton" type="button" value="input[type=button]"><br>
|
||||
<button id="button">button</button><br>
|
||||
<div id="editor" contenteditable="true">
|
||||
editable contents.<br>
|
||||
<input id="inputTextInEditor" type="text"><br>
|
||||
<input id="inputTextReadonlyInEditor" type="text" readonly><br>
|
||||
<input id="inputButtonInEditor" type="button" value="input[type=button]"><br>
|
||||
<button id="buttonInEditor">button</button><br>
|
||||
<div id="noeditableInEditor" contenteditable="false">
|
||||
<span id="spanInNoneditableInEditor">span element in noneditable in editor</span><br>
|
||||
<input id="inputTextInNoneditableInEditor" type="text"><br>
|
||||
<input id="inputTextReadonlyInNoneditableInEditor" type="text" readonly><br>
|
||||
<input id="inputButtonInNoneditableInEditor" type="button" value="input[type=button]"><br>
|
||||
<button id="buttonInNoneditableInEditor">button</button><br>
|
||||
</div>
|
||||
<span id="spanInEditor">span element in editor</span><br>
|
||||
</div>
|
||||
<div id="otherEditor" contenteditable="true">
|
||||
other editor.
|
||||
</div>
|
||||
</div>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(runTests, window);
|
||||
|
||||
function runTests()
|
||||
{
|
||||
try {
|
||||
runTestsInternal();
|
||||
} catch (e) {
|
||||
ok(false, "Unexpected error happened: " + e);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTestsInternal()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
var fm = Components.classes["@mozilla.org/focus-manager;1"].
|
||||
getService(Components.interfaces.nsIFocusManager);
|
||||
// XXX using selCon for checking the visibility of the caret, however,
|
||||
// selCon is shared in document, cannot get the element of owner of the
|
||||
// caret from javascript?
|
||||
var selCon =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIWebNavigation).
|
||||
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsISelectionDisplay).
|
||||
QueryInterface(Components.interfaces.nsISelectionController);
|
||||
var selection = window.getSelection();
|
||||
|
||||
var inputText = document.getElementById("inputText");
|
||||
var inputTextReadonly = document.getElementById("inputTextReadonly");
|
||||
var inputButton = document.getElementById("inputButton");
|
||||
var button = document.getElementById("button");
|
||||
var editor = document.getElementById("editor");
|
||||
var inputTextInEditor = document.getElementById("inputTextInEditor");
|
||||
var inputTextReadonlyInEditor = document.getElementById("inputTextReadonlyInEditor");
|
||||
var inputButtonInEditor = document.getElementById("inputButtonInEditor");
|
||||
var noeditableInEditor = document.getElementById("noeditableInEditor");
|
||||
var spanInNoneditableInEditor = document.getElementById("spanInNoneditableInEditor");
|
||||
var inputTextInNoneditableInEditor = document.getElementById("inputTextInNoneditableInEditor");
|
||||
var inputTextReadonlyInNoneditableInEditor = document.getElementById("inputTextReadonlyInNoneditableInEditor");
|
||||
var inputButtonInNoneditableInEditor = document.getElementById("inputButtonInNoneditableInEditor");
|
||||
var buttonInNoneditableInEditor = document.getElementById("buttonInNoneditableInEditor");
|
||||
var spanInEditor = document.getElementById("spanInEditor");
|
||||
var otherEditor = document.getElementById("otherEditor");
|
||||
|
||||
// XXX if there is a contenteditable element, HTML editor sets dom selection
|
||||
// to first editable node, but this makes inconsistency with normal document
|
||||
// behavior.
|
||||
todo_is(selection.rangeCount, 0, "unexpected selection range is there");
|
||||
ok(!selCon.caretVisible, "caret is visible in the document");
|
||||
// Move focus to inputTextInEditor
|
||||
inputTextInEditor.focus();
|
||||
is(fm.focusedElement, inputTextInEditor,
|
||||
"inputTextInEditor didn't get focus");
|
||||
todo_is(selection.rangeCount, 0, "unexpected selection range is there");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the inputTextInEditor");
|
||||
// Move focus to the editor
|
||||
editor.focus();
|
||||
is(fm.focusedElement, editor,
|
||||
"editor didn't get focus");
|
||||
is(selection.rangeCount, 1,
|
||||
"there is no selection range when editor has focus");
|
||||
var range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
var startNode = range.startContainer;
|
||||
is(startNode.nodeType, 1, "the caret isn't set to the div node");
|
||||
is(startNode, editor, "the caret isn't set to the editor");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the editor");
|
||||
// Move focus to other editor
|
||||
otherEditor.focus();
|
||||
is(fm.focusedElement, otherEditor,
|
||||
"the other editor didn't get focus");
|
||||
is(selection.rangeCount, 1,
|
||||
"there is no selection range when the other editor has focus");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
var startNode = range.startContainer;
|
||||
is(startNode.nodeType, 1, "the caret isn't set to the div node");
|
||||
is(startNode, otherEditor, "the caret isn't set to the other editor");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the other editor");
|
||||
// Move focus to inputTextInEditor
|
||||
inputTextInEditor.focus();
|
||||
is(fm.focusedElement, inputTextInEditor,
|
||||
"inputTextInEditor didn't get focus #2");
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
var startNode = range.startContainer;
|
||||
is(startNode.nodeType, 1, "the caret isn't set to the div node");
|
||||
// XXX maybe, the caret can stay on the other editor if it's better.
|
||||
is(startNode, editor,
|
||||
"the caret should stay on the other editor");
|
||||
ok(selCon.caretVisible,
|
||||
"caret isn't visible in the inputTextInEditor");
|
||||
// Move focus to the other editor again
|
||||
otherEditor.focus();
|
||||
is(fm.focusedElement, otherEditor,
|
||||
"the other editor didn't get focus #2");
|
||||
// Set selection to the span element in the editor (unfocused)
|
||||
range = document.createRange();
|
||||
range.setStart(spanInEditor.firstChild, 5);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
is(fm.focusedElement, otherEditor,
|
||||
"the other editor shouldn't lose focus by selection range change");
|
||||
ok(selCon.caretVisible, "caret isn't visible in inputTextInEditor");
|
||||
// Move focus to the editor
|
||||
editor.focus();
|
||||
is(fm.focusedElement, editor,
|
||||
"the editor didn't get focus #2");
|
||||
is(selection.rangeCount, 1, "selection range is lost from the document");
|
||||
range = selection.getRangeAt(0);
|
||||
ok(range.collapsed, "the selection range isn't collapsed");
|
||||
is(range.startOffset, 5,
|
||||
"the caret is moved when the editor was focused (offset)");
|
||||
var startNode = range.startContainer;
|
||||
is(startNode.nodeType, 3, "the caret isn't in text node");
|
||||
is(startNode.parentNode, spanInEditor,
|
||||
"the caret is moved when the editor was focused (node)");
|
||||
ok(selCon.caretVisible, "caret isn't visible in the editor (spanInEditor)");
|
||||
|
||||
// Move focus to each focusable element in the editor.
|
||||
function testFocusMove(aSetFocusElementID, aFocusable, aCaretVisible)
|
||||
{
|
||||
editor.focus();
|
||||
is(fm.focusedElement, editor,
|
||||
"testFocusMove: the editor didn't get focus at initializing (" +
|
||||
aSetFocusElementID + ")");
|
||||
var setFocusElement = document.getElementById(aSetFocusElementID);
|
||||
setFocusElement.focus();
|
||||
if (aFocusable) {
|
||||
is(fm.focusedElement, setFocusElement,
|
||||
"testFocusMove: the " + aSetFocusElementID +
|
||||
" didn't get focus");
|
||||
} else {
|
||||
is(fm.focusedElement, editor,
|
||||
"testFocusMove: the editor lost focus by focus() of the " +
|
||||
aSetFocusElementID);
|
||||
}
|
||||
if (aCaretVisible) {
|
||||
ok(selCon.caretVisible,
|
||||
"testFocusMove: caret isn't visible when the " +
|
||||
aSetFocusElementID + " has focus");
|
||||
} else {
|
||||
ok(!selCon.caretVisible,
|
||||
"testFocusMove: caret is visible when the " +
|
||||
aSetFocusElementID + " has focus");
|
||||
}
|
||||
}
|
||||
testFocusMove("inputTextInEditor", true, true);
|
||||
testFocusMove("inputTextReadonlyInEditor", true, true);
|
||||
// XXX shouldn't the caret become invisible?
|
||||
testFocusMove("inputButtonInEditor", true, true);
|
||||
testFocusMove("noeditableInEditor", false, true);
|
||||
testFocusMove("spanInNoneditableInEditor", false, true);
|
||||
testFocusMove("inputTextInNoneditableInEditor", true, true);
|
||||
testFocusMove("inputTextReadonlyInNoneditableInEditor", true, true);
|
||||
testFocusMove("inputButtonInNoneditableInEditor", true, false);
|
||||
testFocusMove("buttonInNoneditableInEditor", true, false);
|
||||
testFocusMove("spanInEditor", false, true);
|
||||
testFocusMove("inputText", true, true);
|
||||
testFocusMove("inputTextReadonly", true, true);
|
||||
testFocusMove("inputButton", true, false);
|
||||
testFocusMove("button", true, false);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,4 +1,4 @@
|
|||
<html>
|
||||
<html style="ime-mode: disabled;">
|
||||
<head>
|
||||
<title>Test for IME state controling</title>
|
||||
<script type="text/javascript"
|
||||
|
@ -8,8 +8,8 @@
|
|||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="setTimeout(runTests, 0);">
|
||||
<p id="display">
|
||||
<body onload="setTimeout(runTests, 0);" style="ime-mode: disabled;">
|
||||
<div id="display" style="ime-mode: disabled;">
|
||||
<!-- input elements -->
|
||||
<input type="text" id="text"/><br/>
|
||||
<input type="text" id="text_readonly" readonly="readonly"/><br/>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<isindex id="isindex" prompt="isindex"/><br/>
|
||||
|
||||
<!-- a element -->
|
||||
<a id="a_href" href="">a[href]</a><br/>
|
||||
<a id="a_href" href="about:blank">a[href]</a><br/>
|
||||
|
||||
<!-- ime-mode test -->
|
||||
<input type="text" id="ime_mode_auto" style="ime-mode: auto;"/><br/>
|
||||
|
@ -57,7 +57,15 @@
|
|||
|
||||
<!-- plugin -->
|
||||
<object type="application/x-test" id="plugin"></object><br/>
|
||||
</p>
|
||||
|
||||
<!-- contenteditable editor -->
|
||||
<div id="contenteditableEditor" contenteditable="true"></div>
|
||||
|
||||
<!-- designMode editor -->
|
||||
<iframe id="designModeEditor"
|
||||
onload="document.getElementById('designModeEditor').contentDocument.designMode = 'on';"
|
||||
src="data:text/html,<html><body></body></html>"></iframe><br/>
|
||||
</div>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
@ -71,6 +79,8 @@ SimpleTest.waitForExplicitFinish();
|
|||
var gUtils = window.
|
||||
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
var gFM = Components.classes["@mozilla.org/focus-manager;1"].
|
||||
getService(Components.interfaces.nsIFocusManager);
|
||||
const kIMEEnabledSupported = navigator.platform.indexOf("Mac") == 0 ||
|
||||
navigator.platform.indexOf("Win") == 0 ||
|
||||
navigator.platform.indexOf("Linux") == 0;
|
||||
|
@ -83,29 +93,51 @@ const kIMEOpenSupported = false;
|
|||
|
||||
function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
||||
{
|
||||
var defaultEnabledState =
|
||||
aIsEditable ? gUtils.IME_STATUS_ENABLED : gUtils.IME_STATUS_DISABLED;
|
||||
|
||||
var nonFormControlNodeEnabledState =
|
||||
aInDesignMode ? gUtils.IME_STATUS_ENABLED : gUtils.IME_STATUS_DISABLED;
|
||||
|
||||
function test(aTest)
|
||||
{
|
||||
function moveFocus(aTest)
|
||||
{
|
||||
if (aTest.expectedEnabled == gUtils.IME_STATUS_DISABLED) {
|
||||
document.getElementById("text").focus();
|
||||
if (aInDesignMode) {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
} else if (aIsEditable) {
|
||||
document.getElementById("display").focus();
|
||||
} else if (aTest.expectedEnabled == gUtils.IME_STATUS_ENABLED) {
|
||||
document.getElementById("password").focus();
|
||||
} else {
|
||||
document.activeElement.blur();
|
||||
document.getElementById("text").focus();
|
||||
}
|
||||
document.getElementById(aTest.id).focus();
|
||||
var previousFocusedElement = gFM.focusedElement;
|
||||
var element = document.getElementById(aTest.id);
|
||||
if (element.contentDocument) {
|
||||
element = element.contentDocument.documentElement;
|
||||
}
|
||||
element.focus();
|
||||
var focusedElement = gFM.focusedElement;
|
||||
if (focusedElement) {
|
||||
var bindingParent = document.getBindingParent(focusedElement);
|
||||
if (bindingParent) {
|
||||
focusedElement = bindingParent;
|
||||
}
|
||||
}
|
||||
if (aTest.focusable) {
|
||||
is(focusedElement, element,
|
||||
aDescription + ": " + aTest.description + ", focus didn't move");
|
||||
return (element == focusedElement);
|
||||
}
|
||||
is(focusedElement, previousFocusedElement,
|
||||
aDescription + ": " + aTest.description + ", focus moved as unexpected");
|
||||
return (previousFocusedElement == focusedElement);
|
||||
}
|
||||
|
||||
function testOpened(aTest, aOpened)
|
||||
{
|
||||
document.getElementById("text").focus();
|
||||
gUtils.IMEIsOpen = aOpened;
|
||||
moveFocus(aTest);
|
||||
if (!moveFocus(aTest)) {
|
||||
return;
|
||||
}
|
||||
var message = aDescription + ": " + aTest.description +
|
||||
", wrong opened state";
|
||||
is(gUtils.IMEIsOpen,
|
||||
|
@ -115,12 +147,11 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
|||
// IME Enabled state testing
|
||||
var enabled = gUtils.IME_STATUS_ENABLED;
|
||||
if (kIMEEnabledSupported) {
|
||||
moveFocus(aTest);
|
||||
if (!moveFocus(aTest)) {
|
||||
return;
|
||||
}
|
||||
enabled = gUtils.IMEStatus;
|
||||
// no focusing of html elements is possible in design mode so ime should
|
||||
// always be enabled for the document
|
||||
var expected = aInDesignMode ? gUtils.IME_STATUS_ENABLED : aTest.expectedEnabled;
|
||||
is(enabled, expected,
|
||||
is(enabled, aTest.expectedEnabled,
|
||||
aDescription + ": " + aTest.description + ", wrong enabled state");
|
||||
}
|
||||
|
||||
|
@ -135,120 +166,176 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
|||
}
|
||||
|
||||
if (kIMEEnabledSupported) {
|
||||
// make sure there is an active element
|
||||
document.getElementById("text").focus();
|
||||
document.activeElement.blur();
|
||||
is(gUtils.IMEStatus, nonFormControlNodeEnabledState,
|
||||
is(gUtils.IMEStatus,
|
||||
aInDesignMode ? gUtils.IME_STATUS_ENABLED : gUtils.IME_STATUS_DISABLED,
|
||||
aDescription + ": unexpected enabled state when no element has focus");
|
||||
}
|
||||
|
||||
// Form controls except text editable elements are "disable" in normal
|
||||
// condition, however, if they are editable, they are "enabled".
|
||||
// XXX Probably there are some bugs: If the form controls editable, they
|
||||
// shouldn't be focusable.
|
||||
const kEnabledStateOnNonEditableElement =
|
||||
(aInDesignMode || aIsEditable) ? gUtils.IME_STATUS_ENABLED :
|
||||
gUtils.IME_STATUS_DISABLED;
|
||||
const kEnabledStateOnPasswordField =
|
||||
aInDesignMode ? gUtils.IME_STATUS_ENABLED : gUtils.IME_STATUS_PASSWORD;
|
||||
const kEnabledStateOnReadonlyField =
|
||||
aInDesignMode ? gUtils.IME_STATUS_ENABLED : gUtils.IME_STATUS_DISABLED;
|
||||
const kTests = [
|
||||
{ id: "text",
|
||||
description: "input[type=text]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "text_readonly",
|
||||
description: "input[type=text][readonly]",
|
||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||
{ id: "password",
|
||||
description: "input[type=password]",
|
||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnPasswordField },
|
||||
{ id: "password_readonly",
|
||||
description: "input[type=password][readonly]",
|
||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||
{ id: "checkbox",
|
||||
description: "input[type=checkbox]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "radio",
|
||||
description: "input[type=radio]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "submit",
|
||||
description: "input[type=submit]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "reset",
|
||||
description: "input[type=reset]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "file",
|
||||
description: "input[type=file]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "button",
|
||||
description: "input[type=button]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "image",
|
||||
description: "input[type=image]",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
|
||||
// form controls
|
||||
{ id: "button",
|
||||
description: "button",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "textarea",
|
||||
description: "textarea",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "textarea_readonly",
|
||||
description: "textarea[readonly]",
|
||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||
{ id: "select",
|
||||
description: "select (dropdown list)",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
{ id: "select_multiple",
|
||||
description: "select (list box)",
|
||||
expectedEnabled: defaultEnabledState },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
|
||||
// a element
|
||||
{ id: "a_href",
|
||||
description: "a[href]",
|
||||
expectedEnabled: nonFormControlNodeEnabledState },
|
||||
focusable: !aIsEditable && !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||
|
||||
// ime-mode
|
||||
{ id: "ime_mode_auto",
|
||||
description: "input[type=text][style=\"ime-mode: auto;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "ime_mode_normal",
|
||||
description: "input[type=text][style=\"ime-mode: normal;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "ime_mode_active",
|
||||
description: "input[type=text][style=\"ime-mode: active;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
focusable: !aInDesignMode,
|
||||
changeOpened: true, expectedOpened: true },
|
||||
{ id: "ime_mode_inactive",
|
||||
description: "input[type=text][style=\"ime-mode: inactive;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
focusable: !aInDesignMode,
|
||||
changeOpened: true, expectedOpened: false },
|
||||
{ id: "ime_mode_disabled",
|
||||
description: "input[type=text][style=\"ime-mode: disabled;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnPasswordField },
|
||||
{ id: "ime_mode_auto_p",
|
||||
description: "input[type=password][style=\"ime-mode: auto;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnPasswordField },
|
||||
{ id: "ime_mode_normal_p",
|
||||
description: "input[type=password][style=\"ime-mode: normal;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "ime_mode_active_p",
|
||||
description: "input[type=password][style=\"ime-mode: active;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
focusable: !aInDesignMode,
|
||||
changeOpened: true, expectedOpened: true },
|
||||
{ id: "ime_mode_inactive_p",
|
||||
description: "input[type=password][style=\"ime-mode: inactive;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
focusable: !aInDesignMode,
|
||||
changeOpened: true, expectedOpened: false },
|
||||
{ id: "ime_mode_disabled_p",
|
||||
description: "input[type=password][style=\"ime-mode: disabled;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnPasswordField },
|
||||
{ id: "ime_mode_auto",
|
||||
description: "textarea[style=\"ime-mode: auto;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "ime_mode_normal",
|
||||
description: "textarea[style=\"ime-mode: normal;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "ime_mode_active",
|
||||
description: "textarea[style=\"ime-mode: active;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
changeOpened: true, expectedOpened: true },
|
||||
{ id: "ime_mode_inactive",
|
||||
description: "textarea[style=\"ime-mode: inactive;\"]",
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||
changeOpened: true, expectedOpened: false },
|
||||
{ id: "ime_mode_disabled",
|
||||
description: "textarea[style=\"ime-mode: disabled;\"]",
|
||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD }
|
||||
focusable: !aInDesignMode,
|
||||
expectedEnabled: kEnabledStateOnPasswordField },
|
||||
|
||||
// HTML editors
|
||||
{ id: "contenteditableEditor",
|
||||
description: "div[contenteditable=\"true\"]",
|
||||
focusable: !aIsEditable && !aInDesignMode,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
{ id: "designModeEditor",
|
||||
description: "designMode editor",
|
||||
focusable: true,
|
||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||
];
|
||||
|
||||
for (var i = 0; i < kTests.length; i++) {
|
||||
|
@ -351,7 +438,7 @@ function runTypeChangingTest()
|
|||
type: "text", expected: gUtils.IME_STATUS_PASSWORD, imeMode: true,
|
||||
description: "[type=\"text\"][ime-mode: disabled;]" },
|
||||
{ id: "ime_mode_auto_p",
|
||||
type: "password", expected: gUtils.IME_STATUS_ENABLED, imeMode: true,
|
||||
type: "password", expected: gUtils.IME_STATUS_PASSWORD, imeMode: true,
|
||||
description: "[type=\"password\"][ime-mode: auto;]" },
|
||||
{ id: "ime_mode_normal_p",
|
||||
type: "password", expected: gUtils.IME_STATUS_ENABLED, imeMode: true,
|
||||
|
@ -383,7 +470,7 @@ function runTypeChangingTest()
|
|||
function getExpectedIMEEnabled(aNewType, aInputControl)
|
||||
{
|
||||
if (aNewType.expected == gUtils.IME_STATUS_DISABLED ||
|
||||
aInputControl.isReadOnly)
|
||||
aInputControl.isReadonly)
|
||||
return gUtils.IME_STATUS_DISABLED;
|
||||
return aInputControl.imeMode ? aInputControl.expected : aNewType.expected;
|
||||
}
|
||||
|
@ -477,6 +564,214 @@ function runReadonlyChangingTest()
|
|||
}
|
||||
}
|
||||
|
||||
function runComplexContenteditableTests()
|
||||
{
|
||||
if (!kIMEEnabledSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
var description = "runReadonlyChangingOnContenteditable: ";
|
||||
|
||||
var container = document.getElementById("display");
|
||||
var button = document.getElementById("button");
|
||||
|
||||
// the editor has focus directly.
|
||||
container.setAttribute("contenteditable", "true");
|
||||
container.focus();
|
||||
|
||||
is(gFM.focusedElement, container,
|
||||
description + "The editor doesn't get focus");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_ENABLED,
|
||||
description + "IME isn't enabled on HTML editor");
|
||||
const kReadonly =
|
||||
Components.interfaces.nsIPlaintextEditor.eEditorReadonlyMask;
|
||||
var editor =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIWebNavigation).
|
||||
QueryInterface(Components.interfaces.nsIEditorDocShell).editor;
|
||||
var flags = editor.flags;
|
||||
editor.flags = flags | kReadonly;
|
||||
is(gFM.focusedElement, container,
|
||||
description + "The editor loses focus by flag change");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_DISABLED,
|
||||
description + "IME is still enabled on readonly HTML editor");
|
||||
editor.flags = flags;
|
||||
is(gFM.focusedElement, container,
|
||||
description + "The editor loses focus by flag change #2");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_ENABLED,
|
||||
description + "IME is still disabled, the editor isn't readonly now");
|
||||
container.removeAttribute("contenteditable");
|
||||
todo_is(gFM.focusedElement, null,
|
||||
description + "The container still has focus, the editor has been no editable");
|
||||
todo_is(gUtils.IMEStatus, gUtils.IME_STATUS_DISABLED,
|
||||
description + "IME is still enabled on the editor, the editor has been no editable");
|
||||
|
||||
// a button which is in the editor has focus
|
||||
button.focus();
|
||||
is(gFM.focusedElement, button,
|
||||
description + "The button doesn't get focus");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_DISABLED,
|
||||
description + "IME is enabled on the button");
|
||||
container.setAttribute("contenteditable", "true");
|
||||
is(gFM.focusedElement, button,
|
||||
description + "The button loses focus, the container is editable now");
|
||||
todo_is(gUtils.IMEStatus, gUtils.IME_STATUS_ENABLED,
|
||||
description + "IME is still disabled on the button, the container is editable now");
|
||||
editor =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIWebNavigation).
|
||||
QueryInterface(Components.interfaces.nsIEditorDocShell).editor;
|
||||
flags = editor.flags;
|
||||
editor.flags = flags | kReadonly;
|
||||
is(gFM.focusedElement, button,
|
||||
description + "The button loses focus by changing editor flags");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_DISABLED,
|
||||
description + "IME is still enabled on the button, the container is readonly now");
|
||||
editor.flags = flags;
|
||||
is(gFM.focusedElement, button,
|
||||
description + "The button loses focus by changing editor flags #2");
|
||||
is(gUtils.IMEStatus, gUtils.IME_STATUS_ENABLED,
|
||||
description + "IME is still disabled on the button, the container isn't readonly now");
|
||||
container.removeAttribute("contenteditable");
|
||||
is(gFM.focusedElement, button,
|
||||
description + "The button loses focus, the container has been no editable");
|
||||
todo_is(gUtils.IMEStatus, gUtils.IME_STATUS_DISABLED,
|
||||
description + "IME is still enabled on the button, the container has been no editable");
|
||||
|
||||
description = "testOnIndependentEditor: ";
|
||||
function testOnIndependentEditor(aEditor, aEditorDescription)
|
||||
{
|
||||
var isReadonly = aEditor.readOnly;
|
||||
var expectedState =
|
||||
aEditor.readOnly ? gUtils.IME_STATUS_DISABLED : gUtils.IME_STATUS_ENABLED;
|
||||
var unexpectedStateDescription =
|
||||
expectedState != gUtils.IME_STATUS_ENABLED ? "enabled" : "disabled";
|
||||
aEditor.focus();
|
||||
is(gFM.focusedElement, aEditor,
|
||||
description + "The " + aEditorDescription + " doesn't get focus");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME is " + unexpectedStateDescription +
|
||||
" on the " + aEditorDescription);
|
||||
container.setAttribute("contenteditable", "true");
|
||||
is(gFM.focusedElement, aEditor,
|
||||
description + "The " + aEditorDescription +
|
||||
" loses focus, the container is editable now");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription +
|
||||
" on the " + aEditorDescription + ", the container is editable now");
|
||||
editor =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIWebNavigation).
|
||||
QueryInterface(Components.interfaces.nsIEditorDocShell).editor;
|
||||
flags = editor.flags;
|
||||
editor.flags = flags | kReadonly;
|
||||
is(gFM.focusedElement, aEditor,
|
||||
description + "The " + aEditorDescription +
|
||||
" loses focus by changing editor flags");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on the " +
|
||||
aEditorDescription + ", the container is readonly now");
|
||||
editor.flags = flags;
|
||||
is(gFM.focusedElement, aEditor,
|
||||
description + "The " + aEditorDescription +
|
||||
" loses focus by changing editor flags #2");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on the " +
|
||||
aEditorDescription + ", the container isn't readonly now");
|
||||
container.removeAttribute("contenteditable");
|
||||
is(gFM.focusedElement, aEditor,
|
||||
description + "The " + aEditorDescription +
|
||||
" loses focus, the container has been no editable");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on the " +
|
||||
aEditorDescription + ", the container has been no editable");
|
||||
}
|
||||
|
||||
// a textarea which is in the editor has focus
|
||||
testOnIndependentEditor(document.getElementById("textarea"),
|
||||
"textarea");
|
||||
// a readonly textarea which is in the editor has focus
|
||||
testOnIndependentEditor(document.getElementById("textarea_readonly"),
|
||||
"textarea[readonly]");
|
||||
// an input field which is in the editor has focus
|
||||
testOnIndependentEditor(document.getElementById("text"),
|
||||
"input[type=\"text\"]");
|
||||
// a readonly input field which is in the editor has focus
|
||||
testOnIndependentEditor(document.getElementById("text_readonly"),
|
||||
"input[type=\"text\"][readonly]");
|
||||
|
||||
description = "testOnOutsideOfEditor: ";
|
||||
function testOnOutsideOfEditor(aFocusNode, aFocusNodeDescription, aEditor)
|
||||
{
|
||||
if (aFocusNode) {
|
||||
aFocusNode.focus();
|
||||
is(gFM.focusedElement, aFocusNode,
|
||||
description + "The " + aFocusNodeDescription + " doesn't get focus");
|
||||
} else {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
is(gFM.focusedElement, null,
|
||||
description + "Unexpected element has focus");
|
||||
}
|
||||
var expectedState =
|
||||
aFocusNode ? gUtils.IMEStatus : gUtils.IME_STATUS_DISABLED;
|
||||
var unexpectedStateDescription =
|
||||
expectedState != gUtils.IME_STATUS_ENABLED ? "enabled" : "disabled";
|
||||
|
||||
aEditor.setAttribute("contenteditable", "true");
|
||||
is(gFM.focusedElement, aFocusNode,
|
||||
description + "The " + aFocusNodeDescription +
|
||||
" loses focus, a HTML editor is editable now");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription +
|
||||
" on the " + aFocusNodeDescription +
|
||||
", the HTML editor is editable now");
|
||||
editor =
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIWebNavigation).
|
||||
QueryInterface(Components.interfaces.nsIEditorDocShell).editor;
|
||||
flags = editor.flags;
|
||||
editor.flags = flags | kReadonly;
|
||||
is(gFM.focusedElement, aFocusNode,
|
||||
description + aFocusNodeDescription +
|
||||
" loses focus by changing HTML editor flags");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on " +
|
||||
aFocusNodeDescription + ", the HTML editor is readonly now");
|
||||
editor.flags = flags;
|
||||
is(gFM.focusedElement, aFocusNode,
|
||||
description + aFocusNodeDescription +
|
||||
" loses focus by changing HTML editor flags #2");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on " +
|
||||
aFocusNodeDescription + ", the HTML editor isn't readonly now");
|
||||
container.removeAttribute("contenteditable");
|
||||
is(gFM.focusedElement, aFocusNode,
|
||||
description + aFocusNodeDescription +
|
||||
" loses focus, the HTML editor has been no editable");
|
||||
is(gUtils.IMEStatus, expectedState,
|
||||
description + "IME becomes " + unexpectedStateDescription + " on " +
|
||||
aFocusNodeDescription + ", the HTML editor has been no editable");
|
||||
}
|
||||
|
||||
var div = document.getElementById("contenteditableEditor");
|
||||
// a textarea which is outside of the editor has focus
|
||||
testOnOutsideOfEditor(document.getElementById("textarea"), "textarea", div);
|
||||
// a readonly textarea which is outside of the editor has focus
|
||||
testOnOutsideOfEditor(document.getElementById("textarea_readonly"),
|
||||
"textarea[readonly]", div);
|
||||
// an input field which is outside of the editor has focus
|
||||
testOnOutsideOfEditor(document.getElementById("text"),
|
||||
"input[type=\"text\"]", div);
|
||||
// a readonly input field which outside of the editor has focus
|
||||
testOnOutsideOfEditor(document.getElementById("text_readonly"),
|
||||
"input[type=\"text\"][readonly]", div);
|
||||
// a readonly input field which outside of the editor has focus
|
||||
testOnOutsideOfEditor(document.getElementById("button"), "button", div);
|
||||
// nobody has focus.
|
||||
testOnOutsideOfEditor(null, "nobody", div);
|
||||
}
|
||||
|
||||
function runEditableSubframeTests()
|
||||
{
|
||||
|
@ -519,12 +814,14 @@ function runTests()
|
|||
runBasicTest(false, false, "Testing designMode=\"off\"");
|
||||
|
||||
// changing input[type] values
|
||||
// XXX currently, type attribute changing doesn't work fine. bug 488420.
|
||||
// XXX currently, type attribute changing doesn't work fine. bug 559728.
|
||||
// runTypeChangingTest();
|
||||
|
||||
// changing readonly attribute
|
||||
// XXX currently, readonly attribute changing doesn't work fine. bug 488420.
|
||||
// runReadonlyChangingTest();
|
||||
runReadonlyChangingTest();
|
||||
|
||||
// complex contenteditable editor's tests
|
||||
runComplexContenteditableTests();
|
||||
|
||||
runASyncTests();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче