fix for 142855: cf_html paste functionality. r=brade,cmanske; sr=kin
git-svn-id: svn://10.0.0.236/trunk@134304 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user