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