4
\$\begingroup\$

For my first use of javascript I've made an app that takes an input verb from html in Japanese and outputs it in to many conjugated (manipulated) forms.

Essentially, it defines an alphabet, some initial arrays and functions for use, a function to initially check for values and interact with the html page, an object to pass different verb values to, and then a whole slew of "self invoking functions" that essentially take the verb and pass it to the object, and then another function to interact with the page.

Right now I'm at a loss on how to rewrite it in modular JS. I have a couple libraries defined in the HTML (bootstrap, jQuery, and a Japanese IME). Although I'm using self-invoking functions and have a general idea of what modules are, I have no idea what a practical way of splitting up the code in to modules would be.

$(document).ready(function () {

    //hiragana table
    var hiragana = {
        a: ["あ", "か", "さ", "た", "な", "は", "ま", "や", "ら", "わ", "が", "ざ", "だ", "ば", "ぱ"],
        i: ["い", "き", "し", "ち", "に", "ひ", "み", " ", "り", " ", "ぎ", "じ", "ぢ", "び", "ぴ"],
        u: ["う", "く", "す", "つ", "ぬ", "ふ", "む", "ゆ", "る", " ", "ぐ", "ず", "づ", "ぶ", "ぷ"],
        e: ["え", "け", "せ", "て", "ね", "へ", "め", " ", "れ", " ",  "げ", "ぜ", "で", "べ", "ぺ"],
        o: ["お", "こ", "そ", "と", "の", "ほ", "も", "よ", "ろ", "を", "ご", "ぞ", "ど", "ぼ", "ぽ"],
        teOne: ["み", "に", "び"],
        teTwo: ["い", "ち", "り"],
        change: function (input, initVowel, desiredVowel) {
            var x = hiragana[initVowel].indexOf(input);
            return hiragana[desiredVowel][x];
        }
    };

    var groupOneExceptions = ["はいる", "はしる", "かえる", "かぎる", "きる", "しゃべる", "しる", "いる"];
    var groupThree = ["くる", "する"];
    var existence = [["いる", "ある"], ["です"]];

    //check if in array
    function isInArray(array, search) {
        return array.indexOf(search) >= 0;
    }

    //add input to the page
    function printPage(id, value) {
        $("#" + id).replaceWith("<div id = " + id + ">" + value + "</span>");
    }

    //bind input to wanakana on page load
    var input = document.getElementById("input");
    wanakana.bind(input);

    //check radio buttons and enact changes on enter form
    $("input:radio[name=input-method]").change(function () {
        if ($(this).val() === "Hiragana") {
            //wanakana support
            wanakana.bind(input);
            $("#input").attr("placeholder", "たべる");
        }

        if ($(this).val() === "Romaji") {
            wanakana.unbind(input);
            $("#input").attr("placeholder", "taberu");
        }
    });

    //Click the button to get the form value.
    $("#submit").click(function () {

        var verb = {
            //put an if check here for masu? LATER
            group: "",
            u: $("#input").val(),
            end: "",
            endTwo: "",
            withoutEnd: "",
            i: "",
            te: "",
            preMasu: "",
            masu: "",
            ta: "",
            taEnd: "",
            nakatta: "",
            mashita: "",
            masendeshita: "",
            teEnd: "",
            nai: "",
            naiEnd: "",
            masen: "",
            ou: "",
            ouEnd: "",
            naidarou: "",
            eba: "",
            ebaEnd: "",
            nakereba: "",
            eru: "",
            eruEnd: "",
            erunai: "",
            seru: "",
            serunai: "",
            reru: "",
            rerunai: ""
        };

        var init = (function () {
            printPage("callout", "");
            //clear table

            for (prop in verb) {
                if (typeof verb[prop] === "string") {
                    printPage(prop, "");
                }
            }

            //init verb.u for hiragana processing
            if (wanakana.isKana(verb.u) === false) {
                verb.u = wanakana.toHiragana(verb.u);
            }

            //do some initial slicing
            verb.end = verb.u.slice(-1);
            verb.endTwo = verb.u.slice(-2, -1);
            verb.withoutEnd = verb.u.slice(0, -1);

            if (isInArray(hiragana.u, verb.end) === false) {
                printPage("callout", "<div class=\"bs-callout bs-callout-danger\"> It doesn't look like " + verb.u + " is a valid Japanese verb in plain form. Try something that ends with an \"u\".</div>");
            }

            if (isInArray(existence[0], verb.u)) {
                printPage("callout", "<div class=\"bs-callout bs-callout-info\"> If you were referring to the existence construct " + verb.u + " (to be), refer here.</div>");
            } else if (isInArray(existence[1], verb.u)) {
                printPage("callout", "<div class=\"bs-callout bs-callout-info\"> If you were referring to the existence construct " + verb.u + " (is), refer here.</div>");
            }

        })();

        if (isInArray(hiragana.u, verb.end)) {

            verb.getGroup = (function () {

                if (isInArray(groupThree, verb.u)) {
                    verb.group = "3";
                } else if (verb.end === "る" && (isInArray(hiragana.i, verb.endTwo) || isInArray(hiragana.e, verb.endTwo))) {
                    verb.group = "2";
                } else if (isInArray(hiragana.u, verb.end)) {
                    verb.group = "1";
                }

                if (isInArray(groupOneExceptions, verb.u)) {
                    verb.group = "1";
                }
            })();

            verb.getI = (function () {
                if (verb.group === "1") {
                    verb.preMasu = hiragana.change(verb.end, "u", "i");
                    verb.i = verb.u.slice(0, -1) + verb.preMasu;

                }
                if (verb.group === "2") {
                    verb.i = verb.u.slice(0, -1);
                }

                if (verb.group === "3") {
                    verb.i = hiragana.change(verb.withoutEnd, "u", "i");
                }

            })();

            verb.getTe = (function () {

                if (verb.group === "3" || verb.group === "2") {
                    verb.te = verb.i + "て";
                }
                if (verb.group === "1") {
                    if (isInArray(hiragana.teOne, verb.preMasu)) {
                        verb.teEnd = "んで";
                    } else if (isInArray(hiragana.teTwo, verb.preMasu)) {
                        verb.teEnd = "って";
                    } else if (verb.preMasu === "き") {
                        verb.teEnd = "いて";
                    } else if (verb.preMasu === "ぎ") {
                        verb.teEnd = "いで";
                    } else if (verb.preMasu === "し") {
                        verb.teEnd = "して";
                    }

                    //exception
                    if (verb.u === "いく") {
                        verb.teEnd = "って";
                    }

                    verb.te = verb.withoutEnd + verb.teEnd;
                }

            })();

            verb.getNai = (function () {
                if (verb.group === "3") {
                    if (verb.u === "する") {
                        verb.nai = "しない";
                    }
                    if (verb.u === "くる") {
                        verb.nai = "こない";
                    }
                }

                if (verb.group === "2") {
                    verb.nai = verb.i + "ない";
                }

                if (verb.group === "1") {
                    if (verb.preMasu === "い") {
                        verb.naiEnd = "わ";
                    } else {
                        verb.naiEnd = hiragana.change(verb.preMasu, "i", "a") + "ない";
                    }
                    verb.nai = verb.withoutEnd + verb.naiEnd;

                    if (verb.u === "ある") {
                        verb.nai = "ない";
                    }
                }

            })();

            verb.getMasu = (function () {
                verb.masu = verb.i + "ます";

            })();

            verb.getMasen = (function () {
                verb.masen = verb.i + "ません";

            })();

            verb.getTa = (function () {
                if (verb.group === "3" || verb.group === "2") {
                    verb.ta = verb.i + "た";
                }
                if (verb.group === "1") {
                    verb.taEnd = verb.teEnd.slice(0, -1) + hiragana.change(verb.teEnd.slice(-1), "e", "a");
                    verb.ta = verb.withoutEnd + verb.taEnd;
                }

            })();

            verb.getNakatta = (function () {
                verb.nakatta = verb.nai.slice(0, -1) + "かった";

            })();

            verb.getMashita = (function () {
                verb.mashita = verb.i + "ました";

            })();

            verb.getMasendeshita = (function () {
                verb.masendeshita = verb.masen + " でした";

            })();

            verb.getOu = (function () {
                if (verb.group === "3") {
                    verb.ou = verb.nai.slice(0, -2) + "よう";
                }
                if (verb.group === "2") {
                    verb.ou = verb.i + "よう";
                }
                if (verb.group === "1") {
                    verb.ouEnd = hiragana.change(verb.preMasu, "i", "o") + "う";
                    verb.ou = verb.withoutEnd + verb.ouEnd;
                }

            })();

            verb.getNaidarou = (function () {
                verb.naidarou = verb.nai + " だろう";

            })();

            verb.getEba = (function () {
                if (verb.group === "3") {
                    verb.eba = verb.withoutEnd + "れば";
                }
                if (verb.group === "2") {
                    verb.eba = verb.i + "れば";
                }
                if (verb.group === "1") {
                    verb.ebaEnd = hiragana.change(verb.preMasu, "i", "e") + "ば";
                    verb.eba = verb.withoutEnd + verb.ebaEnd;
                }

            })();

            verb.getNakereba = (function () {
                verb.nakereba = verb.nai.slice(0, -1) + "ければ";
            })();

            verb.getEru = (function () {
                if (verb.group === "3") {
                    if (verb.u === "する") {
                        verb.eru = "できる";
                    }
                    if (verb.u === "くる") {
                        verb.eru = "こられる";
                    }
                }
                if (verb.group === "2") {
                    verb.eru = verb.withoutEnd + "られる";
                }
                if (verb.group === "1") {
                    verb.eruEnd = hiragana.change(verb.preMasu, "i", "e") + "る";
                    verb.eru = verb.withoutEnd + verb.eruEnd;
                }

            })();

            verb.getErunai = (function () {
                verb.erunai = verb.eru.slice(0, -1) + "ない";
            })();

            verb.getReru = (function () {
                if (verb.group === "3") {
                    if (verb.u === "する") {
                        verb.reru = "される";
                    }
                    if (verb.u === "くる") {
                        verb.reru = "こらせる";
                    }
                }
                if (verb.group === "2") {
                    verb.reru = verb.eru;
                }
                if (verb.group === "1") {
                    verb.reru = verb.nai.slice(0, -2) + "れる";
                }
            })();

            verb.getRerunai = (function () {
                verb.rerunai = verb.reru.slice(0, -1) + "ない";
            })();

            verb.getSeru = (function () {
                if (verb.group === "3") {
                    if (verb.u === "する") {
                        verb.seru = "させる";
                    }
                    if (verb.u === "くる") {
                        verb.seru = "こさせる";
                    }
                }
                if (verb.group === "2") {
                    verb.seru = verb.withoutEnd + "させる";
                }
                if (verb.group === "1") {
                    verb.seru = verb.nai.slice(0, -2) + "せる";
                }

            })();

            verb.getserunai = (function () {
                verb.serunai = verb.seru.slice(0, -1) + "ない";
            })();

            verb.process = (function () {

                var prop = "";
                //goes through verb object, checks for romaji, prints page
                for (prop in verb) {
                    if (typeof verb[prop] === "string") {
                        if (wanakana.isKana($("#input").val()) === false) {
                            verb[prop] = wanakana.toRomaji(verb[prop]);
                        }
                        printPage(prop, verb[prop]);
                    } //string
                } //for in
            })();
        }
    });
});
\$\endgroup\$
  • \$\begingroup\$ Don't mix business and presentation logic. \$\endgroup\$ – CodesInChaos Aug 27 '14 at 13:44
1
\$\begingroup\$
  • Comments such as //check if in array before a function called isInArray and //hiragana table are completely pointless. It would be more important to describe what you are actually doing for everyone who doesn't know Japanese.

  • $("#" + id).replaceWith("<div id = " + id + ">" + value + "</span>");: Besides the mismatching tags, this looks like a very bad way to output something.

  • document.getElementById("input");: Don't hard code IDs. The next time you or someone else needs to re-use the code on a different page, they'll need to search and replace them all, also why don't you use jQuery here?

  • wanakana is not defined.

  • There are far too many magic strings.

  • In general you seem to completely confused on the point of using self-invoking functions. You are not using them for any practical purpose nor do they return anything and yet you attempt to store their return value.

I can only suggest:

  • Re-write everything in a straight forward procedural manner, breaking the functionally down into functions (procedures) no longer than, say, 10 lines (arbitrary number, just for the practice).

  • Don't have the functions access any "global" variables - that is let them work only with their arguments. The only exception would be accessing any global constants.

  • Make sure you don't use any string literals, other than when defining constants.

  • Give all constants a name with CAPITAL_LETTERS, so they are recognizable as such.

  • Ignore input and output for now. For testing/development just start your program with a function call to the main function with the verb as it's argument, and output to the console. E.g.:

console.log( japaneseVerbConjugator("Some Japanese verb") );

\$\endgroup\$
  • \$\begingroup\$ Hi and thanks a lot! I've recoded everything and separated the "business" and "presentation" code in to different files (modules?) returning actual values using requireJS. I was wondering why HTML was so clumsy in Javascript but thanks to a quick google of "magic string" I understand what you mean. I'll change the getElementbyId method to JQuery for consistency, and stop using literals when processing output strings. However, I don't quite get what you mean with accessing arguments, right now an object is serving as a data storage object and the conjugation functions are simply accessing it. \$\endgroup\$ – cardboardtheory Sep 2 '14 at 3:33
  • \$\begingroup\$ If there's a better way of doing the same task please let me know! Otherwise, I'll really try to improve my code according to your advice. If there's more advice or any other sources for useful knowledge and standard ways of doing things, I would be infinitely grateful as my coding knowledge up to now is basically a few Codecademy courses. \$\endgroup\$ – cardboardtheory Sep 2 '14 at 3:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.