Bug 1509583 - Move InlineSpellChecker to sync over locale codes rather than indexes. r=Felipe
authorZibi Braniecki <zbraniecki@mozilla.com>
Fri, 11 Jan 2019 00:23:48 +0000
changeset 510529 8d5e2931f526c53bf8ca86250c3caea6441b5614
parent 510528 9d7f77b05ae7ed2a809e2ecf3d7c76974c9e62f7
child 510530 ee1c9afb353f2b5bffe498b7a71c60e9b78927cc
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersFelipe
bugs1509583
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1509583 - Move InlineSpellChecker to sync over locale codes rather than indexes. r=Felipe Differential Revision: https://phabricator.services.mozilla.com/D15762
toolkit/modules/InlineSpellChecker.jsm
toolkit/modules/InlineSpellCheckerContent.jsm
--- a/toolkit/modules/InlineSpellChecker.jsm
+++ b/toolkit/modules/InlineSpellChecker.jsm
@@ -48,17 +48,16 @@ InlineSpellChecker.prototype = {
     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(rangeParent, rangeOffset) {
     this.mOverMisspelling = false;
@@ -165,35 +164,28 @@ InlineSpellChecker.prototype = {
     }
     this.mSuggestionItems = [];
   },
 
   sortDictionaryList(list) {
     var sortedList = [];
     var names = Services.intl.getLocaleDisplayNames(undefined, list);
     for (var i = 0; i < list.length; i++) {
-      sortedList.push({"id": list[i],
-                       "label": names[i]});
+      sortedList.push({"localeCode": list[i],
+                       "displayName": names[i]});
     }
-    sortedList.sort(function(a, b) {
-      if (a.label < b.label)
-        return -1;
-      if (a.label > b.label)
-        return 1;
-      return 0;
-    });
-
+    let comparer = (new Services.intl.Collator()).compare;
+    sortedList.sort((a, b) => comparer(a.displayName, b.displayName));
     return sortedList;
   },
 
   // returns the number of dictionary languages. If insertBefore is NULL, this
   // does an append to the given menu
   addDictionaryListToMenu(menu, insertBefore) {
     this.mDictionaryMenu = menu;
-    this.mDictionaryNames = [];
     this.mDictionaryItems = [];
 
     if (!this.enabled)
       return 0;
 
     var list;
     var curlang = "";
     if (this.mRemote) {
@@ -207,37 +199,39 @@ InlineSpellChecker.prototype = {
       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.createXULElement("menuitem");
-      item.setAttribute("id", "spell-check-dictionary-" + sortedList[i].id);
-      item.setAttribute("label", sortedList[i].label);
+      item.setAttribute("id", "spell-check-dictionary-" + sortedList[i].localeCode);
+      // XXX: Once Fluent has dynamic references, we could also lazily
+      //      inject regionNames/languageNames FTL and localize using
+      //      `l10n-id` here.
+      item.setAttribute("label", sortedList[i].displayName);
       item.setAttribute("type", "radio");
       this.mDictionaryItems.push(item);
-      if (curlang == sortedList[i].id) {
+      if (curlang == sortedList[i].localeCode) {
         item.setAttribute("checked", "true");
       } else {
-        var callback = function(me, val, dictName) {
+        var callback = function(me, localeCode) {
           return function(evt) {
-            me.selectDictionary(val);
+            me.selectDictionary(localeCode);
             // Notify change of dictionary, especially for Thunderbird,
             // which is otherwise not notified any more.
             var view = menu.ownerGlobal;
             var spellcheckChangeEvent = new view.CustomEvent(
-                  "spellcheck-changed", {detail: { dictionary: dictName}});
+                  "spellcheck-changed", {detail: { dictionary: localeCode}});
             menu.ownerDocument.dispatchEvent(spellcheckChangeEvent);
           };
         };
-        item.addEventListener("command", callback(this, i, sortedList[i].id), true);
+        item.addEventListener("command", callback(this, sortedList[i].localeCode), true);
       }
       if (insertBefore)
         menu.insertBefore(item, insertBefore);
       else
         menu.appendChild(item);
     }
     return list.length;
   },
@@ -247,25 +241,25 @@ InlineSpellChecker.prototype = {
   clearDictionaryListFromMenu() {
     for (var i = 0; i < this.mDictionaryItems.length; i++) {
       this.mDictionaryMenu.removeChild(this.mDictionaryItems[i]);
     }
     this.mDictionaryItems = [];
   },
 
   // callback for selecting a dictionary
-  selectDictionary(index) {
+  selectDictionary(localeCode) {
     if (this.mRemote) {
-      this.mRemote.selectDictionary(index);
+      this.mRemote.selectDictionary(localeCode);
       return;
     }
-    if (!this.mInlineSpellChecker || index < 0 || index >= this.mDictionaryNames.length)
+    if (!this.mInlineSpellChecker)
       return;
     var spellchecker = this.mInlineSpellChecker.spellChecker;
-    spellchecker.SetCurrentDictionary(this.mDictionaryNames[index]);
+    spellchecker.SetCurrentDictionary(localeCode);
     this.mInlineSpellChecker.spellCheckRange(null); // causes recheck
   },
 
   // callback for selecting a suggested replacement
   replaceMisspelling(index) {
     if (this.mRemote) {
       this.mRemote.replaceMisspelling(index);
       return;
@@ -462,19 +456,19 @@ RemoteSpellChecker.prototype = {
       return "";
     }
     return next.value;
   },
 
   get currentDictionary() { return this._spellInfo.currentDictionary; },
   get dictionaryList() { return this._spellInfo.dictionaryList.slice(); },
 
-  selectDictionary(index) {
+  selectDictionary(localeCode) {
     this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:selectDictionary",
-                                            { index });
+                                            { localeCode });
   },
 
   replaceMisspelling(index) {
     this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:replaceMisspelling",
                                             { index });
   },
 
   toggleEnabled() { this._spellInfo.target.sendAsyncMessage("InlineSpellChecker:toggleEnabled", {}); },
--- a/toolkit/modules/InlineSpellCheckerContent.jsm
+++ b/toolkit/modules/InlineSpellCheckerContent.jsm
@@ -51,31 +51,24 @@ var InlineSpellCheckerContent = {
                initialSpellCheckPending: true,
                enableRealTimeSpell: true };
     }
 
     let dictionaryList = {};
     let realSpellChecker = spellChecker.mInlineSpellChecker.spellChecker;
     realSpellChecker.GetDictionaryList(dictionaryList, {});
 
-    // The original list we get is in random order. We need our list to be
-    // sorted by display names.
-    dictionaryList = spellChecker.sortDictionaryList(dictionaryList.value).map((obj) => {
-      return obj.id;
-    });
-    spellChecker.mDictionaryNames = dictionaryList;
-
     return { canSpellCheck: spellChecker.canSpellCheck,
              initialSpellCheckPending: spellChecker.initialSpellCheckPending,
              enableRealTimeSpell: spellChecker.enabled,
              overMisspelling: spellChecker.overMisspelling,
              misspelling: spellChecker.mMisspelling,
              spellSuggestions: this._generateSpellSuggestions(),
              currentDictionary: spellChecker.mInlineSpellChecker.spellChecker.GetCurrentDictionary(),
-             dictionaryList };
+             dictionaryList: dictionaryList.value };
   },
 
   uninitContextMenu() {
     for (let i of this._messages)
       this._manager.removeMessageListener(i, this);
 
     this._manager = null;
     this._spellChecker = null;
@@ -115,17 +108,17 @@ var InlineSpellCheckerContent = {
   _addMessageListeners() {
     for (let i of this._messages)
       this._manager.addMessageListener(i, this);
   },
 
   receiveMessage(msg) {
     switch (msg.name) {
       case "InlineSpellChecker:selectDictionary":
-        this._spellChecker.selectDictionary(msg.data.index);
+        this._spellChecker.selectDictionary(msg.data.localeCode);
         break;
 
       case "InlineSpellChecker:replaceMisspelling":
         this._spellChecker.replaceMisspelling(msg.data.index);
         break;
 
       case "InlineSpellChecker:toggleEnabled":
         this._spellChecker.toggleEnabled();