diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp index 52dbc2391aa..65aba5c337d 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp @@ -136,6 +136,8 @@ #include "nsBidiUtils.h" #endif +#include "nsIEditingSession.h" + #define DETECTOR_CONTRACTID_MAX 127 static char g_detector_contractid[DETECTOR_CONTRACTID_MAX + 1]; static PRBool gInitDetector = PR_FALSE; @@ -292,7 +294,8 @@ nsHTMLDocument::nsHTMLDocument() mReferrer(nsnull), mNumForms(0), mIsWriting(0), - mDomainWasSet(PR_FALSE) + mDomainWasSet(PR_FALSE), + mEditingIsOn(PR_FALSE) { mImages = nsnull; mApplets = nsnull; @@ -4025,3 +4028,467 @@ nsHTMLDocument::RemoveWyciwygChannel(void) return rv; } + +/* attribute DOMString designMode; */ +NS_IMETHODIMP +nsHTMLDocument::GetDesignMode(nsAString & aDesignMode) +{ + if (mEditingIsOn) { + aDesignMode.Assign(NS_LITERAL_STRING("on")); + } + else { + aDesignMode.Assign(NS_LITERAL_STRING("off")); + } + return NS_OK; +} + +NS_IMETHODIMP +nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode) +{ + // get editing session + if (!mScriptGlobalObject) + return NS_ERROR_FAILURE; + + nsCOMPtr docshell; + mScriptGlobalObject->GetDocShell(getter_AddRefs(docshell)); + if (!docshell) + return NS_ERROR_FAILURE; + + nsCOMPtr editSession = do_GetInterface(docshell); + if (!editSession) + return NS_ERROR_FAILURE; + + if (aDesignMode.Equals(NS_LITERAL_STRING("on"), + nsCaseInsensitiveStringComparator())) { + // go through hoops to get dom window (see nsHTMLDocument::GetSelection) + nsCOMPtr shell = (nsIPresShell*)mPresShells.SafeElementAt(0); + NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE); + + nsCOMPtr cx; + shell->GetPresContext(getter_AddRefs(cx)); + NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); + + nsCOMPtr container; + cx->GetContainer(getter_AddRefs(container)); + NS_ENSURE_TRUE(container, NS_OK); + + nsCOMPtr domwindow(do_GetInterface(container)); + NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE); + + nsresult rv = editSession->Init(domwindow); // content root frame + if (NS_FAILED(rv)) + return rv; + + rv = editSession->MakeWindowEditable(domwindow, "html", false); + if (NS_FAILED(rv)) + return rv; + + // now that we've successfully created the editor, we can reset our flag + mEditingIsOn = PR_TRUE; + } + else { // turn editing off + // right now we don't have a way to turn off editing :-( + mEditingIsOn = PR_FALSE; + } + + return NS_OK; +} + +nsresult +nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr) +{ + // initialize return value + NS_ENSURE_ARG_POINTER(aCmdMgr); + + // check if we have it cached + if (mMidasCommandManager) { + NS_ADDREF(*aCmdMgr = mMidasCommandManager); + return NS_OK; + } + + *aCmdMgr = nsnull; + if (!mScriptGlobalObject) + return NS_ERROR_FAILURE; + + nsCOMPtr docshell; + mScriptGlobalObject->GetDocShell(getter_AddRefs(docshell)); + if (!docshell) + return NS_ERROR_FAILURE; + + nsCOMPtr mMidasCommandManager = do_GetInterface(docshell); + if (!mMidasCommandManager) + return NS_ERROR_FAILURE; + + NS_ADDREF(*aCmdMgr = mMidasCommandManager); + return NS_OK; +} + + +struct MidasCommand { + const char* incomingCommandString; + const char* internalCommandString; + const char* internalParamString; + PRBool useNewParam; +}; + +static struct MidasCommand gMidasCommandTable[] = { + { "bold", "cmd_bold", "", PR_TRUE }, + { "italic", "cmd_italic", "", PR_TRUE }, + { "underline", "cmd_underline", "", PR_TRUE }, + { "strikethrough", "cmd_strikethrough", "", PR_TRUE }, + { "subscript", "cmd_subscript", "", PR_TRUE }, + { "superscript", "cmd_superscript", "", PR_TRUE }, + { "cut", "cmd_cut", "", PR_TRUE }, + { "copy", "cmd_copy", "", PR_TRUE }, + { "paste", "cmd_paste", "", PR_TRUE }, + { "delete", "cmd_delete", "", PR_TRUE }, + { "selectall", "cmd_selectall", "", PR_TRUE }, + { "undo", "cmd_undo", "", PR_TRUE }, + { "redo", "cmd_redo", "", PR_TRUE }, + { "indent", "cmd_indent", "", PR_TRUE }, + { "outdent", "cmd_outdent", "", PR_TRUE }, + { "backcolor", "cmd_backgroundColor", "", PR_FALSE }, + { "forecolor", "cmd_fontColor", "", PR_FALSE }, + { "fontname", "cmd_fontFace", "", PR_FALSE }, + { "horizontalline", "cmd_hline", "", PR_TRUE }, + { "hr", "cmd_hline", "", PR_TRUE }, + { "createlink", "cmd_link", "", PR_TRUE }, + { "justifyleft", "cmd_align", "left", PR_TRUE }, + { "justifyright", "cmd_align", "right", PR_TRUE }, + { "justifycenter", "cmd_align", "center", PR_TRUE }, + { "justifyfull", "cmd_align", "justify", PR_TRUE }, + { "removeformat", "cmd_removeStyles", "", PR_TRUE }, + { "unlink", "cmd_removeLinks", "", PR_TRUE }, + { "orderlist", "cmd_ol", "", PR_TRUE }, + { "unorderlist", "cmd_ul", "", PR_TRUE }, + { "paragraph", "cmd_paragraphState", "p", PR_TRUE }, + { "formatblock", "cmd_paragraphState", "", PR_FALSE }, + { "heading", "cmd_paragraphState", "", PR_FALSE }, +#if 0 + { "fontsize", "cmd_fontSize", "", PR_FALSE }, + { "justifynone", "cmd_align", "", PR_TRUE }, + { "saveas", "cmd_saveAs", "", PR_TRUE }, + { "print", "cmd_print", "", PR_TRUE }, +#endif + { NULL, NULL, NULL, PR_FALSE } +}; + +#define MidasCommandCount ((sizeof(gMidasCommandTable) / sizeof(struct MidasCommand)) - 1) + + +// this function will return false if the command is not recognized +// inCommandID will be converted as necessary for internal operations +// inParam will be converted as necessary for internal operations +// outParam will be Empty if no parameter is needed +PRBool +nsHTMLDocument::ConvertToMidasInternalCommand(const nsAString & inCommandID, + const nsAString & inParam, + nsACString& outCommandID, + nsACString& outParam) +{ + nsCAutoString convertedCommandID = NS_ConvertUCS2toUTF8(inCommandID); + PRUint32 i; + for (i = 0; i < MidasCommandCount; ++i) { + if (convertedCommandID.Equals(gMidasCommandTable[i].incomingCommandString, + nsCaseInsensitiveCStringComparator())) { + // set outCommandID (what we use internally) + outCommandID.Assign(gMidasCommandTable[i].internalCommandString); + + // set outParam based on the flag from the table + if (gMidasCommandTable[i].useNewParam) { + outParam.Assign(gMidasCommandTable[i].internalParamString); + } + else { + // pass through the parameter that was passed to us + outParam.Assign(NS_ConvertUCS2toUTF8(inParam)); + } + + return PR_TRUE; + } + } + + // reset results if the command is not found in our table + outCommandID.SetLength(0); + outParam.SetLength(0); + return PR_FALSE; +} + +/* TODO: don't let this call do anything if the page is not done loading */ +/* boolean execCommand(in DOMString commandID, in boolean doShowUI, + in DOMString value); */ +NS_IMETHODIMP +nsHTMLDocument::ExecCommand(const nsAString & commandID, + PRBool doShowUI, + const nsAString & value, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + // for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go() + // this might add some ugly JS dependencies? + + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + // if they are requesting UI from us, let's fail since we have no UI + if (doShowUI) + return NS_ERROR_NOT_IMPLEMENTED; + + // TEMPORARY HACK: (this block will go away very soon) + // always set focus to this widget so the command can be executed only in + // this scope (we wouldn't want to be able to execute commands outside of + // our own editor scope + nsCOMPtr wintmp = do_QueryInterface(mScriptGlobalObject); + if (!wintmp) + return NS_ERROR_FAILURE; + nsresult rv2 = wintmp->Focus(); + if (NS_FAILED(rv2)) + return rv2; + + // get command manager and dispatch command to our window if it's acceptable + nsCOMPtr cmdMgr; + nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr)); + if (NS_FAILED(rv)) + return rv; + if (!cmdMgr) + return NS_ERROR_FAILURE; + + nsCOMPtr window = do_QueryInterface(mScriptGlobalObject); + if (!window) + return NS_ERROR_FAILURE; + + nsCAutoString cmdToDispatch, paramStr; + if (!ConvertToMidasInternalCommand(commandID, value, cmdToDispatch, paramStr)) + return NS_ERROR_NOT_IMPLEMENTED; + + if (paramStr.IsEmpty()) { + rv = cmdMgr->DoCommand(cmdToDispatch.get(), nsnull); + } else { + // we have a command that requires a parameter, create params + nsCOMPtr cmdParams = do_CreateInstance( + NS_COMMAND_PARAMS_CONTRACTID, &rv); + if (!cmdParams) + return NS_ERROR_OUT_OF_MEMORY; + rv = cmdParams->SetCStringValue("state_attribute", paramStr.get()); + if (NS_FAILED(rv)) + return rv; + rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams); + } + + *_retval = NS_SUCCEEDED(rv); + + return rv; +} + +/* TODO: don't let this call do anything if the page is not done loading */ +/* boolean execCommandShowHelp(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::ExecCommandShowHelp(const nsAString & commandID, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* boolean queryCommandEnabled(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandEnabled(const nsAString & commandID, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* boolean queryCommandIndeterm (in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* boolean queryCommandState(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandState(const nsAString & commandID, PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + // TEMPORARY HACK: (this block will go away very soon) + // always set focus to this widget so the command can be executed only in + // this scope (we wouldn't want to be able to execute commands outside of + // our own editor scope + nsCOMPtr wintmp = do_QueryInterface(mScriptGlobalObject); + if (!wintmp) + return NS_ERROR_FAILURE; + nsresult rv2 = wintmp->Focus(); + if (NS_FAILED(rv2)) + return rv2; + + // get command manager and dispatch command to our window if it's acceptable + nsCOMPtr cmdMgr; + nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr)); + if (NS_FAILED(rv)) + return rv; + if (!cmdMgr) + return NS_ERROR_FAILURE; + + nsCOMPtr window = do_QueryInterface(mScriptGlobalObject); + if (!window) + return NS_ERROR_FAILURE; + + nsCAutoString cmdToDispatch, paramToCheck; + if (!ConvertToMidasInternalCommand(commandID, commandID, + cmdToDispatch, paramToCheck)) + return NS_ERROR_NOT_IMPLEMENTED; + + nsCOMPtr cmdParams = do_CreateInstance( + NS_COMMAND_PARAMS_CONTRACTID, &rv); + if (!cmdParams) + return NS_ERROR_OUT_OF_MEMORY; + + rv = cmdMgr->GetCommandState(cmdToDispatch.get(), cmdParams); + if (NS_FAILED(rv)) + return rv; + + // handle alignment as a special case (possibly other commands too?) + // Alignment is special because the external api is individual commands + // but internally we use cmd_align with different parameters. When getting + // the state of this command, we need to return the boolean for this + // particular alignment rather than the string of 'which alignment is this?' + if (cmdToDispatch.Equals("cmd_align")) { + char * actualAlignmentType = nsnull; + rv = cmdParams->GetCStringValue("state_attribute", &actualAlignmentType); + if (NS_SUCCEEDED(rv) && actualAlignmentType && actualAlignmentType[0]) { + *_retval = paramToCheck.Equals(actualAlignmentType); + } + if (actualAlignmentType) + nsMemory::Free(actualAlignmentType); + } + else { + rv = cmdParams->GetBooleanValue("state_all", _retval); + if (NS_FAILED(rv)) + *_retval = PR_FALSE; + } + + return rv; +} + +/* boolean queryCommandSupported(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandSupported(const nsAString & commandID, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* DOMString queryCommandText(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandText(const nsAString & commandID, + nsAString & _retval) +{ + _retval.SetLength(0); + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* DOMString queryCommandValue(in DOMString commandID); */ +NS_IMETHODIMP +nsHTMLDocument::QueryCommandValue(const nsAString & commandID, + nsAString &_retval) +{ + _retval.SetLength(0); + + // if editing is not on, bail + if (!mEditingIsOn) + return NS_ERROR_FAILURE; + + // TEMPORARY HACK: (this block will go away very soon) + // always set focus to this widget so the command can be executed only in + // this scope (we wouldn't want to be able to execute commands outside of + // our own editor scope + nsCOMPtr wintmp = do_QueryInterface(mScriptGlobalObject); + if (!wintmp) + return NS_ERROR_FAILURE; + nsresult rv2 = wintmp->Focus(); + if (NS_FAILED(rv2)) + return rv2; + + // get command manager and dispatch command to our window if it's acceptable + nsCOMPtr cmdMgr; + nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr)); + if (NS_FAILED(rv)) + return rv; + if (!cmdMgr) + return NS_ERROR_FAILURE; + + nsCOMPtr window = do_QueryInterface(mScriptGlobalObject); + if (!window) + return NS_ERROR_FAILURE; + + nsCAutoString cmdToDispatch, paramStr; + if (!ConvertToMidasInternalCommand(commandID, commandID, + cmdToDispatch, paramStr)) + return NS_ERROR_NOT_IMPLEMENTED; + + // create params + nsCOMPtr cmdParams = do_CreateInstance( + NS_COMMAND_PARAMS_CONTRACTID, &rv); + if (!cmdParams) + return NS_ERROR_OUT_OF_MEMORY; + rv = cmdParams->SetCStringValue("state_attribute", paramStr.get()); + if (NS_FAILED(rv)) + return rv; + + rv = cmdMgr->GetCommandState(cmdToDispatch.get(), cmdParams); + if (NS_FAILED(rv)) + return rv; + + char *cStringResult = nsnull; + rv = cmdParams->GetCStringValue("state_attribute", &cStringResult); + if (NS_SUCCEEDED(rv) && cStringResult && cStringResult[0]) { + _retval.Assign(NS_ConvertUTF8toUCS2(cStringResult)); + } + if (cStringResult) { + nsMemory::Free(cStringResult); + } + + return rv; +} diff --git a/mozilla/dom/public/idl/html/nsIDOMNSHTMLDocument.idl b/mozilla/dom/public/idl/html/nsIDOMNSHTMLDocument.idl index dbc9adeb972..2fac39969c1 100644 --- a/mozilla/dom/public/idl/html/nsIDOMNSHTMLDocument.idl +++ b/mozilla/dom/public/idl/html/nsIDOMNSHTMLDocument.idl @@ -72,4 +72,35 @@ interface nsIDOMNSHTMLDocument : nsISupports // mapped to attribute embeds for NS4 compat readonly attribute nsIDOMHTMLCollection plugins; + + + /** + * Midas additions + */ + attribute DOMString designMode; + + boolean execCommand(in DOMString commandID, + in boolean doShowUI, + in DOMString value); + + // returns true if the help is being shown for command (false if not) + boolean execCommandShowHelp(in DOMString commandID); + + // returns true if the command is enabled (false otherwise) + boolean queryCommandEnabled(in DOMString commandID); + + // returns true if the command is in a indeterminate state (false otherwise) + boolean queryCommandIndeterm(in DOMString commandID); + + // returns true if the command has been executed (false otherwise) + boolean queryCommandState(in DOMString commandID); + + // returns true if the command is supported on the current range + boolean queryCommandSupported(in DOMString commandID); + + // + DOMString queryCommandText(in DOMString commandID); + + // returns the current value of the document or current selection for command + DOMString queryCommandValue(in DOMString commandID); };