mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
157a125630
- Bug 1144778 - Send an HTTP Date request header with telemetry pings. r=dexter (b630ff3123) - Bug 1268581 - Reduce Telemetry initialization delay in tests. r=dexter (08ea2597f4) - Bug 1205898 - Making TelemetryStopwatch.jsm handle keyed histograms. r=gfritzsche (2e1d793bc0) - Bug 1262386 - Move Scheduler shutdown() next to init(). r=dexter (9aa12c0859) - Bug 1162538 - Add test coverage for Telemetry archive probes. r=gfritzsche (f7f9095e82) - Bug 1186955 - Add test coverage. r=gfritzsche (cc76ba4fda) - Bug 1262386 - Trigger Telemetry scheduler tick after waking up from sleep. r=dexter (27b03357bf) - Bug 1178005 - Fix unintended octal literals (00 => 0). r=Mossop (dd738033b1) - Bug 1222054 - Fix broken tests. r=gfritzsche (a6c6fa3445) - Bug 1161515 - Reset UUID generator with fakeGenerateUUID(). r=gfritzsche (460ed17cb5) - Bug 1209912 - Use JSON.parse instead of nsIJSON.decode in Telemetry tests. r=Dexter (7ca55a9b5c) - Bug 1245136 - Discard old-format pending Telemetry files. r=gfritzsche (57f2a19c9d) - Bug 1034138 - d. Test BackgroundHangMonitor permahangs; r=vladan (7313b143bc) - Bug 1016629 - h. Fix wrong sysinfo usage; r=trivial (9823cd5ed0) - Bug 1197612 - In test_TelemetrySendOldPings.js, set the FHR pref to the value the tests assume it has. r=gfritzsche (06a41428b2) - Bug 1136082 - test_TelemetrySendOldPings.js is missing AddonManager initialization. r=froydnj (cfc700dd44) - Bug 1239480 - Make test_TelemetryReportingPolicy.js set the minimum policy version pref for the right channel. r=gfritzsche (e44841aa2a) - Bug 1230213 - test_TelemetryLog yields from a non generator function. r=dexter (34f28fb0b1) - Bug 1226178 - Fix deprecated octal literals warnings in Telemetry tests. r=gfritzsche (88208f0f2e) - Bug 1174111 - |test_sendTimeout| in test_TelemetryControllerShutdown.js must not wait on ping submission. r=gfritzsche (3b010e9743) - Bug 1120379 - Add tests for the deletion ping. r=gfritzsche (61e6fbd8a1) - Bug 1178262 - Add test-coverage for sending persisted deletion pings. r=gfritzsche (657fbbbcc2) - Bug 1174674 - Add test coverage. r=gfritzsche (426212e94c) - Bug 1167456 - Add test coverage. r=gfritzsche (4842d38e2e) - Bug 1198364 - Set FHR upload pref in telemetry/tests/unit/head.js to avoid test failures. r=gfritzsche (024599364e) - Bug 1149284 - Restore Telemetry tests. r=rvitillo, r=sstamm (88d4022e6b) - add esl (c459da1cd3) - Bug 1251785 - Remove remaining references to MOZILLA_XPCOMRT_API from toolkit. r=froydnj (5b5708031d) - Bug 1120379 - Add the documentation for deletion pings. r=gfritzsche (723f44f669) - Bug 1241599 - Add 'core' ping telemetry docs. r=gfritzsche (35fcc54195) - Bug 1241697 - Add docs for 'experiments' field in core ping. r=mfinkle (3c408f1a61) - Bug 1247572 - Add profileDate field to Android core ping docs. r=gfritzsche (79b1c71b53) - Bug 1249288 - Update telemetry docs to include defaultSearch. r=gfritzsche,rnewman (3807061291) - Bug 1257595 - Document that the 'core' pings profileDate field can be missing. r=mcomella (f40392cb2d) - Bug 1246816 - Add docs for profileDate. r=gfritzsche (7248d799aa) - Bug 1263761 - Update defaultSearch in core ping docs for custom search engines. r=gfritzsche (e516ecbab3) - Bug 1247982 - Lock request headers. r=mcmanus (8a5940a109) - Bug 1251332 - add PAC support for reversed ranges; r=bagder (7ac8fd97cb) - Bug 1178337 - Part 1: Supports all referrer policies for element atrributes. r=sicking, r=Gijs, r=mcmanus (85b7421b02) - Bug 1187357 - rename referrer attribute to referrerpolicy in tests. r=hsivonen (da334bf712) - Bug 1178337 - Part 2: Update/add test cases. r=sicking. (acec860fd8) - Bug 1260766 - the comparison of OriginAttributes in nsFrameLoader::Swap* methods should consider the usercontextid attribute of the owning element, r=smaug (82f8895bec) - bits of Bug 1110485 P1 (f8908eb35f) - Bug 1195968 - Check how CanvasFilterChainObserver accesses the CanvasRenderingContext2D. r=mstange (eecc12329b) - Bug 1260960 - Check skiaGL is enabled before calling skiaGLTex(), r=snorp (82c069fcc9) - align test stuff (c0ccc11ed9) - Bug 1245256 - GMP Plugins now installed in flat manner to accomodate widevine. r=spohl (ae0eb69979) - Bug 1245649: Turn on use-isnan, no-unexpected-multiline (0633b3470f) - Bug 1079665 - [e10s] Findbar focusContent doesn't work when a link was found. r=enndeakin (b349e62d5a) - Bug 1174291 - Fix ctrl-return for e10s findbar. r=evilpie (6f0bf0b149) - Bug 1174289 - Remove fake focus-ring after e10s findbar is closed. r=evilpie (302ffe7559) - Bug 1079665 - follow up, remove accidental line included from different patch. r=me (0904fe927c) - Bug 1260208 - part 1 - use C I/O facilities in TestWebGLElementArrayCache instead of C++ ones; r=BenWa The libc++ included with the Android NDK does not seem to work correctly with std::cerr; writing to it (or to std::cout, as confirmed by tests) causes the process to hang indefinitely, causing test failures. Using fprintf and stderr, however, seems to work correctly. (4279c2d09d) - Bug 1260208 - part 5 - add libc++ license to about:license when using it on Android; r=gerv,nalexander (4bcf23794a) - Bug 1260208 - part 0 - correctly compare EHTable when sorting; r=froydnj operator< for EHTable compares the LHS start PC with the RHS *end* PC. Because the ranges are non-overlapping, this works fine for two distinct EHTables. However, the comparison doesn't work if LHS and RHS refer to the same EHTable; in that case operator< returns true, even though it should return false because the two operands are identical. (dc2af36cec) - Bug 1254908 - ./mach bootstrap doesn't work on CentOS/Fedora when it attempts to upgrade Mercurial. r=gps (d288b314ec) - Bug 1239413. Clarify comment about the context flags. (c2b01ef6d1) - Bug 1146875 - Fix the leak-gauge.html broken and add a encoding declaration. r=dbaron (8df2510774) - Bug 1132499 - part 1 - convert nsTextEditorState::mValue to use Maybe instead of heap allocation; r=ehsan (2644faebbb) - Bug 1132499 - part 2 - convert nsTextEditorState::mValue to be an nsString; r=ehsan (6e0df4d1dc) - Bug 409885 - Use SetHostPort in nsHTMLDocument::SetDomain. r=bz (2d289a79c5) - Bug 1269475 - Fix uninitialized variable warning. r=jdm (881fa29803) - Bug 1263935 - Expose native version of mapURIToAddonId via amIAddonPathService. r=mossop (04da9fe703) - missing bit of Bug 1255040 Add webidl for install/uninstall (63b5489b3d) - Bug 1234974 - Handle null GetOwner() in |BluetoothAdapter::IsBluetoothCertifiedApp|, r=shuang (e4dde47d7f) - Bug 1241117 - Fix mAppUuid access before assign in BluetoothGatt::Connect. r=joliu (3920535f2a) - Bug 1238424 - Fix a missing header in Bluetooth module. r=brsun (438fd74375) - Bug 1267958: Only complain for negative size, not merely zero. r=jrmuizel (194bd2a754) - Bug 1320621 - Make sure --enable-system-hunspell picks up system headers. r=glandium (125c4ea215) - Bug 1266430: Support offsets in DrawTargetD2D1::CopySurface when using PartialUploading. r=jrmuizel (de8630b117) - Bug 1267363. Disable hinting on osx fonts only if we have expclity grayscale AA. r=mstange (c4c32fd7cc) - Bug 1134549 - Switch FlattenBezier from floats to doubles. r=bas (5753ab16a3) - Bug 1240437 part 2: Follow-up to fix implicit constrcutor static analysis failure. r=me (525d9d9a9f) - Bug 1256678 - Backout diagnostic patch rev 39c895b67af2 - r=me (f63698de77) - Bug 1256678 - Account for truncated font names in ScaledFontWin::GetFontFileData() - r=jfkthame (a6930e0a33) - Bug 1256678 - Re-add nightly-only crash if ScaledFontWin::GetFontFileData fails to find a matching TrueType collection font - r=jfkthame (8bec2d43a2) - Bug 1260350 - GFX: 2D: Use ConvolveHorizontally_LS3. r=jrmuizel (9d2f372593) - Bug 1260112 - GFX: 2D: Fix unaligned access in ConvolveVertically/Horizontally_LS3. r=huangwenjun06 (43ba8f7b05) - Bug 1260885 - Make SurfaceFormat::R5G6B5_UINT16 properly round-trip through SourceSurfaceCairo. r=lsalzman (bc8f0c0876) - Bug 1262415 - make Accessible to keep weak pointers to parent and children, r=yzen (c0b987fe10) - Bug 1267271 - skip empty surfaces in DrawTargetSkia::DrawSurfaceWithShadow. r=mchang (fd488c918a) - Bug 1249600. Lookup font and font family from font face when requesting SkTypeface. r=bas (0281313c33) - Bug 1268096. Sync the D3D11 rasterizer state if pointDrawMode or multisample changes. (25b2af8b26) - Bug 1203132 - Add an SVG for the B2G flow of touch events. r=botond (2ce3b0ddc4) - Bug 1180322. Add a document describing the history of layers (b3351dbba3) - Bug 1235223. Update history document. (212d356bd0) - Bug 1235223 - Fix typos in layers history document. (f19a5802d8) - Bug 1235223 - Fix another typo in the layers history document. (9663fe5447) - Bug 1265112 - Add support for NV_texture_barrier to GLContext. r=jrmuizel (f1f5fb1a3a) - Bug 1240730 - Initialize all GLLibraryEGL symbols in the ctor. r=mattwoodrow (dae8955458) - Bug 1240730 - Initialize all GLXLibrary members in the ctor. r=mattwoodrow (8218ed6fd9) - bug 1250485 - make the ctor for GLXLibrary constexpr r=jrmuizel (a571491f0a) - mitor spacing (0083550ab2) - Bug 1256492 - Cast to proper width to avoid C4312 on VS2015; r=jrmuizel (1bb2ed20d3) - Bug 1266878 - Fix off-by-one error in ParamTraits<StereoMode> - r=nical (f467d496b8) - Bug 1258758 - rename GetEffectiveClipRect to GetLocalClipRect. r=kats (897798948f) - Bug 1249936 - add a LayerComposite::GetShadowTransform method & simplify Layer::GetLocalTransform. r=botond (fe492a1327) - Bug 1269032 - Add support for user multipliers to pan gesture inputs. r=mstange (ea7698dca2) - Bug 1265510 - Add some scroll-snapping logging to APZC. r=botond (6f2369163a) - Bug 1268523 - Avoid leaking tasks when they are posted to a destroyed APZC instance. r=botond (70e1e63b7b) - Bug 1265510 - Ensure that new input blocks still allow APZCs with interrupted animations to scroll-snap. r=botond (01341b554b) - Bug 1269068 - Zero out the axis velocity once the wheel scroll animation is terminating. r=botond (9a9f384485) - Bug 1246056 - Ensure that the MockContentController's timestamp is always >= GetStartupTime(). r=botond (4fe53e1f24) - Bug 1256341 - Add a gtest to catch scenarios where a tap timeout is interrupted by a non-touch block. r=botond (21a15f5a5a) - Bug 1266833 - When the scroll position is clamped during a frame reconstruction, send a scroll offset update to APZ. r=tnikkel (c0acd70a3d) - Bug 1268517 - Remove unused function. r=botond (534e4d9bae) - Bug 1213095 - Fix APZEventState build with logging enabled. r=botond (ac7c1e9401) - Bug 1250954 - Correct the SharedSurfaceTextureClient when forwarder changed. r=jgilbert (0a389bc0fa) - Bug 1265873 - Use gfxSharedReadLock in TextureClientPool r=nical (e3ed936a8a) - Bug 1265468 - Update the compositor pointer on all TextureSources in the list when recycling in ImageHost. r=nical (78f29244bb) - Bug 1252237 - Remove the TextureHost shmem mapping failed assert. r=milan (d0b7230dff) - Bug 1265112 - When rendering blend modes with CompositorOGL, use NV_texture_barrier (if available) to sample directly from the framebuffer. r=jrmuizel (6f3ae237a5) - Bug 1268878 - Include various of gfxFontEntry's sub-objects in memory reporting. r=njn (b960415fa8) - Bug 1268951 - Reallocate sanitized user font data into an appropriately-sized block, to reduce ongoing RAM footprint. r=jrmuizel (a26e9dd632) - Bug 1123416 - Part 1: Make topsrcdir a valid Gradle project root. r=sebastian (77b0b35fc1) - Bug 1260672: Remove 'nsAutoPtr.h' and clean up includes of Gonk diskspace watcher, r=gsvelto (99c4c35e3d) - Bug 1167535 - Fix fanotify 4g size limit. r=fabrice (c62015e454) - Bug 1167817 - Switch back to printf_stderr in GonkDiskSpaceWatcher.cpp r=dhylands (110445f628) - Bug 1260672: Use |UniquePtr| for Gonk alarms, r=gsvelto (03678b9015) - Bug 1260672: Use |UniquePtr| for Gonk sensors, r=gsvelto (545ec3fc70) - Bug 1263845. When a parent changes from auto height to non-auto height or vice versa, a percentage height non-block child needs to realize it's doing a vertical resize. r=dbaron (05db492bc8) - Bug 1268009 - If APZ is force-disabled, disable paint skipping even for apz-originated scrolls. r=kats (c02f8755cd) - Bug 1267555 part 1 - [css-grid] Make grid-aligned abs.pos. descendants that span from 'auto' to the first/last line stretch to the outer edge of the first/last track respectively. r=dholbert (88f6261043) - Bug 1267555 part 2 - [css-grid] Adjust reftests for abs.pos. "auto/first-line" and "last-line/auto" change. (43d03ab15b)
594 lines
19 KiB
JavaScript
594 lines
19 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
this.EXPORTED_SYMBOLS = [ "InlineSpellChecker",
|
|
"SpellCheckHelper" ];
|
|
var gLanguageBundle;
|
|
var gRegionBundle;
|
|
const MAX_UNDO_STACK_DEPTH = 1;
|
|
|
|
const Cc = Components.classes;
|
|
const Ci = Components.interfaces;
|
|
const Cu = Components.utils;
|
|
|
|
this.InlineSpellChecker = function InlineSpellChecker(aEditor) {
|
|
this.init(aEditor);
|
|
this.mAddedWordStack = []; // We init this here to preserve it between init/uninit calls
|
|
}
|
|
|
|
InlineSpellChecker.prototype = {
|
|
// Call this function to initialize for a given editor
|
|
init: function(aEditor)
|
|
{
|
|
this.uninit();
|
|
this.mEditor = aEditor;
|
|
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;
|
|
}
|
|
},
|
|
|
|
initFromRemote: function(aSpellInfo)
|
|
{
|
|
if (this.mRemote)
|
|
throw new Error("Unexpected state");
|
|
this.uninit();
|
|
|
|
if (!aSpellInfo)
|
|
return;
|
|
this.mInlineSpellChecker = this.mRemote = new RemoteSpellChecker(aSpellInfo);
|
|
this.mOverMisspelling = aSpellInfo.overMisspelling;
|
|
this.mMisspelling = aSpellInfo.misspelling;
|
|
},
|
|
|
|
// call this to clear state
|
|
uninit: function()
|
|
{
|
|
if (this.mRemote) {
|
|
this.mRemote.uninit();
|
|
this.mRemote = null;
|
|
}
|
|
|
|
this.mEditor = null;
|
|
this.mInlineSpellChecker = null;
|
|
this.mOverMisspelling = false;
|
|
this.mMisspelling = "";
|
|
this.mMenu = null;
|
|
this.mSpellSuggestions = [];
|
|
this.mSuggestionItems = [];
|
|
this.mDictionaryMenu = null;
|
|
this.mDictionaryNames = [];
|
|
this.mDictionaryItems = [];
|
|
this.mWordNode = null;
|
|
},
|
|
|
|
// for each UI event, you must call this function, it will compute the
|
|
// word the cursor is over
|
|
initFromEvent: function(rangeParent, rangeOffset)
|
|
{
|
|
this.mOverMisspelling = false;
|
|
|
|
if (!rangeParent || !this.mInlineSpellChecker)
|
|
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.getMisspelledWord(rangeParent,
|
|
rangeOffset);
|
|
if (! range)
|
|
return; // not over a misspelled word
|
|
|
|
this.mMisspelling = range.toString();
|
|
this.mOverMisspelling = true;
|
|
this.mWordNode = rangeParent;
|
|
this.mWordOffset = 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
|
|
if (this.mRemote)
|
|
return this.mRemote.canSpellCheck;
|
|
return this.mInlineSpellChecker != null;
|
|
},
|
|
|
|
get initialSpellCheckPending() {
|
|
if (this.mRemote) {
|
|
return this.mRemote.spellCheckPending;
|
|
}
|
|
return !!(this.mInlineSpellChecker &&
|
|
!this.mInlineSpellChecker.spellChecker &&
|
|
this.mInlineSpellChecker.spellCheckPending);
|
|
},
|
|
|
|
// Whether spellchecking is enabled in the current box
|
|
get enabled()
|
|
{
|
|
if (this.mRemote)
|
|
return this.mRemote.enableRealTimeSpell;
|
|
return (this.mInlineSpellChecker &&
|
|
this.mInlineSpellChecker.enableRealTimeSpell);
|
|
},
|
|
set enabled(isEnabled)
|
|
{
|
|
if (this.mRemote)
|
|
this.mRemote.setSpellcheckUserOverride(isEnabled);
|
|
else if (this.mInlineSpellChecker)
|
|
this.mEditor.setSpellcheckUserOverride(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.mRemote && (!this.mInlineSpellChecker || !this.mOverMisspelling))
|
|
return 0; // nothing to do
|
|
|
|
var spellchecker = this.mRemote || this.mInlineSpellChecker.spellChecker;
|
|
try {
|
|
if (!this.mRemote && !spellchecker.CheckCurrentWord(this.mMisspelling))
|
|
return 0; // word seems not misspelled after all (?)
|
|
} catch(e) {
|
|
return 0;
|
|
}
|
|
|
|
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 = menu.ownerDocument.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 = [];
|
|
},
|
|
|
|
sortDictionaryList: function(list) {
|
|
var sortedList = [];
|
|
for (var i = 0; i < list.length; i ++) {
|
|
sortedList.push({"id": list[i],
|
|
"label": this.getDictionaryDisplayName(list[i])});
|
|
}
|
|
sortedList.sort(function(a, b) {
|
|
if (a.label < b.label)
|
|
return -1;
|
|
if (a.label > b.label)
|
|
return 1;
|
|
return 0;
|
|
});
|
|
|
|
return sortedList;
|
|
},
|
|
|
|
// 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.enabled)
|
|
return 0;
|
|
|
|
var list;
|
|
var curlang = "";
|
|
if (this.mRemote) {
|
|
list = this.mRemote.dictionaryList;
|
|
curlang = this.mRemote.currentDictionary;
|
|
}
|
|
else if (this.mInlineSpellChecker) {
|
|
var spellchecker = this.mInlineSpellChecker.spellChecker;
|
|
var o1 = {}, o2 = {};
|
|
spellchecker.GetDictionaryList(o1, o2);
|
|
list = o1.value;
|
|
var listcount = o2.value;
|
|
try {
|
|
curlang = spellchecker.GetCurrentDictionary();
|
|
} catch(e) {}
|
|
}
|
|
|
|
var sortedList = this.sortDictionaryList(list);
|
|
|
|
for (var i = 0; i < sortedList.length; i ++) {
|
|
this.mDictionaryNames.push(sortedList[i].id);
|
|
var item = menu.ownerDocument.createElement("menuitem");
|
|
item.setAttribute("id", "spell-check-dictionary-" + sortedList[i].id);
|
|
item.setAttribute("label", sortedList[i].label);
|
|
item.setAttribute("type", "radio");
|
|
this.mDictionaryItems.push(item);
|
|
if (curlang == sortedList[i].id) {
|
|
item.setAttribute("checked", "true");
|
|
} else {
|
|
var callback = function(me, val, dictName) {
|
|
return function(evt) {
|
|
me.selectDictionary(val);
|
|
// Notify change of dictionary, especially for Thunderbird,
|
|
// which is otherwise not notified any more.
|
|
var view = menu.ownerDocument.defaultView;
|
|
var spellcheckChangeEvent = new view.CustomEvent(
|
|
"spellcheck-changed", {detail: { dictionary: dictName}});
|
|
menu.ownerDocument.dispatchEvent(spellcheckChangeEvent);
|
|
}
|
|
};
|
|
item.addEventListener("command", callback(this, i, sortedList[i].id), true);
|
|
}
|
|
if (insertBefore)
|
|
menu.insertBefore(item, insertBefore);
|
|
else
|
|
menu.appendChild(item);
|
|
}
|
|
return list.length;
|
|
},
|
|
|
|
// Formats a valid BCP 47 language tag based on available localized names.
|
|
getDictionaryDisplayName: function(dictionaryName) {
|
|
try {
|
|
// Get the display name for this dictionary.
|
|
let languageTagMatch = /^([a-z]{2,3}|[a-z]{4}|[a-z]{5,8})(?:[-_]([a-z]{4}))?(?:[-_]([A-Z]{2}|[0-9]{3}))?((?:[-_](?:[a-z0-9]{5,8}|[0-9][a-z0-9]{3}))*)(?:[-_][a-wy-z0-9](?:[-_][a-z0-9]{2,8})+)*(?:[-_]x(?:[-_][a-z0-9]{1,8})+)?$/i;
|
|
var [languageTag, languageSubtag, scriptSubtag, regionSubtag, variantSubtags] = dictionaryName.match(languageTagMatch);
|
|
} catch(e) {
|
|
// If we weren't given a valid language tag, just use the raw dictionary name.
|
|
return dictionaryName;
|
|
}
|
|
|
|
if (!gLanguageBundle) {
|
|
// Create the bundles for language and region names.
|
|
var bundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
|
.getService(Components.interfaces.nsIStringBundleService);
|
|
gLanguageBundle = bundleService.createBundle(
|
|
"chrome://global/locale/languageNames.properties");
|
|
gRegionBundle = bundleService.createBundle(
|
|
"chrome://global/locale/regionNames.properties");
|
|
}
|
|
|
|
var displayName = "";
|
|
|
|
// Language subtag will normally be 2 or 3 letters, but could be up to 8.
|
|
try {
|
|
displayName += gLanguageBundle.GetStringFromName(languageSubtag.toLowerCase());
|
|
} catch(e) {
|
|
displayName += languageSubtag.toLowerCase(); // Fall back to raw language subtag.
|
|
}
|
|
|
|
// Region subtag will be 2 letters or 3 digits.
|
|
if (regionSubtag) {
|
|
displayName += " (";
|
|
|
|
try {
|
|
displayName += gRegionBundle.GetStringFromName(regionSubtag.toLowerCase());
|
|
} catch(e) {
|
|
displayName += regionSubtag.toUpperCase(); // Fall back to raw region subtag.
|
|
}
|
|
|
|
displayName += ")";
|
|
}
|
|
|
|
// Script subtag will be 4 letters.
|
|
if (scriptSubtag) {
|
|
displayName += " / ";
|
|
|
|
// XXX: See bug 666662 and bug 666731 for full implementation.
|
|
displayName += scriptSubtag; // Fall back to raw script subtag.
|
|
}
|
|
|
|
// Each variant subtag will be 4 to 8 chars.
|
|
if (variantSubtags)
|
|
// XXX: See bug 666662 and bug 666731 for full implementation.
|
|
displayName += " (" + variantSubtags.substr(1).split(/[-_]/).join(" / ") + ")"; // Collapse multiple variants.
|
|
|
|
return displayName;
|
|
},
|
|
|
|
// 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.mRemote) {
|
|
this.mRemote.selectDictionary(index);
|
|
return;
|
|
}
|
|
if (! this.mInlineSpellChecker || index < 0 || index >= this.mDictionaryNames.length)
|
|
return;
|
|
var spellchecker = this.mInlineSpellChecker.spellChecker;
|
|
spellchecker.SetCurrentDictionary(this.mDictionaryNames[index]);
|
|
this.mInlineSpellChecker.spellCheckRange(null); // causes recheck
|
|
},
|
|
|
|
// callback for selecting a suggested replacement
|
|
replaceMisspelling: function(index)
|
|
{
|
|
if (this.mRemote) {
|
|
this.mRemote.replaceMisspelling(index);
|
|
return;
|
|
}
|
|
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()
|
|
{
|
|
if (this.mRemote)
|
|
this.mRemote.toggleEnabled();
|
|
else
|
|
this.mEditor.setSpellcheckUserOverride(!this.mInlineSpellChecker.enableRealTimeSpell);
|
|
},
|
|
|
|
// callback for adding the current misspelling to the user-defined dictionary
|
|
addToDictionary: function()
|
|
{
|
|
// Prevent the undo stack from growing over the max depth
|
|
if (this.mAddedWordStack.length == MAX_UNDO_STACK_DEPTH)
|
|
this.mAddedWordStack.shift();
|
|
|
|
this.mAddedWordStack.push(this.mMisspelling);
|
|
if (this.mRemote)
|
|
this.mRemote.addToDictionary();
|
|
else {
|
|
this.mInlineSpellChecker.addWordToDictionary(this.mMisspelling);
|
|
}
|
|
},
|
|
// callback for removing the last added word to the dictionary LIFO fashion
|
|
undoAddToDictionary: function()
|
|
{
|
|
if (this.mAddedWordStack.length > 0)
|
|
{
|
|
var word = this.mAddedWordStack.pop();
|
|
if (this.mRemote)
|
|
this.mRemote.undoAddToDictionary(word);
|
|
else
|
|
this.mInlineSpellChecker.removeWordFromDictionary(word);
|
|
}
|
|
},
|
|
canUndo : function()
|
|
{
|
|
// Return true if we have words on the stack
|
|
return (this.mAddedWordStack.length > 0);
|
|
},
|
|
ignoreWord: function()
|
|
{
|
|
if (this.mRemote)
|
|
this.mRemote.ignoreWord();
|
|
else
|
|
this.mInlineSpellChecker.ignoreWord(this.mMisspelling);
|
|
}
|
|
};
|
|
|
|
var SpellCheckHelper = {
|
|
// Set when over a non-read-only <textarea> or editable <input>.
|
|
EDITABLE: 0x1,
|
|
|
|
// Set when over an <input> element of any type.
|
|
INPUT: 0x2,
|
|
|
|
// Set when over any <textarea>.
|
|
TEXTAREA: 0x4,
|
|
|
|
// Set when over any text-entry <input>.
|
|
TEXTINPUT: 0x8,
|
|
|
|
// Set when over an <input> that can be used as a keyword field.
|
|
KEYWORD: 0x10,
|
|
|
|
// Set when over an element that otherwise would not be considered
|
|
// "editable" but is because content editable is enabled for the document.
|
|
CONTENTEDITABLE: 0x20,
|
|
|
|
// Set when over an <input type="number"> or other non-text field.
|
|
NUMERIC: 0x40,
|
|
|
|
// Set when over an <input type="password"> field.
|
|
PASSWORD: 0x80,
|
|
|
|
isTargetAKeywordField(aNode, window) {
|
|
if (!(aNode instanceof window.HTMLInputElement))
|
|
return false;
|
|
|
|
var form = aNode.form;
|
|
if (!form || aNode.type == "password")
|
|
return false;
|
|
|
|
var method = form.method.toUpperCase();
|
|
|
|
// These are the following types of forms we can create keywords for:
|
|
//
|
|
// method encoding type can create keyword
|
|
// GET * YES
|
|
// * YES
|
|
// POST YES
|
|
// POST application/x-www-form-urlencoded YES
|
|
// POST text/plain NO (a little tricky to do)
|
|
// POST multipart/form-data NO
|
|
// POST everything else YES
|
|
return (method == "GET" || method == "") ||
|
|
(form.enctype != "text/plain") && (form.enctype != "multipart/form-data");
|
|
},
|
|
|
|
// Returns the computed style attribute for the given element.
|
|
getComputedStyle(aElem, aProp) {
|
|
return aElem.ownerDocument
|
|
.defaultView
|
|
.getComputedStyle(aElem, "").getPropertyValue(aProp);
|
|
},
|
|
|
|
isEditable(element, window) {
|
|
var flags = 0;
|
|
if (element instanceof window.HTMLInputElement) {
|
|
flags |= this.INPUT;
|
|
|
|
if (element.mozIsTextField(false) || element.type == "number") {
|
|
flags |= this.TEXTINPUT;
|
|
|
|
if (element.type == "number") {
|
|
flags |= this.NUMERIC;
|
|
}
|
|
|
|
// Allow spellchecking UI on all text and search inputs.
|
|
if (!element.readOnly &&
|
|
(element.type == "text" || element.type == "search")) {
|
|
flags |= this.EDITABLE;
|
|
}
|
|
if (this.isTargetAKeywordField(element, window))
|
|
flags |= this.KEYWORD;
|
|
if (element.type == "password") {
|
|
flags |= this.PASSWORD;
|
|
}
|
|
}
|
|
} else if (element instanceof window.HTMLTextAreaElement) {
|
|
flags |= this.TEXTINPUT | this.TEXTAREA;
|
|
if (!element.readOnly) {
|
|
flags |= this.EDITABLE;
|
|
}
|
|
}
|
|
|
|
if (!(flags & this.EDITABLE)) {
|
|
var win = element.ownerDocument.defaultView;
|
|
if (win) {
|
|
var isEditable = false;
|
|
try {
|
|
var editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIEditingSession);
|
|
if (editingSession.windowIsEditable(win) &&
|
|
this.getComputedStyle(element, "-moz-user-modify") == "read-write") {
|
|
isEditable = true;
|
|
}
|
|
}
|
|
catch(ex) {
|
|
// If someone built with composer disabled, we can't get an editing session.
|
|
}
|
|
|
|
if (isEditable)
|
|
flags |= this.CONTENTEDITABLE;
|
|
}
|
|
}
|
|
|
|
return flags;
|
|
},
|
|
};
|
|
|
|
function RemoteSpellChecker(aSpellInfo) {
|
|
this._spellInfo = aSpellInfo;
|
|
this._suggestionGenerator = null;
|
|
}
|
|
|
|
RemoteSpellChecker.prototype = {
|
|
get canSpellCheck() { return this._spellInfo.canSpellCheck; },
|
|
get spellCheckPending() { return this._spellInfo.initialSpellCheckPending; },
|
|
get overMisspelling() { return this._spellInfo.overMisspelling; },
|
|
get enableRealTimeSpell() { return this._spellInfo.enableRealTimeSpell; },
|
|
|
|
GetSuggestedWord() {
|
|
if (!this._suggestionGenerator) {
|
|
this._suggestionGenerator = (function*(spellInfo) {
|
|
for (let i of spellInfo.spellSuggestions)
|
|
yield i;
|
|
})(this._spellInfo);
|
|
}
|
|
|
|
let next = this._suggestionGenerator.next();
|
|
if (next.done) {
|
|
this._suggestionGenerator = null;
|
|
return "";
|
|
}
|
|
return next.value;
|
|
},
|
|
|
|
get currentDictionary() { return this._spellInfo.currentDictionary },
|
|
get dictionaryList() { return this._spellInfo.dictionaryList.slice(); },
|
|
|
|
selectDictionary(index) {
|
|
this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:selectDictionary",
|
|
{ index });
|
|
},
|
|
|
|
replaceMisspelling(index) {
|
|
this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:replaceMisspelling",
|
|
{ index });
|
|
},
|
|
|
|
toggleEnabled() { this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:toggleEnabled", {}); },
|
|
addToDictionary() {
|
|
// This is really ugly. There is an nsISpellChecker somewhere in the
|
|
// parent that corresponds to our current element's spell checker in the
|
|
// child, but it's hard to access it. However, we know that
|
|
// addToDictionary adds the word to the singleton personal dictionary, so
|
|
// we just do that here.
|
|
// NB: We also rely on the fact that we only ever pass an empty string in
|
|
// as the "lang".
|
|
|
|
let dictionary = Cc["@mozilla.org/spellchecker/personaldictionary;1"]
|
|
.getService(Ci.mozIPersonalDictionary);
|
|
dictionary.addWord(this._spellInfo.misspelling, "");
|
|
|
|
this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:recheck", {});
|
|
},
|
|
undoAddToDictionary(word) {
|
|
let dictionary = Cc["@mozilla.org/spellchecker/personaldictionary;1"]
|
|
.getService(Ci.mozIPersonalDictionary);
|
|
dictionary.removeWord(word, "");
|
|
|
|
this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:recheck", {});
|
|
},
|
|
ignoreWord() {
|
|
let dictionary = Cc["@mozilla.org/spellchecker/personaldictionary;1"]
|
|
.getService(Ci.mozIPersonalDictionary);
|
|
dictionary.ignoreWord(this._spellInfo.misspelling);
|
|
|
|
this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:recheck", {});
|
|
},
|
|
uninit() { this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:uninit", {}); }
|
|
};
|