зеркало из 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_PASSWORD | IME_STATUS_PLUGIN,
|
||||||
IME_STATUS_MASK_OPENED = IME_STATUS_OPEN | IME_STATUS_CLOSE
|
IME_STATUS_MASK_OPENED = IME_STATUS_OPEN | IME_STATUS_CLOSE
|
||||||
};
|
};
|
||||||
virtual PRUint32 GetDesiredIMEState()
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets content node with the binding (or native code, possibly on the
|
* Gets content node with the binding (or native code, possibly on the
|
||||||
|
|
|
@ -125,6 +125,7 @@
|
||||||
#include "nsIDOMUserDataHandler.h"
|
#include "nsIDOMUserDataHandler.h"
|
||||||
#include "nsGenericHTMLElement.h"
|
#include "nsGenericHTMLElement.h"
|
||||||
#include "nsIEditor.h"
|
#include "nsIEditor.h"
|
||||||
|
#include "nsIEditorIMESupport.h"
|
||||||
#include "nsIEditorDocShell.h"
|
#include "nsIEditorDocShell.h"
|
||||||
#include "nsEventDispatcher.h"
|
#include "nsEventDispatcher.h"
|
||||||
#include "nsContentCreatorFunctions.h"
|
#include "nsContentCreatorFunctions.h"
|
||||||
|
@ -636,6 +637,47 @@ nsIContent::GetFlattenedTreeParent() const
|
||||||
return parent;
|
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)
|
NS_IMPL_ADDREF(nsChildContentList)
|
||||||
|
|
|
@ -83,7 +83,7 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||||
nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
|
nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
||||||
SetIMEState(sPresContext, newState, widget);
|
SetIMEState(newState, widget);
|
||||||
}
|
}
|
||||||
sContent = nsnull;
|
sContent = nsnull;
|
||||||
sPresContext = nsnull;
|
sPresContext = nsnull;
|
||||||
|
@ -108,7 +108,7 @@ nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
widget->ResetInputState();
|
widget->ResetInputState();
|
||||||
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
|
||||||
SetIMEState(sPresContext, newState, widget);
|
SetIMEState(newState, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
sContent = nsnull;
|
sContent = nsnull;
|
||||||
|
@ -162,7 +162,7 @@ nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
|
||||||
|
|
||||||
if (newState != nsIContent::IME_STATUS_NONE) {
|
if (newState != nsIContent::IME_STATUS_NONE) {
|
||||||
// Update IME state for new focus widget
|
// Update IME state for new focus widget
|
||||||
SetIMEState(aPresContext, newState, widget);
|
SetIMEState(newState, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
sPresContext = aPresContext;
|
sPresContext = aPresContext;
|
||||||
|
@ -178,6 +178,26 @@ nsIMEStateManager::OnInstalledMenuKeyboardListener(PRBool aInstalling)
|
||||||
OnChangeFocus(sPresContext, sContent);
|
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
|
PRUint32
|
||||||
nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||||
nsIContent* aContent)
|
nsIContent* aContent)
|
||||||
|
@ -204,18 +224,17 @@ nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsIMEStateManager::SetIMEState(nsPresContext* aPresContext,
|
nsIMEStateManager::SetIMEState(PRUint32 aState,
|
||||||
PRUint32 aState,
|
nsIWidget* aWidget)
|
||||||
nsIWidget* aKB)
|
|
||||||
{
|
{
|
||||||
if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
|
if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
|
||||||
PRUint32 state =
|
PRUint32 state =
|
||||||
nsContentUtils::GetWidgetStatusFromIMEStatus(aState);
|
nsContentUtils::GetWidgetStatusFromIMEStatus(aState);
|
||||||
aKB->SetIMEEnabled(state);
|
aWidget->SetIMEEnabled(state);
|
||||||
}
|
}
|
||||||
if (aState & nsIContent::IME_STATUS_MASK_OPENED) {
|
if (aState & nsIContent::IME_STATUS_MASK_OPENED) {
|
||||||
PRBool open = !!(aState & nsIContent::IME_STATUS_OPEN);
|
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
|
// Get the focused editor's selection and root
|
||||||
static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
|
static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
|
||||||
nsIContent** aRoot);
|
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:
|
protected:
|
||||||
static void SetIMEState(nsPresContext* aPresContext,
|
static void SetIMEState(PRUint32 aState, nsIWidget* aWidget);
|
||||||
PRUint32 aState,
|
|
||||||
nsIWidget* aKB);
|
|
||||||
static PRUint32 GetNewIMEState(nsPresContext* aPresContext,
|
static PRUint32 GetNewIMEState(nsPresContext* aPresContext,
|
||||||
nsIContent* aContent);
|
nsIContent* aContent);
|
||||||
|
|
||||||
|
|
|
@ -91,4 +91,5 @@ include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
INCLUDES += \
|
INCLUDES += \
|
||||||
-I$(topsrcdir)/content/base/src \
|
-I$(topsrcdir)/content/base/src \
|
||||||
|
-I$(topsrcdir)/content/events/src \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
#include "nsIDOMHTMLElement.h"
|
#include "nsIDOMHTMLElement.h"
|
||||||
#include "nsIDOMNSHTMLElement.h"
|
#include "nsIDOMNSHTMLElement.h"
|
||||||
#include "nsPIDOMEventTarget.h"
|
#include "nsPIDOMEventTarget.h"
|
||||||
|
#include "nsIMEStateManager.h"
|
||||||
|
#include "nsFocusManager.h"
|
||||||
#include "nsIPrefBranch.h"
|
#include "nsIPrefBranch.h"
|
||||||
#include "nsIPrefService.h"
|
#include "nsIPrefService.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
|
@ -219,13 +221,17 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||||
if ((nsnull==aDoc) || (nsnull==aPresShell))
|
if ((nsnull==aDoc) || (nsnull==aPresShell))
|
||||||
return NS_ERROR_NULL_POINTER;
|
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
|
mDocWeak = do_GetWeakReference(aDoc); // weak reference to doc
|
||||||
mPresShellWeak = do_GetWeakReference(aPresShell); // weak reference to pres shell
|
mPresShellWeak = do_GetWeakReference(aPresShell); // weak reference to pres shell
|
||||||
mSelConWeak = do_GetWeakReference(aSelCon); // weak reference to selectioncontroller
|
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);
|
nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
|
||||||
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
if (!ps) return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
|
||||||
|
@ -279,8 +285,8 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsEditor::PostCreate()
|
nsEditor::PostCreate()
|
||||||
{
|
{
|
||||||
// Set up spellchecking
|
// Synchronize some stuff for the flags
|
||||||
nsresult rv = SyncRealTimeSpell();
|
nsresult rv = SetFlags(mFlags);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// Set up listeners
|
// Set up listeners
|
||||||
|
@ -437,8 +443,29 @@ nsEditor::SetFlags(PRUint32 aFlags)
|
||||||
{
|
{
|
||||||
mFlags = 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
|
// 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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5155,3 +5182,18 @@ nsEditor::IsModifiableNode(nsIDOMNode *aNode)
|
||||||
{
|
{
|
||||||
return PR_TRUE;
|
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;
|
return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether the editor has focus or not.
|
||||||
|
virtual PRBool HasFocus();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
PRUint32 mModCount; // number of modifications (for undo/redo stack)
|
PRUint32 mModCount; // number of modifications (for undo/redo stack)
|
||||||
|
|
|
@ -917,6 +917,9 @@ FindSelectionRoot(nsEditor *aEditor, nsIContent *aContent)
|
||||||
return root;
|
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()) {
|
if (aEditor->IsReadonly()) {
|
||||||
// We still want to allow selection in a readonly editor.
|
// We still want to allow selection in a readonly editor.
|
||||||
nsCOMPtr<nsIDOMElement> rootElement;
|
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
|
// For non-readonly editors we want to find the root of the editable subtree
|
||||||
// containing aContent.
|
// 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;
|
nsIContent *parent, *content = aContent;
|
||||||
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
|
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
|
||||||
content = parent;
|
content = parent;
|
||||||
|
@ -965,6 +973,12 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
|
||||||
PRBool targetIsEditableDoc = PR_FALSE;
|
PRBool targetIsEditableDoc = PR_FALSE;
|
||||||
nsCOMPtr<nsIContent> editableRoot;
|
nsCOMPtr<nsIContent> editableRoot;
|
||||||
if (content) {
|
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);
|
editableRoot = FindSelectionRoot(mEditor, content);
|
||||||
|
|
||||||
// make sure that the element is really focused in case an earlier
|
// make sure that the element is really focused in case an earlier
|
||||||
|
|
|
@ -97,6 +97,8 @@
|
||||||
#include "SetDocTitleTxn.h"
|
#include "SetDocTitleTxn.h"
|
||||||
#include "nsGUIEvent.h"
|
#include "nsGUIEvent.h"
|
||||||
#include "nsTextFragment.h"
|
#include "nsTextFragment.h"
|
||||||
|
#include "nsFocusManager.h"
|
||||||
|
#include "nsPIDOMWindow.h"
|
||||||
|
|
||||||
// netwerk
|
// netwerk
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
|
@ -5632,3 +5634,78 @@ nsHTMLEditor::GetReturnInParagraphCreatesNewParagraph(PRBool *aCreatesNewParagra
|
||||||
*aCreatesNewParagraph = mCRInParagraphCreatesParagraph;
|
*aCreatesNewParagraph = mCRInParagraphCreatesParagraph;
|
||||||
return NS_OK;
|
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_IMETHODIMP HandleKeyPress(nsIDOMKeyEvent* aKeyEvent);
|
||||||
NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable);
|
NS_IMETHOD GetIsDocumentEditable(PRBool *aIsDocumentEditable);
|
||||||
NS_IMETHODIMP BeginningOfDocument();
|
NS_IMETHODIMP BeginningOfDocument();
|
||||||
|
virtual PRBool HasFocus();
|
||||||
|
|
||||||
|
/* ------------ nsIEditorIMESupport overrides ------------ */
|
||||||
|
NS_IMETHOD GetPreferredIMEState(PRUint32 *aState);
|
||||||
|
|
||||||
/* ------------ nsIHTMLEditor methods -------------- */
|
/* ------------ nsIHTMLEditor methods -------------- */
|
||||||
|
|
||||||
|
@ -725,6 +729,12 @@ protected:
|
||||||
nsresult HasStyleOrIdOrClass(nsIDOMElement * aElement, PRBool *aHasStyleOrIdOrClass);
|
nsresult HasStyleOrIdOrClass(nsIDOMElement * aElement, PRBool *aHasStyleOrIdOrClass);
|
||||||
nsresult RemoveElementIfNoStyleOrIdOrClass(nsIDOMElement * aElement, nsIAtom * aTag);
|
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
|
// Data members
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ _TEST_FILES = \
|
||||||
test_bug487524.html \
|
test_bug487524.html \
|
||||||
test_bug525389.html \
|
test_bug525389.html \
|
||||||
test_bug537046.html \
|
test_bug537046.html \
|
||||||
|
test_contenteditable_focus.html \
|
||||||
test_select_all_without_body.html \
|
test_select_all_without_body.html \
|
||||||
file_select_all_without_body.html \
|
file_select_all_without_body.html \
|
||||||
$(NULL)
|
$(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>
|
<head>
|
||||||
<title>Test for IME state controling</title>
|
<title>Test for IME state controling</title>
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
|
@ -8,8 +8,8 @@
|
||||||
<link rel="stylesheet" type="text/css"
|
<link rel="stylesheet" type="text/css"
|
||||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
</head>
|
</head>
|
||||||
<body onload="setTimeout(runTests, 0);">
|
<body onload="setTimeout(runTests, 0);" style="ime-mode: disabled;">
|
||||||
<p id="display">
|
<div id="display" style="ime-mode: disabled;">
|
||||||
<!-- input elements -->
|
<!-- input elements -->
|
||||||
<input type="text" id="text"/><br/>
|
<input type="text" id="text"/><br/>
|
||||||
<input type="text" id="text_readonly" readonly="readonly"/><br/>
|
<input type="text" id="text_readonly" readonly="readonly"/><br/>
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
<isindex id="isindex" prompt="isindex"/><br/>
|
<isindex id="isindex" prompt="isindex"/><br/>
|
||||||
|
|
||||||
<!-- a element -->
|
<!-- 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 -->
|
<!-- ime-mode test -->
|
||||||
<input type="text" id="ime_mode_auto" style="ime-mode: auto;"/><br/>
|
<input type="text" id="ime_mode_auto" style="ime-mode: auto;"/><br/>
|
||||||
|
@ -57,7 +57,15 @@
|
||||||
|
|
||||||
<!-- plugin -->
|
<!-- plugin -->
|
||||||
<object type="application/x-test" id="plugin"></object><br/>
|
<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 id="content" style="display: none">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,6 +79,8 @@ SimpleTest.waitForExplicitFinish();
|
||||||
var gUtils = window.
|
var gUtils = window.
|
||||||
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||||
|
var gFM = Components.classes["@mozilla.org/focus-manager;1"].
|
||||||
|
getService(Components.interfaces.nsIFocusManager);
|
||||||
const kIMEEnabledSupported = navigator.platform.indexOf("Mac") == 0 ||
|
const kIMEEnabledSupported = navigator.platform.indexOf("Mac") == 0 ||
|
||||||
navigator.platform.indexOf("Win") == 0 ||
|
navigator.platform.indexOf("Win") == 0 ||
|
||||||
navigator.platform.indexOf("Linux") == 0;
|
navigator.platform.indexOf("Linux") == 0;
|
||||||
|
@ -83,29 +93,51 @@ const kIMEOpenSupported = false;
|
||||||
|
|
||||||
function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
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 test(aTest)
|
||||||
{
|
{
|
||||||
function moveFocus(aTest)
|
function moveFocus(aTest)
|
||||||
{
|
{
|
||||||
if (aTest.expectedEnabled == gUtils.IME_STATUS_DISABLED) {
|
if (aInDesignMode) {
|
||||||
document.getElementById("text").focus();
|
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 {
|
} 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)
|
function testOpened(aTest, aOpened)
|
||||||
{
|
{
|
||||||
document.getElementById("text").focus();
|
document.getElementById("text").focus();
|
||||||
gUtils.IMEIsOpen = aOpened;
|
gUtils.IMEIsOpen = aOpened;
|
||||||
moveFocus(aTest);
|
if (!moveFocus(aTest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var message = aDescription + ": " + aTest.description +
|
var message = aDescription + ": " + aTest.description +
|
||||||
", wrong opened state";
|
", wrong opened state";
|
||||||
is(gUtils.IMEIsOpen,
|
is(gUtils.IMEIsOpen,
|
||||||
|
@ -115,12 +147,11 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
||||||
// IME Enabled state testing
|
// IME Enabled state testing
|
||||||
var enabled = gUtils.IME_STATUS_ENABLED;
|
var enabled = gUtils.IME_STATUS_ENABLED;
|
||||||
if (kIMEEnabledSupported) {
|
if (kIMEEnabledSupported) {
|
||||||
moveFocus(aTest);
|
if (!moveFocus(aTest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
enabled = gUtils.IMEStatus;
|
enabled = gUtils.IMEStatus;
|
||||||
// no focusing of html elements is possible in design mode so ime should
|
is(enabled, aTest.expectedEnabled,
|
||||||
// always be enabled for the document
|
|
||||||
var expected = aInDesignMode ? gUtils.IME_STATUS_ENABLED : aTest.expectedEnabled;
|
|
||||||
is(enabled, expected,
|
|
||||||
aDescription + ": " + aTest.description + ", wrong enabled state");
|
aDescription + ": " + aTest.description + ", wrong enabled state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,120 +166,176 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kIMEEnabledSupported) {
|
if (kIMEEnabledSupported) {
|
||||||
|
// make sure there is an active element
|
||||||
|
document.getElementById("text").focus();
|
||||||
document.activeElement.blur();
|
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");
|
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 = [
|
const kTests = [
|
||||||
{ id: "text",
|
{ id: "text",
|
||||||
description: "input[type=text]",
|
description: "input[type=text]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "text_readonly",
|
{ id: "text_readonly",
|
||||||
description: "input[type=text][readonly]",
|
description: "input[type=text][readonly]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||||
{ id: "password",
|
{ id: "password",
|
||||||
description: "input[type=password]",
|
description: "input[type=password]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnPasswordField },
|
||||||
{ id: "password_readonly",
|
{ id: "password_readonly",
|
||||||
description: "input[type=password][readonly]",
|
description: "input[type=password][readonly]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||||
{ id: "checkbox",
|
{ id: "checkbox",
|
||||||
description: "input[type=checkbox]",
|
description: "input[type=checkbox]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "radio",
|
{ id: "radio",
|
||||||
description: "input[type=radio]",
|
description: "input[type=radio]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "submit",
|
{ id: "submit",
|
||||||
description: "input[type=submit]",
|
description: "input[type=submit]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "reset",
|
{ id: "reset",
|
||||||
description: "input[type=reset]",
|
description: "input[type=reset]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "file",
|
{ id: "file",
|
||||||
description: "input[type=file]",
|
description: "input[type=file]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "button",
|
{ id: "button",
|
||||||
description: "input[type=button]",
|
description: "input[type=button]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "image",
|
{ id: "image",
|
||||||
description: "input[type=image]",
|
description: "input[type=image]",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
|
|
||||||
// form controls
|
// form controls
|
||||||
{ id: "button",
|
{ id: "button",
|
||||||
description: "button",
|
description: "button",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "textarea",
|
{ id: "textarea",
|
||||||
description: "textarea",
|
description: "textarea",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "textarea_readonly",
|
{ id: "textarea_readonly",
|
||||||
description: "textarea[readonly]",
|
description: "textarea[readonly]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_DISABLED },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnReadonlyField },
|
||||||
{ id: "select",
|
{ id: "select",
|
||||||
description: "select (dropdown list)",
|
description: "select (dropdown list)",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
{ id: "select_multiple",
|
{ id: "select_multiple",
|
||||||
description: "select (list box)",
|
description: "select (list box)",
|
||||||
expectedEnabled: defaultEnabledState },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
|
|
||||||
// a element
|
// a element
|
||||||
{ id: "a_href",
|
{ id: "a_href",
|
||||||
description: "a[href]",
|
description: "a[href]",
|
||||||
expectedEnabled: nonFormControlNodeEnabledState },
|
focusable: !aIsEditable && !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnNonEditableElement },
|
||||||
|
|
||||||
// ime-mode
|
// ime-mode
|
||||||
{ id: "ime_mode_auto",
|
{ id: "ime_mode_auto",
|
||||||
description: "input[type=text][style=\"ime-mode: auto;\"]",
|
description: "input[type=text][style=\"ime-mode: auto;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "ime_mode_normal",
|
{ id: "ime_mode_normal",
|
||||||
description: "input[type=text][style=\"ime-mode: normal;\"]",
|
description: "input[type=text][style=\"ime-mode: normal;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "ime_mode_active",
|
{ id: "ime_mode_active",
|
||||||
description: "input[type=text][style=\"ime-mode: active;\"]",
|
description: "input[type=text][style=\"ime-mode: active;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
|
focusable: !aInDesignMode,
|
||||||
changeOpened: true, expectedOpened: true },
|
changeOpened: true, expectedOpened: true },
|
||||||
{ id: "ime_mode_inactive",
|
{ id: "ime_mode_inactive",
|
||||||
description: "input[type=text][style=\"ime-mode: inactive;\"]",
|
description: "input[type=text][style=\"ime-mode: inactive;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
|
focusable: !aInDesignMode,
|
||||||
changeOpened: true, expectedOpened: false },
|
changeOpened: true, expectedOpened: false },
|
||||||
{ id: "ime_mode_disabled",
|
{ id: "ime_mode_disabled",
|
||||||
description: "input[type=text][style=\"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",
|
{ id: "ime_mode_auto_p",
|
||||||
description: "input[type=password][style=\"ime-mode: auto;\"]",
|
description: "input[type=password][style=\"ime-mode: auto;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnPasswordField },
|
||||||
{ id: "ime_mode_normal_p",
|
{ id: "ime_mode_normal_p",
|
||||||
description: "input[type=password][style=\"ime-mode: normal;\"]",
|
description: "input[type=password][style=\"ime-mode: normal;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "ime_mode_active_p",
|
{ id: "ime_mode_active_p",
|
||||||
description: "input[type=password][style=\"ime-mode: active;\"]",
|
description: "input[type=password][style=\"ime-mode: active;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
|
focusable: !aInDesignMode,
|
||||||
changeOpened: true, expectedOpened: true },
|
changeOpened: true, expectedOpened: true },
|
||||||
{ id: "ime_mode_inactive_p",
|
{ id: "ime_mode_inactive_p",
|
||||||
description: "input[type=password][style=\"ime-mode: inactive;\"]",
|
description: "input[type=password][style=\"ime-mode: inactive;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
|
focusable: !aInDesignMode,
|
||||||
changeOpened: true, expectedOpened: false },
|
changeOpened: true, expectedOpened: false },
|
||||||
{ id: "ime_mode_disabled_p",
|
{ id: "ime_mode_disabled_p",
|
||||||
description: "input[type=password][style=\"ime-mode: disabled;\"]",
|
description: "input[type=password][style=\"ime-mode: disabled;\"]",
|
||||||
expectedEnabled: gUtils.IME_STATUS_PASSWORD },
|
focusable: !aInDesignMode,
|
||||||
|
expectedEnabled: kEnabledStateOnPasswordField },
|
||||||
{ id: "ime_mode_auto",
|
{ id: "ime_mode_auto",
|
||||||
description: "textarea[style=\"ime-mode: auto;\"]",
|
description: "textarea[style=\"ime-mode: auto;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "ime_mode_normal",
|
{ id: "ime_mode_normal",
|
||||||
description: "textarea[style=\"ime-mode: normal;\"]",
|
description: "textarea[style=\"ime-mode: normal;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
expectedEnabled: gUtils.IME_STATUS_ENABLED },
|
||||||
{ id: "ime_mode_active",
|
{ id: "ime_mode_active",
|
||||||
description: "textarea[style=\"ime-mode: active;\"]",
|
description: "textarea[style=\"ime-mode: active;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
changeOpened: true, expectedOpened: true },
|
changeOpened: true, expectedOpened: true },
|
||||||
{ id: "ime_mode_inactive",
|
{ id: "ime_mode_inactive",
|
||||||
description: "textarea[style=\"ime-mode: inactive;\"]",
|
description: "textarea[style=\"ime-mode: inactive;\"]",
|
||||||
|
focusable: !aInDesignMode,
|
||||||
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
expectedEnabled: gUtils.IME_STATUS_ENABLED,
|
||||||
changeOpened: true, expectedOpened: false },
|
changeOpened: true, expectedOpened: false },
|
||||||
{ id: "ime_mode_disabled",
|
{ id: "ime_mode_disabled",
|
||||||
description: "textarea[style=\"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++) {
|
for (var i = 0; i < kTests.length; i++) {
|
||||||
|
@ -351,7 +438,7 @@ function runTypeChangingTest()
|
||||||
type: "text", expected: gUtils.IME_STATUS_PASSWORD, imeMode: true,
|
type: "text", expected: gUtils.IME_STATUS_PASSWORD, imeMode: true,
|
||||||
description: "[type=\"text\"][ime-mode: disabled;]" },
|
description: "[type=\"text\"][ime-mode: disabled;]" },
|
||||||
{ id: "ime_mode_auto_p",
|
{ 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;]" },
|
description: "[type=\"password\"][ime-mode: auto;]" },
|
||||||
{ id: "ime_mode_normal_p",
|
{ id: "ime_mode_normal_p",
|
||||||
type: "password", expected: gUtils.IME_STATUS_ENABLED, imeMode: true,
|
type: "password", expected: gUtils.IME_STATUS_ENABLED, imeMode: true,
|
||||||
|
@ -383,7 +470,7 @@ function runTypeChangingTest()
|
||||||
function getExpectedIMEEnabled(aNewType, aInputControl)
|
function getExpectedIMEEnabled(aNewType, aInputControl)
|
||||||
{
|
{
|
||||||
if (aNewType.expected == gUtils.IME_STATUS_DISABLED ||
|
if (aNewType.expected == gUtils.IME_STATUS_DISABLED ||
|
||||||
aInputControl.isReadOnly)
|
aInputControl.isReadonly)
|
||||||
return gUtils.IME_STATUS_DISABLED;
|
return gUtils.IME_STATUS_DISABLED;
|
||||||
return aInputControl.imeMode ? aInputControl.expected : aNewType.expected;
|
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()
|
function runEditableSubframeTests()
|
||||||
{
|
{
|
||||||
|
@ -519,12 +814,14 @@ function runTests()
|
||||||
runBasicTest(false, false, "Testing designMode=\"off\"");
|
runBasicTest(false, false, "Testing designMode=\"off\"");
|
||||||
|
|
||||||
// changing input[type] values
|
// 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();
|
// runTypeChangingTest();
|
||||||
|
|
||||||
// changing readonly attribute
|
// changing readonly attribute
|
||||||
// XXX currently, readonly attribute changing doesn't work fine. bug 488420.
|
runReadonlyChangingTest();
|
||||||
// runReadonlyChangingTest();
|
|
||||||
|
// complex contenteditable editor's tests
|
||||||
|
runComplexContenteditableTests();
|
||||||
|
|
||||||
runASyncTests();
|
runASyncTests();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче