tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AsyncSpellCheckTestHelper.sys.mjs (4386B)


      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 const SPELL_CHECK_ENDED_TOPIC = "inlineSpellChecker-spellCheck-ended";
      6 const SPELL_CHECK_STARTED_TOPIC = "inlineSpellChecker-spellCheck-started";
      7 
      8 const CP = Cc["@mozilla.org/content-pref/service;1"].getService(
      9  Ci.nsIContentPrefService2
     10 );
     11 
     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 export function maybeOnSpellCheck(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);
     37  }
     38 
     39  try {
     40    // False is important here.  Pass false so that the inline spell checker
     41    // isn't created if it doesn't already exist.
     42    var isc = editor.getInlineSpellChecker(false);
     43  } catch (err) {
     44    // getInlineSpellChecker throws if spell checking is not enabled instead of
     45    // just returning null, which seems kind of lame.  (Spell checking is not
     46    // enabled on Android.)  The point here is only to determine whether spell
     47    // check is pending, and if getInlineSpellChecker throws, then it's not
     48    // pending.
     49  }
     50  let waitingForEnded = isc && isc.spellCheckPending;
     51  let count = 0;
     52 
     53  function observe(subj, topic) {
     54    if (subj != editor) {
     55      return;
     56    }
     57    count = 0;
     58    let expectedTopic = waitingForEnded
     59      ? SPELL_CHECK_ENDED_TOPIC
     60      : SPELL_CHECK_STARTED_TOPIC;
     61    if (topic != expectedTopic) {
     62      console.error("Expected " + expectedTopic + " but got " + topic + "!");
     63    }
     64    waitingForEnded = !waitingForEnded;
     65  }
     66 
     67  // eslint-disable-next-line mozilla/use-services
     68  let os = Cc["@mozilla.org/observer-service;1"].getService(
     69    Ci.nsIObserverService
     70  );
     71  os.addObserver(observe, SPELL_CHECK_STARTED_TOPIC);
     72  os.addObserver(observe, SPELL_CHECK_ENDED_TOPIC);
     73 
     74  let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     75  timer.init(
     76    function tick() {
     77      // Wait an arbitrarily large number -- 100 -- turns of the event loop before
     78      // declaring that no spell checks will start.
     79      if (waitingForEnded || ++count < 100) {
     80        return;
     81      }
     82      timer.cancel();
     83      os.removeObserver(observe, SPELL_CHECK_STARTED_TOPIC);
     84      os.removeObserver(observe, SPELL_CHECK_ENDED_TOPIC);
     85      callback();
     86    },
     87    0,
     88    Ci.nsITimer.TYPE_REPEATING_SLACK
     89  );
     90 }
     91 
     92 /**
     93 * Waits until spell checking has stopped on the given element.
     94 *
     95 * @param editableElement  The element being spell checked.
     96 * @param callback         Called when spell check has completed or enough turns
     97 *                         of the event loop have passed to determine it has not
     98 *                         started.
     99 */
    100 export function onSpellCheck(editableElement, callback) {
    101  const { TestUtils } = ChromeUtils.importESModule(
    102    "resource://testing-common/TestUtils.sys.mjs"
    103  );
    104 
    105  let editor = editableElement.editor;
    106  TestUtils.topicObserved(SPELL_CHECK_ENDED_TOPIC, s => s == editor).then(
    107    callback
    108  );
    109 }
    110 
    111 export async function getDictionaryContentPref() {
    112  let dictionaries = await new Promise(resolve => {
    113    let value = "";
    114    CP.getByDomainAndName("mochi.test", "spellcheck.lang", null, {
    115      handleResult(pref) {
    116        value = pref.value;
    117      },
    118      handleCompletion() {
    119        resolve(value);
    120      },
    121    });
    122  });
    123 
    124  return dictionaries;
    125 }