CSS in Composer, step 1 ; b=77705, r=jfrancis, r=cmanske, sr=kin

This commit is contained in:
glazman%netscape.com 2002-01-09 13:51:37 +00:00
Родитель 738505d551
Коммит e33a80b378
51 изменённых файлов: 3955 добавлений и 177 удалений

Просмотреть файл

@ -20,7 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ryan Cassin (rcassin@supernova.org)
* Ryan Cassin <rcassin@supernova.org>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -792,6 +793,77 @@ nsFontColorStateCommand::SetState(nsIEditorShell *aEditorShell, nsString& newSta
return rv;
}
#ifdef XP_MAC
#pragma mark -
#endif
nsHighlightColorStateCommand::nsHighlightColorStateCommand()
: nsMultiStateCommand()
{
}
nsresult
nsHighlightColorStateCommand::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->GetHighlightColorState(&outMixed, outStateString);
}
nsresult
nsHighlightColorStateCommand::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;
nsCOMPtr<nsIAtom> fontAtom = getter_AddRefs(NS_NewAtom("font"));
if (!newState.Length() || newState.Equals(NS_LITERAL_STRING("normal"))) {
rv = htmlEditor->RemoveInlineProperty(fontAtom, NS_LITERAL_STRING("bgcolor"));
} else {
rv = htmlEditor->SetCSSInlineProperty(fontAtom, NS_LITERAL_STRING("bgcolor"), newState);
}
return rv;
}
NS_IMETHODIMP
nsHighlightColorStateCommand::IsCommandEnabled(const nsAReadableString & aCommandName, nsISupports *refCon, PRBool *outCmdEnabled)
{
nsCOMPtr<nsIEditorShell> editorShell = do_QueryInterface(refCon);
*outCmdEnabled = PR_FALSE;
if (editorShell && EditingHTML(editorShell))
{
nsCOMPtr<nsIEditor> editor;
editorShell->GetEditor(getter_AddRefs(editor));
PRBool useCSS;
editor->IsCSSEnabled(&useCSS);
*outCmdEnabled = useCSS;
}
nsresult rv = UpdateCommandState(aCommandName, refCon);
if (NS_FAILED(rv)) {
*outCmdEnabled = PR_FALSE;
return NS_OK;
}
return NS_OK;
}
#ifdef XP_MAC
#pragma mark -
#endif

Просмотреть файл

@ -20,7 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ryan Cassin (rcassin@supernova.org)
* Ryan Cassin <rcassin@supernova.org>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -215,6 +216,19 @@ protected:
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
};
class nsHighlightColorStateCommand : public nsMultiStateCommand
{
public:
nsHighlightColorStateCommand();
protected:
virtual nsresult GetCurrentState(nsIEditorShell *aEditorShell, nsString& outStateString, PRBool& outMixed);
virtual nsresult SetState(nsIEditorShell *aEditorShell, nsString& newState);
NS_IMETHOD IsCommandEnabled(const nsAReadableString & aCommandName, nsISupports *aCommandRefCon, PRBool *_retval);
};
class nsFontColorStateCommand : public nsMultiStateCommand
{
public:

Просмотреть файл

@ -22,6 +22,7 @@
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Ryan Cassin <rcassin@supernova.org>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -200,6 +201,7 @@ nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandMana
NS_REGISTER_ONE_COMMAND(nsFontFaceStateCommand, "cmd_fontFace");
NS_REGISTER_ONE_COMMAND(nsFontColorStateCommand, "cmd_fontColor");
NS_REGISTER_ONE_COMMAND(nsBackgroundColorStateCommand, "cmd_backgroundColor");
NS_REGISTER_ONE_COMMAND(nsHighlightColorStateCommand, "cmd_highlight");
NS_REGISTER_ONE_COMMAND(nsAlignCommand, "cmd_align");
NS_REGISTER_ONE_COMMAND(nsRemoveStylesCommand, "cmd_removeStyles");

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -4982,3 +4983,14 @@ nsEditorShell::DoControllerCommand(const nsAReadableString& aCommand)
return rv;
}
nsresult
nsEditorShell::CSSPrefChangedCallback(PRBool aIsCSSPrefChecked)
{
nsresult err = NS_NOINTERFACE;
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
if (htmlEditor)
{
err = htmlEditor->SetCSSEnabled(aIsCSSPrefChecked);
}
return err;
}

Просмотреть файл

@ -17,6 +17,7 @@
* Copyright (C) 1999, Mozilla. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*/
#include "nsISupports.idl"
@ -78,6 +79,14 @@ interface nsIEditor : nsISupports
*/
[noscript] void Init(in nsIDOMDocument doc, in nsIPresShellPtr shell, in nsIContentPtr aRoot, in nsISelectionController aSelCon, in unsigned long aFlags);
/** IsCSSEnabled answers a boolean which is true is the HTMLEditor has been
* instantiated with CSS knowledge and if the CSS pref is currently checked
*
* @param aIsSet [OUT] true if CSS handled and enabled
*/
void IsCSSEnabled(out PRBool aIsSet);
void SetCSSEquivalentToHTMLStyle(in nsIDOMElement element, in DOMString sourceAttrName, in DOMString sourceAttrValue);
/**
* PostCreate should be called after Init, and is the time that the editor tells
* its documentStateObservers that the document has been created.

Просмотреть файл

@ -514,6 +514,7 @@ interface nsIEditorShell : nsISupports
wstring GetAlignment(out boolean mixed);
void ApplyStyleSheet(in wstring url);
void CSSPrefChangedCallback(in boolean isCSSPrefChecked);
/** Set the display mode for editing
* displayMode

Просмотреть файл

@ -76,6 +76,9 @@ interface nsIHTMLEditor : nsISupports
* @param aValue if aAttribute is not null, the value of the attribute. May be null.
* Example: aProperty="font", aAttribute="color", aValue="0x00FFFF"
*/
void SetCSSInlineProperty(in nsIAtom aProperty,
in DOMString aAttribute,
in DOMString aValue);
void SetInlineProperty(in nsIAtom aProperty,
in DOMString aAttribute,
in DOMString aValue);
@ -273,6 +276,14 @@ interface nsIHTMLEditor : nsISupports
*/
void GetBackgroundColorState(out boolean aMixed,out DOMString outColor);
/**
* GetHighlightColorState returns what the highlight color of the selection.
* @param aMixed True if there is more than one font color
* @param outColor Color string. "" is returned for none.
*/
void GetHighlightColorState(out boolean aMixed,out DOMString outColor);
wstring GetHighlightColor(out boolean mixed);
/**
* GetListState returns what list type is in the selection.
* @param aMixed True if there is more than one type of list, or
@ -430,5 +441,8 @@ interface nsIHTMLEditor : nsISupports
* @return aNodeList the linked nodes found
*/
nsISupportsArray GetLinkedObjects();
void SetCSSEnabled(in boolean aIsCSSPrefChecked);
};

Просмотреть файл

@ -46,6 +46,7 @@
#include "nsIEditProperty.h"
#include "nsIParser.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
void
ChangeCSSInlineStyleTxn::AppendDeclaration(nsAWritableString & aOutputString,
@ -91,7 +92,9 @@ ChangeCSSInlineStyleTxn::ValueIncludes(const nsAReadableString &aValueList, cons
}
}
else {
if (!nsCRT::strcasecmp(value, start)) {
if (!Compare(nsDependentString(value),
nsDependentString(start),
nsCaseInsensitiveStringComparator())) {
result = PR_TRUE;
break;
}
@ -162,6 +165,8 @@ NS_IMETHODIMP ChangeCSSInlineStyleTxn::Init(nsIEditor *aEditor,
mValue.Assign(aValue);
mRemoveProperty = aRemoveProperty;
mPropertyWasSet = PR_FALSE;
mUndoAttributeWasSet = PR_FALSE;
mRedoAttributeWasSet = PR_FALSE;
mUndoValue.SetLength(0);
return NS_OK;
}
@ -174,8 +179,13 @@ NS_IMETHODIMP ChangeCSSInlineStyleTxn::DoTransaction(void)
nsresult result=NS_OK;
nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
PRUint32 length;
result = GetInlineStyles(mElement, getter_AddRefs(cssDecl), &length);
PRUint32 length = 0;
nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyles = do_QueryInterface(mElement);
if (!inlineStyles) return NS_ERROR_NULL_POINTER;
result = inlineStyles->GetStyle(getter_AddRefs(cssDecl));
if (NS_FAILED(result)) return result;
if (!cssDecl) return NS_ERROR_NULL_POINTER;
result = cssDecl->GetLength(&length);
if (NS_FAILED(result)) return result;
nsAutoString newDeclString, propertyNameString, undoString, redoString;
@ -343,21 +353,6 @@ NS_IMETHODIMP ChangeCSSInlineStyleTxn::GetTxnDescription(nsAWritableString& aStr
return NS_OK;
}
nsresult
ChangeCSSInlineStyleTxn::GetInlineStyles(nsIDOMElement *aElement,
nsIDOMCSSStyleDeclaration **aCssDecl,
PRUint32 *aLength)
{
if (!aElement || !aLength) return NS_ERROR_NULL_POINTER;
*aLength = 0;
nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyles = do_QueryInterface(aElement);
if (!inlineStyles) return NS_ERROR_NULL_POINTER;
nsresult res = inlineStyles->GetStyle(aCssDecl);
if (NS_FAILED(res) || !aCssDecl) return NS_ERROR_NULL_POINTER;
(*aCssDecl)->GetLength(aLength);
return NS_OK;
}
// answers true if the CSS property accepts more than one value
PRBool
ChangeCSSInlineStyleTxn::AcceptsMoreThanOneValue(nsIAtom *aCSSProperty)

Просмотреть файл

@ -75,15 +75,6 @@ public:
const nsAReadableString & aValue,
PRBool aRemoveProperty);
/** get the specified inline styles (style attribute) for an element
*
* @param aElement [IN] the element node
* @param aCssDecl [OUT] the CSS declaration corresponding to the style attr
* @param aLength [OUT] the number of declarations in aCssDecl
*/
static nsresult GetInlineStyles(nsIDOMElement * aElement, nsIDOMCSSStyleDeclaration ** aCssDecl,
PRUint32 * aLength);
/** returns true if the list of white-space separated values contains aValue
*
* @return true if the value is in the list of values
@ -111,8 +102,8 @@ private:
PRBool AcceptsMoreThanOneValue(nsIAtom * aCSSProperty);
/** remove a value from a list of white-space separated values
* @param aValueList [IN] a list of white-space separated values
* @param aValue [IN] the value to remove from the list
* @param aValues [IN] a list of white-space separated values
* @param aRemoveValue [IN] the value to remove from the list
*/
void RemoveValueFromListOfValues(nsAWritableString & aValues, const nsAReadableString & aRemoveValue);

Просмотреть файл

@ -44,6 +44,7 @@ REQUIRES = xpcom \
gfx \
widget \
xuldoc \
unicharutil \
webbrwsr \
$(NULL)
@ -65,6 +66,7 @@ CPPSRCS += \
EditTxn.cpp \
PlaceholderTxn.cpp \
ChangeAttributeTxn.cpp \
ChangeCSSInlineStyleTxn.cpp \
CreateElementTxn.cpp \
DeleteElementTxn.cpp \
DeleteRangeTxn.cpp \

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -54,6 +55,7 @@
#ifndef MOZILLA_PLAINTEXT_EDITOR_ONLY
#include "SetDocTitleTxn.h"
#include "ChangeCSSInlineStyleTxn.h"
#endif // MOZILLA_PLAINTEXT_EDITOR_ONLY
TransactionFactory::TransactionFactory()
@ -83,6 +85,10 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult)
*aResult = new DeleteRangeTxn();
else if (aTxnType.Equals(ChangeAttributeTxn::GetCID()))
*aResult = new ChangeAttributeTxn();
#ifndef MOZILLA_PLAINTEXT_EDITOR_ONLY
else if (aTxnType.Equals(ChangeCSSInlineStyleTxn::GetCID()))
*aResult = new ChangeCSSInlineStyleTxn();
#endif // MOZILLA_PLAINTEXT_EDITOR_ONLY
else if (aTxnType.Equals(SplitElementTxn::GetCID()))
*aResult = new SplitElementTxn();
else if (aTxnType.Equals(JoinElementTxn::GetCID()))

Просмотреть файл

@ -38,11 +38,13 @@ REQUIRES = xpcom \
appshell \
gfx \
widget \
webBrowser_core \
unicharutil \
webBrowser_core \
$(NULL)
CPP_OBJS = \
.\$(OBJDIR)\ChangeAttributeTxn.obj \
.\$(OBJDIR)\ChangeCSSInlineStyleTxn.obj \
.\$(OBJDIR)\CreateElementTxn.obj \
.\$(OBJDIR)\DeleteElementTxn.obj \
.\$(OBJDIR)\DeleteRangeTxn.obj \

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -71,6 +72,8 @@
#include "nsIPlaintextEditor.h"
#include "nsGUIEvent.h"
#include "nsIDOMCSSStyleDeclaration.h"
#include "nsIFrame.h" // Needed by IME code
#include "nsICSSStyleSheet.h"
@ -87,6 +90,7 @@
#include "EditAggregateTxn.h"
#include "PlaceholderTxn.h"
#include "ChangeAttributeTxn.h"
#include "ChangeCSSInlineStyleTxn.h"
#include "CreateElementTxn.h"
#include "InsertElementTxn.h"
#include "DeleteElementTxn.h"
@ -97,6 +101,7 @@
#include "JoinElementTxn.h"
#include "nsStyleSheetTxns.h"
#include "IMETextTxn.h"
#include "nsIEditProperty.h"
// included for nsEditor::CreateHTMLContent
#include "nsIElementFactory.h"
@ -1078,7 +1083,6 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAReadableString & aAttri
return result;
}
NS_IMETHODIMP
nsEditor::GetAttributeValue(nsIDOMElement *aElement,
const nsAReadableString & aAttribute,
@ -2173,6 +2177,8 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
if (!aDestNode || !aSourceNode)
return NS_ERROR_NULL_POINTER;
PRBool useCSS;
IsCSSEnabled(&useCSS);
nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
@ -2255,10 +2261,19 @@ nsEditor::CloneAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode)
*/
if (NS_SUCCEEDED(sourceAttribute->GetValue(sourceAttrValue)))
{
if (destInBody)
SetAttribute(destElement, sourceAttrName, sourceAttrValue);
else
if (destInBody) {
if (useCSS) {
res = SetCSSEquivalentToHTMLStyle(destElement, sourceAttrName, sourceAttrValue);
}
else {
SetAttribute(destElement, sourceAttrName, sourceAttrValue);
}
}
else {
// only elements in BODY can carry a STYLE attribute
// so there is no need to test the value of useCSS here
destElement->SetAttribute(sourceAttrName, sourceAttrValue);
}
} else {
// Do we ever get here?
#if DEBUG_cmanske
@ -5229,3 +5244,18 @@ nsEditor::CreateHTMLContent(const nsAReadableString& aTag, nsIContent** aContent
return NS_OK;
}
nsresult
nsEditor::IsCSSEnabled(PRBool *aIsSet)
{
*aIsSet = PR_FALSE;
return NS_OK;
}
nsresult
nsEditor::SetCSSEquivalentToHTMLStyle(nsIDOMElement * aElement,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue)
{
return SetAttribute(aElement, aAttribute, aValue);
}

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -136,6 +137,7 @@ public:
/* ------------ utility methods -------------- */
NS_IMETHOD GetPresShell(nsIPresShell **aPS);
void NotifyEditorObservers(void);
/* ------------ nsIEditor methods -------------- */
NS_DECL_NSIEDITOR
/* ------------ nsIEditorIMESupport methods -------------- */
@ -501,7 +503,7 @@ public:
/** from html rules code - migration in progress */
static nsresult GetTagString(nsIDOMNode *aNode, nsAWritableString& outString);
static nsCOMPtr<nsIAtom> GetTag(nsIDOMNode *aNode);
static PRBool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
virtual PRBool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
static PRBool IsTextOrElementNode(nsIDOMNode *aNode);
static PRBool IsTextNode(nsIDOMNode *aNode);

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -144,9 +145,37 @@ public:
// XXX: end temp code
/** CSS strings */
static nsIAtom *cssBackgroundColor;
static nsIAtom *cssBackgroundImage;
static nsIAtom *cssBorder;
static nsIAtom *cssCaptionSide;
static nsIAtom *cssColor;
static nsIAtom *cssFloat;
static nsIAtom *cssFontFamily;
static nsIAtom *cssFontSize;
static nsIAtom *cssFontStyle;
static nsIAtom *cssFontWeight;
static nsIAtom *cssHeight;
static nsIAtom *cssListStyleType;
static nsIAtom *cssMarginLeft;
static nsIAtom *cssMarginRight;
static nsIAtom *cssTextAlign;
static nsIAtom *cssTextDecoration;
static nsIAtom *cssVerticalAlign;
static nsIAtom *cssWhitespace;
static nsIAtom *cssWidth;
static nsIAtom *cssPxUnit;
static nsIAtom *cssEmUnit;
static nsIAtom *cssCmUnit;
static nsIAtom *cssPercentUnit;
static nsIAtom *cssInUnit;
static nsIAtom *cssMmUnit;
static nsIAtom *cssPtUnit;
static nsIAtom *cssPcUnit;
static nsIAtom *cssExUnit;
};
extern nsresult NS_NewEditProperty(nsIEditProperty **aResult);

Просмотреть файл

@ -34,7 +34,7 @@ REQUIRES = xpcom \
dom \
layout \
locale \
unicharutil \
unicharutil \
content \
txmgr \
htmlparser \
@ -50,11 +50,12 @@ REQUIRES = xpcom \
CPPSRCS = \
nsEditProperty.cpp \
nsHTMLDataTransfer.cpp \
nsHTMLCSSUtils.cpp \
nsHTMLEditor.cpp \
nsHTMLEditorStyle.cpp \
nsHTMLEditRules.cpp \
nsHTMLEditUtils.cpp \
nsHTMLURIRefObject.cpp \
nsHTMLURIRefObject.cpp \
nsTableEditor.cpp \
nsWSRunObject.cpp \
TypeInState.cpp \

Просмотреть файл

@ -36,12 +36,14 @@ REQUIRES = xpcom \
pref \
gfx \
widget \
unicharutil \
webBrowser_core \
$(NULL)
CPP_OBJS = \
.\$(OBJDIR)\TypeInState.obj \
.\$(OBJDIR)\nsEditProperty.obj \
.\$(OBJDIR)\nsHTMLCSSUtils.obj \
.\$(OBJDIR)\nsHTMLDataTransfer.obj \
.\$(OBJDIR)\nsHTMLEditRules.obj \
.\$(OBJDIR)\nsHTMLEditUtils.obj \

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -122,6 +123,37 @@ nsIAtom * nsIEditProperty::color;
nsIAtom * nsIEditProperty::face;
nsIAtom * nsIEditProperty::size;
nsIAtom * nsIEditProperty::cssBackgroundColor;
nsIAtom * nsIEditProperty::cssBackgroundImage;
nsIAtom * nsIEditProperty::cssBorder;
nsIAtom * nsIEditProperty::cssCaptionSide;
nsIAtom * nsIEditProperty::cssColor;
nsIAtom * nsIEditProperty::cssFloat;
nsIAtom * nsIEditProperty::cssFontFamily;
nsIAtom * nsIEditProperty::cssFontSize;
nsIAtom * nsIEditProperty::cssFontStyle;
nsIAtom * nsIEditProperty::cssFontWeight;
nsIAtom * nsIEditProperty::cssHeight;
nsIAtom * nsIEditProperty::cssListStyleType;
nsIAtom * nsIEditProperty::cssMarginLeft;
nsIAtom * nsIEditProperty::cssMarginRight;
nsIAtom * nsIEditProperty::cssTextAlign;
nsIAtom * nsIEditProperty::cssTextDecoration;
nsIAtom * nsIEditProperty::cssVerticalAlign;
nsIAtom * nsIEditProperty::cssWhitespace;
nsIAtom * nsIEditProperty::cssWidth;
nsIAtom * nsIEditProperty::cssPxUnit;
nsIAtom * nsIEditProperty::cssEmUnit;
nsIAtom * nsIEditProperty::cssCmUnit;
nsIAtom * nsIEditProperty::cssPercentUnit;
nsIAtom * nsIEditProperty::cssInUnit;
nsIAtom * nsIEditProperty::cssMmUnit;
nsIAtom * nsIEditProperty::cssPtUnit;
nsIAtom * nsIEditProperty::cssPcUnit;
nsIAtom * nsIEditProperty::cssExUnit;
// special
nsString * nsIEditProperty::allProperties;
@ -227,6 +259,36 @@ nsEditProperty::nsEditProperty()
nsIEditProperty::face = NS_NewAtom("face");
nsIEditProperty::size = NS_NewAtom("size");
nsIEditProperty::cssBackgroundColor = NS_NewAtom("background-color");
nsIEditProperty::cssBackgroundImage = NS_NewAtom("background-image");
nsIEditProperty::cssBorder = NS_NewAtom("border");
nsIEditProperty::cssCaptionSide = NS_NewAtom("caption-side");
nsIEditProperty::cssColor = NS_NewAtom("color");
nsIEditProperty::cssFloat = NS_NewAtom("float");
nsIEditProperty::cssFontFamily = NS_NewAtom("font-family");
nsIEditProperty::cssFontSize = NS_NewAtom("font-size");
nsIEditProperty::cssFontStyle = NS_NewAtom("font-style");
nsIEditProperty::cssFontWeight = NS_NewAtom("font-weight");
nsIEditProperty::cssHeight = NS_NewAtom("height");
nsIEditProperty::cssListStyleType = NS_NewAtom("list-style-type");
nsIEditProperty::cssMarginRight = NS_NewAtom("margin-right");
nsIEditProperty::cssMarginLeft = NS_NewAtom("margin-left");
nsIEditProperty::cssTextAlign = NS_NewAtom("text-align");
nsIEditProperty::cssTextDecoration = NS_NewAtom("text-decoration");
nsIEditProperty::cssVerticalAlign = NS_NewAtom("vertical-align");
nsIEditProperty::cssWhitespace = NS_NewAtom("white-space");
nsIEditProperty::cssWidth = NS_NewAtom("width");
nsIEditProperty::cssPxUnit = NS_NewAtom("px");
nsIEditProperty::cssEmUnit = NS_NewAtom("em");
nsIEditProperty::cssCmUnit = NS_NewAtom("cm");
nsIEditProperty::cssPercentUnit = NS_NewAtom("%");
nsIEditProperty::cssInUnit = NS_NewAtom("in");
nsIEditProperty::cssMmUnit = NS_NewAtom("mm");
nsIEditProperty::cssPtUnit = NS_NewAtom("pt");
nsIEditProperty::cssPcUnit = NS_NewAtom("pc");
nsIEditProperty::cssExUnit = NS_NewAtom("ex");
// special
if ( (nsIEditProperty::allProperties = new nsString) != nsnull )
@ -307,6 +369,36 @@ nsEditProperty::~nsEditProperty()
NS_IF_RELEASE(nsIEditProperty::face);
NS_IF_RELEASE(nsIEditProperty::size);
NS_IF_RELEASE(nsIEditProperty::cssBackgroundColor);
NS_IF_RELEASE(nsIEditProperty::cssBackgroundImage);
NS_IF_RELEASE(nsIEditProperty::cssBorder);
NS_IF_RELEASE(nsIEditProperty::cssCaptionSide);
NS_IF_RELEASE(nsIEditProperty::cssColor);
NS_IF_RELEASE(nsIEditProperty::cssFloat);
NS_IF_RELEASE(nsIEditProperty::cssFontFamily);
NS_IF_RELEASE(nsIEditProperty::cssFontSize);
NS_IF_RELEASE(nsIEditProperty::cssFontStyle);
NS_IF_RELEASE(nsIEditProperty::cssFontWeight);
NS_IF_RELEASE(nsIEditProperty::cssHeight);
NS_IF_RELEASE(nsIEditProperty::cssListStyleType);
NS_IF_RELEASE(nsIEditProperty::cssMarginRight);
NS_IF_RELEASE(nsIEditProperty::cssMarginLeft);
NS_IF_RELEASE(nsIEditProperty::cssTextAlign);
NS_IF_RELEASE(nsIEditProperty::cssTextDecoration);
NS_IF_RELEASE(nsIEditProperty::cssVerticalAlign);
NS_IF_RELEASE(nsIEditProperty::cssWhitespace);
NS_IF_RELEASE(nsIEditProperty::cssWidth);
NS_IF_RELEASE(nsIEditProperty::cssPxUnit);
NS_IF_RELEASE(nsIEditProperty::cssEmUnit);
NS_IF_RELEASE(nsIEditProperty::cssCmUnit);
NS_IF_RELEASE(nsIEditProperty::cssPercentUnit);
NS_IF_RELEASE(nsIEditProperty::cssInUnit);
NS_IF_RELEASE(nsIEditProperty::cssMmUnit);
NS_IF_RELEASE(nsIEditProperty::cssPtUnit);
NS_IF_RELEASE(nsIEditProperty::cssPcUnit);
NS_IF_RELEASE(nsIEditProperty::cssExUnit);
// special
if (nsIEditProperty::allProperties) {
delete (nsIEditProperty::allProperties);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,389 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Original Author: Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsHTMLCSSUtils_h__
#define nsHTMLCSSUtils_h__
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIDOMViewCSS.h"
#include "nsIDOMNode.h"
#include "nsIDOMElement.h"
#include "nsIHTMLEditor.h"
#include "ChangeCSSInlineStyleTxn.h"
#include "nsIEditProperty.h"
#include "nsIDOMCSSStyleDeclaration.h"
#define SPECIFIED_STYLE_TYPE 1
#define COMPUTED_STYLE_TYPE 2
class nsHTMLEditor;
typedef void (*nsProcessValueFunc)(nsAReadableString * aInputString, nsAWritableString & aOutputString,
const char * aDefaultValueString,
const char * aPrependString, const char* aAppendString);
class nsHTMLCSSUtils
{
public:
nsHTMLCSSUtils();
~nsHTMLCSSUtils();
enum nsCSSEditableProperty {
eCSSEditableProperty_NONE=0,
eCSSEditableProperty_background_color,
eCSSEditableProperty_background_image,
eCSSEditableProperty_border,
eCSSEditableProperty_caption_side,
eCSSEditableProperty_color,
eCSSEditableProperty_float,
eCSSEditableProperty_font_family,
eCSSEditableProperty_font_size,
eCSSEditableProperty_font_style,
eCSSEditableProperty_font_weight,
eCSSEditableProperty_height,
eCSSEditableProperty_list_style_type,
eCSSEditableProperty_margin_left,
eCSSEditableProperty_margin_right,
eCSSEditableProperty_text_align,
eCSSEditableProperty_text_decoration,
eCSSEditableProperty_vertical_align,
eCSSEditableProperty_whitespace,
eCSSEditableProperty_width
};
struct CSSEquivTable {
nsCSSEditableProperty cssProperty;
nsProcessValueFunc processValueFunctor;
const char * defaultValue;
const char * prependValue;
const char * appendValue;
PRBool gettable;
};
public:
nsresult Init(nsHTMLEditor * aEditor);
/** answers true if the given combination element_name/attribute_name
* has a CSS equivalence in this implementation
*
* @return a boolean saying if the tag/attribute has a css equiv
* @param aNode [IN] a DOM node
* @param aProperty [IN] an atom containing a HTML tag name
* @param aAttribute [IN] a string containing the name of a HTML attribute carried by the element above
*/
PRBool IsCSSEditableProperty(nsIDOMNode * aNode, nsIAtom * aProperty, const nsAReadableString * aAttribute);
/** adds/remove a CSS declaration to the STYLE atrribute carried by a given element
*
* @param aElement [IN] a DOM element
* @param aProperty [IN] an atom containing the CSS property to set
* @param aValue [IN] a string containing the value of the CSS property
*/
nsresult SetCSSProperty(nsIDOMElement * aElement, nsIAtom * aProperty,
const nsAReadableString & aValue);
nsresult RemoveCSSProperty(nsIDOMElement * aElement, nsIAtom * aProperty,
const nsAReadableString & aPropertyValue);
/** gets the specified/computed style value of a CSS property for a given node (or its element
* ancestor if it is not an element)
*
* @param aNode [IN] a DOM node
* @param aProperty [IN] an atom containing the CSS property to get
* @param aPropertyValue [OUT] the retrieved value of the property
*/
nsresult GetSpecifiedProperty(nsIDOMNode *aNode, nsIAtom *aProperty,
nsAWritableString & aValue);
nsresult GetComputedProperty(nsIDOMNode *aNode, nsIAtom *aProperty,
nsAWritableString & aValue);
/** Removes a CSS property from the specified declarations in STYLE attribute
** and removes the node if it is an useless span
*
* @param aNode [IN] the specific node we want to remove a style from
* @param aProperty [IN] the CSS property atom to remove
* @param aPropertyValue [IN] the value of the property we have to rremove if the property
* accepts more than one value
*/
nsresult RemoveCSSInlineStyle(nsIDOMNode * aNode, nsIAtom * aProperty, nsAReadableString & aPropertyValue);
/** Answers true is the property can be removed by setting a "none" CSS value
* on a node
*
* @return a boolean saying if the property can be remove by setting a "none" value
* @param aProperty [IN] an atom containing a CSS property
* @param aAttribute [IN] pointer to an attribute name or null if this information is irrelevant
*/
PRBool IsCSSInvertable(nsIAtom * aProperty, const nsAReadableString * aAttribute);
/** Get the default browser background color if we need it for GetCSSBackgroundColorState
*
* @param aColor [OUT] the default color as it is defined in prefs
*/
nsresult GetDefaultBackgroundColor(nsAWritableString & aColor);
/** Get the default length unit used for CSS Indent/Outdent
*
* @param aLengthUnit [OUT] the default length unit as it is defined in prefs
*/
nsresult GetDefaultLengthUnit(nsAWritableString & aLengthUnit);
/** asnwers true if the element aElement carries an ID or a class
*
* @param aElement [IN] a DOM element
* @param aReturn [OUT] the boolean answer
*/
nsresult HasClassOrID(nsIDOMElement * aElement, PRBool & aReturn);
/** returns the list of values for the CSS equivalences to
* the passed HTML style for the passed node
*
* @param aNode [IN] a DOM node
* @param aHTMLProperty [IN] an atom containing an HTML property
* @param aAttribute [IN] a pointer to an attribute name or nsnull if irrelevant
* @param aValueString [OUT] the list of css values
* @param aStyleType [IN] SPECIFIED_STYLE_TYPE to query the specified style values
COMPUTED_STYLE_TYPE to query the computed style values
*/
nsresult GetCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode * aNode,
nsIAtom * aHTMLProperty,
const nsAReadableString * aAttribute,
nsAWritableString & aValueString,
PRUint8 aStyleType);
/** Does the node aNode (or his parent if it is not an element node) carries
* the CSS equivalent styles to the HTML style for this node ?
*
* @param aNode [IN] a DOM node
* @param aHTMLProperty [IN] an atom containing an HTML property
* @param aAttribute [IN] a pointer to an attribute name or nsnull if irrelevant
* @param aIsSet [OUT] a boolean being true if the css properties are set
* @param aValueString [IN/OUT] the attribute value (in) the list of css values (out)
* @param aStyleType [IN] SPECIFIED_STYLE_TYPE to query the specified style values
COMPUTED_STYLE_TYPE to query the computed style values
*/
nsresult IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode * aNode,
nsIAtom * aHTMLProperty,
const nsAReadableString * aAttribute,
PRBool & aIsSet,
nsAWritableString & aValueString,
PRUint8 aStyleType);
/** Adds to the node the CSS inline styles equivalent to the HTML style
* and return the number of CSS properties set by the call
*
* @param aNode [IN] a DOM node
* @param aHTMLProperty [IN] an atom containing an HTML property
* @param aAttribute [IN] a pointer to an attribute name or nsnull if irrelevant
* @param aValue [IN] the attribute value
* @param aCount [OUT] the number of CSS properties set by the call
*/
nsresult SetCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
nsIAtom * aHTMLProperty,
const nsAReadableString * aAttribute,
const nsAReadableString * aValue,
PRInt32 * aCount);
/** removes from the node the CSS inline styles equivalent to the HTML style
*
* @param aNode [IN] a DOM node
* @param aHTMLProperty [IN] an atom containing an HTML property
* @param aAttribute [IN] a pointer to an attribute name or nsnull if irrelevant
* @param aValue [IN] the attribute value
*/
nsresult RemoveCSSEquivalentToHTMLStyle(nsIDOMNode * aNode,
nsIAtom *aHTMLProperty,
const nsAReadableString *aAttribute,
const nsAReadableString *aValue);
/** parses a "xxxx.xxxxxuuu" string where x is a digit and u an alpha char
* we need such a parser because nsIDOMCSSStyleDeclaration::GetPropertyCSSValue() is not
* implemented
*
* @param aString [IN] input string to parse
* @param aValue [OUT] numeric part
* @param aUnit [OUT] unit part
*/
void ParseLength(nsAReadableString & aString, float * aValue, nsIAtom ** aUnit);
/** sets the mIsCSSPrefChecked private member ; used as callback from observer when
* the css pref state is changed
*
* @param aIsCSSPrefChecked [IN] the new boolean state for the pref
*/
nsresult SetCSSEnabled(PRBool aIsCSSPrefChecked);
/** retrieves the mIsCSSPrefChecked private member, true if the css pref is checked,
* false if it is not
*
* @return the boolean value of the css pref
*/
PRBool IsCSSPrefChecked();
/** ElementsSameStyle compares two elements and checks if they have the same
* specified CSS declarations in the STYLE attribute
* The answer is always false if at least one of them carries an ID or a class
*
* @return true if the two elements are considered to have same styles
* @param aFirstNode [IN] a DOM node
* @param aSecondNode [IN] a DOM node
*/
PRBool ElementsSameStyle(nsIDOMNode *aFirstNode, nsIDOMNode *aSecondNode);
/** get the specified inline styles (style attribute) for an element
*
* @param aElement [IN] the element node
* @param aCssDecl [OUT] the CSS declaration corresponding to the style attr
* @param aLength [OUT] the number of declarations in aCssDecl
*/
nsresult GetInlineStyles(nsIDOMElement * aElement, nsIDOMCSSStyleDeclaration ** aCssDecl,
PRUint32 * aLength);
/** returns aNode itself if it is an element node, or the first ancestors being an element
* node if aNode is not one itself
*
* @param aNode [IN] a node
* @param aElement [OUT] the deepest element node containing aNode (possibly aNode itself)
*/
nsresult GetElementContainerOrSelf(nsIDOMNode * aNode, nsIDOMElement ** aElement);
private:
/** retrieves the css property atom from an enum
*
* @param aProperty [IN] the enum value for the property
* @param aAtom [OUT] the corresponding atom
*/
void GetCSSPropertyAtom(nsCSSEditableProperty aProperty, nsIAtom ** aAtom);
/** retrieves the CSS declarations equivalent to a HTML style value for
* a given equivalence table
*
* @param aPropertyArray [OUT] the array of css properties
* @param aValueArray [OUT] the array of values for the css properties above
* @param aEquivTable [IN] the equivalence table
* @param aValue [IN] the HTML style value
* @param aGetOrRemoveRequest [IN] a boolean value being true if the call to the current method
* is made for GetCSSEquivalentToHTMLInlineStyleSet or
* RemoveCSSEquivalentToHTMLInlineStyleSet
*/
void BuildCSSDeclarations(nsVoidArray & aPropertyArray,
nsStringArray & cssValueArray,
const CSSEquivTable * aEquivTable,
const nsAReadableString * aValue,
PRBool aGetOrRemoveRequest);
/** retrieves the CSS declarations equivalent to the given HTML property/attribute/value
* for a given node
*
* @param aNode [IN] the DOM node
* @param aHTMLProperty [IN] an atom containing an HTML property
* @param aAttribute [IN] a pointer to an attribute name or nsnull if irrelevant
* @param aValue [IN] the attribute value
* @param aPropertyArray [OUT] the array of css properties
* @param aValueArray [OUT] the array of values for the css properties above
* @param aGetOrRemoveRequest [IN] a boolean value being true if the call to the current method
* is made for GetCSSEquivalentToHTMLInlineStyleSet or
* RemoveCSSEquivalentToHTMLInlineStyleSet
*/
void GenerateCSSDeclarationsFromHTMLStyle(nsIDOMNode * aNode,
nsIAtom * aHTMLProperty,
const nsAReadableString *aAttribute,
const nsAReadableString *aValue,
nsVoidArray & aPropertyArray,
nsStringArray & aValueArray,
PRBool aGetOrRemoveRequest);
/** Gets the default DOMView for a given node
*
* @param aNode the node we want the default DOMView for
* @param aViewCSS [OUT] the default DOMViewCSS
*/
nsresult GetDefaultViewCSS(nsIDOMNode * aNode, nsIDOMViewCSS ** aViewCSS);
/** creates a Transaction for setting or removing a css property
*
* @param aElement [IN] a DOM element
* @param aProperty [IN] a CSS property
* @param aValue [IN] the value to remove for this CSS property or the empty string if irrelevant
* @param aTxn [OUT] the created transaction
* @param aRemoveProperty [IN] true if we create a "remove" transaction, false for a "set"
*/
nsresult CreateCSSPropertyTxn(nsIDOMElement * aElement,
nsIAtom * aProperty,
const nsAReadableString & aValue,
ChangeCSSInlineStyleTxn ** aTxn,
PRBool aRemoveProperty);
/** back-end for GetSpecifiedProperty and GetComputedProperty
*
* @param aNode [IN] a DOM node
* @param aProperty [IN] a CSS property
* @param aValue [OUT] the retrieved value for this property
* @param aViewCSS [IN] the ViewCSS we need in case we query computed styles
* @param aStyleType [IN] SPECIFIED_STYLE_TYPE to query the specified style values
COMPUTED_STYLE_TYPE to query the computed style values
*/
nsresult GetCSSInlinePropertyBase(nsIDOMNode * aNode, nsIAtom * aProperty,
nsAWritableString & aValue,
nsIDOMViewCSS * aViewCSS,
PRUint8 aStyleType);
private:
nsHTMLEditor *mHTMLEditor;
PRBool mIsCSSPrefChecked;
};
nsresult NS_NewHTMLCSSUtils(nsHTMLCSSUtils** aInstancePtrResult);
#define NS_EDITOR_INDENT_INCREMENT_IN 0.4134f
#define NS_EDITOR_INDENT_INCREMENT_CM 1.05f
#define NS_EDITOR_INDENT_INCREMENT_MM 10.5f
#define NS_EDITOR_INDENT_INCREMENT_PT 29.76f
#define NS_EDITOR_INDENT_INCREMENT_PC 2.48f
#define NS_EDITOR_INDENT_INCREMENT_EM 3
#define NS_EDITOR_INDENT_INCREMENT_EX 6
#define NS_EDITOR_INDENT_INCREMENT_PX 40
#define NS_EDITOR_INDENT_INCREMENT_PERCENT 4
#endif /* nsHTMLCSSUtils_h__ */

Просмотреть файл

@ -70,6 +70,7 @@
#include "nsIPresShell.h"
#include "nsLayoutCID.h"
#include "nsIPref.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsEditorUtils.h"
#include "nsWSRunObject.h"
@ -716,6 +717,45 @@ nsHTMLEditRules::GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign)
if (!nodeToExamine) return NS_ERROR_NULL_POINTER;
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
nsAutoString typeAttrName(NS_LITERAL_STRING("align"));
nsIAtom *dummyProperty = nsnull;
if (useCSS && mHTMLEditor->mHTMLCSSUtils->IsCSSEditableProperty(nodeToExamine, dummyProperty, &typeAttrName))
{
// we are in CSS mode and we know how to align this element with CSS
nsAutoString value;
// let's get the value(s) of text-align or margin-left/margin-right
mHTMLEditor->mHTMLCSSUtils->GetCSSEquivalentToHTMLInlineStyleSet(nodeToExamine,
dummyProperty,
&typeAttrName,
value,
COMPUTED_STYLE_TYPE);
if (value.Equals(NS_LITERAL_STRING("center")) ||
value.Equals(NS_LITERAL_STRING("-moz-center")) ||
value.Equals(NS_LITERAL_STRING("auto auto")))
{
*aAlign = nsIHTMLEditor::eCenter;
return NS_OK;
}
else if (value.Equals(NS_LITERAL_STRING("right")) ||
value.Equals(NS_LITERAL_STRING("-moz-right")) ||
value.Equals(NS_LITERAL_STRING("auto 0px")))
{
*aAlign = nsIHTMLEditor::eRight;
return NS_OK;
}
else if (value.Equals(NS_LITERAL_STRING("justify")))
{
*aAlign = nsIHTMLEditor::eJustify;
return NS_OK;
}
else {
*aAlign = nsIHTMLEditor::eLeft;
return NS_OK;
}
}
// check up the ladder for divs with alignment
nsCOMPtr<nsIDOMNode> temp = nodeToExamine;
PRBool isFirstNodeToExamine = PR_TRUE;
@ -734,7 +774,6 @@ nsHTMLEditRules::GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign)
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(nodeToExamine);
if (elem)
{
nsAutoString typeAttrName(NS_LITERAL_STRING("align"));
nsAutoString typeAttrVal;
res = elem->GetAttribute(typeAttrName, typeAttrVal);
ToLowerCase(typeAttrVal);
@ -787,6 +826,8 @@ nsHTMLEditRules::GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent)
PRUint32 listCount;
PRInt32 i;
arrayOfNodes->Count(&listCount);
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
for (i=(PRInt32)listCount-1; i>=0; i--)
{
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
@ -799,6 +840,22 @@ nsHTMLEditRules::GetIndentState(PRBool *aCanIndent, PRBool *aCanOutdent)
*aCanOutdent = PR_TRUE;
break;
}
else if (useCSS) {
// we are in CSS mode, indentation is done using the margin-left property
nsAutoString value;
// retrieve its specified value
mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, nsIEditProperty::cssMarginLeft, value);
float f;
nsIAtom * unit;
// get its number part and its unit
mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, &unit);
NS_IF_RELEASE(unit);
// if the number part is strictly positive, outdent is possible
if (0 < f) {
*aCanOutdent = PR_TRUE;
break;
}
}
}
if (!*aCanOutdent)
@ -1043,6 +1100,8 @@ nsHTMLEditRules::WillInsertText(PRInt32 aAction,
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
if (inString->IsEmpty() && (aAction != kInsertTextIME))
{
// HACK: this is a fix for bug 19395
@ -1537,6 +1596,7 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
}
// block parents the same?
if (mHTMLEditor->HasSameBlockNodeParent(startNode, priorNode))
{
// is prior node a text node?
@ -2342,6 +2402,7 @@ nsHTMLEditRules::DeleteNonTableElements(nsIDOMNode *aNode)
children->Item(j,getter_AddRefs(node));
res = DeleteNonTableElements(node);
if (NS_FAILED(res)) return res;
}
}
}
@ -2887,6 +2948,22 @@ nsHTMLEditRules::DidMakeBasicBlock(nsISelection *aSelection,
nsresult
nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
{
PRBool useCSS;
nsresult res;
mHTMLEditor->IsCSSEnabled(&useCSS);
if (useCSS) {
res = WillCSSIndent(aSelection, aCancel, aHandled);
}
else {
res = WillHTMLIndent(aSelection, aCancel, aHandled);
}
return res;
}
nsresult
nsHTMLEditRules::WillCSSIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
@ -2940,6 +3017,151 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *
if (NS_FAILED(res)) return res;
}
// if nothing visible in list, make an empty block
if (ListIsEmptyLine(arrayOfNodes))
{
nsCOMPtr<nsIDOMNode> parent, theBlock;
PRInt32 offset;
nsAutoString quoteType(NS_LITERAL_STRING("div"));
// get selection location
res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(parent), &offset);
if (NS_FAILED(res)) return res;
// make sure we can put a block here
res = SplitAsNeeded(&quoteType, address_of(parent), &offset);
if (NS_FAILED(res)) return res;
res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock));
if (NS_FAILED(res)) return res;
// remember our new block for postprocessing
mNewBlock = theBlock;
RelativeChangeIndentation(theBlock, +1);
// delete anything that was in the list of nodes
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
nsCOMPtr<nsIDOMNode> curNode;
while (isupports)
{
curNode = do_QueryInterface(isupports);
res = mHTMLEditor->DeleteNode(curNode);
if (NS_FAILED(res)) return res;
res = arrayOfNodes->RemoveElementAt(0);
if (NS_FAILED(res)) return res;
isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
}
// put selection in new block
res = aSelection->Collapse(theBlock,0);
selectionResetter.Abort(); // to prevent selection reseter from overriding us.
*aHandled = PR_TRUE;
return res;
}
// Next we detect all the transitions in the array, where a transition
// means that adjacent nodes in the array don't have the same parent.
nsVoidArray transitionList;
res = MakeTransitionList(arrayOfNodes, &transitionList);
if (NS_FAILED(res)) return res;
// Ok, now go through all the nodes and put them in a blockquote,
// or whatever is appropriate. Wohoo!
PRInt32 i;
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curQuote;
nsCOMPtr<nsIDOMNode> curList;
PRUint32 listCount;
arrayOfNodes->Count(&listCount);
for (i=0; i<(PRInt32)listCount; i++)
{
// here's where we actually figure out what to do
nsCOMPtr<nsISupports> isupports = dont_AddRef(arrayOfNodes->ElementAt(i));
nsCOMPtr<nsIDOMNode> curNode( do_QueryInterface(isupports ) );
PRInt32 offset;
res = nsEditor::GetNodeLocation(curNode, address_of(curParent), &offset);
if (NS_FAILED(res)) return res;
// some logic for putting list items into nested lists...
if (nsHTMLEditUtils::IsList(curParent))
{
if (!curList || transitionList[i])
{
nsAutoString listTag;
nsEditor::GetTagString(curParent,listTag);
ToLowerCase(listTag);
// create a new nested list of correct type
res = SplitAsNeeded(&listTag, address_of(curParent), &offset);
if (NS_FAILED(res)) return res;
res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
if (NS_FAILED(res)) return res;
// curList is now the correct thing to put curNode in
// remember our new block for postprocessing
mNewBlock = curList;
}
// tuck the node into the end of the active list
PRUint32 listLen;
res = mHTMLEditor->GetLengthOfDOMNode(curList, listLen);
if (NS_FAILED(res)) return res;
res = mHTMLEditor->MoveNode(curNode, curList, listLen);
if (NS_FAILED(res)) return res;
}
else // not a list item
{
if (IsBlockNode(curNode)) {
RelativeChangeIndentation(curNode, +1);
curQuote = nsnull;
}
else {
if (!curQuote) // || transitionList[i])
{
nsAutoString quoteType; quoteType.Assign(NS_LITERAL_STRING("div"));
res = SplitAsNeeded(&quoteType, address_of(curParent), &offset);
if (NS_FAILED(res)) return res;
res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
if (NS_FAILED(res)) return res;
RelativeChangeIndentation(curQuote, +1);
// remember our new block for postprocessing
mNewBlock = curQuote;
// curQuote is now the correct thing to put curNode in
}
// tuck the node into the end of the active blockquote
PRUint32 quoteLen;
res = mHTMLEditor->GetLengthOfDOMNode(curQuote, quoteLen);
if (NS_FAILED(res)) return res;
res = mHTMLEditor->MoveNode(curNode, curQuote, quoteLen);
if (NS_FAILED(res)) return res;
}
}
}
return res;
}
nsresult
nsHTMLEditRules::WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * aHandled)
{
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
nsresult res = WillInsert(aSelection, aCancel);
if (NS_FAILED(res)) return res;
// initialize out param
// we want to ignore result of WillInsert()
*aCancel = PR_FALSE;
*aHandled = PR_TRUE;
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
// convert the selection ranges into "promoted" selection ranges:
// this basically just expands the range to include the immediate
// block parent, and then further expands to include any ancestors
// whose children are all in the range
nsCOMPtr<nsISupportsArray> arrayOfRanges;
res = GetPromotedRanges(aSelection, address_of(arrayOfRanges), kIndent);
if (NS_FAILED(res)) return res;
// use these ranges to contruct a list of nodes to act on.
nsCOMPtr<nsISupportsArray> arrayOfNodes;
res = GetNodesForOperation(arrayOfRanges, address_of(arrayOfNodes), kIndent);
if (NS_FAILED(res)) return res;
// if nothing visible in list, make an empty block
if (ListIsEmptyLine(arrayOfNodes))
{
@ -3097,7 +3319,9 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
*aHandled = PR_TRUE;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> rememberedLeftBQ, rememberedRightBQ;
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
// some scoping for selection resetting - we may need to tweak it
{
nsAutoSelectionReset selectionResetter(aSelection, mHTMLEditor);
@ -3246,6 +3470,9 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
res = mHTMLEditor->RemoveBlockContainer(curNode);
if (NS_FAILED(res)) return res;
}
else if (useCSS) {
RelativeChangeIndentation(curNode, -1);
}
}
}
if (curBlockQuote)
@ -3599,11 +3826,11 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
{
// the node is a table element, an horiz rule, a paragraph, a div
// or a section header; in HTML 4, it can directly carry the ALIGN
// attribute and we don't need to make a div!
// attribute and we don't need to make a div! If we are in CSS mode,
// all the work is done in AlignBlock
nsCOMPtr<nsIDOMElement> theElem = do_QueryInterface(theNode);
res = mHTMLEditor->SetAttribute(theElem, NS_LITERAL_STRING("align"), *alignType);
res = AlignBlock(theElem, alignType, PR_TRUE);
if (NS_FAILED(res)) return res;
RemoveAlignmentInside(theNode);
return NS_OK;
}
@ -3660,9 +3887,9 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
if (NS_FAILED(res)) return res;
// remember our new block for postprocessing
mNewBlock = theDiv;
// set up the alignment on the div
// set up the alignment on the div, using HTML or CSS
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(theDiv);
res = mHTMLEditor->SetAttribute(divElem, NS_LITERAL_STRING("align"), *alignType);
res = AlignBlock(divElem, alignType, PR_TRUE);
if (NS_FAILED(res)) return res;
*aHandled = PR_TRUE;
// put in a moz-br so that it won't get deleted
@ -3686,6 +3913,8 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
PRInt32 i;
nsCOMPtr<nsIDOMNode> curParent;
nsCOMPtr<nsIDOMNode> curDiv;
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
for (i=0; i<(PRInt32)listCount; i++)
{
// here's where we actually figure out what to do
@ -3697,16 +3926,15 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
// the node is a table element, an horiz rule, a paragraph, a div
// or a section header; in HTML 4, it can directly carry the ALIGN
// attribute and we don't need to nest it, just set the alignment
// attribute and we don't need to nest it, just set the alignment.
// In CSS, assign the corresponding CSS styles in AlignBlock
if (nsHTMLEditUtils::SupportsAlignAttr(curNode))
{
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curNode);
nsAutoString attr(NS_LITERAL_STRING("align"));
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(curNode);
res = AlignBlock(curElem, alignType, PR_FALSE);
if (NS_FAILED(res)) return res;
// clear out curDiv so that we don't put nodes after this one into it
curDiv = 0;
RemoveAlignmentInside(curNode);
continue;
}
@ -3721,13 +3949,27 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
// inside a list, forget any "current" div, and instead put divs inside
// the appropriate block (td, li, etc)
if ( nsHTMLEditUtils::IsListItem(curNode)
|| (nsHTMLEditUtils::IsList(curNode) && nsHTMLEditUtils::IsList(curParent)))
|| nsHTMLEditUtils::IsList(curNode))
{
res = AlignInnerBlocks(curNode, alignType);
if (NS_FAILED(res)) return res;
if (useCSS) {
RemoveAlignment(curNode, *alignType, PR_TRUE);
nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(curNode);
nsAutoString attrName(NS_LITERAL_STRING("align"));
PRInt32 count;
mHTMLEditor->mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(curNode, nsnull,
&attrName, alignType, &count);
curDiv = 0;
continue;
}
else if (nsHTMLEditUtils::IsList(curParent)) {
// if we don't use CSS, add a contraint to list element : they have
// to be inside another list, ie >= second level of nesting
res = AlignInnerBlocks(curNode, alignType);
if (NS_FAILED(res)) return res;
curDiv = 0;
continue;
}
// clear out curDiv so that we don't put nodes after this one into it
curDiv = 0;
continue;
}
// need to make a div to put things in if we haven't already,
@ -3743,9 +3985,10 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
mNewBlock = curDiv;
// set up the alignment on the div
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(curDiv);
nsAutoString attr(NS_LITERAL_STRING("align"));
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
if (NS_FAILED(res)) return res;
res = AlignBlock(divElem, alignType, PR_TRUE);
// nsAutoString attr(NS_LITERAL_STRING("align"));
// res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
// if (NS_FAILED(res)) return res;
// curDiv is now the correct thing to put curNode in
}
@ -3806,10 +4049,14 @@ nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsAReadableString *
nsresult res;
nsCOMPtr <nsIDOMNode> firstChild, lastChild, divNode;
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
res = mHTMLEditor->GetFirstEditableChild(aNode, address_of(firstChild));
if (NS_FAILED(res)) return res;
res = mHTMLEditor->GetLastEditableChild(aNode, address_of(lastChild));
if (NS_FAILED(res)) return res;
nsAutoString attr(NS_LITERAL_STRING("align"));
if (!firstChild)
{
// this cell has no content, nothing to align
@ -3819,8 +4066,14 @@ nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsAReadableString *
// the cell already has a div containing all of it's content: just
// act on this div.
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(firstChild);
nsAutoString attr(NS_LITERAL_STRING("align"));
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
if (useCSS) {
res = mHTMLEditor->RemoveAttribute(divElem, attr);
mHTMLEditor->SetCSSEquivalentToHTMLStyle(divElem, attr, *alignType);
}
else {
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
if (NS_FAILED(res)) return res;
}
if (NS_FAILED(res)) return res;
}
else
@ -3831,9 +4084,14 @@ nsHTMLEditRules::AlignBlockContents(nsIDOMNode *aNode, const nsAReadableString *
if (NS_FAILED(res)) return res;
// set up the alignment on the div
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(divNode);
nsAutoString attr(NS_LITERAL_STRING("align"));
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
if (NS_FAILED(res)) return res;
if (useCSS) {
res = mHTMLEditor->RemoveAttribute(divElem, attr);
mHTMLEditor->SetCSSEquivalentToHTMLStyle(divElem, attr, *alignType);
}
else {
res = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
if (NS_FAILED(res)) return res;
}
// tuck the children into the end of the active div
while (lastChild && (lastChild != divNode))
{
@ -4495,6 +4753,9 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
nsCOMPtr<nsIDOMRange> opRange;
nsCOMPtr<nsISupports> isupports;
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
// bust up any inlines that cross our range endpoints,
// but only if we are allowed to touch content.
@ -4550,8 +4811,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
// certain operations should not act on li's and td's, but rather inside
// them. alter the list as needed
if ( (inOperationType == kMakeBasicBlock) ||
(inOperationType == kAlign) )
if (inOperationType == kMakeBasicBlock)
{
PRUint32 listCount;
(*outArrayOfNodes)->Count(&listCount);
@ -4587,7 +4847,7 @@ nsHTMLEditRules::GetNodesForOperation(nsISupportsArray *inArrayOfRanges,
}
}
// outdent should look inside of divs.
if (inOperationType == kOutdent)
if (inOperationType == kOutdent && !useCSS)
{
PRUint32 listCount;
(*outArrayOfNodes)->Count(&listCount);
@ -5559,6 +5819,7 @@ nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes)
}
}
else
{
curNode->GetParentNode(getter_AddRefs(prevParent));
}
@ -6313,6 +6574,7 @@ nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection
}
}
// we aren't in a textnode: are we adjacent to a break or an image?
res = mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(nearNode));
if (NS_FAILED(res)) return res;
@ -7269,25 +7531,36 @@ nsHTMLEditRules::DidDeleteSelection(nsISelection *aSelection)
// element (here we have to remove the container and keep its
// children). We break on tables and don't look at their children.
nsresult
nsHTMLEditRules::RemoveAlignmentInside(nsIDOMNode * aNode)
nsHTMLEditRules::RemoveAlignment(nsIDOMNode * aNode, nsAReadableString & aAlignType, PRBool aChildrenOnly)
{
if (!aNode) return NS_ERROR_NULL_POINTER;
if (mHTMLEditor->IsTextNode(aNode) || nsHTMLEditUtils::IsTable(aNode)) return NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> child,tmp;
aNode->GetFirstChild(getter_AddRefs(child));
nsCOMPtr<nsIDOMNode> child = aNode,tmp;
if (aChildrenOnly)
{
aNode->GetFirstChild(getter_AddRefs(child));
}
PRBool useCSS;
mHTMLEditor->IsCSSEnabled(&useCSS);
while (child)
{
// get the next sibling right now because we could have to remove child
child->GetNextSibling(getter_AddRefs(tmp));
if (aChildrenOnly) {
// get the next sibling right now because we could have to remove child
child->GetNextSibling(getter_AddRefs(tmp));
}
else
{
tmp = nsnull;
}
PRBool isBlock;
res = mHTMLEditor->NodeIsBlockStatic(child, &isBlock);
if (NS_FAILED(res)) return res;
if (isBlock)
if (isBlock || nsHTMLEditUtils::IsHR(child))
{
// the current node is a block element
nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(child);
@ -7297,10 +7570,22 @@ nsHTMLEditRules::RemoveAlignmentInside(nsIDOMNode * aNode)
res = mHTMLEditor->RemoveAttribute(curElem, NS_LITERAL_STRING("align"));
if (NS_FAILED(res)) return res;
}
if (useCSS)
{
if (nsHTMLEditUtils::IsTable(child) || nsHTMLEditUtils::IsHR(child))
{
mHTMLEditor->SetCSSEquivalentToHTMLStyle(curElem, NS_LITERAL_STRING("align"), aAlignType);
}
else
{
nsAutoString dummyCssValue;
mHTMLEditor->mHTMLCSSUtils->RemoveCSSInlineStyle(child, nsIEditProperty::cssTextAlign, dummyCssValue);
}
}
if (!nsHTMLEditUtils::IsTable(child))
{
// unless this is a table, look at children
res = RemoveAlignmentInside(child);
res = RemoveAlignment(child, aAlignType, PR_TRUE);
if (NS_FAILED(res)) return res;
}
}
@ -7308,7 +7593,7 @@ nsHTMLEditRules::RemoveAlignmentInside(nsIDOMNode * aNode)
{
// this is a CENTER element and we have to remove it
// first remove children's alignment
res = RemoveAlignmentInside(child);
res = RemoveAlignment(child, aAlignType, PR_TRUE);
if (NS_FAILED(res)) return res;
// we may have to insert BRs in first and last position of CENTER's children
@ -7405,3 +7690,115 @@ nsHTMLEditRules::MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode)
return res;
}
nsresult
nsHTMLEditRules::AlignBlock(nsIDOMElement * aElement, const nsAReadableString * aAlignType, PRBool aContentsOnly)
{
if (!aElement) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
PRBool isBlock = IsBlockNode(node);
if (!isBlock && !nsHTMLEditUtils::IsHR(node)) {
// we deal only with blocks; early way out
return NS_OK;
}
RemoveAlignment(node, *aAlignType, aContentsOnly);
nsAutoString attr(NS_LITERAL_STRING("align"));
PRBool useCSS;
nsresult res;
mHTMLEditor->IsCSSEnabled(&useCSS);
if (useCSS) {
// let's use CSS alignment; we use margin-left and margin-right for tables
// and text-align for other block-level elements
res = mHTMLEditor->RemoveAttribute(aElement, attr);
if (NS_FAILED(res)) return res;
mHTMLEditor->SetCSSEquivalentToHTMLStyle(aElement, attr, *aAlignType);
}
else {
// HTML case; this code is supposed to be called ONLY if the element
// supports the align attribute but we'll never know...
if (nsHTMLEditUtils::SupportsAlignAttr(node)) {
res = mHTMLEditor->SetAttribute(aElement, attr, *aAlignType);
if (NS_FAILED(res)) return res;
}
}
return NS_OK;
}
nsresult
nsHTMLEditRules::RelativeChangeIndentation(nsIDOMNode *aNode, PRInt8 aRelativeChange)
{
if ( !( (aRelativeChange==1) || (aRelativeChange==-1) ) )
return NS_ERROR_ILLEGAL_VALUE;
nsAutoString value;
nsresult res;
mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(aNode, nsIEditProperty::cssMarginLeft, value);
float f;
nsIAtom * unit;
mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, &unit);
if (0 == f) {
NS_IF_RELEASE(unit);
nsAutoString defaultLengthUnit;
mHTMLEditor->mHTMLCSSUtils->GetDefaultLengthUnit(defaultLengthUnit);
unit = NS_NewAtom(defaultLengthUnit);
}
nsAutoString unitString;
unit->ToString(unitString);
if (nsIEditProperty::cssInUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_IN * aRelativeChange;
else if (nsIEditProperty::cssCmUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_CM * aRelativeChange;
else if (nsIEditProperty::cssMmUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_MM * aRelativeChange;
else if (nsIEditProperty::cssPtUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_PT * aRelativeChange;
else if (nsIEditProperty::cssPcUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_PC * aRelativeChange;
else if (nsIEditProperty::cssEmUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_EM * aRelativeChange;
else if (nsIEditProperty::cssExUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_EX * aRelativeChange;
else if (nsIEditProperty::cssPxUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_PX * aRelativeChange;
else if (nsIEditProperty::cssPercentUnit == unit)
f += NS_EDITOR_INDENT_INCREMENT_PERCENT * aRelativeChange;
NS_IF_RELEASE(unit);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
if (element) {
if (0 < f) {
nsAutoString newValue;
newValue.AppendFloat(f);
newValue.Append(unitString);
mHTMLEditor->mHTMLCSSUtils->SetCSSProperty(element, nsIEditProperty::cssMarginLeft, newValue);
}
else {
mHTMLEditor->mHTMLCSSUtils->RemoveCSSProperty(element, nsIEditProperty::cssMarginLeft, value);
if (nsHTMLEditUtils::IsDiv(aNode)) {
// we deal with a DIV ; let's see if it is useless and if we can remove it
nsCOMPtr<nsIDOMNamedNodeMap> attributeList;
res = element->GetAttributes(getter_AddRefs(attributeList));
if (NS_FAILED(res)) return res;
PRUint32 count;
attributeList->GetLength(&count);
if (!count) {
// the DIV has no attribute at all, let's remove it
res = mHTMLEditor->RemoveContainer(element);
if (NS_FAILED(res)) return res;
}
else if (1 == count) {
nsCOMPtr<nsIDOMNode> styleAttributeNode;
res = attributeList->GetNamedItem(NS_LITERAL_STRING("style"),
getter_AddRefs(styleAttributeNode));
if (!styleAttributeNode) {
res = mHTMLEditor->RemoveContainer(element);
if (NS_FAILED(res)) return res;
}
}
}
}
}
return NS_OK;
}

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -138,6 +139,8 @@ protected:
nsresult WillMakeList(nsISelection *aSelection, const nsAReadableString *aListType, PRBool aEntireList, const nsAReadableString *aBulletType, PRBool *aCancel, PRBool *aHandled, const nsAReadableString *aItemType=nsnull);
nsresult WillRemoveList(nsISelection *aSelection, PRBool aOrderd, PRBool *aCancel, PRBool *aHandled);
nsresult WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult WillCSSIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult WillHTMLIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult WillAlign(nsISelection *aSelection, const nsAReadableString *alignType, PRBool *aCancel, PRBool *aHandled);
nsresult WillMakeDefListItem(nsISelection *aSelection, const nsAReadableString *aBlockType, PRBool aEntireList, PRBool *aCancel, PRBool *aHandled);
@ -235,9 +238,11 @@ protected:
PRBool IsVisBreak(nsIDOMNode *aNode);
PRBool IsEmptyInline(nsIDOMNode *aNode);
PRBool ListIsEmptyLine(nsISupportsArray *arrayOfNodes);
nsresult RemoveAlignmentInside(nsIDOMNode * aNode);
nsresult RemoveAlignment(nsIDOMNode * aNode, nsAReadableString & aAlignType, PRBool aChildrenOnly);
nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode, PRBool aStarts);
nsresult MakeSureElemStartsOrEndsOnCR(nsIDOMNode *aNode);
nsresult AlignBlock(nsIDOMElement * aElement, const nsAReadableString * aAlignType, PRBool aContentsOnly);
nsresult RelativeChangeIndentation(nsIDOMNode *aNode, PRInt8 aRelativeChange);
// data members
protected:

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* Pierre Phaneuf <pp@ludusdesign.com>
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -65,6 +66,7 @@
#include "nsISelectionPrivate.h"
#include "nsIDOMHTMLAnchorElement.h"
#include "nsISelectionController.h"
#include "nsIDOMHTMLHtmlElement.h"
#include "TransactionFactory.h"
@ -164,6 +166,7 @@ nsHTMLEditor::nsHTMLEditor()
, mIgnoreSpuriousDragEvent(PR_FALSE)
, mTypeInState(nsnull)
, mSelectedCellIndex(0)
, mHTMLCSSUtils(nsnull)
{
// Done in nsEditor
// NS_INIT_REFCNT();
@ -272,6 +275,14 @@ NS_IMETHODIMP nsHTMLEditor::Init(nsIDOMDocument *aDoc,
result = nsPlaintextEditor::Init(aDoc, aPresShell, aRoot, aSelCon, aFlags);
if (NS_FAILED(result)) { return result; }
// the HTML Editor is CSS-aware only in the case of Composer
mCSSAware = PRBool(0 == aFlags);
// Init the HTML-CSS utils
result = NS_NewHTMLCSSUtils(&mHTMLCSSUtils);
if (NS_FAILED(result)) { return result; }
mHTMLCSSUtils->Init(this);
// disable links
nsCOMPtr<nsIPresContext> context;
aPresShell->GetPresContext(getter_AddRefs(context));
@ -586,19 +597,19 @@ nsHTMLEditor::NodeIsBlockStatic(nsIDOMNode *aNode, PRBool *aIsBlock)
tagAtom==nsIEditProperty::noscript ||
tagAtom==nsIEditProperty::form ||
tagAtom==nsIEditProperty::hr ||
tagAtom==nsIEditProperty::table ||
tagAtom==nsIEditProperty::fieldset ||
tagAtom==nsIEditProperty::address ||
tagAtom==nsIEditProperty::body ||
tagAtom==nsIEditProperty::tr ||
tagAtom==nsIEditProperty::td ||
tagAtom==nsIEditProperty::th ||
tagAtom==nsIEditProperty::caption ||
tagAtom==nsIEditProperty::col ||
tagAtom==nsIEditProperty::colgroup ||
tagAtom==nsIEditProperty::table ||
tagAtom==nsIEditProperty::tbody ||
tagAtom==nsIEditProperty::thead ||
tagAtom==nsIEditProperty::tfoot ||
tagAtom==nsIEditProperty::tr ||
tagAtom==nsIEditProperty::td ||
tagAtom==nsIEditProperty::th ||
tagAtom==nsIEditProperty::col ||
tagAtom==nsIEditProperty::colgroup ||
tagAtom==nsIEditProperty::li ||
tagAtom==nsIEditProperty::dt ||
tagAtom==nsIEditProperty::dd ||
@ -1166,9 +1177,14 @@ NS_IMETHODIMP nsHTMLEditor::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent)
}
else if (keyCode == nsIDOMKeyEvent::DOM_VK_ESCAPE)
{
// pass escape keypresses through as empty strings: needed forime support
nsString empty;
return TypedText(empty, eTypedText);
if (isShift) {
return SelectParentOfSelection();
}
else {
// pass escape keypresses through as empty strings: needed forime support
nsString empty;
return TypedText(empty, eTypedText);
}
}
// if we got here we either fell out of the tab case or have a normal character.
@ -2103,8 +2119,163 @@ nsHTMLEditor::GetParagraphState(PRBool *aMixed, nsAWritableString &outFormat)
return htmlRules->GetParagraphState(aMixed, outFormat);
}
NS_IMETHODIMP
NS_IMETHODIMP
nsHTMLEditor::GetBackgroundColorState(PRBool *aMixed, nsAWritableString &aOutColor)
{
nsresult res;
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (useCSS) {
// if we are in CSS mode, we have to check if the containing block defines
// a background color
res = GetCSSBackgroundColorState(aMixed, aOutColor, PR_TRUE);
}
else {
// in HTML mode, we look only at page's background
res = GetHTMLBackgroundColorState(aMixed, aOutColor);
}
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetHighlightColorState(PRBool *aMixed, nsAWritableString &aOutColor)
{
nsresult res = NS_OK;
PRBool useCSS;
IsCSSEnabled(&useCSS);
*aMixed = PR_FALSE;
aOutColor.Assign(NS_LITERAL_STRING("transparent"));
if (useCSS) {
// in CSS mode, text background can be added by the Text Highlight button
// we need to query the background of the selection without looking for
// the block container of the ranges in the selection
res = GetCSSBackgroundColorState(aMixed, aOutColor, PR_FALSE);
}
return res;
}
NS_IMETHODIMP
nsHTMLEditor::GetHighlightColor(PRBool *aMixed, PRUnichar **_retval)
{
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
nsAutoString outColorString(NS_LITERAL_STRING("transparent"));
*aMixed = PR_FALSE;
nsresult err = NS_NOINTERFACE;
err = GetHighlightColorState(aMixed, outColorString);
*_retval = ToNewUnicode(outColorString);
return err;
}
nsresult
nsHTMLEditor::GetCSSBackgroundColorState(PRBool *aMixed, nsAWritableString &aOutColor, PRBool aBlockLevel)
{
if (!aMixed) return NS_ERROR_NULL_POINTER;
*aMixed = PR_FALSE;
// the default background color is transparent
aOutColor.Assign(NS_LITERAL_STRING("transparent"));
// get selection
nsCOMPtr<nsISelection>selection;
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
// get selection location
nsCOMPtr<nsIDOMNode> parent;
PRInt32 offset;
res = GetStartNodeAndOffset(selection, address_of(parent), &offset);
if (NS_FAILED(res)) return res;
// is the selection collapsed?
PRBool bCollapsed;
res = selection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> nodeToExamine;
if (bCollapsed || IsTextNode(parent))
{
// we want to look at the parent and ancestors
nodeToExamine = parent;
}
else
{
// otherwise we want to look at the first editable node after
// {parent,offset} and it's ancestors for divs with alignment on them
nodeToExamine = GetChildAt(parent, offset);
//GetNextNode(parent, offset, PR_TRUE, address_of(nodeToExamine));
}
if (!nodeToExamine) return NS_ERROR_NULL_POINTER;
// is the node to examine a block ?
PRBool isBlock;
res = NodeIsBlockStatic(nodeToExamine, &isBlock);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMHTMLHtmlElement> htmlElement;
nsCOMPtr<nsIDOMNode> tmp;
if (aBlockLevel) {
// we are querying the block background (and not the text background), let's
// climb to the block container
nsCOMPtr<nsIDOMNode> blockParent = nodeToExamine;
if (!isBlock) {
blockParent = GetBlockNodeParent(nodeToExamine);
}
do {
// retrieve the computed style of background-color for blockParent
mHTMLCSSUtils->GetComputedProperty(blockParent, nsIEditProperty::cssBackgroundColor,
aOutColor);
tmp = blockParent;
res = tmp->GetParentNode(getter_AddRefs(blockParent));
htmlElement = do_QueryInterface(tmp);
// look at parent if the queried color is transparent and if the node to
// examine is not the root of the document
} while ( aOutColor.Equals(NS_LITERAL_STRING("transparent")) && !htmlElement );
if (htmlElement && aOutColor.Equals(NS_LITERAL_STRING("transparent"))) {
// we have hit the root of the document and the color is still transparent !
// Grumble... Let's look at the default background color because that's the
// color we are looking for
mHTMLCSSUtils->GetDefaultBackgroundColor(aOutColor);
}
}
else {
// no, we are querying the text background for the Text Highlight button
if (IsTextNode(nodeToExamine)) {
// if the node of interest is a text node, let's climb a level
res = nodeToExamine->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
nodeToExamine = parent;
}
do {
// is the node to examine a block ?
res = NodeIsBlockStatic(nodeToExamine, &isBlock);
if (NS_FAILED(res)) return res;
if (isBlock) {
// yes it is a block; in that case, the text background color is transparent
aOutColor.Assign(NS_LITERAL_STRING("transparent"));
break;
}
else {
// no, it's not; let's retrieve the computed style of background-color for the
// node to examine
mHTMLCSSUtils->GetComputedProperty(nodeToExamine, nsIEditProperty::cssBackgroundColor,
aOutColor);
if (!aOutColor.Equals(NS_LITERAL_STRING("transparent"))) {
break;
}
}
res = nodeToExamine->GetParentNode(getter_AddRefs(tmp));
if (NS_FAILED(res)) return res;
nodeToExamine = tmp;
htmlElement = do_QueryInterface(tmp);
} while ( aOutColor.Equals(NS_LITERAL_STRING("transparent")) && !htmlElement );
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLEditor::GetHTMLBackgroundColorState(PRBool *aMixed, nsAWritableString &aOutColor)
{
//TODO: We don't handle "mixed" correctly!
if (!aMixed) return NS_ERROR_NULL_POINTER;
@ -3032,8 +3203,8 @@ nsHTMLEditor::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
return res;
}
NS_IMETHODIMP
nsHTMLEditor::SetBackgroundColor(const nsAReadableString& aColor)
NS_IMETHODIMP
nsHTMLEditor::SetHTMLBackgroundColor(const nsAReadableString& aColor)
{
NS_PRECONDITION(mDocWeak, "Missing Editor DOM Document");
@ -4831,3 +5002,415 @@ nsHTMLEditor::IsEmptyNode( nsIDOMNode *aNode,
return NS_OK;
}
// add to aElement the CSS inline styles corresponding to the HTML attribute
// aAttribute with its value aValue
nsresult
nsHTMLEditor::SetCSSEquivalentToHTMLStyle(nsIDOMElement * aElement,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue)
{
PRBool useCSS;
nsresult res = NS_OK;
IsCSSEnabled(&useCSS);
if (useCSS && mHTMLCSSUtils) {
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(aElement, nsnull, &aAttribute, &aValue, &count);
if (NS_FAILED(res)) return res;
if (!count) {
// count is an integer that represents the number of CSS declarations applied to the
// element. If it is zero, we found no equivalence in this implementation for the
// attribute
if (aAttribute.Equals(NS_LITERAL_STRING("style"))) {
// if it is the style attribute, just add the new value to the existing style
// attribute's value
nsAutoString existingValue;
PRBool wasSet = PR_FALSE;
res = GetAttributeValue(aElement, NS_LITERAL_STRING("style"), existingValue, &wasSet);
if (NS_FAILED(res)) return res;
existingValue.Append(NS_LITERAL_STRING(" "));
existingValue.Append(aValue);
res = SetAttribute(aElement, aAttribute, existingValue);
}
else {
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
res = SetAttribute(aElement, aAttribute, aValue);
}
}
}
else {
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
res = SetAttribute(aElement, aAttribute, aValue);
}
return res;
}
nsresult
nsHTMLEditor::SetCSSEnabled(PRBool aIsCSSPrefChecked)
{
nsresult err = NS_ERROR_NOT_INITIALIZED;
if (mHTMLCSSUtils)
{
err = mHTMLCSSUtils->SetCSSEnabled(aIsCSSPrefChecked);
}
return err;
}
// Set the block background color
NS_IMETHODIMP
nsHTMLEditor::SetCSSBackgroundColor(const nsAReadableString& aColor)
{
if (!mRules) { return NS_ERROR_NOT_INITIALIZED; }
ForceCompositionEnd();
nsresult res;
nsCOMPtr<nsISelection>selection;
res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
if (!selection) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
PRBool isCollapsed;
selection->GetIsCollapsed(&isCollapsed);
nsAutoEditBatch batchIt(this);
nsAutoRules beginRulesSniffing(this, kOpInsertElement, nsIEditor::eNext);
nsAutoSelectionReset selectionResetter(selection, this);
nsAutoTxnsConserveSelection dontSpazMySelection(this);
PRBool cancel, handled;
nsTextRulesInfo ruleInfo(nsTextEditRules::kSetTextProperty);
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
if (NS_FAILED(res)) return res;
if (!cancel && !handled)
{
// get selection range enumerator
nsCOMPtr<nsIEnumerator> enumerator;
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_FAILURE;
// loop thru the ranges in the selection
enumerator->First();
nsCOMPtr<nsISupports> currentItem;
nsAutoString bgcolor; bgcolor.AssignWithConversion("bgcolor");
nsCOMPtr<nsIDOMNode> cachedBlockParent = nsnull;
while ((NS_ENUMERATOR_FALSE == enumerator->IsDone()))
{
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
if (!currentItem) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
// check for easy case: both range endpoints in same text node
nsCOMPtr<nsIDOMNode> startNode, endNode;
PRInt32 startOffset, endOffset;
res = range->GetStartContainer(getter_AddRefs(startNode));
if (NS_FAILED(res)) return res;
res = range->GetEndContainer(getter_AddRefs(endNode));
if (NS_FAILED(res)) return res;
res = range->GetStartOffset(&startOffset);
if (NS_FAILED(res)) return res;
res = range->GetEndOffset(&endOffset);
if (NS_FAILED(res)) return res;
if ((startNode == endNode) && IsTextNode(startNode))
{
// let's find the block container of the text node
nsCOMPtr<nsIDOMNode> blockParent;
blockParent = GetBlockNodeParent(startNode);
// and apply the background color to that block container
if (cachedBlockParent != blockParent)
{
cachedBlockParent = blockParent;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
}
else if ((startNode == endNode) && nsTextEditUtils::IsBody(startNode) && !startOffset && !endOffset )
{
// we have no block in the document, let's apply the background to the body
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(startNode);
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
else if ((startNode == endNode) && (((endOffset-startOffset) == 1) || (!startOffset && !endOffset)))
{
// a unique node is selected, let's also apply the background color
// to the containing block, possibly the node itself
nsCOMPtr<nsIDOMNode> selectedNode = GetChildAt(startNode, startOffset);
PRBool isBlock =PR_FALSE;
res = NodeIsBlockStatic(selectedNode, &isBlock);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> blockParent = selectedNode;
if (!isBlock) {
blockParent = GetBlockNodeParent(selectedNode);
}
if (cachedBlockParent != blockParent)
{
cachedBlockParent = blockParent;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
}
else
{
// not the easy case. range not contained in single text node.
// there are up to three phases here. There are all the nodes
// reported by the subtree iterator to be processed. And there
// are potentially a starting textnode and an ending textnode
// which are only partially contained by the range.
// lets handle the nodes reported by the iterator. These nodes
// are entirely contained in the selection range. We build up
// a list of them (since doing operations on the document during
// iteration would perturb the iterator).
nsCOMPtr<nsIContentIterator> iter;
res = nsComponentManager::CreateInstance(kSubtreeIteratorCID, nsnull,
NS_GET_IID(nsIContentIterator),
getter_AddRefs(iter));
if (NS_FAILED(res)) return res;
if (!iter) return NS_ERROR_FAILURE;
nsCOMPtr<nsISupportsArray> arrayOfNodes;
nsCOMPtr<nsIContent> content;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsISupports> isupports;
// make a array
res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
if (NS_FAILED(res)) return res;
// iterate range and build up array
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))
{
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;
}
}
// first check the start parent of the range to see if it needs to
// be seperately handled (it does if it's a text node, due to how the
// subtree iterator works - it will not have reported it).
if (IsTextNode(startNode) && IsEditable(startNode))
{
nsCOMPtr<nsIDOMNode> blockParent;
blockParent = GetBlockNodeParent(startNode);
if (cachedBlockParent != blockParent)
{
cachedBlockParent = blockParent;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
}
// then loop through the list, set the property on each node
PRUint32 listCount;
PRUint32 j;
arrayOfNodes->Count(&listCount);
for (j = 0; j < listCount; j++)
{
isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
node = do_QueryInterface(isupports);
// do we have a block here ?
PRBool isBlock =PR_FALSE;
res = NodeIsBlockStatic(node, &isBlock);
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> blockParent = node;
if (!isBlock) {
// no we don't, let's find the block ancestor
blockParent = GetBlockNodeParent(node);
}
if (cachedBlockParent != blockParent)
{
cachedBlockParent = blockParent;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
PRInt32 count;
// and set the property on it
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
arrayOfNodes->RemoveElementAt(0);
}
// last check the end parent of the range to see if it needs to
// be seperately handled (it does if it's a text node, due to how the
// subtree iterator works - it will not have reported it).
if (IsTextNode(endNode) && IsEditable(endNode))
{
nsCOMPtr<nsIDOMNode> blockParent;
blockParent = GetBlockNodeParent(endNode);
if (cachedBlockParent != blockParent)
{
cachedBlockParent = blockParent;
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(blockParent);
PRInt32 count;
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, nsnull, &bgcolor, &aColor, &count);
if (NS_FAILED(res)) return res;
}
}
}
enumerator->Next();
}
}
if (!cancel)
{
// post-process
res = mRules->DidDoAction(selection, &ruleInfo, res);
}
return res;
}
NS_IMETHODIMP
nsHTMLEditor::SetBackgroundColor(const nsAReadableString& aColor)
{
nsresult res;
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (useCSS) {
// if we are in CSS mode, we have to apply the background color to the
// containing block (or the body if we have no block-level element in
// the document)
res = SetCSSBackgroundColor(aColor);
}
else {
// but in HTML mode, we can only set the document's background color
res = SetHTMLBackgroundColor(aColor);
}
return res;
}
///////////////////////////////////////////////////////////////////////////
// NodesSameType: do these nodes have the same tag?
//
PRBool
nsHTMLEditor::NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2)
{
if (!aNode1 || !aNode2)
{
NS_NOTREACHED("null node passed to nsEditor::NodesSameType()");
return PR_FALSE;
}
PRBool useCSS;
IsCSSEnabled(&useCSS);
nsCOMPtr<nsIAtom> atom1 = GetTag(aNode1);
nsCOMPtr<nsIAtom> atom2 = GetTag(aNode2);
if (atom1.get() == atom2.get()) {
if (useCSS && NodeIsType(aNode1, NS_LITERAL_STRING("span"))) {
if (mHTMLCSSUtils->ElementsSameStyle(aNode1, aNode2)) {
return PR_TRUE;
}
}
else {
return PR_TRUE;
}
}
return PR_FALSE;
}
nsresult
nsHTMLEditor::SelectParentOfSelection()
{
// get selection
nsCOMPtr<nsISelection>selection;
nsresult res = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
if (!selPriv)
return NS_ERROR_FAILURE;
PRBool bCollapsed;
res = selection->GetIsCollapsed(&bCollapsed);
if (NS_FAILED(res)) return res;
if (bCollapsed) {
// get selection location
nsCOMPtr<nsIDOMNode> node, parent;
PRInt32 offset;
res = GetStartNodeAndOffset(selection, address_of(node), &offset);
if (NS_FAILED(res)) return res;
res = node->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res) || !parent) return res;
nsCOMPtr<nsIDOMElement> resultElement = do_QueryInterface(parent);
if (!resultElement) return NS_OK;
res = SelectElement(resultElement);
return res;
}
nsCOMPtr<nsIEnumerator> enumerator;
res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
if (NS_FAILED(res)) return res;
if (!enumerator) return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsISupportsArray> arrayOfNodes;
// make a array
res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
if (NS_FAILED(res)) return res;
nsCOMPtr<nsISupports> isupports;
for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
{
nsCOMPtr<nsISupports> currentItem;
res = enumerator->CurrentItem(getter_AddRefs(currentItem));
if (NS_FAILED(res)) return res;
if (!currentItem) return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) );
nsCOMPtr<nsIDOMNode> commonParent;
range->GetCommonAncestorContainer(getter_AddRefs(commonParent));
isupports = do_QueryInterface(commonParent);
res = arrayOfNodes->AppendElement(isupports);
if (NS_FAILED(res)) return res;
}
PRUint32 listCount;
arrayOfNodes->Count(&listCount);
// res = ClearSelection();
if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsIDOMElement> element;
PRUint32 j;
for (j = 0; j < listCount; j++)
{
isupports = dont_AddRef(arrayOfNodes->ElementAt(j));
node = do_QueryInterface(isupports);
element = do_QueryInterface(node);
if (IsElementInBody(element))
{
res = AppendNodeToSelectionAsRange(node);
if (NS_FAILED(res)) return res;
}
}
return res;
}

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -59,7 +60,8 @@
#include "nsEditRules.h"
#include "nsIEditProperty.h"
#include "nsHTMLCSSUtils.h"
class nsIDOMKeyEvent;
class nsITransferable;
class nsIDOMEventReceiver;
@ -116,9 +118,14 @@ public:
NS_IMETHODIMP CollapseSelectionToStart();
/* ------------ nsIHTMLEditor methods -------------- */
NS_IMETHOD SetCSSInlineProperty(nsIAtom *aProperty,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue);
NS_IMETHOD SetInlineProperty(nsIAtom *aProperty,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue);
const nsAReadableString & aAttribute,
const nsAReadableString & aValue);
NS_IMETHOD GetInlineProperty(nsIAtom *aProperty,
const nsAReadableString & aAttribute,
@ -157,7 +164,11 @@ public:
NS_IMETHOD GetParagraphState(PRBool *aMixed, nsAWritableString &outFormat);
NS_IMETHOD GetFontFaceState(PRBool *aMixed, nsAWritableString &outFace);
NS_IMETHOD GetFontColorState(PRBool *aMixed, nsAWritableString &outColor);
NS_IMETHOD GetCSSBackgroundColorState(PRBool *aMixed, nsAWritableString &aOutColor, PRBool aBlockLevel);
NS_IMETHOD GetHTMLBackgroundColorState(PRBool *aMixed, nsAWritableString &outColor);
NS_IMETHOD GetBackgroundColorState(PRBool *aMixed, nsAWritableString &outColor);
NS_IMETHOD GetHighlightColorState(PRBool *aMixed, nsAWritableString &outColor);
NS_IMETHOD GetHighlightColor(PRBool *mixed, PRUnichar **_retval);
NS_IMETHOD GetListState(PRBool *aMixed, PRBool *aOL, PRBool *aUL, PRBool *aDL);
NS_IMETHOD GetListItemState(PRBool *aMixed, PRBool *aLI, PRBool *aDT, PRBool *aDD);
NS_IMETHOD GetAlignment(PRBool *aMixed, nsIHTMLEditor::EAlignment *aAlign);
@ -178,6 +189,8 @@ public:
NS_IMETHOD GetLinkedObjects(nsISupportsArray** aNodeList);
NS_IMETHOD SetCSSEnabled(PRBool aIsCSSPrefChecked);
/* ------------ nsIEditorIMESupport overrides -------------- */
NS_IMETHOD SetCompositionString(const nsAReadableString& aCompositionString, nsIPrivateTextRangeList* aTextRangeList,nsTextEventReply* aReply);
@ -265,6 +278,8 @@ public:
/* miscellaneous */
// This sets background on the appropriate container element (table, cell,)
// or calls into nsTextEditor to set the page background
NS_IMETHOD SetCSSBackgroundColor(const nsAReadableString& aColor);
NS_IMETHOD SetHTMLBackgroundColor(const nsAReadableString& aColor);
NS_IMETHOD SetBackgroundColor(const nsAReadableString& aColor);
NS_IMETHOD SetBodyAttribute(const nsAReadableString& aAttr, const nsAReadableString& aValue);
// aTitle may be null or empty string to remove child contents of <title>
@ -364,9 +379,16 @@ public:
/** make the given selection span the entire document */
NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
NS_IMETHOD IsCSSEnabled(PRBool * aIsSet);
NS_IMETHOD SetCSSEquivalentToHTMLStyle(nsIDOMElement * aElement,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue);
/** join together any afjacent editable text nodes in the range */
NS_IMETHOD CollapseAdjacentTextNodes(nsIDOMRange *aInRange);
virtual PRBool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2);
/* ------------ nsICSSLoaderObserver -------------- */
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify);
@ -655,7 +677,7 @@ protected:
const nsAReadableString *aAttribute,
PRBool aChildrenOnly = PR_FALSE);
nsresult RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsAReadableString *aAttribute);
PRBool NodeIsProperty(nsIDOMNode *aNode);
PRBool HasAttr(nsIDOMNode *aNode, const nsAReadableString *aAttribute);
PRBool HasAttrVal(nsIDOMNode *aNode, const nsAReadableString *aAttribute, const nsAReadableString *aValue);
@ -696,6 +718,8 @@ protected:
PRBool *aAll,
nsAWritableString *outValue);
nsresult SelectParentOfSelection();
// Data members
protected:
@ -721,6 +745,8 @@ protected:
nsCOMPtr<nsIRangeUtils> mRangeHelper;
PRBool mCSSAware;
nsHTMLCSSUtils *mHTMLCSSUtils;
public:
// friends

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -66,11 +67,9 @@
#include "nsICSSLoader.h"
#include "nsICSSStyleSheet.h"
#include "nsIHTMLContentContainer.h"
#include "nsIStyleSet.h"
#include "nsIDocumentObserver.h"
#include "nsIDocumentStateListener.h"
#include "nsIStyleContext.h"
#include "TypeInState.h"
#include "nsIEnumerator.h"
@ -99,6 +98,7 @@
#include "nsInternetCiter.h"
#include "nsISupportsPrimitives.h"
#include "InsertTextTxn.h"
#include "ChangeCSSInlineStyleTxn.h"
// Transactionas
#include "PlaceholderTxn.h"
@ -119,6 +119,21 @@ static PRBool gNoisy = PR_FALSE;
static const PRBool gNoisy = PR_FALSE;
#endif
// Add the CSS style corresponding to the HTML inline style defined
// by aProperty aAttribute and aValue to the selection
NS_IMETHODIMP nsHTMLEditor::SetCSSInlineProperty(nsIAtom *aProperty,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue)
{
nsresult res = NS_OK;
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (useCSS) {
res = SetInlineProperty(aProperty, aAttribute, aValue);
}
return res;
}
NS_IMETHODIMP nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
const nsAReadableString & aAttribute,
@ -305,11 +320,17 @@ nsHTMLEditor::SetInlinePropertyOnTextNode( nsIDOMCharacterData *aTextNode,
const nsAReadableString *aValue)
{
if (!aTextNode) return NS_ERROR_NULL_POINTER;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> parent;
res = aTextNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
nsAutoString tagString;
aProperty->ToString(tagString);
if (!CanContainTag(parent, tagString)) return NS_OK;
// dont need to do anything if no characters actually selected
if (aStartOffset == aEndOffset) return NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> tmp, node = do_QueryInterface(aTextNode);
// dont need to do anything if property already set on node
@ -378,6 +399,38 @@ nsHTMLEditor::SetInlinePropertyOnNode( nsIDOMNode *aNode,
aProperty->ToString(tag);
ToLowerCase(tag);
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (useCSS) {
// we are in CSS mode
if (mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) {
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for the node aNode
nsCOMPtr<nsIDOMNode> tmp = aNode;
if (IsTextNode(tmp)) {
// we are working on a text node and need to create a span container
// that will carry the styles
InsertContainerAbove( aNode,
address_of(tmp),
NS_LITERAL_STRING("span"),
nsnull,
nsnull);
}
nsCOMPtr<nsIDOMElement>element;
element = do_QueryInterface(tmp);
// first we have to remove occurences of the same style hint in the
// children of the aNode
res = RemoveStyleInside(tmp, aProperty, aAttribute, PR_TRUE);
if (NS_FAILED(res)) return res;
PRInt32 count;
// then we add the css styles corresponding to the HTML style request
res = mHTMLCSSUtils->SetCSSEquivalentToHTMLStyle(element, aProperty, aAttribute, aValue, &count);
if (NS_FAILED(res)) return res;
return res;
}
}
// dont need to do anything if property already set on node
PRBool bHasProp;
nsCOMPtr<nsIDOMNode> styleNode;
@ -497,7 +550,7 @@ nsresult nsHTMLEditor::SplitStyleAboveRange(nsIDOMRange *inRange,
// split any matching style nodes above the start of range
res = SplitStyleAbovePoint(address_of(startNode), &startOffset, aProperty, aAttribute);
if (NS_FAILED(res)) return res;
if (sameNode && (startNode != origStartNode))
{
// our startNode got split. This changes the offset of the end of our range.
@ -528,12 +581,27 @@ nsresult nsHTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsIDOMNode> *aNode,
// split any matching style nodes above the node/offset
nsCOMPtr<nsIDOMNode> parent, tmp = *aNode;
PRInt32 offset;
PRBool useCSS;
IsCSSEnabled(&useCSS);
PRBool isSet;
while (tmp && !IsBlockNode(tmp))
{
isSet = PR_FALSE;
if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(tmp, aProperty, aAttribute)) {
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for the node tmp; let's check if it carries those css styles
nsAutoString firstValue;
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(tmp, aProperty, aAttribute,
isSet, firstValue,
SPECIFIED_STYLE_TYPE);
}
if ( (aProperty && NodeIsType(tmp, aProperty)) || // node is the correct inline prop
(aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) || // node is href - test if really <a href=...
(!aProperty && NodeIsProperty(tmp)) ) // or node is any prop, and we asked to split them all
(aProperty == nsIEditProperty::href && nsHTMLEditUtils::IsLink(tmp)) ||
// node is href - test if really <a href=...
(!aProperty && NodeIsProperty(tmp)) || // or node is any prop, and we asked to split them all
isSet) // or the style is specified in the style attribute
{
// found a style node we need to split
SplitNodeDeep(tmp, *aNode, *aOffset, &offset, PR_FALSE, outLeftNode, outRightNode);
@ -610,7 +678,44 @@ nsresult nsHTMLEditor::RemoveStyleInside(nsIDOMNode *aNode,
}
}
}
else {
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (!aChildrenOnly
&& useCSS && mHTMLCSSUtils->IsCSSEditableProperty(aNode, aProperty, aAttribute)) {
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for the node aNode; let's check if it carries those css styles
nsAutoString propertyValue;
PRBool isSet;
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode, aProperty, aAttribute,
isSet, propertyValue,
SPECIFIED_STYLE_TYPE);
if (isSet) {
// yes, tmp has the corresponding css declarations in its style attribute
// let's remove them
mHTMLCSSUtils->RemoveCSSEquivalentToHTMLStyle(aNode,
aProperty,
aAttribute,
&propertyValue);
// remove the node if it is a span, if its style attribute is empty or absent,
// and if it does not have a class nor an id
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(aNode);
nsAutoString styleVal;
PRBool isStyleSet;
res = GetAttributeValue(elem, NS_LITERAL_STRING("style"), styleVal, &isStyleSet);
if (NS_FAILED(res)) return res;
if (NodeIsType(aNode, nsIEditProperty::span) && (!isStyleSet || (0 == styleVal.Length()))) {
PRBool hasClassOrId ;
res = mHTMLCSSUtils->HasClassOrID(elem, hasClassOrId);
if (!hasClassOrId) {
res = RemoveContainer(aNode);
if (NS_FAILED(res)) return res;
}
}
}
}
}
if ( aProperty == nsIEditProperty::font && // or node is big or small and we are setting font size
(NodeIsType(aNode, nsIEditProperty::big) || NodeIsType(aNode, nsIEditProperty::small)) &&
!Compare(*aAttribute,NS_LITERAL_STRING("size"),nsCaseInsensitiveStringComparator()))
@ -869,6 +974,10 @@ nsHTMLEditor::GetInlinePropertyBase(nsIAtom *aProperty,
*aAll=PR_TRUE;
*aFirst=PR_FALSE;
PRBool first=PR_TRUE;
PRBool useCSS;
IsCSSEnabled(&useCSS);
nsCOMPtr<nsISelection>selection;
result = GetSelection(getter_AddRefs(selection));
if (NS_FAILED(result)) return result;
@ -916,11 +1025,13 @@ nsHTMLEditor::GetInlinePropertyBase(nsIAtom *aProperty,
*aFirst = *aAny = *aAll = theSetting;
return NS_OK;
}
nsCOMPtr<nsIDOMNode> resultNode;
IsTextPropertySetByContent(collapsedNode, aProperty, aAttribute, aValue,
isSet, getter_AddRefs(resultNode), outValue);
*aFirst = *aAny = *aAll = isSet;
return NS_OK;
if (!useCSS) {
nsCOMPtr<nsIDOMNode> resultNode;
IsTextPropertySetByContent(collapsedNode, aProperty, 0, 0,
isSet, getter_AddRefs(resultNode));
*aFirst = *aAny = *aAll = isSet;
return NS_OK;
}
}
// non-collapsed selection
@ -983,18 +1094,42 @@ nsHTMLEditor::GetInlinePropertyBase(nsIAtom *aProperty,
{
if (node)
{
PRBool isSet;
PRBool isSet = PR_FALSE;
nsCOMPtr<nsIDOMNode>resultNode;
if (first)
{
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet, getter_AddRefs(resultNode), &firstValue);
if (useCSS &&
mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
// the HTML styles defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for node; let's check if it carries those css styles
if (aValue) firstValue.Assign(*aValue);
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, aAttribute,
isSet, firstValue,
COMPUTED_STYLE_TYPE);
}
else {
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 (useCSS &&
mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
// the HTML styles defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for node; let's check if it carries those css styles
if (aValue) firstValue.Assign(*aValue);
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, aAttribute,
isSet, theValue,
COMPUTED_STYLE_TYPE);
}
else {
IsTextPropertySetByContent(node, aProperty, aAttribute, aValue, isSet,
getter_AddRefs(resultNode), &theValue);
}
if (firstValue != theValue)
*aAll = PR_FALSE;
}
@ -1085,6 +1220,10 @@ nsresult nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsARea
PRBool isCollapsed;
selection->GetIsCollapsed(&isCollapsed);
PRBool useCSS;
IsCSSEnabled(&useCSS);
if (isCollapsed)
{
// manipulating text attributes on a collapsed selection only sets state for the next text insertion
@ -1142,6 +1281,32 @@ nsresult nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsARea
if ((startNode == endNode) && IsTextNode(startNode))
{
// we're done with this range!
if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(startNode, aProperty, aAttribute)) {
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for startNode
nsAutoString cssValue;
PRBool isSet = PR_FALSE;
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(startNode,
aProperty,
aAttribute,
isSet ,
cssValue,
COMPUTED_STYLE_TYPE);
if (isSet) {
// startNode's computed style indicates the CSS equivalence to the HTML style to
// remove is applied; but we found no element in the ancestors of startNode
// carrying specified styles; assume it comes from a rule and let's try to
// insert a span "inverting" the style
nsAutoString value; value.AssignWithConversion("-moz-editor-invert-value");
PRInt32 startOffset, endOffset;
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(startNode);
if (mHTMLCSSUtils->IsCSSInvertable(aProperty, aAttribute)) {
SetInlinePropertyOnTextNode(nodeAsText, startOffset, endOffset, aProperty, aAttribute, &value);
}
}
}
}
else
{
@ -1189,6 +1354,28 @@ nsresult nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsARea
node = do_QueryInterface(isupports);
res = RemoveStyleInside(node, aProperty, aAttribute);
if (NS_FAILED(res)) return res;
if (useCSS && mHTMLCSSUtils->IsCSSEditableProperty(node, aProperty, aAttribute)) {
// the HTML style defined by aProperty/aAttribute has a CSS equivalence
// in this implementation for node
nsAutoString cssValue;
PRBool isSet = PR_FALSE;
mHTMLCSSUtils->IsCSSEquivalentToHTMLInlineStyleSet(node,
aProperty,
aAttribute,
isSet ,
cssValue,
COMPUTED_STYLE_TYPE);
if (isSet) {
// startNode's computed style indicates the CSS equivalence to the HTML style to
// remove is applied; but we found no element in the ancestors of startNode
// carrying specified styles; assume it comes from a rule and let's try to
// insert a span "inverting" the style
if (mHTMLCSSUtils->IsCSSInvertable(aProperty, aAttribute)) {
nsAutoString value; value.AssignWithConversion("-moz-editor-invert-value");
SetInlinePropertyOnNode(node, aProperty, aAttribute, &value);
}
}
}
arrayOfNodes->RemoveElementAt(0);
}
}
@ -1239,6 +1426,21 @@ nsHTMLEditor::RelativeFontChange( PRInt32 aSizeChange)
nsCOMPtr<nsIAtom> atom;
if (aSizeChange==1) atom = nsIEditProperty::big;
else atom = nsIEditProperty::small;
// Let's see in what kind of element the selection is
PRInt32 offset;
nsCOMPtr<nsIDOMNode> selectedNode;
res = GetStartNodeAndOffset(selection, address_of(selectedNode), &offset);
if (IsTextNode(selectedNode)) {
nsCOMPtr<nsIDOMNode> parent;
res = selectedNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
selectedNode = parent;
}
nsAutoString tag;
atom->ToString(tag);
if (!CanContainTag(selectedNode, tag)) return NS_OK;
// manipulating text attributes on a collapsed selection only sets state for the next text insertion
return mTypeInState->SetProp(atom, nsAutoString(), nsAutoString());
}
@ -1388,6 +1590,11 @@ nsHTMLEditor::RelativeFontChangeOnTextNode( PRInt32 aSizeChange,
if (aStartOffset == aEndOffset) return NS_OK;
nsresult res = NS_OK;
nsCOMPtr<nsIDOMNode> parent;
res = aTextNode->GetParentNode(getter_AddRefs(parent));
if (NS_FAILED(res)) return res;
if (!CanContainTag(parent, NS_LITERAL_STRING("big"))) return NS_OK;
nsCOMPtr<nsIDOMNode> tmp, node = do_QueryInterface(aTextNode);
// do we need to split the text node?
@ -1501,6 +1708,7 @@ nsHTMLEditor::RelativeFontChangeHelper( PRInt32 aSizeChange,
}
}
}
return res;
}
@ -1656,3 +1864,19 @@ nsHTMLEditor::GetFontColorState(PRBool *aMixed, nsAWritableString &aOutColor)
return res;
}
// the return value is true only if the instance of the HTML editor we created
// can handle CSS styles (for instance, Composer can, Messenger can't) and if
// the CSS preference is checked
nsresult
nsHTMLEditor::IsCSSEnabled(PRBool *aIsSet)
{
*aIsSet = PR_FALSE;
if (mCSSAware) {
// TBD later : removal of mCSSAware and use only the presence of mHTMLCSSUtils
if (mHTMLCSSUtils) {
*aIsSet = mHTMLCSSUtils->IsCSSPrefChecked();
}
}
return NS_OK;
}

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -254,6 +255,15 @@ nsPlaintextEditor::EndEditorInit()
return res;
}
nsresult
nsPlaintextEditor::IsCSSEnabled(PRBool *aIsSet)
{
// STUB
*aIsSet = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsPlaintextEditor::SetDocumentCharacterSet(const nsAReadableString & characterSet)
{
@ -2104,3 +2114,11 @@ void nsPlaintextEditor::HandleEventListenerError()
#pragma mark -
#endif
nsresult
nsPlaintextEditor::SetCSSEquivalentToHTMLStyle(nsIDOMElement * aElement,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue)
{
// STUB
return NS_OK;
}

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -106,6 +107,10 @@ public:
/* ------------ Overrides of nsEditor interface methods -------------- */
NS_IMETHOD BeginComposition(nsTextEventReply* aReply);
NS_IMETHOD IsCSSEnabled(PRBool *aIsSet);
NS_IMETHOD SetCSSEquivalentToHTMLStyle(nsIDOMElement * aElement,
const nsAReadableString & aAttribute,
const nsAReadableString & aValue);
/** prepare the editor for use */
NS_IMETHOD Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell, nsIContent *aRoot, nsISelectionController *aSelCon, PRUint32 aFlags);

Просмотреть файл

@ -1291,6 +1291,20 @@
<FILEKIND>Library</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -1558,6 +1572,16 @@
<PATH>UnicharUtilsStaticDebug.o</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -2791,6 +2815,20 @@
<FILEKIND>Library</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -3053,6 +3091,16 @@
<PATH>UnicharUtilsStatic.o</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -4202,6 +4250,20 @@
<FILEKIND>Library</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -4404,6 +4466,16 @@
<PATH>UnicharUtilsStaticDebug.o</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
<TARGET>
@ -5553,6 +5625,20 @@
<FILEKIND>Library</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
<FILE>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
<FILEKIND>Text</FILEKIND>
<FILEFLAGS>Debug</FILEFLAGS>
</FILE>
</FILELIST>
<LINKORDER>
<FILEREF>
@ -5755,6 +5841,16 @@
<PATH>UnicharUtilsStatic.o</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
</LINKORDER>
</TARGET>
</TARGETLIST>
@ -5774,6 +5870,12 @@
<PATH>ChangeAttributeTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>HTMLEditorDebug.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>ChangeCSSInlineStyleTxn.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>HTMLEditorDebug.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
@ -5922,6 +6024,12 @@
<PATH>nsEditProperty.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>HTMLEditorDebug.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>
<PATH>nsHTMLCSSUtils.cpp</PATH>
<PATHFORMAT>MacOS</PATHFORMAT>
</FILEREF>
<FILEREF>
<TARGETNAME>HTMLEditorDebug.shlb</TARGETNAME>
<PATHTYPE>Name</PATHTYPE>

Просмотреть файл

@ -75,3 +75,6 @@ pref("editor.history.url_maximum", 10);
pref("editor.quotesPreformatted", true);
pref("editor.publish.", "");
pref("editor.use_css", false);
pref("editor.css.default_length_unit", "px");

Просмотреть файл

@ -24,6 +24,7 @@
* Dan Haddix (dan6992@hotmail.com)
* John Ratke (jratke@owc.net)
* Ryan Cassin (rcassin@supernova.org)
* Daniel Glazman (glazman@netscape.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -71,6 +72,7 @@ var gIsHTMLEditor = false;
var gColorObj = new Object();
var gDefaultTextColor = "";
var gDefaultBackgroundColor = "";
var gCSSPrefListener;
var gPrefs;
// These must be kept in synch with the XUL <options> lists
@ -78,6 +80,59 @@ var gFontSizeNames = new Array("xx-small","x-small","small","medium","large","x-
const nsIFilePicker = Components.interfaces.nsIFilePicker;
function nsButtonPrefListener()
{
try {
var pbi = pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
pbi.addObserver(this.domain, this, false);
} catch(ex) {
dump("Failed to observe prefs: " + ex + "\n");
}
}
// implements nsIObserver
nsButtonPrefListener.prototype =
{
domain: "editor.use_css",
observe: function(subject, topic, prefName)
{
dump("FOOOOO\n");
// verify that we're changing a button pref
if (topic != "nsPref:changed") return;
if (prefName.substr(0, this.domain.length) != this.domain) return;
var button = document.getElementById("cmd_highlight");
var mixedObj = new Object();
if (button) {
var prefs = GetPrefs();
var useCSS = prefs.getBoolPref(prefName);
if (useCSS) {
button.removeAttribute("disabled");
var state = editorShell.editor.QueryInterface(Components.interfaces.nsIHTMLEditor).GetHighlightColor(mixedObj);
button.setAttribute("state", state);
}
else {
button.setAttribute("disabled", "true");
button.setAttribute("state", "transparent");
}
editorShell.CSSPrefChangedCallback(useCSS);
}
}
}
function AfterHighlightColorChange()
{
var button = document.getElementById("cmd_highlight");
var mixedObj = new Object();
if (button) {
var state = editorShell.editor.QueryInterface(Components.interfaces.nsIHTMLEditor).GetHighlightColor(mixedObj);
button.setAttribute("state", state);
onHighlightColorChange();
}
}
function EditorOnLoad()
{
// See if argument was passed.
@ -241,6 +296,8 @@ function EditorStartup(editorType, editorElement)
// such as file-related commands, HTML Source editing, Edit Modes...
SetupComposerWindowCommands();
gCSSPrefListener = new nsButtonPrefListener();
// Get url for editor content and load it.
// the editor gets instantiated by the editor shell when the URL has finished loading.
var url = document.getElementById("args").getAttribute("value");
@ -309,6 +366,7 @@ function EditorSharedStartup()
// For new window, no default last-picked colors
gColorObj.LastTextColor = "";
gColorObj.LastBackgroundColor = "";
gColorObj.LastHighlightColor = "";
}
function _EditorNotImplemented()
@ -777,6 +835,23 @@ function initFontSizeMenu(menuPopup)
}
}
function onHighlightColorChange()
{
var commandNode = document.getElementById("cmd_highlight");
if (commandNode)
{
var color = commandNode.getAttribute("state");
var button = document.getElementById("HighlightColorButton");
if (button)
{
// No color set - get color set on page or other defaults
if (!color)
color = "transparent" ;
button.setAttribute("style", "background-color:"+color+" !important");
}
}
}
function onFontColorChange()
{
var commandNode = document.getElementById("cmd_fontColor");
@ -861,7 +936,8 @@ function GetBackgroundElementWithColor()
var element = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj);
if (element && tagNameObj && tagNameObj.value)
{
gColorObj.BackgroundColor = element.getAttribute("bgcolor");
gColorObj.BackgroundColor = GetHTMLOrCSSStyleValue(element, "bgcolor", "background-color");
gColorObj.BackgroundColor = ConvertRGBColorIntoHEXColor(gColorObj.BackgroundColor);
if (tagNameObj.value.toLowerCase() == "td")
{
gColorObj.Type = "Cell";
@ -869,7 +945,8 @@ function GetBackgroundElementWithColor()
// Get any color that might be on parent table
var table = GetParentTable(element);
gColorObj.TableColor = table.getAttribute("bgcolor");
gColorObj.TableColor = GetHTMLOrCSSStyleValue(table, "bgcolor", "background-color");
gColorObj.TableColor = ConvertRGBColorIntoHEXColor(gColorObj.TableColor);
}
else
{
@ -879,11 +956,39 @@ function GetBackgroundElementWithColor()
}
else
{
element = GetBodyElement();
var prefs = GetPrefs();
var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
var element;
if (IsCSSPrefChecked && editorShell.editorType == "html")
{
var selection = window.editorShell.editorSelection;
if (selection)
{
element = selection.focusNode;
while (!window.editorShell.NodeIsBlock(element))
element = element.parentNode;
}
else
{
element = GetBodyElement();
}
}
else
{
element = GetBodyElement();
}
if (element)
{
gColorObj.Type = "Page";
gColorObj.BackgroundColor = element.getAttribute("bgcolor");
gColorObj.BackgroundColor = GetHTMLOrCSSStyleValue(element, "bgcolor", "background-color");
if (gColorObj.BackgroundColor == "")
{
gColorObj.BackgroundColor = "transparent";
}
else
{
gColorObj.BackgroundColor = ConvertRGBColorIntoHEXColor(gColorObj.BackgroundColor);
}
gColorObj.PageColor = gColorObj.BackgroundColor;
}
}
@ -926,6 +1031,20 @@ function EditorSelectColor(colorType, mouseEvent)
else
useLastColor = false;
}
else if (colorType == "Highlight")
{
gColorObj.Type = colorType;
// Get color from command node state
commandNode = document.getElementById("cmd_highlight");
currentColor = commandNode.getAttribute("state");
gColorObj.HighlightColor = currentColor;
if (useLastColor && gColorObj.LastHighlightColor )
gColorObj.HighlightColor = gColorObj.LastHighlightColor;
else
useLastColor = false;
}
else
{
element = GetBackgroundElementWithColor();
@ -980,7 +1099,7 @@ function EditorSelectColor(colorType, mouseEvent)
return;
}
if (colorType == "Text")
if (gColorObj.Type == "Text")
{
if (currentColor != gColorObj.TextColor)
{
@ -992,9 +1111,21 @@ function EditorSelectColor(colorType, mouseEvent)
// Update the command state (this will trigger color button update)
goUpdateCommand("cmd_fontColor");
}
else if (gColorObj.Type == "Highlight")
{
if (currentColor != gColorObj.HighlightColor)
{
if (gColorObj.HighlightColor)
window.editorShell.SetTextProperty("font", "bgcolor", gColorObj.HighlightColor);
else
window.editorShell.RemoveTextProperty("font", "bgcolor");
}
// Update the command state (this will trigger color button update)
goUpdateCommand("cmd_highlight");
}
else if (element)
{
if (gColorObj.Type == "Table")
if (false /*gColorObj.Type == "Table"*/)
{
// Set background on a table
// Note that we shouldn't trust "currentColor" because of "TableOrCell" behavior
@ -1024,7 +1155,7 @@ function EditorSelectColor(colorType, mouseEvent)
{
var defColors = GetDefaultBrowserColors();
if (defColors)
{
{ // GLAZOU : this has to be changed
if (!bodyelement.getAttribute("text"))
window.editorShell.SetAttribute(bodyelement, "text", defColors.TextColor);
@ -2428,3 +2559,22 @@ function SwitchInsertCharToAnotherEditorOrClose()
}
}
function GetHTMLOrCSSStyleValue(element, attrName, cssPropertyName)
{
var prefs = GetPrefs();
var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
var value;
if (IsCSSPrefChecked && editorShell.editorType == "html")
{
value = element.style.getPropertyValue(cssPropertyName);
if (value == "") {
value = element.getAttribute(attrName);
}
}
else
{
value = element.getAttribute(attrName);
}
return value;
}

Просмотреть файл

@ -181,6 +181,10 @@
<!-- from editorOverlay -->
<menulist id="ParagraphSelect"/>
<stack id="ColorButtons"/>
<toolbarbutton id="HighlightColorButton"/>
<toolbarseparator class="toolbarseparator-standard"/>
<toolbarbutton id="DecreaseFontSizeButton"/>
<toolbarbutton id="IncreaseFontSizeButton"/>

Просмотреть файл

@ -20,6 +20,7 @@
-
- Contributor(s):
- Ryan Cassin (rcassin@supernova.org)
- Daniel Glazman (glazman@netscape.com)
-->
<!DOCTYPE window SYSTEM "chrome://editor/locale/editorOverlay.dtd">
@ -202,6 +203,7 @@
<!-- No "oncommand", use EditorSelectColor() to bring up color dialog -->
<command id="cmd_fontColor" state=""/>
<command id="cmd_backgroundColor" state=""/>
<command id="cmd_highlight" state="transparent" oncommand="EditorSelectColor('Highlight', event);"/>
<command id="cmd_fontSize" state="" oncommand="goDoCommand('cmd_fontSize')"/>
<command id="cmd_align" state=""/>
@ -748,6 +750,10 @@
onclick="EditorSelectColor('Text', event);"
tooltiptext="&TextColorButton.tooltip;"/>
</stack>
<toolbarbutton id="HighlightColorButton" tooltip="aTooltip"
tooltiptext="&HighlightColorButton.tooltip;" command="cmd_highlight">
<observes element="cmd_highlight" attribute="state" onbroadcast="onHighlightColorChange()"/>
</toolbarbutton>
<!-- A BUG IN CSS/BOXES MAKES THIS ASSERT WHEN CLASS= IS PRESENT AND WE TRY TO COLLAPSE THE TOOLBOX -->
<toolbarbutton id="DecreaseFontSizeButton" observes="cmd_decreaseFont"

Просмотреть файл

@ -20,6 +20,7 @@
* Contributor(s):
* Pete Collins
* Brian King
* Daniel Glazman <glazman@netscape.com>
*/
/*
if we ever need to use a different string bundle, use srGetStrBundle
@ -664,3 +665,43 @@ function GetOS()
return gOS;
}
function ConvertRGBColorIntoHEXColor(color)
{
if (color.search( /rgb.*/ ) != -1)
{
res = color.match( /rgb\((\d*),(\d*),(\d*)\)/ );
r = Number(RegExp.$1).toString(16);
if (r.length == 1) r = "0"+r;
v = Number(RegExp.$2).toString(16);
if (v.length == 1) v = "0"+v;
b = Number(RegExp.$3).toString(16);
if (b.length == 1) b = "0"+b;
return "#"+r+v+b;
}
else
{
return color;
}
}
function GetHTMLOrCSSStyleValue(element, attrName, cssPropertyName)
{
var prefs = GetPrefs();
var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
var value;
if (IsCSSPrefChecked && editorShell.editorType == "html")
{
value = element.style.getPropertyValue(cssPropertyName);
if (value == "") {
value = element.getAttribute(attrName);
}
}
else
{
value = element.getAttribute(attrName);
}
if (value == null) {
value = "";
}
return value;
}

Просмотреть файл

@ -34,7 +34,7 @@
<script type="application/x-javascript">
<!-- Add "shouldAutoSave", "autoSaveAmount" to _elementIDs when implemented -->
<![CDATA[
var _elementIDs = ["maintainTableStructure", "preserveFormatting", "recentFiles"];
var _elementIDs = ["maintainTableStructure", "preserveFormatting", "recentFiles", "useCSS"];
]]>
</script>
<script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
@ -155,4 +155,16 @@
</groupbox>
-->
<groupbox>
<caption label="&cssEditing.label;"/>
<checkbox
label = "&useCSS.label;"
id = "useCSS"
accesskey = ""
pref = "true"
preftype = "bool"
prefstring= "editor.use_css"
prefattribute="checked"
/>
</groupbox>
</page>

Просмотреть файл

@ -101,7 +101,9 @@ SaveToUseRelativeUrl=Relative URLs can only be used on pages which have been sav
NoNamedAnchors=(No named anchors in this page)
NoHeadings=(No headings without anchors)
TextColor=Text Color
HighlightColor=Highlight Color
PageColor=Page Background Color
BlockColor=Block Background Color
TableColor=Table Background Color
CellColor=Cell Background Color
TableOrCellColor=Table or Cell Color

Просмотреть файл

@ -595,6 +595,7 @@
<!ENTITY TextColorButton.tooltip "Choose color for text">
<!ENTITY BackgroundColorButton.tooltip "Choose color for background">
<!ENTITY throbber.tooltip "Go to the &vendorShortName; home page">
<!ENTITY HighlightColorButton.tooltip "Choose highlight color for text">
<!-- editor toolbar -->
<!ENTITY decreaseFontSizeToolbarCmd.tooltip "Smaller font size">

Просмотреть файл

@ -31,3 +31,6 @@
<!ENTITY recentFiles.title "Recent Pages Menu">
<!ENTITY documentsInMenu "Maximum number of pages listed:">
<!ENTITY cssEditing.label "CSS Editing">
<!ENTITY useCSS.label "Use CSS (Cascading Style Sheets) styles instead of HTML elements and attributes">

Просмотреть файл

@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
* Daniel Glazman (glazman@netscape.com)
*/
@ -28,6 +29,7 @@ var gColor = "";
var LastPickedColor = "";
var ColorType = "Text";
var TextType = false;
var HighlightType = false;
var TableOrCell = false;
var LastPickedIsDefault = true;
var NoDefault = false;
@ -36,6 +38,8 @@ var gColorObj;
// dialog initialization code
function Startup()
{
// if (!InitEditorShell()) return;
if (!window.arguments[1])
{
dump("EdColorPicker: Missing color object param\n");
@ -64,9 +68,17 @@ function Startup()
ColorType = gColorObj.Type;
// Get string for dialog title from passed-in type
// (note constraint on editor.properties string name)
window.title = GetString(ColorType+"Color");
var prefs = GetPrefs();
var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
if (ColorType == "Page" && IsCSSPrefChecked && editorShell.editorType == "html")
{
window.title = GetString("BlockColor");
}
else
{
window.title = GetString(ColorType+"Color");
}
}
if (!window.title)
window.title = GetString("Color");
@ -107,6 +119,11 @@ function Startup()
gDialog.CellRadio.focus();
}
break;
case "Highlight":
HighlightType = true;
if (gColorObj.HighlightColor)
gColor = gColorObj.HighlightColor;
break;
default:
// Any other type will change some kind of text,
TextType = true;
@ -127,6 +144,12 @@ function Startup()
gColorObj.LastTextColor = gDialog.LastPickedColor.getAttribute("LastTextColor");
LastPickedColor = gColorObj.LastTextColor;
}
else if (HighlightType)
{
if ( !("LastHighlightColor" in gColorObj) || !gColorObj.LastHighlightColor)
gColorObj.LastHighlightColor = gDialog.LastPickedColor.getAttribute("LastHighlightColor");
LastPickedColor = gColorObj.LastHighlightColor;
}
else
{
if ( !("LastBackgroundColor" in gColorObj) || !gColorObj.LastBackgroundColor)
@ -265,6 +288,15 @@ function onAccept()
gColorObj.LastTextColor = gColor;
}
}
else if (HighlightType)
{
gColorObj.HighlightColor = gColor;
if (gColor.length > 0)
{
gDialog.LastPickedColor.setAttribute("LastHighlightColor", gColor);
gColorObj.LastHighlightColor = gColor;
}
}
else
{
gColorObj.BackgroundColor = gColor;

Просмотреть файл

@ -49,9 +49,12 @@ const vlinkStr = "vlink";
const alinkStr = "alink";
const bgcolorStr = "bgcolor";
const backgroundStr = "background";
const colorStyle = "color: ";
const backColorStyle = "background-color: ";
const backImageStyle = "; background-image: url(";
const cssColorStr = "color";
const cssBackgroundColorStr = "background-color";
const cssBackgroundImageStr = "background-image";
const colorStyle = cssColorStr + ": ";
const backColorStyle = cssBackgroundColorStr + ": ";
const backImageStyle = "; " + cssBackgroundImageStr + ": url(";
var customTextColor;
var customLinkColor;
@ -113,7 +116,12 @@ function Startup()
function InitDialog()
{
// Get image from document
backgroundImage = globalElement.getAttribute(backgroundStr);
backgroundImage = GetHTMLOrCSSStyleValue(globalElement, backgroundStr, cssBackgroundImageStr);
innerURL = backgroundImage.match( /url\((.*)\)/ ) ;
if (innerURL)
{
backgroundImage = RegExp.$1;
}
if (backgroundImage)
{
gDialog.BackgroundImageInput.value = backgroundImage;
@ -122,11 +130,13 @@ function InitDialog()
SetRelativeCheckbox();
customTextColor = globalElement.getAttribute(textStr);
customTextColor = GetHTMLOrCSSStyleValue(globalElement, textStr, cssColorStr);
customTextColor = ConvertRGBColorIntoHEXColor(customTextColor);
customLinkColor = globalElement.getAttribute(linkStr);
customActiveColor = globalElement.getAttribute(alinkStr);
customVisitedColor = globalElement.getAttribute(vlinkStr);
customBackgroundColor = globalElement.getAttribute(bgcolorStr);
customBackgroundColor = GetHTMLOrCSSStyleValue(globalElement, bgcolorStr, cssBackgroundColorStr);
customBackgroundColor = ConvertRGBColorIntoHEXColor(customBackgroundColor);
var haveCustomColor =
customTextColor ||

Просмотреть файл

@ -515,11 +515,22 @@ function LimitStringLength(elementID, length)
editField.value = stringIn.slice(0,length);
}
function StripPxUnit(value)
{
var pxIndex = value.search(/px/);
if (pxIndex > 0) {
// Strip out the unit
value = value.substr(0, pxIndex);
}
return value;
}
function InitPixelOrPercentMenulist(elementForAtt, elementInDoc, attribute, menulistID, defaultIndex)
{
if (!defaultIndex) defaultIndex = gPixel;
var size = elementForAtt.getAttribute(attribute);
// var size = elementForAtt.getAttribute(attribute);
var size = GetHTMLOrCSSStyleValue(elementForAtt, attribute, attribute)
var menulist = document.getElementById(menulistID);
var pixelItem;
var percentItem;
@ -538,8 +549,9 @@ function InitPixelOrPercentMenulist(elementForAtt, elementInDoc, attribute, menu
percentItem = AppendStringToMenulist(menulist, GetAppropriatePercentString(elementForAtt, elementInDoc));
if (size && size.length > 0)
{
// Search for a "%" character
// Search for a "%" or "px"
var percentIndex = size.search(/%/);
var pxIndex = size.search(/px/);
if (percentIndex > 0)
{
// Strip out the %
@ -547,6 +559,12 @@ function InitPixelOrPercentMenulist(elementForAtt, elementInDoc, attribute, menu
if (percentItem)
menulist.selectedItem = percentItem;
}
else if (pxIndex > 0)
{
// Strip out the %
size = size.substr(0, pxIndex);
menulist.selectedItem = pixelItem;
}
else
menulist.selectedItem = pixelItem;
}

Просмотреть файл

@ -71,8 +71,10 @@ function Startup()
// by AdvancedEdit(), which is shared by all property dialogs
function InitDialog()
{
// Just to be confusing, "size" is used instead of height
var height = globalElement.getAttribute("size");
// Just to be confusing, "size" is used instead of height because it does
// not accept % values, only pixels
var height = GetHTMLOrCSSStyleValue(globalElement, "size", "height")
height = StripPxUnit(height);
if(!height) {
height = 2; //Default value
}
@ -84,24 +86,21 @@ function InitDialog()
// This sets contents of menulist (adds pixel and percent menuitems elements)
gDialog.widthInput.value = InitPixelOrPercentMenulist(globalElement, hLineElement, "width","pixelOrPercentMenulist");
align = globalElement.getAttribute("align");
if (!align)
align = "";
align = align.toLowerCase();
var marginLeft = GetHTMLOrCSSStyleValue(globalElement, "align", "margin-left").toLowerCase();
var marginRight = GetHTMLOrCSSStyleValue(globalElement, "align", "margin-right").toLowerCase();
align = marginLeft + " " + marginRight;
gDialog.centerAlign.checked = (align == "center center" || align == "auto auto");
gDialog.rightAlign.checked = (align == "right right" || align == "auto 0px");
gDialog.leftAlign.checked = (align == "left left" || align == "0px auto" || align == " ");
var selectedRadio = gDialog.centerAlign;
var radioGroup = gDialog.centerAlign.radioGroup
switch (align)
{
case "left":
gDialog.alignGroup.selectedItem = gDialog.leftAlign;
break;
case "right":
gDialog.alignGroup.selectedItem = gDialog.rightAlign;
break;
default:
gDialog.alignGroup.selectedItem = gDialog.centerAlign;
break;
if (gDialog.centerAlign.checked) {
gDialog.alignGroup.selectedItem = gDialog.centerAlign;
}
else if (gDialog.rightAlign.checked) {
gDialog.alignGroup.selectedItem = gDialog.rightAlign;
}
else {
gDialog.alignGroup.selectedItem = gDialog.leftAlign;
}
// This is tricky! Since the "noshade" attribute doesn't always have a value,

Просмотреть файл

@ -185,7 +185,28 @@ function InitDialog()
// set spacing editfields
gDialog.imagelrInput.value = globalElement.getAttribute("hspace");
gDialog.imagetbInput.value = globalElement.getAttribute("vspace");
gDialog.border.value = globalElement.getAttribute("border");
// dialog.border.value = globalElement.getAttribute("border");
bv = GetHTMLOrCSSStyleValue(globalElement, "border", "border-top-width");
var pxIndex = bv.search(/px/);
if (pxIndex > 0)
{
// Strip out the px
bv = bv.substr(0, pxIndex);
}
else if (bv == "thin")
{
bv = "1";
}
else if (bv == "medium")
{
bv = "3";
}
else if (bv == "thick")
{
bv = "5";
}
gDialog.border.value = bv;
// Get alignment setting
var align = globalElement.getAttribute("align");

Просмотреть файл

@ -30,6 +30,7 @@ var maxColumns = 10000;
var maxPixels = 10000;
var rows;
var columns;
var prefs = GetPrefs();
// dialog initialization code
function Startup()
@ -53,7 +54,10 @@ function Startup()
// Make a copy to use for AdvancedEdit
globalElement = tableElement.cloneNode(false);
if (prefs.getBoolPref("editor.use_css") && (editorShell.editorType == "html")) {
// only for Composer and not for htmlmail
globalElement.setAttribute("style", "text-align: left;");
}
// Initialize all widgets with image attributes
InitDialog();

Просмотреть файл

@ -93,14 +93,15 @@ function InitDialog()
BuildBulletStyleList();
gDialog.StartingNumberInput.value = "";
var type = globalElement ? globalElement.getAttribute("type") : null;
var type = globalElement ? GetHTMLOrCSSStyleValue(globalElement, "type", "list-style-type") : null;
if (type)
type = type.toLowerCase();
var index = 0;
if (ListType == "ul")
{
if (type)
{
type = type.toLowerCase();
if (type == "disc")
index = 1;
else if (type == "circle")
@ -114,18 +115,23 @@ function InitDialog()
switch (type)
{
case "1":
case "decimal":
index = 1;
break;
case "I":
case "upper-roman":
index = 2;
break;
case "i":
case "lower-roman":
index = 3;
break;
case "A":
case "upper-alpha":
index = 4;
break;
case "a":
case "lower-alpha":
index = 5;
break;
}

Просмотреть файл

@ -44,6 +44,8 @@ var bgcolor = "bgcolor";
var TableColor;
var CellColor;
const cssBackgroundColorStr = "background-color";
var rowCount = 1;
var colCount = 1;
var lastRowIndex;
@ -81,6 +83,8 @@ var maxColumns = 1000;
var selection;
var CellDataChanged = false;
var canDelete = false;
var gPrefs = GetPrefs();
var gUseCSS = true;
// dialog initialization code
function Startup()
@ -95,6 +99,15 @@ function Startup()
gDialog.TableColumnsInput = document.getElementById("TableColumnsInput");
gDialog.TableWidthInput = document.getElementById("TableWidthInput");
gDialog.TableWidthUnits = document.getElementById("TableWidthUnits");
gDialog.TableHeightInput = document.getElementById("TableHeightInput");
gDialog.TableHeightUnits = document.getElementById("TableHeightUnits");
if (!gPrefs.getBoolPref("editor.use_css") || (editorShell.editorType != "html")) {
gUseCSS = false;
tableHeightLabel = document.getElementById("TableHeightLabel");
tableHeightLabel.parentNode.removeChild(tableHeightLabel);
gDialog.TableHeightInput.parentNode.removeChild(gDialog.TableHeightInput);
gDialog.TableHeightUnits.parentNode.removeChild(gDialog.TableHeightUnits);
}
gDialog.BorderWidthInput = document.getElementById("BorderWidthInput");
gDialog.SpacingInput = document.getElementById("SpacingInput");
gDialog.PaddingInput = document.getElementById("PaddingInput");
@ -264,15 +277,20 @@ function InitDialog()
gDialog.TableRowsInput.value = rowCount;
gDialog.TableColumnsInput.value = colCount;
gDialog.TableWidthInput.value = InitPixelOrPercentMenulist(globalTableElement, TableElement, "width", "TableWidthUnits", gPercent);
if (gUseCSS) {
gDialog.TableHeightInput.value = InitPixelOrPercentMenulist(globalTableElement, TableElement, "height",
"TableHeightUnits", gPercent);
}
gDialog.BorderWidthInput.value = globalTableElement.border;
gDialog.SpacingInput.value = globalTableElement.cellSpacing;
gDialog.PaddingInput.value = globalTableElement.cellPadding;
//BUG: The align strings are converted: e.g., "center" becomes "Center";
var halign = globalTableElement.align.toLowerCase();
if (halign == centerStr)
var marginLeft = GetHTMLOrCSSStyleValue(globalTableElement, "align", "margin-left");
var marginRight = GetHTMLOrCSSStyleValue(globalTableElement, "align", "margin-right");
var halign = marginLeft.toLowerCase() + " " + marginRight.toLowerCase();
if (halign == "center center" || halign == "auto auto")
gDialog.TableAlignList.selectedIndex = 1;
else if (halign == rightStr)
else if (halign == "right right" || halign == "auto 0px")
gDialog.TableAlignList.selectedIndex = 2;
else // Default = left
gDialog.TableAlignList.selectedIndex = 0;
@ -291,7 +309,8 @@ function InitDialog()
}
gDialog.TableCaptionList.selectedIndex = index;
TableColor = globalTableElement.bgColor;
TableColor = GetHTMLOrCSSStyleValue(globalTableElement, bgcolor, cssBackgroundColorStr);
TableColor = ConvertRGBColorIntoHEXColor(TableColor);
SetColor("tableBackgroundCW", TableColor);
InitCellPanel();
@ -329,7 +348,7 @@ function InitCellPanel()
alignWasChar = false;
var halign = globalCellElement.align.toLowerCase();
var halign = GetHTMLOrCSSStyleValue(globalCellElement, "align", "text-align").toLowerCase();
switch (halign)
{
case centerStr:
@ -362,13 +381,17 @@ function InitCellPanel()
gDialog.CellStyleCheckbox.checked = AdvancedEditUsed && previousIndex != gDialog.CellStyleList.selectedIndex;
previousIndex = gDialog.TextWrapList.selectedIndex;
gDialog.TextWrapList.selectedIndex = globalCellElement.noWrap ? 1 : 0;
if (GetHTMLOrCSSStyleValue(globalCellElement, "nowrap", "white-space") == "nowrap")
gDialog.TextWrapList.selectedIndex = 1;
else
gDialog.TextWrapList.selectedIndex = 0;
gDialog.TextWrapCheckbox.checked = AdvancedEditUsed && previousIndex != gDialog.TextWrapList.selectedIndex;
previousValue = CellColor;
SetColor("cellBackgroundCW", globalCellElement.bgColor);
gDialog.CellColorCheckbox.checked = AdvancedEditUsed && CellColor != globalCellElement.bgColor;
CellColor = globalCellElement.bgColor;
CellColor = GetHTMLOrCSSStyleValue(globalCellElement, bgcolor, cssBackgroundColorStr);
CellColor = ConvertRGBColorIntoHEXColor(CellColor);
SetColor("cellBackgroundCW", CellColor);
gDialog.CellColorCheckbox.checked = AdvancedEditUsed && previousValue != CellColor;
// We want to set this true in case changes came
// from Advanced Edit dialog session (must assume something changed)
@ -816,6 +839,12 @@ function ValidateTableData()
1, maxPixels, globalTableElement, "width");
if (gValidationError) return false;
if (gUseCSS) {
ValidateNumber(gDialog.TableHeightInput, gDialog.TableHeightUnits,
1, maxPixels, globalTableElement, "height");
if (gValidationError) return false;
}
var border = ValidateNumber(gDialog.BorderWidthInput, null, 0, maxPixels, globalTableElement, "border");
// TODO: Deal with "BORDER" without value issue
if (gValidationError) return false;
@ -950,7 +979,6 @@ function ChangeIntTextbox(textboxID, checkboxID)
function CloneAttribute(destElement, srcElement, attr)
{
var value = srcElement.getAttribute(attr);
// Use editorShell methods since we are always
// modifying a table in the document and
// we need transaction system for undo

Просмотреть файл

@ -57,23 +57,20 @@
<vbox id="TablePanel">
<groupbox orient="horizontal"><caption label="&size.label;"/>
<grid>
<columns><column/><column/></columns>
<rows>
<row align="center">
<label value="&tableRows.label;"/>
<textbox class="narrow" id="TableRowsInput" oninput="forceInteger(this.id);"/>
</row>
<row align="center">
<label value="&tableColumns.label;"/>
<textbox class="narrow" id="TableColumnsInput" oninput="forceInteger(this.id);"/>
</row>
</rows>
</grid>
<spacer class="bigspacer"/>
<grid>
<columns><column/><column/><column flex="1"/></columns>
<rows>
<columns><column/><column/><column/><column/><column/></columns>
<rows>
<row align="center">
<text class="label" value="&tableRows.label;"/>
<textbox class="narrow" id="TableRowsInput" oninput="forceInteger(this.id);"/>
<spring class="bigspacer"/>
<text class="label" value="&tableHeight.label;" id="TableHeightLabel"/>
<textbox class="narrow" id="TableHeightInput" oninput="forceInteger(this.id);"/>
<menulist id="TableHeightUnits"/>
</row>
<row align="center">
<text class="label" value="&tableColumns.label;"/>
<textbox class="narrow" id="TableColumnsInput" oninput="forceInteger(this.id);"/>
<spring class="bigspacer"/>
<label value="&tableWidth.label;"/>
<textbox class="narrow" id="TableWidthInput" oninput="forceInteger(this.id);"/>
<menulist id="TableWidthUnits"/>

Просмотреть файл

@ -75,3 +75,6 @@ pref("editor.history.url_maximum", 10);
pref("editor.quotesPreformatted", true);
pref("editor.publish.", "");
pref("editor.use_css", false);
pref("editor.css.default_length_unit", "px");

Просмотреть файл

@ -473,3 +473,22 @@
margin: 9px 2px 2px 9px;
}
#HighlightColorButton {
-moz-image-region: rect(260px 16px 272px 0px);
background-color: transparent;
}
#HighlightColorButton:hover {
-moz-image-region: rect(260px 32px 272px 16px);
}
#HighlightColorButton:hover:active {
-moz-image-region: rect(260px 48px 272px 32px);
}
#HighlightColorButton[disabled="true"],
#HighlightColorButton[disabled="true"]:hover,
#HighlightColorButton[disabled="true"]:hover:active {
-moz-image-region: rect(260px 64px 272px 48px);
}

Двоичные данные
themes/classic/editor/icons/btn2.gif

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.1 KiB

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Просмотреть файл

@ -494,3 +494,29 @@
margin: 9px 2px 2px 9px;
}
#HighlightColorButton > .toolbarbutton-icon {
margin-right: 0px ! important ;
}
#HighlightColorButton {
-moz-image-region: rect(355px 44px 372px 22px);
margin: 4px;
border: 1px inset #5B7693;
padding: 0px;
width: 20px; height: 17px;
}
#HighlightColorButton:hover {
-moz-image-region: rect(355px 66px 372px 44px);
}
#HighlightColorButton:hover:active {
-moz-image-region: rect(355px 88px 372px 66px);
}
#HighlightColorButton[disabled="true"],
#HighlightColorButton[disabled="true"]:hover,
#HighlightColorButton[disabled="true"]:hover:active {
-moz-image-region: rect(372px 22px 389px 0px);
}

Двоичные данные
themes/modern/editor/icons/btn2.gif

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 13 KiB

После

Ширина:  |  Высота:  |  Размер: 15 KiB