Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
var EXPORTED_SYMBOLS = ["onSpellCheck"];
6
7
const SPELL_CHECK_ENDED_TOPIC = "inlineSpellChecker-spellCheck-ended";
8
const SPELL_CHECK_STARTED_TOPIC = "inlineSpellChecker-spellCheck-started";
9
10
/**
11
* Waits until spell checking has stopped on the given element.
12
*
13
* When a spell check is pending, this waits indefinitely until the spell check
14
* ends. When a spell check is not pending, it waits a small number of turns of
15
* the event loop: if a spell check begins, it resumes waiting indefinitely for
16
* the end, and otherwise it stops waiting and calls the callback.
17
*
18
* This this can therefore trap spell checks that have not started at the time
19
* of calling, spell checks that have already started, multiple consecutive
20
* spell checks, and the absence of spell checks altogether.
21
*
22
* @param editableElement The element being spell checked.
23
* @param callback Called when spell check has completed or enough turns
24
* of the event loop have passed to determine it has not
25
* started.
26
*/
27
function onSpellCheck(editableElement, callback) {
28
let editor = editableElement.editor;
29
if (!editor) {
30
let win = editableElement.ownerGlobal;
31
editor = win.docShell.editingSession.getEditorForWindow(win);
32
}
33
if (!editor) {
34
throw new Error("Unable to find editor for element " + editableElement);
35
}
36
37
try {
38
// False is important here. Pass false so that the inline spell checker
39
// isn't created if it doesn't already exist.
40
var isc = editor.getInlineSpellChecker(false);
41
} catch (err) {
42
// getInlineSpellChecker throws if spell checking is not enabled instead of
43
// just returning null, which seems kind of lame. (Spell checking is not
44
// enabled on Android.) The point here is only to determine whether spell
45
// check is pending, and if getInlineSpellChecker throws, then it's not
46
// pending.
47
}
48
let waitingForEnded = isc && isc.spellCheckPending;
49
let count = 0;
50
51
function observe(subj, topic, data) {
52
if (subj != editor) {
53
return;
54
}
55
count = 0;
56
let expectedTopic = waitingForEnded
57
? SPELL_CHECK_ENDED_TOPIC
58
: SPELL_CHECK_STARTED_TOPIC;
59
if (topic != expectedTopic) {
60
Cu.reportError("Expected " + expectedTopic + " but got " + topic + "!");
61
}
62
waitingForEnded = !waitingForEnded;
63
}
64
65
// eslint-disable-next-line mozilla/use-services
66
let os = Cc["@mozilla.org/observer-service;1"].getService(
67
Ci.nsIObserverService
68
);
69
os.addObserver(observe, SPELL_CHECK_STARTED_TOPIC);
70
os.addObserver(observe, SPELL_CHECK_ENDED_TOPIC);
71
72
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
73
timer.init(
74
function tick() {
75
// Wait an arbitrarily large number -- 50 -- turns of the event loop before
76
// declaring that no spell checks will start.
77
if (waitingForEnded || ++count < 50) {
78
return;
79
}
80
timer.cancel();
81
os.removeObserver(observe, SPELL_CHECK_STARTED_TOPIC);
82
os.removeObserver(observe, SPELL_CHECK_ENDED_TOPIC);
83
callback();
84
},
85
0,
86
Ci.nsITimer.TYPE_REPEATING_SLACK
87
);
88
}