Fixed bugs 12515, 16493,16494,16495,16692,16794,most of 9758. Replaced old 'target' icon with interim 'anchor' icon. r=sfraser

This commit is contained in:
cmanske%netscape.com 1999-10-20 14:15:25 +00:00
parent 3f31c6d6f2
commit e7457117e4
25 changed files with 421 additions and 195 deletions

View File

@ -1173,7 +1173,10 @@ nsEditorShell::CheckAndSaveDocument(PRBool *_retval)
// Ask user if they want to save current changes
nsAutoString tmp1 = GetString("Save");
nsAutoString tmp2 = GetString("DontSave");
EConfirmResult result = ConfirmWithCancel(GetString("SaveDocument"), GetString("SaveFilePrompt"),
nsAutoString title;
GetDocumentTitle(title);
nsAutoString saveMsg = GetString("SaveFilePrompt")+" "+"\""+title+"\""+GetString("QuestionMark");
EConfirmResult result = ConfirmWithCancel(GetString("SaveDocument"), saveMsg,
&tmp1, &tmp2);
if (result == eCancel)
{
@ -1216,7 +1219,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
// find out if the doc already has a fileSpec associated with it.
nsFileSpec docFileSpec;
PRBool mustShowFileDialog = saveAs || (diskDoc->GetFileSpec(docFileSpec) == NS_ERROR_NOT_INITIALIZED);
PRBool noFileSpec = (diskDoc->GetFileSpec(docFileSpec) == NS_ERROR_NOT_INITIALIZED);
PRBool mustShowFileDialog = saveAs || noFileSpec;
PRBool replacing = !saveAs;
if (mustShowFileDialog)
@ -1230,7 +1234,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
nsString title;
res = HTMLDoc->GetTitle(title);
if (NS_SUCCEEDED(res) && title.Length() == 0)
// Prompt for title ONLY for a new blank doc (no filespec yet)
if (noFileSpec && NS_SUCCEEDED(res) && title.Length() == 0)
{
// Use a "prompt" common dialog to get title string from user
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &res);
@ -1250,7 +1255,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
return NS_OK;
}
//This will call UpdateWindowTitle
SetTitle(titleUnicode);
SetDocumentTitle(titleUnicode);
title = titleUnicode;
bUpdateWindowTitle = PR_FALSE;
nsCRT::free(titleUnicode);
}
@ -1260,14 +1266,16 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
res = nsComponentManager::CreateInstance(kCFileWidgetCID, nsnull, nsIFileWidget::GetIID(), getter_AddRefs(fileWidget));
if (NS_SUCCEEDED(res) && fileWidget)
{
nsString promptString = GetString("SaveDocumentAs");
nsAutoString promptString = GetString("SaveDocumentAs");
nsString* titles = nsnull;
nsString* filters = nsnull;
nsString* nextTitle;
nsString* nextFilter;
nsString HTMLFiles;
nsString TextFiles;
nsAutoString HTMLFiles;
nsAutoString TextFiles;
nsAutoString fileName;
nsFileSpec parentPath;
titles = new nsString[2];
if (!titles)
@ -1289,15 +1297,50 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
if (HTMLFiles.Length() == 0 || TextFiles.Length() == 0)
goto SkipFilters;
*nextTitle++ = "HTML Files";
*nextTitle++ = HTMLFiles;
*nextFilter++ = "*.htm; *.html; *.shtml";
*nextTitle++ = "Text Files";
*nextTitle++ = TextFiles;
*nextFilter++ = "*.txt";
fileWidget->SetFilterList(2, titles, filters);
if (noFileSpec)
{
// Use page title as suggested name for new document
if (title.Length() > 0)
{
//Replace "bad" filename characteres with "_"
PRUnichar space = (PRUnichar)' ';
PRUnichar dot = (PRUnichar)'.';
PRUnichar bslash = (PRUnichar)'\\';
PRUnichar fslash = (PRUnichar)'/';
PRUnichar amp = (PRUnichar)'@';
PRUnichar colon = (PRUnichar)':';
PRUnichar underscore = (PRUnichar)'_';
title = title.ReplaceChar(space, underscore);
title = title.ReplaceChar(dot, underscore);
title = title.ReplaceChar(bslash, underscore);
title = title.ReplaceChar(fslash, underscore);
title = title.ReplaceChar(amp, underscore);
title = title.ReplaceChar(colon, underscore);
fileName = title + nsString(".html");
}
} else {
char *leafName = docFileSpec.GetLeafName();
if (leafName)
{
fileName = leafName;
nsCRT::free(leafName);
}
docFileSpec.GetParent(parentPath);
// TODO: CHANGE TO THE DIRECTORY OF THE PARENT PATH?
}
if (fileName.Length() > 0)
fileWidget->SetDefaultString(fileName);
SkipFilters:
nsFileDlgResults dialogResult;
// 1ST PARAM SHOULD BE nsIDOMWindow*, not nsIWidget*
dialogResult = fileWidget->PutFile(/*mContentWindow*/nsnull, promptString, docFileSpec);
dialogResult = fileWidget->PutFile(nsnull, promptString, docFileSpec);
delete [] titles;
delete [] filters;
@ -1449,20 +1492,43 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindow *parent, const PRUnichar *filterType
if (NS_SUCCEEDED(res))
{
nsFileDlgResults dialogResult;
nsString* titles = nsnull;
nsString* filters = nsnull;
nsString* nextTitle;
nsString* nextFilter;
if (htmlFilter)
{
nsAutoString titles[] = {"HTML Files"};
nsAutoString filters[] = {"*.htm; *.html; *.shtml"};
fileWidget->SetFilterList(1, titles, filters);
// First param should be Parent window, but type is nsIWidget*
// Bug is filed to change this to a more suitable window type
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
titles = new nsString[3];
filters = new nsString[3];
if (!titles || ! filters)
return NS_ERROR_OUT_OF_MEMORY;
nextTitle = titles;
nextFilter = filters;
*nextTitle++ = GetString("HTMLFiles");
*nextTitle++ = GetString("TextFiles");
*nextFilter++ = "*.htm; *.html; *.shtml";
*nextFilter++ = "*.txt";
fileWidget->SetFilterList(3, titles, filters);
} else {
nsAutoString imgTitles[] = {"Image Files"};
nsAutoString imgFilters[] = {"*.gif; *.jpg; *.jpeg; *.png"};
fileWidget->SetFilterList(1, imgTitles, imgFilters);
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
titles = new nsString[2];
filters = new nsString[2];
if (!titles || ! filters)
return NS_ERROR_OUT_OF_MEMORY;
nextTitle = titles;
nextFilter = filters;
*nextTitle++ = GetString("IMGFiles");
*nextFilter++ = "*.gif; *.jpg; *.jpeg; *.png", "*.*";
fileWidget->SetFilterList(2, titles, filters);
}
*nextTitle++ = GetString("AllFiles");
*nextFilter++ = "*.*";
// First param should be Parent window, but type is nsIWidget*
// Bug is filed to change this to a more suitable window type
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
delete [] titles;
delete [] filters;
// Do this after we get this from preferences
//fileWidget->SetDisplayDirectory(aDisplayDirectory);
@ -1484,10 +1550,23 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindow *parent, const PRUnichar *filterType
NS_IMETHODIMP
nsEditorShell::UpdateWindowTitle()
{
if (!mContentAreaWebShell)
return NS_ERROR_NOT_INITIALIZED;
nsAutoString windowCaption;
nsresult res = GetDocumentTitle(windowCaption);
if (NS_SUCCEEDED(res))
res = mContentAreaWebShell->SetTitle(windowCaption.GetUnicode());
return res;
}
NS_IMETHODIMP
nsEditorShell::GetDocumentTitle(nsString& title)
{
nsresult res = NS_ERROR_NOT_INITIALIZED;
if (!mEditor && !mContentAreaWebShell)
if (!mEditor)
return res;
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
@ -1495,41 +1574,59 @@ nsEditorShell::UpdateWindowTitle()
return res;
nsCOMPtr<nsIDOMDocument> domDoc;
editor->GetDocument(getter_AddRefs(domDoc));
if (domDoc)
res = editor->GetDocument(getter_AddRefs(domDoc));
if (NS_SUCCEEDED(res) && domDoc)
{
// Get the document title
nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc);
if (HTMLDoc)
{
nsAutoString windowCaption;
HTMLDoc->GetTitle(windowCaption);
if (windowCaption.Length() == 0)
{
// Set the window title to be "untitled"
windowCaption = GetString("UntitledWithParens");
}
res = HTMLDoc->GetTitle(title);
// Append " - Composer" to the title
windowCaption += (nsString(" ") + GetString("ComposerCaptionSuffix"));
res = mContentAreaWebShell->SetTitle(windowCaption.GetUnicode());
}
// If title is empty, use "untitled"
if (title.Length() == 0)
title = GetString("untitled");
}
return res;
}
// JavaScript version
NS_IMETHODIMP
nsEditorShell::GetDocumentTitle(PRUnichar **title)
{
if (!title)
return NS_ERROR_NULL_POINTER;
nsAutoString titleStr;
nsresult res = GetDocumentTitle(titleStr);
if (NS_SUCCEEDED(res))
{
*title = titleStr.ToNewUnicode();
} else {
// Don't fail, just return an empty string
nsAutoString empty("");
*title = empty.ToNewUnicode();
res = NS_OK;
}
return res;
}
NS_IMETHODIMP
nsEditorShell::SetTitle(const PRUnichar *title)
nsEditorShell::SetDocumentTitle(const PRUnichar *title)
{
nsresult res = NS_ERROR_NOT_INITIALIZED;
if (!mEditor && !mContentAreaWebShell)
return res;
// This should only be allowed for HTML documents
if (mEditorType != eHTMLTextEditorType)
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
if (!editor)
return res;
return NS_ERROR_FAILURE;
nsAutoString titleStr(title);
nsCOMPtr<nsIDOMDocument> domDoc;
res = editor->GetDocument(getter_AddRefs(domDoc));
@ -1541,7 +1638,7 @@ nsEditorShell::SetTitle(const PRUnichar *title)
{
// This sets the window title, and saves the title as a member varialble,
// but does NOT insert the <title> node.
HTMLDoc->SetTitle(nsString(title));
HTMLDoc->SetTitle(titleStr);
nsCOMPtr<nsIDOMNodeList> titleList;
nsCOMPtr<nsIDOMNode>titleNode;
@ -1590,7 +1687,8 @@ nsEditorShell::SetTitle(const PRUnichar *title)
if (headNode)
{
PRBool newTitleNode = PR_FALSE;
if (!titleNode) {
if (!titleNode)
{
// Didn't find one above: Create a new one
nsCOMPtr<nsIDOMElement>titleElement;
res = domDoc->CreateElement("title",getter_AddRefs(titleElement));
@ -1599,23 +1697,24 @@ nsEditorShell::SetTitle(const PRUnichar *title)
titleNode = do_QueryInterface(titleElement);
newTitleNode = PR_TRUE;
}
// Note: There should ALWAYS be a <title> in any HTML document,
// so we will insert the node and not make it undoable
res = headNode->AppendChild(titleNode, getter_AddRefs(resultNode));
if (NS_FAILED(res))
return NS_ERROR_FAILURE;
}
if (titleNode)
// Append a text node under the TITLE
// only if the title text isn't empty
if (titleNode && titleStr.Length() > 0)
{
// Append a text node under the TITLE
nsCOMPtr<nsIDOMText> textNode;
res = domDoc->CreateTextNode(title, getter_AddRefs(textNode));
res = domDoc->CreateTextNode(titleStr, getter_AddRefs(textNode));
if (NS_SUCCEEDED(res) && textNode)
{
// Finally, append the titleNode+child text node to the document <head>
// SHOULD THIS GO THROUGH TRANSACTION SYSTEM?
// If yes, use: editor->InsertElement(titleNode, headNode, 0) for the created node
// or editor->InsertElement(textNode, headNode, 0) if we already had a title node
res = titleNode->AppendChild(textNode,getter_AddRefs(resultNode));
// Append the new node to the head
if (NS_SUCCEEDED(res) && newTitleNode)
res = headNode->AppendChild(titleNode, getter_AddRefs(resultNode));
// Go through the editor API so action is undoable
res = editor->InsertNode(textNode, headNode, 0);
// This is the non-undoable code:
//res = titleNode->AppendChild(textNode,getter_AddRefs(resultNode));
}
}
}

View File

@ -204,6 +204,9 @@ class nsEditorShell : public nsIEditorShell,
// Get a string from the string bundle file
nsString GetString(const nsString& name);
// Get the text of the <title> tag
NS_IMETHOD GetDocumentTitle(nsString& title);
// Get the current document title an use it as part of the window title
// Uses "(Untitled)" for empty title

View File

@ -197,7 +197,8 @@ nsTextEditRules::DidDoAction(nsIDOMSelection *aSelection,
case kOutputText:
return DidOutputText(aSelection, aResult);
}
return NS_ERROR_FAILURE;
// Don't fail on transactions we don't handle here!
return NS_OK;
}

View File

@ -1173,7 +1173,10 @@ nsEditorShell::CheckAndSaveDocument(PRBool *_retval)
// Ask user if they want to save current changes
nsAutoString tmp1 = GetString("Save");
nsAutoString tmp2 = GetString("DontSave");
EConfirmResult result = ConfirmWithCancel(GetString("SaveDocument"), GetString("SaveFilePrompt"),
nsAutoString title;
GetDocumentTitle(title);
nsAutoString saveMsg = GetString("SaveFilePrompt")+" "+"\""+title+"\""+GetString("QuestionMark");
EConfirmResult result = ConfirmWithCancel(GetString("SaveDocument"), saveMsg,
&tmp1, &tmp2);
if (result == eCancel)
{
@ -1216,7 +1219,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
// find out if the doc already has a fileSpec associated with it.
nsFileSpec docFileSpec;
PRBool mustShowFileDialog = saveAs || (diskDoc->GetFileSpec(docFileSpec) == NS_ERROR_NOT_INITIALIZED);
PRBool noFileSpec = (diskDoc->GetFileSpec(docFileSpec) == NS_ERROR_NOT_INITIALIZED);
PRBool mustShowFileDialog = saveAs || noFileSpec;
PRBool replacing = !saveAs;
if (mustShowFileDialog)
@ -1230,7 +1234,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
nsString title;
res = HTMLDoc->GetTitle(title);
if (NS_SUCCEEDED(res) && title.Length() == 0)
// Prompt for title ONLY for a new blank doc (no filespec yet)
if (noFileSpec && NS_SUCCEEDED(res) && title.Length() == 0)
{
// Use a "prompt" common dialog to get title string from user
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &res);
@ -1250,7 +1255,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
return NS_OK;
}
//This will call UpdateWindowTitle
SetTitle(titleUnicode);
SetDocumentTitle(titleUnicode);
title = titleUnicode;
bUpdateWindowTitle = PR_FALSE;
nsCRT::free(titleUnicode);
}
@ -1260,14 +1266,16 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
res = nsComponentManager::CreateInstance(kCFileWidgetCID, nsnull, nsIFileWidget::GetIID(), getter_AddRefs(fileWidget));
if (NS_SUCCEEDED(res) && fileWidget)
{
nsString promptString = GetString("SaveDocumentAs");
nsAutoString promptString = GetString("SaveDocumentAs");
nsString* titles = nsnull;
nsString* filters = nsnull;
nsString* nextTitle;
nsString* nextFilter;
nsString HTMLFiles;
nsString TextFiles;
nsAutoString HTMLFiles;
nsAutoString TextFiles;
nsAutoString fileName;
nsFileSpec parentPath;
titles = new nsString[2];
if (!titles)
@ -1289,15 +1297,50 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
if (HTMLFiles.Length() == 0 || TextFiles.Length() == 0)
goto SkipFilters;
*nextTitle++ = "HTML Files";
*nextTitle++ = HTMLFiles;
*nextFilter++ = "*.htm; *.html; *.shtml";
*nextTitle++ = "Text Files";
*nextTitle++ = TextFiles;
*nextFilter++ = "*.txt";
fileWidget->SetFilterList(2, titles, filters);
if (noFileSpec)
{
// Use page title as suggested name for new document
if (title.Length() > 0)
{
//Replace "bad" filename characteres with "_"
PRUnichar space = (PRUnichar)' ';
PRUnichar dot = (PRUnichar)'.';
PRUnichar bslash = (PRUnichar)'\\';
PRUnichar fslash = (PRUnichar)'/';
PRUnichar amp = (PRUnichar)'@';
PRUnichar colon = (PRUnichar)':';
PRUnichar underscore = (PRUnichar)'_';
title = title.ReplaceChar(space, underscore);
title = title.ReplaceChar(dot, underscore);
title = title.ReplaceChar(bslash, underscore);
title = title.ReplaceChar(fslash, underscore);
title = title.ReplaceChar(amp, underscore);
title = title.ReplaceChar(colon, underscore);
fileName = title + nsString(".html");
}
} else {
char *leafName = docFileSpec.GetLeafName();
if (leafName)
{
fileName = leafName;
nsCRT::free(leafName);
}
docFileSpec.GetParent(parentPath);
// TODO: CHANGE TO THE DIRECTORY OF THE PARENT PATH?
}
if (fileName.Length() > 0)
fileWidget->SetDefaultString(fileName);
SkipFilters:
nsFileDlgResults dialogResult;
// 1ST PARAM SHOULD BE nsIDOMWindow*, not nsIWidget*
dialogResult = fileWidget->PutFile(/*mContentWindow*/nsnull, promptString, docFileSpec);
dialogResult = fileWidget->PutFile(nsnull, promptString, docFileSpec);
delete [] titles;
delete [] filters;
@ -1449,20 +1492,43 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindow *parent, const PRUnichar *filterType
if (NS_SUCCEEDED(res))
{
nsFileDlgResults dialogResult;
nsString* titles = nsnull;
nsString* filters = nsnull;
nsString* nextTitle;
nsString* nextFilter;
if (htmlFilter)
{
nsAutoString titles[] = {"HTML Files"};
nsAutoString filters[] = {"*.htm; *.html; *.shtml"};
fileWidget->SetFilterList(1, titles, filters);
// First param should be Parent window, but type is nsIWidget*
// Bug is filed to change this to a more suitable window type
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
titles = new nsString[3];
filters = new nsString[3];
if (!titles || ! filters)
return NS_ERROR_OUT_OF_MEMORY;
nextTitle = titles;
nextFilter = filters;
*nextTitle++ = GetString("HTMLFiles");
*nextTitle++ = GetString("TextFiles");
*nextFilter++ = "*.htm; *.html; *.shtml";
*nextFilter++ = "*.txt";
fileWidget->SetFilterList(3, titles, filters);
} else {
nsAutoString imgTitles[] = {"Image Files"};
nsAutoString imgFilters[] = {"*.gif; *.jpg; *.jpeg; *.png"};
fileWidget->SetFilterList(1, imgTitles, imgFilters);
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
titles = new nsString[2];
filters = new nsString[2];
if (!titles || ! filters)
return NS_ERROR_OUT_OF_MEMORY;
nextTitle = titles;
nextFilter = filters;
*nextTitle++ = GetString("IMGFiles");
*nextFilter++ = "*.gif; *.jpg; *.jpeg; *.png", "*.*";
fileWidget->SetFilterList(2, titles, filters);
}
*nextTitle++ = GetString("AllFiles");
*nextFilter++ = "*.*";
// First param should be Parent window, but type is nsIWidget*
// Bug is filed to change this to a more suitable window type
dialogResult = fileWidget->GetFile(/*parent*/ nsnull, title, fileSpec);
delete [] titles;
delete [] filters;
// Do this after we get this from preferences
//fileWidget->SetDisplayDirectory(aDisplayDirectory);
@ -1484,10 +1550,23 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindow *parent, const PRUnichar *filterType
NS_IMETHODIMP
nsEditorShell::UpdateWindowTitle()
{
if (!mContentAreaWebShell)
return NS_ERROR_NOT_INITIALIZED;
nsAutoString windowCaption;
nsresult res = GetDocumentTitle(windowCaption);
if (NS_SUCCEEDED(res))
res = mContentAreaWebShell->SetTitle(windowCaption.GetUnicode());
return res;
}
NS_IMETHODIMP
nsEditorShell::GetDocumentTitle(nsString& title)
{
nsresult res = NS_ERROR_NOT_INITIALIZED;
if (!mEditor && !mContentAreaWebShell)
if (!mEditor)
return res;
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
@ -1495,41 +1574,59 @@ nsEditorShell::UpdateWindowTitle()
return res;
nsCOMPtr<nsIDOMDocument> domDoc;
editor->GetDocument(getter_AddRefs(domDoc));
if (domDoc)
res = editor->GetDocument(getter_AddRefs(domDoc));
if (NS_SUCCEEDED(res) && domDoc)
{
// Get the document title
nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc);
if (HTMLDoc)
{
nsAutoString windowCaption;
HTMLDoc->GetTitle(windowCaption);
if (windowCaption.Length() == 0)
{
// Set the window title to be "untitled"
windowCaption = GetString("UntitledWithParens");
}
res = HTMLDoc->GetTitle(title);
// Append " - Composer" to the title
windowCaption += (nsString(" ") + GetString("ComposerCaptionSuffix"));
res = mContentAreaWebShell->SetTitle(windowCaption.GetUnicode());
}
// If title is empty, use "untitled"
if (title.Length() == 0)
title = GetString("untitled");
}
return res;
}
// JavaScript version
NS_IMETHODIMP
nsEditorShell::GetDocumentTitle(PRUnichar **title)
{
if (!title)
return NS_ERROR_NULL_POINTER;
nsAutoString titleStr;
nsresult res = GetDocumentTitle(titleStr);
if (NS_SUCCEEDED(res))
{
*title = titleStr.ToNewUnicode();
} else {
// Don't fail, just return an empty string
nsAutoString empty("");
*title = empty.ToNewUnicode();
res = NS_OK;
}
return res;
}
NS_IMETHODIMP
nsEditorShell::SetTitle(const PRUnichar *title)
nsEditorShell::SetDocumentTitle(const PRUnichar *title)
{
nsresult res = NS_ERROR_NOT_INITIALIZED;
if (!mEditor && !mContentAreaWebShell)
return res;
// This should only be allowed for HTML documents
if (mEditorType != eHTMLTextEditorType)
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
if (!editor)
return res;
return NS_ERROR_FAILURE;
nsAutoString titleStr(title);
nsCOMPtr<nsIDOMDocument> domDoc;
res = editor->GetDocument(getter_AddRefs(domDoc));
@ -1541,7 +1638,7 @@ nsEditorShell::SetTitle(const PRUnichar *title)
{
// This sets the window title, and saves the title as a member varialble,
// but does NOT insert the <title> node.
HTMLDoc->SetTitle(nsString(title));
HTMLDoc->SetTitle(titleStr);
nsCOMPtr<nsIDOMNodeList> titleList;
nsCOMPtr<nsIDOMNode>titleNode;
@ -1590,7 +1687,8 @@ nsEditorShell::SetTitle(const PRUnichar *title)
if (headNode)
{
PRBool newTitleNode = PR_FALSE;
if (!titleNode) {
if (!titleNode)
{
// Didn't find one above: Create a new one
nsCOMPtr<nsIDOMElement>titleElement;
res = domDoc->CreateElement("title",getter_AddRefs(titleElement));
@ -1599,23 +1697,24 @@ nsEditorShell::SetTitle(const PRUnichar *title)
titleNode = do_QueryInterface(titleElement);
newTitleNode = PR_TRUE;
}
// Note: There should ALWAYS be a <title> in any HTML document,
// so we will insert the node and not make it undoable
res = headNode->AppendChild(titleNode, getter_AddRefs(resultNode));
if (NS_FAILED(res))
return NS_ERROR_FAILURE;
}
if (titleNode)
// Append a text node under the TITLE
// only if the title text isn't empty
if (titleNode && titleStr.Length() > 0)
{
// Append a text node under the TITLE
nsCOMPtr<nsIDOMText> textNode;
res = domDoc->CreateTextNode(title, getter_AddRefs(textNode));
res = domDoc->CreateTextNode(titleStr, getter_AddRefs(textNode));
if (NS_SUCCEEDED(res) && textNode)
{
// Finally, append the titleNode+child text node to the document <head>
// SHOULD THIS GO THROUGH TRANSACTION SYSTEM?
// If yes, use: editor->InsertElement(titleNode, headNode, 0) for the created node
// or editor->InsertElement(textNode, headNode, 0) if we already had a title node
res = titleNode->AppendChild(textNode,getter_AddRefs(resultNode));
// Append the new node to the head
if (NS_SUCCEEDED(res) && newTitleNode)
res = headNode->AppendChild(titleNode, getter_AddRefs(resultNode));
// Go through the editor API so action is undoable
res = editor->InsertNode(textNode, headNode, 0);
// This is the non-undoable code:
//res = titleNode->AppendChild(textNode,getter_AddRefs(resultNode));
}
}
}

View File

@ -204,6 +204,9 @@ class nsEditorShell : public nsIEditorShell,
// Get a string from the string bundle file
nsString GetString(const nsString& name);
// Get the text of the <title> tag
NS_IMETHOD GetDocumentTitle(nsString& title);
// Get the current document title an use it as part of the window title
// Uses "(Untitled)" for empty title

View File

@ -62,8 +62,14 @@ interface nsIEditorShell : nsISupports
void SetToolbarWindow(in nsIDOMWindow win);
void SetContentWindow(in nsIDOMWindow win);
void SetWebShellWindow(in nsIDOMWindow win);
void SetTitle(in wstring title);
void LoadUrl(in wstring url);
/* Set the value of the <title> tag in the <head> of a document
* Also uses this to set the editing window caption
*/
void SetDocumentTitle(in wstring title);
/* Get value of the <title> tag */
wstring GetDocumentTitle();
/** Register a doc state listener. This gets added to a list of listeners
which are registered with the editor when that gets instantiated.

View File

@ -197,7 +197,8 @@ nsTextEditRules::DidDoAction(nsIDOMSelection *aSelection,
case kOutputText:
return DidOutputText(aSelection, aResult);
}
return NS_ERROR_FAILURE;
// Don't fail on transactions we don't handle here!
return NS_OK;
}

View File

@ -38,11 +38,16 @@
<window id="main-window" xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="EditorOnLoad()"
onunload="EditorShutdown()" title="&editorWindow.title;" align="vertical"
onunload="EditorShutdown()"
titlemodifier="&editorWindow.titlemodifier;"
titlemenuseparator="&editorWindow.titlemodifiermenuseparator;"
align="vertical"
width="640" height="480">
<html:script language="JavaScript" src="chrome://editor/content/EditorCommands.js"/>
<!-- Use this when we abandon the default startup page -->
<!-- broadcaster id="args" value="about:blank"/ -->
<broadcaster id="args" value="chrome://editor/content/EditorInitPage.html"/>
<broadcaster id="canPrint"/>
@ -203,7 +208,7 @@
<editor type="content-primary" id="content-frame" src="about:blank" flex="100%"/>
<box align="horizontal" id="DisplayModeBar">
<box align="horizontal" id="DisplayModeBar" style="padding-top: 0px">
<spring class="spacer"/>
<!-- This is a pain: can't use CSS margin to add extra space above text? -->
<box align="vertical">

View File

@ -29,7 +29,7 @@
a[name] {
padding-left: 20px;
background: url(chrome://editor/skin/images/left.gif) 5px 50% no-repeat;
background: url(chrome://editor/skin/images/anchor.gif) 5px 50% no-repeat;
}
table {

View File

@ -32,7 +32,10 @@
<window id="main-window" xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onunload="EditorShutdown()" title="&textEditorWindow.title;" align="vertical"
onunload="EditorShutdown()"
titlemodifier="&textEditorWindow.titlemodifier;"
titlemenuseparator="&editorWindow.titlemodifiermenuseparator;"
align="vertical"
width="640" height="480">
<html:script language="JavaScript" src="chrome://editor/content/EditorCommands.js">

View File

@ -21,8 +21,6 @@
- Contributor(s):
-->
<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
<!DOCTYPE window SYSTEM "chrome://editor/locale/editorOverlay.dtd">
<overlay id="editorOverlay"
@ -134,7 +132,6 @@
<!-- Broadcaster nodes -->
<!-- Note: NewEditor items are now in globalOverlay.xul -->
<broadcaster id="Editor:Open" value="&openCmd.label;" oncommand="EditorOpen()"/>
<broadcaster id="Editor:Save" value="&saveCmd.label;" disabled="true" oncommand="EditorSave()"/>
<broadcaster id="Editor:SaveAs" value="&saveAsCmd.label;" disabled="false" oncommand="EditorSaveAs()"/>
@ -638,7 +635,7 @@
<titledbutton id="hlineButton" src="&hlineIcon.url;" value="&hruleToolbarCmd.label;" onclick="EditorInsertHLine()"/>
<titledbutton id="tableButton" src="&tableIcon.url;" value="&tableToolbarCmd.label;" onclick="EditorInsertOrEditTable(true)"/>
<titledbutton id="linkButton" src="&linkIcon.url;" value="&linkToolbarCmd.label;" onclick="EditorInsertLink()"/>
<titledbutton id="namedAnchorButton" src="&targetIcon.url;" value="&anchorToolbarCmd.label;" onclick="EditorInsertNamedAnchor()"/>
<titledbutton id="namedAnchorButton" src="&anchorIcon.url;" value="&anchorToolbarCmd.label;" onclick="EditorInsertNamedAnchor()"/>
<!-- Formatting toolbar items -->
<titledbutton style="width:68pt" id="ParagraphPopupButton" value="&paragraphToolbarMenu.label;" class="popup" align="left" popupanchor="bottomleft">
@ -676,6 +673,7 @@
<!-- DEBUG only -->
<menu id="debugMenu" value="&debugMenu.label;">
<menupopup>
<menuitem value="Composer with Test Page" oncommand="window.openDialog('chrome://editor/content','_blank','chrome,all,dialog=no','chrome://editor/content/EditorInitPage.html')"/>
<menuitem value="&outputTextCmd.label;"
oncommand="EditorGetText()"/>
<menuitem value="&outputHTMLCmd.label;"

View File

@ -21,8 +21,10 @@
-->
<!-- Window title -->
<!ENTITY editorWindow.title "Editor">
<!ENTITY textEditorWindow.title "Text Editor">
<!-- LOCALIZATION NOTE mainWindow.title: Do NOT localize "Composer" -->
<!ENTITY editorWindow.titlemodifier "Composer">
<!ENTITY editorWindow.titlemodifiermenuseparator " - ">
<!ENTITY textEditorWindow.titlemodifier "Text Editor">
<!-- Menu items: the . means that the menu item isn't implemented yet -->
@ -42,6 +44,9 @@
<!ENTITY aboutCmd.label ".About">
<!-- Display Mode Toolbar -->
<!ENTITY displayMode.label "Display Mode:">
<!ENTITY editModeButton.label "Normal Editing">
<!ENTITY browserModeButton.label "Edit in Browser Layout">
<!ENTITY displayMode.label "Edit Mode:">
<!ENTITY editModeButton.label "Normal">
<!ENTITY browserModeButton.label "Browser">
<!ENTITY viewModeButton.label "View Mode:">
<!ENTITY htmlModeButton.label "HTML Source">
<!ENTITY treeModeButton.label "Tag Tree">

View File

@ -22,8 +22,11 @@ NoSuggestedWords=(no suggested words)
NoMisspelledWord=No misspelled word was found.
CheckSpelling=Check Spelling
HTMLFiles=HTML Files
IMGFiles=Image Files
TextFiles=Text Files
SaveFilePrompt=Save changes to current file?
AllFiles=All Files
SaveFilePrompt=Save changes to
QuestionMark=?
SaveFileFailed=Saving file failed!
DocumentTitle=Document Title
NeedDocTitle=Enter a title for the current page./nThe title identifies the page in the window title and bookmarks.
@ -33,8 +36,6 @@ EmptyHREFError=You must enter or choose<br>a location (URL) to create a new link
LinkText=Link text:
EnterLinkText=Enter text to display for the link:
EmptyLinkTextError=You must enter some text for this link.
HeadingsCaption=Headings:
NamedAnchorsCaption=NamedAnchors:
ValidateNumber1=The number you entered (
ValidateNumber2=) is outside of allowed range.<br>Please enter a number between
ValidateNumber3=and
@ -55,6 +56,7 @@ Pixels=pixels
Percent=percent
PercentOfCell=% of cell
PercentOfWindow=% of window
UntitledWithParens=(Untitled)
untitled=untitled
ComposerCaptionSuffix=- Composer
NoNamedAnchors=(No named anchors in this page)
NoHeadings=(No headings in this page)

View File

@ -435,7 +435,7 @@
<!ENTITY findIcon.url "chrome://editor/skin/images/find.gif">
<!ENTITY linkIcon.url "chrome://editor/skin/images/link.gif">
<!ENTITY imageIcon.url "chrome://editor/skin/images/image.gif">
<!ENTITY targetIcon.url "chrome://editor/skin/images/target.gif">
<!ENTITY anchorIcon.url "chrome://editor/skin/images/anchor.gif">
<!ENTITY hlineIcon.url "chrome://editor/skin/images/hline.gif">
<!ENTITY tableIcon.url "chrome://editor/skin/images/table.gif">
<!ENTITY spellingIcon.url "chrome://editor/skin/images/spell.gif">

View File

@ -40,7 +40,8 @@ box#EditorProgessBox {
}
box#DisplayModeBar {
margin-top: -2px;
/*margin-top: -2px;*/
border-top: 1px solid darkgray;
min-width:30px;
background-color: inherit;
}

View File

@ -35,7 +35,7 @@ images:justify.gif
images:numbers.gif
images:redo.gif
images:spell.gif
images:target.gif
images:anchor.gif
images:undo.gif
images:bullets.gif
images:copy.gif
@ -73,4 +73,4 @@ images:savemod.gif
images:publish.gif
images:preview.gif
images:print.gif
images:find.gif
images:find.gif

View File

@ -45,7 +45,7 @@ EXPORT_RESOURCE_TOOLBAR = \
$(srcdir)/images/redo.gif \
$(srcdir)/images/spell.gif \
$(srcdir)/images/table.gif \
$(srcdir)/images/target.gif \
$(srcdir)/images/anchor.gif \
$(srcdir)/images/underline.gif \
$(srcdir)/images/undo.gif \
$(srcdir)/images/text-color.gif \

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

View File

@ -43,7 +43,7 @@ install:: $(DLL)
$(MAKE_INSTALL) images\redo.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\spell.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\table.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\target.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\anchor.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\underline.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\undo.gif $(DIST)\bin\chrome\editor\skin\default\images
$(MAKE_INSTALL) images\text-color.gif $(DIST)\bin\chrome\editor\skin\default\images
@ -87,7 +87,7 @@ clobber::
rm -f $(DIST)\bin\chrome\editor\skin\default\images\redo.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\spell.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\table.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\target.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\anchor.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\underline.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\undo.gif
rm -f $(DIST)\bin\chrome\editor\skin\default\images\text-color.gif

View File

@ -65,6 +65,9 @@ function Startup()
// SET FOCUS TO FIRST CONTROL
dialog.heightInput.focus();
// Resize window
window.sizeToContent();
}
// Set dialog widgets with attribute data
@ -79,8 +82,6 @@ function InitDialog()
// Get the width attribute of the element, stripping out "%"
// This sets contents of combobox (adds pixel and percent option elements)
dialog.widthInput.value = InitPixelOrPercentCombobox(globalElement,"width","pixelOrPercentSelect");
// Resize window after filling combobox
window.sizeToContent();
align = globalElement.getAttribute("align");
if (align == "center") {

View File

@ -75,6 +75,9 @@ function Startup()
dialog.columnsInput.value = 2;
dialog.rowsInput.focus();
// Resize window
window.sizeToContent();
}
// Set dialog widgets with attribute data
@ -87,9 +90,6 @@ function InitDialog()
// This sets contents of select combobox list
dialog.widthInput.value = InitPixelOrPercentCombobox(globalElement,"width","pixelOrPercentSelect");
dialog.borderInput.value = globalElement.getAttribute("border");
// Resize window after filling combobox
window.sizeToContent();
}
// Get and validate data from widgets.

View File

@ -30,11 +30,10 @@ var hrefInput;
var linkMessage;
var href;
var newLinkText;
var HeadingsIndex = -1;
var NamedAnchorsIndex = -1;
var NamedAnchorList = 0;
var HNodeArray;
var NamedAnchorLink = "";
var haveNamedAnchors = false;
var haveHeadings = false;
// NOTE: Use "href" instead of "a" to distinguish from Named Anchor
// The returned node is has an "a" tagName
@ -49,11 +48,12 @@ function Startup()
doSetOKCancel(onOK, null);
// Message was wrapped in a <label> or <div>, so actual text is a child text node
linkCaption = (document.getElementById("linkTextCaption")).firstChild;
linkMessage = (document.getElementById("linkTextMessage")).firstChild;
linkTextInput = document.getElementById("linkTextInput");
hrefInput = document.getElementById("hrefInput");
linkCaption = (document.getElementById("linkTextCaption")).firstChild;
linkMessage = (document.getElementById("linkTextMessage")).firstChild;
linkTextInput = document.getElementById("linkTextInput");
hrefInput = document.getElementById("hrefInput");
NamedAnchorList = document.getElementById("NamedAnchorList");
HeadingsList = document.getElementById("HeadingsList");
// Get a single selected anchor element
anchorElement = editorShell.GetSelectedElement(tagName);
@ -99,18 +99,13 @@ function Startup()
dump("Element not selected - calling createElementWithDefaults\n");
anchorElement = editorShell.CreateElementWithDefaults(tagName);
dump("1\n");
// We will insert a new link at caret location if there's no selection
// TODO: This isn't entirely correct. If selection doesn't have any text
// or an image, then shouldn't we clear the selection and insert new text?
insertNew = selection.isCollapsed;
dump("2\n");
dump("insertNew is " + insertNew + "\n");
linkCaption.data = GetString("EnterLinkText");
dump("3\n");
linkMessage.data = "";
dump("4\n");
}
}
if(!anchorElement)
@ -121,21 +116,17 @@ dump("4\n");
// Replace the link message with the link source string
selectedText = GetSelectionAsText();
dump("5\n");
if (selectedText.length > 0) {
// Use just the first 50 characters and add "..."
selectedText = TruncateStringAtWordEnd(selectedText, 50, true);
dump("6\n");
} else {
dump("Selected text for link source not found. Non-text elements selected?\n");
}
linkMessage.data = selectedText;
dump("7\n");
// The label above the selected text:
linkCaption.data = GetString("LinkText");
}
dump("8\n");
if (!selection.isCollapsed)
{
// HREF is a weird case: If selection extends beyond
@ -148,14 +139,11 @@ dump("8\n");
dump("insertLinkAroundSelection is TRUE\n");
}
dump("9\n");
// Make a copy to use for AdvancedEdit and onSaveDefault
globalElement = anchorElement.cloneNode(false);
dump("10\n");
// Get the list of existing named anchors and headings
FillNamedAnchorList();
dump("11\n");
FillListboxes();
// Set data for the dialog controls
InitDialog();
@ -177,6 +165,8 @@ dump("11\n");
linkTextInput = null;
}
}
window.sizeToContent();
}
// Set dialog widgets with attribute data
@ -205,18 +195,18 @@ function RemoveLink()
hrefInput.value = "";
}
function FillNamedAnchorList()
function FillListboxes()
{
NamedAnchorNodeList = editorShell.editorDocument.anchors;
var NamedAnchorCount = NamedAnchorNodeList.length;
if (NamedAnchorCount > 0) {
// Save index so we ignore if user selects it
NamedAnchorsIndex = 0;
AppendStringToListByID(NamedAnchorList,"NamedAnchorsCaption");
for (var i = 0; i < NamedAnchorCount; i++) {
// Prefix with some spaces to give an indented look
AppendStringToList(NamedAnchorList," "+NamedAnchorNodeList.item(i).name);
AppendStringToList(NamedAnchorList,NamedAnchorNodeList.item(i).name);
}
haveNamedAnchors = true;
} else {
// Message to tell user there are none
AppendStringToList(NamedAnchorList,GetString("NoNamedAnchors"));
}
var firstHeading = true;
for (var j = 1; j <= 6; j++) {
@ -240,21 +230,14 @@ function FillNamedAnchorList()
range.setEnd(heading,lastChildIndex);
var text = range.toString();
if (text) {
if (firstHeading) {
// Save index so we ignore if user selects it
HeadingsIndex = NamedAnchorList.length;
AppendStringToListByID(NamedAnchorList,"HeadingsCaption");
firstHeading = false;
}
// Use just first 40 characters, don't add "...",
// and replace whitespace with "_" and strip non-word characters
text = PrepareStringForURL(TruncateStringAtWordEnd(text, 40, false));
// Append "_" to any name already in the list
if (GetExistingAnchorIndex(text) > -1)
if (GetExistingHeadingIndex(text) > -1)
text += "_";
// Prefix with some spaces to give an indented look
AppendStringToList(NamedAnchorList," "+text);
dump("Heading text for Named Anchor: "+text+"\n");
AppendStringToList(HeadingsList, text);
// Save nodes in an array so we can create anchor node under it later
if (!HNodeArray)
HNodeArray = new Array(heading)
@ -263,13 +246,18 @@ function FillNamedAnchorList()
}
}
}
if (HNodeArray) {
haveHeadings = true;
} else {
// Message to tell user there are none
AppendStringToList(HeadingsList,GetString("NoHeadings"));
}
}
function GetExistingAnchorIndex(text)
function GetExistingHeadingIndex(text)
{
for (i=0; i < NamedAnchorList.length; i++) {
if (i != HeadingsIndex && i != NamedAnchorsIndex &&
NamedAnchorList[i].name == name)
for (i=0; i < HeadingsList.length; i++) {
if (HeadingsList[i].name == name)
return i;
}
return -1;
@ -277,9 +265,16 @@ function GetExistingAnchorIndex(text)
function SelectNamedAnchor()
{
var selIndex = NamedAnchorList.selectedIndex;
if (selIndex != HeadingsIndex && selIndex != NamedAnchorsIndex)
hrefInput.value = "#" + NamedAnchorList.options[selIndex].value.trimString();
if (haveNamedAnchors) {
hrefInput.value = "#"+NamedAnchorList.options[NamedAnchorList.selectedIndex].value;
}
}
function SelectHeading()
{
if (haveHeadings) {
hrefInput.value = "#"+HeadingsList.options[HeadingsList.selectedIndex].value;
}
}
// Get and validate data from widgets.
@ -347,28 +342,24 @@ function onOK()
return true;
}
}
// Check if the link was to a heading in
// the named anchor list.
if (HeadingsIndex > -1 && href[0] == "#") {
// Check if the link was to a heading
if (href[0] == "#") {
var name = href.substr(1);
var index = GetExistingAnchorIndex(name);
// This assumes Headings are always AFTER the Named Anchors in the list
dump("HeadingsIndex="+HeadingsIndex+" SelectIndex="+index+"\n");
if (index > HeadingsIndex) {
var index = GetExistingHeadingIndex(name);
dump("Heading name="+name+" Index="+index+"\n");
if (index >= 0) {
// We need to create a named anchor
// and insert it as the first child of the heading element
var headNode = HNodeList[index - (HeadingsIndex+1)];
var headNode = HNodeArray[index];
var anchorNode = editorShell.editorDocument.createElement("a");
if (anchorNode) {
anchorNode.name = name;
// Remember to use editorShell method so it is undoable!
editorShell.InsertElement(anchorNode, headNode.parentNode, 0);
editorShell.InsertElement(anchorNode, headNode, 0);
dump("Anchor node created and inserted under heading\n");
}
}
else {
dump("HREF is a named anchor but is not in the list!\n");
} else {
dump("HREF is a heading but is not in the list!\n");
}
}
editorShell.EndBatchChanges();

View File

@ -68,7 +68,11 @@
</xul:box>
<xul:spring class="spacer"/>
<div>&NamedAnchorMsg.label;</div>
<select id="NamedAnchorList" style="width: 15em;" size="5" onchange="SelectNamedAnchor()"/>
<select id="NamedAnchorList" style="width: 15em;" size="3" onchange="SelectNamedAnchor()"/>
<xul:spring class="spacer"/>
<div>&HeadingMsg.label;</div>
<select id="HeadingsList" style="width: 15em;" size="3" onchange="SelectHeading()"/>
<div>&HeadingMsg2.label;</div>
</fieldset>
</xul:box>

View File

@ -38,7 +38,8 @@
<!ENTITY LinkURLEditField.label "Enter a web page location or local file:">
<!ENTITY LinkChooseFileButton.label "Choose File...">
<!ENTITY RemoveLinkButton.label "Remove Link">
<!ENTITY NamedAnchorMsg.label "Or select a named anchor or heading:">
<!ENTITY NamedAnchorMissingMsg.label "Create named anchors and/or headings and they will appear in this list">
<!ENTITY NamedAnchorMsg.label "or select a Named Anchor:">
<!ENTITY HeadingMsg.label "or select a Heading:">
<!ENTITY HeadingMsg2.label "(A named anchor will be created automatically)">

View File

@ -32,7 +32,10 @@
<window id="main-window" xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onunload="EditorShutdown()" title="&textEditorWindow.title;" align="vertical"
onunload="EditorShutdown()"
titlemodifier="&textEditorWindow.titlemodifier;"
titlemenuseparator="&editorWindow.titlemodifiermenuseparator;"
align="vertical"
width="640" height="480">
<html:script language="JavaScript" src="chrome://editor/content/EditorCommands.js">