Home Reference Source

lib/dictionary/loader.js

import event from '../events/events.js';
import Chord from '../engine/chord.js';
import Word from '../engine/word.js';

class DictLoader extends event.EventEmitter {
    constructor(output, convert, root, MacroLoader) {
        super()

        this.isdict = true;
        this.convert = convert;
        this.output = output;

        // Private
        this._root = root;
        this._words = [];
        this._dictionary = {};

        // Public
        this.dicts = [];
        this.macros = MacroLoader;

        // Aliases
        this.reload = this.load;
        this.remove = this.unload;
        this.add = this.load;
    };

    onLoad() {
        //console.log("Loading Dictionaries");
    };

    onUnload() {
        //console.log("Unloading Dictionaries");
    };

    _generateDictionary(dicts = this.dicts) {
        const mergedDict = {};

        for (let obj of dicts) {
            for (let key in obj) {
                if (obj.hasOwnProperty(key)) {
                    mergedDict[key] = obj[key];
                };
            };
        };

        return mergedDict;
    };

    _demetafy(translationString) {
        // TAKEN FROM PLOVERPAD
        // FULL CREDITS

        // Sentence stops
        translationString = translationString.replace(/\s*{(\.|!|\?)}\s*(\w?)/g, function (matchString, punctuationMark, nextLetter) { return punctuationMark + ' ' + nextLetter.toUpperCase(); });

        // Sentence breaks
        translationString = translationString.replace(/\s*{(,|:|;)}\s*/g, function (matchString, punctuationMark) { return punctuationMark + ' '; });

        // Simple suffixes (pure javascript translation from the Python code base)
        translationString = translationString.replace(/(\w*)\s*{(\^ed|\^ing|\^er|\^s)}/g, simpleSuffix);
        function simpleSuffix() {
            var matchString = arguments[0];
            var prevWord = arguments[1];
            var suffix = arguments[2];
            var returnString = '';

            var CONSONANTS = { 'b': true, 'c': true, 'd': true, 'f': true, 'g': true, 'h': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'p': true, 'q': true, 'r': true, 's': true, 't': true, 'v': true, 'w': true, 'x': true, 'z': true, 'B': true, 'C': true, 'D': true, 'F': true, 'G': true, 'H': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'P': true, 'Q': true, 'R': true, 'S': true, 'T': true, 'V': true, 'W': true, 'X': true, 'Z': true };
            var VOWELS = { 'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'A': true, 'E': true, 'I': true, 'O': true, 'U': true };
            var W = { 'w': true, 'W': true };
            var Y = { 'y': true, 'Y': true };
            var PLURAL_SPECIAL = { 's': true, 'x': true, 'z': true, 'S': true, 'X': true, 'Z': true };
            var prepForSimpleSuffix = function (wordParam) {
                var numChars = wordParam.length;
                if (numChars < 2) {
                    return wordParam;
                }
                if (numChars >= 3) {
                    thirdToLast = wordParam.slice(-3, -2);
                } else {
                    thirdToLast = '';
                }
                secondToLast = wordParam.slice(-2, -1);
                last = wordParam.slice(-1);
                if (secondToLast in VOWELS || secondToLast in CONSONANTS) {
                    if (last in VOWELS) {
                        if (thirdToLast && (thirdToLast in VOWELS || thirdToLast in CONSONANTS)) {
                            return wordParam.slice(0, -1);
                        }
                    } else if (last in CONSONANTS && !(last in W) && secondToLast in VOWELS && thirdToLast && !(thirdToLast in VOWELS)) {
                        return wordParam + last;
                    } else if (last in Y && secondToLast in CONSONANTS) {
                        return wordParam.slice(0, -1) + 'i';
                    }
                }
                return wordParam;
            }

            if (suffix === '^s') {
                if (prevWord.length < 2) {
                    return prevWord + 's';
                }
                var a = prevWord.slice(-2, -1);
                var b = prevWord.slice(-1);

                if (b in PLURAL_SPECIAL) {
                    return prevWord + 'es';
                } else if (b in Y && a in CONSONANTS) {
                    return prevWord.slice(0, -1) + 'ies';
                }
                return prevWord + 's';
            }
            if (suffix === '^ed') {
                return prepForSimpleSuffix(prevWord) + 'ed';
            }
            if (suffix === '^er') {
                return prepForSimpleSuffix(prevWord) + 'er';
            }
            if (suffix === '^ing') {
                if (prevWord && prevWord.slice(-1) in Y) {
                    return prevWord + 'ing';
                }
                return prepForSimpleSuffix(prevWord) + 'ing';
            }
        }

        // Capitalize
        translationString = translationString.replace(/\s*{-\|}\s*(\w?)/g, function (matchString, nextLetter) { return nextLetter.toUpperCase(); });

        // Glue flag
        translationString = translationString.replace(/(\s*{&[^}]+}\s*)+/g, glue);
        function glue() {
            var testString = '';
            for (i = 0; i < arguments.length; i++) {
                testString += arguments[i] + ', ';
            }
            var matchString = arguments[0];
            matchString = matchString.replace(/\s*{&([^}]+)}\s*/g, function (a, p1) { return p1; });
            return ' ' + matchString + ' ';
        }

        // Attach flag
        translationString = translationString.replace(/\s*{\^([^}]+)\^}\s*/g, function (matchString, attachString) { return attachString; });
        translationString = translationString.replace(/\s*{\^([^}]+)}(\s*)/g, function (matchString, attachString, whitespace) { return attachString + whitespace; });
        translationString = translationString.replace(/(\s*){([^}]+)\^}\s*/g, function (matchString, whitespace, attachString) { return whitespace + attachString; });

        // Key Combinations
        translationString = translationString.replace(/\s*{#Return}\s*/g, '\n');
        translationString = translationString.replace(/\s*{#Tab}\s*/g, '\t');

        return translationString;
    };

    onChord(keys, next) {
        // Limit
        if (this._words.length > this._root.config.undo_history) this._words = this._words.slice(this._words.length - this._root.config.undo_history);

        var modifyArr = [];
        const chord = new Chord(keys);

        // Slightly rewritten ploverpad code. Huge credits to openstenoproject for making plover open source.
        if (this._words.length > 0) {
            if (chord.toRTFCRE() !== '*') { // NORMAL KEYS
                const lastWord = this._words[this._words.length - 1];
                const combinedString = lastWord.toString() + '/' + chord.toRTFCRE();
                modifyArr.push({ action: 'delete', amount: lastWord.length + 1 });
                if (this._dictionary[combinedString]) {
                    lastWord.addStroke(chord);
                    modifyArr.push({ action: 'add', text: this._demetafy(chord.toEnglish(this._dictionary, this.macros.checkMarco) + ' ') });
                } else {
                    var temp = new Word([chord])
                    this._words.push(temp);
                    modifyArr.push({ action: 'add', text: this._demetafy(temp.toEnglish(this._dictionary, this.macros.checkMarco) + ' ') });
                };
            } else if (chord.toRTFCRE() === '*') { // SPECIAL KEY
                if (this._words.length < 1) return;

                modifyArr.push({ action: 'delete', amount: this._words.length + 1 });
                this._words[this._words.length - 1].removeStroke();
                if (this._words[this._words.length - 1].toString() === '') {
                    this._words.pop();
                };
                if (this._words.length < 2 && this._words[this._words.length - 1]) modifyArr.push({ action: 'add', text: this._demetafy(this._words[this._words.length - 1].toEnglish(this._dictionary, this.macros.checkMarco) + ' ') });
            };
        } else { // NEW STROKE
            var temp = new Word([chord]);
            this._words.push(temp);
            modifyArr.push({ action: 'add', text: this._demetafy(temp.toEnglish(this._dictionary, this.macros.checkMarco) + ' ') });
        };

        const fullSteno = this._words.reduce((acc, word) => acc + word.toEnglish(this._dictionary, this.macros.checkMarco) + ' ', '');
        this.output._onData(this._demetafy(fullSteno));

        // Handle modify  [ { action: 'delete', amount: 5 }, { action: 'add', text: "hello" } ]
        this.output._onModify(modifyArr);

        return next();
    };

    lookup(phrase) {

    };

    reloadAll() {
        if (this.dicts.length < 1) {
            this.emit("reloadAllFailed");
            this._root.emit("dictionariesReloadFailed");
            return false;
        };

        this.dicts.forEach(dict => this.load(dict, false));
        this._dictionary = this._generateDictionary();
        this.emit("reloadAll", this.dicts);
        this._root.emit("dictionariesReload");
        return true;
    };

    load(dict, genDict = true) {
        if (typeof dict !== 'object') return false;

        this.dicts.push(dict);

        if (genDict == true) this._dictionary = this._generateDictionary();

        if (dict in this.dicts) {
            this.emit("load", dict);
            this._root.emit("dictionaryLoad", dict);

            this.emit("reload", dict);
            this._root.emit("dictionaryReload", dict);

            return dict;
        } else {
            this.emit("loadFailed", dict);
            this._root.emit("dictionaryLoadFailed", dict);

            this.emit("reloadFailed", dict);
            this._root.emit("dictionaryReloadFailed", dict);

            return false;
        };
    };

    unload(dict) {
        if (dict in this.dicts) {
            delete this.dicts[this.dicts.indexOf(dict)];
            this._dictionary = this._generateDictionary();
            return true;
        } else {
            return false;
        };
    };
}

export { DictLoader };