diff --git a/editor/base/nsComposerCommands.cpp b/editor/base/nsComposerCommands.cpp index 21cbbfb12c2b..1fdcaee387ff 100644 --- a/editor/base/nsComposerCommands.cpp +++ b/editor/base/nsComposerCommands.cpp @@ -94,6 +94,24 @@ nsBaseComposerCommand::SetCommandNodeState(const nsAReadableString & aCommandNam return uiNode->SetAttribute(NS_ConvertASCIItoUCS2("state"), inNodeState); } +//-------------------------------------------------------------------------------------------------------------------- +PRBool +nsBaseComposerCommand::EditingHTML(nsIEditorShell* inEditorShell) +//-------------------------------------------------------------------------------------------------------------------- +{ + nsXPIDLCString mimeType; + inEditorShell->GetContentsMIMEType(getter_Copies(mimeType)); + if (nsCRT::strcmp(mimeType, "text/html") != 0) + return PR_FALSE; + + PRBool sourceMode = PR_FALSE; + inEditorShell->IsHTMLSourceMode(&sourceMode); + if (sourceMode) + return PR_FALSE; + + return PR_TRUE; +} + #ifdef XP_MAC #pragma mark - @@ -119,23 +137,12 @@ nsBaseStateUpdatingCommand::IsCommandEnabled(const nsAReadableString & aCommandN { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (!editorShell) return NS_OK; - // check for plain text? - nsCOMPtr editor; - editorShell->GetEditor(getter_AddRefs(editor)); - if (!editor) return NS_OK; - // Enable commands only if not in HTML source edit mode - PRBool sourceMode = PR_FALSE; - editorShell->IsHTMLSourceMode(&sourceMode); - *outCmdEnabled = !sourceMode; - - // also udpate the command state - nsresult rv = UpdateCommandState(aCommandName, refCon); - if (NS_FAILED(rv)) + if (editorShell && EditingHTML(editorShell)) { - *outCmdEnabled = PR_FALSE; - return NS_OK; + *outCmdEnabled = PR_TRUE; + // also udpate the command state. + UpdateCommandState(aCommandName, refCon); } return NS_OK; @@ -472,7 +479,7 @@ nsRemoveListCommand::IsCommandEnabled(const nsAReadableString & aCommandName, ns { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { // It is enabled if we are in any list type PRBool bMixed; @@ -515,7 +522,7 @@ nsIndentCommand::IsCommandEnabled(const nsAReadableString & aCommandName, nsISup { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -547,7 +554,7 @@ nsOutdentCommand::IsCommandEnabled(const nsAReadableString & aCommandName, nsISu { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -571,7 +578,7 @@ nsOutdentCommand::DoCommand(const nsAReadableString & aCommandName, nsISupports nsCOMPtr editorShell = do_QueryInterface(refCon); nsresult rv = NS_OK; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsAutoString indentStr; indentStr.AssignWithConversion("outdent"); rv = editorShell->Indent(indentStr.GetUnicode()); @@ -602,7 +609,7 @@ nsMultiStateCommand::IsCommandEnabled(const nsAReadableString & aCommandName, ns { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -923,7 +930,7 @@ nsRemoveStylesCommand::IsCommandEnabled(const nsAReadableString & aCommandName, { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -968,7 +975,7 @@ nsIncreaseFontSizeCommand::IsCommandEnabled(const nsAReadableString & aCommandNa { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -1006,7 +1013,7 @@ nsDecreaseFontSizeCommand::IsCommandEnabled(const nsAReadableString & aCommandNa { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); diff --git a/editor/base/nsComposerCommands.h b/editor/base/nsComposerCommands.h index 50948aa96006..bae9a8c690cf 100644 --- a/editor/base/nsComposerCommands.h +++ b/editor/base/nsComposerCommands.h @@ -59,6 +59,8 @@ protected: nsresult GetCommandNodeState(const nsAReadableString & aCommandName, nsIEditorShell* editorShell, nsString& outNodeState); nsresult SetCommandNodeState(const nsAReadableString & aCommandName, nsIEditorShell* editorShell, const nsString& inNodeState); + // are we in HTML edit mode (not source view or plain text editing) + PRBool EditingHTML(nsIEditorShell* inEditorShell); }; diff --git a/editor/base/nsEditorShell.cpp b/editor/base/nsEditorShell.cpp index efc4de68c926..7dd268d567c0 100644 --- a/editor/base/nsEditorShell.cpp +++ b/editor/base/nsEditorShell.cpp @@ -100,6 +100,8 @@ #include "nsILookAndFeel.h" #include "nsIChromeRegistry.h" +#include "nsCExternalHandlerService.h" +#include "nsIMIMEService.h" /////////////////////////////////////// // Editor Includes @@ -207,13 +209,14 @@ GetChromeElement(nsIDocShell *aShell, const char *aID, nsIDOMElement **aElement) // Utility to set and attribute of a UI element static nsresult SetChromeAttribute(nsIDocShell *aShell, const char *aID, - const char *aName, const nsString &aValue) + const nsAString& aName, const nsAString &aValue) { nsCOMPtr elem; nsresult rv = GetChromeElement(aShell, aID, getter_AddRefs(elem)); + + // Set the text attribute. if (NS_SUCCEEDED(rv) && elem) - // Set the text attribute. - rv = elem->SetAttribute( NS_ConvertASCIItoUCS2(aName), aValue); + rv = elem->SetAttribute(aName, aValue); return rv; } @@ -254,6 +257,8 @@ nsEditorShell::nsEditorShell() , mCloseWindowWhenLoaded(PR_FALSE) , mCantEditReason(eCantEditNoReason) , mEditorType(eUninitializedEditorType) +, mContentMIMEType("text/html") +, mContentTypeKnown(PR_FALSE) , mWrapColumn(0) , mSuggestedWordIndex(0) , mDictionaryIndex(0) @@ -436,6 +441,37 @@ nsEditorShell::ResetEditingState() return NS_OK; } + +// is this a MIME type that we support the editing of, in plain text mode? +const char* const gSupportedTextTypes[] = { + "text/plain", + "text/css", + "text/rdf", + "text/xml", + "text/xsl", + "text/javascript", // obsolete type + "application/x-javascript", + "text/xul", // obsolete type + "application/vnd.mozilla.xul+xml", + NULL // IMPORTANT! Null must be at end +}; + +PRBool +nsEditorShell::IsSupportedTextType(const char* aMIMEType) +{ + PRInt32 i = 0; + + while (gSupportedTextTypes[i]) + { + if (nsCRT::strcmp(gSupportedTextTypes[i], aMIMEType) == 0) + return PR_TRUE; + + i ++; + } + + return PR_FALSE; +} + nsresult nsEditorShell::PrepareDocumentForEditing(nsIDOMWindow* aDOMWindow, nsIURI *aUrl) { @@ -884,6 +920,21 @@ nsEditorShell::GetEditorType(PRUnichar **_retval) return NS_OK; } +/* attribute string contentsMIMEType; */ +NS_IMETHODIMP +nsEditorShell::GetContentsMIMEType(char * *aContentsMIMEType) +{ + NS_ENSURE_ARG_POINTER(aContentsMIMEType); + *aContentsMIMEType = mContentMIMEType.ToNewCString(); + return NS_OK; +} + +NS_IMETHODIMP +nsEditorShell::SetContentsMIMEType(const char * aContentsMIMEType) +{ + mContentMIMEType.Assign(aContentsMIMEType ? aContentsMIMEType : ""); + return NS_OK; +} nsresult nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell) @@ -895,58 +946,66 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell) if (mEditor) return NS_ERROR_ALREADY_INITIALIZED; - nsresult err = NS_OK; + nsresult rv = NS_OK; nsCOMPtr editor; - err = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, NS_GET_IID(nsIEditor), getter_AddRefs(editor)); - if(!editor) - err = NS_ERROR_OUT_OF_MEMORY; + rv = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, NS_GET_IID(nsIEditor), getter_AddRefs(editor)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr selCon = do_QueryInterface(aPresShell); - if (NS_SUCCEEDED(err)) + if (mEditorTypeString.EqualsWithConversion("text")) { - if (mEditorTypeString.EqualsWithConversion("text")) + PRInt16 flags = nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask; + if (mMailCompose) flags |= nsIPlaintextEditor::eEditorMailMask; + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, flags); + mEditorType = ePlainTextEditorType; + } + else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor + { + PRUint32 editorFlags = 0; + EEditorType editorType = eHTMLTextEditorType; + + // if the MIME type of the docment we are editing is text/plain, make a text editor + if (IsSupportedTextType(mContentMIMEType)) { - PRInt16 flags = nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask; - if (mMailCompose) flags |= nsIPlaintextEditor::eEditorMailMask; - err = editor->Init(aDoc, aPresShell, nsnull, selCon, flags); - mEditorType = ePlainTextEditorType; + editorFlags = nsIPlaintextEditor::eEditorPlaintextMask; + editorType = ePlainTextEditorType; } - else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor - { - err = editor->Init(aDoc, aPresShell, nsnull, selCon, 0); - mEditorType = eHTMLTextEditorType; - } - else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules - { - err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask); - mEditorType = eHTMLTextEditorType; - } - else - { - err = NS_ERROR_INVALID_ARG; // this is not an editor we know about + + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, editorFlags); + mEditorType = editorType; + } + else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules + { + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask); + mEditorType = eHTMLTextEditorType; + } + else + { + rv = NS_ERROR_INVALID_ARG; // this is not an editor we know about #if DEBUG - nsAutoString errorMsg; errorMsg.AssignWithConversion("Failed to init editor. Unknown editor type \""); - errorMsg += mEditorTypeString; - errorMsg.AppendWithConversion("\"\n"); - char *errorMsgCString = errorMsg.ToNewCString(); - NS_WARNING(errorMsgCString); - nsCRT::free(errorMsgCString); + nsAutoString errorMsg; errorMsg.AssignWithConversion("Failed to init editor. Unknown editor type \""); + errorMsg += mEditorTypeString; + errorMsg.AppendWithConversion("\"\n"); + char *errorMsgCString = errorMsg.ToNewCString(); + NS_WARNING(errorMsgCString); + nsCRT::free(errorMsgCString); #endif - } + } // disable the preference style sheet so we can override colors - if (NS_SUCCEEDED(err)) { - err = aPresShell->EnablePrefStyleRules(PR_FALSE,0); - } + if (NS_SUCCEEDED(rv)) + { + rv = aPresShell->EnablePrefStyleRules(PR_FALSE,0); + } - if (NS_SUCCEEDED(err) && editor) - { - mEditor = do_QueryInterface(editor); // this does the addref that is the owning reference - } + if (NS_SUCCEEDED(rv) && editor) + { + mEditor = do_QueryInterface(editor); // this does the addref that is the owning reference } - return err; + return rv; } @@ -1688,6 +1747,27 @@ nsEditorShell::CheckOpenWindowForURLMatch(const PRUnichar* inFileURL, nsIDOMWind return NS_OK; } +// helper function +static nsresult GetExtensionForMIMEType(const char* inMIMEType, nsACString& outExtension) +{ + nsresult rv; + nsCOMPtr mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr mimeInfo; + rv = mimeService->GetFromMIMEType(inMIMEType, getter_AddRefs(mimeInfo)); + if (NS_FAILED(rv)) return rv; + + nsXPIDLCString fileExtension; + rv = mimeInfo->FirstExtension(getter_Copies(fileExtension)); + if (NS_FAILED(rv)) return rv; + + outExtension.Assign(fileExtension); + + return NS_OK; +} + + NS_IMETHODIMP nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* aMimeType, PRBool *_retval) { @@ -1696,13 +1776,20 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a NS_ENSURE_ARG_POINTER((aMimeType)); - nsAutoString mimeType(aMimeType); - PRBool saveAsText = mimeType.EqualsWithConversion("text/plain"); + nsCAutoString mimeTypeCStr; mimeTypeCStr.AssignWithConversion(aMimeType); + PRBool saveAsText = IsSupportedTextType(mimeTypeCStr); // Currently, we only understand plain text and html - if (!mimeType.EqualsWithConversion("text/html") && !saveAsText) + if (!mimeTypeCStr.Equals("text/html") && !saveAsText) return NS_ERROR_FAILURE; + nsAutoString mimeType(aMimeType); + + // if we're saving as text, force the text/plain MIME type (because we use this + // to get a content serializer on save) + if (saveAsText) + mimeType.Assign(NS_LITERAL_STRING("text/plain").get()); + switch (mEditorType) { case ePlainTextEditorType: @@ -1858,11 +1945,12 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a title.ReplaceChar(" .\\/@:", (PRUnichar)'_'); } + // get the correct extension from the MIME type here fileName = title; - if (saveAsText) - fileName.AppendWithConversion(".txt"); - else - fileName.AppendWithConversion(".html"); + nsCAutoString fileExt(saveAsText ? "txt" : "html"); + GetExtensionForMIMEType(mimeTypeCStr.get(), fileExt); + fileName.Append(PRUnichar('.')); + fileName.AppendWithConversion(fileExt); } else // have a file spec { @@ -1881,9 +1969,12 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a index = fileName.RFind(".shtml", PR_TRUE); if (index > 0) { + nsCAutoString fileExt("txt"); + GetExtensionForMIMEType(mimeTypeCStr.get(), fileExt); + // Truncate after "." and append "txt" extension fileName.SetLength(index+1); - fileName.AppendWithConversion("txt"); + fileName.AppendWithConversion(fileExt); } } @@ -4934,6 +5025,8 @@ nsEditorShell::OnStateChange(nsIWebProgress *aProgress, PRInt32 aStateFlags, nsresult aStatus) { + nsresult rv = NS_OK; + // // A Request has started... // @@ -4942,7 +5035,8 @@ nsEditorShell::OnStateChange(nsIWebProgress *aProgress, // Page level notification... if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) { - StartPageLoad(); + nsCOMPtr channel(do_QueryInterface(aRequest)); + StartPageLoad(channel); } // Document level notification... if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) @@ -5013,12 +5107,36 @@ nsEditorShell::OnSecurityChange(nsIWebProgress *aWebProgress, return NS_OK; } -nsresult nsEditorShell::StartPageLoad() +nsresult nsEditorShell::StartPageLoad(nsIChannel *aChannel) { + nsXPIDLCString contentType; + aChannel->GetContentType(getter_Copies(contentType)); + + // save the original MIME type; we'll use it later + mContentMIMEType.Assign(contentType.get() ? contentType : ""); + + if (nsCRT::strcmp(contentType, "text/html") == 0) + { + // fine, do nothing + mContentTypeKnown = PR_TRUE; + } + else if (IsSupportedTextType(contentType)) + { + // set the mime type to text/plain so that it renders as text + aChannel->SetContentType("text/plain"); + mContentTypeKnown = PR_TRUE; + } + else + { + // we don't know what this is yet. It might be HTML loaded from + // a directory URL (http://www.foo.com/). We'll know the real + // MIME type later. + mContentTypeKnown = PR_FALSE; + } + // Start the throbber // TODO: We should also start/stop it for saving and publishing? - SetChromeAttribute( mDocShell, "Editor:Throbber", "busy", - NS_ConvertASCIItoUCS2("true") ); + SetChromeAttribute( mDocShell, "Editor:Throbber", NS_LITERAL_STRING("busy"), NS_LITERAL_STRING("true") ); // set up a parser observer if (!mParserObserver) @@ -5029,6 +5147,7 @@ nsresult nsEditorShell::StartPageLoad() } NS_ADDREF(mParserObserver); mParserObserver->RegisterTagToWatch("FRAMESET"); + mParserObserver->RegisterTagToWatch("IFRAME"); mParserObserver->Start(); } @@ -5048,12 +5167,31 @@ nsresult nsEditorShell::EndPageLoad(nsIDOMWindow *aDOMWindow, NS_RELEASE(mParserObserver); } - SetChromeAttribute( mDocShell, "Editor:Throbber", "busy", - NS_ConvertASCIItoUCS2("false") ); + SetChromeAttribute( mDocShell, "Editor:Throbber", NS_LITERAL_STRING("busy"), NS_LITERAL_STRING("false") ); + + // Is this a MIME type we can handle? + if (aChannel) + { + // if we didn't get the content-type at the start of the load, get it now + if (!mContentTypeKnown) + { + nsXPIDLCString contentType; + aChannel->GetContentType(getter_Copies(contentType)); + + if (contentType.get()) + mContentMIMEType.Assign(contentType); + } + } + + if ( !mContentMIMEType.Equals("text/html") && !IsSupportedTextType(mContentMIMEType) ) + { + mCloseWindowWhenLoaded = PR_TRUE; + mCantEditReason = eCantEditMimeType; + } nsAutoString doneText; GetBundleString(NS_LITERAL_STRING("LoadingDone"), doneText); - SetChromeAttribute(mDocShell, "statusText", "label", doneText); + SetChromeAttribute(mDocShell, "statusText", NS_LITERAL_STRING("label"), doneText); // Display an Alert dialog if the page cannot be edited... if (mCloseWindowWhenLoaded) @@ -5101,6 +5239,7 @@ nsresult nsEditorShell::EndPageLoad(nsIDOMWindow *aDOMWindow, { nsCOMPtr url; aChannel->GetURI(getter_AddRefs(url)); + (void) PrepareDocumentForEditing(aDOMWindow, url); } @@ -5143,24 +5282,6 @@ nsresult nsEditorShell::EndDocumentLoad(nsIDOMWindow *aDOMWindow, nsCOMPtr refreshURI = do_QueryInterface(mContentAreaDocShell); if (refreshURI) refreshURI->CancelRefreshURITimers(); - - // Is this a MIME type we can handle? - if (aChannel) - { - char *contentType; - aChannel->GetContentType(&contentType); - if (contentType) - { - if ( (nsCRT::strcmp(contentType, "text/html") != 0) && - (nsCRT::strcmp(contentType, "text/plain") != 0)) - { - mCloseWindowWhenLoaded = PR_TRUE; - mCantEditReason = eCantEditMimeType; - } - - nsMemory::Free(contentType); - } - } return NS_OK; } diff --git a/editor/base/nsEditorShell.h b/editor/base/nsEditorShell.h index c336a0a1391a..1d67651ef326 100644 --- a/editor/base/nsEditorShell.h +++ b/editor/base/nsEditorShell.h @@ -158,7 +158,7 @@ class nsEditorShell : public nsIEditorShell, nsresult UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs); // Helper method which is called at the beginning of a new page load - nsresult StartPageLoad(); + nsresult StartPageLoad(nsIChannel *aChannel); // Helper method which is called when an entire page load finishes nsresult EndPageLoad(nsIDOMWindow *aDOMWindow, @@ -174,6 +174,8 @@ class nsEditorShell : public nsIEditorShell, nsIChannel *aChannel, nsresult aStatus); + PRBool IsSupportedTextType(const char* aMIMEType); + // Check a preference and call NormalizeTable if pref is true // Use after deleting or inserting table cells to automatically // fix rowspan, colspan, and missing cells problems @@ -234,8 +236,11 @@ class nsEditorShell : public nsIEditorShell, PRPackedBool mCloseWindowWhenLoaded; // error on load. Close window when loaded ECantEditReason mCantEditReason; - EEditorType mEditorType; + EEditorType mEditorType; nsString mEditorTypeString; // string which describes which editor type will be instantiated (lowercased) + nsCString mContentMIMEType; // MIME type of the doc we are editing. + PRBool mContentTypeKnown; + PRInt32 mWrapColumn; // can't actually set this 'til the editor is created, so we may have to hold on to it for a while nsStringArray mSuggestedWordList; diff --git a/editor/composer/src/nsComposerCommands.cpp b/editor/composer/src/nsComposerCommands.cpp index 21cbbfb12c2b..1fdcaee387ff 100644 --- a/editor/composer/src/nsComposerCommands.cpp +++ b/editor/composer/src/nsComposerCommands.cpp @@ -94,6 +94,24 @@ nsBaseComposerCommand::SetCommandNodeState(const nsAReadableString & aCommandNam return uiNode->SetAttribute(NS_ConvertASCIItoUCS2("state"), inNodeState); } +//-------------------------------------------------------------------------------------------------------------------- +PRBool +nsBaseComposerCommand::EditingHTML(nsIEditorShell* inEditorShell) +//-------------------------------------------------------------------------------------------------------------------- +{ + nsXPIDLCString mimeType; + inEditorShell->GetContentsMIMEType(getter_Copies(mimeType)); + if (nsCRT::strcmp(mimeType, "text/html") != 0) + return PR_FALSE; + + PRBool sourceMode = PR_FALSE; + inEditorShell->IsHTMLSourceMode(&sourceMode); + if (sourceMode) + return PR_FALSE; + + return PR_TRUE; +} + #ifdef XP_MAC #pragma mark - @@ -119,23 +137,12 @@ nsBaseStateUpdatingCommand::IsCommandEnabled(const nsAReadableString & aCommandN { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (!editorShell) return NS_OK; - // check for plain text? - nsCOMPtr editor; - editorShell->GetEditor(getter_AddRefs(editor)); - if (!editor) return NS_OK; - // Enable commands only if not in HTML source edit mode - PRBool sourceMode = PR_FALSE; - editorShell->IsHTMLSourceMode(&sourceMode); - *outCmdEnabled = !sourceMode; - - // also udpate the command state - nsresult rv = UpdateCommandState(aCommandName, refCon); - if (NS_FAILED(rv)) + if (editorShell && EditingHTML(editorShell)) { - *outCmdEnabled = PR_FALSE; - return NS_OK; + *outCmdEnabled = PR_TRUE; + // also udpate the command state. + UpdateCommandState(aCommandName, refCon); } return NS_OK; @@ -472,7 +479,7 @@ nsRemoveListCommand::IsCommandEnabled(const nsAReadableString & aCommandName, ns { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { // It is enabled if we are in any list type PRBool bMixed; @@ -515,7 +522,7 @@ nsIndentCommand::IsCommandEnabled(const nsAReadableString & aCommandName, nsISup { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -547,7 +554,7 @@ nsOutdentCommand::IsCommandEnabled(const nsAReadableString & aCommandName, nsISu { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -571,7 +578,7 @@ nsOutdentCommand::DoCommand(const nsAReadableString & aCommandName, nsISupports nsCOMPtr editorShell = do_QueryInterface(refCon); nsresult rv = NS_OK; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsAutoString indentStr; indentStr.AssignWithConversion("outdent"); rv = editorShell->Indent(indentStr.GetUnicode()); @@ -602,7 +609,7 @@ nsMultiStateCommand::IsCommandEnabled(const nsAReadableString & aCommandName, ns { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -923,7 +930,7 @@ nsRemoveStylesCommand::IsCommandEnabled(const nsAReadableString & aCommandName, { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -968,7 +975,7 @@ nsIncreaseFontSizeCommand::IsCommandEnabled(const nsAReadableString & aCommandNa { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); @@ -1006,7 +1013,7 @@ nsDecreaseFontSizeCommand::IsCommandEnabled(const nsAReadableString & aCommandNa { nsCOMPtr editorShell = do_QueryInterface(refCon); *outCmdEnabled = PR_FALSE; - if (editorShell) + if (editorShell && EditingHTML(editorShell)) { nsCOMPtr editor; editorShell->GetEditor(getter_AddRefs(editor)); diff --git a/editor/composer/src/nsComposerCommands.h b/editor/composer/src/nsComposerCommands.h index 50948aa96006..bae9a8c690cf 100644 --- a/editor/composer/src/nsComposerCommands.h +++ b/editor/composer/src/nsComposerCommands.h @@ -59,6 +59,8 @@ protected: nsresult GetCommandNodeState(const nsAReadableString & aCommandName, nsIEditorShell* editorShell, nsString& outNodeState); nsresult SetCommandNodeState(const nsAReadableString & aCommandName, nsIEditorShell* editorShell, const nsString& inNodeState); + // are we in HTML edit mode (not source view or plain text editing) + PRBool EditingHTML(nsIEditorShell* inEditorShell); }; diff --git a/editor/composer/src/nsEditorShell.cpp b/editor/composer/src/nsEditorShell.cpp index efc4de68c926..7dd268d567c0 100644 --- a/editor/composer/src/nsEditorShell.cpp +++ b/editor/composer/src/nsEditorShell.cpp @@ -100,6 +100,8 @@ #include "nsILookAndFeel.h" #include "nsIChromeRegistry.h" +#include "nsCExternalHandlerService.h" +#include "nsIMIMEService.h" /////////////////////////////////////// // Editor Includes @@ -207,13 +209,14 @@ GetChromeElement(nsIDocShell *aShell, const char *aID, nsIDOMElement **aElement) // Utility to set and attribute of a UI element static nsresult SetChromeAttribute(nsIDocShell *aShell, const char *aID, - const char *aName, const nsString &aValue) + const nsAString& aName, const nsAString &aValue) { nsCOMPtr elem; nsresult rv = GetChromeElement(aShell, aID, getter_AddRefs(elem)); + + // Set the text attribute. if (NS_SUCCEEDED(rv) && elem) - // Set the text attribute. - rv = elem->SetAttribute( NS_ConvertASCIItoUCS2(aName), aValue); + rv = elem->SetAttribute(aName, aValue); return rv; } @@ -254,6 +257,8 @@ nsEditorShell::nsEditorShell() , mCloseWindowWhenLoaded(PR_FALSE) , mCantEditReason(eCantEditNoReason) , mEditorType(eUninitializedEditorType) +, mContentMIMEType("text/html") +, mContentTypeKnown(PR_FALSE) , mWrapColumn(0) , mSuggestedWordIndex(0) , mDictionaryIndex(0) @@ -436,6 +441,37 @@ nsEditorShell::ResetEditingState() return NS_OK; } + +// is this a MIME type that we support the editing of, in plain text mode? +const char* const gSupportedTextTypes[] = { + "text/plain", + "text/css", + "text/rdf", + "text/xml", + "text/xsl", + "text/javascript", // obsolete type + "application/x-javascript", + "text/xul", // obsolete type + "application/vnd.mozilla.xul+xml", + NULL // IMPORTANT! Null must be at end +}; + +PRBool +nsEditorShell::IsSupportedTextType(const char* aMIMEType) +{ + PRInt32 i = 0; + + while (gSupportedTextTypes[i]) + { + if (nsCRT::strcmp(gSupportedTextTypes[i], aMIMEType) == 0) + return PR_TRUE; + + i ++; + } + + return PR_FALSE; +} + nsresult nsEditorShell::PrepareDocumentForEditing(nsIDOMWindow* aDOMWindow, nsIURI *aUrl) { @@ -884,6 +920,21 @@ nsEditorShell::GetEditorType(PRUnichar **_retval) return NS_OK; } +/* attribute string contentsMIMEType; */ +NS_IMETHODIMP +nsEditorShell::GetContentsMIMEType(char * *aContentsMIMEType) +{ + NS_ENSURE_ARG_POINTER(aContentsMIMEType); + *aContentsMIMEType = mContentMIMEType.ToNewCString(); + return NS_OK; +} + +NS_IMETHODIMP +nsEditorShell::SetContentsMIMEType(const char * aContentsMIMEType) +{ + mContentMIMEType.Assign(aContentsMIMEType ? aContentsMIMEType : ""); + return NS_OK; +} nsresult nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell) @@ -895,58 +946,66 @@ nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell) if (mEditor) return NS_ERROR_ALREADY_INITIALIZED; - nsresult err = NS_OK; + nsresult rv = NS_OK; nsCOMPtr editor; - err = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, NS_GET_IID(nsIEditor), getter_AddRefs(editor)); - if(!editor) - err = NS_ERROR_OUT_OF_MEMORY; + rv = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, NS_GET_IID(nsIEditor), getter_AddRefs(editor)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr selCon = do_QueryInterface(aPresShell); - if (NS_SUCCEEDED(err)) + if (mEditorTypeString.EqualsWithConversion("text")) { - if (mEditorTypeString.EqualsWithConversion("text")) + PRInt16 flags = nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask; + if (mMailCompose) flags |= nsIPlaintextEditor::eEditorMailMask; + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, flags); + mEditorType = ePlainTextEditorType; + } + else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor + { + PRUint32 editorFlags = 0; + EEditorType editorType = eHTMLTextEditorType; + + // if the MIME type of the docment we are editing is text/plain, make a text editor + if (IsSupportedTextType(mContentMIMEType)) { - PRInt16 flags = nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask; - if (mMailCompose) flags |= nsIPlaintextEditor::eEditorMailMask; - err = editor->Init(aDoc, aPresShell, nsnull, selCon, flags); - mEditorType = ePlainTextEditorType; + editorFlags = nsIPlaintextEditor::eEditorPlaintextMask; + editorType = ePlainTextEditorType; } - else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor - { - err = editor->Init(aDoc, aPresShell, nsnull, selCon, 0); - mEditorType = eHTMLTextEditorType; - } - else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules - { - err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask); - mEditorType = eHTMLTextEditorType; - } - else - { - err = NS_ERROR_INVALID_ARG; // this is not an editor we know about + + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, editorFlags); + mEditorType = editorType; + } + else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules + { + rv = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask); + mEditorType = eHTMLTextEditorType; + } + else + { + rv = NS_ERROR_INVALID_ARG; // this is not an editor we know about #if DEBUG - nsAutoString errorMsg; errorMsg.AssignWithConversion("Failed to init editor. Unknown editor type \""); - errorMsg += mEditorTypeString; - errorMsg.AppendWithConversion("\"\n"); - char *errorMsgCString = errorMsg.ToNewCString(); - NS_WARNING(errorMsgCString); - nsCRT::free(errorMsgCString); + nsAutoString errorMsg; errorMsg.AssignWithConversion("Failed to init editor. Unknown editor type \""); + errorMsg += mEditorTypeString; + errorMsg.AppendWithConversion("\"\n"); + char *errorMsgCString = errorMsg.ToNewCString(); + NS_WARNING(errorMsgCString); + nsCRT::free(errorMsgCString); #endif - } + } // disable the preference style sheet so we can override colors - if (NS_SUCCEEDED(err)) { - err = aPresShell->EnablePrefStyleRules(PR_FALSE,0); - } + if (NS_SUCCEEDED(rv)) + { + rv = aPresShell->EnablePrefStyleRules(PR_FALSE,0); + } - if (NS_SUCCEEDED(err) && editor) - { - mEditor = do_QueryInterface(editor); // this does the addref that is the owning reference - } + if (NS_SUCCEEDED(rv) && editor) + { + mEditor = do_QueryInterface(editor); // this does the addref that is the owning reference } - return err; + return rv; } @@ -1688,6 +1747,27 @@ nsEditorShell::CheckOpenWindowForURLMatch(const PRUnichar* inFileURL, nsIDOMWind return NS_OK; } +// helper function +static nsresult GetExtensionForMIMEType(const char* inMIMEType, nsACString& outExtension) +{ + nsresult rv; + nsCOMPtr mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr mimeInfo; + rv = mimeService->GetFromMIMEType(inMIMEType, getter_AddRefs(mimeInfo)); + if (NS_FAILED(rv)) return rv; + + nsXPIDLCString fileExtension; + rv = mimeInfo->FirstExtension(getter_Copies(fileExtension)); + if (NS_FAILED(rv)) return rv; + + outExtension.Assign(fileExtension); + + return NS_OK; +} + + NS_IMETHODIMP nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* aMimeType, PRBool *_retval) { @@ -1696,13 +1776,20 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a NS_ENSURE_ARG_POINTER((aMimeType)); - nsAutoString mimeType(aMimeType); - PRBool saveAsText = mimeType.EqualsWithConversion("text/plain"); + nsCAutoString mimeTypeCStr; mimeTypeCStr.AssignWithConversion(aMimeType); + PRBool saveAsText = IsSupportedTextType(mimeTypeCStr); // Currently, we only understand plain text and html - if (!mimeType.EqualsWithConversion("text/html") && !saveAsText) + if (!mimeTypeCStr.Equals("text/html") && !saveAsText) return NS_ERROR_FAILURE; + nsAutoString mimeType(aMimeType); + + // if we're saving as text, force the text/plain MIME type (because we use this + // to get a content serializer on save) + if (saveAsText) + mimeType.Assign(NS_LITERAL_STRING("text/plain").get()); + switch (mEditorType) { case ePlainTextEditorType: @@ -1858,11 +1945,12 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a title.ReplaceChar(" .\\/@:", (PRUnichar)'_'); } + // get the correct extension from the MIME type here fileName = title; - if (saveAsText) - fileName.AppendWithConversion(".txt"); - else - fileName.AppendWithConversion(".html"); + nsCAutoString fileExt(saveAsText ? "txt" : "html"); + GetExtensionForMIMEType(mimeTypeCStr.get(), fileExt); + fileName.Append(PRUnichar('.')); + fileName.AppendWithConversion(fileExt); } else // have a file spec { @@ -1881,9 +1969,12 @@ nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* a index = fileName.RFind(".shtml", PR_TRUE); if (index > 0) { + nsCAutoString fileExt("txt"); + GetExtensionForMIMEType(mimeTypeCStr.get(), fileExt); + // Truncate after "." and append "txt" extension fileName.SetLength(index+1); - fileName.AppendWithConversion("txt"); + fileName.AppendWithConversion(fileExt); } } @@ -4934,6 +5025,8 @@ nsEditorShell::OnStateChange(nsIWebProgress *aProgress, PRInt32 aStateFlags, nsresult aStatus) { + nsresult rv = NS_OK; + // // A Request has started... // @@ -4942,7 +5035,8 @@ nsEditorShell::OnStateChange(nsIWebProgress *aProgress, // Page level notification... if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) { - StartPageLoad(); + nsCOMPtr channel(do_QueryInterface(aRequest)); + StartPageLoad(channel); } // Document level notification... if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) @@ -5013,12 +5107,36 @@ nsEditorShell::OnSecurityChange(nsIWebProgress *aWebProgress, return NS_OK; } -nsresult nsEditorShell::StartPageLoad() +nsresult nsEditorShell::StartPageLoad(nsIChannel *aChannel) { + nsXPIDLCString contentType; + aChannel->GetContentType(getter_Copies(contentType)); + + // save the original MIME type; we'll use it later + mContentMIMEType.Assign(contentType.get() ? contentType : ""); + + if (nsCRT::strcmp(contentType, "text/html") == 0) + { + // fine, do nothing + mContentTypeKnown = PR_TRUE; + } + else if (IsSupportedTextType(contentType)) + { + // set the mime type to text/plain so that it renders as text + aChannel->SetContentType("text/plain"); + mContentTypeKnown = PR_TRUE; + } + else + { + // we don't know what this is yet. It might be HTML loaded from + // a directory URL (http://www.foo.com/). We'll know the real + // MIME type later. + mContentTypeKnown = PR_FALSE; + } + // Start the throbber // TODO: We should also start/stop it for saving and publishing? - SetChromeAttribute( mDocShell, "Editor:Throbber", "busy", - NS_ConvertASCIItoUCS2("true") ); + SetChromeAttribute( mDocShell, "Editor:Throbber", NS_LITERAL_STRING("busy"), NS_LITERAL_STRING("true") ); // set up a parser observer if (!mParserObserver) @@ -5029,6 +5147,7 @@ nsresult nsEditorShell::StartPageLoad() } NS_ADDREF(mParserObserver); mParserObserver->RegisterTagToWatch("FRAMESET"); + mParserObserver->RegisterTagToWatch("IFRAME"); mParserObserver->Start(); } @@ -5048,12 +5167,31 @@ nsresult nsEditorShell::EndPageLoad(nsIDOMWindow *aDOMWindow, NS_RELEASE(mParserObserver); } - SetChromeAttribute( mDocShell, "Editor:Throbber", "busy", - NS_ConvertASCIItoUCS2("false") ); + SetChromeAttribute( mDocShell, "Editor:Throbber", NS_LITERAL_STRING("busy"), NS_LITERAL_STRING("false") ); + + // Is this a MIME type we can handle? + if (aChannel) + { + // if we didn't get the content-type at the start of the load, get it now + if (!mContentTypeKnown) + { + nsXPIDLCString contentType; + aChannel->GetContentType(getter_Copies(contentType)); + + if (contentType.get()) + mContentMIMEType.Assign(contentType); + } + } + + if ( !mContentMIMEType.Equals("text/html") && !IsSupportedTextType(mContentMIMEType) ) + { + mCloseWindowWhenLoaded = PR_TRUE; + mCantEditReason = eCantEditMimeType; + } nsAutoString doneText; GetBundleString(NS_LITERAL_STRING("LoadingDone"), doneText); - SetChromeAttribute(mDocShell, "statusText", "label", doneText); + SetChromeAttribute(mDocShell, "statusText", NS_LITERAL_STRING("label"), doneText); // Display an Alert dialog if the page cannot be edited... if (mCloseWindowWhenLoaded) @@ -5101,6 +5239,7 @@ nsresult nsEditorShell::EndPageLoad(nsIDOMWindow *aDOMWindow, { nsCOMPtr url; aChannel->GetURI(getter_AddRefs(url)); + (void) PrepareDocumentForEditing(aDOMWindow, url); } @@ -5143,24 +5282,6 @@ nsresult nsEditorShell::EndDocumentLoad(nsIDOMWindow *aDOMWindow, nsCOMPtr refreshURI = do_QueryInterface(mContentAreaDocShell); if (refreshURI) refreshURI->CancelRefreshURITimers(); - - // Is this a MIME type we can handle? - if (aChannel) - { - char *contentType; - aChannel->GetContentType(&contentType); - if (contentType) - { - if ( (nsCRT::strcmp(contentType, "text/html") != 0) && - (nsCRT::strcmp(contentType, "text/plain") != 0)) - { - mCloseWindowWhenLoaded = PR_TRUE; - mCantEditReason = eCantEditMimeType; - } - - nsMemory::Free(contentType); - } - } return NS_OK; } diff --git a/editor/composer/src/nsEditorShell.h b/editor/composer/src/nsEditorShell.h index c336a0a1391a..1d67651ef326 100644 --- a/editor/composer/src/nsEditorShell.h +++ b/editor/composer/src/nsEditorShell.h @@ -158,7 +158,7 @@ class nsEditorShell : public nsIEditorShell, nsresult UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs); // Helper method which is called at the beginning of a new page load - nsresult StartPageLoad(); + nsresult StartPageLoad(nsIChannel *aChannel); // Helper method which is called when an entire page load finishes nsresult EndPageLoad(nsIDOMWindow *aDOMWindow, @@ -174,6 +174,8 @@ class nsEditorShell : public nsIEditorShell, nsIChannel *aChannel, nsresult aStatus); + PRBool IsSupportedTextType(const char* aMIMEType); + // Check a preference and call NormalizeTable if pref is true // Use after deleting or inserting table cells to automatically // fix rowspan, colspan, and missing cells problems @@ -234,8 +236,11 @@ class nsEditorShell : public nsIEditorShell, PRPackedBool mCloseWindowWhenLoaded; // error on load. Close window when loaded ECantEditReason mCantEditReason; - EEditorType mEditorType; + EEditorType mEditorType; nsString mEditorTypeString; // string which describes which editor type will be instantiated (lowercased) + nsCString mContentMIMEType; // MIME type of the doc we are editing. + PRBool mContentTypeKnown; + PRInt32 mWrapColumn; // can't actually set this 'til the editor is created, so we may have to hold on to it for a while nsStringArray mSuggestedWordList; diff --git a/editor/idl/nsIEditorShell.idl b/editor/idl/nsIEditorShell.idl index 4e3337c039e4..369af00827de 100644 --- a/editor/idl/nsIEditorShell.idl +++ b/editor/idl/nsIEditorShell.idl @@ -45,6 +45,7 @@ interface nsIEditorShell : nsISupports attribute nsIDOMWindowInternal webShellWindow; attribute nsIDOMWindowInternal contentWindow; attribute wstring editorType; + attribute string contentsMIMEType; readonly attribute nsIEditor editor; diff --git a/editor/ui/composer/content/ComposerCommands.js b/editor/ui/composer/content/ComposerCommands.js index 46fc0d1f0651..7610d5ac9ac8 100644 --- a/editor/ui/composer/content/ComposerCommands.js +++ b/editor/ui/composer/content/ComposerCommands.js @@ -25,9 +25,6 @@ /* Implementations of nsIControllerCommand for composer commands */ -var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(); -promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService); - //----------------------------------------------------------------------------------- function SetupHTMLEditorCommands() { @@ -39,7 +36,9 @@ function SetupHTMLEditorCommands() // Include everthing a text editor does SetupTextEditorCommands(); - dump("Registering HTML editor commands\n"); + //dump("Registering HTML editor commands\n"); + + controller.registerCommand("cmd_renderedHTMLEnabler", nsDummyHTMLCommand); controller.registerCommand("cmd_listProperties", nsListPropertiesCommand); controller.registerCommand("cmd_pageProperties", nsPagePropertiesCommand); @@ -92,7 +91,7 @@ function SetupTextEditorCommands() if (!controller) return; - dump("Registering plain text editor commands\n"); + //dump("Registering plain text editor commands\n"); controller.registerCommand("cmd_find", nsFindCommand); controller.registerCommand("cmd_findNext", nsFindNextCommand); @@ -179,7 +178,7 @@ function SetupComposerWindowCommands() function GetEditorController() { var numControllers = window._content.controllers.getControllerCount(); - + // count down to find a controller that supplies a nsIControllerCommandManager interface for (var i = numControllers; i >= 0 ; i --) { @@ -187,11 +186,16 @@ function GetEditorController() try { var controller = window._content.controllers.getControllerAt(i); + var interfaceRequestor = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor); if (!interfaceRequestor) continue; commandManager = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandManager); - } catch(ex) {} + } + catch(ex) + { + //dump(ex + "\n"); + } if (commandManager) return commandManager; @@ -240,6 +244,22 @@ function PrintNodeID(id) PrintObject(document.getElementById(id)); } +//----------------------------------------------------------------------------------- +var nsDummyHTMLCommand = +{ + isCommandEnabled: function(aCommand, dummy) + { + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); + }, + + doCommand: function(aCommand) + { + // do nothing + dump("Hey, who's calling the dummy command?\n"); + } + +}; + //----------------------------------------------------------------------------------- var nsOpenCommand = { @@ -295,7 +315,7 @@ var nsSaveCommand = { FinishHTMLSource(); // In editor.js var doSaveAs = window.editorShell.editorDocument.location == "about:blank"; - var result = window.editorShell.saveDocument(doSaveAs, false, window.gDefaultSaveMimeType); + var result = window.editorShell.saveDocument(doSaveAs, false, editorShell.contentsMIMEType); window._content.focus(); return result; } @@ -315,7 +335,7 @@ var nsSaveAsCommand = if (window.editorShell) { FinishHTMLSource(); - var result = window.editorShell.saveDocument(true, false, window.gDefaultSaveMimeType); + var result = window.editorShell.saveDocument(true, false, editorShell.contentsMIMEType); window._content.focus(); return result; } @@ -363,7 +383,7 @@ var nsSaveAsCharsetCommand = } else { - window.ok = window.editorShell.saveDocument(true, false, window.gDefaultSaveMimeType); + window.ok = window.editorShell.saveDocument(true, false, editorShell.contentsMIMEType); } } window._content.focus(); @@ -384,6 +404,9 @@ var nsRevertCommand = doCommand: function(aCommand) { // Confirm with the user to abandon current changes + var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(); + promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService); + if (promptService) { var result = {value:0}; @@ -477,7 +500,7 @@ var nsPreviewCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell != null && (DocumentHasBeenSaved() || window.editorShell.documentModified)); + return (window.editorShell && IsEditorContentHTML() && (DocumentHasBeenSaved() || window.editorShell.documentModified)); }, doCommand: function(aCommand) @@ -612,7 +635,7 @@ var nsImageCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -626,7 +649,7 @@ var nsHLineCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -695,7 +718,7 @@ var nsLinkCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -709,7 +732,7 @@ var nsAnchorCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -723,7 +746,7 @@ var nsInsertHTMLCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -737,7 +760,7 @@ var nsInsertCharsCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -750,7 +773,7 @@ var nsInsertBreakCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -763,7 +786,7 @@ var nsInsertBreakAllCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -776,7 +799,7 @@ var nsListPropertiesCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -791,7 +814,7 @@ var nsPagePropertiesCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -806,7 +829,7 @@ var nsObjectPropertiesCommand = isCommandEnabled: function(aCommand, dummy) { var isEnabled = false; - if (window.editorShell && window.editorShell.documentEditable) + if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()) { isEnabled = (GetObjectForProperties() != null || window.editorShell.GetSelectedElement("href") != null); @@ -870,7 +893,7 @@ var nsSetSmiley = { isCommandEnabled: function(aCommand, dummy) { - return ( window.editorShell && window.editorShell.documentEditable); + return ( window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, @@ -959,7 +982,7 @@ var nsAdvancedPropertiesCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -974,7 +997,7 @@ var nsColorPropertiesCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -989,7 +1012,7 @@ var nsRemoveLinksCommand = isCommandEnabled: function(aCommand, dummy) { // We could see if there's any link in selection, but it doesn't seem worth the work! - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -1004,7 +1027,7 @@ var nsNormalModeCommand = { isCommandEnabled: function(aCommand, dummy) { - return true; //(window.editorShell && window.editorShell.documentEditable); + return IsEditorContentHTML(); //(window.editorShell && window.editorShell.documentEditable); }, doCommand: function(aCommand) { @@ -1017,7 +1040,7 @@ var nsAllTagsModeCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML()); }, doCommand: function(aCommand) { @@ -1030,7 +1053,7 @@ var nsHTMLSourceModeCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML()); }, doCommand: function(aCommand) { @@ -1043,7 +1066,7 @@ var nsPreviewModeCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditorContentHTML()); }, doCommand: function(aCommand) { @@ -1058,7 +1081,7 @@ var nsInsertOrEditTableCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()); }, doCommand: function(aCommand) { @@ -1153,7 +1176,7 @@ var nsInsertTableCommand = { isCommandEnabled: function(aCommand, dummy) { - return (window.editorShell && window.editorShell.documentEditable); + return window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML(); }, doCommand: function(aCommand) { @@ -1359,7 +1382,7 @@ var nsJoinTableCellsCommand = { isCommandEnabled: function(aCommand, dummy) { - if (window.editorShell && window.editorShell.documentEditable) + if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()) { var tagNameObj = new Object; var countObj = new Object; @@ -1407,7 +1430,7 @@ var nsSplitTableCellCommand = { isCommandEnabled: function(aCommand, dummy) { - if (window.editorShell && window.editorShell.documentEditable) + if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()) { var tagNameObj = new Object; var countObj = new Object; @@ -1507,6 +1530,8 @@ var nsConvertToTable = { isCommandEnabled: function(aCommand, dummy) { + if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()) + { var selection = window.editorShell.editorSelection; if (selection && !selection.isCollapsed) @@ -1525,6 +1550,7 @@ var nsConvertToTable = return false return true; + } } return false; }, @@ -1537,3 +1563,4 @@ var nsConvertToTable = window._content.focus(); } }; + diff --git a/editor/ui/composer/content/editor.js b/editor/ui/composer/content/editor.js index a82e7d85f276..231242879f65 100644 --- a/editor/ui/composer/content/editor.js +++ b/editor/ui/composer/content/editor.js @@ -70,7 +70,6 @@ var gColorObj = new Object(); var gPrefs; var gDefaultTextColor = ""; var gDefaultBackgroundColor = ""; -var gDefaultSaveMimeType = "text/html"; // These must be kept in synch with the XUL lists var gFontSizeNames = new Array("xx-small","x-small","small","medium","large","x-large","xx-large"); @@ -110,6 +109,17 @@ function PageIsEmptyAndUntouched() return (editorShell != null) && (editorShell.documentIsEmpty == true) && (docWasModified == false); } +function IsEditorContentHTML() +{ + return (editorShell.contentsMIMEType == "text/html"); +} + +// are we editing HTML (i.e. neither in HTML source mode, nor editing a text file) +function IsEditingRenderedHTML() +{ + return IsEditorContentHTML() && (gEditorDisplayMode != DisplayModeSource); +} + // This is called when the real editor document is created, // before it's loaded. var DocumentStateListener = @@ -189,7 +199,7 @@ function EditorStartup(editorType, editorElement) EditorSharedStartup(); // Commands specific to the Composer Application window, - // (i.e., not embeded editors) + // (i.e., not embedded editors) // such as file-related commands, HTML Source editing, Edit Modes... SetupComposerWindowCommands(); @@ -211,17 +221,17 @@ function EditorSharedStartup() case "html": case "htmlmail": SetupHTMLEditorCommands(); - window.gDefaultSaveMimeType = "text/html"; + editorShell.contentsMIMEType = "text/html"; break; case "text": case "textmail": SetupTextEditorCommands(); - window.gDefaultSaveMimeType = "text/plain"; + editorShell.contentsMIMEType = "text/plain"; break; default: dump("INVALID EDITOR TYPE: "+editorShell.editorType+"\n"); SetupTextEditorCommands(); - window.gDefaultSaveMimeType = "text/plain"; + editorShell.contentsMIMEType = "text/plain"; break; } @@ -395,6 +405,9 @@ function CheckAndSaveDocument(reasonToSave, allowDontSave) var dialogMsg = window.editorShell.GetString("SaveFilePrompt"); dialogMsg = (dialogMsg.replace(/%title%/,title)).replace(/%reason%/,reasonToSave); + var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(); + promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService); + var result = {value:0}; promptService.confirmEx(window, dialogTitle, dialogMsg, (promptService.BUTTON_TITLE_SAVE * promptService.BUTTON_POS_0) + @@ -406,7 +419,7 @@ function CheckAndSaveDocument(reasonToSave, allowDontSave) if (result.value == 0) { // Save - var success = window.editorShell.saveDocument(false, false, window.gDefaultSaveMimeType); + var success = window.editorShell.saveDocument(false, false, editorShell.contentsMIMEType); return success; } @@ -1230,15 +1243,15 @@ function SetDisplayMode(mode) // Switch to the sourceWindow (second in the deck) gContentWindowDeck.setAttribute("index","1"); - DisableMenusForHTMLSource(true); - - //Hide the formating toolbar if not already hidden + //Hide the formatting toolbar if not already hidden gFormatToolbarHidden = gFormatToolbar.getAttribute("hidden"); if (gFormatToolbarHidden != "true") { gFormatToolbar.setAttribute("hidden", "true"); } + // update commands to disable stuff + window.updateCommands("mode_switch"); gSourceContentWindow.focus(); } else @@ -1247,13 +1260,14 @@ function SetDisplayMode(mode) gContentWindowDeck.setAttribute("index","0"); // Restore menus and toolbars - DisableMenusForHTMLSource(false); - if (gFormatToolbarHidden != "true") { gFormatToolbar.setAttribute("hidden", gFormatToolbarHidden); } + // update commands to re-enable stuff + window.updateCommands("mode_switch"); + gContentWindow.focus(); } @@ -1287,51 +1301,6 @@ function SetDisplayMode(mode) return false; } -// We disable all items in View menu except Edit mode and sidebar items -function DisableMenusForHTMLSource(disable) -{ - // Disable toolbar buttons - DisableItem("spellingButton", disable); - DisableItem("imageButton", disable); - DisableItem("hlineButton", disable); - DisableItem("tableButton", disable); - DisableItem("linkButton", disable); - DisableItem("namedAnchorButton", disable); - - // Any toolbar can be toggled on/off except the format toolbar - DisableItem("viewFormatToolbar", disable); - - - // Top-level menus that we completely hide - CollapseItem("insertMenu", disable); - CollapseItem("formatMenu", disable); - CollapseItem("tableMenu", disable); - - // Edit menu items - DisableItem("menu_find", disable); - DisableItem("menu_findnext", disable); - DisableItem("menu_replace", disable); - DisableItem("menu_checkspelling", disable); - - // Disable all items in the view menu except mode switch items - var viewMenu = document.getElementById("viewMenu"); - // menuitems are children of the menupopup child - var children = viewMenu.firstChild.childNodes; - for (var i = 0; i < children.length; i++) - { - var item = children.item(i); - if (item.id != "viewToolbar" && - item.id != "viewNormalMode" && - item.id != "viewAllTagsMode" && - item.id != "viewSourceMode" && - item.id != "viewPreviewMode" && - item.id != "sidebar-menu") - { - DisableItem(item.id, disable); - } - } -} - function EditorToggleParagraphMarks() { var menuItem = document.getElementById("viewParagraphMarks"); @@ -1529,8 +1498,10 @@ function getUnicharPref(aPrefName, aDefVal) function EditorInitFormatMenu() { - InitObjectPropertiesMenuitem("objectProperties"); - InitRemoveStylesMenuitems("removeStylesMenuitem", "removeLinksMenuitem"); + try { + InitObjectPropertiesMenuitem("objectProperties"); + InitRemoveStylesMenuitems("removeStylesMenuitem", "removeLinksMenuitem"); + } catch(ex) {} // Set alignment check } @@ -1542,10 +1513,13 @@ function InitObjectPropertiesMenuitem(id) var menuItem = document.getElementById(id); if (!menuItem) return null; - var element = GetObjectForProperties(); + var element; var menuStr = GetString("ObjectProperties"); var name; + if (IsEditingRenderedHTML()) + element = GetObjectForProperties(); + if (element && element.nodeName) { var objStr = ""; @@ -1671,6 +1645,18 @@ function InitAlignMenu() function EditorInitToolbars() { // Nothing to do now, but we might want some state updating here + if (!IsEditorContentHTML()) + { + //Hide the formating toolbar + gFormatToolbar.setAttribute("hidden", "true"); + + //Hide the edit mode toolbar + gEditModeBar.setAttribute("hidden", "true"); + + DisableItem("cmd_viewFormatToolbar", true); + DisableItem("cmd_viewEditModeToolbar", true); + } + } function EditorSetDefaultPrefsAndDoctype() @@ -2044,7 +2030,7 @@ function IsSpellCheckerInstalled() var spellcheckerClass = Components.classes["@mozilla.org/spellchecker;1"]; gHaveSpellChecker = (spellcheckerClass != null); gSoughtSpellChecker = true; - dump("Have SpellChecker = "+gHaveSpellChecker+"\n"); + //dump("Have SpellChecker = "+gHaveSpellChecker+"\n"); return gHaveSpellChecker; } @@ -2059,7 +2045,7 @@ function IsFindInstalled() var findClass = Components.classes["@mozilla.org/appshell/component/find;1"]; gHaveFind = (findClass != null); gSoughtFind = true; - dump("Have Find = "+gHaveFind+"\n"); + //dump("Have Find = "+gHaveFind+"\n"); return gHaveFind; } @@ -2139,7 +2125,9 @@ function GetPrefsService() // with this "oncreate" hander: function EditorInitTableMenu() { - InitJoinCellMenuitem("menu_JoinTableCells"); + try { + InitJoinCellMenuitem("menu_JoinTableCells"); + } catch (ex) {} // Set enable states for all table commands goUpdateTableMenuItems(document.getElementById("composerTableMenuItems")); @@ -2159,7 +2147,12 @@ function InitJoinCellMenuitem(id) // Use "Join selected cells if there's more than 1 cell selected var tagNameObj = new Object; var countObj = new Object; - if (window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj) && countObj.value > 1) + var foundElement; + + if (IsEditingRenderedHTML()) + foundElement = window.editorShell.GetSelectedOrParentTableElement(tagNameObj, countObj); + + if (foundElement && countObj.value > 1) menuText = GetString("JoinSelectedCells"); else menuText = GetString("JoinCellToRight"); @@ -2195,9 +2188,9 @@ function InitRemoveStylesMenuitems(removeStylesId, removeLinksId) function goUpdateTableMenuItems(commandset) { var enabled = false; - var enabledIfTable = false; - if (window.editorShell && window.editorShell.documentEditable) + + if (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML()) { var selectedCountObj = new Object(); var tagNameObj = new Object(); @@ -2246,13 +2239,13 @@ function goUpdateTableMenuItems(commandset) function IsInTable() { - return (window.editorShell && window.editorShell.documentEditable && + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML() && null != window.editorShell.GetElementOrParentByTagName("table", null)); } function IsInTableCell() { - return (window.editorShell && window.editorShell.documentEditable && + return (window.editorShell && window.editorShell.documentEditable && IsEditingRenderedHTML() && null != window.editorShell.GetElementOrParentByTagName("td", null)); } @@ -2476,3 +2469,4 @@ function SwitchInsertCharToAnotherEditorOrClose() window.InsertCharWindow.close(); } } + diff --git a/editor/ui/composer/content/editor.xul b/editor/ui/composer/content/editor.xul index da41901d2e80..76a46f43ea59 100644 --- a/editor/ui/composer/content/editor.xul +++ b/editor/ui/composer/content/editor.xul @@ -250,7 +250,7 @@ -