зеркало из https://github.com/mozilla/gecko-dev.git
Bug 302050 inline spellchecking for text boxes r=bryner, sr=beng
This commit is contained in:
Родитель
b9193728c5
Коммит
cf6a628f86
|
@ -435,5 +435,9 @@ pref("bidi.browser.ui", false);
|
|||
// 2 and other values, nothing
|
||||
pref("browser.backspace_action", 0);
|
||||
|
||||
// this will automatically enable inline spellchecking (if it is available) for
|
||||
// multi-line text entry controls <textarea>s in HTML
|
||||
pref("layout.textarea.spellcheckDefault", true);
|
||||
|
||||
pref("view_source.editor.path", "");
|
||||
pref("view_source.editor.external", false);
|
||||
|
|
|
@ -37,7 +37,30 @@
|
|||
|
||||
<popup id="contentAreaContextMenu"
|
||||
onpopupshowing="if (event.target != this) return true; gContextMenu = new nsContextMenu( this ); return gContextMenu.shouldDisplay;"
|
||||
onpopuphiding="if (event.target == this) gContextMenu = null;">
|
||||
onpopuphiding="if (event.target == this) { gContextMenu.hiding(); gContextMenu = null; }">
|
||||
<menuitem id="spell-no-suggestions"
|
||||
disabled="true"
|
||||
label="&spellNoSuggestions.label;"/>
|
||||
<menuseparator id="spell-suggestions-separator"/>
|
||||
<menuitem id="spell-add-to-dictionary"
|
||||
label="&spellAddToDictionary.label;"
|
||||
accesskey="&spellAddToDictionary.accesskey;"
|
||||
oncommand="InlineSpellCheckerUI.addToDictionary();"/>
|
||||
<menuitem id="spell-check-enabled"
|
||||
label="&spellEnable.label;"
|
||||
accesskey="&spellEnable.accesskey;"
|
||||
oncommand="InlineSpellCheckerUI.toggleEnabled();"/>
|
||||
<menu id="spell-dictionaries"
|
||||
label="&spellDictionaries.label;"
|
||||
accesskey="&spellDictionaries.accesskey;">
|
||||
<menupopup id="spell-dictionaries-menu">
|
||||
<menuseparator id="spell-language-separator"/>
|
||||
<menuitem id="spell-add-dictionaries"
|
||||
label="&spellAddDictionaries.label;"
|
||||
accesskey="&spellAddDictionaries.accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator id="spell-separator"/>
|
||||
<menuitem id="context-openlink"
|
||||
label="&openLinkCmd.label;"
|
||||
accesskey="&openLinkCmd.accesskey;"
|
||||
|
|
|
@ -8,6 +8,10 @@ toolbar[printpreview="true"] {
|
|||
-moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
|
||||
}
|
||||
|
||||
menuitem.spell-suggestion {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
#noPreviewAvailable
|
||||
{
|
||||
background-color: white !important;
|
||||
|
|
|
@ -4075,7 +4075,7 @@ nsContextMenu.prototype = {
|
|||
this.menu = popup;
|
||||
|
||||
// Get contextual info.
|
||||
this.setTarget( document.popupNode );
|
||||
this.setTarget( document.popupNode, document.popupEvent );
|
||||
|
||||
this.isTextSelected = this.isTextSelection();
|
||||
this.isContentSelected = this.isContentSelection();
|
||||
|
@ -4088,6 +4088,7 @@ nsContextMenu.prototype = {
|
|||
this.initNavigationItems();
|
||||
this.initViewItems();
|
||||
this.initMiscItems();
|
||||
this.initSpellingItems();
|
||||
this.initSaveItems();
|
||||
this.initClipboardItems();
|
||||
this.initMetadataItems();
|
||||
|
@ -4200,6 +4201,35 @@ nsContextMenu.prototype = {
|
|||
// Only show the block image item if the image can be blocked
|
||||
this.showItem( "context-blockimage", this.onImage && hostLabel);
|
||||
},
|
||||
initSpellingItems : function () {
|
||||
var canSpell = InlineSpellCheckerUI.canSpellCheck;
|
||||
var onMisspelling = InlineSpellCheckerUI.overMisspelling;
|
||||
this.showItem("spell-check-enabled", canSpell);
|
||||
this.showItem("spell-separator", canSpell);
|
||||
if (canSpell)
|
||||
document.getElementById("spell-check-enabled").setAttribute("checked",
|
||||
InlineSpellCheckerUI.enabled);
|
||||
this.showItem("spell-add-to-dictionary", onMisspelling);
|
||||
|
||||
// suggestion list
|
||||
this.showItem("spell-suggestions-separator", onMisspelling);
|
||||
if (onMisspelling) {
|
||||
var menu = document.getElementById("contentAreaContextMenu");
|
||||
var suggestionsSeparator = document.getElementById("spell-suggestions-separator");
|
||||
var numsug = InlineSpellCheckerUI.addSuggestionsToMenu(menu, suggestionsSeparator, 5);
|
||||
this.showItem("spell-no-suggestions", numsug == 0);
|
||||
} else {
|
||||
this.showItem("spell-no-suggestions", false);
|
||||
}
|
||||
|
||||
// dictionary list
|
||||
this.showItem("spell-dictionaries", InlineSpellCheckerUI.enabled);
|
||||
if (canSpell) {
|
||||
var dictMenu = document.getElementById("spell-dictionaries-menu");
|
||||
var dictSep = document.getElementById("spell-language-separator");
|
||||
InlineSpellCheckerUI.addDictionaryListToMenu(dictMenu, dictSep);
|
||||
}
|
||||
},
|
||||
initClipboardItems : function () {
|
||||
|
||||
// Copy depends on whether there is selected text.
|
||||
|
@ -4243,8 +4273,13 @@ nsContextMenu.prototype = {
|
|||
// Show if user clicked on something which has metadata.
|
||||
this.showItem( "context-metadata", this.onMetaDataItem );
|
||||
},
|
||||
// called when the menu is going away
|
||||
hiding : function() {
|
||||
InlineSpellCheckerUI.clearSuggestionsFromMenu();
|
||||
InlineSpellCheckerUI.clearDictionaryListFromMenu();
|
||||
},
|
||||
// Set various context menu attributes based on the state of the world.
|
||||
setTarget : function ( node ) {
|
||||
setTarget : function ( node, event ) {
|
||||
const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
if ( node.namespaceURI == xulNS ) {
|
||||
this.shouldDisplay = false;
|
||||
|
@ -4267,6 +4302,7 @@ nsContextMenu.prototype = {
|
|||
this.inFrame = false;
|
||||
this.hasBGImage = false;
|
||||
this.bgImageURL = "";
|
||||
InlineSpellCheckerUI.uninit();
|
||||
|
||||
// Remember the node that was clicked.
|
||||
this.target = node;
|
||||
|
@ -4291,9 +4327,18 @@ nsContextMenu.prototype = {
|
|||
this.onStandaloneImage = true;
|
||||
} else if ( this.target instanceof HTMLInputElement ) {
|
||||
this.onTextInput = this.isTargetATextBox(this.target);
|
||||
// allow spellchecking UI on all writable text boxes except passwords
|
||||
if (this.onTextInput && ! this.target.readOnly && this.target.type != "password") {
|
||||
InlineSpellCheckerUI.init(this.target);
|
||||
InlineSpellCheckerUI.initFromEvent(event);
|
||||
}
|
||||
this.onKeywordField = this.isTargetAKeywordField(this.target);
|
||||
} else if ( this.target instanceof HTMLTextAreaElement ) {
|
||||
this.onTextInput = true;
|
||||
if (! this.target.readOnly) {
|
||||
InlineSpellCheckerUI.init(this.target);
|
||||
InlineSpellCheckerUI.initFromEvent(event);
|
||||
}
|
||||
} else if ( this.target instanceof HTMLHtmlElement ) {
|
||||
// pages with multiple <body>s are lame. we'll teach them a lesson.
|
||||
var bodyElt = this.target.ownerDocument.getElementsByTagName("body")[0];
|
||||
|
|
|
@ -46,4 +46,5 @@
|
|||
<script type="application/x-javascript" src="chrome://browser/content/bookmarks/bookmarksMenu.js"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/viewZoomOverlay.js"/>
|
||||
<script type="application/x-javascript" src="chrome://browser/content/browser.js"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/viewSourceUtils.js"/>
|
||||
|
|
|
@ -357,3 +357,13 @@
|
|||
<!ENTITY findAgainCmd.accesskey "g">
|
||||
<!ENTITY findAgainCmd.commandkey "g">
|
||||
<!ENTITY findAgainCmd.commandkey2 "VK_F3">
|
||||
|
||||
<!ENTITY spellAddToDictionary.label "Add to dictionary">
|
||||
<!ENTITY spellAddToDictionary.accesskey "t">
|
||||
<!ENTITY spellEnable.label "Spell check this field">
|
||||
<!ENTITY spellEnable.accesskey "S">
|
||||
<!ENTITY spellNoSuggestions.label "(No spelling suggestions)">
|
||||
<!ENTITY spellDictionaries.label "Languages">
|
||||
<!ENTITY spellDictionaries.accesskey "l">
|
||||
<!ENTITY spellAddDictionaries.label "Add dictionaries...">
|
||||
<!ENTITY spellAddDictionaries.accesskey "A">
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
# -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Inline spellcheck code
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Google Inc.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2005
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Brett Wilson <brettw@gmail.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
var InlineSpellCheckerUI = {
|
||||
|
||||
// Call this function to initialize for a given edit element
|
||||
init: function(inputElt)
|
||||
{
|
||||
this.uninit();
|
||||
this.mEditor = inputElt.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
|
||||
try {
|
||||
this.mInlineSpellChecker = this.mEditor.getInlineSpellChecker(true);
|
||||
// note: this might have been NULL if there is no chance we can spellcheck
|
||||
} catch(e) {
|
||||
this.mInlineSpellChecker = null;
|
||||
}
|
||||
},
|
||||
|
||||
// call this to clear state
|
||||
uninit: function()
|
||||
{
|
||||
this.mInlineSpellChecker = null;
|
||||
this.mOverMisspelling = false;
|
||||
this.mMisspelling = "";
|
||||
this.mMenu = null;
|
||||
this.mSpellSuggestions = []; // text of words
|
||||
this.mSuggestionItems = []; // menuitem nodes
|
||||
this.mDictionaryMenu = null;
|
||||
this.mDictionaryNames = [];
|
||||
this.mDictionaryItems = [];
|
||||
},
|
||||
|
||||
// for each UI event, you must call this function, it will compute the
|
||||
// word the cursor is over
|
||||
initFromEvent: function(event)
|
||||
{
|
||||
this.mOverMisspelling = false;
|
||||
this.mEvent = event;
|
||||
|
||||
if (! this.mInlineSpellChecker || ! (event instanceof UIEvent))
|
||||
return;
|
||||
|
||||
var selcon = this.mEditor.selectionController;
|
||||
var spellsel = selcon.getSelection(selcon.SELECTION_SPELLCHECK);
|
||||
if (spellsel.rangeCount == 0)
|
||||
return; // easy case - no misspellings
|
||||
|
||||
var range = this.mInlineSpellChecker.getMispelledWord(event.rangeParent,
|
||||
event.rangeOffset);
|
||||
if (! range)
|
||||
return; // not over a misspelled word
|
||||
|
||||
this.mMisspelling = range.toString();
|
||||
this.mOverMisspelling = true;
|
||||
this.mWordNode = event.rangeParent;
|
||||
this.mWordOffset = event.rangeOffset;
|
||||
},
|
||||
|
||||
// returns false if there should be no spellchecking UI enabled at all, true
|
||||
// means that you can at least give the user the ability to turn it on.
|
||||
get canSpellCheck()
|
||||
{
|
||||
// inline spell checker objects will be created only if there are actual
|
||||
// dictionaries available
|
||||
return (this.mInlineSpellChecker != null);
|
||||
},
|
||||
|
||||
// Whether spellchecking is enabled in the current box
|
||||
get enabled()
|
||||
{
|
||||
return (this.mInlineSpellChecker &&
|
||||
this.mInlineSpellChecker.enableRealTimeSpell);
|
||||
},
|
||||
set enabled(isEnabled)
|
||||
{
|
||||
if (this.mInlineSpellChecker)
|
||||
this.mInlineSpellChecker.enableRealTimeSpell = isEnabled;
|
||||
},
|
||||
|
||||
// returns true if the given event is over a misspelled word
|
||||
get overMisspelling()
|
||||
{
|
||||
return this.mOverMisspelling;
|
||||
},
|
||||
|
||||
// this prepends up to "maxNumber" suggestions at the given menu position
|
||||
// for the word under the cursor. Returns the number of suggestions inserted.
|
||||
addSuggestionsToMenu: function(menu, insertBefore, maxNumber)
|
||||
{
|
||||
if (! this.mInlineSpellChecker || ! this.mOverMisspelling)
|
||||
return 0; // nothing to do
|
||||
|
||||
var spellchecker = this.mInlineSpellChecker.spellChecker;
|
||||
if (! spellchecker.CheckCurrentWord(this.mMisspelling))
|
||||
return 0; // word seems not misspelled after all (?)
|
||||
|
||||
this.mMenu = menu;
|
||||
this.mSpellSuggestions = [];
|
||||
this.mSuggestionItems = [];
|
||||
for (var i = 0; i < maxNumber; i ++) {
|
||||
var suggestion = spellchecker.GetSuggestedWord();
|
||||
if (! suggestion.length)
|
||||
break;
|
||||
this.mSpellSuggestions.push(suggestion);
|
||||
|
||||
var item = document.createElement("menuitem");
|
||||
this.mSuggestionItems.push(item);
|
||||
item.setAttribute("label", suggestion);
|
||||
item.setAttribute("value", suggestion);
|
||||
// this function thing is necessary to generate a callback with the
|
||||
// correct binding of "val" (the index in this loop).
|
||||
var callback = function(me, val) { return function(evt) { me.replaceMisspelling(val); } };
|
||||
item.addEventListener("command", callback(this, i), true);
|
||||
item.setAttribute("class", "spell-suggestion");
|
||||
menu.insertBefore(item, insertBefore);
|
||||
}
|
||||
return this.mSpellSuggestions.length;
|
||||
},
|
||||
|
||||
// undoes the work of addSuggestionsToMenu for the same menu
|
||||
// (call from popup hiding)
|
||||
clearSuggestionsFromMenu: function()
|
||||
{
|
||||
for (var i = 0; i < this.mSuggestionItems.length; i ++) {
|
||||
this.mMenu.removeChild(this.mSuggestionItems[i]);
|
||||
}
|
||||
this.mSuggestionItems = [];
|
||||
},
|
||||
|
||||
// returns the number of dictionary languages. If insertBefore is NULL, this
|
||||
// does an append to the given menu
|
||||
addDictionaryListToMenu: function(menu, insertBefore)
|
||||
{
|
||||
this.mDictionaryMenu = menu;
|
||||
this.mDictionaryNames = [];
|
||||
this.mDictionaryItems = [];
|
||||
|
||||
if (! this.mInlineSpellChecker || ! this.enabled)
|
||||
return 0;
|
||||
var spellchecker = this.mInlineSpellChecker.spellChecker;
|
||||
var o1 = {}, o2 = {};
|
||||
spellchecker.GetDictionaryList(o1, o2);
|
||||
var list = o1.value;
|
||||
var listcount = o2.value;
|
||||
var curlang = spellchecker.GetCurrentDictionary();
|
||||
|
||||
for (var i = 0; i < list.length; i ++) {
|
||||
this.mDictionaryNames.push(list[i]);
|
||||
var item = document.createElement("menuitem");
|
||||
item.setAttribute("label", list[i]);
|
||||
this.mDictionaryItems.push(item);
|
||||
if (curlang == list[i]) {
|
||||
item.setAttribute("checked", "true");
|
||||
} else {
|
||||
var callback = function(me, val) { return function(evt) { me.selectDictionary(val); } };
|
||||
item.addEventListener("command", callback(this, i), true);
|
||||
}
|
||||
if (insertBefore)
|
||||
menu.insertBefore(item, insertBefore);
|
||||
else
|
||||
menu.appendChild(item);
|
||||
}
|
||||
return list.length;
|
||||
},
|
||||
|
||||
// undoes the work of addDictionaryListToMenu for the menu
|
||||
// (call on popup hiding)
|
||||
clearDictionaryListFromMenu: function()
|
||||
{
|
||||
for (var i = 0; i < this.mDictionaryItems.length; i ++) {
|
||||
this.mDictionaryMenu.removeChild(this.mDictionaryItems[i]);
|
||||
}
|
||||
this.mDictionaryItems = [];
|
||||
},
|
||||
|
||||
// callback for selecting a dictionary
|
||||
selectDictionary: function(index)
|
||||
{
|
||||
if (! this.mInlineSpellChecker || index < 0 || index >= this.mDictionaryNames.length)
|
||||
return;
|
||||
this.mInlineSpellChecker.spellChecker.SetCurrentDictionary(this.mDictionaryNames[index]);
|
||||
this.mInlineSpellChecker.spellCheckRange(null); // causes recheck
|
||||
},
|
||||
|
||||
// callback for selecting a suggesteed replacement
|
||||
replaceMisspelling: function(index)
|
||||
{
|
||||
if (! this.mInlineSpellChecker || ! this.mOverMisspelling)
|
||||
return;
|
||||
if (index < 0 || index >= this.mSpellSuggestions.length)
|
||||
return;
|
||||
this.mInlineSpellChecker.replaceWord(this.mWordNode, this.mWordOffset,
|
||||
this.mSpellSuggestions[index]);
|
||||
},
|
||||
|
||||
// callback for enabling or disabling spellchecking
|
||||
toggleEnabled: function()
|
||||
{
|
||||
this.mInlineSpellChecker.enableRealTimeSpell =
|
||||
! this.mInlineSpellChecker.enableRealTimeSpell;
|
||||
},
|
||||
|
||||
// callback for adding the current misspelling to the user-defined dictionary
|
||||
addToDictionary: function()
|
||||
{
|
||||
this.mInlineSpellChecker.addWordToDictionary(this.mMisspelling);
|
||||
}
|
||||
};
|
|
@ -26,6 +26,7 @@ toolkit.jar:
|
|||
*+ content/global/fontpackage.js (fontpackage.js)
|
||||
*+ content/global/fontpackage.xul (fontpackage.xul)
|
||||
*+ content/global/globalOverlay.js (globalOverlay.js)
|
||||
*+ content/global/inlineSpellCheckUI.js (inlineSpellCheckUI.js)
|
||||
+ content/global/mozilla.xhtml (mozilla.xhtml)
|
||||
*+ content/global/nsDragAndDrop.js (nsDragAndDrop.js)
|
||||
+ content/global/nsTransferable.js (nsTransferable.js)
|
||||
|
|
|
@ -83,6 +83,23 @@
|
|||
<property name="selectionEnd" onset="this.inputField.selectionEnd = val; return val;"
|
||||
onget="return this.inputField.selectionEnd;"/>
|
||||
|
||||
<!-- use this property "spellCheckerUI" instead of "InlineSpellCheckUI",
|
||||
because this object does the lazy creation and initialization
|
||||
you need -->
|
||||
<property name="spellCheckerUI" readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (! this.InlineSpellCheckerUI) {
|
||||
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].
|
||||
getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||
loader.loadSubScript("chrome://global/content/inlineSpellCheckUI.js", this);
|
||||
// watch out - that could have failed
|
||||
if (this.InlineSpellCheckerUI)
|
||||
this.InlineSpellCheckerUI.init(this.inputField);
|
||||
}
|
||||
return this.InlineSpellCheckerUI;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<method name="setSelectionRange">
|
||||
<parameter name="aSelectionStart"/>
|
||||
<parameter name="aSelectionEnd"/>
|
||||
|
@ -91,6 +108,33 @@
|
|||
</body>
|
||||
</method>
|
||||
|
||||
<constructor><![CDATA[
|
||||
var str = this.boxObject.getProperty("value");
|
||||
if (str) {
|
||||
this.inputField.value=str;
|
||||
this.boxObject.removeProperty("value");
|
||||
}
|
||||
str = this.getAttribute("spellcheck");
|
||||
if (str == "true") {
|
||||
// the problem is that we can't initialize the spell checker in the
|
||||
// constructor because not everything is initialized and the editor
|
||||
// will fail to create the inline spell checker object.
|
||||
setTimeout(this._delayedInitSpellCheck, 0, this)
|
||||
}
|
||||
]]></constructor>
|
||||
<destructor action="if (this.inputField.value) this.boxObject.setProperty('value', this.inputField.value);"/>
|
||||
|
||||
<method name="_delayedInitSpellCheck">
|
||||
<parameter name="me"/>
|
||||
<body><![CDATA[
|
||||
// called by the constructor to turn on spell checking
|
||||
var spellui = me.spellCheckerUI;
|
||||
if (spellui) {
|
||||
spellui.enabled = true;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
var str = this.boxObject.getProperty('value');
|
||||
|
@ -216,8 +260,20 @@
|
|||
<xul:menupopup anonid="input-box-contextmenu"
|
||||
onpopupshowing="if (document.commandDispatcher.focusedElement != this.parentNode.firstChild)
|
||||
this.parentNode.firstChild.focus();
|
||||
this.parentNode.doPopupItemEnabling(this);"
|
||||
oncommand="this.parentNode.doCommand(event.originalTarget.getAttribute('cmd'));event.preventBubble();">
|
||||
this.parentNode._doPopupItemEnabling(this);"
|
||||
onpopuphiding="this.parentNode._doPopupItemDisabling(this);"
|
||||
oncommand="var cmd = event.originalTarget.getAttribute('cmd'); if(cmd) { this.parentNode.doCommand(cmd); event.preventBubble(); }">
|
||||
<xul:menuitem label="&spellNoSuggestions.label;" anonid="spell-no-suggestions" disabled="true"/>
|
||||
<xul:menuseparator anonid="spell-suggestions-separator"/>
|
||||
<xul:menuitem label="&spellAddToDictionary.label;" accesskey="&spellAddToDictionary.accesskey;" anonid="spell-add-to-dictionary" oncommand="this.parentNode.parentNode.spellui.addToDictionary();"/>
|
||||
<xul:menuitem label="&spellEnable.label;" accesskey="&spellEnable.accesskey;" anonid="spell-check-enabled" oncommand="this.parentNode.parentNode.spellui.toggleEnabled();"/>
|
||||
<xul:menu label="&spellDictionaries.label;" accesskey="&spellDictionaries.accesskey;" anonid="spell-dictionaries">
|
||||
<xul:menupopup anonid="spell-dictionaries-menu"
|
||||
onpopupshowing="event.stopPropagation();"
|
||||
onpopuphiding="event.stopPropagation();">
|
||||
</xul:menupopup>
|
||||
</xul:menu>
|
||||
<xul:menuseparator anonid="spell-check-separator"/>
|
||||
<xul:menuitem label="&undoCmd.label;" accesskey="&undoCmd.accesskey;" cmd="cmd_undo"/>
|
||||
<xul:menuseparator/>
|
||||
<xul:menuitem label="&cutCmd.label;" accesskey="&cutCmd.accesskey;" cmd="cmd_cut"/>
|
||||
|
@ -230,7 +286,7 @@
|
|||
</content>
|
||||
|
||||
<implementation>
|
||||
<method name="doPopupItemEnabling">
|
||||
<method name="_doPopupItemEnabling">
|
||||
<parameter name="popupNode"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
|
@ -246,9 +302,80 @@
|
|||
children[i].setAttribute("disabled", "true");
|
||||
}
|
||||
}
|
||||
|
||||
// -- spell checking --
|
||||
var textboxElt = popupNode;
|
||||
do {
|
||||
if (textboxElt.localName == "textbox")
|
||||
break;
|
||||
textboxElt = textboxElt.parentNode;
|
||||
} while (textboxElt);
|
||||
if (! textboxElt || textboxElt.localName != "textbox") {
|
||||
// can't find it, give up
|
||||
this._setNoSpellCheckingAllowed();
|
||||
return;
|
||||
}
|
||||
var spellui = textboxElt.spellCheckerUI;
|
||||
this.spellui = spellui;
|
||||
|
||||
if (! spellui.canSpellCheck)
|
||||
{
|
||||
this._setNoSpellCheckingAllowed();
|
||||
return;
|
||||
}
|
||||
|
||||
spellui.initFromEvent(document.popupEvent);
|
||||
|
||||
var enabled = spellui.enabled;
|
||||
document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"spell-check-enabled").setAttribute("checked", enabled);
|
||||
|
||||
var overMisspelling = spellui.overMisspelling;
|
||||
this._setMenuItemVisibility("spell-add-to-dictionary", overMisspelling);
|
||||
this._setMenuItemVisibility("spell-suggestions-separator", overMisspelling);
|
||||
|
||||
// suggestion list
|
||||
var spellSeparator = document.getAnonymousElementByAttribute(this,
|
||||
"anonid", "spell-suggestions-separator");
|
||||
var numsug = spellui.addSuggestionsToMenu(popupNode, spellSeparator, 5);
|
||||
this._setMenuItemVisibility("spell-no-suggestions", overMisspelling && numsug == 0);
|
||||
|
||||
// dictionary list
|
||||
var dictmenu = document.getAnonymousElementByAttribute(this, "anonid",
|
||||
"spell-dictionaries-menu");
|
||||
var numdicts = spellui.addDictionaryListToMenu(dictmenu, null);
|
||||
this._setMenuItemVisibility("spell-dictionaries", enabled && numdicts > 1);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="_doPopupItemDisabling">
|
||||
<parameter name="popupNode"/>
|
||||
<body><![CDATA[
|
||||
if (this.spellui) {
|
||||
this.spellui.clearSuggestionsFromMenu();
|
||||
this.spellui.clearDictionaryListFromMenu();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_setMenuItemVisibility">
|
||||
<parameter name="anonid"/>
|
||||
<parameter name="visible"/>
|
||||
<body><![CDATA[
|
||||
document.getAnonymousElementByAttribute(this, "anonid", anonid).
|
||||
hidden = ! visible;
|
||||
]]></body>
|
||||
</method>
|
||||
<method name="_setNoSpellCheckingAllowed">
|
||||
<body><![CDATA[
|
||||
this._setMenuItemVisibility("spell-no-suggestions", false);
|
||||
this._setMenuItemVisibility("spell-check-enabled", false);
|
||||
this._setMenuItemVisibility("spell-check-separator", false);
|
||||
this._setMenuItemVisibility("spell-add-to-dictionary", false);
|
||||
this._setMenuItemVisibility("spell-suggestions-separator", false);
|
||||
this._setMenuItemVisibility("spell-dictionaries", false);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="doCommand">
|
||||
<parameter name="command"/>
|
||||
|
|
|
@ -10,3 +10,10 @@
|
|||
<!ENTITY selectAllCmd.accesskey "a">
|
||||
<!ENTITY deleteCmd.label "Delete">
|
||||
<!ENTITY deleteCmd.accesskey "d">
|
||||
<!ENTITY spellAddToDictionary.label "Add to dictionary">
|
||||
<!ENTITY spellAddToDictionary.accesskey "t">
|
||||
<!ENTITY spellEnable.label "Spell check this field">
|
||||
<!ENTITY spellEnable.accesskey "S">
|
||||
<!ENTITY spellNoSuggestions.label "(No spelling suggestions)">
|
||||
<!ENTITY spellDictionaries.label "Languages">
|
||||
<!ENTITY spellDictionaries.accesskey "l">
|
||||
|
|
|
@ -81,6 +81,9 @@ menubar > menu[open] {
|
|||
color: -moz-menuhovertext;
|
||||
background-color: -moz-menuhover;
|
||||
}
|
||||
menuitem.spell-suggestion {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
/* ::::: menu/menuitems in menulist popups ::::: */
|
||||
|
||||
|
|
|
@ -72,6 +72,10 @@ menuitem[_moz-menuactive="true"][disabled="true"] {
|
|||
color: GrayText;
|
||||
}
|
||||
|
||||
menuitem.spell-suggestion {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
/* ..... internal content .... */
|
||||
|
||||
.menu-accel,
|
||||
|
|
Загрузка…
Ссылка в новой задаче