зеркало из https://github.com/mozilla/pjs.git
fixes:
This commit is contained in:
Родитель
6630ca37f6
Коммит
18736fd80c
|
@ -57,6 +57,7 @@ TypeInState::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
TypeInState::TypeInState() :
|
||||
mSetArray()
|
||||
,mClearedArray()
|
||||
,mRelativeFontSize(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
|
@ -108,6 +109,18 @@ nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr)
|
|||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// special case for big/small, these nest
|
||||
if (nsIEditProperty::big == aProp)
|
||||
{
|
||||
mRelativeFontSize++;
|
||||
return NS_OK;
|
||||
}
|
||||
if (nsIEditProperty::small == aProp)
|
||||
{
|
||||
mRelativeFontSize--;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if it's already set we are done
|
||||
if (IsPropSet(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
|
@ -196,6 +209,17 @@ nsresult TypeInState::TakeSetProperty(PropItem **outPropItem)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// TakeRelativeFontSize: hands back relative font value, which is then
|
||||
// cleared out.
|
||||
nsresult TypeInState::TakeRelativeFontSize(PRInt32 *outRelSize)
|
||||
{
|
||||
if (!outRelSize) return NS_ERROR_NULL_POINTER;
|
||||
*outRelSize = mRelativeFontSize;
|
||||
mRelativeFontSize = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, nsAutoString(), nsAutoString());
|
||||
|
@ -248,6 +272,7 @@ nsresult TypeInState::RemovePropFromSetList(nsIAtom *aProp,
|
|||
if (!aProp)
|
||||
{
|
||||
// clear _all_ props
|
||||
mRelativeFontSize=0;
|
||||
while ((index = mSetArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
|
|
|
@ -69,6 +69,11 @@ public:
|
|||
// caller assumes ownership of PropItem and must delete it.
|
||||
nsresult TakeSetProperty(PropItem **outPropItem);
|
||||
|
||||
//**************************************************************************
|
||||
// TakeRelativeFontSize: hands back relative font value, which is then
|
||||
// cleared out.
|
||||
nsresult TakeRelativeFontSize(PRInt32 *outRelSize);
|
||||
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr);
|
||||
|
@ -87,6 +92,7 @@ protected:
|
|||
|
||||
nsVoidArray mSetArray;
|
||||
nsVoidArray mClearedArray;
|
||||
PRInt32 mRelativeFontSize;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -165,40 +165,6 @@ nsBaseStateUpdatingCommand::UpdateCommandState(const PRUnichar *aCommandName, ns
|
|||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAlwaysEnabledCommands::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
*outCmdEnabled = (editorShell.get() != nsnull); // enabled if we have an editorShell
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAlwaysEnabledCommands::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
if (!editorShell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsAutoString cmdString(aCommand);
|
||||
|
||||
/*
|
||||
if (cmdString.EqualsWithConversion("cmd_scrollTop"))
|
||||
return selCont->CompleteScroll(PR_FALSE);
|
||||
else if (cmdString.EqualsWithConversion("cmd_scrollBottom"))
|
||||
return selCont->CompleteScroll(PR_TRUE);
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
@ -522,13 +488,13 @@ nsOutdentCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refC
|
|||
{
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editorShell->GetEditor(getter_AddRefs(editor));
|
||||
if (editor)
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (htmlEditor)
|
||||
{
|
||||
// XXX fix me. You can't outdent if you're already at the top level.
|
||||
//PRBool canOutdent;
|
||||
//editor->CanIndent("outdent", &canOutdent);
|
||||
PRBool canIndent, canOutdent;
|
||||
htmlEditor->GetIndentState(canIndent, canOutdent);
|
||||
|
||||
*outCmdEnabled = PR_TRUE;
|
||||
*outCmdEnabled = canOutdent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,8 +521,21 @@ nsOutdentCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
|||
#pragma mark -
|
||||
#endif
|
||||
|
||||
|
||||
nsMultiStateCommand::nsMultiStateCommand()
|
||||
: nsBaseComposerCommand()
|
||||
, mGotState(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsMultiStateCommand::~nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsMultiStateCommand, nsBaseComposerCommand, nsIStateUpdatingControllerCommand);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParagraphStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
nsMultiStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
*outCmdEnabled = PR_FALSE;
|
||||
|
@ -566,34 +545,166 @@ nsParagraphStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports
|
|||
editorShell->GetEditor(getter_AddRefs(editor));
|
||||
if (editor)
|
||||
{
|
||||
// should be disabled sometimes, like if the current selection is an image
|
||||
*outCmdEnabled = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
return UpdateCommandState(aCommand, refCon);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParagraphStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
nsMultiStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (editorShell)
|
||||
{
|
||||
// we have to grab the state attribute on our command node to find out
|
||||
// what format to set the paragraph to
|
||||
nsAutoString stateAttribute;
|
||||
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = editorShell->SetParagraphFormat(stateAttribute.GetUnicode());
|
||||
// we have to grab the state attribute on our command node to find out
|
||||
// what format to set the paragraph to
|
||||
nsAutoString stateAttribute;
|
||||
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = SetState(editorShell, stateAttribute);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMultiStateCommand::UpdateCommandState(const PRUnichar *aCommandName, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
nsresult rv = NS_OK;
|
||||
if (editorShell)
|
||||
{
|
||||
nsString curFormat;
|
||||
PRBool isMixed;
|
||||
|
||||
rv = GetCurrentState(editorShell, curFormat, isMixed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isMixed)
|
||||
curFormat.AssignWithConversion("mixed");
|
||||
|
||||
if (!mGotState || (curFormat != mStateString))
|
||||
{
|
||||
// poke the UI
|
||||
SetCommandNodeState(aCommandName, editorShell, curFormat);
|
||||
|
||||
mGotState = PR_TRUE;
|
||||
mStateString = curFormat;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
nsParagraphStateCommand::nsParagraphStateCommand()
|
||||
: nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsParagraphStateCommand::GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->GetParagraphState(outMixed, outStateString);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsParagraphStateCommand::SetState(nsIEditorShell *aEditorShell, nsString& newState)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->SetParagraphFormat(newState);
|
||||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
nsFontFaceStateCommand::nsFontFaceStateCommand()
|
||||
: nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontFaceStateCommand::GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->GetFontFaceState(outMixed, outStateString);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsFontFaceStateCommand::SetState(nsIEditorShell *aEditorShell, nsString& newState)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
NS_ConvertASCIItoUCS2 emptyString("");
|
||||
NS_ConvertASCIItoUCS2 fontString("font");
|
||||
NS_ConvertASCIItoUCS2 faceString("face");
|
||||
|
||||
nsCOMPtr<nsIAtom> ttAtom = getter_AddRefs(NS_NewAtom("tt"));
|
||||
nsCOMPtr<nsIAtom> fontAtom = getter_AddRefs(NS_NewAtom("font"));
|
||||
|
||||
if (newState.EqualsWithConversion("tt"))
|
||||
{
|
||||
// The old "teletype" attribute
|
||||
rv = htmlEditor->SetInlineProperty(ttAtom, &emptyString, &emptyString);
|
||||
// Clear existing font face
|
||||
rv = htmlEditor->RemoveInlineProperty(fontAtom, &faceString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove any existing TT nodes
|
||||
rv = htmlEditor->RemoveInlineProperty(ttAtom, &emptyString);
|
||||
|
||||
if (newState == emptyString || newState.EqualsWithConversion("normal")) {
|
||||
rv = htmlEditor->RemoveInlineProperty(fontAtom, &faceString);
|
||||
} else {
|
||||
rv = htmlEditor->SetInlineProperty(fontAtom, &faceString, &newState);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
|
|
@ -66,7 +66,7 @@ public: \
|
|||
NS_DECL_NSICONTROLLERCOMMAND \
|
||||
};
|
||||
|
||||
// virtual base class for commands that need to save and update state
|
||||
// virtual base class for commands that need to save and update Boolean state (like styles etc)
|
||||
class nsBaseStateUpdatingCommand : public nsBaseComposerCommand,
|
||||
public nsIStateUpdatingControllerCommand
|
||||
{
|
||||
|
@ -98,7 +98,8 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
// shared class for the various style updating commands
|
||||
// Shared class for the various style updating commands like bold, italics etc.
|
||||
// Suitable for commands whose state is either 'on' or 'off'.
|
||||
class nsStyleUpdatingCommand : public nsBaseStateUpdatingCommand
|
||||
{
|
||||
public:
|
||||
|
@ -132,8 +133,58 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
// Base class for commands whose state consists of a string (e.g. para format)
|
||||
class nsMultiStateCommand : public nsBaseComposerCommand,
|
||||
public nsIStateUpdatingControllerCommand
|
||||
{
|
||||
public:
|
||||
|
||||
nsMultiStateCommand();
|
||||
virtual ~nsMultiStateCommand();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTROLLERCOMMAND
|
||||
NS_DECL_NSISTATEUPDATINGCONTROLLERCOMMAND
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed) = 0;
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
PRPackedBool mGotState;
|
||||
nsString mStateString;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class nsParagraphStateCommand : public nsMultiStateCommand
|
||||
{
|
||||
public:
|
||||
nsParagraphStateCommand();
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed);
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
|
||||
};
|
||||
|
||||
class nsFontFaceStateCommand : public nsMultiStateCommand
|
||||
{
|
||||
public:
|
||||
nsFontFaceStateCommand();
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed);
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// composer commands
|
||||
NS_DECL_COMPOSER_COMMAND(nsAlwaysEnabledCommands)
|
||||
|
||||
NS_DECL_COMPOSER_COMMAND(nsCloseCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsPrintingCommands)
|
||||
|
@ -157,7 +208,6 @@ NS_DECL_COMPOSER_COMMAND(nsPasteQuotationCommand)
|
|||
NS_DECL_COMPOSER_COMMAND(nsIndentCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsOutdentCommand)
|
||||
|
||||
NS_DECL_COMPOSER_COMMAND(nsParagraphStateCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsAlignCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsRemoveStylesCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsIncreaseFontSizeCommand)
|
||||
|
|
|
@ -3695,6 +3695,23 @@ nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEditor::NodeIsType(nsIDOMNode *aNode, const nsString &aTagStr)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(aNode);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString tag;
|
||||
element->GetTagName(tag);
|
||||
if (tag.EqualsIgnoreCase(aTagStr))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aChildTag)
|
||||
{
|
||||
|
|
|
@ -598,6 +598,7 @@ public:
|
|||
|
||||
/** returns PR_TRUE if aNode is of the type implied by aTag */
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, const nsString &aTag);
|
||||
|
||||
/** returns PR_TRUE if aParent can contain a child of type aTag */
|
||||
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
|
||||
|
|
|
@ -327,6 +327,8 @@ nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandMana
|
|||
|
||||
// format stuff
|
||||
NS_REGISTER_ONE_COMMAND(nsParagraphStateCommand, "cmd_paragraphState");
|
||||
NS_REGISTER_ONE_COMMAND(nsFontFaceStateCommand, "cmd_fontFace");
|
||||
|
||||
NS_REGISTER_ONE_COMMAND(nsAlignCommand, "cmd_align");
|
||||
NS_REGISTER_ONE_COMMAND(nsRemoveStylesCommand, "cmd_removeStyles");
|
||||
NS_REGISTER_ONE_COMMAND(nsIncreaseFontSizeCommand, "cmd_increaseFont");
|
||||
|
|
|
@ -79,7 +79,6 @@ nsHTMLEditRules::nsHTMLEditRules() :
|
|||
mDocChangeRange(nsnull)
|
||||
,mListenerEnabled(PR_TRUE)
|
||||
,mUtilRange(nsnull)
|
||||
,mBody(nsnull)
|
||||
,mJoinOffset(0)
|
||||
{
|
||||
}
|
||||
|
@ -192,73 +191,8 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
nsresult res = NS_OK;
|
||||
if (!--mActionNesting)
|
||||
{
|
||||
ConfirmSelectionInBody();
|
||||
if (action == nsEditor::kOpIgnore) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (mDocChangeRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
|
||||
{
|
||||
// dont let any txns in here move the selection around behind our back.
|
||||
// Note that this won't prevent explicit selection setting from working.
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
|
||||
// expand the "changed doc range" as needed
|
||||
res = PromoteRange(mDocChangeRange, action);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// add in any needed <br>s, and remove any unneeded ones.
|
||||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
if ( (action != nsEditor::kOpInsertText &&
|
||||
action != nsEditor::kOpInsertIMEText) )
|
||||
{
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustWhitespace(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// replace newlines that are preformatted
|
||||
// MOOSE: This is buttUgly. A better way to
|
||||
// organize the action enum is in order.
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsHTMLEditor::kOpInsertElement) ||
|
||||
(action == nsHTMLEditor::kOpInsertQuotation) ||
|
||||
(action == nsEditor::kOpInsertNode))
|
||||
{
|
||||
res = ReplaceNewlines(mDocChangeRange);
|
||||
}
|
||||
|
||||
// clean up any empty nodes in the selection
|
||||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
|
||||
// do all the tricky stuff
|
||||
res = AfterEditInner(action, aDirection);
|
||||
// turn on caret
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
mEditor->GetSelectionController(getter_AddRefs(selCon));
|
||||
|
@ -269,6 +203,79 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
ConfirmSelectionInBody();
|
||||
if (action == nsEditor::kOpIgnore) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (mDocChangeRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
|
||||
{
|
||||
// dont let any txns in here move the selection around behind our back.
|
||||
// Note that this won't prevent explicit selection setting from working.
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
|
||||
// expand the "changed doc range" as needed
|
||||
res = PromoteRange(mDocChangeRange, action);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// add in any needed <br>s, and remove any unneeded ones.
|
||||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
if ( (action != nsEditor::kOpInsertText &&
|
||||
action != nsEditor::kOpInsertIMEText) )
|
||||
{
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustWhitespace(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// replace newlines that are preformatted
|
||||
// MOOSE: This is buttUgly. A better way to
|
||||
// organize the action enum is in order.
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsHTMLEditor::kOpInsertElement) ||
|
||||
(action == nsHTMLEditor::kOpInsertQuotation) ||
|
||||
(action == nsEditor::kOpInsertNode))
|
||||
{
|
||||
res = ReplaceNewlines(mDocChangeRange);
|
||||
}
|
||||
|
||||
// clean up any empty nodes in the selection
|
||||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
||||
nsRulesInfo *aInfo,
|
||||
|
@ -303,7 +310,7 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
case kDeleteSelection:
|
||||
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
||||
case kMakeList:
|
||||
return WillMakeList(aSelection, info->bOrdered, aCancel, aHandled);
|
||||
return WillMakeList(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kIndent:
|
||||
return WillIndent(aSelection, aCancel, aHandled);
|
||||
case kOutdent:
|
||||
|
@ -314,6 +321,8 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
return WillMakeBasicBlock(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kRemoveList:
|
||||
return WillRemoveList(aSelection, info->bOrdered, aCancel, aHandled);
|
||||
case kMakeDefListItem:
|
||||
return WillMakeDefListItem(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kInsertElement:
|
||||
return WillInsert(aSelection, aCancel);
|
||||
}
|
||||
|
@ -349,10 +358,10 @@ nsHTMLEditRules::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
PRBool bNonList = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes);
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// yummy yummy yummy i've got nodes in my tummy
|
||||
// examine list type for nodes in selection
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
|
@ -389,7 +398,102 @@ nsHTMLEditRules::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
aCanIndent = PR_TRUE;
|
||||
aCanOutdent = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// examine nodes in selection for blockquotes or list elements;
|
||||
// these we can outdent. Note that we return true for canOutdent
|
||||
// if *any* of the selection is outdentable, rather than all of it.
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
if (nsHTMLEditUtils::IsList(curNode) ||
|
||||
nsHTMLEditUtils::IsListItem(curNode) ||
|
||||
nsHTMLEditUtils::IsBlockquote(curNode))
|
||||
{
|
||||
aCanOutdent = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::GetParagraphState(PRBool &aMixed, nsString &outFormat)
|
||||
{
|
||||
// This routine is *heavily* tied to our ui choices in the paragraph
|
||||
// style popup. I cant see a way around that.
|
||||
aMixed = PR_TRUE;
|
||||
outFormat.AssignWithConversion("");
|
||||
|
||||
PRBool bMixed = PR_FALSE;
|
||||
nsAutoString formatStr;
|
||||
// using "x" as anuninitialized value, since "" is meaningful
|
||||
formatStr.AssignWithConversion("x");
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetParagraphFormatNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// loop through the nodes in selection and examine their paragraph format
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
nsAutoString format;
|
||||
nsCOMPtr<nsIAtom> atom = mEditor->GetTag(curNode);
|
||||
|
||||
if (mEditor->IsInlineNode(curNode))
|
||||
format.AssignWithConversion("");
|
||||
else if (nsIEditProperty::p == atom)
|
||||
format.AssignWithConversion("P");
|
||||
else if (nsHTMLEditUtils::IsHeader(curNode))
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(curNode,tag);
|
||||
tag.ToUpperCase();
|
||||
format = tag;
|
||||
}
|
||||
else if (nsIEditProperty::blockquote == atom)
|
||||
format.AssignWithConversion("BLOCKQUOTE");
|
||||
else if (nsIEditProperty::address == atom)
|
||||
format.AssignWithConversion("ADDRESS");
|
||||
else if (nsIEditProperty::pre == atom)
|
||||
format.AssignWithConversion("PRE");
|
||||
else if (nsIEditProperty::dt == atom)
|
||||
format.AssignWithConversion("DT");
|
||||
else if (nsIEditProperty::dd == atom)
|
||||
format.AssignWithConversion("DD");
|
||||
|
||||
// if this is the first node, we've found, remember it as the format
|
||||
if (formatStr.EqualsWithConversion("x"))
|
||||
formatStr = format;
|
||||
// else make sure it matches previously found format
|
||||
else if (format != formatStr)
|
||||
{
|
||||
bMixed = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aMixed = bMixed;
|
||||
outFormat = formatStr;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -825,19 +929,30 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
}
|
||||
}
|
||||
}
|
||||
// is prior node inline and same type? (This shouldn't happen)
|
||||
if ( mEditor->HasSameBlockNodeParent(node, priorNode) &&
|
||||
( mEditor->IsInlineNode(node) || mEditor->IsTextNode(node) ) &&
|
||||
mEditor->NodesSameType(node, priorNode) )
|
||||
// is prior node a text node?
|
||||
else if ( mEditor->IsTextNode(priorNode) )
|
||||
{
|
||||
// if so, join them!
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
priorNode->GetParentNode(getter_AddRefs(topParent));
|
||||
*aHandled = PR_TRUE;
|
||||
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
|
||||
// delete last character
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(priorNode);
|
||||
nodeAsText->GetLength((PRUint32*)&offset);
|
||||
res = aSelection->Collapse(priorNode,offset);
|
||||
// just return without setting handled to true.
|
||||
// default code will take care of actual deletion
|
||||
return res;
|
||||
}
|
||||
else if ( mEditor->IsInlineNode(priorNode) )
|
||||
{
|
||||
// remember where we are
|
||||
res = mEditor->GetNodeLocation(priorNode, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// delete it
|
||||
res = mEditor->DeleteNode(priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// fix up selection
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
res = aSelection->Collapse(node,offset);
|
||||
return res;
|
||||
}
|
||||
else return NS_OK; // punt to default
|
||||
|
@ -924,19 +1039,30 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
}
|
||||
}
|
||||
}
|
||||
// is next node inline and same type? (This shouldn't happen)
|
||||
if ( mEditor->HasSameBlockNodeParent(node, nextNode) &&
|
||||
( mEditor->IsInlineNode(node) || mEditor->IsTextNode(node) ) &&
|
||||
mEditor->NodesSameType(node, nextNode) )
|
||||
// is next node a text node?
|
||||
else if ( mEditor->IsTextNode(nextNode) )
|
||||
{
|
||||
// if so, join them!
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
nextNode->GetParentNode(getter_AddRefs(topParent));
|
||||
*aHandled = PR_TRUE;
|
||||
res = JoinNodesSmart(node,nextNode,&selNode,&selOffset);
|
||||
// delete last character
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(nextNode);
|
||||
nodeAsText->GetLength((PRUint32*)&offset);
|
||||
res = aSelection->Collapse(nextNode,offset);
|
||||
// just return without setting handled to true.
|
||||
// default code will take care of actual deletion
|
||||
return res;
|
||||
}
|
||||
else if ( mEditor->IsInlineNode(nextNode) )
|
||||
{
|
||||
// remember where we are
|
||||
res = mEditor->GetNodeLocation(nextNode, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// delete it
|
||||
res = mEditor->DeleteNode(nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// fix up selection
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
res = aSelection->Collapse(node,offset);
|
||||
return res;
|
||||
}
|
||||
else return NS_OK; // punt to default
|
||||
|
@ -1001,6 +1127,11 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeToDelete) return NS_ERROR_NULL_POINTER;
|
||||
if (mBody == nodeToDelete)
|
||||
{
|
||||
*aCancel = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
// if this node is text node, adjust selection
|
||||
if (nsEditor::IsTextNode(nodeToDelete))
|
||||
|
@ -1153,28 +1284,32 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
||||
PRBool aOrdered,
|
||||
const nsString *aListType,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled)
|
||||
PRBool *aHandled,
|
||||
const nsString *aItemType)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
if (!aSelection || !aListType || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res = WillInsert(aSelection, aCancel);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsAutoString listType;
|
||||
listType.AssignWithConversion( aOrdered ? "ol" : "ul" );
|
||||
|
||||
// initialize out param
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
*aHandled = PR_FALSE;
|
||||
|
||||
nsAutoString blockType;
|
||||
blockType.AssignWithConversion( aOrdered ? "ol" : "ul");
|
||||
// deduce what tag to use for list items
|
||||
nsAutoString itemType;
|
||||
if (aItemType)
|
||||
itemType = *aItemType;
|
||||
else if (aListType->EqualsWithConversion("dl"))
|
||||
itemType.AssignWithConversion("dd");
|
||||
else
|
||||
itemType.AssignWithConversion("li");
|
||||
|
||||
PRBool outMakeEmpty;
|
||||
res = ShouldMakeEmptyBlock(aSelection, &blockType, &outMakeEmpty);
|
||||
res = ShouldMakeEmptyBlock(aSelection, aListType, &outMakeEmpty);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (outMakeEmpty)
|
||||
{
|
||||
|
@ -1186,11 +1321,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// make sure we can put a list here
|
||||
res = SplitAsNeeded(&listType, &parent, &offset);
|
||||
res = SplitAsNeeded(aListType, &parent, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, parent, offset, getter_AddRefs(theList));
|
||||
res = mEditor->CreateNode(*aListType, parent, offset, getter_AddRefs(theList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(NS_ConvertASCIItoUCS2("li"), theList, 0, getter_AddRefs(theListItem));
|
||||
res = mEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// put selection in new list item
|
||||
res = aSelection->Collapse(theListItem,0);
|
||||
|
@ -1224,8 +1359,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
while (nsHTMLEditUtils::IsDiv(curNode)
|
||||
|| nsHTMLEditUtils::IsOrderedList(curNode)
|
||||
|| nsHTMLEditUtils::IsUnorderedList(curNode)
|
||||
|| nsHTMLEditUtils::IsList(curNode)
|
||||
|| nsHTMLEditUtils::IsBlockquote(curNode))
|
||||
{
|
||||
// dive as long as there is only one child, and it is a list, div, blockquote
|
||||
|
@ -1238,8 +1372,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// keep diving
|
||||
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
||||
if (nsHTMLEditUtils::IsDiv(tmpNode)
|
||||
|| nsHTMLEditUtils::IsOrderedList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsUnorderedList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsBlockquote(tmpNode))
|
||||
{
|
||||
// check editablility XXX floppy moose
|
||||
|
@ -1305,37 +1438,38 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
|
||||
if (nsHTMLEditUtils::IsList(curNode))
|
||||
{
|
||||
nsAutoString existingListStr;
|
||||
res = mEditor->GetTagString(curNode, existingListStr);
|
||||
// do we have a curList already?
|
||||
if (curList && !nsHTMLEditUtils::IsDescendantOf(curNode, curList))
|
||||
{
|
||||
// move all of our dachildren into curList.
|
||||
// move all of our children into curList.
|
||||
// cheezy way to do it: move whole list and then
|
||||
// RemoveContainer() on the list
|
||||
// RemoveContainer() on the list.
|
||||
// ConvertListType first: that routine
|
||||
// handles converting the list item types, if needed
|
||||
res = mEditor->MoveNode(curNode, curList, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->RemoveContainer(curNode);
|
||||
res = ConvertListType(curNode, &newBlock, *aListType, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
else if ( (nsHTMLEditUtils::IsUnorderedList(curNode) && aOrdered) ||
|
||||
(nsHTMLEditUtils::IsOrderedList(curNode) && !aOrdered) )
|
||||
|
||||
{
|
||||
// replace list with new list type
|
||||
res = mEditor->ReplaceContainer(curNode,&newBlock,blockType);
|
||||
res = mEditor->RemoveContainer(newBlock);
|
||||
if (NS_FAILED(res)) return res;
|
||||
curList = newBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
curList = curNode;
|
||||
// replace list with new list type
|
||||
res = ConvertListType(curNode, &newBlock, *aListType, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
curList = newBlock;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
if ( (nsHTMLEditUtils::IsUnorderedList(curParent) && aOrdered) ||
|
||||
(nsHTMLEditUtils::IsOrderedList(curParent) && !aOrdered) )
|
||||
nsAutoString existingListStr;
|
||||
res = mEditor->GetTagString(curParent, existingListStr);
|
||||
if ( existingListStr != *aListType )
|
||||
{
|
||||
// list item is in wrong type of list.
|
||||
// if we dont have a curList, split the old list
|
||||
|
@ -1348,16 +1482,23 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
PRInt32 o;
|
||||
res = nsEditor::GetNodeLocation(curParent, &p, &o);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, p, o, getter_AddRefs(curList));
|
||||
res = mEditor->CreateNode(*aListType, p, o, getter_AddRefs(curList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
// move list item to new list
|
||||
res = mEditor->MoveNode(curNode, curList, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// convert list item type if needed
|
||||
if (!mEditor->NodeIsType(curNode,itemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &newBlock, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// item is in right type of list. But we might still have to move it.
|
||||
// and we might need to convert list item types.
|
||||
if (!curList)
|
||||
curList = curParent;
|
||||
else
|
||||
|
@ -1369,6 +1510,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
if (!mEditor->NodeIsType(curNode,itemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &newBlock, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1377,9 +1523,9 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// or if this node doesn't go in list we used earlier.
|
||||
if (!curList) // || transitionList[i])
|
||||
{
|
||||
res = SplitAsNeeded(&listType, &curParent, &offset);
|
||||
res = SplitAsNeeded(aListType, &curParent, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, curParent, offset, getter_AddRefs(curList));
|
||||
res = mEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// curList is now the correct thing to put curNode in
|
||||
prevListItem = 0;
|
||||
|
@ -1404,11 +1550,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// don't wrap li around a paragraph. instead replace paragraph with li
|
||||
if (nsHTMLEditUtils::IsParagraph(curNode))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &listItem, NS_ConvertASCIItoUCS2("li"));
|
||||
res = mEditor->ReplaceContainer(curNode, &listItem, itemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->InsertContainerAbove(curNode, &listItem, NS_ConvertASCIItoUCS2("li"));
|
||||
res = mEditor->InsertContainerAbove(curNode, &listItem, itemType);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nsEditor::IsInlineNode(curNode))
|
||||
|
@ -1525,6 +1671,18 @@ nsHTMLEditRules::WillRemoveList(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeDefListItem(nsIDOMSelection *aSelection,
|
||||
const nsString *aItemType,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled)
|
||||
{
|
||||
// for now we let WillMakeList handle this
|
||||
nsAutoString listType;
|
||||
listType.AssignWithConversion("dl");
|
||||
return WillMakeList(aSelection, &listType, aCancel, aHandled, aItemType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeBasicBlock(nsIDOMSelection *aSelection,
|
||||
const nsString *aBlockType,
|
||||
|
@ -1808,6 +1966,40 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ConvertListType: convert list type and list item type.
|
||||
//
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::ConvertListType(nsIDOMNode *aList,
|
||||
nsCOMPtr<nsIDOMNode> *outList,
|
||||
const nsString& aListType,
|
||||
const nsString& aItemType)
|
||||
{
|
||||
if (!aList || !outList) return NS_ERROR_NULL_POINTER;
|
||||
*outList = aList; // we migvht not need to change the list
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> child, temp;
|
||||
aList->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
if (!mEditor->NodeIsType(child, aItemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(child, &temp, aItemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
child = temp;
|
||||
}
|
||||
child->GetNextSibling(getter_AddRefs(temp));
|
||||
child = temp;
|
||||
}
|
||||
if (!mEditor->NodeIsType(aList, aListType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(aList, outList, aListType);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateStyleForInsertText: take care of clearing and setting appropriate
|
||||
// style nodes for text insertion.
|
||||
|
@ -1839,10 +2031,15 @@ nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDoc
|
|||
}
|
||||
|
||||
// then process setting any styles
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
PRInt32 relFontSize;
|
||||
|
||||
if (item) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
res = mEditor->mTypeInState->TakeRelativeFontSize(&relFontSize);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (item || relFontSize) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
if (mEditor->IsTextNode(node))
|
||||
{
|
||||
// if we are in a text node, split it
|
||||
|
@ -1863,17 +2060,29 @@ nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDoc
|
|||
node = newNode;
|
||||
offset = 0;
|
||||
weDidSometing = PR_TRUE;
|
||||
|
||||
if (relFontSize)
|
||||
{
|
||||
PRInt32 j, dir;
|
||||
// dir indicated bigger versus smaller. 1 = bigger, -1 = smaller
|
||||
if (relFontSize > 0) dir=1;
|
||||
else dir = -1;
|
||||
for (j=0; j<abs(relFontSize); j++)
|
||||
{
|
||||
res = mEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, 0, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we own item now (TakeSetProperty hands ownership to us)
|
||||
delete item;
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
}
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we own item now (TakeSetProperty hands ownership to us)
|
||||
delete item;
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
}
|
||||
|
||||
if (weDidSometing)
|
||||
return aSelection->Collapse(node, offset);
|
||||
|
||||
|
@ -2616,7 +2825,8 @@ nsHTMLEditRules::PromoteRange(nsIDOMRange *inRange,
|
|||
nsresult
|
||||
nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType)
|
||||
PRInt32 inOperationType,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!inArrayOfRanges || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
|
@ -2669,7 +2879,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
|||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
||||
if (mEditor->IsInlineNode(node) && mEditor->IsContainer(node))
|
||||
if (!aDontTouchContent && mEditor->IsInlineNode(node) && mEditor->IsContainer(node))
|
||||
{
|
||||
nsCOMPtr<nsISupportsArray> arrayOfInlines;
|
||||
res = BustUpInlinesAtBRs(node, &arrayOfInlines);
|
||||
|
@ -2735,7 +2945,8 @@ nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
|
|||
// GetListActionNodes:
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
||||
nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
|
@ -2748,7 +2959,58 @@ nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// use these ranges to contruct a list of nodes to act on.
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList);
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList, aDontTouchContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// pre process our list of nodes...
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
(*outArrayOfNodes)->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
|
||||
|
||||
// Remove all non-editable nodes. Leave them be.
|
||||
if (!mEditor->IsEditable(testNode))
|
||||
{
|
||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||
}
|
||||
|
||||
// scan for table elements. If we find table elements other than table,
|
||||
// replace it with a list of any editable non-table content.
|
||||
if (mEditor->IsTableElement(testNode) && !mEditor->IsTable(testNode))
|
||||
{
|
||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||
nsCOMPtr<nsISupportsArray> arrayOfTableContent;
|
||||
res = GetTableContent(testNode, &arrayOfTableContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
(*outArrayOfNodes)->AppendElements(arrayOfTableContent);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetParagraphFormatNodes:
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||
res = GetPromotedRanges(selection, &arrayOfRanges, kMakeList);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// use these ranges to contruct a list of nodes to act on.
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeBasicBlock, aDontTouchContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// pre process our list of nodes...
|
||||
|
@ -3285,7 +3547,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
// Note that if _nothing_ should happen, ie, the selection is
|
||||
// already entireyl inside a block (or blocks) or the correct type,
|
||||
// then you don't want to return true in outMakeEmpty, since the
|
||||
// defualt code will insert a new empty block anyway, rather than
|
||||
// default code will insert a new empty block anyway, rather than
|
||||
// doing nothing. So we have to detect that case and return false.
|
||||
|
||||
if (!aSelection || !outMakeEmpty) return NS_ERROR_NULL_POINTER;
|
||||
|
@ -3342,18 +3604,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
*outMakeEmpty = PR_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
// in an empty block?
|
||||
PRBool bIsEmptyNode;
|
||||
// the PR_TRUE param tell IsEmptyNode to not count moz-BRs as content
|
||||
res = IsEmptyNode(block, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (bIsEmptyNode)
|
||||
{
|
||||
// we must be in a text or inline node - convert existing block
|
||||
*outMakeEmpty = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// is it after a <br> with no inline nodes after it, or a <br> after it??
|
||||
if (offset)
|
||||
{
|
||||
|
@ -3383,7 +3634,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
// we are after a <br> and not before inline content,
|
||||
// or we are between <br>s.
|
||||
// make an empty block
|
||||
*outMakeEmpty = PR_FALSE;
|
||||
*outMakeEmpty = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
// nsIHTMLEditRules methods
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL);
|
||||
NS_IMETHOD GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent);
|
||||
NS_IMETHOD GetParagraphState(PRBool &aMixed, nsString &outFormat);
|
||||
|
||||
// nsIEditActionListener methods
|
||||
|
||||
|
@ -97,11 +98,12 @@ protected:
|
|||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::EDirection aAction,
|
||||
PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeList(nsIDOMSelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeList(nsIDOMSelection *aSelection, const nsString *aListType, PRBool *aCancel, PRBool *aHandled, const nsString *aItemType=nsnull);
|
||||
nsresult WillRemoveList(nsIDOMSelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeDefListItem(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidMakeBasicBlock(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
||||
|
||||
|
@ -115,17 +117,13 @@ protected:
|
|||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr<nsIDOMNode> *outList, const nsString& aListType, const nsString& aItemType);
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
#if 0
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
#endif
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
@ -138,11 +136,13 @@ protected:
|
|||
PRInt32 inOperationType);
|
||||
nsresult PromoteRange(nsIDOMRange *inRange, PRInt32 inOperationType);
|
||||
nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType);
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType,
|
||||
PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult BustUpInlinesAtBRs(nsIDOMNode *inNode,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||
|
@ -185,7 +185,6 @@ protected:
|
|||
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
||||
PRBool mListenerEnabled;
|
||||
nsCOMPtr<nsIDOMRange> mUtilRange;
|
||||
nsCOMPtr<nsIDOMNode> mBody;
|
||||
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
|
||||
|
||||
};
|
||||
|
|
|
@ -220,7 +220,9 @@ nsHTMLEditUtils::IsListItem(nsIDOMNode *node)
|
|||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if (tag.EqualsWithConversion("li"))
|
||||
if (tag.EqualsWithConversion("li") ||
|
||||
tag.EqualsWithConversion("dd") ||
|
||||
tag.EqualsWithConversion("dt"))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -289,7 +291,8 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node)
|
|||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if ( (tag.EqualsWithConversion("ol")) ||
|
||||
if ( (tag.EqualsWithConversion("dl")) ||
|
||||
(tag.EqualsWithConversion("ol")) ||
|
||||
(tag.EqualsWithConversion("ul")) )
|
||||
{
|
||||
return PR_TRUE;
|
||||
|
@ -299,7 +302,7 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node)
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsOrderedList: true if node an html orderd list
|
||||
// IsOrderedList: true if node an html ordered list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
|
||||
|
@ -317,7 +320,7 @@ nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsUnorderedList: true if node an html orderd list
|
||||
// IsUnorderedList: true if node an html unordered list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
|
||||
|
@ -334,6 +337,24 @@ nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsDefinitionList: true if node an html definition list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node)
|
||||
{
|
||||
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsDefinitionList");
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if (tag.EqualsWithConversion("dl"))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsBlockquote: true if node an html blockquote node
|
||||
//
|
||||
|
|
|
@ -48,8 +48,9 @@ public:
|
|||
static PRBool IsTableRow(nsIDOMNode *aNode);
|
||||
static PRBool IsTableCell(nsIDOMNode *aNode);
|
||||
static PRBool IsList(nsIDOMNode *aNode);
|
||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsDefinitionList(nsIDOMNode *aNode);
|
||||
static PRBool IsBlockquote(nsIDOMNode *aNode);
|
||||
static PRBool IsPre(nsIDOMNode *aNode);
|
||||
static PRBool IsAddress(nsIDOMNode *aNode);
|
||||
|
|
|
@ -1001,6 +1001,10 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode)
|
|||
|
||||
if (!outBRNode) return NS_ERROR_NULL_POINTER;
|
||||
*outBRNode = nsnull;
|
||||
|
||||
// calling it text insertion to trigger moz br treatment by rules
|
||||
nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext);
|
||||
|
||||
nsresult res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = selection->GetIsCollapsed(&bCollapsed);
|
||||
|
@ -1019,6 +1023,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// position selection after br
|
||||
res = GetNodeLocation(*outBRNode, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selection->SetHint(PR_TRUE);
|
||||
res = selection->Collapse(selNode, selOffset+1);
|
||||
|
||||
|
@ -1127,22 +1133,28 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// iterate range and build up array
|
||||
iter->Init(range);
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
res = iter->Init(range);
|
||||
// init returns an error if no nodes in range.
|
||||
// this can easily happen with the subtree
|
||||
// iterator if the selection doesn't contain
|
||||
// any *whole* nodes.
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
res = iter->CurrentNode(getter_AddRefs(content));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = do_QueryInterface(content);
|
||||
if (!node) return NS_ERROR_FAILURE;
|
||||
if (IsEditable(node))
|
||||
{
|
||||
isupports = do_QueryInterface(node);
|
||||
arrayOfNodes->AppendElement(isupports);
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
res = iter->CurrentNode(getter_AddRefs(content));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = do_QueryInterface(content);
|
||||
if (!node) return NS_ERROR_FAILURE;
|
||||
if (IsEditable(node))
|
||||
{
|
||||
isupports = do_QueryInterface(node);
|
||||
arrayOfNodes->AppendElement(isupports);
|
||||
}
|
||||
res = iter->Next();
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
res = iter->Next();
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// MOOSE: workaround for selection bug:
|
||||
//selection->ClearSelection();
|
||||
|
||||
|
@ -1713,7 +1725,20 @@ PRBool nsHTMLEditor::IsAtEndOfNode(nsIDOMNode *aNode, PRInt32 aOffset)
|
|||
NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll)
|
||||
PRBool &aFirst,
|
||||
PRBool &aAny,
|
||||
PRBool &aAll)
|
||||
{
|
||||
return GetInlinePropertyWithAttrValue( aProperty, aAttribute, aValue, aFirst, aAny, aAll, nsnull);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::GetInlinePropertyWithAttrValue(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst,
|
||||
PRBool &aAny,
|
||||
PRBool &aAll,
|
||||
nsString *outValue)
|
||||
{
|
||||
if (!aProperty)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
@ -1805,11 +1830,6 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
else if (aProperty == mFontAtom.get())
|
||||
{
|
||||
// MOOSE!
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// either non-collapsed selection or no cached value: do it the hard way
|
||||
|
@ -1822,6 +1842,7 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
|
||||
iter->Init(range);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
nsAutoString firstValue, theValue;
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
|
@ -1866,12 +1887,20 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
{
|
||||
PRBool isSet;
|
||||
nsCOMPtr<nsIDOMNode>resultNode;
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode));
|
||||
if (first)
|
||||
{
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode), &firstValue);
|
||||
aFirst = isSet;
|
||||
first = PR_FALSE;
|
||||
if (outValue) *outValue = firstValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode), &theValue);
|
||||
if (firstValue != theValue)
|
||||
aAll = PR_FALSE;
|
||||
}
|
||||
|
||||
if (isSet) {
|
||||
aAny = PR_TRUE;
|
||||
}
|
||||
|
@ -2790,7 +2819,10 @@ nsHTMLEditor::SetParagraphFormat(const nsString& aParagraphFormat)
|
|||
{
|
||||
nsAutoString tag; tag.Assign(aParagraphFormat);
|
||||
tag.ToLowerCase();
|
||||
return InsertBasicBlock(tag);
|
||||
if (tag.EqualsWithConversion("dd") || tag.EqualsWithConversion("dt"))
|
||||
return MakeDefinitionItem(tag);
|
||||
else
|
||||
return InsertBasicBlock(tag);
|
||||
}
|
||||
|
||||
// XXX: ERROR_HANDLING -- this method needs a little work to ensure all error codes are
|
||||
|
@ -2907,20 +2939,52 @@ nsHTMLEditor::GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists)
|
|||
}
|
||||
|
||||
|
||||
// get the paragraph style(s) for the selection
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetParagraphTags(nsStringArray *aTagList)
|
||||
nsHTMLEditor::GetParagraphState(PRBool &aMixed, nsString &outFormat)
|
||||
{
|
||||
#if 0
|
||||
if (gNoisy) { printf("---------- nsHTMLEditor::GetPargraphTags ----------\n"); }
|
||||
#endif
|
||||
return GetParentBlockTags(aTagList, PR_FALSE);
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
||||
if (!htmlRules) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlRules->GetParagraphState(aMixed, outFormat);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetListTags(nsStringArray *aTagList)
|
||||
nsHTMLEditor::GetFontFaceState(PRBool &aMixed, nsString &outFace)
|
||||
{
|
||||
return GetParentBlockTags(aTagList, PR_TRUE);
|
||||
aMixed = PR_TRUE;
|
||||
outFace.AssignWithConversion("");
|
||||
|
||||
nsresult res;
|
||||
nsAutoString faceStr; faceStr.AssignWithConversion("face");
|
||||
PRBool first, any, all;
|
||||
|
||||
res = GetInlinePropertyWithAttrValue(nsIEditProperty::font, &faceStr, nsnull, first, any, all, &outFace);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (any && !all) return res; // mixed
|
||||
if (all)
|
||||
{
|
||||
aMixed = PR_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
res = GetInlineProperty(nsIEditProperty::tt, nsnull, nsnull, first, any, all);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (any && !all) return res; // mixed
|
||||
if (all)
|
||||
{
|
||||
aMixed = PR_FALSE;
|
||||
nsIEditProperty::tt->ToString(outFace);
|
||||
}
|
||||
|
||||
if (!any)
|
||||
{
|
||||
// there was no font face attrs of any kind. We are in normal font.
|
||||
outFace.AssignWithConversion("");
|
||||
aMixed = PR_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2934,6 +2998,17 @@ nsHTMLEditor::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
return htmlRules->GetListState(aMixed, aOL, aUL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)
|
||||
{
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
||||
if (!htmlRules) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlRules->GetIndentState(aCanIndent, aCanOutdent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::MakeOrChangeList(const nsString& aListType)
|
||||
{
|
||||
|
@ -2952,8 +3027,7 @@ nsHTMLEditor::MakeOrChangeList(const nsString& aListType)
|
|||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeList);
|
||||
if (aListType.EqualsWithConversion("ol")) ruleInfo.bOrdered = PR_TRUE;
|
||||
else ruleInfo.bOrdered = PR_FALSE;
|
||||
ruleInfo.blockType = &aListType;
|
||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
if (cancel || (NS_FAILED(res))) return res;
|
||||
|
||||
|
@ -3041,8 +3115,37 @@ nsHTMLEditor::RemoveList(const nsString& aListType)
|
|||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::MakeDefinitionItem(const nsString& aItemType)
|
||||
{
|
||||
nsresult res;
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
PRBool cancel, handled;
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
nsAutoRules beginRulesSniffing(this, kOpMakeDefListItem, nsIEditor::eNext);
|
||||
|
||||
// pre-process
|
||||
res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeDefListItem);
|
||||
ruleInfo.blockType = &aItemType;
|
||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
if (cancel || (NS_FAILED(res))) return res;
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
// todo: no default for now. we count on rules to handle it.
|
||||
}
|
||||
|
||||
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::InsertBasicBlock(const nsString& aBlockType)
|
||||
{
|
||||
nsresult res;
|
||||
|
@ -5534,7 +5637,8 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aIsSet,
|
||||
nsIDOMNode **aStyleNode) const
|
||||
nsIDOMNode **aStyleNode,
|
||||
nsString *outValue) const
|
||||
{
|
||||
nsresult result;
|
||||
aIsSet = PR_FALSE; // must be initialized to false for code below to work
|
||||
|
@ -5548,15 +5652,15 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
|
|||
element = do_QueryInterface(node);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsAutoString tag, value;
|
||||
element->GetTagName(tag);
|
||||
if (propName.EqualsIgnoreCase(tag))
|
||||
{
|
||||
PRBool found = PR_FALSE;
|
||||
if (aAttribute && 0!=aAttribute->Length())
|
||||
{
|
||||
nsAutoString value;
|
||||
element->GetAttribute(*aAttribute, value);
|
||||
if (outValue) *outValue = value;
|
||||
if (value.Length())
|
||||
{
|
||||
if (!aValue) {
|
||||
|
@ -6182,12 +6286,14 @@ nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
|
|||
res = selection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's collapsed dont do anything.
|
||||
// MOOSE: We should probably have typing state for this like
|
||||
// we do for other things.
|
||||
// if it's collapsed set typing state
|
||||
if (bCollapsed)
|
||||
{
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
if (aSizeChange==1) atom = nsIEditProperty::big;
|
||||
else atom = nsIEditProperty::small;
|
||||
// manipulating text attributes on a collapsed selection only sets state for the next text insertion
|
||||
return mTypeInState->SetProp(atom, nsnull, nsnull);
|
||||
}
|
||||
|
||||
// wrap with txn batching, rules sniffing, and selection preservation code
|
||||
|
@ -6346,6 +6452,9 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
|
|||
PRUint32 textLen;
|
||||
aTextNode->GetLength(&textLen);
|
||||
|
||||
// -1 is a magic value meaning to the end of node
|
||||
if (aEndOffset == -1) aEndOffset = textLen;
|
||||
|
||||
if ( (PRUint32)aEndOffset != textLen )
|
||||
{
|
||||
// we need to split off back of text node
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
kOpAlign = 3004,
|
||||
kOpMakeBasicBlock = 3005,
|
||||
kOpRemoveList = 3006,
|
||||
kOpMakeDefListItem = 3007,
|
||||
kOpInsertElement = 3008,
|
||||
kOpInsertQuotation = 3009
|
||||
};
|
||||
|
@ -103,6 +104,11 @@ public:
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll);
|
||||
NS_IMETHOD GetInlinePropertyWithAttrValue(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll,
|
||||
nsString *outValue);
|
||||
|
||||
NS_IMETHOD RemoveAllInlineProperties();
|
||||
NS_IMETHOD RemoveInlineProperty(nsIAtom *aProperty, const nsString *aAttribute);
|
||||
|
@ -125,13 +131,14 @@ public:
|
|||
NS_IMETHOD SetParagraphFormat(const nsString& aParagraphFormat);
|
||||
|
||||
NS_IMETHOD GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists);
|
||||
NS_IMETHOD GetParagraphTags(nsStringArray *aTagList);
|
||||
NS_IMETHOD GetListTags(nsStringArray *aTagList);
|
||||
|
||||
NS_IMETHOD GetParagraphState(PRBool &aMixed, nsString &outFormat);
|
||||
NS_IMETHOD GetFontFaceState(PRBool &aMixed, nsString &outFace);
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL);
|
||||
NS_IMETHOD GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent);
|
||||
|
||||
NS_IMETHOD MakeOrChangeList(const nsString& aListType);
|
||||
NS_IMETHOD RemoveList(const nsString& aListType);
|
||||
NS_IMETHOD InsertBasicBlock(const nsString& aBlockType);
|
||||
NS_IMETHOD Indent(const nsString& aIndent);
|
||||
NS_IMETHOD Align(const nsString& aAlign);
|
||||
|
||||
|
@ -441,7 +448,8 @@ protected:
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aIsSet,
|
||||
nsIDOMNode **aStyleNode) const;
|
||||
nsIDOMNode **aStyleNode,
|
||||
nsString *outValue = nsnull) const;
|
||||
|
||||
/** style-based query returns PR_TRUE if (aProperty, aAttribute) is set in aSC.
|
||||
* WARNING: not well tested yet since we don't do style-based queries anywhere.
|
||||
|
@ -473,6 +481,10 @@ protected:
|
|||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
/* helpers for block transformations */
|
||||
nsresult MakeDefinitionItem(const nsString& aItemType);
|
||||
nsresult InsertBasicBlock(const nsString& aBlockType);
|
||||
|
||||
/* increase/decrease the font size of selection */
|
||||
nsresult RelativeFontChange( PRInt32 aSizeChange);
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ NS_NewTextEditRules(nsIEditRules** aInstancePtrResult)
|
|||
nsTextEditRules::nsTextEditRules()
|
||||
: mEditor(nsnull)
|
||||
, mFlags(0) // initialized to 0 ("no flags set"). Real initial value is given in Init()
|
||||
, mPasswordText()
|
||||
, mBogusNode(nsnull)
|
||||
, mBody(nsnull)
|
||||
, mActionNesting(0)
|
||||
, mLockRulesSniffing(PR_FALSE)
|
||||
, mTheAction(0)
|
||||
|
@ -106,29 +109,33 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
|||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
mEditor->GetSelection(getter_AddRefs(selection));
|
||||
NS_ASSERTION(selection, "editor cannot get selection");
|
||||
nsresult res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
|
||||
|
||||
// create a range that is the entire body contents
|
||||
if (NS_FAILED(res)) return res;
|
||||
// remember our root node
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
nsresult res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
if (!bodyNode) return NS_ERROR_FAILURE;
|
||||
mBody = do_QueryInterface(bodyElement);
|
||||
if (!mBody) return NS_ERROR_FAILURE;
|
||||
|
||||
// put in a magic br if needed
|
||||
res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create a range that is the entire body contents
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc;
|
||||
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(wholeDoc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
wholeDoc->SetStart(bodyNode,0);
|
||||
wholeDoc->SetStart(mBody,0);
|
||||
nsCOMPtr<nsIDOMNodeList> list;
|
||||
res = bodyNode->GetChildNodes(getter_AddRefs(list));
|
||||
res = mBody->GetChildNodes(getter_AddRefs(list));
|
||||
if (NS_FAILED(res) || !list) return res?res:NS_ERROR_FAILURE;
|
||||
PRUint32 listCount;
|
||||
res = list->GetLength(&listCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
res = wholeDoc->SetEnd(bodyNode,listCount);
|
||||
res = wholeDoc->SetEnd(mBody,listCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// replace newlines in that range with breaks
|
||||
|
@ -1188,19 +1195,14 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
|
|||
// tell rules system to not do any post-processing
|
||||
nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
|
||||
nsresult res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
if (!mBody) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// now we've got the body tag.
|
||||
// iterate the body tag, looking for editable content
|
||||
// if no editable content is found, insert the bogus node
|
||||
PRBool needsBogusContent=PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode>bodyChild;
|
||||
res = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
nsresult res = mBody->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
while ((NS_SUCCEEDED(res)) && bodyChild)
|
||||
{
|
||||
if (mEditor->IsMozEditorBogusNode(bodyChild) || mEditor->IsEditable(bodyChild))
|
||||
|
@ -1214,25 +1216,27 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
|
|||
}
|
||||
if (needsBogusContent)
|
||||
{
|
||||
// set mBogusNode to be the newly created <br>
|
||||
res = mEditor->CreateNode(NS_ConvertASCIItoUCS2("br"), bodyNode, 0,
|
||||
getter_AddRefs(mBogusNode));
|
||||
// create a br
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIDOMElement>brElement;
|
||||
res = domDoc->CreateElement(NS_ConvertASCIItoUCS2("br"),getter_AddRefs(brElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// set mBogusNode to be the newly created <br>
|
||||
mBogusNode = do_QueryInterface(brElement);
|
||||
if (!mBogusNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// give it a special attribute
|
||||
nsCOMPtr<nsIDOMElement>newPElement;
|
||||
newPElement = do_QueryInterface(mBogusNode);
|
||||
if (newPElement)
|
||||
{
|
||||
newPElement->SetAttribute(
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeAttr),
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeValue)
|
||||
);
|
||||
}
|
||||
brElement->SetAttribute( NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeAttr),
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeValue) );
|
||||
|
||||
// put the node in the document
|
||||
res = mEditor->InsertNode(mBogusNode,mBody,0);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// set selection
|
||||
aSelection->Collapse(bodyNode,0);
|
||||
aSelection->Collapse(mBody,0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
kAlign = 3004,
|
||||
kMakeBasicBlock = 3005,
|
||||
kRemoveList = 3006,
|
||||
kMakeDefListItem = 3007,
|
||||
kInsertElement = 3008
|
||||
};
|
||||
|
||||
|
@ -173,6 +174,7 @@ protected:
|
|||
nsHTMLEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
|
@ -195,7 +197,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
outputFormat(0),
|
||||
maxLength(-1),
|
||||
collapsedAction(nsIEditor::eNext),
|
||||
bOrdered(PR_FALSE),
|
||||
alignType(0),
|
||||
blockType(0),
|
||||
insertElement(0)
|
||||
|
|
|
@ -165,40 +165,6 @@ nsBaseStateUpdatingCommand::UpdateCommandState(const PRUnichar *aCommandName, ns
|
|||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAlwaysEnabledCommands::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
*outCmdEnabled = (editorShell.get() != nsnull); // enabled if we have an editorShell
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAlwaysEnabledCommands::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
if (!editorShell) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsAutoString cmdString(aCommand);
|
||||
|
||||
/*
|
||||
if (cmdString.EqualsWithConversion("cmd_scrollTop"))
|
||||
return selCont->CompleteScroll(PR_FALSE);
|
||||
else if (cmdString.EqualsWithConversion("cmd_scrollBottom"))
|
||||
return selCont->CompleteScroll(PR_TRUE);
|
||||
*/
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
@ -522,13 +488,13 @@ nsOutdentCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refC
|
|||
{
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
editorShell->GetEditor(getter_AddRefs(editor));
|
||||
if (editor)
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (htmlEditor)
|
||||
{
|
||||
// XXX fix me. You can't outdent if you're already at the top level.
|
||||
//PRBool canOutdent;
|
||||
//editor->CanIndent("outdent", &canOutdent);
|
||||
PRBool canIndent, canOutdent;
|
||||
htmlEditor->GetIndentState(canIndent, canOutdent);
|
||||
|
||||
*outCmdEnabled = PR_TRUE;
|
||||
*outCmdEnabled = canOutdent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,8 +521,21 @@ nsOutdentCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
|||
#pragma mark -
|
||||
#endif
|
||||
|
||||
|
||||
nsMultiStateCommand::nsMultiStateCommand()
|
||||
: nsBaseComposerCommand()
|
||||
, mGotState(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsMultiStateCommand::~nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(nsMultiStateCommand, nsBaseComposerCommand, nsIStateUpdatingControllerCommand);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParagraphStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
nsMultiStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
*outCmdEnabled = PR_FALSE;
|
||||
|
@ -566,34 +545,166 @@ nsParagraphStateCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports
|
|||
editorShell->GetEditor(getter_AddRefs(editor));
|
||||
if (editor)
|
||||
{
|
||||
// should be disabled sometimes, like if the current selection is an image
|
||||
*outCmdEnabled = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
return UpdateCommandState(aCommand, refCon);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsParagraphStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
nsMultiStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (editorShell)
|
||||
{
|
||||
// we have to grab the state attribute on our command node to find out
|
||||
// what format to set the paragraph to
|
||||
nsAutoString stateAttribute;
|
||||
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = editorShell->SetParagraphFormat(stateAttribute.GetUnicode());
|
||||
// we have to grab the state attribute on our command node to find out
|
||||
// what format to set the paragraph to
|
||||
nsAutoString stateAttribute;
|
||||
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = SetState(editorShell, stateAttribute);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMultiStateCommand::UpdateCommandState(const PRUnichar *aCommandName, nsISupports * refCon)
|
||||
{
|
||||
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
|
||||
nsresult rv = NS_OK;
|
||||
if (editorShell)
|
||||
{
|
||||
nsString curFormat;
|
||||
PRBool isMixed;
|
||||
|
||||
rv = GetCurrentState(editorShell, curFormat, isMixed);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isMixed)
|
||||
curFormat.AssignWithConversion("mixed");
|
||||
|
||||
if (!mGotState || (curFormat != mStateString))
|
||||
{
|
||||
// poke the UI
|
||||
SetCommandNodeState(aCommandName, editorShell, curFormat);
|
||||
|
||||
mGotState = PR_TRUE;
|
||||
mStateString = curFormat;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
nsParagraphStateCommand::nsParagraphStateCommand()
|
||||
: nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsParagraphStateCommand::GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->GetParagraphState(outMixed, outStateString);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsParagraphStateCommand::SetState(nsIEditorShell *aEditorShell, nsString& newState)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->SetParagraphFormat(newState);
|
||||
}
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
nsFontFaceStateCommand::nsFontFaceStateCommand()
|
||||
: nsMultiStateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFontFaceStateCommand::GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlEditor->GetFontFaceState(outMixed, outStateString);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsFontFaceStateCommand::SetState(nsIEditorShell *aEditorShell, nsString& newState)
|
||||
{
|
||||
NS_ASSERTION(aEditorShell, "Need an editor shell here");
|
||||
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
aEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(editor);
|
||||
if (!htmlEditor) return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
NS_ConvertASCIItoUCS2 emptyString("");
|
||||
NS_ConvertASCIItoUCS2 fontString("font");
|
||||
NS_ConvertASCIItoUCS2 faceString("face");
|
||||
|
||||
nsCOMPtr<nsIAtom> ttAtom = getter_AddRefs(NS_NewAtom("tt"));
|
||||
nsCOMPtr<nsIAtom> fontAtom = getter_AddRefs(NS_NewAtom("font"));
|
||||
|
||||
if (newState.EqualsWithConversion("tt"))
|
||||
{
|
||||
// The old "teletype" attribute
|
||||
rv = htmlEditor->SetInlineProperty(ttAtom, &emptyString, &emptyString);
|
||||
// Clear existing font face
|
||||
rv = htmlEditor->RemoveInlineProperty(fontAtom, &faceString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove any existing TT nodes
|
||||
rv = htmlEditor->RemoveInlineProperty(ttAtom, &emptyString);
|
||||
|
||||
if (newState == emptyString || newState.EqualsWithConversion("normal")) {
|
||||
rv = htmlEditor->RemoveInlineProperty(fontAtom, &faceString);
|
||||
} else {
|
||||
rv = htmlEditor->SetInlineProperty(fontAtom, &faceString, &newState);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
|
|
@ -66,7 +66,7 @@ public: \
|
|||
NS_DECL_NSICONTROLLERCOMMAND \
|
||||
};
|
||||
|
||||
// virtual base class for commands that need to save and update state
|
||||
// virtual base class for commands that need to save and update Boolean state (like styles etc)
|
||||
class nsBaseStateUpdatingCommand : public nsBaseComposerCommand,
|
||||
public nsIStateUpdatingControllerCommand
|
||||
{
|
||||
|
@ -98,7 +98,8 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
// shared class for the various style updating commands
|
||||
// Shared class for the various style updating commands like bold, italics etc.
|
||||
// Suitable for commands whose state is either 'on' or 'off'.
|
||||
class nsStyleUpdatingCommand : public nsBaseStateUpdatingCommand
|
||||
{
|
||||
public:
|
||||
|
@ -132,8 +133,58 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
// Base class for commands whose state consists of a string (e.g. para format)
|
||||
class nsMultiStateCommand : public nsBaseComposerCommand,
|
||||
public nsIStateUpdatingControllerCommand
|
||||
{
|
||||
public:
|
||||
|
||||
nsMultiStateCommand();
|
||||
virtual ~nsMultiStateCommand();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTROLLERCOMMAND
|
||||
NS_DECL_NSISTATEUPDATINGCONTROLLERCOMMAND
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed) = 0;
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
PRPackedBool mGotState;
|
||||
nsString mStateString;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class nsParagraphStateCommand : public nsMultiStateCommand
|
||||
{
|
||||
public:
|
||||
nsParagraphStateCommand();
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed);
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
|
||||
};
|
||||
|
||||
class nsFontFaceStateCommand : public nsMultiStateCommand
|
||||
{
|
||||
public:
|
||||
nsFontFaceStateCommand();
|
||||
|
||||
protected:
|
||||
|
||||
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed);
|
||||
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// composer commands
|
||||
NS_DECL_COMPOSER_COMMAND(nsAlwaysEnabledCommands)
|
||||
|
||||
NS_DECL_COMPOSER_COMMAND(nsCloseCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsPrintingCommands)
|
||||
|
@ -157,7 +208,6 @@ NS_DECL_COMPOSER_COMMAND(nsPasteQuotationCommand)
|
|||
NS_DECL_COMPOSER_COMMAND(nsIndentCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsOutdentCommand)
|
||||
|
||||
NS_DECL_COMPOSER_COMMAND(nsParagraphStateCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsAlignCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsRemoveStylesCommand)
|
||||
NS_DECL_COMPOSER_COMMAND(nsIncreaseFontSizeCommand)
|
||||
|
|
|
@ -3695,6 +3695,23 @@ nsEditor::NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEditor::NodeIsType(nsIDOMNode *aNode, const nsString &aTagStr)
|
||||
{
|
||||
nsCOMPtr<nsIDOMElement>element;
|
||||
element = do_QueryInterface(aNode);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString tag;
|
||||
element->GetTagName(tag);
|
||||
if (tag.EqualsIgnoreCase(aTagStr))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsEditor::CanContainTag(nsIDOMNode* aParent, const nsString &aChildTag)
|
||||
{
|
||||
|
|
|
@ -598,6 +598,7 @@ public:
|
|||
|
||||
/** returns PR_TRUE if aNode is of the type implied by aTag */
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag);
|
||||
static PRBool NodeIsType(nsIDOMNode *aNode, const nsString &aTag);
|
||||
|
||||
/** returns PR_TRUE if aParent can contain a child of type aTag */
|
||||
PRBool CanContainTag(nsIDOMNode* aParent, const nsString &aTag);
|
||||
|
|
|
@ -327,6 +327,8 @@ nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandMana
|
|||
|
||||
// format stuff
|
||||
NS_REGISTER_ONE_COMMAND(nsParagraphStateCommand, "cmd_paragraphState");
|
||||
NS_REGISTER_ONE_COMMAND(nsFontFaceStateCommand, "cmd_fontFace");
|
||||
|
||||
NS_REGISTER_ONE_COMMAND(nsAlignCommand, "cmd_align");
|
||||
NS_REGISTER_ONE_COMMAND(nsRemoveStylesCommand, "cmd_removeStyles");
|
||||
NS_REGISTER_ONE_COMMAND(nsIncreaseFontSizeCommand, "cmd_increaseFont");
|
||||
|
|
|
@ -57,6 +57,7 @@ TypeInState::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|||
TypeInState::TypeInState() :
|
||||
mSetArray()
|
||||
,mClearedArray()
|
||||
,mRelativeFontSize(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset();
|
||||
|
@ -108,6 +109,18 @@ nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr)
|
|||
|
||||
nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
|
||||
{
|
||||
// special case for big/small, these nest
|
||||
if (nsIEditProperty::big == aProp)
|
||||
{
|
||||
mRelativeFontSize++;
|
||||
return NS_OK;
|
||||
}
|
||||
if (nsIEditProperty::small == aProp)
|
||||
{
|
||||
mRelativeFontSize--;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if it's already set we are done
|
||||
if (IsPropSet(aProp,aAttr,aValue)) return NS_OK;
|
||||
|
||||
|
@ -196,6 +209,17 @@ nsresult TypeInState::TakeSetProperty(PropItem **outPropItem)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// TakeRelativeFontSize: hands back relative font value, which is then
|
||||
// cleared out.
|
||||
nsresult TypeInState::TakeRelativeFontSize(PRInt32 *outRelSize)
|
||||
{
|
||||
if (!outRelSize) return NS_ERROR_NULL_POINTER;
|
||||
*outRelSize = mRelativeFontSize;
|
||||
mRelativeFontSize = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult TypeInState::GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp)
|
||||
{
|
||||
return GetTypingState(isSet, theSetting, aProp, nsAutoString(), nsAutoString());
|
||||
|
@ -248,6 +272,7 @@ nsresult TypeInState::RemovePropFromSetList(nsIAtom *aProp,
|
|||
if (!aProp)
|
||||
{
|
||||
// clear _all_ props
|
||||
mRelativeFontSize=0;
|
||||
while ((index = mSetArray.Count()))
|
||||
{
|
||||
// go backwards to keep nsVoidArray from memmoving everything each time
|
||||
|
|
|
@ -69,6 +69,11 @@ public:
|
|||
// caller assumes ownership of PropItem and must delete it.
|
||||
nsresult TakeSetProperty(PropItem **outPropItem);
|
||||
|
||||
//**************************************************************************
|
||||
// TakeRelativeFontSize: hands back relative font value, which is then
|
||||
// cleared out.
|
||||
nsresult TakeRelativeFontSize(PRInt32 *outRelSize);
|
||||
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp);
|
||||
nsresult GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp,
|
||||
const nsString &aAttr);
|
||||
|
@ -87,6 +92,7 @@ protected:
|
|||
|
||||
nsVoidArray mSetArray;
|
||||
nsVoidArray mClearedArray;
|
||||
PRInt32 mRelativeFontSize;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ nsHTMLEditRules::nsHTMLEditRules() :
|
|||
mDocChangeRange(nsnull)
|
||||
,mListenerEnabled(PR_TRUE)
|
||||
,mUtilRange(nsnull)
|
||||
,mBody(nsnull)
|
||||
,mJoinOffset(0)
|
||||
{
|
||||
}
|
||||
|
@ -192,73 +191,8 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
nsresult res = NS_OK;
|
||||
if (!--mActionNesting)
|
||||
{
|
||||
ConfirmSelectionInBody();
|
||||
if (action == nsEditor::kOpIgnore) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (mDocChangeRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
|
||||
{
|
||||
// dont let any txns in here move the selection around behind our back.
|
||||
// Note that this won't prevent explicit selection setting from working.
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
|
||||
// expand the "changed doc range" as needed
|
||||
res = PromoteRange(mDocChangeRange, action);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// add in any needed <br>s, and remove any unneeded ones.
|
||||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
if ( (action != nsEditor::kOpInsertText &&
|
||||
action != nsEditor::kOpInsertIMEText) )
|
||||
{
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustWhitespace(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// replace newlines that are preformatted
|
||||
// MOOSE: This is buttUgly. A better way to
|
||||
// organize the action enum is in order.
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsHTMLEditor::kOpInsertElement) ||
|
||||
(action == nsHTMLEditor::kOpInsertQuotation) ||
|
||||
(action == nsEditor::kOpInsertNode))
|
||||
{
|
||||
res = ReplaceNewlines(mDocChangeRange);
|
||||
}
|
||||
|
||||
// clean up any empty nodes in the selection
|
||||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
|
||||
// do all the tricky stuff
|
||||
res = AfterEditInner(action, aDirection);
|
||||
// turn on caret
|
||||
nsCOMPtr<nsISelectionController> selCon;
|
||||
mEditor->GetSelectionController(getter_AddRefs(selCon));
|
||||
|
@ -269,6 +203,79 @@ nsHTMLEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection)
|
||||
{
|
||||
ConfirmSelectionInBody();
|
||||
if (action == nsEditor::kOpIgnore) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (mDocChangeRange && !((action == nsEditor::kOpUndo) || (action == nsEditor::kOpRedo)))
|
||||
{
|
||||
// dont let any txns in here move the selection around behind our back.
|
||||
// Note that this won't prevent explicit selection setting from working.
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
|
||||
// expand the "changed doc range" as needed
|
||||
res = PromoteRange(mDocChangeRange, action);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// add in any needed <br>s, and remove any unneeded ones.
|
||||
res = AdjustSpecialBreaks();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// merge any adjacent text nodes
|
||||
if ( (action != nsEditor::kOpInsertText &&
|
||||
action != nsEditor::kOpInsertIMEText) )
|
||||
{
|
||||
res = mEditor->CollapseAdjacentTextNodes(mDocChangeRange);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// adjust whitespace for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustWhitespace(selection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// replace newlines that are preformatted
|
||||
// MOOSE: This is buttUgly. A better way to
|
||||
// organize the action enum is in order.
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsHTMLEditor::kOpInsertElement) ||
|
||||
(action == nsHTMLEditor::kOpInsertQuotation) ||
|
||||
(action == nsEditor::kOpInsertNode))
|
||||
{
|
||||
res = ReplaceNewlines(mDocChangeRange);
|
||||
}
|
||||
|
||||
// clean up any empty nodes in the selection
|
||||
res = RemoveEmptyNodes();
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// adjust selection for insert text and delete actions
|
||||
if ((action == nsEditor::kOpInsertText) ||
|
||||
(action == nsEditor::kOpInsertIMEText) ||
|
||||
(action == nsEditor::kOpDeleteSelection))
|
||||
{
|
||||
res = AdjustSelection(selection, aDirection);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
// detect empty doc
|
||||
res = CreateBogusNodeIfNeeded(selection);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
||||
nsRulesInfo *aInfo,
|
||||
|
@ -303,7 +310,7 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
case kDeleteSelection:
|
||||
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
||||
case kMakeList:
|
||||
return WillMakeList(aSelection, info->bOrdered, aCancel, aHandled);
|
||||
return WillMakeList(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kIndent:
|
||||
return WillIndent(aSelection, aCancel, aHandled);
|
||||
case kOutdent:
|
||||
|
@ -314,6 +321,8 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
return WillMakeBasicBlock(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kRemoveList:
|
||||
return WillRemoveList(aSelection, info->bOrdered, aCancel, aHandled);
|
||||
case kMakeDefListItem:
|
||||
return WillMakeDefListItem(aSelection, info->blockType, aCancel, aHandled);
|
||||
case kInsertElement:
|
||||
return WillInsert(aSelection, aCancel);
|
||||
}
|
||||
|
@ -349,10 +358,10 @@ nsHTMLEditRules::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
PRBool bNonList = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes);
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// yummy yummy yummy i've got nodes in my tummy
|
||||
// examine list type for nodes in selection
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
|
@ -389,7 +398,102 @@ nsHTMLEditRules::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
aCanIndent = PR_TRUE;
|
||||
aCanOutdent = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetListActionNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// examine nodes in selection for blockquotes or list elements;
|
||||
// these we can outdent. Note that we return true for canOutdent
|
||||
// if *any* of the selection is outdentable, rather than all of it.
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
if (nsHTMLEditUtils::IsList(curNode) ||
|
||||
nsHTMLEditUtils::IsListItem(curNode) ||
|
||||
nsHTMLEditUtils::IsBlockquote(curNode))
|
||||
{
|
||||
aCanOutdent = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditRules::GetParagraphState(PRBool &aMixed, nsString &outFormat)
|
||||
{
|
||||
// This routine is *heavily* tied to our ui choices in the paragraph
|
||||
// style popup. I cant see a way around that.
|
||||
aMixed = PR_TRUE;
|
||||
outFormat.AssignWithConversion("");
|
||||
|
||||
PRBool bMixed = PR_FALSE;
|
||||
nsAutoString formatStr;
|
||||
// using "x" as anuninitialized value, since "" is meaningful
|
||||
formatStr.AssignWithConversion("x");
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
||||
nsresult res = GetParagraphFormatNodes(&arrayOfNodes, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// loop through the nodes in selection and examine their paragraph format
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
arrayOfNodes->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(arrayOfNodes->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
nsAutoString format;
|
||||
nsCOMPtr<nsIAtom> atom = mEditor->GetTag(curNode);
|
||||
|
||||
if (mEditor->IsInlineNode(curNode))
|
||||
format.AssignWithConversion("");
|
||||
else if (nsIEditProperty::p == atom)
|
||||
format.AssignWithConversion("P");
|
||||
else if (nsHTMLEditUtils::IsHeader(curNode))
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(curNode,tag);
|
||||
tag.ToUpperCase();
|
||||
format = tag;
|
||||
}
|
||||
else if (nsIEditProperty::blockquote == atom)
|
||||
format.AssignWithConversion("BLOCKQUOTE");
|
||||
else if (nsIEditProperty::address == atom)
|
||||
format.AssignWithConversion("ADDRESS");
|
||||
else if (nsIEditProperty::pre == atom)
|
||||
format.AssignWithConversion("PRE");
|
||||
else if (nsIEditProperty::dt == atom)
|
||||
format.AssignWithConversion("DT");
|
||||
else if (nsIEditProperty::dd == atom)
|
||||
format.AssignWithConversion("DD");
|
||||
|
||||
// if this is the first node, we've found, remember it as the format
|
||||
if (formatStr.EqualsWithConversion("x"))
|
||||
formatStr = format;
|
||||
// else make sure it matches previously found format
|
||||
else if (format != formatStr)
|
||||
{
|
||||
bMixed = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aMixed = bMixed;
|
||||
outFormat = formatStr;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -825,19 +929,30 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
}
|
||||
}
|
||||
}
|
||||
// is prior node inline and same type? (This shouldn't happen)
|
||||
if ( mEditor->HasSameBlockNodeParent(node, priorNode) &&
|
||||
( mEditor->IsInlineNode(node) || mEditor->IsTextNode(node) ) &&
|
||||
mEditor->NodesSameType(node, priorNode) )
|
||||
// is prior node a text node?
|
||||
else if ( mEditor->IsTextNode(priorNode) )
|
||||
{
|
||||
// if so, join them!
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
priorNode->GetParentNode(getter_AddRefs(topParent));
|
||||
*aHandled = PR_TRUE;
|
||||
res = JoinNodesSmart(priorNode,node,&selNode,&selOffset);
|
||||
// delete last character
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(priorNode);
|
||||
nodeAsText->GetLength((PRUint32*)&offset);
|
||||
res = aSelection->Collapse(priorNode,offset);
|
||||
// just return without setting handled to true.
|
||||
// default code will take care of actual deletion
|
||||
return res;
|
||||
}
|
||||
else if ( mEditor->IsInlineNode(priorNode) )
|
||||
{
|
||||
// remember where we are
|
||||
res = mEditor->GetNodeLocation(priorNode, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// delete it
|
||||
res = mEditor->DeleteNode(priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// fix up selection
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
res = aSelection->Collapse(node,offset);
|
||||
return res;
|
||||
}
|
||||
else return NS_OK; // punt to default
|
||||
|
@ -924,19 +1039,30 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
}
|
||||
}
|
||||
}
|
||||
// is next node inline and same type? (This shouldn't happen)
|
||||
if ( mEditor->HasSameBlockNodeParent(node, nextNode) &&
|
||||
( mEditor->IsInlineNode(node) || mEditor->IsTextNode(node) ) &&
|
||||
mEditor->NodesSameType(node, nextNode) )
|
||||
// is next node a text node?
|
||||
else if ( mEditor->IsTextNode(nextNode) )
|
||||
{
|
||||
// if so, join them!
|
||||
nsCOMPtr<nsIDOMNode> topParent;
|
||||
nextNode->GetParentNode(getter_AddRefs(topParent));
|
||||
*aHandled = PR_TRUE;
|
||||
res = JoinNodesSmart(node,nextNode,&selNode,&selOffset);
|
||||
// delete last character
|
||||
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
||||
nodeAsText = do_QueryInterface(nextNode);
|
||||
nodeAsText->GetLength((PRUint32*)&offset);
|
||||
res = aSelection->Collapse(nextNode,offset);
|
||||
// just return without setting handled to true.
|
||||
// default code will take care of actual deletion
|
||||
return res;
|
||||
}
|
||||
else if ( mEditor->IsInlineNode(nextNode) )
|
||||
{
|
||||
// remember where we are
|
||||
res = mEditor->GetNodeLocation(nextNode, &node, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// delete it
|
||||
res = mEditor->DeleteNode(nextNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we did something, so lets say so.
|
||||
*aHandled = PR_TRUE;
|
||||
// fix up selection
|
||||
res = aSelection->Collapse(selNode,selOffset);
|
||||
res = aSelection->Collapse(node,offset);
|
||||
return res;
|
||||
}
|
||||
else return NS_OK; // punt to default
|
||||
|
@ -1001,6 +1127,11 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!nodeToDelete) return NS_ERROR_NULL_POINTER;
|
||||
if (mBody == nodeToDelete)
|
||||
{
|
||||
*aCancel = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
// if this node is text node, adjust selection
|
||||
if (nsEditor::IsTextNode(nodeToDelete))
|
||||
|
@ -1153,28 +1284,32 @@ nsHTMLEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
|||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
||||
PRBool aOrdered,
|
||||
const nsString *aListType,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled)
|
||||
PRBool *aHandled,
|
||||
const nsString *aItemType)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
if (!aSelection || !aListType || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
nsresult res = WillInsert(aSelection, aCancel);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsAutoString listType;
|
||||
listType.AssignWithConversion( aOrdered ? "ol" : "ul" );
|
||||
|
||||
// initialize out param
|
||||
// we want to ignore result of WillInsert()
|
||||
*aCancel = PR_FALSE;
|
||||
*aHandled = PR_FALSE;
|
||||
|
||||
nsAutoString blockType;
|
||||
blockType.AssignWithConversion( aOrdered ? "ol" : "ul");
|
||||
// deduce what tag to use for list items
|
||||
nsAutoString itemType;
|
||||
if (aItemType)
|
||||
itemType = *aItemType;
|
||||
else if (aListType->EqualsWithConversion("dl"))
|
||||
itemType.AssignWithConversion("dd");
|
||||
else
|
||||
itemType.AssignWithConversion("li");
|
||||
|
||||
PRBool outMakeEmpty;
|
||||
res = ShouldMakeEmptyBlock(aSelection, &blockType, &outMakeEmpty);
|
||||
res = ShouldMakeEmptyBlock(aSelection, aListType, &outMakeEmpty);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (outMakeEmpty)
|
||||
{
|
||||
|
@ -1186,11 +1321,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// make sure we can put a list here
|
||||
res = SplitAsNeeded(&listType, &parent, &offset);
|
||||
res = SplitAsNeeded(aListType, &parent, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, parent, offset, getter_AddRefs(theList));
|
||||
res = mEditor->CreateNode(*aListType, parent, offset, getter_AddRefs(theList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(NS_ConvertASCIItoUCS2("li"), theList, 0, getter_AddRefs(theListItem));
|
||||
res = mEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// put selection in new list item
|
||||
res = aSelection->Collapse(theListItem,0);
|
||||
|
@ -1224,8 +1359,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports) );
|
||||
|
||||
while (nsHTMLEditUtils::IsDiv(curNode)
|
||||
|| nsHTMLEditUtils::IsOrderedList(curNode)
|
||||
|| nsHTMLEditUtils::IsUnorderedList(curNode)
|
||||
|| nsHTMLEditUtils::IsList(curNode)
|
||||
|| nsHTMLEditUtils::IsBlockquote(curNode))
|
||||
{
|
||||
// dive as long as there is only one child, and it is a list, div, blockquote
|
||||
|
@ -1238,8 +1372,7 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// keep diving
|
||||
nsCOMPtr <nsIDOMNode> tmpNode = nsEditor::GetChildAt(curNode, 0);
|
||||
if (nsHTMLEditUtils::IsDiv(tmpNode)
|
||||
|| nsHTMLEditUtils::IsOrderedList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsUnorderedList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsList(tmpNode)
|
||||
|| nsHTMLEditUtils::IsBlockquote(tmpNode))
|
||||
{
|
||||
// check editablility XXX floppy moose
|
||||
|
@ -1305,37 +1438,38 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
|
||||
if (nsHTMLEditUtils::IsList(curNode))
|
||||
{
|
||||
nsAutoString existingListStr;
|
||||
res = mEditor->GetTagString(curNode, existingListStr);
|
||||
// do we have a curList already?
|
||||
if (curList && !nsHTMLEditUtils::IsDescendantOf(curNode, curList))
|
||||
{
|
||||
// move all of our dachildren into curList.
|
||||
// move all of our children into curList.
|
||||
// cheezy way to do it: move whole list and then
|
||||
// RemoveContainer() on the list
|
||||
// RemoveContainer() on the list.
|
||||
// ConvertListType first: that routine
|
||||
// handles converting the list item types, if needed
|
||||
res = mEditor->MoveNode(curNode, curList, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->RemoveContainer(curNode);
|
||||
res = ConvertListType(curNode, &newBlock, *aListType, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
else if ( (nsHTMLEditUtils::IsUnorderedList(curNode) && aOrdered) ||
|
||||
(nsHTMLEditUtils::IsOrderedList(curNode) && !aOrdered) )
|
||||
|
||||
{
|
||||
// replace list with new list type
|
||||
res = mEditor->ReplaceContainer(curNode,&newBlock,blockType);
|
||||
res = mEditor->RemoveContainer(newBlock);
|
||||
if (NS_FAILED(res)) return res;
|
||||
curList = newBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
curList = curNode;
|
||||
// replace list with new list type
|
||||
res = ConvertListType(curNode, &newBlock, *aListType, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
curList = newBlock;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nsHTMLEditUtils::IsListItem(curNode))
|
||||
{
|
||||
if ( (nsHTMLEditUtils::IsUnorderedList(curParent) && aOrdered) ||
|
||||
(nsHTMLEditUtils::IsOrderedList(curParent) && !aOrdered) )
|
||||
nsAutoString existingListStr;
|
||||
res = mEditor->GetTagString(curParent, existingListStr);
|
||||
if ( existingListStr != *aListType )
|
||||
{
|
||||
// list item is in wrong type of list.
|
||||
// if we dont have a curList, split the old list
|
||||
|
@ -1348,16 +1482,23 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
PRInt32 o;
|
||||
res = nsEditor::GetNodeLocation(curParent, &p, &o);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, p, o, getter_AddRefs(curList));
|
||||
res = mEditor->CreateNode(*aListType, p, o, getter_AddRefs(curList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
// move list item to new list
|
||||
res = mEditor->MoveNode(curNode, curList, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// convert list item type if needed
|
||||
if (!mEditor->NodeIsType(curNode,itemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &newBlock, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// item is in right type of list. But we might still have to move it.
|
||||
// and we might need to convert list item types.
|
||||
if (!curList)
|
||||
curList = curParent;
|
||||
else
|
||||
|
@ -1369,6 +1510,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
if (!mEditor->NodeIsType(curNode,itemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &newBlock, itemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1377,9 +1523,9 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// or if this node doesn't go in list we used earlier.
|
||||
if (!curList) // || transitionList[i])
|
||||
{
|
||||
res = SplitAsNeeded(&listType, &curParent, &offset);
|
||||
res = SplitAsNeeded(aListType, &curParent, &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->CreateNode(listType, curParent, offset, getter_AddRefs(curList));
|
||||
res = mEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
|
||||
if (NS_FAILED(res)) return res;
|
||||
// curList is now the correct thing to put curNode in
|
||||
prevListItem = 0;
|
||||
|
@ -1404,11 +1550,11 @@ nsHTMLEditRules::WillMakeList(nsIDOMSelection *aSelection,
|
|||
// don't wrap li around a paragraph. instead replace paragraph with li
|
||||
if (nsHTMLEditUtils::IsParagraph(curNode))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(curNode, &listItem, NS_ConvertASCIItoUCS2("li"));
|
||||
res = mEditor->ReplaceContainer(curNode, &listItem, itemType);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->InsertContainerAbove(curNode, &listItem, NS_ConvertASCIItoUCS2("li"));
|
||||
res = mEditor->InsertContainerAbove(curNode, &listItem, itemType);
|
||||
}
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (nsEditor::IsInlineNode(curNode))
|
||||
|
@ -1525,6 +1671,18 @@ nsHTMLEditRules::WillRemoveList(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeDefListItem(nsIDOMSelection *aSelection,
|
||||
const nsString *aItemType,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled)
|
||||
{
|
||||
// for now we let WillMakeList handle this
|
||||
nsAutoString listType;
|
||||
listType.AssignWithConversion("dl");
|
||||
return WillMakeList(aSelection, &listType, aCancel, aHandled, aItemType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillMakeBasicBlock(nsIDOMSelection *aSelection,
|
||||
const nsString *aBlockType,
|
||||
|
@ -1808,6 +1966,40 @@ nsHTMLEditRules::WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBoo
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ConvertListType: convert list type and list item type.
|
||||
//
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::ConvertListType(nsIDOMNode *aList,
|
||||
nsCOMPtr<nsIDOMNode> *outList,
|
||||
const nsString& aListType,
|
||||
const nsString& aItemType)
|
||||
{
|
||||
if (!aList || !outList) return NS_ERROR_NULL_POINTER;
|
||||
*outList = aList; // we migvht not need to change the list
|
||||
nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> child, temp;
|
||||
aList->GetFirstChild(getter_AddRefs(child));
|
||||
while (child)
|
||||
{
|
||||
if (!mEditor->NodeIsType(child, aItemType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(child, &temp, aItemType);
|
||||
if (NS_FAILED(res)) return res;
|
||||
child = temp;
|
||||
}
|
||||
child->GetNextSibling(getter_AddRefs(temp));
|
||||
child = temp;
|
||||
}
|
||||
if (!mEditor->NodeIsType(aList, aListType))
|
||||
{
|
||||
res = mEditor->ReplaceContainer(aList, outList, aListType);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CreateStyleForInsertText: take care of clearing and setting appropriate
|
||||
// style nodes for text insertion.
|
||||
|
@ -1839,10 +2031,15 @@ nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDoc
|
|||
}
|
||||
|
||||
// then process setting any styles
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
PRInt32 relFontSize;
|
||||
|
||||
if (item) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
res = mEditor->mTypeInState->TakeRelativeFontSize(&relFontSize);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (item || relFontSize) // we have at least one style to add; make a
|
||||
{ // new text node to insert style nodes above.
|
||||
if (mEditor->IsTextNode(node))
|
||||
{
|
||||
// if we are in a text node, split it
|
||||
|
@ -1863,17 +2060,29 @@ nsHTMLEditRules::CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDoc
|
|||
node = newNode;
|
||||
offset = 0;
|
||||
weDidSometing = PR_TRUE;
|
||||
|
||||
if (relFontSize)
|
||||
{
|
||||
PRInt32 j, dir;
|
||||
// dir indicated bigger versus smaller. 1 = bigger, -1 = smaller
|
||||
if (relFontSize > 0) dir=1;
|
||||
else dir = -1;
|
||||
for (j=0; j<abs(relFontSize); j++)
|
||||
{
|
||||
res = mEditor->RelativeFontChangeOnTextNode(dir, nodeAsText, 0, -1);
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we own item now (TakeSetProperty hands ownership to us)
|
||||
delete item;
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
}
|
||||
}
|
||||
|
||||
while (item)
|
||||
{
|
||||
res = mEditor->SetInlinePropertyOnNode(node, item->tag, &item->attr, &item->value);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// we own item now (TakeSetProperty hands ownership to us)
|
||||
delete item;
|
||||
mEditor->mTypeInState->TakeSetProperty(&item);
|
||||
}
|
||||
|
||||
if (weDidSometing)
|
||||
return aSelection->Collapse(node, offset);
|
||||
|
||||
|
@ -2616,7 +2825,8 @@ nsHTMLEditRules::PromoteRange(nsIDOMRange *inRange,
|
|||
nsresult
|
||||
nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType)
|
||||
PRInt32 inOperationType,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!inArrayOfRanges || !outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
|
@ -2669,7 +2879,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
|||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> node( do_QueryInterface(isupports) );
|
||||
if (mEditor->IsInlineNode(node) && mEditor->IsContainer(node))
|
||||
if (!aDontTouchContent && mEditor->IsInlineNode(node) && mEditor->IsContainer(node))
|
||||
{
|
||||
nsCOMPtr<nsISupportsArray> arrayOfInlines;
|
||||
res = BustUpInlinesAtBRs(node, &arrayOfInlines);
|
||||
|
@ -2735,7 +2945,8 @@ nsHTMLEditRules::GetChildNodesForOperation(nsIDOMNode *inNode,
|
|||
// GetListActionNodes:
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
||||
nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
|
@ -2748,7 +2959,58 @@ nsHTMLEditRules::GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// use these ranges to contruct a list of nodes to act on.
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList);
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeList, aDontTouchContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// pre process our list of nodes...
|
||||
PRUint32 listCount;
|
||||
PRInt32 i;
|
||||
(*outArrayOfNodes)->Count(&listCount);
|
||||
for (i=(PRInt32)listCount-1; i>=0; i--)
|
||||
{
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)((*outArrayOfNodes)->ElementAt(i));
|
||||
nsCOMPtr<nsIDOMNode> testNode( do_QueryInterface(isupports ) );
|
||||
|
||||
// Remove all non-editable nodes. Leave them be.
|
||||
if (!mEditor->IsEditable(testNode))
|
||||
{
|
||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||
}
|
||||
|
||||
// scan for table elements. If we find table elements other than table,
|
||||
// replace it with a list of any editable non-table content.
|
||||
if (mEditor->IsTableElement(testNode) && !mEditor->IsTable(testNode))
|
||||
{
|
||||
(*outArrayOfNodes)->RemoveElementAt(i);
|
||||
nsCOMPtr<nsISupportsArray> arrayOfTableContent;
|
||||
res = GetTableContent(testNode, &arrayOfTableContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
(*outArrayOfNodes)->AppendElements(arrayOfTableContent);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// GetParagraphFormatNodes:
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRBool aDontTouchContent)
|
||||
{
|
||||
if (!outArrayOfNodes) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsCOMPtr<nsIDOMSelection>selection;
|
||||
nsresult res = mEditor->GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> arrayOfRanges;
|
||||
res = GetPromotedRanges(selection, &arrayOfRanges, kMakeList);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// use these ranges to contruct a list of nodes to act on.
|
||||
res = GetNodesForOperation(arrayOfRanges, outArrayOfNodes, kMakeBasicBlock, aDontTouchContent);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// pre process our list of nodes...
|
||||
|
@ -3285,7 +3547,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
// Note that if _nothing_ should happen, ie, the selection is
|
||||
// already entireyl inside a block (or blocks) or the correct type,
|
||||
// then you don't want to return true in outMakeEmpty, since the
|
||||
// defualt code will insert a new empty block anyway, rather than
|
||||
// default code will insert a new empty block anyway, rather than
|
||||
// doing nothing. So we have to detect that case and return false.
|
||||
|
||||
if (!aSelection || !outMakeEmpty) return NS_ERROR_NULL_POINTER;
|
||||
|
@ -3342,18 +3604,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
*outMakeEmpty = PR_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
// in an empty block?
|
||||
PRBool bIsEmptyNode;
|
||||
// the PR_TRUE param tell IsEmptyNode to not count moz-BRs as content
|
||||
res = IsEmptyNode(block, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
||||
if (bIsEmptyNode)
|
||||
{
|
||||
// we must be in a text or inline node - convert existing block
|
||||
*outMakeEmpty = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// is it after a <br> with no inline nodes after it, or a <br> after it??
|
||||
if (offset)
|
||||
{
|
||||
|
@ -3383,7 +3634,7 @@ nsHTMLEditRules::ShouldMakeEmptyBlock(nsIDOMSelection *aSelection,
|
|||
// we are after a <br> and not before inline content,
|
||||
// or we are between <br>s.
|
||||
// make an empty block
|
||||
*outMakeEmpty = PR_FALSE;
|
||||
*outMakeEmpty = PR_TRUE;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
// nsIHTMLEditRules methods
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL);
|
||||
NS_IMETHOD GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent);
|
||||
NS_IMETHOD GetParagraphState(PRBool &aMixed, nsString &outFormat);
|
||||
|
||||
// nsIEditActionListener methods
|
||||
|
||||
|
@ -97,11 +98,12 @@ protected:
|
|||
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillDeleteSelection(nsIDOMSelection *aSelection, nsIEditor::EDirection aAction,
|
||||
PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeList(nsIDOMSelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeList(nsIDOMSelection *aSelection, const nsString *aListType, PRBool *aCancel, PRBool *aHandled, const nsString *aItemType=nsnull);
|
||||
nsresult WillRemoveList(nsIDOMSelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillIndent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillOutdent(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillAlign(nsIDOMSelection *aSelection, const nsString *alignType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeDefListItem(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult WillMakeBasicBlock(nsIDOMSelection *aSelection, const nsString *aBlockType, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidMakeBasicBlock(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
|
||||
|
||||
|
@ -115,17 +117,13 @@ protected:
|
|||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult ReturnInListItem(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
|
||||
nsresult AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection);
|
||||
nsresult ConvertListType(nsIDOMNode *aList, nsCOMPtr<nsIDOMNode> *outList, const nsString& aListType, const nsString& aItemType);
|
||||
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, nsIDOMDocument *aDoc);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
#if 0
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
#endif
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
@ -138,11 +136,13 @@ protected:
|
|||
PRInt32 inOperationType);
|
||||
nsresult PromoteRange(nsIDOMRange *inRange, PRInt32 inOperationType);
|
||||
nsresult GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType);
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes,
|
||||
PRInt32 inOperationType,
|
||||
PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult GetChildNodesForOperation(nsIDOMNode *inNode,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult GetListActionNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult GetParagraphFormatNodes(nsCOMPtr<nsISupportsArray> *outArrayOfNodes, PRBool aDontTouchContent=PR_FALSE);
|
||||
nsresult BustUpInlinesAtBRs(nsIDOMNode *inNode,
|
||||
nsCOMPtr<nsISupportsArray> *outArrayOfNodes);
|
||||
nsresult MakeTransitionList(nsISupportsArray *inArrayOfNodes,
|
||||
|
@ -185,7 +185,6 @@ protected:
|
|||
nsCOMPtr<nsIDOMRange> mDocChangeRange;
|
||||
PRBool mListenerEnabled;
|
||||
nsCOMPtr<nsIDOMRange> mUtilRange;
|
||||
nsCOMPtr<nsIDOMNode> mBody;
|
||||
PRUint32 mJoinOffset; // need to remember an int across willJoin/didJoin...
|
||||
|
||||
};
|
||||
|
|
|
@ -220,7 +220,9 @@ nsHTMLEditUtils::IsListItem(nsIDOMNode *node)
|
|||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if (tag.EqualsWithConversion("li"))
|
||||
if (tag.EqualsWithConversion("li") ||
|
||||
tag.EqualsWithConversion("dd") ||
|
||||
tag.EqualsWithConversion("dt"))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -289,7 +291,8 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node)
|
|||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if ( (tag.EqualsWithConversion("ol")) ||
|
||||
if ( (tag.EqualsWithConversion("dl")) ||
|
||||
(tag.EqualsWithConversion("ol")) ||
|
||||
(tag.EqualsWithConversion("ul")) )
|
||||
{
|
||||
return PR_TRUE;
|
||||
|
@ -299,7 +302,7 @@ nsHTMLEditUtils::IsList(nsIDOMNode *node)
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsOrderedList: true if node an html orderd list
|
||||
// IsOrderedList: true if node an html ordered list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
|
||||
|
@ -317,7 +320,7 @@ nsHTMLEditUtils::IsOrderedList(nsIDOMNode *node)
|
|||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsUnorderedList: true if node an html orderd list
|
||||
// IsUnorderedList: true if node an html unordered list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
|
||||
|
@ -334,6 +337,24 @@ nsHTMLEditUtils::IsUnorderedList(nsIDOMNode *node)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsDefinitionList: true if node an html definition list
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditUtils::IsDefinitionList(nsIDOMNode *node)
|
||||
{
|
||||
NS_PRECONDITION(node, "null parent passed to nsHTMLEditUtils::IsDefinitionList");
|
||||
nsAutoString tag;
|
||||
nsEditor::GetTagString(node,tag);
|
||||
tag.ToLowerCase();
|
||||
if (tag.EqualsWithConversion("dl"))
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsBlockquote: true if node an html blockquote node
|
||||
//
|
||||
|
|
|
@ -48,8 +48,9 @@ public:
|
|||
static PRBool IsTableRow(nsIDOMNode *aNode);
|
||||
static PRBool IsTableCell(nsIDOMNode *aNode);
|
||||
static PRBool IsList(nsIDOMNode *aNode);
|
||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsOrderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsUnorderedList(nsIDOMNode *aNode);
|
||||
static PRBool IsDefinitionList(nsIDOMNode *aNode);
|
||||
static PRBool IsBlockquote(nsIDOMNode *aNode);
|
||||
static PRBool IsPre(nsIDOMNode *aNode);
|
||||
static PRBool IsAddress(nsIDOMNode *aNode);
|
||||
|
|
|
@ -1001,6 +1001,10 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode)
|
|||
|
||||
if (!outBRNode) return NS_ERROR_NULL_POINTER;
|
||||
*outBRNode = nsnull;
|
||||
|
||||
// calling it text insertion to trigger moz br treatment by rules
|
||||
nsAutoRules beginRulesSniffing(this, kOpInsertText, nsIEditor::eNext);
|
||||
|
||||
nsresult res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = selection->GetIsCollapsed(&bCollapsed);
|
||||
|
@ -1019,6 +1023,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertBR(nsCOMPtr<nsIDOMNode> *outBRNode)
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// position selection after br
|
||||
res = GetNodeLocation(*outBRNode, &selNode, &selOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
selection->SetHint(PR_TRUE);
|
||||
res = selection->Collapse(selNode, selOffset+1);
|
||||
|
||||
|
@ -1127,22 +1133,28 @@ NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// iterate range and build up array
|
||||
iter->Init(range);
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
res = iter->Init(range);
|
||||
// init returns an error if no nodes in range.
|
||||
// this can easily happen with the subtree
|
||||
// iterator if the selection doesn't contain
|
||||
// any *whole* nodes.
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
res = iter->CurrentNode(getter_AddRefs(content));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = do_QueryInterface(content);
|
||||
if (!node) return NS_ERROR_FAILURE;
|
||||
if (IsEditable(node))
|
||||
{
|
||||
isupports = do_QueryInterface(node);
|
||||
arrayOfNodes->AppendElement(isupports);
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
res = iter->CurrentNode(getter_AddRefs(content));
|
||||
if (NS_FAILED(res)) return res;
|
||||
node = do_QueryInterface(content);
|
||||
if (!node) return NS_ERROR_FAILURE;
|
||||
if (IsEditable(node))
|
||||
{
|
||||
isupports = do_QueryInterface(node);
|
||||
arrayOfNodes->AppendElement(isupports);
|
||||
}
|
||||
res = iter->Next();
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
res = iter->Next();
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
|
||||
// MOOSE: workaround for selection bug:
|
||||
//selection->ClearSelection();
|
||||
|
||||
|
@ -1713,7 +1725,20 @@ PRBool nsHTMLEditor::IsAtEndOfNode(nsIDOMNode *aNode, PRInt32 aOffset)
|
|||
NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll)
|
||||
PRBool &aFirst,
|
||||
PRBool &aAny,
|
||||
PRBool &aAll)
|
||||
{
|
||||
return GetInlinePropertyWithAttrValue( aProperty, aAttribute, aValue, aFirst, aAny, aAll, nsnull);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHTMLEditor::GetInlinePropertyWithAttrValue(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst,
|
||||
PRBool &aAny,
|
||||
PRBool &aAll,
|
||||
nsString *outValue)
|
||||
{
|
||||
if (!aProperty)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
@ -1805,11 +1830,6 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
}
|
||||
return NS_OK;
|
||||
}
|
||||
else if (aProperty == mFontAtom.get())
|
||||
{
|
||||
// MOOSE!
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// either non-collapsed selection or no cached value: do it the hard way
|
||||
|
@ -1822,6 +1842,7 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
|
||||
iter->Init(range);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
nsAutoString firstValue, theValue;
|
||||
iter->CurrentNode(getter_AddRefs(content));
|
||||
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
||||
{
|
||||
|
@ -1866,12 +1887,20 @@ NS_IMETHODIMP nsHTMLEditor::GetInlineProperty(nsIAtom *aProperty,
|
|||
{
|
||||
PRBool isSet;
|
||||
nsCOMPtr<nsIDOMNode>resultNode;
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode));
|
||||
if (first)
|
||||
{
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode), &firstValue);
|
||||
aFirst = isSet;
|
||||
first = PR_FALSE;
|
||||
if (outValue) *outValue = firstValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode), &theValue);
|
||||
if (firstValue != theValue)
|
||||
aAll = PR_FALSE;
|
||||
}
|
||||
|
||||
if (isSet) {
|
||||
aAny = PR_TRUE;
|
||||
}
|
||||
|
@ -2790,7 +2819,10 @@ nsHTMLEditor::SetParagraphFormat(const nsString& aParagraphFormat)
|
|||
{
|
||||
nsAutoString tag; tag.Assign(aParagraphFormat);
|
||||
tag.ToLowerCase();
|
||||
return InsertBasicBlock(tag);
|
||||
if (tag.EqualsWithConversion("dd") || tag.EqualsWithConversion("dt"))
|
||||
return MakeDefinitionItem(tag);
|
||||
else
|
||||
return InsertBasicBlock(tag);
|
||||
}
|
||||
|
||||
// XXX: ERROR_HANDLING -- this method needs a little work to ensure all error codes are
|
||||
|
@ -2907,20 +2939,52 @@ nsHTMLEditor::GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists)
|
|||
}
|
||||
|
||||
|
||||
// get the paragraph style(s) for the selection
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetParagraphTags(nsStringArray *aTagList)
|
||||
nsHTMLEditor::GetParagraphState(PRBool &aMixed, nsString &outFormat)
|
||||
{
|
||||
#if 0
|
||||
if (gNoisy) { printf("---------- nsHTMLEditor::GetPargraphTags ----------\n"); }
|
||||
#endif
|
||||
return GetParentBlockTags(aTagList, PR_FALSE);
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
||||
if (!htmlRules) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlRules->GetParagraphState(aMixed, outFormat);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetListTags(nsStringArray *aTagList)
|
||||
nsHTMLEditor::GetFontFaceState(PRBool &aMixed, nsString &outFace)
|
||||
{
|
||||
return GetParentBlockTags(aTagList, PR_TRUE);
|
||||
aMixed = PR_TRUE;
|
||||
outFace.AssignWithConversion("");
|
||||
|
||||
nsresult res;
|
||||
nsAutoString faceStr; faceStr.AssignWithConversion("face");
|
||||
PRBool first, any, all;
|
||||
|
||||
res = GetInlinePropertyWithAttrValue(nsIEditProperty::font, &faceStr, nsnull, first, any, all, &outFace);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (any && !all) return res; // mixed
|
||||
if (all)
|
||||
{
|
||||
aMixed = PR_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
res = GetInlineProperty(nsIEditProperty::tt, nsnull, nsnull, first, any, all);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (any && !all) return res; // mixed
|
||||
if (all)
|
||||
{
|
||||
aMixed = PR_FALSE;
|
||||
nsIEditProperty::tt->ToString(outFace);
|
||||
}
|
||||
|
||||
if (!any)
|
||||
{
|
||||
// there was no font face attrs of any kind. We are in normal font.
|
||||
outFace.AssignWithConversion("");
|
||||
aMixed = PR_FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2934,6 +2998,17 @@ nsHTMLEditor::GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)
|
|||
return htmlRules->GetListState(aMixed, aOL, aUL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)
|
||||
{
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
nsCOMPtr<nsIHTMLEditRules> htmlRules = do_QueryInterface(mRules);
|
||||
if (!htmlRules) return NS_ERROR_FAILURE;
|
||||
|
||||
return htmlRules->GetIndentState(aCanIndent, aCanOutdent);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHTMLEditor::MakeOrChangeList(const nsString& aListType)
|
||||
{
|
||||
|
@ -2952,8 +3027,7 @@ nsHTMLEditor::MakeOrChangeList(const nsString& aListType)
|
|||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeList);
|
||||
if (aListType.EqualsWithConversion("ol")) ruleInfo.bOrdered = PR_TRUE;
|
||||
else ruleInfo.bOrdered = PR_FALSE;
|
||||
ruleInfo.blockType = &aListType;
|
||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
if (cancel || (NS_FAILED(res))) return res;
|
||||
|
||||
|
@ -3041,8 +3115,37 @@ nsHTMLEditor::RemoveList(const nsString& aListType)
|
|||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::MakeDefinitionItem(const nsString& aItemType)
|
||||
{
|
||||
nsresult res;
|
||||
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
PRBool cancel, handled;
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
nsAutoRules beginRulesSniffing(this, kOpMakeDefListItem, nsIEditor::eNext);
|
||||
|
||||
// pre-process
|
||||
res = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kMakeDefListItem);
|
||||
ruleInfo.blockType = &aItemType;
|
||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
if (cancel || (NS_FAILED(res))) return res;
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
// todo: no default for now. we count on rules to handle it.
|
||||
}
|
||||
|
||||
res = mRules->DidDoAction(selection, &ruleInfo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLEditor::InsertBasicBlock(const nsString& aBlockType)
|
||||
{
|
||||
nsresult res;
|
||||
|
@ -5534,7 +5637,8 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aIsSet,
|
||||
nsIDOMNode **aStyleNode) const
|
||||
nsIDOMNode **aStyleNode,
|
||||
nsString *outValue) const
|
||||
{
|
||||
nsresult result;
|
||||
aIsSet = PR_FALSE; // must be initialized to false for code below to work
|
||||
|
@ -5548,15 +5652,15 @@ void nsHTMLEditor::IsTextPropertySetByContent(nsIDOMNode *aNode,
|
|||
element = do_QueryInterface(node);
|
||||
if (element)
|
||||
{
|
||||
nsAutoString tag;
|
||||
nsAutoString tag, value;
|
||||
element->GetTagName(tag);
|
||||
if (propName.EqualsIgnoreCase(tag))
|
||||
{
|
||||
PRBool found = PR_FALSE;
|
||||
if (aAttribute && 0!=aAttribute->Length())
|
||||
{
|
||||
nsAutoString value;
|
||||
element->GetAttribute(*aAttribute, value);
|
||||
if (outValue) *outValue = value;
|
||||
if (value.Length())
|
||||
{
|
||||
if (!aValue) {
|
||||
|
@ -6182,12 +6286,14 @@ nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
|
|||
res = selection->GetIsCollapsed(&bCollapsed);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// if it's collapsed dont do anything.
|
||||
// MOOSE: We should probably have typing state for this like
|
||||
// we do for other things.
|
||||
// if it's collapsed set typing state
|
||||
if (bCollapsed)
|
||||
{
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIAtom> atom;
|
||||
if (aSizeChange==1) atom = nsIEditProperty::big;
|
||||
else atom = nsIEditProperty::small;
|
||||
// manipulating text attributes on a collapsed selection only sets state for the next text insertion
|
||||
return mTypeInState->SetProp(atom, nsnull, nsnull);
|
||||
}
|
||||
|
||||
// wrap with txn batching, rules sniffing, and selection preservation code
|
||||
|
@ -6346,6 +6452,9 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
|
|||
PRUint32 textLen;
|
||||
aTextNode->GetLength(&textLen);
|
||||
|
||||
// -1 is a magic value meaning to the end of node
|
||||
if (aEndOffset == -1) aEndOffset = textLen;
|
||||
|
||||
if ( (PRUint32)aEndOffset != textLen )
|
||||
{
|
||||
// we need to split off back of text node
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
kOpAlign = 3004,
|
||||
kOpMakeBasicBlock = 3005,
|
||||
kOpRemoveList = 3006,
|
||||
kOpMakeDefListItem = 3007,
|
||||
kOpInsertElement = 3008,
|
||||
kOpInsertQuotation = 3009
|
||||
};
|
||||
|
@ -103,6 +104,11 @@ public:
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll);
|
||||
NS_IMETHOD GetInlinePropertyWithAttrValue(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll,
|
||||
nsString *outValue);
|
||||
|
||||
NS_IMETHOD RemoveAllInlineProperties();
|
||||
NS_IMETHOD RemoveInlineProperty(nsIAtom *aProperty, const nsString *aAttribute);
|
||||
|
@ -125,13 +131,14 @@ public:
|
|||
NS_IMETHOD SetParagraphFormat(const nsString& aParagraphFormat);
|
||||
|
||||
NS_IMETHOD GetParentBlockTags(nsStringArray *aTagList, PRBool aGetLists);
|
||||
NS_IMETHOD GetParagraphTags(nsStringArray *aTagList);
|
||||
NS_IMETHOD GetListTags(nsStringArray *aTagList);
|
||||
|
||||
NS_IMETHOD GetParagraphState(PRBool &aMixed, nsString &outFormat);
|
||||
NS_IMETHOD GetFontFaceState(PRBool &aMixed, nsString &outFace);
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL);
|
||||
NS_IMETHOD GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent);
|
||||
|
||||
NS_IMETHOD MakeOrChangeList(const nsString& aListType);
|
||||
NS_IMETHOD RemoveList(const nsString& aListType);
|
||||
NS_IMETHOD InsertBasicBlock(const nsString& aBlockType);
|
||||
NS_IMETHOD Indent(const nsString& aIndent);
|
||||
NS_IMETHOD Align(const nsString& aAlign);
|
||||
|
||||
|
@ -441,7 +448,8 @@ protected:
|
|||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aIsSet,
|
||||
nsIDOMNode **aStyleNode) const;
|
||||
nsIDOMNode **aStyleNode,
|
||||
nsString *outValue = nsnull) const;
|
||||
|
||||
/** style-based query returns PR_TRUE if (aProperty, aAttribute) is set in aSC.
|
||||
* WARNING: not well tested yet since we don't do style-based queries anywhere.
|
||||
|
@ -473,6 +481,10 @@ protected:
|
|||
/* small utility routine to test the eEditorReadonly bit */
|
||||
PRBool IsModifiable();
|
||||
|
||||
/* helpers for block transformations */
|
||||
nsresult MakeDefinitionItem(const nsString& aItemType);
|
||||
nsresult InsertBasicBlock(const nsString& aBlockType);
|
||||
|
||||
/* increase/decrease the font size of selection */
|
||||
nsresult RelativeFontChange( PRInt32 aSizeChange);
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ NS_NewTextEditRules(nsIEditRules** aInstancePtrResult)
|
|||
nsTextEditRules::nsTextEditRules()
|
||||
: mEditor(nsnull)
|
||||
, mFlags(0) // initialized to 0 ("no flags set"). Real initial value is given in Init()
|
||||
, mPasswordText()
|
||||
, mBogusNode(nsnull)
|
||||
, mBody(nsnull)
|
||||
, mActionNesting(0)
|
||||
, mLockRulesSniffing(PR_FALSE)
|
||||
, mTheAction(0)
|
||||
|
@ -106,29 +109,33 @@ nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
|||
nsCOMPtr<nsIDOMSelection> selection;
|
||||
mEditor->GetSelection(getter_AddRefs(selection));
|
||||
NS_ASSERTION(selection, "editor cannot get selection");
|
||||
nsresult res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
|
||||
|
||||
// create a range that is the entire body contents
|
||||
if (NS_FAILED(res)) return res;
|
||||
// remember our root node
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
nsresult res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
if (!bodyNode) return NS_ERROR_FAILURE;
|
||||
mBody = do_QueryInterface(bodyElement);
|
||||
if (!mBody) return NS_ERROR_FAILURE;
|
||||
|
||||
// put in a magic br if needed
|
||||
res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// create a range that is the entire body contents
|
||||
nsCOMPtr<nsIDOMRange> wholeDoc;
|
||||
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(wholeDoc));
|
||||
if (NS_FAILED(res)) return res;
|
||||
wholeDoc->SetStart(bodyNode,0);
|
||||
wholeDoc->SetStart(mBody,0);
|
||||
nsCOMPtr<nsIDOMNodeList> list;
|
||||
res = bodyNode->GetChildNodes(getter_AddRefs(list));
|
||||
res = mBody->GetChildNodes(getter_AddRefs(list));
|
||||
if (NS_FAILED(res) || !list) return res?res:NS_ERROR_FAILURE;
|
||||
PRUint32 listCount;
|
||||
res = list->GetLength(&listCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
res = wholeDoc->SetEnd(bodyNode,listCount);
|
||||
res = wholeDoc->SetEnd(mBody,listCount);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// replace newlines in that range with breaks
|
||||
|
@ -1188,19 +1195,14 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
|
|||
// tell rules system to not do any post-processing
|
||||
nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> bodyElement;
|
||||
|
||||
nsresult res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
||||
nsCOMPtr<nsIDOMNode>bodyNode = do_QueryInterface(bodyElement);
|
||||
if (!mBody) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// now we've got the body tag.
|
||||
// iterate the body tag, looking for editable content
|
||||
// if no editable content is found, insert the bogus node
|
||||
PRBool needsBogusContent=PR_TRUE;
|
||||
nsCOMPtr<nsIDOMNode>bodyChild;
|
||||
res = bodyNode->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
nsresult res = mBody->GetFirstChild(getter_AddRefs(bodyChild));
|
||||
while ((NS_SUCCEEDED(res)) && bodyChild)
|
||||
{
|
||||
if (mEditor->IsMozEditorBogusNode(bodyChild) || mEditor->IsEditable(bodyChild))
|
||||
|
@ -1214,25 +1216,27 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
|
|||
}
|
||||
if (needsBogusContent)
|
||||
{
|
||||
// set mBogusNode to be the newly created <br>
|
||||
res = mEditor->CreateNode(NS_ConvertASCIItoUCS2("br"), bodyNode, 0,
|
||||
getter_AddRefs(mBogusNode));
|
||||
// create a br
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
res = mEditor->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIDOMElement>brElement;
|
||||
res = domDoc->CreateElement(NS_ConvertASCIItoUCS2("br"),getter_AddRefs(brElement));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// set mBogusNode to be the newly created <br>
|
||||
mBogusNode = do_QueryInterface(brElement);
|
||||
if (!mBogusNode) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// give it a special attribute
|
||||
nsCOMPtr<nsIDOMElement>newPElement;
|
||||
newPElement = do_QueryInterface(mBogusNode);
|
||||
if (newPElement)
|
||||
{
|
||||
newPElement->SetAttribute(
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeAttr),
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeValue)
|
||||
);
|
||||
}
|
||||
brElement->SetAttribute( NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeAttr),
|
||||
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeValue) );
|
||||
|
||||
// put the node in the document
|
||||
res = mEditor->InsertNode(mBogusNode,mBody,0);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// set selection
|
||||
aSelection->Collapse(bodyNode,0);
|
||||
aSelection->Collapse(mBody,0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
kAlign = 3004,
|
||||
kMakeBasicBlock = 3005,
|
||||
kRemoveList = 3006,
|
||||
kMakeDefListItem = 3007,
|
||||
kInsertElement = 3008
|
||||
};
|
||||
|
||||
|
@ -173,6 +174,7 @@ protected:
|
|||
nsHTMLEditor *mEditor; // note that we do not refcount the editor
|
||||
nsString mPasswordText; // a buffer we use to store the real value of password editors
|
||||
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
|
||||
nsCOMPtr<nsIDOMNode> mBody; // cached root node
|
||||
PRUint32 mFlags;
|
||||
PRUint32 mActionNesting;
|
||||
PRBool mLockRulesSniffing;
|
||||
|
@ -195,7 +197,6 @@ class nsTextRulesInfo : public nsRulesInfo
|
|||
outputFormat(0),
|
||||
maxLength(-1),
|
||||
collapsedAction(nsIEditor::eNext),
|
||||
bOrdered(PR_FALSE),
|
||||
alignType(0),
|
||||
blockType(0),
|
||||
insertElement(0)
|
||||
|
|
|
@ -121,6 +121,12 @@ public:
|
|||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll)=0;
|
||||
|
||||
NS_IMETHOD GetInlinePropertyWithAttrValue(nsIAtom *aProperty,
|
||||
const nsString *aAttribute,
|
||||
const nsString *aValue,
|
||||
PRBool &aFirst, PRBool &aAny, PRBool &aAll,
|
||||
nsString *outValue)=0;
|
||||
|
||||
/**
|
||||
* RemoveAllInlineProperties() deletes all the inline properties from all
|
||||
* text in the current selection.
|
||||
|
@ -237,16 +243,6 @@ public:
|
|||
*/
|
||||
NS_IMETHOD DeleteSelectionAndCreateNode(const nsString& aTag, nsIDOMNode ** aNewNode)=0;
|
||||
|
||||
/**
|
||||
* GetListState returns what list type is in the selection.
|
||||
* @param aMixed True if there is more than one type of list, or
|
||||
* if there is some list and non-list
|
||||
* @param aOL The company that employs me. No, really, it's
|
||||
* true if an "ol" list is selected.
|
||||
* @param aUL true if an "ul" list is selected.
|
||||
*/
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)=0;
|
||||
|
||||
/* ------------ Selection manipulation -------------- */
|
||||
/* Should these be moved to nsIDOMSelection? */
|
||||
|
||||
|
@ -281,19 +277,34 @@ public:
|
|||
NS_IMETHOD SetParagraphFormat(const nsString& aParagraphFormat)=0;
|
||||
|
||||
/**
|
||||
* Get a list of tagnames of all paragraph tags
|
||||
* (the closest block parent tags) of all
|
||||
* elements in the current selection
|
||||
* Document me!
|
||||
*
|
||||
*/
|
||||
NS_IMETHOD GetParagraphTags(nsStringArray *aTagList)=0;
|
||||
NS_IMETHOD GetParagraphState(PRBool &aMixed, nsString &outFace)=0;
|
||||
|
||||
/**
|
||||
* Get a list of tagnames of all list tags
|
||||
* (the closest parent tags that are UL, OL, or DL) of all
|
||||
* elements in the current selection
|
||||
/**
|
||||
* GetFontFaceState returns what font face is in the selection.
|
||||
* @param aMixed True if there is more than one font face
|
||||
* @param outFace name of face. Note: "tt" is returned for
|
||||
* tt tag. "" is returned for none.
|
||||
*/
|
||||
NS_IMETHOD GetListTags(nsStringArray *aTagList)=0;
|
||||
NS_IMETHOD GetFontFaceState(PRBool &aMixed, nsString &outFont)=0;
|
||||
|
||||
/**
|
||||
* GetListState returns what list type is in the selection.
|
||||
* @param aMixed True if there is more than one type of list, or
|
||||
* if there is some list and non-list
|
||||
* @param aOL The company that employs me. No, really, it's
|
||||
* true if an "ol" list is selected.
|
||||
* @param aUL true if an "ul" list is selected.
|
||||
*/
|
||||
NS_IMETHOD GetListState(PRBool &aMixed, PRBool &aOL, PRBool &aUL)=0;
|
||||
|
||||
/**
|
||||
* Document me!
|
||||
*
|
||||
*/
|
||||
NS_IMETHOD GetIndentState(PRBool &aCanIndent, PRBool &aCanOutdent)=0;
|
||||
|
||||
/**
|
||||
* Document me!
|
||||
|
|
|
@ -380,6 +380,7 @@ function EditorSaveDocument(doSaveAs, doSaveCopy)
|
|||
function EditorCanClose()
|
||||
{
|
||||
// Returns FALSE only if user cancels save action
|
||||
dump("Calling EditorCanClose\n");
|
||||
return editorShell.CheckAndSaveDocument(GetString("BeforeClosing"));
|
||||
}
|
||||
|
||||
|
@ -434,65 +435,94 @@ function EditorSetTextProperty(property, attribute, value)
|
|||
gContentWindow.focus();
|
||||
}
|
||||
|
||||
function onParagraphFormatChange(commandID)
|
||||
function onParagraphFormatChange(paraMenuList, commandID)
|
||||
{
|
||||
var commandNode = document.getElementById(commmandID);
|
||||
var commandNode = document.getElementById(commandID);
|
||||
var state = commandNode.getAttribute("state");
|
||||
// dump(" ==== onParagraphFormatChange was called. state="+state+"|\n");
|
||||
|
||||
return; //TODO: REWRITE THIS
|
||||
dump("Updating font face with " + state + "\n");
|
||||
|
||||
// force match with "normal"
|
||||
if (state == "body")
|
||||
state = "";
|
||||
|
||||
if (state == "mixed")
|
||||
{
|
||||
//Selection is the "mixed" ( > 1 style) state
|
||||
paraMenuList.selectedItem = null;
|
||||
paraMenuList.setAttribute("value",GetString('MixedFormats'));
|
||||
}
|
||||
else
|
||||
{
|
||||
var menuPopup = document.getElementById("ParagraphPopup");
|
||||
var menuItems = menuPopup.childNodes;
|
||||
for (i=0; i < menuItems.length; i++)
|
||||
{
|
||||
var menuItem = menuItems.item(i);
|
||||
if (menuItem.data == state)
|
||||
{
|
||||
paraMenuList.selectedItem = menuItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function EditorSetParagraphFormat(commandID, paraFormat)
|
||||
{
|
||||
// editorShell.SetParagraphFormat(paraFormat);
|
||||
var commandNode = document.getElementById(commandID);
|
||||
dump("Saving para format state " + paraFormat + "\n");
|
||||
commandNode.setAttribute("state", paraFormat);
|
||||
window.content.focus(); // needed for command dispatch to work
|
||||
goDoCommand(commandID);
|
||||
}
|
||||
|
||||
|
||||
function onFontFaceChange()
|
||||
function onFontFaceChange(fontFaceMenuList, commandID)
|
||||
{
|
||||
return; //TODO: REWRITE THIS
|
||||
var select = document.getElementById("FontFaceSelect");
|
||||
if (select)
|
||||
{
|
||||
// Default selects "Variable Width"
|
||||
var newIndex = 0;
|
||||
var face = select.getAttribute("face");
|
||||
//dump("onFontFaceChange: face="+face+"\n");
|
||||
if ( face == "mixed")
|
||||
var commandNode = document.getElementById(commandID);
|
||||
var state = commandNode.getAttribute("state");
|
||||
|
||||
dump("Updating font face with " + state + "\n");
|
||||
|
||||
if (state == "mixed")
|
||||
{
|
||||
//Selection is the "mixed" ( > 1 style) state
|
||||
fontFaceMenuList.selectedItem = null;
|
||||
fontFaceMenuList.setAttribute("value",GetString('MixedFormats'));
|
||||
}
|
||||
else
|
||||
{
|
||||
var menuPopup = document.getElementById("FontFacePopup");
|
||||
var menuItems = menuPopup.childNodes;
|
||||
for (i=0; i < menuItems.length; i++)
|
||||
{
|
||||
// No single type selected
|
||||
newIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( var i = 0; i < gFontFaceNames.length; i++)
|
||||
var menuItem = menuItems.item(i);
|
||||
if (menuItem.getAttribute("value") && (menuItem.data.toLowerCase() == state.toLowerCase()))
|
||||
{
|
||||
if( gFontFaceNames[i] == face )
|
||||
{
|
||||
newIndex = i;
|
||||
break;
|
||||
}
|
||||
fontFaceMenuList.selectedItem = menuItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (select.selectedIndex != newIndex)
|
||||
select.selectedIndex = newIndex;
|
||||
}
|
||||
}
|
||||
|
||||
function EditorSetFontFace(fontFace)
|
||||
function EditorSetFontFace(commandID, fontFace)
|
||||
{
|
||||
if (fontFace == "tt") {
|
||||
dump("Setting font face to " + fontFace + "\n");
|
||||
var commandNode = document.getElementById(commandID);
|
||||
commandNode.setAttribute("state", fontFace);
|
||||
window.content.focus(); // needed for command dispatch to work
|
||||
goDoCommand(commandID);
|
||||
/*
|
||||
if (fontFace == "tt")
|
||||
{
|
||||
// The old "teletype" attribute
|
||||
editorShell.SetTextProperty("tt", "", "");
|
||||
// Clear existing font face
|
||||
editorShell.RemoveTextProperty("font", "face");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove any existing TT nodes
|
||||
editorShell.RemoveTextProperty("tt", "", "");
|
||||
|
||||
|
@ -502,8 +532,8 @@ function EditorSetFontFace(fontFace)
|
|||
editorShell.SetTextProperty("font", "face", fontFace);
|
||||
}
|
||||
}
|
||||
//dump("Setting focus to content window...\n");
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
*/
|
||||
}
|
||||
|
||||
function EditorSelectFontSize()
|
||||
|
@ -519,33 +549,29 @@ function EditorSelectFontSize()
|
|||
}
|
||||
}
|
||||
|
||||
function onFontSizeChange()
|
||||
function onFontSizeChange(fontSizeMenulist, commandID)
|
||||
{
|
||||
var select = document.getElementById("FontFaceSelect");
|
||||
if (select)
|
||||
{
|
||||
// If we don't match anything, set to "0 (normal)"
|
||||
var newIndex = 2;
|
||||
var size = select.getAttribute("size");
|
||||
if ( size == "mixed")
|
||||
// If we don't match anything, set to "0 (normal)"
|
||||
var newIndex = 2;
|
||||
var size = fontSizeMenulist.getAttribute("size");
|
||||
if ( size == "mixed")
|
||||
{
|
||||
// No single type selected
|
||||
newIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( var i = 0; i < gFontSizeNames.length; i++)
|
||||
{
|
||||
// No single type selected
|
||||
newIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( var i = 0; i < gFontSizeNames.length; i++)
|
||||
if( gFontSizeNames[i] == size )
|
||||
{
|
||||
if( gFontSizeNames[i] == size )
|
||||
{
|
||||
newIndex = i;
|
||||
break;
|
||||
}
|
||||
newIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (select.selectedIndex != newIndex)
|
||||
select.selectedIndex = newIndex;
|
||||
}
|
||||
if (fontSizeMenulist.selectedIndex != newIndex)
|
||||
fontSizeMenulist.selectedIndex = newIndex;
|
||||
}
|
||||
|
||||
function EditorSetFontSize(size)
|
||||
|
@ -553,7 +579,7 @@ function EditorSetFontSize(size)
|
|||
if( size == "0" || size == "normal" ||
|
||||
size == "medium" )
|
||||
{
|
||||
editorShell.RemoveTextProperty("font", size);
|
||||
editorShell.RemoveTextProperty("font", "size");
|
||||
dump("Removing font size\n");
|
||||
} else {
|
||||
dump("Setting font size\n");
|
||||
|
@ -641,7 +667,7 @@ dump("EditorSelectBackColor: "+color+"\n");
|
|||
if (menupopup) menupopup.closePopup();
|
||||
|
||||
EditorSetBackgroundColor(color);
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
function EditorRemoveBackColor(ColorWellID)
|
||||
|
@ -653,7 +679,7 @@ function EditorRemoveBackColor(ColorWellID)
|
|||
}
|
||||
//TODO: Set colorwell to browser's default color
|
||||
editorShell.SetBackgroundColor("");
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
|
||||
|
@ -668,26 +694,25 @@ function SetManualTextColor()
|
|||
function EditorSetFontColor(color)
|
||||
{
|
||||
editorShell.SetTextProperty("font", "color", color);
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
function EditorSetBackgroundColor(color)
|
||||
{
|
||||
editorShell.SetBackgroundColor(color);
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
function EditorApplyStyle(tagName)
|
||||
{
|
||||
dump("applying style\n");
|
||||
editorShell.SetTextProperty(tagName, "", "");
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
function EditorRemoveLinks()
|
||||
{
|
||||
editorShell.RemoveTextProperty("href", "");
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
|
||||
/*TODO: We need an oncreate hook to do enabling/disabling for the
|
||||
|
@ -771,8 +796,9 @@ function SetEditMode(mode)
|
|||
if (bodyNode)
|
||||
editorShell.editorSelection.collapse(bodyNode, 0);
|
||||
|
||||
gContentWindow.focus();
|
||||
setTimeout("gContentWindow.focus()", 10);
|
||||
window.content.focus();
|
||||
// yuck. what is this?
|
||||
setTimeout("window.content.focus()", 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -828,7 +854,7 @@ function SetDisplayMode(mode)
|
|||
// TODO: WE MUST ENABLE APPROPRIATE COMMANDS
|
||||
// and change UI back to "normal"
|
||||
|
||||
gContentWindow.focus();
|
||||
window.content.focus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -919,6 +945,9 @@ function EditorInitEditMenu()
|
|||
{
|
||||
var DelStr = GetString(gIsMac ? "Clear" : "Delete");
|
||||
|
||||
// Yuck. We should be doing this at build time, using
|
||||
// platform-specific overlays or dtd files.
|
||||
|
||||
// Change menu text to "Clear" for Mac
|
||||
// TODO: Should this be in globalOverlay.j?
|
||||
document.getElementById("menu_delete").setAttribute("value",DelStr);
|
||||
|
|
|
@ -182,6 +182,8 @@
|
|||
|
||||
<!-- the state attribute gets filled with the paragraph format before the command is exectued -->
|
||||
<command id="cmd_paragraphState" state="" oncommand="goDoCommand('cmd_paragraphState')"/>
|
||||
<command id="cmd_fontFace" state="" oncommand="goDoCommand('cmd_fontFace')"/>
|
||||
<command id="cmd_fontSize" state="" oncommand="goDoCommand('cmd_fontSize')"/>
|
||||
<command id="cmd_align" state="" oncommand="goDoCommand('cmd_align')"/>
|
||||
|
||||
<command id="cmd_advancedProperties" oncommand="goDoCommand('cmd_advancedProperties')"/>
|
||||
|
@ -234,7 +236,6 @@
|
|||
<command id="cmd_viewtaskbar" oncommand="goToggleToolbar('taskbar','cmd_viewtaskbar');" checked="true"/>
|
||||
|
||||
<!-- Obsolete; these will go away -->
|
||||
<command id="Editor:Font:Face" face=""/>
|
||||
<command id="Editor:Font:Size" fontsize=""/>
|
||||
</broadcasterset>
|
||||
|
||||
|
@ -430,7 +431,7 @@
|
|||
<!-- Font face submenu -->
|
||||
<menu id="fontFaceMenu" value="&fontfaceMenu.label;" accesskey="&formatfontmenu.accesskey;"
|
||||
position="1">
|
||||
<menupopup oncommand="EditorSetFontFace(event.target.data)">
|
||||
<menupopup oncommand="EditorSetFontFace('cmd_fontFace', event.target.data)">
|
||||
<menuitem value="&fontVarWidth.label;" accesskey="&fontvarwidth.accesskey;" data=""/>
|
||||
<menuitem value="&fontFixedWidth.label;" accesskey="&fontfixedwidth.accesskey;" data="tt"/>
|
||||
<menuseparator/>
|
||||
|
@ -558,7 +559,7 @@
|
|||
<menu id="headingMenu" value="&headingMenu.label;"
|
||||
accesskey="&formatheadingmenu.accesskey;"
|
||||
position="10">
|
||||
<menupopup oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.data)">
|
||||
<menupopup oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.getAttribute('data'))">
|
||||
<menuitem value="&normalCmd.label;" accesskey="&normal.accesskey;" data=""/>
|
||||
<menuitem value="&heading1Cmd.label;" accesskey="&heading1.accesskey;" data="H1"/>
|
||||
<menuitem value="&heading2Cmd.label;" accesskey="&heading2.accesskey;" data="H2"/>
|
||||
|
@ -573,7 +574,7 @@
|
|||
<menu id="paragraphMenu" value="¶graphMenu.label;"
|
||||
accesskey="&formatparagraphmenu.accesskey;"
|
||||
position="11">
|
||||
<menupopup oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.data)">
|
||||
<menupopup oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.getAttribute('data'))">
|
||||
<menuitem value="&normalCmd.label;" accesskey="&normal.accesskey;" data=""/>
|
||||
<menuitem value="¶graphParagraphCmd.label;" accesskey="¶graphparagraph.accesskey;" data="P"/>
|
||||
<menuitem value="¶graphBlockquoteCmd.label;" accesskey="¶graphblockquote.accesskey;" data="BLOCKQUOTE"/>
|
||||
|
@ -771,8 +772,8 @@
|
|||
|
||||
<!-- Formatting toolbar items. "data" are HTML tagnames, don't translate -->
|
||||
<menulist id="ParagraphSelect" tooltip="aTooltip" tooltiptext="&ParagraphSelect.tooltip;">
|
||||
<observes element="cmd_paragraphState" attribute="state" onbroadcast="onParagraphFormatChange('cmd_paragraphState')"/>
|
||||
<menupopup oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.data)">
|
||||
<observes element="cmd_paragraphState" attribute="state" onbroadcast="onParagraphFormatChange(this.parentNode, 'cmd_paragraphState')"/>
|
||||
<menupopup id="ParagraphPopup" oncommand="EditorSetParagraphFormat('cmd_paragraphState', event.target.data)">
|
||||
<menuitem value="&normalCmd.label;" data=""/>
|
||||
<menuitem value="¶graphParagraphCmd.label;" data="P"/>
|
||||
<menuitem value="&heading1Cmd.label;" data="H1"/>
|
||||
|
@ -792,8 +793,8 @@
|
|||
<!-- TODO: Use actual "face" value when combobox can display arbitrary HTML -->
|
||||
<!-- "data" are HTML tagnames, don't translate -->
|
||||
<menulist id="FontFaceSelect" tooltip="aTooltip" tooltiptext="&FontFaceSelect.tooltip;">
|
||||
<observes element="Editor:Font:Face" attribute="face" onbroadcast="onFontFaceChange()"/>
|
||||
<menupopup oncommand="EditorSetFontFace(event.target.data)">
|
||||
<observes element="cmd_fontFace" attribute="state" onbroadcast="onFontFaceChange(this.parentNode, 'cmd_fontFace')"/>
|
||||
<menupopup id="FontFacePopup" oncommand="EditorSetFontFace('cmd_fontFace', event.target.data)">
|
||||
<menuitem value="&fontVarWidth.label;" data=""/>
|
||||
<menuitem value="&fontFixedWidth.label;" data="tt"/>
|
||||
<menuseparator/>
|
||||
|
@ -804,7 +805,7 @@
|
|||
</menulist>
|
||||
|
||||
<menulist id="FontSizeSelect" oncommand="EditorSelectFontSize()" tooltip="aTooltip" tooltiptext="&FontSizeSelect.tooltip;">
|
||||
<observes element="Editor:Font:Size" attribute="fontsize" onbroadcast="onFontSizeChange()"/>
|
||||
<observes element="cmd_fontSize" attribute="state" onbroadcast="onFontSizeChange(this.parentNode, 'cmd_fontSize')"/>
|
||||
<menupopup>
|
||||
<menuitem value="&size-xx-smallCmd.label;"/>
|
||||
<menuitem value="&size-x-smallCmd.label;"/>
|
||||
|
|
|
@ -60,6 +60,8 @@ EmptyHREFError=You must enter or choose a location (URL) to create a new link.
|
|||
LinkText=Link text:
|
||||
LinkImage=Link image:
|
||||
MixedSelection=[Mixed selection]
|
||||
MixedFormats=(mixed)
|
||||
MixedFonts=(mixed)
|
||||
EnterLinkText=Enter text to display for the link:
|
||||
EmptyLinkTextError=You must enter some text for this link.
|
||||
#Don't translate: %n% %min% %max%
|
||||
|
@ -115,3 +117,4 @@ Clear=Clear
|
|||
#Mouse actions
|
||||
Click=Click
|
||||
Drag=Drag
|
||||
Unknown=Unknown
|
Загрузка…
Ссылка в новой задаче