VulpesOS/gaia/apps/keyboard/js/settings/user_dictionary.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

155 lines
3.9 KiB
JavaScript
Executable file

'use strict';
/* global PromiseStorage, WordListConverter */
(function(exports) {
// The "model" of user dictionary (controller logic is currently kept at app)
var UserDictionary = function UserDictionary() {
this._wordSet = null;
this._saveQueue = null;
this._dbStore = null;
this._started = false;
};
UserDictionary.prototype.start = function() {
if (this._started) {
console.error('UserDictionary: attempting to start twice');
return;
}
this._started = true;
this._saveQueue = Promise.resolve();
this._dbStore = new PromiseStorage(this.DB_NAME);
this._dbStore.start();
};
UserDictionary.prototype.stop = function() {
if (this._started) {
this._wordSet = null;
this._saveQueue = null;
this._dbStore.stop();
}
};
UserDictionary.prototype.DB_NAME = 'UserDictLatin';
// Get the list of words from indexedDB
UserDictionary.prototype.getList = function() {
if (!this._started) {
return Promise.reject('UserDictionary not started');
}
return this._dbStore.getItem('wordlist').then(list => {
list = list || [];
this._wordSet = new Set(list);
return this._wordSet;
}).catch(e => {
e && console.error(e);
this._wordSet = new Set([]);
return this._wordSet;
});
};
// Save the list of words and the dictionary blob to indexedDB.
// We queue the saves such that firing successive saves won't easily break.
// Meanwhile, the queued save has to resolve back to the view to update the
// UI accordingly.
// Returns the list of words as it has been sorted here.
// XXX: implement abortable queue for successive saves such that we skip
// not-yet-executed intermediate saves.
// XXX: blob generation can be time-consuming. WebWorker-ize it?
UserDictionary.prototype._saveDict = function() {
// Keep the words sorted.
// XXX: We're not yet able to do true lexicographical sort, see bug 866301.
// But here, let's at least do some case insensitive sort, though.
var wordList = Array.from(this._wordSet);
wordList = wordList.sort((a, b) =>
a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()));
this._wordSet = new Set(wordList);
var dictBlob =
0 === wordList.length ?
undefined :
new WordListConverter(wordList).toBlob();
var p = this._saveQueue.then(
() => {
this._dbStore.setItems({
'wordlist': wordList,
'dictblob': dictBlob
});
return wordList;
}
);
this._saveQueue = p;
this._saveQueue = this._saveQueue.catch(e => {
console.error(e);
});
return p;
};
UserDictionary.prototype.addWord = function(word) {
if (!this._started) {
return Promise.reject('UserDictionary not started');
}
word = word.trim();
if (this._wordSet.has(word)) {
return Promise.reject('existing');
}
this._wordSet.add(word);
return this._saveDict();
};
UserDictionary.prototype.updateWord = function(oldWord, word) {
if (!this._started) {
return Promise.reject('UserDictionary not started');
}
word = word.trim();
if (oldWord === word) {
return Promise.resolve(Array.from(this._wordSet));
}
// if new word already exists, delete the old and save,
// but tell view about this scenario
this._wordSet.delete(oldWord);
if (this._wordSet.has(word)) {
// XXX: word list resolved from saveDict is lost, but we don't really care
// since we'll only be deleteing something at view
return this._saveDict().then(() => Promise.reject('existing'));
} else {
this._wordSet.add(word);
return this._saveDict();
}
};
UserDictionary.prototype.removeWord = function(word) {
if (!this._started) {
return Promise.reject('UserDictionary not started');
}
this._wordSet.delete(word);
return this._saveDict();
};
// A small helper function to ease debugging. This is *not* used in real-world
// scenario as the blob is only retrieved by prediction engine.
UserDictionary.prototype._getBlob = function() {
return this._dbStore.getItem('dictblob');
};
exports.UserDictionary = UserDictionary;
})(window);