fix for 142855: cf_html paste functionality. r=brade,cmanske; sr=kin

This commit is contained in:
jfrancis%netscape.com 2002-11-22 03:30:59 +00:00
Родитель d3f58deeab
Коммит 0c756dc3b3
10 изменённых файлов: 457 добавлений и 114 удалений

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

@ -240,6 +240,10 @@
#define NS_HTMLFRAGMENTSINK_CID \
{ 0xd4f2b600, 0xb5c1, 0x11d6, { 0xb4, 0x83, 0xcc, 0x97, 0xc6, 0x3e, 0x56, 0x7c } }
// {13111d00-ce81-11d6-8082-ecf3665af67c}
#define NS_HTMLFRAGMENTSINK2_CID \
{ 0x13111d00, 0xce81, 0x11d6, { 0x80, 0x82, 0xec, 0xf3, 0x66, 0x5a, 0xf6, 0x7c } }
// {3986B301-097C-11d3-BF87-00105A1B0627}
#define NS_XULPOPUPLISTENER_CID \
{ 0x3986b301, 0x97c, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } }

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

@ -240,6 +240,10 @@
#define NS_HTMLFRAGMENTSINK_CID \
{ 0xd4f2b600, 0xb5c1, 0x11d6, { 0xb4, 0x83, 0xcc, 0x97, 0xc6, 0x3e, 0x56, 0x7c } }
// {13111d00-ce81-11d6-8082-ecf3665af67c}
#define NS_HTMLFRAGMENTSINK2_CID \
{ 0x13111d00, 0xce81, 0x11d6, { 0x80, 0x82, 0xec, 0xf3, 0x66, 0x5a, 0xf6, 0x7c } }
// {3986B301-097C-11d3-BF87-00105A1B0627}
#define NS_XULPOPUPLISTENER_CID \
{ 0x3986b301, 0x97c, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } }

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

@ -367,6 +367,7 @@ MAKE_CTOR(CreateXMLContentSerializer, nsIContentSerializer, NS_NewXML
MAKE_CTOR(CreateHTMLContentSerializer, nsIContentSerializer, NS_NewHTMLContentSerializer)
MAKE_CTOR(CreatePlainTextSerializer, nsIContentSerializer, NS_NewPlainTextSerializer)
MAKE_CTOR(CreateHTMLFragmentSink, nsIHTMLFragmentContentSink, NS_NewHTMLFragmentContentSink)
MAKE_CTOR(CreateHTMLFragmentSink2, nsIHTMLFragmentContentSink, NS_NewHTMLFragmentContentSink2)
MAKE_CTOR(CreateSanitizingHTMLSerializer, nsIContentSerializer, NS_NewSanitizingHTMLSerializer)
MAKE_CTOR(CreateXBLService, nsIXBLService, NS_NewXBLService)
MAKE_CTOR(CreateBindingManager, nsIBindingManager, NS_NewBindingManager)
@ -772,6 +773,11 @@ static const nsModuleComponentInfo gComponents[] = {
NS_HTMLFRAGMENTSINK_CONTRACTID,
CreateHTMLFragmentSink },
{ "html fragment sink 2",
NS_HTMLFRAGMENTSINK2_CID,
NS_HTMLFRAGMENTSINK2_CONTRACTID,
CreateHTMLFragmentSink2 },
{ "HTML sanitizing content serializer",
MOZ_SANITIZINGHTMLSERIALIZER_CID,
MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID,

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

@ -164,6 +164,35 @@ public:
nsCOMPtr<nsINodeInfoManager> mNodeInfoManager;
};
class nsHTMLFragmentContentSink2 : public nsHTMLFragmentContentSink
{
public:
nsHTMLFragmentContentSink2() { mHitSentinel = PR_TRUE; mSeenBody = PR_FALSE;}
virtual ~nsHTMLFragmentContentSink2() {}
NS_IMETHODIMP OpenHead(const nsIParserNode& aNode) { return OpenContainer(aNode); }
NS_IMETHODIMP CloseHead(const nsIParserNode& aNode) { return CloseContainer(aNode); }
};
nsresult
NS_NewHTMLFragmentContentSink2(nsIHTMLFragmentContentSink** aResult)
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
nsHTMLFragmentContentSink2* it;
NS_NEWXPCOM(it, nsHTMLFragmentContentSink2);
if (nsnull == it) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv = it->Init();
if (NS_FAILED(rv)) {
delete it;
return rv;
}
return it->QueryInterface(NS_GET_IID(nsIHTMLFragmentContentSink), (void **)aResult);
}
nsresult
NS_NewHTMLFragmentContentSink(nsIHTMLFragmentContentSink** aResult)
@ -386,7 +415,6 @@ nsHTMLFragmentContentSink::CloseHTML()
NS_IMETHODIMP
nsHTMLFragmentContentSink::OpenHead(const nsIParserNode& aNode)
{
// XXX Not likely to get a head in the fragment
return NS_OK;
}

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

@ -48,6 +48,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMAttr.h"
#include "nsIDOMNode.h"
#include "nsIDOMDocumentFragment.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMRange.h"
@ -5118,4 +5119,56 @@ nsEditor::RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
{
return RemoveAttribute(aElement, aAttribute);
}
#if DEBUG_JOE
void
nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
{
PRInt32 i;
for (i=0; i<indent; i++)
printf(" ");
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aNode);
nsCOMPtr<nsIDOMDocumentFragment> docfrag = do_QueryInterface(aNode);
if (element || docfrag)
{
if (element)
{
nsAutoString tag;
char ctag[40];
element->GetTagName(tag);
tag.ToCString(ctag,40);
ctag[40]=0;
printf("<%s>\n", ctag);
}
else
{
printf("<document fragment>\n");
}
nsCOMPtr<nsIDOMNodeList> childList;
aNode->GetChildNodes(getter_AddRefs(childList));
if (!childList) return NS_ERROR_NULL_POINTER;
PRUint32 numChildren;
childList->GetLength(&numChildren);
nsCOMPtr<nsIDOMNode> child, tmp;
aNode->GetFirstChild(getter_AddRefs(child));
for (i=0; i<numChildren; i++)
{
DumpNode(child, indent+1);
child->GetNextSibling(getter_AddRefs(tmp));
child = tmp;
}
}
else if (IsTextNode(aNode))
{
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aNode);
nsAutoString str;
textNode->GetData(str);
char theText[30], *c;
str.ToCString(theText,30);
theText[30]=0;
while (c=strchr(theText,'\n')) (*c) = ' ';
printf("<textnode> %s\n", theText);
}
}
#endif

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

@ -496,6 +496,9 @@ public:
static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *outStartNode, PRInt32 *outStartOffset);
static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsCOMPtr<nsIDOMNode> *outEndNode, PRInt32 *outEndOffset);
#if DEBUG_JOE
static void DumpNode(nsIDOMNode *aNode, PRInt32 indent=0);
#endif
// Helpers to add a node to the selection.
// Used by table cell selection methods

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

@ -103,6 +103,8 @@
#include "nsInternetCiter.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "nsLinebreakConverter.h"
#include "nsIHTMLFragmentContentSink.h"
// netwerk
#include "nsIURI.h"
@ -123,6 +125,7 @@ const PRUnichar nbsp = 160;
static NS_DEFINE_CID(kCRangeCID, NS_RANGE_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
// Drag & Drop, Clipboard Support
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
@ -132,6 +135,10 @@ static NS_DEFINE_CID(kCHTMLFormatConverterCID, NS_HTMLFORMATCONVERTER_CID);
#define kHTMLContext "text/_moz_htmlcontext"
#define kHTMLInfo "text/_moz_htmlinfo"
// some little helpers
static PRInt32 FindPositiveIntegerAfterString(const char *aLeadingString, nsCString &aCStr);
static nsresult RemoveFragComments(nsCString &theStr);
static void RemoveBodyAndHead(nsIDOMNode *aNode);
#if defined(NS_DEBUG) && defined(DEBUG_buster)
static PRBool gNoisy = PR_FALSE;
@ -381,7 +388,7 @@ nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAString & aInputString,
// this is because if there is a br at end of what we paste, it will make
// the invisible br visible.
nsWSRunObject wsObj(this, parentNode, offsetOfNewNode);
if ( nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
if (nsTextEditUtils::IsBreak(wsObj.mEndReasonNode) &&
!IsVisBreak(wsObj.mEndReasonNode) )
{
res = DeleteNode(wsObj.mEndReasonNode);
@ -758,31 +765,136 @@ nsHTMLEditor::StripFormattingNodes(nsIDOMNode *aNode, PRBool aListOnly)
}
NS_IMETHODIMP nsHTMLEditor::PrepareTransferable(nsITransferable **transferable)
{
return NS_OK;
}
NS_IMETHODIMP nsHTMLEditor::PrepareHTMLTransferable(nsITransferable **aTransferable,
PRBool aHavePrivFlavor)
{
// Create generic Transferable for getting the data
nsresult rv = nsComponentManager::CreateInstance(kCTransferableCID, nsnull,
NS_GET_IID(nsITransferable),
(void**)transferable);
(void**)aTransferable);
if (NS_FAILED(rv))
return rv;
// Get the nsITransferable interface for getting the data from the clipboard
if (transferable)
if (aTransferable)
{
// Create the desired DataFlavor for the type of data
// we want to get out of the transferable
if ((mFlags & eEditorPlaintextMask) == 0) // This should only happen in html editors, not plaintext
{
(*transferable)->AddDataFlavor(kHTMLMime);
(*transferable)->AddDataFlavor(kFileMime);
if (!aHavePrivFlavor)
{
(*aTransferable)->AddDataFlavor(kNativeHTMLMime);
}
(*aTransferable)->AddDataFlavor(kHTMLMime);
(*aTransferable)->AddDataFlavor(kFileMime);
//(*transferable)->AddDataFlavor(kJPEGImageMime);
}
(*transferable)->AddDataFlavor(kUnicodeMime);
(*aTransferable)->AddDataFlavor(kUnicodeMime);
}
return NS_OK;
}
PRInt32
FindPositiveIntegerAfterString(const char *aLeadingString, nsCString &aCStr)
{
// first obtain offsets from cfhtml str
PRInt32 numFront = aCStr.Find(aLeadingString);
if (numFront == -1)
return -1;
numFront += nsCRT::strlen(aLeadingString);
PRInt32 numBack = aCStr.FindCharInSet(CRLF, numFront);
if (numBack == -1)
return -1;
nsCAutoString numStr(Substring(aCStr, numFront, numBack-numFront));
PRInt32 errorCode;
return numStr.ToInteger(&errorCode);
}
nsresult
RemoveFragComments(nsCString & aStr)
{
// remove the StartFragment/EndFragment comments from the str, if present
PRInt32 startCommentIndx = aStr.Find("<!--StartFragment");
if (startCommentIndx >= 0)
{
PRInt32 startCommentEnd = aStr.Find("-->", PR_FALSE, startCommentIndx);
if (startCommentEnd > startCommentIndx)
aStr.Cut(startCommentIndx, (startCommentEnd+3)-startCommentIndx);
}
PRInt32 endCommentIndx = aStr.Find("<!--EndFragment");
if (endCommentIndx >= 0)
{
PRInt32 endCommentEnd = aStr.Find("-->", PR_FALSE, endCommentIndx);
if (endCommentEnd > endCommentIndx)
aStr.Cut(endCommentIndx, (endCommentEnd+3)-endCommentIndx);
}
return NS_OK;
}
nsresult
nsHTMLEditor::ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnichar **aCfcontext)
{
// first obtain offsets from cfhtml str
PRInt32 startHTML = FindPositiveIntegerAfterString("StartHTML:", aCfhtml);
PRInt32 endHTML = FindPositiveIntegerAfterString("EndHTML:", aCfhtml);
PRInt32 startFragment = FindPositiveIntegerAfterString("StartFragment:", aCfhtml);
PRInt32 endFragment = FindPositiveIntegerAfterString("EndFragment:", aCfhtml);
if ((startHTML<0) || (endHTML<0) || (startFragment<0) || (endFragment<0))
return NS_ERROR_FAILURE;
// create context string
nsCAutoString contextUTF8(Substring(aCfhtml, startHTML, startFragment - startHTML) +
Substring(aCfhtml, endFragment, endHTML - endFragment));
// create fragment string
nsCAutoString fragmentUTF8(Substring(aCfhtml, startFragment, endFragment-startFragment));
// remove the StartFragment/EndFragment comments from the fragment, if present
RemoveFragComments(fragmentUTF8);
// remove the StartFragment/EndFragment comments from the context, if present
RemoveFragComments(contextUTF8);
// convert both strings to usc2
const nsAFlatString& fragUcs2Str = NS_ConvertUTF8toUCS2(fragmentUTF8);
const nsAFlatString& cntxtUcs2Str = NS_ConvertUTF8toUCS2(contextUTF8);
// translate platform linebreaks for fragment
PRUnichar* newStr = 0;
PRInt32 oldLengthInChars = fragUcs2Str.Length() + 1; // +1 to include null terminator
PRInt32 newLengthInChars = 0;
*aStuffToPaste = nsLinebreakConverter::ConvertUnicharLineBreaks(fragUcs2Str.get(),
nsLinebreakConverter::eLinebreakAny,
nsLinebreakConverter::eLinebreakContent,
oldLengthInChars, &newLengthInChars);
if (!aStuffToPaste)
{
return NS_ERROR_FAILURE;
}
// translate platform linebreaks for context
newStr = 0;
oldLengthInChars = cntxtUcs2Str.Length(); // +1 to include null terminator
newLengthInChars = 0;
*aCfcontext = nsLinebreakConverter::ConvertUnicharLineBreaks(cntxtUcs2Str.get(),
nsLinebreakConverter::eLinebreakAny,
nsLinebreakConverter::eLinebreakContent,
oldLengthInChars, &newLengthInChars);
// it's ok for context to be empty. frag might be whole doc and contain all it's context.
// we're done!
return NS_OK;
}
NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable,
const nsAString & aContextStr,
const nsAString & aInfoStr)
@ -795,41 +907,59 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable
{
nsAutoTxnsConserveSelection dontSpazMySelection(this);
nsAutoString flavor, stuffToPaste;
flavor.AssignWithConversion( bestFlavor ); // just so we can use flavor.Equals()
flavor.AssignWithConversion(bestFlavor); // just so we can use flavor.Equals()
#ifdef DEBUG_clipboard
printf("Got flavor [%s]\n", bestFlavor);
#endif
if (flavor.Equals(NS_LITERAL_STRING(kHTMLMime)))
if (flavor.Equals(NS_LITERAL_STRING(kNativeHTMLMime)))
{
nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
// note cf_html uses utf8, hence use length = len, not len/2 as in flavors below
nsCOMPtr<nsISupportsCString> textDataObj(do_QueryInterface(genericDataObj));
if (textDataObj && len > 0)
{
nsCAutoString cfhtml;
textDataObj->GetData(cfhtml);
NS_ASSERTION(cfhtml.Length() <= (len), "Invalid length!");
nsXPIDLString cfcontext, cffragment, cfselection; // cfselection left emtpy for now
rv = ParseCFHTML(cfhtml, getter_Copies(cffragment), getter_Copies(cfcontext));
if (NS_SUCCEEDED(rv) && !cffragment.IsEmpty())
{
nsAutoEditBatch beginBatching(this);
rv = InsertHTMLWithContext(cffragment, cfcontext, cfselection);
}
}
}
else if (flavor.Equals(NS_LITERAL_STRING(kHTMLMime)))
{
nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
if (textDataObj && len > 0)
{
nsAutoString text;
textDataObj->GetData ( text );
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
stuffToPaste.Assign ( text.get(), len / 2 );
stuffToPaste.Assign(text.get(), len / 2);
nsAutoEditBatch beginBatching(this);
rv = InsertHTMLWithContext(stuffToPaste, aContextStr, aInfoStr);
}
}
else if (flavor.Equals(NS_LITERAL_STRING(kUnicodeMime)))
{
nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
if (textDataObj && len > 0)
{
nsAutoString text;
textDataObj->GetData ( text );
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
stuffToPaste.Assign ( text.get(), len / 2 );
stuffToPaste.Assign(text.get(), len / 2);
nsAutoEditBatch beginBatching(this);
rv = InsertText(stuffToPaste);
}
}
else if (flavor.Equals(NS_LITERAL_STRING(kFileMime)))
{
nsCOMPtr<nsIFile> fileObj ( do_QueryInterface(genericDataObj) );
nsCOMPtr<nsIFile> fileObj(do_QueryInterface(genericDataObj));
if (fileObj && len > 0)
{
@ -839,27 +969,27 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromTransferable(nsITransferable *transferable
return rv;
nsCOMPtr<nsIURL> fileURL(do_QueryInterface(uri));
if ( fileURL )
if (fileURL)
{
PRBool insertAsImage = PR_FALSE;
nsCAutoString fileextension;
rv = fileURL->GetFileExtension( fileextension );
if ( NS_SUCCEEDED(rv) && !fileextension.IsEmpty() )
rv = fileURL->GetFileExtension(fileextension);
if (NS_SUCCEEDED(rv) && !fileextension.IsEmpty())
{
if ( (nsCRT::strcasecmp( fileextension.get(), "jpg" ) == 0 )
|| (nsCRT::strcasecmp( fileextension.get(), "jpeg" ) == 0 )
|| (nsCRT::strcasecmp( fileextension.get(), "gif" ) == 0 )
|| (nsCRT::strcasecmp( fileextension.get(), "png" ) == 0 ) )
if ( (nsCRT::strcasecmp(fileextension.get(), "jpg") == 0 )
|| (nsCRT::strcasecmp(fileextension.get(), "jpeg") == 0 )
|| (nsCRT::strcasecmp(fileextension.get(), "gif") == 0 )
|| (nsCRT::strcasecmp(fileextension.get(), "png") == 0 ) )
{
insertAsImage = PR_TRUE;
}
}
nsCAutoString urltext;
rv = fileURL->GetSpec( urltext );
if ( NS_SUCCEEDED(rv) && !urltext.IsEmpty() )
rv = fileURL->GetSpec(urltext);
if (NS_SUCCEEDED(rv) && !urltext.IsEmpty())
{
if ( insertAsImage )
if (insertAsImage)
{
stuffToPaste.Assign(NS_LITERAL_STRING("<IMG src=\""));
stuffToPaste.Append(NS_ConvertUTF8toUCS2(urltext));
@ -910,9 +1040,15 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
dragService->GetCurrentSession(getter_AddRefs(dragSession));
if (!dragSession) return NS_OK;
// find out if we have our internal html flavor on the clipboard. We don't want to mess
// around with cfhtml if we do.
PRBool bHavePrivateHTMLFlavor = PR_FALSE;
rv = dragSession->IsDataFlavorSupported(kHTMLContext, &bHavePrivateHTMLFlavor);
if (NS_FAILED(rv)) return rv;
// Get the nsITransferable interface for getting the data from the drop
nsCOMPtr<nsITransferable> trans;
rv = PrepareTransferable(getter_AddRefs(trans));
rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
if (NS_FAILED(rv)) return rv;
if (!trans) return NS_OK; // NS_ERROR_FAILURE; SHOULD WE FAIL?
@ -953,30 +1089,30 @@ NS_IMETHODIMP nsHTMLEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
{
nsAutoString text;
textDataObj = do_QueryInterface(contextDataObj);
textDataObj->GetData ( text );
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
contextStr.Assign ( text.get(), contextLen / 2 );
contextStr.Assign(text.get(), contextLen / 2);
}
if (infoDataObj)
{
nsAutoString text;
textDataObj = do_QueryInterface(infoDataObj);
textDataObj->GetData ( text );
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
infoStr.Assign ( text.get(), infoLen / 2 );
infoStr.Assign(text.get(), infoLen / 2);
}
if ( doPlaceCaret )
if (doPlaceCaret)
{
// check if the user pressed the key to force a copy rather than a move
// if we run into problems here, we'll just assume the user doesn't want a copy
PRBool userWantsCopy = PR_FALSE;
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent (do_QueryInterface(aDropEvent));
nsCOMPtr<nsIDOMNSUIEvent> nsuiEvent(do_QueryInterface(aDropEvent));
if (!nsuiEvent) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aDropEvent) );
nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aDropEvent));
if (mouseEvent)
#ifdef XP_MAC
@ -1141,24 +1277,26 @@ NS_IMETHODIMP nsHTMLEditor::CanDrag(nsIDOMEvent *aDragEvent, PRBool *aCanDrag)
if (NS_FAILED(res)) return res;
// if we are collapsed, we have no selection so nothing to drag
if ( isCollapsed )
if (isCollapsed)
return NS_OK;
nsCOMPtr<nsIDOMEventTarget> eventTarget;
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aDragEvent));
if (nsevent) {
if (nsevent)
{
res = nsevent->GetOriginalTarget(getter_AddRefs(eventTarget));
if (NS_FAILED(res)) {
if (NS_FAILED(res))
{
return res;
}
}
if ( eventTarget )
if (eventTarget)
{
nsCOMPtr<nsIDOMNode> eventTargetDomNode = do_QueryInterface(eventTarget);
if ( eventTargetDomNode )
if (eventTargetDomNode)
{
PRBool isTargetedCorrectly = PR_FALSE;
res = selection->ContainsNode(eventTargetDomNode, PR_FALSE, &isTargetedCorrectly);
@ -1252,7 +1390,7 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
}
// if we have an empty string, we're done; otherwise continue
if ( !buffer.IsEmpty() )
if (!buffer.IsEmpty())
{
nsCOMPtr<nsISupportsString> dataWrapper, contextWrapper, infoWrapper;
@ -1269,7 +1407,7 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
// QI the data object an |nsISupports| so that when the transferable holds
// onto it, it will addref the correct interface.
nsCOMPtr<nsISupports> genericDataObj ( do_QueryInterface(dataWrapper) );
nsCOMPtr<nsISupports> genericDataObj(do_QueryInterface(dataWrapper));
rv = trans->SetTransferData(kUnicodeMime, genericDataObj, buffer.Length() * 2);
if (NS_FAILED(rv)) return rv;
}
@ -1280,8 +1418,8 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
infoWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
NS_ENSURE_TRUE(infoWrapper, NS_ERROR_FAILURE);
contextWrapper->SetData ( parents );
infoWrapper->SetData ( info );
contextWrapper->SetData(parents);
infoWrapper->SetData(info);
rv = trans->AddDataFlavor(kHTMLMime);
if (NS_FAILED(rv)) return rv;
@ -1292,7 +1430,7 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
rv = trans->SetConverter(htmlConverter);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupports> genericDataObj ( do_QueryInterface(dataWrapper) );
nsCOMPtr<nsISupports> genericDataObj(do_QueryInterface(dataWrapper));
rv = trans->SetTransferData(kHTMLMime, genericDataObj, buffer.Length() * 2);
if (NS_FAILED(rv)) return rv;
@ -1321,12 +1459,13 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
// in some cases we'll want to cut rather than copy... hmmmmm...
flags = nsIDragService::DRAGDROP_ACTION_COPY + nsIDragService::DRAGDROP_ACTION_MOVE;
rv = dragService->InvokeDragSession( domnode, transferableArray, nsnull, flags);
rv = dragService->InvokeDragSession(domnode, transferableArray, nsnull, flags);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aDragEvent));
if (nsevent) {
if (nsevent)
{
nsevent->PreventBubble();
}
}
@ -1335,19 +1474,50 @@ NS_IMETHODIMP nsHTMLEditor::DoDrag(nsIDOMEvent *aDragEvent)
return rv;
}
PRBool nsHTMLEditor::HavePrivateHTMLFlavor(nsIClipboard *aClipboard)
{
// check the clipboard for our special kHTMLContext flavor. If that is there, we know
// we have our own internal html format on clipboard.
if (!aClipboard) return PR_FALSE;
PRBool bHavePrivateHTMLFlavor = PR_FALSE;
nsCOMPtr<nsISupportsArray> flavArray;
nsresult res = NS_NewISupportsArray(getter_AddRefs(flavArray));
if (NS_FAILED(res)) return PR_FALSE;
nsCOMPtr<nsISupportsCString> contextString = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if (!contextString) return PR_FALSE;
contextString->SetData(NS_LITERAL_CSTRING(kHTMLContext));
flavArray->AppendElement(contextString);
if (NS_SUCCEEDED(aClipboard->HasDataMatchingFlavors (flavArray, nsIClipboard::kGlobalClipboard, &bHavePrivateHTMLFlavor )))
return bHavePrivateHTMLFlavor;
return PR_FALSE;
}
NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType)
{
ForceCompositionEnd();
// Get Clipboard Service
nsresult rv;
nsCOMPtr<nsIClipboard> clipboard( do_GetService( kCClipboardCID, &rv ) );
if ( NS_FAILED(rv) )
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
if (NS_FAILED(rv))
return rv;
// find out if we have our internal html flavor on the clipboard. We don't want to mess
// around with cfhtml if we do.
PRBool bHavePrivateHTMLFlavor = HavePrivateHTMLFlavor(clipboard);
// Get the nsITransferable interface for getting the data from the clipboard
nsCOMPtr<nsITransferable> trans;
rv = PrepareTransferable(getter_AddRefs(trans));
rv = PrepareHTMLTransferable(getter_AddRefs(trans), bHavePrivateHTMLFlavor);
if (NS_SUCCEEDED(rv) && trans)
{
// Get the Data from the clipboard
@ -1355,38 +1525,43 @@ NS_IMETHODIMP nsHTMLEditor::Paste(PRInt32 aSelectionType)
{
// also get additional html copy hints, if present
nsAutoString contextStr, infoStr;
nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
PRUint32 contextLen, infoLen;
nsCOMPtr<nsISupportsString> textDataObj;
nsCOMPtr<nsITransferable> contextTrans = do_CreateInstance(kCTransferableCID);
NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
contextTrans->AddDataFlavor(kHTMLContext);
clipboard->GetData(contextTrans, aSelectionType);
contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
nsCOMPtr<nsITransferable> infoTrans = do_CreateInstance(kCTransferableCID);
NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
infoTrans->AddDataFlavor(kHTMLInfo);
clipboard->GetData(infoTrans, aSelectionType);
infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
if (contextDataObj)
// also get additional html copy hints, if present
if (bHavePrivateHTMLFlavor)
{
nsAutoString text;
textDataObj = do_QueryInterface(contextDataObj);
textDataObj->GetData ( text );
NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
contextStr.Assign ( text.get(), contextLen / 2 );
}
if (infoDataObj)
{
nsAutoString text;
textDataObj = do_QueryInterface(infoDataObj);
textDataObj->GetData ( text );
NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
infoStr.Assign ( text.get(), infoLen / 2 );
nsCOMPtr<nsISupports> contextDataObj, infoDataObj;
PRUint32 contextLen, infoLen;
nsCOMPtr<nsISupportsString> textDataObj;
nsCOMPtr<nsITransferable> contextTrans = do_CreateInstance(kCTransferableCID);
NS_ENSURE_TRUE(contextTrans, NS_ERROR_NULL_POINTER);
contextTrans->AddDataFlavor(kHTMLContext);
clipboard->GetData(contextTrans, aSelectionType);
contextTrans->GetTransferData(kHTMLContext, getter_AddRefs(contextDataObj), &contextLen);
nsCOMPtr<nsITransferable> infoTrans = do_CreateInstance(kCTransferableCID);
NS_ENSURE_TRUE(infoTrans, NS_ERROR_NULL_POINTER);
infoTrans->AddDataFlavor(kHTMLInfo);
clipboard->GetData(infoTrans, aSelectionType);
infoTrans->GetTransferData(kHTMLInfo, getter_AddRefs(infoDataObj), &infoLen);
if (contextDataObj)
{
nsAutoString text;
textDataObj = do_QueryInterface(contextDataObj);
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (contextLen/2), "Invalid length!");
contextStr.Assign(text.get(), contextLen / 2);
}
if (infoDataObj)
{
nsAutoString text;
textDataObj = do_QueryInterface(infoDataObj);
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (infoLen/2), "Invalid length!");
infoStr.Assign(text.get(), infoLen / 2);
}
}
rv = InsertFromTransferable(trans, contextStr, infoStr);
}
@ -1404,8 +1579,8 @@ NS_IMETHODIMP nsHTMLEditor::PasteNoFormatting(PRInt32 aSelectionType)
// Get Clipboard Service
nsresult rv;
nsCOMPtr<nsIClipboard> clipboard( do_GetService( kCClipboardCID, &rv ) );
if ( NS_FAILED(rv) )
nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
if (NS_FAILED(rv))
return rv;
// Get the nsITransferable interface for getting the data from the clipboard.
@ -1454,9 +1629,7 @@ NS_IMETHODIMP nsHTMLEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste)
// add the flavors for all editors
for (const char* const* flavor = textEditorFlavors; *flavor; flavor++)
{
nsCOMPtr<nsISupportsCString> flavorString;
nsComponentManager::CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
NS_GET_IID(nsISupportsCString), getter_AddRefs(flavorString));
nsCOMPtr<nsISupportsCString> flavorString = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if (flavorString)
{
flavorString->SetData(nsDependentCString(*flavor));
@ -1471,9 +1644,7 @@ NS_IMETHODIMP nsHTMLEditor::CanPaste(PRInt32 aSelectionType, PRBool *aCanPaste)
*htmlFlavor;
htmlFlavor++)
{
nsCOMPtr<nsISupportsCString> flavorString;
nsComponentManager::CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
NS_GET_IID(nsISupportsCString), getter_AddRefs(flavorString));
nsCOMPtr<nsISupportsCString> flavorString = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
if (flavorString)
{
flavorString->SetData(nsDependentCString(*htmlFlavor));
@ -1595,13 +1766,13 @@ NS_IMETHODIMP nsHTMLEditor::PasteAsPlaintextQuotation(PRInt32 aSelectionType)
nsAutoString stuffToPaste;
if (flavor.Equals(NS_LITERAL_STRING(kUnicodeMime)))
{
nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
nsCOMPtr<nsISupportsString> textDataObj(do_QueryInterface(genericDataObj));
if (textDataObj && len > 0)
{
nsAutoString text;
textDataObj->GetData ( text );
textDataObj->GetData(text);
NS_ASSERTION(text.Length() <= (len/2), "Invalid length!");
stuffToPaste.Assign ( text.get(), len / 2 );
stuffToPaste.Assign(text.get(), len / 2);
nsAutoEditBatch beginBatching(this);
rv = InsertAsPlaintextQuotation(stuffToPaste, PR_TRUE, 0);
}
@ -1903,6 +2074,46 @@ nsHTMLEditor::InsertAsCitedQuotation(const nsAString & aQuotedText,
return res;
}
void RemoveBodyAndHead(nsIDOMNode *aNode)
{
if (!aNode)
return;
nsCOMPtr<nsIDOMNode> tmp, child, body, head;
// find the body and head nodes if any.
// look only at immediate children of aNode.
aNode->GetFirstChild(getter_AddRefs(child));
while (child)
{
if (nsTextEditUtils::IsBody(child))
{
body = child;
}
else if (nsEditor::NodeIsType(child, NS_LITERAL_STRING("head")))
{
head = child;
}
child->GetNextSibling(getter_AddRefs(tmp));
child = tmp;
}
if (head)
{
aNode->RemoveChild(head, getter_AddRefs(tmp));
}
if (body)
{
body->GetFirstChild(getter_AddRefs(child));
while (child)
{
aNode->InsertBefore(child, body, getter_AddRefs(tmp));
body->GetFirstChild(getter_AddRefs(child));
}
aNode->RemoveChild(body, getter_AddRefs(tmp));
}
}
nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange,
const nsAString & aInputString,
const nsAString & aContextStr,
@ -1914,46 +2125,43 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange,
if (!outFragNode || !outRangeStartHint || !outRangeEndHint || !aNSRange)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMDocumentFragment> docfrag;
nsCOMPtr<nsIDOMNode> contextAsNode;
nsCOMPtr<nsIDOMNode> contextAsNode, tmp;
nsresult res = NS_OK;
// if we have context info, create a fragment for that
nsCOMPtr<nsIDOMDocumentFragment> contextfrag;
nsCOMPtr<nsIDOMNode> contextLeaf;
nsCOMPtr<nsIDOMNode> contextLeaf, junk;
PRInt32 contextDepth = 0;
if (aContextStr.Length())
{
res = aNSRange->CreateContextualFragment(aContextStr, getter_AddRefs(contextfrag));
res = ParseFragment(aContextStr, address_of(contextAsNode));
NS_ENSURE_SUCCESS(res, res);
contextAsNode = do_QueryInterface(contextfrag);
NS_ENSURE_TRUE(contextAsNode, NS_ERROR_FAILURE);
res = StripFormattingNodes(contextAsNode);
NS_ENSURE_SUCCESS(res, res);
RemoveBodyAndHead(contextAsNode);
// cache the deepest leaf in the context
nsCOMPtr<nsIDOMNode> junk, child, tmp = contextAsNode;
tmp = contextAsNode;
while (tmp)
{
contextDepth++;
contextLeaf = tmp;
contextLeaf->GetFirstChild(getter_AddRefs(tmp));
}
// tweak aNSRange to point inside contextAsNode
nsCOMPtr<nsIDOMRange> range(do_QueryInterface(aNSRange));
if (range)
{
aNSRange->NSDetach();
range->SetStart(contextLeaf,0);
range->SetEnd(contextLeaf,0);
}
}
// create fragment for pasted html
res = aNSRange->CreateContextualFragment(aInputString, getter_AddRefs(docfrag));
res = ParseFragment(aInputString, outFragNode);
NS_ENSURE_SUCCESS(res, res);
*outFragNode = do_QueryInterface(docfrag);
if (contextfrag)
NS_ENSURE_TRUE(*outFragNode, NS_ERROR_FAILURE);
RemoveBodyAndHead(*outFragNode);
if (contextAsNode)
{
nsCOMPtr<nsIDOMNode> junk;
// unite the two trees
contextLeaf->AppendChild(*outFragNode, getter_AddRefs(junk));
*outFragNode = contextAsNode;
@ -1983,6 +2191,36 @@ nsresult nsHTMLEditor::CreateDOMFragmentFromPaste(nsIDOMNSRange *aNSRange,
return res;
}
nsresult nsHTMLEditor::ParseFragment(const nsAString &aFragStr, nsCOMPtr<nsIDOMNode> *outNode)
{
// create the parser to do the conversion.
nsCOMPtr<nsIParser> parser;
nsresult res = nsComponentManager::CreateInstance(kCParserCID, nsnull, NS_GET_IID(nsIParser),
getter_AddRefs(parser));
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(parser, NS_ERROR_FAILURE);
// create the html fragment sink
nsCOMPtr<nsIContentSink> sink;
sink = do_CreateInstance(NS_HTMLFRAGMENTSINK2_CONTRACTID);
NS_ENSURE_TRUE(sink, NS_ERROR_FAILURE);
nsCOMPtr<nsIHTMLFragmentContentSink> fragSink(do_QueryInterface(sink));
NS_ENSURE_TRUE(fragSink, NS_ERROR_FAILURE);
// parse the fragment
parser->SetContentSink(sink);
parser->Parse(aFragStr, 0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE, eDTDMode_fragment);
// get the fragment node
nsCOMPtr<nsIDOMDocumentFragment> contextfrag;
res = fragSink->GetFragment(getter_AddRefs(contextfrag));
NS_ENSURE_SUCCESS(res, res);
*outNode = do_QueryInterface(contextfrag);
return res;
}
nsresult nsHTMLEditor::CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode,
nsCOMArray<nsIDOMNode>& outNodeList,
PRInt32 aRangeStartHint,

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

@ -70,6 +70,7 @@ class nsITransferable;
class nsIDOMEventReceiver;
class nsIDOMNSRange;
class nsIDocumentEncoder;
class nsIClipboard;
class TypeInState;
/**
@ -643,9 +644,12 @@ protected:
// factored methods for handling insertion of data from transferables (drag&drop or clipboard)
NS_IMETHOD PrepareTransferable(nsITransferable **transferable);
NS_IMETHOD PrepareHTMLTransferable(nsITransferable **transferable, PRBool havePrivFlavor);
NS_IMETHOD InsertFromTransferable(nsITransferable *transferable,
const nsAString & aContextStr,
const nsAString & aInfoStr);
PRBool HavePrivateHTMLFlavor( nsIClipboard *clipboard );
nsresult ParseCFHTML(nsCString & aCfhtml, PRUnichar **aStuffToPaste, PRUnichar **aCfcontext);
nsresult InsertHTMLWithContext(const nsAString & aInputString,
const nsAString & aContextStr,
const nsAString & aInfoStr);
@ -662,6 +666,7 @@ protected:
nsCOMPtr<nsIDOMNode> *outFragNode,
PRInt32 *outRangeStartHint,
PRInt32 *outRangeEndHint);
nsresult ParseFragment(const nsAString & aFragStr, nsCOMPtr<nsIDOMNode> *outNode);
nsresult CreateListOfNodesToPaste(nsIDOMNode *aFragmentAsNode,
nsCOMArray<nsIDOMNode>& outNodeList,
PRInt32 aRangeStartHint,

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

@ -41,6 +41,7 @@
#include "nsIHTMLContentSink.h"
#define NS_HTMLFRAGMENTSINK_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;1"
#define NS_HTMLFRAGMENTSINK2_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;2"
class nsIDOMDocumentFragment;

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

@ -41,6 +41,7 @@
#include "nsIHTMLContentSink.h"
#define NS_HTMLFRAGMENTSINK_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;1"
#define NS_HTMLFRAGMENTSINK2_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;2"
class nsIDOMDocumentFragment;